// Shared utilities + SVG placeholder art components

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

// Hook: reveal on scroll
function useReveal() {
  const ref = useRef(null);
  useEffect(() => {
    const el = ref.current; if (!el) return;
    const io = new IntersectionObserver((entries) => {
      entries.forEach(e => { if (e.isIntersecting) { e.target.classList.add('in'); io.unobserve(e.target); } });
    }, { threshold: 0.15, rootMargin: '0px 0px -80px 0px' });
    io.observe(el);
    return () => io.disconnect();
  }, []);
  return ref;
}

// Hook: counter (animated)
function useCountUp(target, { duration = 1600, when = true } = {}) {
  const [v, setV] = useState(0);
  const started = useRef(false);
  useEffect(() => {
    if (!when || started.current) return;
    started.current = true;
    const start = performance.now();
    const tick = (t) => {
      const p = Math.min(1, (t - start) / duration);
      const eased = 1 - Math.pow(1 - p, 3);
      setV(target * eased);
      if (p < 1) requestAnimationFrame(tick);
    };
    requestAnimationFrame(tick);
  }, [when, target, duration]);
  return v;
}

// Formats
const fmt = {
  money: (n) => `$${n.toFixed(0)}B`,
  int: (n) => Math.round(n).toLocaleString(),
};

// Reveal wrapper
function Reveal({ children, delay = 0, as = 'div', className = '', ...rest }) {
  const r = useReveal();
  const Tag = as;
  const dClass = delay ? ` r-${delay}` : '';
  return <Tag ref={r} className={`reveal${dClass} ${className}`} {...rest}>{children}</Tag>;
}

// Logo mark
function LogoMark({ size = 22, color = 'var(--ink)' }) {
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" aria-hidden>
      <path d="M3 21 L3 11 L12 3 L21 11 L21 21 Z" stroke={color} strokeWidth="1.6" strokeLinejoin="round" fill="none" />
      <path d="M8 21 L8 14 L16 14 L16 21" stroke={color} strokeWidth="1.6" strokeLinejoin="round" fill="none" />
      <circle cx="12" cy="9" r="1.3" fill="var(--accent)" />
    </svg>
  );
}

// Arrow
const ArrowRight = ({ size = 16 }) => (
  <svg width={size} height={size} viewBox="0 0 16 16" fill="none" aria-hidden>
    <path d="M3 8 H13 M9 4 L13 8 L9 12" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" />
  </svg>
);

// Site identity — single source of truth, set in index.html before this
// script loads. Components interpolate from window.__site rather than
// hardcoding project/place names.
const SITE = (typeof window !== 'undefined' && window.__site) || {
  park: 'Technology Park', county: 'the county', state: '', sponsor: 'the project sponsor', locationLine: '',
};

// jumpToSection — reusable smooth-scroll-with-offset + pulse-ring highlight.
// Extracted from the old CompareStrip's goTo() so the Hero CTA and the
// Elephants panels' "see the full story" links can reuse the exact same
// mechanism. Uses history.replaceState (not location.hash=) so it doesn't
// fire a hashchange event and double-trigger App's own scrollIntoView
// handler.
function jumpToSection(id) {
  if (typeof window === 'undefined' || typeof document === 'undefined') return;
  const el = document.getElementById(id);
  if (!el) return;
  const yOffset = -100; // account for fixed nav
  const y = el.getBoundingClientRect().top + window.scrollY + yOffset;
  const reduceMotion = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
  window.scrollTo({ top: y, behavior: reduceMotion ? 'auto' : 'smooth' });
  if (window.history && window.history.replaceState) {
    window.history.replaceState(null, '', `#${id}`);
  }
  el.classList.add('js-target-pulse');
  window.setTimeout(() => el.classList.remove('js-target-pulse'), 2200);
}

