From 9d281920e983729d2c1dff5ca79f00490a08b4b1 Mon Sep 17 00:00:00 2001 From: Vadym Samoilenko Date: Sun, 8 Mar 2026 15:58:14 +0000 Subject: [PATCH] Add Results in Numbers, Service Selector, and Popular Bundles to Services page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Metrics section: 4 gradient stat cards with spring entrance animation - Interactive selector: 3-step wizard (goal → budget → recommendations) - Popular Bundles: 3 package tiers (Starter, Growth, Full Stack) with CTA - Full responsive support for all new sections Co-Authored-By: Claude Opus 4.6 --- src/pages/ServicesPage.css | 433 +++++++++++++++++++++++++++++++++++++ src/pages/ServicesPage.tsx | 240 +++++++++++++++++++- 2 files changed, 670 insertions(+), 3 deletions(-) diff --git a/src/pages/ServicesPage.css b/src/pages/ServicesPage.css index dc0b19a..61328c7 100644 --- a/src/pages/ServicesPage.css +++ b/src/pages/ServicesPage.css @@ -274,6 +274,401 @@ font-weight: 600; } +/* ── Results in Numbers ── */ +.metrics-grid { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 1.5rem; + max-width: 1200px; + margin: 0 auto; +} + +.metric-card { + background: rgba(255, 255, 255, 0.05); + backdrop-filter: blur(12px); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 20px; + padding: 2rem 1.5rem; + text-align: center; + display: flex; + flex-direction: column; + gap: 0.5rem; + position: relative; + overflow: hidden; + transition: border-color 0.3s, box-shadow 0.4s, transform 0.35s; +} + +.metric-card::before { + content: ''; + position: absolute; + top: 0; left: 0; right: 0; bottom: 0; + background: radial-gradient(circle at 30% 20%, rgba(255, 91, 4, 0.08), transparent 60%); + opacity: 0; + transition: opacity 0.4s; + pointer-events: none; + border-radius: 20px; +} + +.metric-card:hover { + border-color: rgba(255, 255, 255, 0.2); + transform: translateY(-3px); + box-shadow: 0 8px 30px rgba(0, 0, 0, 0.15); +} + +.metric-card:hover::before { opacity: 1; } + +.metric-value { + font-size: clamp(2rem, 4vw, 2.8rem); + font-weight: 900; + line-height: 1; + background: linear-gradient(135deg, var(--orange-100), var(--yellow-100)); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; +} + +.metric-label { + color: var(--light-grey-100); + font-size: 0.9rem; + opacity: 0.85; + line-height: 1.4; +} + +/* ── Service Selector ── */ +.selector-section .container { + max-width: 800px; +} + +.selector-steps { + display: flex; + justify-content: center; + gap: 2rem; + margin-bottom: 2.5rem; +} + +.selector-step-dot { + display: flex; + flex-direction: column; + align-items: center; + gap: 0.4rem; + opacity: 0.35; + transition: opacity 0.3s; +} + +.selector-step-dot--active { opacity: 1; } + +.selector-step-num { + width: 36px; + height: 36px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + border: 2px solid rgba(255, 255, 255, 0.15); + color: var(--light-grey-100); + font-weight: 700; + font-size: 0.85rem; + transition: all 0.3s; +} + +.selector-step-dot--active .selector-step-num { + border-color: var(--orange-100); + background: var(--orange-100); + color: #fff; +} + +.selector-step-label { + font-size: 0.75rem; + color: var(--light-grey-100); + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.04em; +} + +.selector-panel { + text-align: center; + min-height: 200px; +} + +.selector-question { + font-size: 1.15rem; + color: #fff; + font-weight: 600; + margin-bottom: 1.5rem; +} + +.selector-options { + display: flex; + flex-wrap: wrap; + justify-content: center; + gap: 0.75rem; +} + +.selector-pill { + background: rgba(255, 255, 255, 0.05); + backdrop-filter: blur(12px); + border: 1px solid rgba(255, 255, 255, 0.12); + border-radius: 100px; + padding: 0.75rem 1.5rem; + color: var(--light-grey-100); + font-size: 0.95rem; + font-weight: 600; + cursor: pointer; + font-family: var(--font-primary); + transition: border-color 0.3s, box-shadow 0.3s, background 0.3s; +} + +.selector-pill:hover { + border-color: rgba(255, 91, 4, 0.4); + background: rgba(255, 91, 4, 0.08); +} + +.selector-pill--active { + border-color: var(--orange-100); + background: rgba(255, 91, 4, 0.12); + color: var(--orange-100); + box-shadow: 0 0 20px rgba(255, 91, 4, 0.15); +} + +.selector-results { + display: flex; + flex-direction: column; + gap: 0.75rem; + max-width: 600px; + margin: 0 auto 1.5rem; +} + +.selector-result-card { + display: flex; + align-items: center; + gap: 1rem; + background: rgba(255, 255, 255, 0.05); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 16px; + padding: 1rem 1.25rem; + text-align: left; + transition: border-color 0.3s; +} + +.selector-result-card:hover { + border-color: rgba(255, 91, 4, 0.3); +} + +.selector-result-icon { + width: 28px; + height: 28px; + color: var(--orange-100); + flex-shrink: 0; +} + +.selector-result-icon svg { width: 100%; height: 100%; } + +.selector-result-card h4 { + color: #fff; + font-size: 0.95rem; + font-weight: 700; + margin-bottom: 0.15rem; +} + +.selector-result-price { + color: var(--orange-100); + font-size: 0.85rem; + font-weight: 600; +} + +.selector-actions { + display: flex; + justify-content: center; + gap: 1rem; + align-items: center; +} + +.selector-reset { + background: none; + border: none; + color: var(--light-grey-100); + opacity: 0.7; + font-size: 0.9rem; + cursor: pointer; + font-family: var(--font-primary); + text-decoration: underline; + transition: opacity 0.2s; +} + +.selector-reset:hover { opacity: 1; } + +.selector-back { + display: block; + background: none; + border: none; + color: var(--light-grey-100); + font-size: 0.9rem; + cursor: pointer; + font-family: var(--font-primary); + margin: 1rem auto 0; + opacity: 0.7; + transition: opacity 0.2s; +} + +.selector-back:hover { opacity: 1; } + +.selector-no-results { + color: var(--light-grey-100); + opacity: 0.7; + font-size: 0.95rem; +} + +/* ── Popular Bundles ── */ +.bundles-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 1.5rem; + max-width: 1200px; + margin: 0 auto; + align-items: start; +} + +.bundle-card { + background: rgba(255, 255, 255, 0.05); + backdrop-filter: blur(12px); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 20px; + padding: 2rem; + display: flex; + flex-direction: column; + position: relative; + overflow: hidden; + transition: border-color 0.3s, box-shadow 0.4s, transform 0.35s; +} + +.bundle-card::before { + content: ''; + position: absolute; + top: 0; left: 0; right: 0; bottom: 0; + background: radial-gradient(circle at 50% 0%, rgba(255, 91, 4, 0.06), transparent 60%); + opacity: 0; + transition: opacity 0.4s; + pointer-events: none; +} + +.bundle-card:hover { + transform: translateY(-4px); + box-shadow: 0 8px 30px rgba(0, 0, 0, 0.15); +} + +.bundle-card:hover::before { opacity: 1; } + +.bundle-card--popular { + border-color: var(--orange-100); + background: rgba(255, 91, 4, 0.06); +} + +.bundle-card--popular::before { opacity: 0.5; } + +.bundle-card--popular:hover { + box-shadow: 0 8px 40px rgba(255, 91, 4, 0.15); +} + +.bundle-popular-badge { + position: absolute; + top: -12px; + left: 50%; + transform: translateX(-50%); + background: linear-gradient(135deg, var(--orange-100), var(--yellow-100)); + color: #fff; + padding: 0.3rem 1rem; + border-radius: 100px; + font-size: 0.8rem; + font-weight: 700; + white-space: nowrap; + box-shadow: 0 2px 10px rgba(255, 91, 4, 0.3); +} + +.bundle-name { + font-size: 1.3rem; + font-weight: 700; + color: #fff; + margin-bottom: 0.25rem; +} + +.bundle-tagline { + font-size: 0.9rem; + color: var(--light-grey-100); + opacity: 0.75; + margin-bottom: 1.25rem; + font-style: italic; +} + +.bundle-services { + list-style: none; + padding: 0; + margin: 0 0 1.5rem 0; + flex: 1; + border-top: 1px solid rgba(255, 255, 255, 0.08); + padding-top: 1rem; +} + +.bundle-services li { + color: var(--light-grey-100); + font-size: 0.9rem; + line-height: 1.5; + padding: 0.35rem 0 0.35rem 1.4rem; + position: relative; +} + +.bundle-services li::before { + content: '→'; + position: absolute; + left: 0; + color: var(--yellow-100); + font-weight: 700; +} + +.bundle-price { + font-size: 1.5rem; + font-weight: 900; + background: linear-gradient(135deg, var(--orange-100), var(--yellow-100)); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; + margin-bottom: 1.25rem; +} + +.bundle-cta { + display: inline-block; + text-align: center; + background: rgba(255, 91, 4, 0.15); + color: var(--orange-100); + border: 1px solid rgba(255, 91, 4, 0.3); + padding: 0.75rem 1.5rem; + border-radius: 100px; + font-size: 0.9rem; + font-weight: 600; + cursor: pointer; + font-family: var(--font-primary); + transition: background 0.3s, box-shadow 0.3s; +} + +.bundle-cta:hover { + background: rgba(255, 91, 4, 0.25); +} + +.bundle-cta--popular { + background: var(--orange-100); + color: #fff; + border-color: var(--orange-100); + box-shadow: 0 4px 15px rgba(255, 91, 4, 0.3); +} + +.bundle-cta--popular:hover { + box-shadow: 0 8px 25px rgba(255, 91, 4, 0.45); +} + +/* Scroll margin for selector "View Services" */ +.services-grid { + scroll-margin-top: 10rem; +} + /* CTA */ .services-cta-section { padding-bottom: 6rem; @@ -342,6 +737,15 @@ .services-grid { grid-template-columns: 1fr; } + + .metrics-grid { + grid-template-columns: repeat(2, 1fr); + } + + .bundles-grid { + grid-template-columns: 1fr; + max-width: 450px; + } } @media (max-width: 900px) { @@ -368,6 +772,35 @@ grid-template-columns: 1fr; } + .metrics-grid { + gap: 1rem; + } + + .metric-card { + padding: 1.5rem 1rem; + } + + .metric-value { + font-size: 1.8rem; + } + + .selector-steps { + gap: 1rem; + } + + .selector-step-label { + display: none; + } + + .selector-pill { + padding: 0.6rem 1.2rem; + font-size: 0.85rem; + } + + .bundles-grid { + max-width: 100%; + } + .services-cta { padding: 2.5rem 1.5rem; } diff --git a/src/pages/ServicesPage.tsx b/src/pages/ServicesPage.tsx index 29708de..19110f9 100644 --- a/src/pages/ServicesPage.tsx +++ b/src/pages/ServicesPage.tsx @@ -1,5 +1,5 @@ -import { useEffect, useState } from 'react'; -import { motion } from 'framer-motion'; +import { useEffect, useState, useRef } from 'react'; +import { motion, AnimatePresence } from 'framer-motion'; import { Helmet } from 'react-helmet-async'; import SEO from '../components/SEO'; import Modal from '../components/Modal'; @@ -173,10 +173,87 @@ const assurancePack = [ 'Handover & transition plan', ]; +const metrics = [ + { value: '30–50%', label: 'Reduction in manual work' }, + { value: '2–8 wks', label: 'Average delivery time' }, + { value: '24/7', label: 'Automated uptime' }, + { value: '£0', label: 'Vendor lock-in fees' }, +]; + +type GoalKey = 'automate' | 'leads' | 'presence' | 'connect' | 'ai'; +type BudgetKey = 'under5k' | '5k-10k' | '10k+'; + +const goalOptions: { key: GoalKey; label: string }[] = [ + { key: 'automate', label: 'Automate workflows' }, + { key: 'leads', label: 'Get more leads' }, + { key: 'presence', label: 'Build online presence' }, + { key: 'connect', label: 'Connect my tools' }, + { key: 'ai', label: 'Add AI capabilities' }, +]; + +const budgetOptions: { key: BudgetKey; label: string }[] = [ + { key: 'under5k', label: 'Under £5K' }, + { key: '5k-10k', label: '£5K – £10K' }, + { key: '10k+', label: '£10K+' }, +]; + +const goalToServices: Record = { + automate: ['Workflow Automation Implementation', 'System Integration & Synchronisation'], + leads: ['AI Chatbots & Virtual Assistants', 'CRM Workflow Optimisation', 'Marketing Automation Setup'], + presence: ['Custom Website Development'], + connect: ['System Integration & Synchronisation', 'Infrastructure Setup & Configuration'], + ai: ['AI Integration & Enhancement', 'AI Chatbots & Virtual Assistants'], +}; + +const budgetFilter: Record = { + 'under5k': [ + 'Infrastructure Setup & Configuration', 'CRM Workflow Optimisation', + 'Custom Website Development', 'System Integration & Synchronisation', + 'AI Chatbots & Virtual Assistants', + ], + '5k-10k': [ + 'Infrastructure Setup & Configuration', 'CRM Workflow Optimisation', + 'Custom Website Development', 'System Integration & Synchronisation', + 'AI Chatbots & Virtual Assistants', 'Workflow Automation Implementation', + 'Marketing Automation Setup', 'AI Integration & Enhancement', + ], + '10k+': services.map(s => s.title), +}; + +const bundles = [ + { + name: 'Starter', + tagline: 'Launch & Engage', + services: ['Custom Website Development', 'AI Chatbots & Virtual Assistants'], + price: 'from £5,500', + }, + { + name: 'Growth', + tagline: 'Scale & Convert', + services: ['CRM Workflow Optimisation', 'Marketing Automation Setup', 'System Integration & Synchronisation'], + price: 'from £9,000', + popular: true, + }, + { + name: 'Full Stack', + tagline: 'Transform Everything', + services: services.map(s => s.title), + price: 'Custom pricing', + }, +]; + const ServicesPage = () => { useEffect(() => { window.scrollTo(0, 0); }, []); const [isModalOpen, setIsModalOpen] = useState(false); const [expandedCard, setExpandedCard] = useState(null); + const [selectorStep, setSelectorStep] = useState(0); + const [selectedGoal, setSelectedGoal] = useState(null); + const [selectedBudget, setSelectedBudget] = useState(null); + const serviceCardsRef = useRef(null); + + const recommendedServices = selectedGoal && selectedBudget + ? goalToServices[selectedGoal].filter(s => budgetFilter[selectedBudget].includes(s)) + : []; return (
@@ -225,7 +302,7 @@ const ServicesPage = () => { {/* Service Cards */}
-
+
{services.map((s, i) => { const isExpanded = expandedCard === i; return ( @@ -299,6 +376,163 @@ const ServicesPage = () => {
+ {/* Results in Numbers */} +
+
+ Results in Numbers +
+ {metrics.map((m, i) => ( + + {m.value} + {m.label} + + ))} +
+
+
+ + {/* Which Service Do You Need? */} +
+
+ Which Service Do You Need? + +
+ {['Your Goal', 'Budget', 'Results'].map((label, i) => ( +
= i ? 'selector-step-dot--active' : ''}`}> + {i + 1} + {label} +
+ ))} +
+ + + {selectorStep === 0 && ( + +

What's your primary goal?

+
+ {goalOptions.map((opt) => ( + { setSelectedGoal(opt.key); setSelectorStep(1); }} + whileHover={{ scale: 1.03 }} + whileTap={{ scale: 0.97 }} + > + {opt.label} + + ))} +
+
+ )} + + {selectorStep === 1 && ( + +

What's your budget range?

+
+ {budgetOptions.map((opt) => ( + { setSelectedBudget(opt.key); setSelectorStep(2); }} + whileHover={{ scale: 1.03 }} + whileTap={{ scale: 0.97 }} + > + {opt.label} + + ))} +
+
+ )} + + {selectorStep === 2 && ( + +

We recommend these services:

+
+ {recommendedServices.length > 0 ? recommendedServices.map((sTitle) => { + const svc = services.find(s => s.title === sTitle); + if (!svc) return null; + return ( +
+
{svc.icon}
+
+

{svc.title}

+ {svc.price} +
+
+ ); + }) : ( +

No exact match — but we can help! Contact us for a custom solution.

+ )} +
+
+ serviceCardsRef.current?.scrollIntoView({ behavior: 'smooth', block: 'start' })} + whileHover={{ scale: 1.03 }} + whileTap={{ scale: 0.97 }} + > + View Services + + +
+
+ )} +
+ + {selectorStep > 0 && selectorStep < 2 && ( + + )} +
+
+ + {/* Popular Bundles */} +
+
+ Popular Bundles +
+ {bundles.map((b, i) => ( + + {'popular' in b && b.popular && Most Popular} +

{b.name}

+

{b.tagline}

+
    + {b.services.map(s => ( +
  • {s}
  • + ))} +
+
{b.price}
+ setIsModalOpen(true)} + whileHover={{ scale: 1.03 }} + whileTap={{ scale: 0.97 }} + > + Get Started + +
+ ))} +
+
+
+ {/* CTA */}