- {/* morphing glyph */}
+ {/* morphing glyph — dimensional: a blurred glow clone sits behind
+ the crisp gradient-filled + gradient-stroked face */}
diff --git a/app/components/Scoreboard.tsx b/app/components/Scoreboard.tsx
index 84e19f8..1e40620 100644
--- a/app/components/Scoreboard.tsx
+++ b/app/components/Scoreboard.tsx
@@ -2,20 +2,65 @@
/**
* METRICS scoreboard.
- * - CountUp numbers animate on view (Motion).
- * - A second ANIMATED-SVG moment: a bar chart whose bars DRAW/grow + a baseline
- * that draws itself (GSAP DrawSVG) when the section scrolls in.
- * Reduced-motion: numbers jump to final, bars render at full height (CSS).
+ * - The four headline metrics count up on view (Motion) and are now the focus:
+ * each cell is an interactive tile with a hover lift, an accent edge that
+ * wipes in, and a tiny per-metric sparkline that animates.
+ * - The previously-meaningless decorative bars are replaced with a MEANINGFUL,
+ * LABELLED growth trend: a 6-month "client revenue" area+line chart with real
+ * month ticks, a value axis, and interactive data points that enlarge + show
+ * a tooltip on hover/focus. It communicates the compounding-growth story
+ * instead of being filler.
+ * Reduced-motion: numbers rest at final value, chart renders fully drawn, no
+ * count-up, no draw animation.
*/
-import { useEffect, useRef } from "react";
+import { useEffect, useRef, useState } from "react";
import { gsap } from "./gsap";
import CountUp from "./CountUp";
import { metrics } from "../content";
-const BARS = [38, 56, 72, 64, 88, 96]; // decorative growth bars (0..100)
+/* 6-month sample "client revenue generated" trend (index, $M). Compounding
+ curve that mirrors the "$40M+ generated / 3.8x ROAS" headline story. */
+const TREND = [
+ { m: "Jan", v: 2.1 },
+ { m: "Feb", v: 3.4 },
+ { m: "Mar", v: 5.0 },
+ { m: "Apr", v: 7.8 },
+ { m: "May", v: 11.2 },
+ { m: "Jun", v: 16.4 },
+];
+
+// tiny per-metric sparkline shapes (each different, matching the metric's story)
+const SPARKS: string[] = [
+ "0,18 20,16 40,12 60,11 80,6 100,2", // revenue — steady climb
+ "0,16 20,14 40,15 60,9 80,7 100,3", // ROAS — climbing with a dip
+ "0,19 20,17 40,12 60,10 80,5 100,1", // organic — strong ramp
+ "0,8 20,7 40,8 60,6 80,7 100,5", // retention — high + stable
+];
+
+const W = 560;
+const H = 200;
+const PAD = { l: 38, r: 16, t: 18, b: 30 };
+const maxV = Math.max(...TREND.map((d) => d.v));
+
+function pt(i: number, v: number) {
+ const x = PAD.l + (i / (TREND.length - 1)) * (W - PAD.l - PAD.r);
+ const y = PAD.t + (1 - v / maxV) * (H - PAD.t - PAD.b);
+ return { x, y };
+}
export default function Scoreboard() {
const root = useRef
(null);
+ const [hover, setHover] = useState(null);
+
+ const pts = TREND.map((d, i) => pt(i, d.v));
+ const linePath = pts.map((p, i) => `${i === 0 ? "M" : "L"}${p.x},${p.y}`).join(" ");
+ const areaPath = `${linePath} L${pts[pts.length - 1].x},${H - PAD.b} L${pts[0].x},${H - PAD.b} Z`;
+ // y-axis gridlines at 0 / 50% / 100% of max
+ const yTicks = [0, 0.5, 1].map((f) => ({
+ f,
+ y: PAD.t + (1 - f) * (H - PAD.t - PAD.b),
+ label: `$${(maxV * f).toFixed(0)}M`,
+ }));
useEffect(() => {
const el = root.current;
@@ -27,36 +72,29 @@ export default function Scoreboard() {
const tl = gsap.timeline({
scrollTrigger: { trigger: ".score__chart", start: "top 82%", once: true },
});
- // Baseline draws first, then bars grow up off it with a tight stagger and
- // a soft landing (back ease => a hair of overshoot so they feel physical).
- tl.from(".score__baseline", {
- drawSVG: "0%",
- duration: 0.8,
- ease: "power2.out",
- })
+ // gridlines fade, the area wipes up, the line draws itself, points pop in,
+ // and each metric sparkline draws — a coherent "data resolving" moment.
+ tl.from(".score__grid line", { autoAlpha: 0, duration: 0.5, stagger: 0.08 })
+ .from(".score__area", { autoAlpha: 0, yPercent: 8, duration: 0.8, ease: "power2.out" }, "-=0.2")
+ .from(".score__line", { drawSVG: "0%", duration: 1.4, ease: "power2.inOut" }, "-=0.7")
.from(
- ".score-bar",
- {
- scaleY: 0,
- transformOrigin: "bottom",
- duration: 1,
- ease: "back.out(1.4)",
- stagger: 0.07,
- },
- "-=0.45"
+ ".score__pt",
+ { scale: 0, transformOrigin: "center", duration: 0.5, ease: "back.out(2.2)", stagger: 0.08 },
+ "-=0.6"
)
.from(
- ".score-bar__cap",
- {
- scale: 0,
- autoAlpha: 0,
- transformOrigin: "center",
- duration: 0.5,
- ease: "back.out(2.4)",
- stagger: 0.07,
- },
- "-=0.9"
+ ".score__mlabel",
+ { autoAlpha: 0, y: 6, duration: 0.4, stagger: 0.06 },
+ "-=0.8"
);
+
+ gsap.from(".score__spark polyline", {
+ drawSVG: "0%",
+ duration: 1,
+ ease: "power2.out",
+ stagger: 0.12,
+ scrollTrigger: { trigger: ".score__grid-stats", start: "top 85%", once: true },
+ });
}, el);
return () => ctx.revert();
@@ -75,8 +113,9 @@ export default function Scoreboard() {
-
- {metrics.map((m) => (
+ {/* four headline metrics — the focus; interactive tiles with sparklines */}
+
+ {metrics.map((m, i) => (
- {m.label}
-
{m.label}
+
))}
- {/* decorative animated bar chart */}
-
-
- {BARS.map((h, i) => (
-
-
-
- ))}
-
-
-
+ {/* meaningful labelled growth trend — replaces the decorative bars */}
+
+
+ Client revenue generated — cumulative, sample 6-month engagement
+
+
+
- {/* anchors the section + sets honest expectation; kills the empty gap
- above the gradient divider */}
Sample data — your numbers, reported monthly.
diff --git a/app/components/Testimonials.tsx b/app/components/Testimonials.tsx
new file mode 100644
index 0000000..b7728ed
--- /dev/null
+++ b/app/components/Testimonials.tsx
@@ -0,0 +1,260 @@
+"use client";
+
+/**
+ * TESTIMONIALS — an interactive, auto-advancing carousel that feels substantial.
+ * - 6 sample testimonials, one large featured quote at a time, with a
+ * monogram avatar, name, role, company and a result chip.
+ * - Auto-advances every ~6s; pauses on hover/focus-within and when offscreen
+ * or the tab is hidden. Manual prev/next buttons + clickable dots.
+ * - A thumbnail rail of all clients (monogram avatars) doubles as navigation;
+ * the active one is highlighted.
+ * - Slides crossfade/slide with Motion (AnimatePresence) using the page's
+ * EASE curves; direction-aware.
+ * - Fully keyboard accessible: real