// ff-utils.jsx — small shared helpers + logo mark

const { useState, useEffect, useRef, useLayoutEffect, useMemo, useCallback } = React;

// Reveal-on-scroll wrapper. Adds .in once the element enters the viewport.
function Reveal({ as = "div", delay = 0, threshold = 0.15, className = "", style, children, ...rest }) {
  const ref = useRef(null);
  const [seen, setSeen] = useState(false);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    // Fallback — if IO never fires (some embed contexts), still reveal.
    const fallback = setTimeout(() => setSeen(true), 1200);
    if (typeof IntersectionObserver === "undefined") {
      setSeen(true);
      return () => clearTimeout(fallback);
    }
    const io = new IntersectionObserver(
      (entries) => {
        for (const e of entries) {
          if (e.isIntersecting) {
            setSeen(true);
            clearTimeout(fallback);
            io.disconnect();
          }
        }
      },
      { threshold, rootMargin: "0px 0px -40px 0px" }
    );
    io.observe(el);
    // Manual check after a tick in case IO is slow / inert.
    const tick = setTimeout(() => {
      const r = el.getBoundingClientRect();
      if (r.top < window.innerHeight && r.bottom > 0) {
        setSeen(true);
        clearTimeout(fallback);
        io.disconnect();
      }
    }, 50);
    return () => {
      io.disconnect();
      clearTimeout(fallback);
      clearTimeout(tick);
    };
  }, [threshold]);
  const Tag = as;
  const cls = `reveal ${delay ? "delay-" + delay : ""} ${seen ? "in" : ""} ${className}`;
  return (
    <Tag ref={ref} className={cls} style={style} {...rest}>
      {children}
    </Tag>
  );
}

// Animated counter — counts to `to` once visible.
function Counter({ to, duration = 1400, prefix = "", suffix = "", className, style, format }) {
  const ref = useRef(null);
  const [v, setV] = useState(0);
  const started = useRef(false);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    const start = () => {
      if (started.current) return;
      started.current = true;
      const t0 = performance.now();
      const tick = (now) => {
        const t = Math.min(1, (now - t0) / duration);
        const eased = 1 - Math.pow(1 - t, 3);
        setV(Math.round(to * eased));
        if (t < 1) requestAnimationFrame(tick);
      };
      requestAnimationFrame(tick);
    };
    // Fallback — always start the counter even if IO never fires.
    const fallback = setTimeout(start, 1200);
    if (typeof IntersectionObserver === "undefined") {
      start();
      return () => clearTimeout(fallback);
    }
    const io = new IntersectionObserver((entries) => {
      for (const e of entries) {
        if (e.isIntersecting) {
          clearTimeout(fallback);
          start();
        }
      }
    }, { threshold: 0.4 });
    io.observe(el);
    const tick = setTimeout(() => {
      const r = el.getBoundingClientRect();
      if (r.top < window.innerHeight && r.bottom > 0) {
        clearTimeout(fallback);
        start();
      }
    }, 50);
    return () => {
      io.disconnect();
      clearTimeout(fallback);
      clearTimeout(tick);
    };
  }, [to, duration]);
  const display = format ? format(v) : v.toLocaleString();
  return <span ref={ref} className={className} style={style}>{prefix}{display}{suffix}</span>;
}

// Logo mark — interlocking arc + flow-line glyph
function LogoMark({ size = 22, color = "currentColor", accent = "var(--accent)" }) {
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" aria-hidden="true">
      <circle cx="12" cy="12" r="10.5" stroke={color} strokeOpacity="0.35" strokeWidth="1" />
      <path
        d="M5 14 C 9 14, 9 8, 13 8 C 17 8, 17 14, 19 14"
        stroke={accent}
        strokeWidth="1.6"
        strokeLinecap="round"
        fill="none"
      />
      <circle cx="5" cy="14" r="1.6" fill={accent} />
      <circle cx="19" cy="14" r="1.6" fill={color} />
    </svg>
  );
}