// Status badge — shared grammar used identically in Elephants, Water,
// Power, Regulations, and the Hero stat rail. Three states only:
// illustrative (demo figure), sourced (has a receipt), commitment (what a
// real deployment would bind to).
const STATUS_LABEL = { illustrative: 'Illustrative', sourced: 'Sourced', commitment: 'Commitment' };
function StatusBadge({ status = 'illustrative', className = '', style }) {
  const label = STATUS_LABEL[status] || STATUS_LABEL.illustrative;
  return (
    <span className={`status-badge status-badge--${status} ${className}`} style={style}>
      {label}
    </span>
  );
}

// Source receipt — dense, single-row citation for Elephants' "how you
// check" beat (2026-08-02 roundtable redesign: was a 3-line padded card,
// now one compact row per source so a panel with 3 receipts doesn't run
// long). title = headline of the source; body = one-line plain-English
// claim/description (what it actually says); issuer/date = who + when;
// checked = the site's own verification stamp, defaults to "Aug 2026".
function SourceReceipt({ title, body, issuer, date, url, checked = 'Aug 2026' }) {
  return (
    <a className="source-receipt" href={url} target="_blank" rel="noopener noreferrer">
      <span className="source-receipt-title">{title}</span>
      {body && <span className="source-receipt-body">{body}</span>}
      <span className="source-receipt-meta">
        {issuer}{issuer && date ? ' · ' : ''}{date}{(issuer || date) ? ' · ' : ''}Checked {checked}
        <ArrowRight size={10} />
      </span>
    </a>
  );
}

