// ui.jsx — shared primitives: icons, Logo, Field, Modal, Toast, Reveal, KPI, etc.

// ---------- icon set (lucide-style stroke icons) ----------
const IP = { fill: "none", stroke: "currentColor", strokeWidth: 1.8, strokeLinecap: "round", strokeLinejoin: "round" };
function Svg({ children, s = 22, ...p }) {
  return <svg width={s} height={s} viewBox="0 0 24 24" {...IP} {...p}>{children}</svg>;
}
const Icon = {
  bulb:   (p) => <Svg {...p}><path d="M9 18h6M10 22h4M12 2a7 7 0 0 0-4 12.7c.6.5 1 1.3 1 2.1V17h6v-.2c0-.8.4-1.6 1-2.1A7 7 0 0 0 12 2Z"/></Svg>,
  book:   (p) => <Svg {...p}><path d="M4 5.5A2.5 2.5 0 0 1 6.5 3H20v15H6.5A2.5 2.5 0 0 0 4 20.5V5.5Z"/><path d="M20 18v3H6.5A2.5 2.5 0 0 1 4 18.5"/></Svg>,
  award:  (p) => <Svg {...p}><circle cx="12" cy="9" r="6"/><path d="M9 13.5 7.5 22 12 19l4.5 3-1.5-8.5"/></Svg>,
  cpu:    (p) => <Svg {...p}><rect x="6" y="6" width="12" height="12" rx="2"/><path d="M9 9h6v6H9z"/><path d="M12 2v3M12 19v3M2 12h3M19 12h3M5 9H2M5 15H2M22 9h-3M22 15h-3M9 2v3M15 2v3M9 19v3M15 19v3"/></Svg>,
  grid:   (p) => <Svg {...p}><rect x="3" y="3" width="7" height="7" rx="1.5"/><rect x="14" y="3" width="7" height="7" rx="1.5"/><rect x="3" y="14" width="7" height="7" rx="1.5"/><rect x="14" y="14" width="7" height="7" rx="1.5"/></Svg>,
  chart:  (p) => <Svg {...p}><path d="M3 3v18h18"/><rect x="7" y="11" width="3" height="6" rx="1"/><rect x="12" y="7" width="3" height="10" rx="1"/><rect x="17" y="13" width="3" height="4" rx="1"/></Svg>,
  arrow:  (p) => <Svg {...p}><path d="M5 12h14M13 6l6 6-6 6"/></Svg>,
  arrowL: (p) => <Svg {...p}><path d="M19 12H5M11 6l-6 6 6 6"/></Svg>,
  check:  (p) => <Svg {...p}><path d="M20 6 9 17l-5-5"/></Svg>,
  clock:  (p) => <Svg {...p}><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></Svg>,
  user:   (p) => <Svg {...p}><circle cx="12" cy="8" r="4"/><path d="M4 21c0-4 4-6 8-6s8 2 8 6"/></Svg>,
  users:  (p) => <Svg {...p}><circle cx="9" cy="8" r="3.5"/><path d="M2.5 20c0-3.3 3-5 6.5-5s6.5 1.7 6.5 5"/><path d="M16 4.5a3.5 3.5 0 0 1 0 7M22 20c0-2.6-1.6-4.3-4-4.8"/></Svg>,
  mail:   (p) => <Svg {...p}><rect x="3" y="5" width="18" height="14" rx="2"/><path d="m3 7 9 6 9-6"/></Svg>,
  phone:  (p) => <Svg {...p}><path d="M6 3h3l2 5-2.5 1.5a12 12 0 0 0 6 6L16 14l5 2v3a2 2 0 0 1-2 2A16 16 0 0 1 4 5a2 2 0 0 1 2-2Z"/></Svg>,
  pin:    (p) => <Svg {...p}><path d="M12 21s7-6 7-11a7 7 0 1 0-14 0c0 5 7 11 7 11Z"/><circle cx="12" cy="10" r="2.5"/></Svg>,
  pen:    (p) => <Svg {...p}><path d="M12 20h9"/><path d="M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4Z"/></Svg>,
  trash:  (p) => <Svg {...p}><path d="M4 7h16M9 7V5a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2M6 7l1 13a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1l1-13"/></Svg>,
  plus:   (p) => <Svg {...p}><path d="M12 5v14M5 12h14"/></Svg>,
  x:      (p) => <Svg {...p}><path d="M18 6 6 18M6 6l12 12"/></Svg>,
  sliders:(p) => <Svg {...p}><path d="M4 21v-7M4 10V3M12 21v-9M12 8V3M20 21v-5M20 12V3M1 14h6M9 8h6M17 16h6"/></Svg>,
  globe:  (p) => <Svg {...p}><circle cx="12" cy="12" r="9"/><path d="M3 12h18M12 3c2.5 2.5 2.5 15 0 18M12 3c-2.5 2.5-2.5 15 0 18"/></Svg>,
  menu:   (p) => <Svg {...p}><path d="M3 6h18M3 12h18M3 18h18"/></Svg>,
  image:  (p) => <Svg {...p}><rect x="3" y="4" width="18" height="16" rx="2"/><circle cx="9" cy="9" r="1.8"/><path d="m4 18 5-5 4 3 3-3 4 4"/></Svg>,
  spark:  (p) => <Svg {...p}><path d="M12 2l2 6 6 2-6 2-2 6-2-6-6-2 6-2 2-6Z"/></Svg>,
  shield: (p) => <Svg {...p}><path d="M12 2 4 5v6c0 5 3.5 8.5 8 11 4.5-2.5 8-6 8-11V5l-8-3Z"/><path d="m9 12 2 2 4-4"/></Svg>,
  rocket: (p) => <Svg {...p}><path d="M5 15c-1.5 1.5-2 5-2 5s3.5-.5 5-2M9 12a14 14 0 0 1 8-9c2 0 2 0 2 2a14 14 0 0 1-9 8l-1 2-2-2-2-2 2-1Z"/><circle cx="14.5" cy="9.5" r="1.2"/></Svg>,
  play:   (p) => <Svg {...p}><path d="M7 4v16l13-8Z"/></Svg>,
  hash:   (p) => <Svg {...p}><path d="M5 9h14M5 15h14M9 4l-2 16M17 4l-2 16"/></Svg>,
  chevR:  (p) => <Svg {...p}><path d="m9 6 6 6-6 6"/></Svg>,
  flask:  (p) => <Svg {...p}><path d="M9 3h6M10 3v6l-5 9a2 2 0 0 0 2 3h10a2 2 0 0 0 2-3l-5-9V3"/><path d="M7.5 15h9"/></Svg>,
  wa:     (p) => <Svg {...p}><path d="M3 21l1.6-4.5A8 8 0 1 1 8 19.5L3 21Z"/><path d="M9 9c0 4 2 6 6 6 .8 0 1-.6 1-1.2 0-.4-1.6-1.2-2-1.2-.5 0-.7.8-1 .8-.8 0-2.2-1.4-2.2-2.2 0-.3.8-.5.8-1 0-.4-.8-2-1.2-2C9.6 8 9 8.2 9 9Z"/></Svg>,
  target: (p) => <Svg {...p}><circle cx="12" cy="12" r="9"/><circle cx="12" cy="12" r="5"/><circle cx="12" cy="12" r="1.5"/></Svg>,
  layers: (p) => <Svg {...p}><path d="m12 3 9 5-9 5-9-5 9-5Z"/><path d="m3 13 9 5 9-5M3 18l9 5 9-5" opacity=".6"/></Svg>,
  lock:   (p) => <Svg {...p}><rect x="4" y="10" width="16" height="11" rx="2.5"/><path d="M8 10V7a4 4 0 0 1 8 0v3"/><path d="M12 14.5v2.5"/></Svg>,
  eye:    (p) => <Svg {...p}><path d="M2 12s3.6-6 10-6 10 6 10 6-3.6 6-10 6-10-6-10-6Z"/><circle cx="12" cy="12" r="3"/></Svg>,
};