// Section marker — animated accent rule + accent label. Index kept in signature for back-compat (rendered as aria only).
function SectionEyebrow({ index, label }) {
  const ref = useRef(null);
  const [seen, setSeen] = useState(false);
  useEffect(() => {
    const el = ref.current;
    if (!el || seen) return;
    if (typeof IntersectionObserver === "undefined") { setSeen(true); return; }
    const io = new IntersectionObserver(
      (entries) => {
        entries.forEach((e) => { if (e.isIntersecting) { setSeen(true); io.disconnect(); } });
      },
      { threshold: 0.5, rootMargin: "0px 0px -10% 0px" }
    );
    io.observe(el);
    return () => io.disconnect();
  }, [seen]);
  return (
    <div ref={ref} className={`eyebrow${seen ? " is-in" : ""}`} aria-label={label}>
      <span className="eyebrow-label">{label}</span>
    </div>
  );
}

// Font pairings
const FONT_PAIRS = {
  geist:   { sans: '"Geist"',         mono: '"Geist Mono"' },
  manrope: { sans: '"Manrope"',       mono: '"JetBrains Mono"' },
  inter:   { sans: '"Inter Tight"',   mono: '"IBM Plex Mono"' },
  space:   { sans: '"Space Grotesk"', mono: '"Space Mono"' },
};

