/* global React */
/* ──────────────────────────────────────────────────────────────
   tech-core.jsx — icons, atoms, hooks
   ────────────────────────────────────────────────────────────── */
const { useState: useStateC, useEffect: useEffectC, useRef: useRefC } = React;

// ── Icons (Lucide-style, 1.75 stroke, currentColor) ──────────────
const ICON_PATHS = {
  arrowRight:  <><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></>,
  play:        <polygon points="6 4 20 12 6 20 6 4"/>,
  spark:       <path d="M12 3l1.9 5.6L19.5 10l-5.6 1.9L12 17.5l-1.9-5.6L4.5 10l5.6-1.4z"/>,
  refresh:     <><polyline points="23 4 23 10 17 10"/><polyline points="1 20 1 14 7 14"/><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"/></>,
  layers:      <><polygon points="12 2 2 7 12 12 22 7 12 2"/><polyline points="2 17 12 22 22 17"/><polyline points="2 12 12 17 22 12"/></>,
  code:        <><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></>,
  split:       <><circle cx="6" cy="6" r="3"/><circle cx="6" cy="18" r="3"/><path d="M20 4v7a4 4 0 0 1-4 4H6"/></>,
  gauge:       <><path d="M12 14l4-4"/><path d="M3.34 19a10 10 0 1 1 17.32 0"/></>,
  map:         <><polygon points="1 6 1 22 8 18 16 22 23 18 23 2 16 6 8 2 1 6"/><line x1="8" y1="2" x2="8" y2="18"/><line x1="16" y1="6" x2="16" y2="22"/></>,
  shield:      <path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/>,
  flask:       <><path d="M9 3h6"/><path d="M10 3v6.5L5 19a2 2 0 0 0 1.8 3h10.4A2 2 0 0 0 19 19l-5-9.5V3"/><line x1="7.5" y1="15" x2="16.5" y2="15"/></>,
  bug:         <><rect x="8" y="6" width="8" height="14" rx="4"/><path d="M19 7l-3 2M5 7l3 2M3 13h3M18 13h3M19 19l-3-2M5 19l3-2M12 2v4"/></>,
  msg:         <path d="M21 11.5a8.38 8.38 0 0 1-9 8.5 9.5 9.5 0 0 1-4-1L3 20l1.5-4a8.5 8.5 0 1 1 16.5-4.5z"/>,
  phone:       <><rect x="6" y="2" width="12" height="20" rx="3"/><line x1="10" y1="18" x2="14" y2="18"/></>,
  sync:        <><path d="M21 2v6h-6"/><path d="M3 12a9 9 0 0 1 15-6.7L21 8"/><path d="M3 22v-6h6"/><path d="M21 12a9 9 0 0 1-15 6.7L3 16"/></>,
  cpu:         <><rect x="6" y="6" width="12" height="12" rx="2"/><path d="M9 2v2M15 2v2M9 20v2M15 20v2M2 9h2M2 15h2M20 9h2M20 15h2"/></>,
  target:      <><circle cx="12" cy="12" r="9"/><circle cx="12" cy="12" r="5"/><circle cx="12" cy="12" r="1.5"/></>,
  pen:         <><path d="M12 19l7-7 3 3-7 7-3-3z"/><path d="M18 13l-1.5-7.5L2 2l3.5 14.5L13 18l5-5z"/><path d="M2 2l7.586 7.586"/><circle cx="11" cy="11" r="2"/></>,
  user:        <><circle cx="12" cy="8" r="4"/><path d="M4 21a8 8 0 0 1 16 0"/></>,
  eye:         <><path d="M1 12s4-7 11-7 11 7 11 7-4 7-11 7-11-7-11-7z"/><circle cx="12" cy="12" r="3"/></>,
  check:       <polyline points="20 6 9 17 4 12"/>,
  x:           <><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></>,
  menu:        <><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/></>,
  globe:       <><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15 15 0 0 1 0 20 15 15 0 0 1 0-20z"/></>,
  bolt:        <polygon points="13 2 3 14 11 14 10 22 21 10 13 10 13 2"/>,
  chevDown:    <polyline points="6 9 12 15 18 9"/>,
  dollar:      <><line x1="12" y1="1" x2="12" y2="23"/><path d="M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"/></>,
  clock:       <><circle cx="12" cy="12" r="9"/><polyline points="12 7 12 12 15 14"/></>,
  building:    <><rect x="4" y="3" width="16" height="18" rx="1"/><path d="M9 8h.01M15 8h.01M9 12h.01M15 12h.01M9 16h.01M15 16h.01"/></>,
  wave:        <><path d="M2 12c2-4 4-4 6 0s4 4 6 0 4-4 6 0"/></>,
};
const Icon = ({ name, size = 20, style, ...rest }) => (
  <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor"
    strokeWidth="1.75" strokeLinecap="round" strokeLinejoin="round" style={{ flexShrink: 0, ...style }} {...rest}>
    {ICON_PATHS[name]}
  </svg>
);

// ── Button ───────────────────────────────────────────────────────
const Btn = ({ variant = 'primary', size = 'md', icon, iconRight, children, as = 'button', ...rest }) => {
  const Tag = as;
  return (
    <Tag className={`tbtn tbtn-${variant} tbtn-${size}`} {...rest}>
      {icon && <Icon name={icon} size={size === 'lg' ? 18 : 16}/>}
      {children}
      {iconRight && <Icon name={iconRight} size={size === 'lg' ? 18 : 16}/>}
    </Tag>
  );
};

// ── Reveal-on-scroll: one shared IntersectionObserver ────────────
let _io;
function _ensureIO() {
  if (_io) return _io;
  _io = new IntersectionObserver((entries) => {
    entries.forEach((e) => { if (e.isIntersecting) { e.target.classList.add('in'); _io.unobserve(e.target); } });
  }, { threshold: 0.14, rootMargin: '0px 0px -8% 0px' });
  return _io;
}
const Reveal = ({ children, delay = 0, as = 'div', className = '', style, ...rest }) => {
  const ref = useRefC(null);
  useEffectC(() => { const el = ref.current; if (!el) return; _ensureIO().observe(el); }, []);
  const Tag = as;
  return <Tag ref={ref} className={`reveal ${className}`} data-d={delay || undefined} style={style} {...rest}>{children}</Tag>;
};

// ── Count-up when scrolled into view ─────────────────────────────
function useCountUp(target, { duration = 1400, decimals = 0 } = {}) {
  const ref = useRefC(null);
  const [val, setVal] = useStateC(0);
  useEffectC(() => {
    const el = ref.current; if (!el) return;
    let raf, started = false;
    const obs = new IntersectionObserver((ents) => {
      ents.forEach((e) => {
        if (e.isIntersecting && !started) {
          started = true;
          const t0 = performance.now();
          const tick = (now) => {
            const p = Math.min(1, (now - t0) / duration);
            const eased = 1 - Math.pow(1 - p, 3);
            setVal(target * eased);
            if (p < 1) raf = requestAnimationFrame(tick);
          };
          raf = requestAnimationFrame(tick);
          obs.unobserve(el);
        }
      });
    }, { threshold: 0.4 });
    obs.observe(el);
    return () => { cancelAnimationFrame(raf); obs.disconnect(); };
  }, [target]);
  const display = decimals ? val.toFixed(decimals) : Math.round(val).toLocaleString();
  return [ref, display];
}

Object.assign(window, { Icon, Btn, Reveal, useCountUp });
