Sunil Prasad c48a11b13c feat: Add smooth 5-second auto-rotation to Hero stories and ProductShowcase cards
- Hero auto-rotates story backdrops every 5 seconds with 500ms fade transitions
- ProductShowcase cards rotate with mint ring highlight on the active card
- Inactive cards fade to 60% opacity on mobile, full opacity on desktop
- New components: StoryBackdrop, StoryOnboarding, CountUp, lib/stories
- Manual Another-story control still works

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 14:10:48 -07:00

99 lines
3.8 KiB
TypeScript

/**
* Goal stories — real human moments behind the numbers.
* One is picked at random every time the page opens (web hero + mobile onboarding).
* Videos are free-license stock from Pexels (pexels.com/license). For production,
* replace with licensed brand footage by swapping the `video` URLs (or move files
* into /public/videos and use local paths).
*/
export type GoalStory = {
id: string;
tag: string;
headline: string;
subline: string;
video: string;
emoji: string;
/** Tailwind gradient classes used if the video fails or while it loads */
fallback: string;
};
export const goalStories: GoalStory[] = [
{
id: "retirement",
tag: "Goal achieved · Comfortable retirement",
headline: "After 34 years of showing up, Rita and Sam clocked out for good.",
subline: "Retired at 61 — two years early — with a plan that never wavered.",
video: "https://videos.pexels.com/video-files/7329851/7329851-sd_640_360_25fps.mp4",
emoji: "🌅",
fallback: "from-[#0A5240] via-[#0F6E56] to-[#B8771F]",
},
{
id: "first-home",
tag: "Goal achieved · First home",
headline: "Maya got the keys to her first home on a Tuesday.",
subline: "18 months of flex budgeting. One very good Tuesday.",
video: "https://videos.pexels.com/video-files/4277738/4277738-sd_640_360_25fps.mp4",
emoji: "🔑",
fallback: "from-[#073D30] via-[#0F6E56] to-[#534AB7]",
},
{
id: "rental-property",
tag: "Goal achieved · First rental property",
headline: "Dev closed on his first rental property this spring.",
subline: "Passive income started as one line item in his Aartha plan.",
video: "https://videos.pexels.com/video-files/4277475/4277475-sd_640_360_25fps.mp4",
emoji: "🏘️",
fallback: "from-[#0A5240] via-[#2E8B6A] to-[#1D9E75]",
},
{
id: "debt-free",
tag: "Goal achieved · Debt-free day",
headline: "The day the Osei family paid off the last of $42,000.",
subline: "Every extra dollar had a job. This was the payoff.",
video: "https://videos.pexels.com/video-files/7712328/7712328-sd_640_360_30fps.mp4",
emoji: "🎉",
fallback: "from-[#3E3792] via-[#534AB7] to-[#0F6E56]",
},
{
id: "college-fund",
tag: "Goal achieved · College fund",
headline: "Amara walked the stage completely debt-free.",
subline: "Her parents started the fund 12 years ago — $180 a month.",
video: "https://videos.pexels.com/video-files/7712350/7712350-sd_640_360_30fps.mp4",
emoji: "🎓",
fallback: "from-[#073D30] via-[#0F6E56] to-[#9BD9C5]",
},
{
id: "new-baby",
tag: "Goal achieved · Ready for baby",
headline: "Leo arrived. The emergency fund was already there.",
subline: "Nine months to prepare — financially calm on day one.",
video: "https://videos.pexels.com/video-files/7918438/7918438-sd_640_360_25fps.mp4",
emoji: "👶",
fallback: "from-[#0F6E56] via-[#2E8B6A] to-[#E8A23A]",
},
{
id: "small-business",
tag: "Goal achieved · Own boss",
headline: "Priya opened her studio's doors with zero business debt.",
subline: "She saved her way to independence, one month at a time.",
video: "https://videos.pexels.com/video-files/6685171/6685171-sd_640_360_30fps.mp4",
emoji: "🚀",
fallback: "from-[#96601A] via-[#B8771F] to-[#0F6E56]",
},
{
id: "dream-trip",
tag: "Goal achieved · Dream trip",
headline: "Three generations, one beach, fully paid for.",
subline: "The Reyes family trip fund hit 100% in June.",
video: "https://videos.pexels.com/video-files/7850307/7850307-sd_640_360_30fps.mp4",
emoji: "🏖️",
fallback: "from-[#0A5240] via-[#1D9E75] to-[#534AB7]",
},
];
export function randomStory(excludeId?: string): GoalStory {
const pool = goalStories.filter((s) => s.id !== excludeId);
return pool[Math.floor(Math.random() * pool.length)];
}