// Icon set
const Icons = {
  Drop: ({ size = 24 }) => (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" aria-hidden>
      <path d="M12 3 C 7 10, 5 14, 5 17 a7 7 0 0 0 14 0 c 0 -3 -2 -7 -7 -14 Z" stroke="currentColor" strokeWidth="1.4" strokeLinejoin="round" />
    </svg>
  ),
  Leaf: ({ size = 24 }) => (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" aria-hidden>
      <path d="M20 4 C 10 4, 4 10, 4 20 C 14 20, 20 14, 20 4 Z M6 18 L 16 8" stroke="currentColor" strokeWidth="1.4" strokeLinejoin="round" />
    </svg>
  ),
  Wave: ({ size = 24 }) => (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" aria-hidden>
      <path d="M3 9 Q 6 5, 9 9 T 15 9 T 21 9 M3 15 Q 6 11, 9 15 T 15 15 T 21 15" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" />
    </svg>
  ),
  Bolt: ({ size = 24 }) => (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" aria-hidden>
      <path d="M13 2 L4 14 H11 L9 22 L20 10 H13 Z" stroke="currentColor" strokeWidth="1.4" strokeLinejoin="round" />
    </svg>
  ),
  Shield: ({ size = 24 }) => (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" aria-hidden>
      <path d="M12 3 L20 6 V12 C 20 17, 16 20, 12 22 C 8 20, 4 17, 4 12 V6 Z" stroke="currentColor" strokeWidth="1.4" strokeLinejoin="round" />
    </svg>
  ),
  Truck: ({ size = 24 }) => (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" aria-hidden>
      <rect x="2" y="7" width="12" height="9" stroke="currentColor" strokeWidth="1.4" />
      <path d="M14 10 H 19 L 22 14 V16 H14 Z" stroke="currentColor" strokeWidth="1.4" strokeLinejoin="round" />
      <circle cx="7" cy="18" r="2" stroke="currentColor" strokeWidth="1.4" />
      <circle cx="17" cy="18" r="2" stroke="currentColor" strokeWidth="1.4" />
    </svg>
  ),
  Briefcase: ({ size = 24 }) => (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" aria-hidden>
      <rect x="3" y="7" width="18" height="13" rx="2" stroke="currentColor" strokeWidth="1.4" />
      <path d="M9 7 V5 a2 2 0 0 1 2 -2 h2 a2 2 0 0 1 2 2 V7" stroke="currentColor" strokeWidth="1.4" />
    </svg>
  ),
  School: ({ size = 24 }) => (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" aria-hidden>
      <path d="M4 10 L12 5 L20 10 V20 H4 Z" stroke="currentColor" strokeWidth="1.4" strokeLinejoin="round" />
      <path d="M10 20 V14 H14 V20" stroke="currentColor" strokeWidth="1.4" />
    </svg>
  ),
  Home: ({ size = 24 }) => (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" aria-hidden>
      <path d="M4 11 L12 4 L20 11 V20 H4 Z" stroke="currentColor" strokeWidth="1.4" strokeLinejoin="round" />
    </svg>
  ),
  Speaker: ({ size = 24 }) => (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" aria-hidden>
      <path d="M4 10 H8 L13 6 V18 L8 14 H4 Z" stroke="currentColor" strokeWidth="1.4" strokeLinejoin="round" />
      <path d="M16 9 Q 19 12, 16 15 M18 6 Q 23 12, 18 18" stroke="currentColor" strokeWidth="1.4" />
    </svg>
  ),
  Moon: ({ size = 24 }) => (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" aria-hidden>
      <path d="M20 14 A 8 8 0 1 1 10 4 A 6 6 0 0 0 20 14 Z" stroke="currentColor" strokeWidth="1.4" strokeLinejoin="round" />
    </svg>
  ),
  Sun: ({ size = 24 }) => (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" aria-hidden>
      <circle cx="12" cy="12" r="4" stroke="currentColor" strokeWidth="1.4" />
      {[0,45,90,135,180,225,270,315].map(a => {
        const r1 = 6.5, r2 = 9.5;
        const x1 = 12 + Math.cos(a*Math.PI/180)*r1, y1 = 12 + Math.sin(a*Math.PI/180)*r1;
        const x2 = 12 + Math.cos(a*Math.PI/180)*r2, y2 = 12 + Math.sin(a*Math.PI/180)*r2;
        return <line key={a} x1={x1} y1={y1} x2={x2} y2={y2} stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" />;
      })}
    </svg>
  ),
  Chat: ({ size = 24 }) => (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" aria-hidden>
      <path d="M4 6 h16 v11 h-7 l-4 4 v-4 H4 Z" stroke="currentColor" strokeWidth="1.4" strokeLinejoin="round" />
    </svg>
  ),
  Plus: ({ size = 16 }) => (
    <svg width={size} height={size} viewBox="0 0 16 16" fill="none" aria-hidden>
      <path d="M8 3 V13 M3 8 H13" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" />
    </svg>
  ),
  // Added 2026-08-03 (design pass) — generator/backup-power topic icon for
  // the hero's nine question cards. A simple genset silhouette: housing +
  // exhaust stack, not a literal engine diagram.
  Generator: ({ size = 24 }) => (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" aria-hidden>
      <rect x="3" y="10" width="15" height="9" rx="1.5" stroke="currentColor" strokeWidth="1.4" />
      <path d="M17 13 H21 V19 H17" stroke="currentColor" strokeWidth="1.4" strokeLinejoin="round" />
      <path d="M8 10 V6 a2 2 0 0 1 2 -2 h1" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" />
      <circle cx="7.5" cy="14.5" r="1.6" stroke="currentColor" strokeWidth="1.3" />
      <path d="M12.5 13.2 L11 16.2 H13.4 L11.9 19" stroke="currentColor" strokeWidth="1.3" strokeLinejoin="round" strokeLinecap="round" />
    </svg>
  ),
  // Added 2026-08-03 (design pass) — "the process" topic icon (decision /
  // public vote), a checked ballot rather than a literal gavel.
  Ballot: ({ size = 24 }) => (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" aria-hidden>
      <rect x="4" y="3" width="16" height="18" rx="1.5" stroke="currentColor" strokeWidth="1.4" />
      <path d="M8 9 H16 M8 13 H16" stroke="currentColor" strokeWidth="1.3" strokeLinecap="round" />
      <rect x="7.2" y="15.6" width="4.2" height="4.2" rx=".8" stroke="currentColor" strokeWidth="1.2" />
      <path d="M8.1 17.7 L9 18.6 L10.6 16.7" stroke="currentColor" strokeWidth="1.2" strokeLinecap="round" strokeLinejoin="round" />
    </svg>
  ),
};