// ---------- Logo ----------
function LogoMark({ size = 40 }) {
  const id = React.useMemo(() => 'lm' + Math.random().toString(36).slice(2, 6), []);
  return (
    <span className="logo-mark" style={{ width: size, height: size }}>
      <svg viewBox="0 0 48 48" width={size} height={size} fill="none" aria-hidden="true">
        {/* radiating idea waves (vibrations) */}
        <g className="lm-waves" stroke="#04201a" strokeLinecap="round" opacity=".55">
          <path className="lm-w1" d="M37 16c2.2 1.8 3.4 4.6 3.4 8s-1.2 6.2-3.4 8" strokeWidth="2" fill="none" />
          <path className="lm-w2" d="M40.5 12c3.4 2.8 5.2 7 5.2 12s-1.8 9.2-5.2 12" strokeWidth="1.8" fill="none" />
        </g>
        {/* emitted idea sparks */}
        <g className="lm-sparks" fill="#04201a">
          <circle className="lm-s1" cx="40" cy="24" r="1.7" />
          <circle className="lm-s2" cx="43.5" cy="17" r="1.4" />
          <circle className="lm-s3" cx="43.5" cy="31" r="1.4" />
        </g>
        {/* brain: organic left lobe + circuit right lobe */}
        <g stroke="#04201a" strokeWidth="2.1" strokeLinejoin="round" strokeLinecap="round">
          <path d="M24 11c-4-3-10-2.4-12.6 1.4-3.4.6-5.4 3.6-4.6 7-2.4 2-2.6 5.4-.4 7.6-.8 3 1.4 6 4.6 6.6 1.6 2.8 5.4 4 8.6 2.4 1.2 1 3 1.2 4.4.4" fill="rgba(4,32,26,.10)" />
          <path d="M24 9v30" strokeWidth="1.7" opacity=".75" />
          {/* left gyri */}
          <path d="M16 16c-3 .8-3.6 4-1.6 5.6M13.5 26c2 .6 3.4-.8 3.2-3M18 33c-2-.4-2.8-3-1.2-4.4" strokeWidth="1.7" opacity=".8" />
        </g>
        {/* right hemisphere circuit nodes */}
        <g>
          <g stroke="#04201a" strokeWidth="1.5" opacity=".6">
            <path d="M24 18h6M30 18l3.5 3M24 27h5M29 27l3 3M24 22.5h3.5" />
          </g>
          <g fill="#04201a">
            <circle cx="30" cy="18" r="2.1" /><circle cx="33.5" cy="21" r="1.8" />
            <circle cx="29" cy="27" r="2.1" /><circle cx="32" cy="30" r="1.7" />
          </g>
        </g>
      </svg>
    </span>
  );
}

