/* ── LANDING SECTIONS ─────────────────────────────────────────────── */ /* ── Intersection helper ───────────────────────────────────────────── Replays the entrance animation every time the element re-enters the viewport (scroll down AND scroll up). Two observers: • Enter — fires when the element is comfortably in view (uses the caller's tighter threshold/rootMargin), flipping `seen` → true. • Leave — fires only when the element is *fully* off-screen, flipping `seen` → false so the next entry can replay. The reset happens out of view, so the user never sees the content disappear. ─────────────────────────────────────────────────────────────────── */ function useInView(ref, options = { threshold: 0.15, rootMargin: "-60px" }) { const [seen, setSeen] = useState(false); useEffect(() => { if (!ref.current) return; const el = ref.current; const enterObs = new IntersectionObserver((entries) => { entries.forEach(en => { if (en.isIntersecting) setSeen(true); }); }, options); enterObs.observe(el); const leaveObs = new IntersectionObserver((entries) => { entries.forEach(en => { if (!en.isIntersecting) setSeen(false); }); }, { threshold: 0, rootMargin: "0px" }); leaveObs.observe(el); return () => { enterObs.disconnect(); leaveObs.disconnect(); }; }, [ref]); return seen; } function Reveal({ children, delay = 0, y = 24, style }) { const ref = useRef(null); const seen = useInView(ref); return (
{children}
); } /* ── ANIMATED HEADING ───────────────────────────────────────────── Reusable heading w/ motion variants: word-up — words fade-up with stagger (default) letter-up — letters fade-up with stagger slide-right — words slide in from the right blur-in — words fade from blur to focus mask-reveal — sliding gold mask reveals each line highlight — gold highlight wipes behind text as you scroll in lines: ["plain", { text, gradient: true, underline: true }] ─────────────────────────────────────────────────────────────────── */ function AnimatedHeading({ lines, motion = "word-up", as: Tag = "h2", className, style, delay = 0 }) { const ref = useRef(null); const seen = useInView(ref, { threshold: 0.25, rootMargin: "-40px" }); const normLines = lines.map(l => (typeof l === "string" ? { text: l } : l)); return ( {normLines.map((line, li) => ( {line.underline && ( )} ))} ); } function HeadingLine({ text, motion, seen, startDelay, gradient }) { // Split text — letter-up splits into letters w/ word groups; others split into words if (motion === "mask-reveal") { return ( {text} ); } if (motion === "highlight") { return ( {text} ); } if (motion === "letter-up") { // split into words to preserve spacing, each word into chars const words = text.split(" "); let idx = 0; return ( <> {words.map((w, wi) => ( {[...w].map((ch) => { const i = idx++; return ( {ch} ); })} {wi < words.length - 1 ? " " : ""} ))} ); } // word-based motions const words = text.split(" "); return ( <> {words.map((w, i) => { let initial = "translateY(.5em)"; if (motion === "slide-right") initial = "translateX(.5em)"; if (motion === "blur-in") initial = "translateY(.2em)"; return ( {w} {i < words.length - 1 ? " " : ""} ); })} ); } /* ── HOW IT WORKS ────────────────────────────────────────────────── */ function HowItWorks() { const ref = useRef(null); const seen = useInView(ref); const STEPS = [ { step: "01", color: "#3b82f6", bg: "rgba(59,130,246,.12)", title: "Connect your sources", desc: "Link Meta Ads, Google Ads, or add a booking form. Leads flow in automatically from the platforms you already use.", icon: , }, { step: "02", color: "#8b5cf6", bg: "rgba(139,92,246,.12)", title: "Build your pipeline", desc: "Create custom stages that match your sales process. Assign owners, set up automation rules, invite your team.", icon: , }, { step: "03", color: "#10b981", bg: "rgba(16,185,129,.12)", title: "Close more deals", desc: "Automated follow-ups go out the moment a lead is ready. Your team focuses on conversations, not admin.", icon: , }, ]; return (

How it works

Three steps to a running sales operation. No configuration consultants needed.

{/* connecting line */}
{/* moving dot along line */}
{STEPS.map((s, i) => (
{s.icon} {s.step}

{s.title}

{s.desc}

))}
); } /* ── PIPELINE SECTION (animated kanban) ──────────────────────────── */ function PipelineSection() { const COLS = [ { label: "New", color: "#3b82f6", count: 12 }, { label: "Qualified", color: "#10b981", count: 8 }, { label: "Closed Won", color: "#059669", count: 38 }, ]; // Card "in motion" — every cycle, a card travels from col 0 → col 1 → col 2 const [phase, setPhase] = useState(0); useEffect(() => { const t = setInterval(() => setPhase(p => (p + 1) % 4), 1800); return () => clearInterval(t); }, []); return (

Visual pipeline

Drag & drop leads through stages. Filter by source, owner, or score. The board updates in real-time across your whole team — no refresh needed.

    {[ { bold: "Customisable stages", rest: ", match your sales motion exactly." }, { bold: "Live presence", rest: ", see who's on which lead, like a Figma file." }, { bold: "Smart filters", rest: ", saved views per role, market, or rep." }, ].map(it => (
  • {it.bold}{it.rest}

  • ))}
Explore the pipeline board
{COLS.map((col, ci) => (
{col.label} {col.count}
{ci === 0 && } {ci === 0 && } {ci === 1 && } {ci === 1 && } {ci === 2 && } {ci === 2 && }
))}
{/* Live presence chips */}
3 teammates viewing
{["#3b82f6","#8b5cf6","#C9A227"].map((c, i) => ( {["A","S","V"][i]} ))}
); } function PipelineCard({ title, sub, tag, tagColor, highlight, ring }) { return (
{title}
{sub}
{tag}
); } /* ── INTEGRATIONS — animated HUB (data flows into Kredoo) ──────── */ function IntegrationsSection() { // 10 integration nodes arranged around an ellipse const ITEMS = [ { name: "Meta Ads", color: "#1877F2", icon: ( ) }, { name: "Google", color: "#4285F4", icon: ( ) }, { name: "WhatsApp", color: "#25D366", icon: ( ) }, { name: "n8n", color: "#FF6D5A", icon: ( ) }, { name: "LinkedIn", color: "#0A66C2", icon: ( ) }, { name: "Instagram", color: "#d6249f", icon: ( ) }, { name: "Gmail", color: "#EA4335", icon: ( ) }, { name: "Outlook", color: "#0078D4", icon: ( ) }, { name: "Slack", color: "#E01E5A", icon: ( ) }, { name: "Webhooks", color: "#6C5CE7", icon: ( ) }, ]; // ellipse: cx 400, cy 270, rx 340, ry 210 const cx = 400, cy = 280, rx = 340, ry = 220; const pos = ITEMS.map((it, i) => { const angle = -Math.PI / 2 + (i / ITEMS.length) * Math.PI * 2; return { x: cx + rx * Math.cos(angle), y: cy + ry * Math.sin(angle), ...it }; }); // Animated counter — total leads streaming in const [count, setCount] = useState(2840); useEffect(() => { const t = setInterval(() => setCount(c => c + Math.floor(Math.random() * 4) + 1), 1200); return () => clearInterval(t); }, []); return (

Integrations

Native connections to the platforms you already run on. Leads route through Kredoo automatically — no copying, no exports, no spreadsheets.

{/* HUB visualization */}
{/* Pulsing rings behind hub */}
{[0, 1, 2].map(i => ( ))}
{/* SVG with connection lines + flowing dots */} {pos.map((p, i) => ( ))} {/* hub glow */} {/* lines from each logo into hub */} {pos.map((p, i) => ( {/* flowing dot */} ))} {/* Logo nodes */} {pos.map((p, i) => (
{p.icon}

{p.name}

))} {/* CENTRAL KREDOO HUB - LIGHT */}
{/* outer rotating shimmer ring */}
{/* inner gold ring */}
Kredoo
Hub
{/* Floating live counter */}

Leads streaming in

{count.toLocaleString()} today

+ 30 more integrations via Zapier and webhooks · see all integrations →

); } /* ── PRODUCT PROOF ────────────────────────────────────────────────── */ function ProductProof() { const ITEMS = [ { title: "Capture leads the moment they arrive", description: "Connect Meta and Google sources so new enquiries land directly in your CRM instead of getting buried in inboxes, exports, or spreadsheets.", label: "Lead capture", color: "#3b82f6", motion: "capture", stats: [{ val: "Seconds", l: "from form to CRM" }, { val: "Meta + Google", l: "ad sources ready" }], icon: , }, { title: "Run your pipeline without spreadsheet chaos", description: "Move leads through custom stages, assign owners, track activity, and keep the whole team looking at the same live board.", label: "Pipeline workspace", color: "#8b5cf6", motion: "pipeline", stats: [{ val: "Custom", l: "stages and fields" }, { val: "Live", l: "team pipeline view" }], icon: , }, { title: "Automate the follow-up work", description: "Use n8n and webhook flows to trigger emails, WhatsApp messages, tasks, and internal alerts as soon as a lead reaches the right stage.", label: "Automation", color: "#10b981", motion: "automation", stats: [{ val: "n8n", l: "workflow support" }, { val: "Rules", l: "stage-based triggers" }], icon: , }, { title: "Launch with the basics already covered", description: "Start with booking links, imports, field mapping, team roles, and reporting foundations so early sales operations do not become messy later.", label: "Ready to operate", color: "#C9A227", motion: "launch", stats: [{ val: "CSV", l: "import and mapping" }, { val: "Bookings", l: "links and calendar" }], icon: , }, ]; return (

Built for the first sales motion

A practical breakdown of the workflows Kredoo helps you put in place: capture, pipeline, automation, and launch operations.

{ITEMS.map((it, i) => (
{/* top accent bar with traveling shimmer */}
{/* Background glow */}
{/* Subtle moving dot pattern in background */}
{/* ripple ring */} {it.icon}

{it.label}

Product capability

Live

{it.title}

{it.description}

{/* Mini animated visualization */}
{it.stats.map(s => (

{s.val}

{s.l}

))}
))}
); } /* Mini-visualization per card */ function PPMotion({ kind, color }) { if (kind === "capture") { // Lead capture: dots flying from "Meta/Google" left → CRM right return ( META · GOOGLE KREDOO {[0, 0.4, 0.8].map((d, i) => ( ))} ); } if (kind === "pipeline") { // Three stages with a card hopping between them return (
{["New", "Qualified", "Won"].map((stage, i) => (
{stage}
))}
); } if (kind === "automation") { // Trigger → Action animated waveform return ( TRIGGER ACTION {/* base line */} {/* travelling highlight */} ); } if (kind === "launch") { // Progress bar filling return (
Setup
5m
); } return null; } Object.assign(window, { HowItWorks, PipelineSection, IntegrationsSection, ProductProof, Reveal, useInView, AnimatedHeading });