/* global React */ const { useState, useEffect, useRef } = React; /* ---------------------------------------------------------------------------- Icon — inline Lucide-style paths (1.75 stroke, round). -------------------------------------------------------------------------- */ const ICONS = { arrowRight: , arrowUpRight: , chevronRight: , chevronDown: , activity: , shieldCheck: <>, users: <>, trendingUp: <>, barChart: <>, lineChart: <>, mapPin: <>, target: <>, handshake: <>, building: <>, landmark: <>, phone: , message: , check: , menu: <>, x: <>, heartPulse: <>, heart: , clipboardCheck: <>, fileText: <>, globe: <>, award: <>, sparkles: <>, layers: <>, compass: <>, lock: <>, calendar: <>, linkedin: <>, twitter: , facebook: , youtube: <>, mail: <>, stethoscope: <>, database: <>, image: <>, }; function Icon({ name, size = 22, stroke = 1.75, className = "", style = {} }) { return ( ); } /* ---- Button ------------------------------------------------------------- */ function Button({ children, variant = "primary", size = "md", icon = "arrowRight", showIcon = false, onClick, href, type, className = "" }) { const cls = `hb hb-${variant} hb-${size} ${className}`; const inner = <>{children}{showIcon && icon && }; if (href) return {inner}; return ; } function Eyebrow({ children, color }) { return {children}; } function SectionHead({ eyebrow, title, lead, align = "left", eyebrowColor, max }) { return (
{eyebrow && {eyebrow}} {title &&

{title}

} {lead &&

{lead}

} ); } /* ---- Reveal: scroll-in animation (respects reduced motion) -------------- */ function Reveal({ children, className = "", style = {}, as = "div", delay = 0, y = 22 }) { const ref = useRef(null); const [seen, setSeen] = useState(false); useEffect(() => { const el = ref.current; if (!el) return; if (window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches) { setSeen(true); return; } // Already in view on mount? Reveal immediately (covers above-the-fold + no-IO contexts). const r = el.getBoundingClientRect(); if (r.top < window.innerHeight * 0.95 && r.bottom > 0) { setSeen(true); return; } let fallback = 0; const io = new IntersectionObserver((entries) => { entries.forEach((e) => { if (e.isIntersecting) { setSeen(true); io.disconnect(); clearTimeout(fallback); } }); }, { threshold: 0.12, rootMargin: "0px 0px -8% 0px" }); io.observe(el); // Safety net: content must never stay hidden if IO never fires. fallback = setTimeout(() => { setSeen(true); io.disconnect(); }, 1200); return () => { io.disconnect(); clearTimeout(fallback); }; }, []); const Tag = as; return ( {children} ); } /* ---- Parallax: subtle scroll translate for decorative / media ----------- */ function useParallax(factor = 0.12) { const ref = useRef(null); useEffect(() => { const el = ref.current; if (!el) return; if (window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches) return; let raf = 0; const onScroll = () => { if (raf) return; raf = requestAnimationFrame(() => { raf = 0; const r = el.getBoundingClientRect(); const center = r.top + r.height / 2 - window.innerHeight / 2; el.style.transform = `translate3d(0, ${(-center * factor).toFixed(1)}px, 0)`; }); }; window.addEventListener("scroll", onScroll, { passive: true }); onScroll(); return () => window.removeEventListener("scroll", onScroll); }, [factor]); return ref; } /* ---- Img: real photo in a rounded frame with rollover zoom -------------- */ function Img({ src, alt = "", ratio, className = "", parallax = 0, imgClass = "", style = {}, eager = false }) { const pref = useParallax(parallax); return (
{alt}
); } /* Photo placeholder kept for back-compat */ function Photo({ label, ratio = "4 / 3", className = "", style = {} }) { return (
{label}
); } /* ---- CountUp: animate a number to its target when scrolled into view ----- */ function CountUp({ to, prefix = "", suffix = "", decimals = 0, format = false, dur = 1500 }) { const ref = useRef(null); const [val, setVal] = useState(0); const started = useRef(false); useEffect(() => { const el = ref.current; if (!el) return; const run = () => { if (started.current) return; started.current = true; const start = performance.now(); const tick = (now) => { const p = Math.min(1, (now - start) / dur); const eased = 1 - Math.pow(1 - p, 3); setVal(to * eased); if (p < 1) requestAnimationFrame(tick); else setVal(to); }; requestAnimationFrame(tick); }; if (window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches) { setVal(to); return; } const r = el.getBoundingClientRect(); if (r.top < window.innerHeight * 0.92 && r.bottom > 0) { run(); return; } const io = new IntersectionObserver((es) => es.forEach((e) => { if (e.isIntersecting) { run(); io.disconnect(); } }), { threshold: 0.3 }); io.observe(el); const fb = setTimeout(run, 1600); return () => { io.disconnect(); clearTimeout(fb); }; }, [to]); const num = format ? Math.round(val).toLocaleString() : (decimals ? val.toFixed(decimals) : Math.round(val).toString()); return {prefix}{num}{suffix}; } /* ---- ImpactBand: capabilities section, reused on every page ------------- */ const IMPACT_CAPS = [ { ic: "users", t: "Population health management" }, { ic: "award", t: "HEDIS and Star Ratings support" }, { ic: "trendingUp", t: "Quality improvement" }, { ic: "target", t: "Care gap closure" }, { ic: "heart", t: "Member engagement and retention" }, { ic: "barChart", t: "Risk adjustment support" }, { ic: "compass", t: "Health equity strategy" }, { ic: "lineChart", t: "Value-based care performance" }, { ic: "mapPin", t: "Community-based outreach" }, { ic: "database", t: "Data-informed reporting and measurement" }, ]; function ImpactBand({ video = "assets/video/middle-2.mp4" }) { return (
What we do

Intelligence-driven. Human-centered. Built to close gaps.

HCDI helps clients identify priority populations, understand barriers to care, and activate outreach strategies that move people toward better health.

Our work supports
{IMPACT_CAPS.map((c, i) => ( {c.t} ))}
); } Object.assign(window, { Icon, Button, Eyebrow, SectionHead, Reveal, useParallax, Img, Photo, CountUp, ImpactBand, useState, useEffect, useRef });