function Logo({ onClick }) {
  return (
    <a className="logo" href="#" onClick={(e)=>{e.preventDefault(); onClick&&onClick();}} aria-label="IBTIKAR">
      <LogoMark size={40} />
      <LogoText />
    </a>
  );
}
function LogoText() {
  const { t } = useI18n();
  return (
    <span className="logo-txt">
      <b>{t('brand')}<span style={{color:'var(--mint)'}}>.health</span></b>
      <span>{t('brand_sub')}</span>
    </span>
  );
}

// ---------- Field ----------
function Field({ label, required, hint, children }) {
  const { t } = useI18n();
  return (
    <div className="field">
      <label>{label} {required ? <span className="req">*</span> : <span className="help" style={{fontWeight:400}}>({t('optional')})</span>}</label>
      {children}
      {hint && <span className="help">{hint}</span>}
    </div>
  );
}

// ---------- Placeholder image ----------
function PH({ h = 200, label, icon = "image", style }) {
  const I = Icon[icon] || Icon.image;
  return (
    <div className="ph" style={{ height: h, ...style }}>
      <span className="ph-ic"><I s={40} /></span>
      {label && <span className="ph-lbl"><Icon.image s={13} /> {label}</span>}
    </div>
  );
}

// ---------- Modal ----------
function Modal({ open, onClose, children, max = 560 }) {
  React.useEffect(() => {
    if (!open) return;
    const h = (e) => e.key === 'Escape' && onClose();
    window.addEventListener('keydown', h);
    return () => window.removeEventListener('keydown', h);
  }, [open]);
  if (!open) return null;
  return (
    <div className="overlay" onClick={onClose}>
      <div className="modal" style={{ maxWidth: max }} onClick={(e) => e.stopPropagation()}>
        {children}
      </div>
    </div>
  );
}