// Full wordmark — W glyph + "wayrelay." White parts use currentColor;
// blue parts track var(--accent). Source: logo/White-blue-text-logo.svg
function BrandLogo({ height = 22, className = "", style = {} }) {
  return (
    <svg
      className={`brand-logo ${className}`}
      height={height}
      viewBox="0 0 738 127"
      fill="none"
      xmlns="http://www.w3.org/2000/svg"
      aria-label="Wayrelay"
      style={style}
    >
      <path fillRule="evenodd" clipRule="evenodd" d="M41.6135 96.8543L41.7736 97.0143L83.8868 54.9011L84 55.0143L84.2264 55.2407L125.84 96.8543L126 97.0143L126.16 96.8543L168 55.0143V84.2219L167.953 84.175L126 126.128L84.046 84.1759L83.8859 84.0158L83.7267 84.175L41.7736 126.128L0 84.3546L2.24563e-05 55.2407L41.6135 96.8543Z" fill="currentColor"/>
      <path d="M126 75.864L84.2264 34.0904L84.0469 33.9109L84 33.9577L83.8868 34.0709L83.7267 33.9109L42 75.6376V41.769L83.6604 0.10868L84 0.448303L84.2264 0.674718L125.611 42.0595L125.547 42.1238L125.712 42.2884L168 0V33.9577L167.953 33.9109L126 75.864Z" fill="var(--accent)"/>
      <path d="M728.389 98.3921C725.659 98.3921 723.312 97.4534 721.349 95.5761C719.472 93.6988 718.533 91.3948 718.533 88.6641C718.533 86.0188 719.472 83.7574 721.349 81.8801C723.312 80.0028 725.659 79.0641 728.389 79.0641C731.035 79.0641 733.296 80.0028 735.173 81.8801C737.051 83.7574 737.989 86.0188 737.989 88.6641C737.989 91.3948 737.051 93.6988 735.173 95.5761C733.296 97.4534 731.035 98.3921 728.389 98.3921Z" fill="currentColor"/>
      <path d="M673.774 122.84V121.816L684.27 97.2401L689.646 85.7201L711.15 32.6001H726.254V33.6241L688.75 122.84H673.774ZM684.27 97.2401L658.67 33.6241V32.6001H673.774L696.302 90.7121V97.2401H684.27Z" fill="currentColor"/>
      <path d="M623.956 99.1601C619.519 99.1601 615.551 98.3067 612.052 96.6001C608.639 94.8934 605.951 92.5041 603.988 89.4321C602.025 86.3601 601.044 82.8614 601.044 78.9361C601.044 72.8774 603.135 68.0561 607.316 64.4721C611.497 60.8027 617.513 58.6694 625.364 58.0721L650.452 56.0241V68.1841L627.54 70.1041C623.444 70.4454 620.5 71.2987 618.708 72.6641C616.916 74.0294 616.02 75.8641 616.02 78.1681C616.02 80.4721 617.044 82.3494 619.092 83.8001C621.14 85.2507 623.743 85.9761 626.9 85.9761C630.228 85.9761 633.215 85.1654 635.86 83.5441C638.591 81.8374 640.767 79.6614 642.388 77.0161C644.009 74.3707 644.82 71.5121 644.82 68.4401V57.8161C644.82 53.7201 643.455 50.3494 640.724 47.7041C637.993 44.9734 634.409 43.6081 629.972 43.6081C626.217 43.6081 623.103 44.5467 620.628 46.4241C618.239 48.2161 616.703 50.4774 616.02 53.2081H614.612L602.068 50.1361C603.604 44.3334 606.804 39.6401 611.668 36.0561C616.617 32.4721 622.761 30.6801 630.1 30.6801C639.231 30.6801 646.356 33.3254 651.476 38.6161C656.596 43.8214 659.156 51.2027 659.156 60.7601V97.2401H646.1V78.4241L651.348 79.1921C650.324 82.8614 648.489 86.2321 645.844 89.3041C643.199 92.2907 639.999 94.6801 636.244 96.4721C632.575 98.2641 628.479 99.1601 623.956 99.1601Z" fill="currentColor"/>
      <path d="M578.778 97.2401V5.08009L593.114 3.28809L593.498 4.31209V97.2401H578.778Z" fill="currentColor"/>
      <path d="M540.615 99.1601C534.044 99.1601 528.242 97.7094 523.207 94.8081C518.258 91.9067 514.375 87.8961 511.559 82.7761C508.743 77.6561 507.335 71.6827 507.335 64.8561C507.335 58.1147 508.7 52.1841 511.431 47.0641C514.247 41.8587 518.087 37.8481 522.951 35.0321C527.9 32.1307 533.575 30.6801 539.975 30.6801C546.375 30.6801 551.922 32.1734 556.615 35.1601C561.394 38.0614 565.106 42.1574 567.751 47.4481C570.482 52.7387 571.847 58.9254 571.847 66.0081V68.4401L569.927 70.3601H514.247V58.0721H565.191L557.383 61.0161C557.298 57.4321 556.444 54.3601 554.823 51.8001C553.287 49.1547 551.239 47.1494 548.679 45.7841C546.204 44.3334 543.388 43.6081 540.231 43.6081C536.818 43.6081 533.703 44.4187 530.887 46.0401C528.071 47.5761 525.895 49.7521 524.359 52.5681C522.823 55.2987 522.055 58.4987 522.055 62.1681V67.2881C522.055 70.7867 522.866 73.9867 524.487 76.8881C526.194 79.7041 528.455 81.9654 531.271 83.6721C534.087 85.3787 537.202 86.2321 540.615 86.2321C543.858 86.2321 546.802 85.3787 549.447 83.6721C552.178 81.8801 554.311 79.4907 555.847 76.5041H557.383L569.287 81.6241C566.727 87.1707 562.93 91.4801 557.895 94.5521C552.946 97.6241 547.186 99.1601 540.615 99.1601Z" fill="currentColor"/>
      <path d="M471.063 97.2401V32.6001H484.887V49.1121L481.175 48.8561C482.967 43.8214 485.954 39.8534 490.135 36.9521C494.317 34.0508 499.095 32.6001 504.471 32.6001H510.743V45.7841H502.295C498.967 45.7841 496.066 46.5521 493.591 48.0881C491.117 49.5388 489.197 51.6294 487.831 54.3601C486.466 57.0908 485.783 60.3334 485.783 64.0881V97.2401H471.063Z" fill="currentColor"/>
      <path d="M416.024 122.84V121.816L426.52 97.2401L431.896 85.7201L453.4 32.6001H468.504V33.6241L431 122.84H416.024ZM426.52 97.2401L400.92 33.6241V32.6001H416.024L438.552 90.7121V97.2401H426.52Z" fill="currentColor"/>
      <path d="M366.206 99.1601C361.769 99.1601 357.801 98.3067 354.302 96.6001C350.889 94.8934 348.201 92.5041 346.238 89.4321C344.276 86.3601 343.294 82.8614 343.294 78.9361C343.294 72.8774 345.385 68.0561 349.566 64.4721C353.748 60.8027 359.764 58.6694 367.614 58.0721L392.702 56.0241V68.1841L369.79 70.1041C365.694 70.4454 362.75 71.2987 360.958 72.6641C359.166 74.0294 358.27 75.8641 358.27 78.1681C358.27 80.4721 359.294 82.3494 361.342 83.8001C363.39 85.2507 365.993 85.9761 369.15 85.9761C372.478 85.9761 375.465 85.1654 378.11 83.5441C380.841 81.8374 383.017 79.6614 384.638 77.0161C386.26 74.3707 387.07 71.5121 387.07 68.4401V57.8161C387.07 53.7201 385.705 50.3494 382.974 47.7041C380.244 44.9734 376.66 43.6081 372.222 43.6081C368.468 43.6081 365.353 44.5467 362.878 46.4241C360.489 48.2161 358.953 50.4774 358.27 53.2081H356.862L344.318 50.1361C345.854 44.3334 349.054 39.6401 353.918 36.0561C358.868 32.4721 365.012 30.6801 372.35 30.6801C381.481 30.6801 388.606 33.3254 393.726 38.6161C398.846 43.8214 401.406 51.2027 401.406 60.7601V97.2401H388.35V78.4241L393.598 79.1921C392.574 82.8614 390.74 86.2321 388.094 89.3041C385.449 92.2907 382.249 94.6801 378.494 96.4721C374.825 98.2641 370.729 99.1601 366.206 99.1601Z" fill="currentColor"/>
      <path d="M305.152 97.2401L277.632 7.64014H292.608L318.592 94.5521L319.744 97.2401H305.152ZM305.152 97.2401L305.792 94.5521L331.264 7.64014H346.24V8.66414L319.744 97.2401H305.152ZM250.496 97.2401L224 8.66414V7.64014H238.976L264.448 94.5521L265.088 97.2401H250.496ZM250.496 97.2401L251.648 94.5521L277.632 7.64014H292.608L265.088 97.2401H250.496Z" fill="currentColor"/>
    </svg>
  );
}

