/* UPOLT site — shared marketing primitives (icon, container, overline, buttons, sectioning). */

/* Inline Lucide-style icon paths, rendered directly as React SVG (no external script mutating
   the DOM outside React's control — that used to race React's own reconciliation and could crash
   the page). Stroke-based, 24x24 viewBox, matches Lucide's outlined style. */
const ICON_PATHS = {
  "arrow-right": '<line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/>',
  check: '<polyline points="20 6 9 17 4 12"/>',
  hexagon: '<path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/>',
  workflow: '<path d="M12 3 4 7v10l8 4 8-4V7z"/><path d="M4 7l8 4 8-4"/><path d="M12 11v10"/>',
  "shield-check": '<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/><polyline points="9 12 12 15 16 10"/>',
  quote: '<path d="M3 21c3 0 7-1 7-8V5c0-1.25-.76-2-2-2H4c-1.25 0-2 .75-2 2v6c0 1.25.75 2 2 2 1 0 1 0 1 1v1c0 1-1 2-2 2s-1 1-1 1"/><path d="M15 21c3 0 7-1 7-8V5c0-1.25-.76-2-2-2h-4c-1.25 0-2 .75-2 2v6c0 1.25.75 2 2 2h.75c0 2.25 0 4-2.75 4"/>',
  mail: '<rect x="2" y="4" width="20" height="16" rx="2"/><path d="m22 6-8.97 6.7a1.94 1.94 0 0 1-2.06 0L2 6"/>',
  "message-square": '<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/>',
  "life-buoy": '<circle cx="12" cy="12" r="10"/><circle cx="12" cy="12" r="4"/><path d="m4.93 4.93 4.24 4.24"/><path d="m14.83 9.17 4.24-4.24"/><path d="m14.83 14.83 4.24 4.24"/><path d="m9.17 14.83-4.24 4.24"/>',
  "chevron-down": '<polyline points="6 9 12 15 18 9"/>',
  activity: '<polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/>',
  "trending-up": '<polyline points="23 6 13.5 15.5 8.5 10.5 1 18"/><polyline points="17 6 23 6 23 12"/>',
  boxes: '<path d="M12 3 4 7v10l8 4 8-4V7z"/><path d="M4 7l8 4 8-4"/><path d="M12 11v10"/>',
  "line-chart": '<path d="M3 3v18h18"/><path d="m19 9-5 5-4-4-3 3"/>',
  sparkles: '<path d="M9.94 15.5A2 2 0 0 0 8.5 14.06l-6.13-1.58a.5.5 0 0 1 0-.96l6.13-1.59A2 2 0 0 0 9.94 8.5l1.58-6.14a.5.5 0 0 1 .96 0l1.58 6.14a2 2 0 0 0 1.44 1.44l6.13 1.58a.5.5 0 0 1 0 .96l-6.13 1.58a2 2 0 0 0-1.44 1.44l-1.58 6.14a.5.5 0 0 1-.96 0z"/>',
  "file-plus-2": '<path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z"/><polyline points="15 2 15 7 20 7"/><line x1="12" y1="12" x2="12" y2="18"/><line x1="9" y1="15" x2="15" y2="15"/>',
  "user-check": '<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><polyline points="16 11 18 13 22 9"/>',
  "badge-check": '<path d="M3.85 8.62a4 4 0 0 1 4.78-4.77 4 4 0 0 1 6.74 0 4 4 0 0 1 4.78 4.78 4 4 0 0 1 0 6.74 4 4 0 0 1-4.77 4.78 4 4 0 0 1-6.75 0 4 4 0 0 1-4.78-4.77 4 4 0 0 1 0-6.76Z"/><polyline points="9 12 11 14 15 10"/>',
  send: '<path d="m22 2-7 20-4-9-9-4Z"/><path d="M22 2 11 13"/>',
  "mouse-pointer-click": '<path d="M14 4.1 12 6"/><path d="m5.1 8-2.9-.8"/><path d="m6 12-1.9 2"/><path d="M7.2 2.2 8 5.1"/><path d="m9.04 9.69 7.38 1.98a.5.5 0 0 1 .1.93l-2.9 1.78a1 1 0 0 0-.32.32l-1.78 2.9a.5.5 0 0 1-.93-.1z"/>',
  "git-branch": '<line x1="6" y1="3" x2="6" y2="15"/><circle cx="18" cy="6" r="3"/><circle cx="6" cy="18" r="3"/><path d="M18 9a9 9 0 0 1-9 9"/>',
  history: '<path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/><path d="M12 7v5l4 2"/>',
  search: '<circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/>',
  "list-checks": '<path d="m3 17 2 2 4-4"/><path d="m3 7 2 2 4-4"/><path d="M13 6h8"/><path d="M13 12h8"/><path d="M13 18h8"/>',
  lock: '<rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/>',
  compass: '<circle cx="12" cy="12" r="10"/><polygon points="16.24 7.76 14.12 14.12 7.76 16.24 9.88 9.88 16.24 7.76"/>',
  telescope: '<path d="m10.07 12.49-6.18 1.32a.93.93 0 0 1-1.1-.7l-.54-2.15a1.07 1.07 0 0 1 .69-1.27l13.5-4.44"/><path d="m13.56 11.75 4.33-.92"/><path d="m16 21-3.1-6.21"/><path d="M16.49 5.94a2 2 0 0 1 1.45-2.42l1.09-.28a1 1 0 0 1 1.22.73l1.51 6.06a1 1 0 0 1-.73 1.22l-1.09.27a2 2 0 0 1-2.42-1.45z"/><path d="m6.16 8.63 1.11 4.46"/><path d="m8 21 3.1-6.21"/><circle cx="12" cy="13" r="2"/>',
  eye: '<path d="M2 12s3-7 10-7 10 7 10 7-3 7-10 7-10-7-10-7Z"/><circle cx="12" cy="12" r="3"/>',
  feather: '<path d="M20.24 12.24a6 6 0 0 0-8.49-8.49L5 10.5V19h8.5z"/><line x1="16" y1="8" x2="2" y2="22"/><line x1="17.5" y1="15" x2="9" y2="15"/>',
  layers: '<path d="m12.83 2.18-8.58 3.9a1 1 0 0 0 0 1.83l8.58 3.91a2 2 0 0 0 1.66 0l8.58-3.9a1 1 0 0 0 0-1.83l-8.58-3.91a2 2 0 0 0-1.66 0Z"/><path d="M2 12a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.66 0l8.58-3.9A1 1 0 0 0 22 12"/><path d="M2 17a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.66 0l8.58-3.9A1 1 0 0 0 22 17"/>',
  briefcase: '<rect x="2" y="7" width="20" height="14" rx="2"/><path d="M16 21V5a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16"/>',
  headphones: '<path d="M3 14h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2H4a1 1 0 0 1-1-1v-6a9 9 0 0 1 18 0v6a1 1 0 0 1-1 1h-2a2 2 0 0 1-2-2v-3a2 2 0 0 1 2-2h3"/>',
};