// ---------- Toast ----------
const ToastCtx = React.createContext(() => {});
function ToastHost({ children }) {
  const [toasts, setToasts] = React.useState([]);
  const push = React.useCallback((msg) => {
    const id = Math.random().toString(36).slice(2);
    setToasts((t) => [...t, { id, msg }]);
    setTimeout(() => setToasts((t) => t.filter((x) => x.id !== id)), 3200);
  }, []);
  return (
    <ToastCtx.Provider value={push}>
      {children}
      <div className="toast-wrap">
        {toasts.map((x) => (
          <div className="toast" key={x.id}>
            <span className="dot"><Icon.check s={15} /></span>{x.msg}
          </div>
        ))}
      </div>
    </ToastCtx.Provider>
  );
}
const useToast = () => React.useContext(ToastCtx);

// ---------- in-view hook (robust: no IntersectionObserver, survives frozen anim clock) ----------
function useInView(margin = 0.92) {
  const ref = React.useRef(null);
  const [seen, setSeen] = React.useState(false);
  React.useEffect(() => {
    const el = ref.current;
    if (!el) return;
    let done = false;
    const force = () => { if (el) { el.style.transition = 'none'; el.style.opacity = '1'; el.style.transform = 'none'; } };
    const reveal = () => {
      if (done) return;
      done = true;
      setSeen(true);
      // guarantee final visible state even if CSS transitions are frozen (preview/capture)
      setTimeout(force, 720);
    };
    const check = () => {
      if (done) return true;
      const r = el.getBoundingClientRect();
      const vh = window.innerHeight || document.documentElement.clientHeight;
      if (r.top < vh * margin && r.bottom > 0) { reveal(); return true; }
      return false;
    };
    if (check()) return;
    const on = () => { if (check()) cleanup(); };
    window.addEventListener('scroll', on, { passive: true });
    window.addEventListener('resize', on);
    let n = 0;
    const iv = setInterval(() => { if (check() || n++ > 16) clearInterval(iv); }, 130);
    const fb = setTimeout(reveal, 1300);
    function cleanup() {
      window.removeEventListener('scroll', on);
      window.removeEventListener('resize', on);
      clearInterval(iv); clearTimeout(fb);
    }
    return cleanup;
  }, []);
  return [ref, seen];
}

// ---------- Reveal on scroll ----------
function Reveal({ children, delay = 0, as = "div", className = "", style }) {
  const [ref, seen] = useInView();
  const Tag = as;
  return <Tag ref={ref} className={`reveal ${seen ? 'in' : ''} ${className}`} style={{ transitionDelay: `${delay}ms`, ...style }}>{children}</Tag>;
}

// ---------- KPI ----------
function CountUp({ to, dur = 1300 }) {
  const [v, setV] = React.useState(0);
  const [ref, seen] = useInView(0.98);
  React.useEffect(() => {
    if (!seen) return;
    // setInterval (timers run even when rAF/anim clock is frozen in capture)
    const steps = 32, stepMs = Math.max(16, dur / steps);
    let i = 0;
    const iv = setInterval(() => {
      i++;
      const p = Math.min(1, i / steps);
      const ease = 1 - Math.pow(1 - p, 3);
      setV(Math.round(to * ease));
      if (p >= 1) clearInterval(iv);
    }, stepMs);
    const fb = setTimeout(() => setV(to), dur + 400);
    return () => { clearInterval(iv); clearTimeout(fb); };
  }, [seen, to]);
  return <span ref={ref}>{v.toLocaleString()}</span>;
}