// ---------------------------------------------------------------------
// Signature texture system (2026-08-03 design pass) — Prairie Gate's
// landscape identity uses prairie-grass line art + topographic contour
// lines as its ownable motif. Inline SVG only,
// restrained: a quiet corner/edge backdrop, never behind body text, never
// stock photography. Both accept a `color` prop so they inherit the
// current tone (wheat on paper, on-ink-line on the dark band).
function TextureGrass({ width = 260, height = 130, color = 'currentColor', opacity = .5, className = '' }) {
  // Hand-set blade paths (not a repeating tile) — a natural, uneven prairie
  // silhouette growing up from a baseline. Heights vary; a few blades bend.
  const blades = [
    'M4,130 C2,108 10,84 6,58',
    'M14,130 C17,104 9,80 15,50',
    'M24,130 C22,100 30,70 25,36',
    'M35,130 C38,106 30,86 36,64',
    'M46,130 C44,98 53,66 47,30',
    'M58,130 C61,110 52,90 59,68',
    'M70,130 C67,96 77,60 71,22',
    'M82,130 C85,108 76,88 83,66',
    'M94,130 C91,100 101,68 95,34',
    'M106,130 C109,112 100,92 107,72',
    'M118,130 C115,94 126,56 119,18',
    'M130,130 C133,110 124,88 131,64',
    'M142,130 C139,98 150,64 143,28',
    'M154,130 C157,112 148,92 155,70',
    'M166,130 C163,96 174,58 167,20',
    'M178,130 C181,108 172,86 179,62',
    'M190,130 C187,100 197,68 191,32',
    'M202,130 C205,112 196,92 203,70',
  ];
  return (
    <svg width={width} height={height} viewBox="0 0 210 130" className={className}
      style={{ opacity, color }} aria-hidden focusable="false">
      {blades.map((d, i) => (
        <path key={i} d={d} stroke={color} strokeWidth="1.3" strokeLinecap="round" fill="none" />
      ))}
    </svg>
  );
}

function TextureTopo({ width = 320, height = 320, color = 'currentColor', opacity = .5, className = '' }) {
  // Irregular concentric contour rings, like an elevation map — the
  // topographic half of the site's two-part motif.
  const rings = [
    'M160,34 C226,40 280,90 277,154 C274,222 214,280 148,277 C82,274 30,216 33,152 C36,88 94,28 160,34 Z',
    'M160,66 C210,71 253,110 250,158 C247,210 202,251 154,248 C104,245 65,204 68,156 C71,108 118,61 160,66 Z',
    'M160,98 C196,101 227,128 225,160 C223,196 192,225 156,223 C118,221 90,192 92,160 C94,128 132,95 160,98 Z',
    'M160,128 C182,130 200,145 199,163 C198,184 180,200 158,198 C136,196 120,180 121,162 C122,144 142,126 160,128 Z',
  ];
  return (
    <svg width={width} height={height} viewBox="0 0 320 320" className={className}
      style={{ opacity, color }} aria-hidden focusable="false">
      {rings.map((d, i) => (
        <path key={i} d={d} stroke={color} strokeWidth="1" fill="none" />
      ))}
    </svg>
  );
}

// Thin horizontal topo-line divider — used sparingly at 2-3 band
// transitions (not on every section) as the "signature texture" ornament.
function DividerTopo({ className = 'divider-topo' }) {
  return (
    <svg viewBox="0 0 1200 22" preserveAspectRatio="none" className={className} aria-hidden focusable="false">
      <path d="M0,11 C60,3 100,19 160,11 C220,3 260,19 320,11 C380,3 420,19 480,11 C540,3 580,19 640,11 C700,3 740,19 800,11 C860,3 900,19 960,11 C1020,3 1060,19 1120,11 C1150,7 1170,15 1200,11"
        stroke="currentColor" strokeWidth="1" fill="none" />
    </svg>
  );
}

const Textures = { Grass: TextureGrass, Topo: TextureTopo, DividerTopo };

Object.assign(window, {
  useReveal, useCountUp, Reveal, LogoMark, ArrowRight, Icons, fmt,
  SITE, jumpToSection, StatusBadge, SourceReceipt, Textures,
});