function Ico({ n, s = 20, c = "currentColor", style = {} }) {
  return (
    <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"
      style={{ display: "inline-flex", flex: "none", ...style }}
      dangerouslySetInnerHTML={{ __html: ICON_PATHS[n] || "" }} />
  );
}

function Container({ children, style = {}, className = "" }) {
  return <div className={("upolt-content " + className).trim()} style={{ maxWidth: "var(--content-max)", margin: "0 auto", padding: "0 40px", ...style }}>{children}</div>;
}

function Overline({ children, onDark = false, style = {} }) {
  return (
    <div style={{ fontSize: 13, fontWeight: 700, letterSpacing: "0.1em", textTransform: "uppercase", color: onDark ? "var(--teal-400)" : "var(--text-accent)", ...style }}>
      {children}
    </div>
  );
}

/* Marketing button — anchor based, supports cross-page hrefs. Mirrors the DS button palette. */
function Btn({ children, variant = "primary", size = "lg", iconLeft, iconRight, href = "#", onClick, style = {} }) {
  const [h, setH] = React.useState(false);
  const [a, setA] = React.useState(false);
  const sizes = { sm: { height: 40, pad: "0 16px", fs: 14 }, md: { height: 46, pad: "0 20px", fs: 15 }, lg: { height: 52, pad: "0 24px", fs: 16 } };
  const s = sizes[size] || sizes.lg;
  const pal = {
    primary: { background: a ? "var(--accent-press)" : h ? "var(--accent-hover)" : "var(--accent)", color: "#fff", border: "1px solid transparent" },
    secondary: { background: a ? "var(--surface-active)" : h ? "var(--surface-hover)" : "transparent", color: "var(--text-primary)", border: "1px solid var(--graphite-900)" },
    ghost: { background: h ? "var(--surface-hover)" : "transparent", color: "var(--text-primary)", border: "1px solid transparent" },
    inverse: { background: a ? "var(--graphite-200)" : h ? "var(--graphite-100)" : "#fff", color: "var(--graphite-900)", border: "1px solid transparent" },
    ghostInverse: { background: h ? "rgba(255,255,255,0.10)" : "transparent", color: "#fff", border: "1px solid rgba(255,255,255,0.28)" },
  }[variant];
  const handle = (e) => { if (href === "#" || !href) e.preventDefault(); if (onClick) onClick(e); };
  return (
    <a href={href} onClick={handle}
      onMouseEnter={() => setH(true)} onMouseLeave={() => { setH(false); setA(false); }}
      onMouseDown={() => setA(true)} onMouseUp={() => setA(false)}
      style={{ display: "inline-flex", alignItems: "center", justifyContent: "center", gap: 8, height: s.height, padding: s.pad, fontFamily: "var(--font-sans)", fontSize: s.fs, fontWeight: 600, letterSpacing: "-0.01em", borderRadius: "var(--radius-button)", textDecoration: "none", cursor: "pointer", whiteSpace: "nowrap", transition: "background var(--motion-fast) var(--ease-standard), border-color var(--motion-fast) var(--ease-standard)", ...pal, ...style }}>
      {iconLeft}{children}{iconRight}
    </a>
  );
}