// Icon-only mark — W glyph. Source: logo/White-blue-logo.svg
function BrandIcon({ height = 28, className = "", style = {} }) {
  return (
    <svg
      className={`brand-icon ${className}`}
      height={height}
      viewBox="0 0 353 265"
      fill="none"
      xmlns="http://www.w3.org/2000/svg"
      aria-label="Wayrelay"
      style={style}
    >
      <defs>
        <linearGradient id="brand-icon-glass-bottom" x1="0" y1="0" x2="0" y2="1">
          <stop offset="0%"   stopColor="currentColor" stopOpacity="0.95" />
          <stop offset="45%"  stopColor="currentColor" stopOpacity="0.6" />
          <stop offset="55%"  stopColor="currentColor" stopOpacity="1" />
          <stop offset="100%" stopColor="currentColor" stopOpacity="0.75" />
        </linearGradient>
        <linearGradient id="brand-icon-glass-top" x1="0" y1="0" x2="0" y2="1">
          <stop offset="0%"   stopColor="var(--accent)" stopOpacity="1" />
          <stop offset="50%"  stopColor="var(--accent)" stopOpacity="0.75" />
          <stop offset="100%" stopColor="var(--accent)" stopOpacity="0.95" />
        </linearGradient>
      </defs>
      <path fillRule="evenodd" clipRule="evenodd" d="M87.4379 203.509L87.7743 203.846L176.262 115.358L176.5 115.596L176.976 116.071L264.414 203.509L264.75 203.846L265.086 203.509L353 115.596V176.966L352.901 176.868L264.75 265.019L176.597 176.87L176.26 176.533L175.926 176.868L87.7743 265.019L0 177.245L4.7185e-05 116.071L87.4379 203.509Z" fill="url(#brand-icon-glass-bottom)"/>
      <path d="M264.75 159.405L176.976 71.6304L176.598 71.2532L176.5 71.3517L176.262 71.5895L175.926 71.2532L88.25 158.929V87.7647L175.786 0.228357L176.5 0.941969L176.976 1.41771L263.933 88.3751L263.798 88.5102L264.144 88.8561L353 0V71.3517L352.901 71.2532L264.75 159.405Z" fill="url(#brand-icon-glass-top)"/>
    </svg>
  );
}

Object.assign(window, { Reveal, Counter, LogoMark, BrandLogo, BrandIcon, SectionEyebrow, FONT_PAIRS });