// ---------- AI brain emblem (professional) ----------
function AIBrain({ s = 200, glow = true }) {
  const id = React.useMemo(() => 'aib' + Math.random().toString(36).slice(2, 7), []);
  const nodes = [
    [70, 56], [102, 44], [128, 64], [134, 96], [116, 124], [86, 132], [62, 112], [54, 82], [96, 88]
  ];
  const links = [[0,1],[1,2],[2,3],[3,4],[4,5],[5,6],[6,7],[7,0],[8,0],[8,2],[8,4],[8,6],[8,1],[8,5]];
  return (
    <svg width={s} height={s} viewBox="0 0 190 180" fill="none" style={{ filter: glow ? `drop-shadow(0 8px 30px rgba(138,109,255,.45))` : 'none' }}>
      <defs>
        <linearGradient id={id} x1="40" y1="30" x2="150" y2="150" gradientUnits="userSpaceOnUse">
          <stop stopColor="#1fd1a3" /><stop offset="1" stopColor="#8a6dff" />
        </linearGradient>
        <radialGradient id={id + 'c'} cx="50%" cy="50%" r="50%">
          <stop stopColor="#bfa9ff" /><stop offset="1" stopColor="#7c5cff" />
        </radialGradient>
      </defs>

      {/* brain outline (two lobes) */}
      <path d="M95 22c-14-10-36-8-46 6-12 2-20 13-18 26-8 7-9 19-2 27-3 11 4 22 15 25 6 10 19 14 30 9 4 4 11 5 16 2V22Z"
        stroke={`url(#${id})`} strokeWidth="3.4" strokeLinejoin="round" fill="rgba(31,209,163,.06)" />
      <path d="M95 22c14-10 36-8 46 6 12 2 20 13 18 26 8 7 9 19 2 27 3 11-4 22-15 25-6 10-19 14-30 9-4 4-11 5-16 2V22Z"
        stroke={`url(#${id})`} strokeWidth="3.4" strokeLinejoin="round" fill="rgba(138,109,255,.06)" />
      {/* central divide */}
      <path d="M95 26v126" stroke={`url(#${id})`} strokeWidth="2.2" strokeDasharray="2 6" opacity=".7" />
      {/* left gyri */}
      <path d="M70 52c-12 4-14 16-6 22M58 92c8 2 13-4 12-12M74 120c-8-2-10-12-4-17" stroke={`url(#${id})`} strokeWidth="2.4" strokeLinecap="round" opacity=".85" />

      {/* right circuit nodes + links */}
      <g stroke="#8a6dff" strokeWidth="1.6" opacity=".55">
        {links.map(([a, b], i) => <line key={i} x1={nodes[a][0]} y1={nodes[a][1]} x2={nodes[b][0]} y2={nodes[b][1]} />)}
      </g>
      {nodes.map(([x, y], i) => (
        <circle key={i} cx={x} cy={y} r={i === 8 ? 7 : 4.2} fill={i === 8 ? `url(#${id}c)` : '#1fd1a3'} stroke="#08141a" strokeWidth="1.5" />
      ))}

      {/* chip pins */}
      <g stroke={`url(#${id})`} strokeWidth="3" strokeLinecap="round">
        <path d="M95 12v8M95 160v8M168 90h8M14 90H6" />
      </g>
    </svg>
  );
}

// ---------- innovation visual (premium hero graphic) ----------
function InnovationVisual({ h = 420, t, L }) {
  const orbit = [
    { r: 80, color: 'var(--mint)', cls: 'iv-spin', dot: { cx: 200, cy: 120 } },
    { r: 128, color: 'var(--purple)', cls: 'iv-spin-rev', dot: { cx: 328, cy: 200 } },
    { r: 172, color: 'var(--gold)', cls: 'iv-spin', dot: { cx: 200, cy: 372 } },
  ];
  const chips = [
    { ic: 'bulb', label: L({ ar: 'فكرة', en: 'Idea' }), color: 'var(--mint)', style: { top: '11%', insetInlineStart: '7%' } },
    { ic: 'book', label: L({ ar: 'دورة', en: 'Course' }), color: 'var(--purple)', style: { top: '7%', insetInlineEnd: '9%' } },
    { ic: 'award', label: L({ ar: 'براءة', en: 'Patent' }), color: 'var(--gold)', style: { bottom: '15%', insetInlineStart: '5%' } },
    { ic: 'cpu', label: L({ ar: 'ذكاء اصطناعي', en: 'AI' }), color: 'var(--purple)', style: { bottom: '9%', insetInlineEnd: '7%' } },
  ];
  return (
    <div className="iv" style={{ height: h }}>
      <svg className="iv-rings" viewBox="0 0 400 400" fill="none">
        {orbit.map((o, i) => (
          <g key={i} className={o.cls}>
            <circle cx="200" cy="200" r={o.r} stroke="rgba(255,255,255,.12)" strokeWidth="1.4" strokeDasharray="3 7" />
            <circle cx={o.dot.cx} cy={o.dot.cy} r="6.5" fill={o.color} />
          </g>
        ))}
        {/* connective lines */}
        <g stroke="rgba(255,255,255,.10)" strokeWidth="1">
          <line x1="200" y1="200" x2="200" y2="120" /><line x1="200" y1="200" x2="328" y2="200" /><line x1="200" y1="200" x2="200" y2="372" />
        </g>
      </svg>
      {chips.map((c, i) => {
        const I = Icon[c.ic];
        return (
          <span key={i} className="iv-chip" style={{ ...c.style, color: c.color }}>
            <I s={15} /> <span style={{ color: 'var(--text)' }}>{c.label}</span>
          </span>
        );
      })}
      <div className="iv-core">
        <svg width="58" height="58" viewBox="0 0 48 48" fill="none">
          <g stroke="#04201a" strokeWidth="2.1" strokeLinejoin="round" strokeLinecap="round">
            <path d="M24 11c-4-3-10-2.4-12.6 1.4-3.4.6-5.4 3.6-4.6 7-2.4 2-2.6 5.4-.4 7.6-.8 3 1.4 6 4.6 6.6 1.6 2.8 5.4 4 8.6 2.4 1.2 1 3 1.2 4.4.4" />
            <path d="M24 9v30" strokeWidth="1.7" opacity=".75" />
            <path d="M16 16c-3 .8-3.6 4-1.6 5.6M13.5 26c2 .6 3.4-.8 3.2-3M18 33c-2-.4-2.8-3-1.2-4.4" strokeWidth="1.7" opacity=".8" />
          </g>
          <g stroke="#04201a" strokeWidth="1.5" opacity=".7"><path d="M24 18h6M30 18l3.5 3M24 27h5M29 27l3 3" /></g>
          <g fill="#04201a"><circle cx="30" cy="18" r="2.1" /><circle cx="33.5" cy="21" r="1.8" /><circle cx="29" cy="27" r="2.1" /><circle cx="32" cy="30" r="1.7" /></g>
        </svg>
      </div>
    </div>
  );
}