/* Inline text link with the teal "Learn more →" treatment. */
function TextLink({ children, href = "#", onDark = false, style = {} }) {
  const [h, setH] = React.useState(false);
  return (
    <a href={href} onClick={e => { if (href === "#") e.preventDefault(); }}
      onMouseEnter={() => setH(true)} onMouseLeave={() => setH(false)}
      style={{ display: "inline-flex", alignItems: "center", gap: 6, fontFamily: "var(--font-sans)", fontSize: 15, fontWeight: 600, color: onDark ? "var(--teal-400)" : "var(--text-accent)", textDecoration: "none", whiteSpace: "nowrap", ...style }}>
      {children}
      <span style={{ display: "inline-flex", transition: "transform var(--motion-fast) var(--ease-standard)", transform: h ? "translateX(3px)" : "none" }}><Ico n="arrow-right" s={16} /></span>
    </a>
  );
}

/* Scroll/entrance reveal — content is visible by default; the fade-up is a pure CSS
   animation layered on top, so content never stays hidden if animations are throttled. */
function Reveal({ children, delay = 0, y = 16, style = {} }) {
  return (
    <div className="upolt-reveal" style={{ "--reveal-y": `${y}px`, animationDelay: delay ? `${delay}ms` : undefined, ...style }}>
      {children}
    </div>
  );
}

/* Fires true once the element scrolls into view. */
function useInView(ref, { threshold = 0.3 } = {}) {
  const [inView, setInView] = React.useState(false);
  React.useEffect(() => {
    if (!ref.current) return;
    if (typeof IntersectionObserver === "undefined") { setInView(true); return; }
    const io = new IntersectionObserver(([e]) => {
      if (e.isIntersecting) { setInView(true); io.disconnect(); }
    }, { threshold });
    io.observe(ref.current);
    return () => io.disconnect();
  }, [ref, threshold]);
  return inView;
}

/* Counts up from 0 to target when `active` becomes true. */
function useCountUp(target, active, { duration = 1200 } = {}) {
  const [val, setVal] = React.useState(0);
  React.useEffect(() => {
    if (!active) return;
    let raf, start;
    const tick = (ts) => {
      if (start == null) start = ts;
      const p = Math.min(1, (ts - start) / duration);
      const eased = 1 - Math.pow(1 - p, 3);
      setVal(target * eased);
      if (p < 1) raf = requestAnimationFrame(tick);
      else setVal(target);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [target, active, duration]);
  return val;
}

/* Safety net around the page root: the Lucide icon script mutates <i data-lucide> nodes into
   <svg> outside React's control on an interval. If that swap races a React re-render (e.g. the
   contact form swapping to its success state) React can throw trying to remove a node Lucide
   already detached, which otherwise unmounts the whole page to a blank screen. Catch that and
   remount cleanly instead of going blank. */
class ErrorBoundary extends React.Component {
  constructor(props) { super(props); this.state = { key: 0 }; }
  componentDidCatch() { this.setState(s => ({ key: s.key + 1 })); }
  render() { return <React.Fragment key={this.state.key}>{this.props.children}</React.Fragment>; }
}

Object.assign(window, { Ico, Container, Overline, Btn, TextLink, Reveal, useInView, useCountUp, ErrorBoundary });