// ---------- file attachments (PDF / Word / images / video) ----------
const ATTACH_MAX = 3 * 1024 * 1024; // 2.9MB per file — keeps browser storage healthy
function fileKind(type, name) {
  const n = (name || '').toLowerCase();
  if ((type || '').startsWith('image/')) return 'image';
  if ((type || '').startsWith('video/')) return 'video';
  if (/pdf/.test(type) || n.endsWith('.pdf')) return 'pdf';
  if (/word|document/.test(type) || /\.(docx?|rtf)$/.test(n)) return 'doc';
  return 'file';
}
const ATTACH_ICON = { image: 'image', video: 'play', pdf: 'book', doc: 'pen', file: 'layers' };
function humanSize(b) {
  if (b < 1024) return b + ' B';
  if (b < 1024 * 1024) return Math.round(b / 1024) + ' KB';
  return (b / 1048576).toFixed(1) + ' MB';
}

function AttachField({ label, hint, value = [], onChange, t, L }) {
  const inputRef = React.useRef(null);
  const [err, setErr] = React.useState('');

  const pick = (e) => {
    const files = [...(e.target.files || [])];
    setErr('');
    const reads = files.map(f => new Promise((res) => {
      if (f.size > ATTACH_MAX) { res({ tooBig: f.name }); return; }
      const fr = new FileReader();
      fr.onload = () => res({ id: 'a' + Date.now() + Math.random().toString(36).slice(2, 6), name: f.name, type: f.type, size: f.size, kind: fileKind(f.type, f.name), data: fr.result });
      fr.onerror = () => res(null);
      fr.readAsDataURL(f);
    }));
    Promise.all(reads).then(items => {
      const big = items.filter(x => x && x.tooBig).map(x => x.tooBig);
      const ok = items.filter(x => x && !x.tooBig);
      if (big.length) setErr(L({ ar: `تجاوز الحجم المسموح (٣ ميجابايت): ${big.join('، ')}`, en: `Over the 3MB limit: ${big.join(', ')}` }));
      if (ok.length) onChange([...(value || []), ...ok]);
      if (inputRef.current) inputRef.current.value = '';
    });
  };
  const remove = (id) => onChange((value || []).filter(a => a.id !== id));

  return (
    <div className="field">
      <label>{label} <span className="help" style={{ fontWeight: 400 }}>({L({ ar: 'اختياري', en: 'optional' })})</span></label>
      <button type="button" className="attach-drop" onClick={() => inputRef.current && inputRef.current.click()}>
        <span className="attach-plus"><Icon.plus s={20} /></span>
        <span>
          <b style={{ fontSize: 14.5, display: 'block' }}>{L({ ar: 'إضافة مرفقات', en: 'Add attachments' })}</b>
          <span className="muted" style={{ fontSize: 12.5 }}>PDF · Word · JPEG · PNG · MP4</span>
        </span>
      </button>
      <input ref={inputRef} type="file" multiple hidden onChange={pick}
        accept=".pdf,.doc,.docx,.rtf,image/*,video/*" />
      {err && <span className="help" style={{ color: 'var(--rose)' }}>{err}</span>}
      {hint && <span className="help">{hint}</span>}
      {(value || []).length > 0 && (
        <div className="attach-list">
          {value.map(a => {
            const I = Icon[ATTACH_ICON[a.kind] || 'layers'];
            return (
              <div key={a.id} className="attach-item">
                <span className="attach-ic"><I s={16} /></span>
                <span style={{ flex: 1, minWidth: 0 }}>
                  <b style={{ fontSize: 13.5, display: 'block', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{a.name}</b>
                  <span className="muted" style={{ fontSize: 11.5 }}>{humanSize(a.size)}</span>
                </span>
                <button type="button" className="btn btn-dark btn-sm" style={{ padding: 6 }} onClick={() => remove(a.id)}><Icon.x s={14} /></button>
              </div>
            );
          })}
        </div>
      )}
    </div>
  );
}

// read-only list of attachments (public/course detail views)
function AttachList({ items, L, compact }) {
  if (!items || !items.length) return null;
  return (
    <div className="attach-list">
      {items.map(a => {
        const I = Icon[ATTACH_ICON[a.kind] || 'layers'];
        return (
          <a key={a.id} className="attach-item hoverable" href={a.data} download={a.name} target="_blank" rel="noopener" style={{ textDecoration: 'none' }}>
            <span className="attach-ic"><I s={16} /></span>
            <span style={{ flex: 1, minWidth: 0 }}>
              <b style={{ fontSize: 13.5, display: 'block', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{a.name}</b>
              {!compact && <span className="muted" style={{ fontSize: 11.5 }}>{humanSize(a.size)}</span>}
            </span>
            <span style={{ color: 'var(--accent)', flex: 'none' }}><Icon.arrow s={16} /></span>
          </a>
        );
      })}
    </div>
  );
}

// ---------- clipboard (works in sandboxed iframes / non-secure contexts too) ----------
function copyText(text) {
  const s = String(text == null ? '' : text);
  try { if (navigator.clipboard && window.isSecureContext) { navigator.clipboard.writeText(s).catch(() => fallbackCopy(s)); return true; } } catch (e) {}
  return fallbackCopy(s);
}
function fallbackCopy(s) {
  try {
    const ta = document.createElement('textarea');
    ta.value = s;
    ta.setAttribute('readonly', '');
    ta.style.cssText = 'position:fixed;top:0;left:0;opacity:0;pointer-events:none';
    document.body.appendChild(ta);
    ta.select();
    ta.setSelectionRange(0, s.length);
    const ok = document.execCommand('copy');
    ta.remove();
    return ok;
  } catch (e) { return false; }
}

// ---------- section heading ----------
function Head({ eyebrow, title, sub, center, icon }) {
  const I = icon ? Icon[icon] : null;
  return (
    <div className={center ? "center" : ""} style={{ maxWidth: center ? 680 : 760, margin: center ? "0 auto" : 0 }}>
      {eyebrow && <div className="eyebrow" style={{ justifyContent: center ? "center" : "flex-start" }}>{I && <I s={15} />}{eyebrow}</div>}
      <h2 style={{ fontSize: "clamp(28px, 4vw, 42px)", marginTop: 14 }}>{title}</h2>
      {sub && <p className="muted" style={{ fontSize: 17, marginTop: 14, lineHeight: 1.7 }}>{sub}</p>}
    </div>
  );
}

Object.assign(window, { Icon, Svg, Logo, LogoMark, LogoText, Field, PH, Modal, ToastHost, useToast, Reveal, CountUp, Head, InnovationVisual, AIBrain, AttachField, AttachList, humanSize, fileKind, copyText });
