Add About, Services, Pricing pages with quote form

- /about: company story, differentiators, values, founder bio, industries, company details
- /services: 6 service cards with pricing, assurance pack, process steps, tech stack
- /pricing: pricing table, retainer tiers, training, payment terms, discounts, comparison, FAQ, inline quote form
- QuoteForm component with service dropdown + project description textarea
- POST /api/quote endpoint via Resend for quote requests
- Nav updated: About Us, Services, Pricing now route to standalone pages
- SEO: JSON-LD schemas, sitemap.xml, llms.txt updated
- Founder photo added

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Vadym Samoilenko 2026-03-08 15:19:30 +00:00
parent 7c8276da17
commit af26ccd2b7
14 changed files with 2716 additions and 13 deletions

View file

@ -46,4 +46,50 @@ app.post('/api/contact', async (req, res) => {
}
});
app.post('/api/quote', async (req, res) => {
const { fullName, workEmail, companyName, jobTitle, phoneNumber, service, projectDescription } = req.body;
if (!fullName || !workEmail || !service || !projectDescription) {
return res.status(400).json({ error: 'Missing required fields' });
}
try {
const response = await fetch('https://api.resend.com/emails', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.RESEND_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
from: 'AImpress Website <noreply@ai-impress.com>',
to: ['hello@ai-impress.com'],
subject: `Quote request: ${fullName}${service}`,
html: `
<h2>New Quote Request</h2>
<p><strong>Name:</strong> ${fullName}</p>
<p><strong>Email:</strong> ${workEmail}</p>
<p><strong>Company:</strong> ${companyName || 'N/A'}</p>
<p><strong>Job Title:</strong> ${jobTitle || 'N/A'}</p>
<p><strong>Phone:</strong> ${phoneNumber || 'N/A'}</p>
<hr>
<p><strong>Service:</strong> ${service}</p>
<p><strong>Project Description:</strong></p>
<p>${projectDescription.replace(/\n/g, '<br>')}</p>
`,
}),
});
if (!response.ok) {
const err = await response.text();
console.error('Resend error:', err);
return res.status(502).json({ error: 'Email delivery failed' });
}
res.json({ ok: true });
} catch (err) {
console.error('Email error:', err);
res.status(500).json({ error: 'Internal error' });
}
});
app.listen(3001, () => console.log('Email API listening on :3001'));

View file

@ -0,0 +1,16 @@
<html><head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<title>413 Request Entity Too Large</title>
</head>
<body text=#000000 bgcolor=#ffffff>
<h1>Error: Request Entity Too Large</h1>
<h2>Your client issued a request that was too large.
</h2>
<h2><script>
(function() { var c=function(a,d,b){a=a+"=deleted; path="+d;b!=null&&(a+="; domain="+b);document.cookie=a+"; expires=Thu, 01 Jan 1970 00:00:00 GMT"};var g=function(a){var d=e,b=location.hostname;c(d,a,null);c(d,a,b);for(var f=0;;){f=b.indexOf(".",f+1);if(f<0)break;c(d,a,b.substring(f+1))}};var h;if(unescape(encodeURI(document.cookie)).length>4E3){for(var k=document.cookie.split(";"),l=[],m=0;m<k.length;m++){var n=k[m].match(/^\s*([^=]+)/);n&&l.push(n[1])}for(var p=0;p<l.length;p++){var e=l[p];g("/");for(var q=location.pathname,r=0;;){r=q.indexOf("/",r+1);if(r<0)break;var t=q.substring(0,r);g(t);g(t+"/")}q.charAt(q.length-1)!="/"&&(g(q),g(q+"/"))}h=!0}else h=!1;
h&&setTimeout(function(){if(history.replaceState){var a=location.href;history.replaceState(null,"","/");location.replace(a)}},1E3); })();
</script>
</h2>
</body></html>

View file

@ -1,7 +1,7 @@
# AImpress Ltd
## About
AImpress is an AI and automation consulting company based in London, UK. We help small and medium-sized enterprises (SMEs) adopt AI-powered solutions to automate operations, reduce costs, and accelerate growth.
AImpress is an AI and automation consulting company based in London, UK. Founded in 2024, we help small and medium-sized enterprises (SMEs), charities, and public sector organisations adopt AI-powered solutions to automate operations, reduce costs, and accelerate growth. We specialise in client-owned infrastructure with no vendor lock-in, full documentation, and team training included in every project.
## Company Details
- Legal Name: AImpress Ltd
@ -12,18 +12,38 @@ AImpress is an AI and automation consulting company based in London, UK. We help
- Website: https://ai-impress.com
- Email: hello@ai-impress.com
## Services
- AI Chatbots & Virtual Assistants — custom chatbots for customer support, lead qualification, and appointment booking
- Business Process Automation — workflow automation using Make.com, Zapier, and custom integrations
- Content Automation (Content Farms) — automated content generation for blogs, social media, and marketing
- Marketing Automation — lead nurturing, email campaigns, CRM integration, and conversion optimisation
- AI Strategy Consulting — roadmap development, tool selection, and implementation planning for SMEs
## Services & Pricing
- Workflow Automation Implementation (£3,500£12,000) — end-to-end process automation using n8n, Make.com, and custom integrations
- System Integration & Synchronisation (£2,500£10,000+) — API integrations, bi-directional data sync, webhook triggers
- CRM Workflow Optimisation (£3,000£6,500) — pipeline restructure, automated lead scoring, email sequences
- Marketing Automation Setup (£3,500£8,000) — drip campaigns, lead capture, audience segmentation, analytics
- AI Integration & Enhancement (£4,000£12,000) — chatbots, content generation, document processing, prompt engineering
- Infrastructure Setup & Configuration (£1,500£4,000) — server provisioning, automation platform deployment, security hardening
## Support Retainers
- Essential: £1,000/month (10 hours, 48h SLA)
- Professional: £2,000/month (22 hours, 24h SLA)
- Enterprise: £3,500/month (40 hours, 4h SLA)
## Impact Grant Programme
- Charities & Non-Profits: up to 50% discount
- Startups (< 2 years): up to 50% discount
- Education: up to 50% discount
- Public Sector: 25% discount + free pilot project
- Ukrainian Businesses: up to 50% discount
## Technologies
Make.com, Zapier, OpenAI, Anthropic Claude, Google AI, HubSpot, Salesforce, WordPress, Shopify, custom API integrations
n8n, Make.com, Zapier, Power Automate, OpenAI, Anthropic Claude, Google AI, LangChain, HubSpot, Salesforce, Pipedrive, Zoho, Mailchimp, ActiveCampaign, Brevo, AWS, Hetzner, Docker, Nginx, Cloudflare, Power BI, Mixpanel, Slack, Teams, Twilio
## Industries Served
Professional services, healthcare, hospitality, retail, e-commerce, property management, education, fitness, food & beverage
E-commerce, professional services, SaaS, charities, education, healthcare, public sector
## Pages
- Home: https://ai-impress.com/
- About: https://ai-impress.com/about
- Services: https://ai-impress.com/services
- Pricing: https://ai-impress.com/pricing
- Blog: https://ai-impress.com/blog
## Social Media
- LinkedIn: https://www.linkedin.com/company/aimpress-ltd/

View file

@ -5,6 +5,21 @@
<changefreq>weekly</changefreq>
<priority>1.0</priority>
</url>
<url>
<loc>https://ai-impress.com/about</loc>
<changefreq>monthly</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>https://ai-impress.com/services</loc>
<changefreq>monthly</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>https://ai-impress.com/pricing</loc>
<changefreq>monthly</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>https://ai-impress.com/blog</loc>
<changefreq>weekly</changefreq>

View file

@ -9,6 +9,9 @@ import BlogPage from './pages/BlogPage';
import BlogPostPage from './pages/BlogPostPage';
import PrivacyPolicyPage from './pages/PrivacyPolicyPage';
import TermsOfUsePage from './pages/TermsOfUsePage';
import AboutPage from './pages/AboutPage';
import ServicesPage from './pages/ServicesPage';
import PricingPage from './pages/PricingPage';
import './App.css';
function App() {
@ -18,6 +21,9 @@ function App() {
<Header />
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/about" element={<AboutPage />} />
<Route path="/services" element={<ServicesPage />} />
<Route path="/pricing" element={<PricingPage />} />
<Route path="/blog" element={<BlogPage />} />
<Route path="/blog/:slug" element={<BlogPostPage />} />
<Route path="/privacy-policy" element={<PrivacyPolicyPage />} />

View file

@ -5,11 +5,11 @@ import Modal from './Modal';
import './Header.css';
const navItems = [
{ name: 'Home', link: '#hero' },
{ name: 'About Us', link: '#benefits' },
{ name: 'Services', link: '#timeline' },
{ name: 'Home', link: '/' },
{ name: 'About Us', link: '/about' },
{ name: 'Services', link: '/services' },
{ name: 'Cases', link: '#testimonials' },
{ name: 'Pricing', link: '#comparison' },
{ name: 'Pricing', link: '/pricing' },
{ name: 'Blog', link: '/blog' },
{ name: 'Contacts', link: '#contact' },
];

View file

@ -0,0 +1,72 @@
.quote-form-container {
width: 100%;
}
.quote-form {
display: flex;
flex-direction: column;
gap: 1.5rem;
}
/* Select styling */
.quote-form-container .form-group select {
background: rgba(255, 255, 255, 0.04);
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 12px;
padding: 0.9rem 1.2rem;
color: #fff;
font-family: inherit;
font-size: 0.95rem;
transition: border-color 0.25s, background 0.25s, box-shadow 0.25s;
appearance: none;
-webkit-appearance: none;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none'%3E%3Cpath d='M1 1.5L6 6.5L11 1.5' stroke='%23D3DDDE' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: right 1.2rem center;
cursor: pointer;
}
.quote-form-container .form-group select option {
background: var(--dark-grey-100);
color: #fff;
}
.quote-form-container .form-group select:focus {
outline: none;
border-color: var(--orange-100);
background-color: rgba(255, 255, 255, 0.06);
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none'%3E%3Cpath d='M1 1.5L6 6.5L11 1.5' stroke='%23FF5B04' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: right 1.2rem center;
box-shadow: 0 0 0 3px rgba(255, 91, 4, 0.1);
}
/* Textarea styling */
.quote-form-container .form-group textarea {
background: rgba(255, 255, 255, 0.04);
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 12px;
padding: 0.9rem 1.2rem;
color: #fff;
font-family: inherit;
font-size: 0.95rem;
resize: vertical;
min-height: 100px;
transition: border-color 0.25s, background 0.25s, box-shadow 0.25s;
}
.quote-form-container .form-group textarea::placeholder {
color: rgba(211, 221, 222, 0.25);
}
.quote-form-container .form-group textarea:focus {
outline: none;
border-color: var(--orange-100);
background: rgba(255, 255, 255, 0.06);
box-shadow: 0 0 0 3px rgba(255, 91, 4, 0.1);
}
/* Full-width field */
.form-group--full {
grid-column: 1 / -1;
}

View file

@ -0,0 +1,202 @@
import React, { useState, type ChangeEvent, type FormEvent } from 'react';
import { motion } from 'framer-motion';
import mixpanel from 'mixpanel-browser';
import './QuoteForm.css';
interface QuoteData {
fullName: string;
workEmail: string;
companyName: string;
jobTitle: string;
phoneNumber: string;
service: string;
projectDescription: string;
}
const serviceOptions = [
'Workflow Automation Implementation',
'System Integration & Synchronisation',
'CRM Workflow Optimisation',
'Marketing Automation Setup',
'AI Integration & Enhancement',
'Infrastructure Setup & Configuration',
'Support Retainer',
'Training & Workshop',
'Other / Not sure yet',
];
interface QuoteFormProps {
onClose?: () => void;
}
const QuoteForm: React.FC<QuoteFormProps> = () => {
const [formData, setFormData] = useState<QuoteData>({
fullName: '',
workEmail: '',
companyName: '',
jobTitle: '',
phoneNumber: '',
service: '',
projectDescription: '',
});
const [status, setStatus] = useState<'idle' | 'submitting' | 'success' | 'error'>('idle');
const [focusedField, setFocusedField] = useState<string | null>(null);
const handleChange = (e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>) => {
const { name, value } = e.target;
setFormData((prev) => ({ ...prev, [name]: value }));
};
const handleSubmit = async (e: FormEvent) => {
e.preventDefault();
setStatus('submitting');
try {
const res = await fetch('/api/quote', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(formData),
});
if (!res.ok) throw new Error('Failed');
mixpanel.track('Conversion', {
'Conversion Type': 'Quote Request',
'company_name': formData.companyName,
'job_title': formData.jobTitle,
'service': formData.service,
});
setStatus('success');
setFormData({
fullName: '',
workEmail: '',
companyName: '',
jobTitle: '',
phoneNumber: '',
service: '',
projectDescription: '',
});
} catch (error) {
console.error(error);
mixpanel.track('Error', {
'error_type': 'quote_form_submission',
'error_message': String(error),
'page_url': window.location.href,
});
setStatus('error');
}
};
const inputFields = [
{ label: 'Full Name', name: 'fullName', type: 'text', placeholder: 'John Doe' },
{ label: 'Job Title / Role', name: 'jobTitle', type: 'text', placeholder: 'Project Manager' },
{ label: 'Work Email', name: 'workEmail', type: 'email', placeholder: 'john@company.com' },
{ label: 'Phone Number', name: 'phoneNumber', type: 'tel', placeholder: '+44...' },
{ label: 'Company Name', name: 'companyName', type: 'text', placeholder: 'Tech Solutions Ltd' },
];
return (
<div className="quote-form-container">
<h2 className="form-title">Get Your Quote</h2>
{status === 'success' ? (
<div className="success-message">
<h3>Thank you!</h3>
<p>We've received your quote request. We'll review your requirements and get back to you within 24 hours with a detailed proposal.</p>
<button onClick={() => setStatus('idle')} className="reset-btn">Submit another request</button>
</div>
) : (
<form onSubmit={handleSubmit} className="quote-form">
<div className="form-grid">
{inputFields.map((field, i) => (
<motion.div
key={field.name}
className={`form-group ${focusedField === field.name ? 'form-group--focused' : ''}`}
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.3, delay: i * 0.08 }}
>
<label>{field.label}*</label>
<input
type={field.type}
name={field.name}
required
value={formData[field.name as keyof QuoteData]}
onChange={handleChange}
onFocus={() => setFocusedField(field.name)}
onBlur={() => setFocusedField(null)}
placeholder={field.placeholder}
/>
</motion.div>
))}
<motion.div
className={`form-group ${focusedField === 'service' ? 'form-group--focused' : ''}`}
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.3, delay: 0.4 }}
>
<label>Service*</label>
<select
name="service"
required
value={formData.service}
onChange={handleChange}
onFocus={() => setFocusedField('service')}
onBlur={() => setFocusedField(null)}
>
<option value="" disabled>Select a service...</option>
{serviceOptions.map((opt) => (
<option key={opt} value={opt}>{opt}</option>
))}
</select>
</motion.div>
</div>
<motion.div
className={`form-group form-group--full ${focusedField === 'projectDescription' ? 'form-group--focused' : ''}`}
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.3, delay: 0.5 }}
>
<label>Project Description*</label>
<textarea
name="projectDescription"
required
value={formData.projectDescription}
onChange={handleChange}
onFocus={() => setFocusedField('projectDescription')}
onBlur={() => setFocusedField(null)}
placeholder="Describe your automation needs, current challenges, and desired outcomes..."
rows={4}
/>
</motion.div>
<motion.div
className="form-actions"
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.3, delay: 0.6 }}
>
<motion.button
type="submit"
className="submit-btn"
disabled={status === 'submitting'}
whileHover={{ scale: 1.03 }}
whileTap={{ scale: 0.97 }}
>
{status === 'submitting' ? 'Sending...' : 'Get Your Quote'}
</motion.button>
{status === 'error' && <p className="error-text">Something went wrong. Please try again.</p>}
</motion.div>
</form>
)}
</div>
);
};
export default QuoteForm;

375
src/pages/AboutPage.css Normal file
View file

@ -0,0 +1,375 @@
.about-page {
padding-top: 8rem;
min-height: 100vh;
}
/* Hero */
.about-hero {
padding: 4rem 2rem 3rem;
text-align: center;
}
.about-hero h1 {
font-size: 3.2rem;
font-weight: 800;
color: #fff;
margin-bottom: 1rem;
}
.about-hero-sub {
font-size: 1.2rem;
color: var(--light-grey-100);
opacity: 0.8;
max-width: 600px;
margin: 0 auto;
}
/* Sections */
.about-section {
padding: 4rem 2rem;
}
.about-section .section-title {
text-align: center;
font-size: 2rem;
font-weight: 800;
color: #fff;
margin-bottom: 2.5rem;
}
/* Story */
.about-story-text {
max-width: 800px;
margin: 0 auto;
color: var(--light-grey-100);
font-size: 1.05rem;
line-height: 1.8;
}
.about-story-text p {
margin-bottom: 1.2rem;
}
/* Differentiator Cards */
.about-diff-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 1.5rem;
max-width: 1000px;
margin: 0 auto;
}
.about-glass-card {
background: rgba(255, 255, 255, 0.05);
backdrop-filter: blur(12px);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 16px;
padding: 2rem;
transition: border-color 0.3s;
}
.about-glass-card:hover {
border-color: var(--orange-100);
}
.about-card-icon {
width: 40px;
height: 40px;
color: var(--orange-100);
margin-bottom: 1rem;
}
.about-card-icon svg {
width: 100%;
height: 100%;
}
.about-glass-card h3 {
font-size: 1.15rem;
font-weight: 700;
color: #fff;
margin-bottom: 0.6rem;
}
.about-glass-card p {
color: var(--light-grey-100);
font-size: 0.95rem;
line-height: 1.6;
opacity: 0.85;
}
/* Values */
.about-values-grid {
display: grid;
grid-template-columns: repeat(5, 1fr);
gap: 1.25rem;
max-width: 1100px;
margin: 0 auto;
}
.about-value-item {
background: rgba(255, 255, 255, 0.04);
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 12px;
padding: 1.5rem;
text-align: center;
}
.about-value-item h3 {
font-size: 1rem;
font-weight: 700;
color: var(--orange-100);
margin-bottom: 0.5rem;
}
.about-value-item p {
color: var(--light-grey-100);
font-size: 0.85rem;
line-height: 1.5;
opacity: 0.8;
}
/* Founder */
.about-founder-card {
display: flex;
gap: 2.5rem;
align-items: flex-start;
max-width: 900px;
margin: 0 auto;
background: rgba(255, 255, 255, 0.05);
backdrop-filter: blur(12px);
border: 1px solid rgba(255, 255, 255, 0.1);
border-left: 3px solid var(--orange-100);
border-radius: 16px;
padding: 2.5rem;
}
.about-founder-photo {
flex-shrink: 0;
}
.about-founder-img {
width: 140px;
height: 140px;
border-radius: 50%;
object-fit: cover;
border: 3px solid rgba(255, 255, 255, 0.15);
}
.about-founder-info h3 {
font-size: 1.5rem;
font-weight: 800;
color: #fff;
margin-bottom: 0.25rem;
}
.about-founder-role {
display: block;
color: var(--orange-100);
font-weight: 600;
font-size: 0.95rem;
margin-bottom: 1.25rem;
}
.about-founder-details {
list-style: none;
padding: 0;
}
.about-founder-details li {
color: var(--light-grey-100);
font-size: 0.95rem;
line-height: 1.6;
margin-bottom: 0.75rem;
padding-left: 1rem;
position: relative;
}
.about-founder-details li::before {
content: '';
position: absolute;
left: 0;
top: 0.55em;
width: 5px;
height: 5px;
border-radius: 50%;
background: var(--orange-100);
}
.about-founder-details li strong {
color: #fff;
}
/* Industries */
.about-industries {
display: flex;
flex-wrap: wrap;
gap: 1rem;
justify-content: center;
max-width: 800px;
margin: 0 auto;
}
.about-industry-badge {
background: rgba(255, 255, 255, 0.06);
border: 1px solid rgba(255, 255, 255, 0.12);
border-radius: 100px;
padding: 0.6rem 1.5rem;
color: var(--light-grey-100);
font-size: 0.95rem;
font-weight: 500;
transition: border-color 0.3s, color 0.3s;
}
.about-industry-badge:hover {
border-color: var(--orange-100);
color: #fff;
}
/* Company Details */
.about-company-details {
max-width: 700px;
margin: 0 auto;
background: rgba(255, 255, 255, 0.04);
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 12px;
overflow: hidden;
}
.about-detail-row {
display: flex;
justify-content: space-between;
padding: 1rem 1.5rem;
border-bottom: 1px solid rgba(255, 255, 255, 0.06);
}
.about-detail-row:last-child {
border-bottom: none;
}
.about-detail-row span:first-child {
color: var(--light-grey-100);
opacity: 0.7;
font-size: 0.9rem;
}
.about-detail-row span:last-child {
color: #fff;
font-weight: 500;
font-size: 0.95rem;
text-align: right;
}
.about-detail-row a {
color: var(--orange-100);
text-decoration: none;
}
.about-detail-row a:hover {
text-decoration: underline;
}
/* CTA */
.about-cta-section {
padding-bottom: 6rem;
}
.about-cta {
text-align: center;
background: rgba(255, 91, 4, 0.08);
border: 1px solid rgba(255, 91, 4, 0.2);
border-radius: 20px;
padding: 3.5rem 2rem;
max-width: 700px;
margin: 0 auto;
}
.about-cta h2 {
font-size: 1.8rem;
font-weight: 800;
color: #fff;
margin-bottom: 0.75rem;
}
.about-cta p {
color: var(--light-grey-100);
font-size: 1.05rem;
margin-bottom: 2rem;
opacity: 0.85;
}
.about-cta-btn {
background: var(--orange-100);
color: #fff;
border: none;
padding: 0.9rem 2.5rem;
border-radius: 100px;
font-size: 1rem;
font-weight: 600;
cursor: pointer;
font-family: var(--font-primary);
}
/* Responsive */
@media (max-width: 900px) {
.about-diff-grid {
grid-template-columns: 1fr;
}
.about-values-grid {
grid-template-columns: repeat(3, 1fr);
}
.about-founder-card {
flex-direction: column;
align-items: center;
text-align: center;
}
.about-founder-details li {
text-align: left;
}
}
@media (max-width: 600px) {
.about-page {
padding-top: 6rem;
}
.about-hero h1 {
font-size: 2.2rem;
}
.about-hero-sub {
font-size: 1rem;
}
.about-section {
padding: 3rem 1rem;
}
.about-values-grid {
grid-template-columns: repeat(2, 1fr);
}
.about-founder-card {
padding: 1.5rem;
}
.about-detail-row {
flex-direction: column;
gap: 0.25rem;
}
.about-detail-row span:last-child {
text-align: left;
}
.about-cta {
padding: 2.5rem 1.5rem;
}
.about-cta h2 {
font-size: 1.4rem;
}
}

275
src/pages/AboutPage.tsx Normal file
View file

@ -0,0 +1,275 @@
import { useEffect, useState } from 'react';
import { motion } from 'framer-motion';
import { Helmet } from 'react-helmet-async';
import SEO from '../components/SEO';
import Modal from '../components/Modal';
import ContactForm from '../components/ContactForm';
import './AboutPage.css';
const fadeUp = {
initial: { opacity: 0, y: 40 },
whileInView: { opacity: 1, y: 0 },
viewport: { once: true, margin: '-80px' },
transition: { duration: 0.5 },
};
const differentiators = [
{
icon: (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
<circle cx="12" cy="10" r="3"/><path d="M12 2a8 8 0 0 0-8 8c0 5.4 7 12 8 12s8-6.6 8-12a8 8 0 0 0-8-8z"/>
</svg>
),
title: 'UK-Based, London Standards',
desc: 'Competitive rates of £90120/hr. UK business hours, GDPR-compliant by default, full accountability under English law.',
},
{
icon: (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
<rect x="2" y="7" width="20" height="14" rx="2" ry="2"/><path d="M16 7V5a4 4 0 0 0-8 0v2"/>
</svg>
),
title: 'SME Specialisation',
desc: 'We focus on CRM, marketing, finance, and e-commerce automation — the workflows that matter most to growing businesses.',
},
{
icon: (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
<rect x="3" y="11" width="18" height="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/>
</svg>
),
title: 'Client-Owned Infrastructure',
desc: 'Your servers, your data, your accounts. We build on infrastructure you own — no vendor lock-in, no hostage situations.',
},
{
icon: (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
<path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/>
</svg>
),
title: 'Knowledge Transfer, Not Dependency',
desc: 'Every project includes full documentation and team training. We teach your people to maintain what we build.',
},
];
const values = [
{ name: 'Transparency', desc: 'Fixed prices, clear scope, no hidden fees' },
{ name: 'Client Ownership', desc: 'You own everything we build — code, data, infrastructure' },
{ name: 'Excellence', desc: 'Enterprise-grade quality at SME-friendly prices' },
{ name: 'Impact Over Profit', desc: 'Discounted rates for charities, startups, and public sector' },
{ name: 'Pragmatism', desc: 'We recommend what works, not what costs more' },
];
const industries = [
'E-commerce', 'Professional Services', 'SaaS', 'Charities',
'Education', 'Healthcare', 'Public Sector',
];
const AboutPage = () => {
useEffect(() => { window.scrollTo(0, 0); }, []);
const [isModalOpen, setIsModalOpen] = useState(false);
return (
<div className="about-page">
<SEO
title="About Us | AImpress — AI & Automation Consulting, London"
description="AImpress Ltd is a London-based automation consultancy for SMEs, charities, and public sector. Founded 2024. Client-owned infrastructure, no vendor lock-in."
url="https://ai-impress.com/about"
/>
<Helmet>
<script type="application/ld+json">{JSON.stringify({
'@context': 'https://schema.org',
'@type': 'AboutPage',
mainEntity: {
'@type': 'Organization',
name: 'AImpress Ltd',
url: 'https://ai-impress.com',
foundingDate: '2024',
address: {
'@type': 'PostalAddress',
streetAddress: 'Suite 6065 Unit 3a, 34-35 Hatton Garden',
addressLocality: 'London',
postalCode: 'EC1N 8DX',
addressCountry: 'GB',
},
},
})}</script>
</Helmet>
{/* Hero */}
<section className="about-hero">
<div className="container">
<motion.h1 {...fadeUp}>About AImpress</motion.h1>
<motion.p className="about-hero-sub" {...fadeUp} transition={{ duration: 0.5, delay: 0.1 }}>
Making professional automation accessible to impact-driven organisations.
</motion.p>
</div>
</section>
{/* Our Story */}
<section className="about-section">
<div className="container">
<motion.div className="about-story" {...fadeUp}>
<h2 className="section-title">Our Story</h2>
<div className="about-story-text">
<p>
Automation is no longer optional it's the difference between growing and getting left behind.
Yet for most SMEs, the options have been limited: offshore teams that are cheap but unreliable,
or UK agencies that charge enterprise prices for basic work.
</p>
<p>
AImpress was founded to fill that gap. We're a London-based consultancy that brings
enterprise-grade automation to small and medium businesses, charities, and public sector
organisations at prices that actually make sense.
</p>
<p>
We don't believe in black-box solutions or vendor lock-in. Every system we build runs on
infrastructure you own, with documentation your team can follow. When we leave, you keep
everything and you know how it works.
</p>
</div>
</motion.div>
</div>
</section>
{/* What Makes Us Different */}
<section className="about-section">
<div className="container">
<motion.h2 className="section-title" {...fadeUp}>What Makes Us Different</motion.h2>
<div className="about-diff-grid">
{differentiators.map((d, i) => (
<motion.div
key={d.title}
className="about-glass-card"
initial={{ opacity: 0, y: 40 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: '-80px' }}
transition={{ duration: 0.5, delay: i * 0.1 }}
>
<div className="about-card-icon">{d.icon}</div>
<h3>{d.title}</h3>
<p>{d.desc}</p>
</motion.div>
))}
</div>
</div>
</section>
{/* Our Values */}
<section className="about-section">
<div className="container">
<motion.h2 className="section-title" {...fadeUp}>Our Values</motion.h2>
<div className="about-values-grid">
{values.map((v, i) => (
<motion.div
key={v.name}
className="about-value-item"
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: '-60px' }}
transition={{ duration: 0.4, delay: i * 0.08 }}
>
<h3>{v.name}</h3>
<p>{v.desc}</p>
</motion.div>
))}
</div>
</div>
</section>
{/* Meet the Founder */}
<section className="about-section">
<div className="container">
<motion.h2 className="section-title" {...fadeUp}>Meet the Founder</motion.h2>
<motion.div className="about-founder-card" {...fadeUp}>
<div className="about-founder-photo">
<img src="/founder-danylo.jpeg" alt="Danylo — CEO & Founder of AImpress" className="about-founder-img" />
</div>
<div className="about-founder-info">
<h3>Danylo</h3>
<span className="about-founder-role">CEO & Founder of AImpress Ltd</span>
<ul className="about-founder-details">
<li>
<strong>Background:</strong> 3+ years leading automation at OLIVER Agency (WPP),
building enterprise-grade workflows for global brands
</li>
<li>
<strong>Certifications:</strong> Microsoft Power BI Data Analyst, Laba Business Analytics
& Marketing Analytics
</li>
<li>
<strong>Education:</strong> Master's in Economic Cybernetics systems modelling,
data analysis, process optimisation
</li>
<li>
<strong>Vision:</strong> Founded AImpress to bring enterprise-level automation to SMEs
at accessible price points
</li>
</ul>
</div>
</motion.div>
</div>
</section>
{/* Industries We Serve */}
<section className="about-section">
<div className="container">
<motion.h2 className="section-title" {...fadeUp}>Industries We Serve</motion.h2>
<div className="about-industries">
{industries.map((ind, i) => (
<motion.span
key={ind}
className="about-industry-badge"
initial={{ opacity: 0, scale: 0.9 }}
whileInView={{ opacity: 1, scale: 1 }}
viewport={{ once: true }}
transition={{ duration: 0.3, delay: i * 0.06 }}
>
{ind}
</motion.span>
))}
</div>
</div>
</section>
{/* Company Details */}
<section className="about-section">
<div className="container">
<motion.h2 className="section-title" {...fadeUp}>Company Details</motion.h2>
<motion.div className="about-company-details" {...fadeUp}>
<div className="about-detail-row"><span>Legal Name</span><span>AImpress Ltd</span></div>
<div className="about-detail-row"><span>Company Number</span><span>16417799 (England & Wales)</span></div>
<div className="about-detail-row"><span>VAT Number</span><span>492173381</span></div>
<div className="about-detail-row"><span>ICO Registration</span><span>ZB979660</span></div>
<div className="about-detail-row"><span>Address</span><span>Suite 6065 Unit 3a, 34-35 Hatton Garden, London, EC1N 8DX</span></div>
<div className="about-detail-row"><span>Email</span><span><a href="mailto:hello@ai-impress.com">hello@ai-impress.com</a></span></div>
</motion.div>
</div>
</section>
{/* CTA */}
<section className="about-section about-cta-section">
<div className="container">
<motion.div className="about-cta" {...fadeUp}>
<h2>Ready to Transform Your Operations?</h2>
<p>Book a free discovery call and find out how automation can work for your business.</p>
<motion.button
className="about-cta-btn"
onClick={() => setIsModalOpen(true)}
whileHover={{ scale: 1.03 }}
whileTap={{ scale: 0.97 }}
>
Book a Free Discovery Call
</motion.button>
</motion.div>
</div>
</section>
<Modal isOpen={isModalOpen} onClose={() => setIsModalOpen(false)}>
<ContactForm onClose={() => setIsModalOpen(false)} />
</Modal>
</div>
);
};
export default AboutPage;

555
src/pages/PricingPage.css Normal file
View file

@ -0,0 +1,555 @@
.pricing-page {
padding-top: 8rem;
min-height: 100vh;
}
/* Hero */
.pricing-hero {
padding: 4rem 2rem 3rem;
text-align: center;
}
.pricing-hero h1 {
font-size: 3.2rem;
font-weight: 800;
color: #fff;
margin-bottom: 1rem;
}
.pricing-hero-sub {
font-size: 1.2rem;
color: var(--light-grey-100);
opacity: 0.8;
max-width: 600px;
margin: 0 auto;
}
/* Sections */
.pricing-section {
padding: 4rem 2rem;
}
.pricing-section .section-title {
text-align: center;
font-size: 2rem;
font-weight: 800;
color: #fff;
margin-bottom: 2.5rem;
}
/* Implementation Pricing Table */
.pricing-table-wrap {
max-width: 800px;
margin: 0 auto;
}
.pricing-table {
display: flex;
flex-direction: column;
gap: 0;
background: rgba(255, 255, 255, 0.04);
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 14px;
overflow: hidden;
}
.pricing-table-row {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1.1rem 1.5rem;
border-bottom: 1px solid rgba(255, 255, 255, 0.06);
}
.pricing-table-row:last-child {
border-bottom: none;
}
.pricing-table-service {
color: var(--light-grey-100);
font-size: 0.95rem;
}
.pricing-table-price {
color: #fff;
font-weight: 700;
font-size: 0.95rem;
white-space: nowrap;
}
/* Retainer Cards */
.retainer-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1.5rem;
max-width: 1100px;
margin: 0 auto;
}
.retainer-card {
background: rgba(255, 255, 255, 0.05);
backdrop-filter: blur(12px);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 16px;
padding: 2rem;
display: flex;
flex-direction: column;
position: relative;
}
.retainer-card--popular {
border-color: var(--orange-100);
}
.retainer-popular-badge {
position: absolute;
top: -12px;
left: 50%;
transform: translateX(-50%);
background: var(--orange-100);
color: #fff;
padding: 0.3rem 1rem;
border-radius: 100px;
font-size: 0.8rem;
font-weight: 700;
white-space: nowrap;
}
.retainer-card h3 {
font-size: 1.3rem;
font-weight: 700;
color: #fff;
margin-bottom: 0.75rem;
}
.retainer-price {
margin-bottom: 1rem;
}
.retainer-amount {
font-size: 2.2rem;
font-weight: 900;
color: #fff;
}
.retainer-period {
color: var(--light-grey-100);
font-size: 1rem;
opacity: 0.7;
}
.retainer-meta {
display: flex;
gap: 1rem;
margin-bottom: 1.25rem;
}
.retainer-meta span {
background: rgba(255, 255, 255, 0.06);
padding: 0.3rem 0.8rem;
border-radius: 100px;
font-size: 0.8rem;
color: var(--light-grey-100);
}
.retainer-features {
list-style: none;
padding: 0;
margin: 0 0 1.5rem 0;
flex: 1;
}
.retainer-features li {
color: var(--light-grey-100);
font-size: 0.9rem;
line-height: 1.5;
padding: 0.35rem 0 0.35rem 1.2rem;
position: relative;
}
.retainer-features li::before {
content: '✓';
position: absolute;
left: 0;
color: var(--orange-100);
font-weight: 700;
}
.retainer-cta {
display: inline-block;
text-align: center;
text-decoration: none;
background: rgba(255, 91, 4, 0.15);
color: var(--orange-100);
border: 1px solid rgba(255, 91, 4, 0.3);
padding: 0.7rem 1.5rem;
border-radius: 100px;
font-size: 0.9rem;
font-weight: 600;
cursor: pointer;
transition: background 0.3s;
font-family: var(--font-primary);
}
.retainer-cta:hover {
background: rgba(255, 91, 4, 0.25);
}
.retainer-card--popular .retainer-cta {
background: var(--orange-100);
color: #fff;
border-color: var(--orange-100);
}
.retainer-card--popular .retainer-cta:hover {
background: #e65200;
}
/* Training */
.training-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 1.25rem;
max-width: 1000px;
margin: 0 auto;
}
.training-card {
background: rgba(255, 255, 255, 0.04);
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 12px;
padding: 1.5rem;
text-align: center;
display: flex;
flex-direction: column;
gap: 0.4rem;
}
.training-card h3 {
font-size: 0.95rem;
font-weight: 700;
color: #fff;
}
.training-price {
font-size: 1.2rem;
font-weight: 800;
color: var(--orange-100);
}
.training-desc {
font-size: 0.8rem;
color: var(--light-grey-100);
opacity: 0.7;
}
/* Payment Terms */
.payment-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 1.25rem;
max-width: 1000px;
margin: 0 auto;
}
.payment-card {
background: rgba(255, 255, 255, 0.04);
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 12px;
padding: 1.5rem;
}
.payment-card h3 {
font-size: 0.95rem;
font-weight: 700;
color: #fff;
margin-bottom: 0.3rem;
}
.payment-card p {
color: var(--light-grey-100);
font-size: 0.85rem;
margin-bottom: 0.75rem;
opacity: 0.8;
}
.payment-visual {
display: flex;
gap: 2px;
border-radius: 6px;
overflow: hidden;
}
.payment-bar {
background: var(--orange-100);
color: #fff;
font-size: 0.7rem;
font-weight: 700;
text-align: center;
padding: 0.3rem 0;
min-height: 24px;
display: flex;
align-items: center;
justify-content: center;
}
.payment-bar:nth-child(2) {
background: rgba(255, 91, 4, 0.6);
}
.payment-bar:nth-child(3) {
background: rgba(255, 91, 4, 0.35);
}
/* Discounts */
.discount-block {
background: rgba(255, 91, 4, 0.06);
border: 1px solid rgba(255, 91, 4, 0.18);
border-radius: 20px;
padding: 2.5rem;
max-width: 900px;
margin: 0 auto;
text-align: center;
}
.discount-block h2 {
font-size: 1.6rem;
font-weight: 800;
color: #fff;
margin-bottom: 0.5rem;
}
.discount-intro {
color: var(--light-grey-100);
font-size: 1rem;
margin-bottom: 2rem;
opacity: 0.85;
}
.discount-grid {
display: grid;
grid-template-columns: repeat(5, 1fr);
gap: 1rem;
}
.discount-item {
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 12px;
padding: 1.25rem 1rem;
display: flex;
flex-direction: column;
gap: 0.5rem;
align-items: center;
}
.discount-group {
color: var(--light-grey-100);
font-size: 0.85rem;
text-align: center;
}
.discount-amount {
color: var(--orange-100);
font-weight: 800;
font-size: 1.1rem;
}
/* Comparison Table */
.comparison-table-wrap {
max-width: 900px;
margin: 0 auto;
overflow-x: auto;
}
.comparison-table {
width: 100%;
border-collapse: collapse;
}
.comparison-table th,
.comparison-table td {
padding: 0.9rem 1.25rem;
text-align: left;
border-bottom: 1px solid rgba(255, 255, 255, 0.06);
font-size: 0.95rem;
color: var(--light-grey-100);
}
.comparison-table th {
color: #fff;
font-weight: 700;
font-size: 0.9rem;
text-transform: uppercase;
letter-spacing: 0.03em;
background: rgba(255, 255, 255, 0.04);
}
.comparison-table .comparison-highlight {
color: var(--orange-100);
font-weight: 600;
}
.comparison-table th.comparison-highlight {
color: var(--orange-100);
}
.comparison-metric {
color: #fff !important;
font-weight: 600;
}
/* FAQ */
.faq-list {
max-width: 800px;
margin: 0 auto;
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.faq-item {
background: rgba(255, 255, 255, 0.04);
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 12px;
overflow: hidden;
transition: border-color 0.3s;
}
.faq-item--open {
border-color: rgba(255, 255, 255, 0.15);
}
.faq-question {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
padding: 1.1rem 1.5rem;
background: none;
border: none;
color: #fff;
font-size: 1rem;
font-weight: 600;
cursor: pointer;
text-align: left;
font-family: var(--font-primary);
}
.faq-question svg {
width: 18px;
height: 18px;
flex-shrink: 0;
transition: transform 0.3s;
color: var(--light-grey-100);
}
.faq-answer {
padding: 0 1.5rem 1.1rem;
overflow: hidden;
}
.faq-answer p {
color: var(--light-grey-100);
font-size: 0.95rem;
line-height: 1.7;
opacity: 0.85;
}
/* Quote Form CTA */
.pricing-cta-section {
padding-bottom: 6rem;
}
.pricing-quote-subtitle {
text-align: center;
color: var(--light-grey-100);
font-size: 1.05rem;
opacity: 0.85;
margin-top: -1.5rem;
margin-bottom: 2.5rem;
}
.pricing-quote-form-wrap {
max-width: 800px;
margin: 0 auto;
background: rgba(255, 255, 255, 0.04);
backdrop-filter: blur(12px);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 20px;
padding: 2.5rem;
}
/* Responsive */
@media (max-width: 900px) {
.retainer-grid {
grid-template-columns: 1fr;
max-width: 450px;
}
.training-grid {
grid-template-columns: repeat(2, 1fr);
}
.payment-grid {
grid-template-columns: repeat(2, 1fr);
}
.discount-grid {
grid-template-columns: repeat(3, 1fr);
}
}
@media (max-width: 600px) {
.pricing-page {
padding-top: 6rem;
}
.pricing-hero h1 {
font-size: 2.2rem;
}
.pricing-hero-sub {
font-size: 1rem;
}
.pricing-section {
padding: 3rem 1rem;
}
.pricing-table-row {
flex-direction: column;
align-items: flex-start;
gap: 0.3rem;
}
.retainer-grid {
max-width: 100%;
}
.training-grid {
grid-template-columns: 1fr;
}
.payment-grid {
grid-template-columns: 1fr;
}
.discount-block {
padding: 1.5rem;
}
.discount-grid {
grid-template-columns: repeat(2, 1fr);
}
.comparison-table th,
.comparison-table td {
padding: 0.6rem 0.75rem;
font-size: 0.8rem;
}
.pricing-quote-form-wrap {
padding: 1.5rem;
}
}

389
src/pages/PricingPage.tsx Normal file
View file

@ -0,0 +1,389 @@
import { useEffect, useState } from 'react';
import { motion } from 'framer-motion';
import { Helmet } from 'react-helmet-async';
import SEO from '../components/SEO';
import QuoteForm from '../components/QuoteForm';
import './PricingPage.css';
const fadeUp = {
initial: { opacity: 0, y: 40 },
whileInView: { opacity: 1, y: 0 },
viewport: { once: true, margin: '-80px' },
transition: { duration: 0.5 },
};
const implementationPricing = [
{ service: 'Workflow Automation Implementation', price: '£3,500 £12,000' },
{ service: 'System Integration & Synchronisation', price: '£2,500 £10,000+' },
{ service: 'CRM Workflow Optimisation', price: '£3,000 £6,500' },
{ service: 'Marketing Automation Setup', price: '£3,500 £8,000' },
{ service: 'AI Integration & Enhancement', price: '£4,000 £12,000' },
{ service: 'Infrastructure Setup & Configuration', price: '£1,500 £4,000' },
];
const retainerTiers = [
{
name: 'Essential',
price: '£1,000',
period: '/month',
hours: '10 hours',
sla: '48h response',
features: [
'10 hours of support',
'Bug fixes & minor updates',
'48-hour response SLA',
'Email support',
'Monthly health check',
],
},
{
name: 'Professional',
price: '£2,000',
period: '/month',
hours: '22 hours',
sla: '24h response',
popular: true,
features: [
'22 hours of support',
'Bug fixes, updates & new features',
'24-hour response SLA',
'Email + Slack support',
'Bi-weekly strategy call',
'Priority scheduling',
],
},
{
name: 'Enterprise',
price: '£3,500',
period: '/month',
hours: '40 hours',
sla: '4h response',
features: [
'40 hours of support',
'Full-scope development & support',
'4-hour response SLA',
'Dedicated Slack channel',
'Weekly strategy call',
'Priority scheduling',
'Quarterly roadmap review',
],
},
];
const training = [
{ type: 'End-User Training', price: '£250', desc: 'Per session' },
{ type: 'Admin Training', price: '£600 £1,000', desc: 'Per session' },
{ type: 'Certification Programme', price: '£1,800', desc: 'Full course' },
{ type: 'Custom Workshop', price: '£400 £1,200', desc: 'Half to full day' },
];
const paymentTerms = [
{ range: 'Under £5,000', split: '100% upfront', visual: [100] },
{ range: '£5,000 £10,000', split: '50% / 50%', visual: [50, 50] },
{ range: 'Over £10,000', split: '33% / 33% / 34%', visual: [33, 33, 34] },
{ range: 'Public Sector', split: 'Net 30 terms', visual: [100] },
];
const discounts = [
{ group: 'Charities & Non-Profits', discount: 'Up to 50%' },
{ group: 'Startups (< 2 years)', discount: 'Up to 50%' },
{ group: 'Education', discount: 'Up to 50%' },
{ group: 'Public Sector', discount: '25% + free pilot project' },
{ group: 'Ukrainian Businesses', discount: 'Up to 50%' },
];
const comparison = [
{ metric: 'Setup Cost', aimpress: 'From £1,500', agency: '£5,000+ /mo', inhouse: '£35,000+ /yr' },
{ metric: 'Time to Deploy', aimpress: '28 weeks', agency: '36 months', inhouse: '612 months' },
{ metric: 'Availability', aimpress: '24/7 automated', agency: 'Business hours', inhouse: '9-to-5 only' },
{ metric: 'Scalability', aimpress: 'Unlimited', agency: 'Staff-limited', inhouse: 'Hard to scale' },
{ metric: 'You Own It', aimpress: 'Yes, always', agency: 'Rarely', inhouse: 'Yes' },
{ metric: 'Hidden Costs', aimpress: 'None', agency: 'Change requests', inhouse: 'Benefits, turnover' },
];
const faq = [
{
q: 'Are you a UK company?',
a: 'Yes. AImpress Ltd is registered in England & Wales (company number 16417799), VAT-registered, and ICO-registered. We operate under English law with full GDPR compliance.',
},
{
q: 'Do you offer managed hosting?',
a: 'We set up infrastructure on your own servers or cloud accounts. You own everything. We can provide ongoing management through our support retainers if needed.',
},
{
q: 'What platforms do you work with?',
a: 'We work with n8n, Make.com, Zapier, Power Automate, HubSpot, Salesforce, Pipedrive, Mailchimp, OpenAI, Claude, and many more. If your tool has an API, we can integrate it.',
},
{
q: 'Can you work with our existing tools?',
a: 'Absolutely. We build on top of your current stack — we don\'t rip and replace. Our goal is to connect and automate what you already have.',
},
{
q: 'What if I don\'t qualify for a discount?',
a: 'Our standard rates are already competitive at £90120/hr — significantly below typical UK agency rates. We offer fixed-price projects so you always know the total cost upfront.',
},
{
q: 'Do you work with clients outside the UK?',
a: 'Yes, we work with international clients. Our primary focus is UK businesses, but we\'re happy to support companies anywhere that need professional automation consulting.',
},
];
const PricingPage = () => {
useEffect(() => { window.scrollTo(0, 0); }, []);
const [openFaq, setOpenFaq] = useState<number | null>(null);
return (
<div className="pricing-page">
<SEO
title="Pricing | AImpress — Transparent Automation Costs from £1,500"
description="Fixed-price automation projects from £1,500. Support retainers from £1,000/month. Up to 50% discount for charities, startups, and public sector."
url="https://ai-impress.com/pricing"
/>
<Helmet>
<script type="application/ld+json">{JSON.stringify({
'@context': 'https://schema.org',
'@type': 'WebPage',
name: 'Pricing',
description: 'AImpress automation pricing and service packages',
offers: {
'@type': 'AggregateOffer',
priceCurrency: 'GBP',
lowPrice: '1500',
highPrice: '12000',
offerCount: implementationPricing.length,
},
})}</script>
</Helmet>
{/* Hero */}
<section className="pricing-hero">
<div className="container">
<motion.h1 {...fadeUp}>Simple, Transparent Pricing</motion.h1>
<motion.p className="pricing-hero-sub" {...fadeUp} transition={{ duration: 0.5, delay: 0.1 }}>
Fixed-price projects. No surprise costs. No vendor lock-in.
</motion.p>
</div>
</section>
{/* Implementation Pricing */}
<section className="pricing-section">
<div className="container">
<motion.h2 className="section-title" {...fadeUp}>Implementation Pricing</motion.h2>
<div className="pricing-table-wrap">
<div className="pricing-table">
{implementationPricing.map((item, i) => (
<motion.div
key={item.service}
className="pricing-table-row"
initial={{ opacity: 0, x: -20 }}
whileInView={{ opacity: 1, x: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.3, delay: i * 0.06 }}
>
<span className="pricing-table-service">{item.service}</span>
<span className="pricing-table-price">{item.price}</span>
</motion.div>
))}
</div>
</div>
</div>
</section>
{/* Support Retainers */}
<section className="pricing-section">
<div className="container">
<motion.h2 className="section-title" {...fadeUp}>Support Retainers</motion.h2>
<div className="retainer-grid">
{retainerTiers.map((tier, i) => (
<motion.div
key={tier.name}
className={`retainer-card ${tier.popular ? 'retainer-card--popular' : ''}`}
initial={{ opacity: 0, y: 40 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: '-60px' }}
transition={{ duration: 0.5, delay: i * 0.1 }}
>
{tier.popular && <span className="retainer-popular-badge">Most Popular</span>}
<h3>{tier.name}</h3>
<div className="retainer-price">
<span className="retainer-amount">{tier.price}</span>
<span className="retainer-period">{tier.period}</span>
</div>
<div className="retainer-meta">
<span>{tier.hours}</span>
<span>{tier.sla}</span>
</div>
<ul className="retainer-features">
{tier.features.map((f) => (
<li key={f}>{f}</li>
))}
</ul>
<a href="#get-quote" className="retainer-cta">
Get Started
</a>
</motion.div>
))}
</div>
</div>
</section>
{/* Training & Workshops */}
<section className="pricing-section">
<div className="container">
<motion.h2 className="section-title" {...fadeUp}>Training & Workshops</motion.h2>
<div className="training-grid">
{training.map((t, i) => (
<motion.div
key={t.type}
className="training-card"
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.3, delay: i * 0.08 }}
>
<h3>{t.type}</h3>
<span className="training-price">{t.price}</span>
<span className="training-desc">{t.desc}</span>
</motion.div>
))}
</div>
</div>
</section>
{/* Payment Terms */}
<section className="pricing-section">
<div className="container">
<motion.h2 className="section-title" {...fadeUp}>Payment Terms</motion.h2>
<div className="payment-grid">
{paymentTerms.map((pt, i) => (
<motion.div
key={pt.range}
className="payment-card"
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.3, delay: i * 0.08 }}
>
<h3>{pt.range}</h3>
<p>{pt.split}</p>
<div className="payment-visual">
{pt.visual.map((pct, j) => (
<div key={j} className="payment-bar" style={{ width: `${pct}%` }}>
{pct}%
</div>
))}
</div>
</motion.div>
))}
</div>
</div>
</section>
{/* Impact Grant (Discounts) */}
<section className="pricing-section">
<div className="container">
<motion.div className="discount-block" {...fadeUp}>
<h2>Impact Grant Programme</h2>
<p className="discount-intro">We believe automation should be accessible to organisations making a difference. Eligible groups receive significant discounts.</p>
<div className="discount-grid">
{discounts.map((d, i) => (
<motion.div
key={d.group}
className="discount-item"
initial={{ opacity: 0, scale: 0.95 }}
whileInView={{ opacity: 1, scale: 1 }}
viewport={{ once: true }}
transition={{ duration: 0.3, delay: i * 0.06 }}
>
<span className="discount-group">{d.group}</span>
<span className="discount-amount">{d.discount}</span>
</motion.div>
))}
</div>
</motion.div>
</div>
</section>
{/* Comparison */}
<section className="pricing-section">
<div className="container">
<motion.h2 className="section-title" {...fadeUp}>How We Compare</motion.h2>
<motion.div className="comparison-table-wrap" {...fadeUp}>
<table className="comparison-table">
<thead>
<tr>
<th></th>
<th className="comparison-highlight">AImpress</th>
<th>Agency</th>
<th>In-House</th>
</tr>
</thead>
<tbody>
{comparison.map((row) => (
<tr key={row.metric}>
<td className="comparison-metric">{row.metric}</td>
<td className="comparison-highlight">{row.aimpress}</td>
<td>{row.agency}</td>
<td>{row.inhouse}</td>
</tr>
))}
</tbody>
</table>
</motion.div>
</div>
</section>
{/* FAQ */}
<section className="pricing-section">
<div className="container">
<motion.h2 className="section-title" {...fadeUp}>Frequently Asked Questions</motion.h2>
<div className="faq-list">
{faq.map((item, i) => (
<motion.div
key={i}
className={`faq-item ${openFaq === i ? 'faq-item--open' : ''}`}
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.3, delay: i * 0.06 }}
>
<button className="faq-question" onClick={() => setOpenFaq(openFaq === i ? null : i)}>
<span>{item.q}</span>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" style={{ transform: openFaq === i ? 'rotate(180deg)' : 'rotate(0)' }}>
<polyline points="6 9 12 15 18 9"/>
</svg>
</button>
{openFaq === i && (
<motion.div
className="faq-answer"
initial={{ opacity: 0, height: 0 }}
animate={{ opacity: 1, height: 'auto' }}
transition={{ duration: 0.3 }}
>
<p>{item.a}</p>
</motion.div>
)}
</motion.div>
))}
</div>
</div>
</section>
{/* Quote Form CTA */}
<section className="pricing-section pricing-cta-section" id="get-quote">
<div className="container">
<motion.h2 className="section-title" {...fadeUp}>Get Your Quote Today</motion.h2>
<motion.p className="pricing-quote-subtitle" {...fadeUp} transition={{ duration: 0.5, delay: 0.1 }}>
Tell us about your project and we'll send you a detailed, fixed-price proposal within 24 hours.
</motion.p>
<motion.div className="pricing-quote-form-wrap" {...fadeUp} transition={{ duration: 0.5, delay: 0.15 }}>
<QuoteForm />
</motion.div>
</div>
</section>
</div>
);
};
export default PricingPage;

379
src/pages/ServicesPage.css Normal file
View file

@ -0,0 +1,379 @@
.services-page {
padding-top: 8rem;
min-height: 100vh;
}
/* Hero */
.services-hero {
padding: 4rem 2rem 3rem;
text-align: center;
}
.services-hero h1 {
font-size: 3.2rem;
font-weight: 800;
color: #fff;
margin-bottom: 1rem;
}
.services-hero-sub {
font-size: 1.2rem;
color: var(--light-grey-100);
opacity: 0.8;
max-width: 600px;
margin: 0 auto;
}
/* Sections */
.services-section {
padding: 4rem 2rem;
}
.services-section .section-title {
text-align: center;
font-size: 2rem;
font-weight: 800;
color: #fff;
margin-bottom: 2.5rem;
}
/* Service Cards Grid */
.services-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 1.5rem;
max-width: 1100px;
margin: 0 auto;
}
.service-card {
background: rgba(255, 255, 255, 0.05);
backdrop-filter: blur(12px);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 16px;
padding: 2rem;
cursor: pointer;
transition: border-color 0.3s, transform 0.2s;
}
.service-card:hover {
border-color: rgba(255, 255, 255, 0.2);
}
.service-card--expanded {
border-color: var(--orange-100);
}
.service-card-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1rem;
}
.service-card-icon {
width: 36px;
height: 36px;
color: var(--orange-100);
}
.service-card-icon svg {
width: 100%;
height: 100%;
}
.service-card-price {
background: rgba(255, 91, 4, 0.12);
color: var(--orange-100);
padding: 0.35rem 0.9rem;
border-radius: 100px;
font-size: 0.85rem;
font-weight: 600;
white-space: nowrap;
}
.service-card h3 {
font-size: 1.15rem;
font-weight: 700;
color: #fff;
margin-bottom: 0.6rem;
}
.service-card-purpose {
color: var(--light-grey-100);
font-size: 0.95rem;
line-height: 1.6;
opacity: 0.85;
margin-bottom: 0.75rem;
}
.service-card-includes {
list-style: none;
padding: 0;
margin: 0.75rem 0;
border-top: 1px solid rgba(255, 255, 255, 0.08);
padding-top: 0.75rem;
}
.service-card-includes li {
color: var(--light-grey-100);
font-size: 0.9rem;
line-height: 1.5;
padding: 0.35rem 0 0.35rem 1.2rem;
position: relative;
}
.service-card-includes li::before {
content: '✓';
position: absolute;
left: 0;
color: var(--orange-100);
font-weight: 700;
}
.service-card-toggle {
display: inline-flex;
align-items: center;
gap: 0.4rem;
color: var(--orange-100);
font-size: 0.85rem;
font-weight: 600;
margin-top: 0.5rem;
}
.service-card-toggle svg {
width: 16px;
height: 16px;
transition: transform 0.3s;
}
/* Assurance Pack */
.assurance-pack {
background: rgba(255, 91, 4, 0.06);
border: 1px solid rgba(255, 91, 4, 0.18);
border-radius: 20px;
padding: 2.5rem;
max-width: 1000px;
margin: 0 auto;
}
.assurance-header {
text-align: center;
margin-bottom: 2rem;
}
.assurance-header h2 {
font-size: 1.6rem;
font-weight: 800;
color: #fff;
margin-bottom: 0.5rem;
}
.assurance-badge {
display: inline-block;
background: rgba(255, 91, 4, 0.15);
color: var(--orange-100);
padding: 0.4rem 1.2rem;
border-radius: 100px;
font-size: 0.9rem;
font-weight: 600;
}
.assurance-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 0.75rem;
}
.assurance-item {
display: flex;
align-items: center;
gap: 0.6rem;
padding: 0.5rem 0;
}
.assurance-item svg {
width: 20px;
height: 20px;
flex-shrink: 0;
}
.assurance-item span {
color: var(--light-grey-100);
font-size: 0.95rem;
}
/* Process Steps */
.process-steps {
max-width: 800px;
margin: 0 auto;
display: flex;
flex-direction: column;
gap: 1.5rem;
}
.process-step {
display: flex;
gap: 1.5rem;
align-items: flex-start;
background: rgba(255, 255, 255, 0.04);
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 14px;
padding: 1.5rem;
}
.process-step-number {
font-size: 2rem;
font-weight: 900;
color: var(--orange-100);
opacity: 0.7;
line-height: 1;
flex-shrink: 0;
width: 50px;
}
.process-step-content h3 {
font-size: 1.1rem;
font-weight: 700;
color: #fff;
margin-bottom: 0.4rem;
}
.process-step-content p {
color: var(--light-grey-100);
font-size: 0.95rem;
line-height: 1.6;
opacity: 0.85;
}
/* Tech Stack */
.tech-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 1rem;
max-width: 1000px;
margin: 0 auto;
}
.tech-card {
background: rgba(255, 255, 255, 0.04);
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 12px;
padding: 1.25rem;
text-align: center;
}
.tech-card h3 {
font-size: 0.85rem;
font-weight: 700;
color: var(--orange-100);
text-transform: uppercase;
letter-spacing: 0.05em;
margin-bottom: 0.5rem;
}
.tech-card p {
color: var(--light-grey-100);
font-size: 0.85rem;
line-height: 1.5;
opacity: 0.8;
}
/* CTA */
.services-cta-section {
padding-bottom: 6rem;
}
.services-cta {
text-align: center;
background: rgba(255, 91, 4, 0.08);
border: 1px solid rgba(255, 91, 4, 0.2);
border-radius: 20px;
padding: 3.5rem 2rem;
max-width: 700px;
margin: 0 auto;
}
.services-cta h2 {
font-size: 1.8rem;
font-weight: 800;
color: #fff;
margin-bottom: 0.75rem;
}
.services-cta p {
color: var(--light-grey-100);
font-size: 1.05rem;
margin-bottom: 2rem;
opacity: 0.85;
}
.services-cta-btn {
background: var(--orange-100);
color: #fff;
border: none;
padding: 0.9rem 2.5rem;
border-radius: 100px;
font-size: 1rem;
font-weight: 600;
cursor: pointer;
font-family: var(--font-primary);
}
/* Responsive */
@media (max-width: 900px) {
.services-grid {
grid-template-columns: 1fr;
}
.assurance-grid {
grid-template-columns: repeat(2, 1fr);
}
.tech-grid {
grid-template-columns: repeat(3, 1fr);
}
}
@media (max-width: 600px) {
.services-page {
padding-top: 6rem;
}
.services-hero h1 {
font-size: 2.2rem;
}
.services-hero-sub {
font-size: 1rem;
}
.services-section {
padding: 3rem 1rem;
}
.assurance-pack {
padding: 1.5rem;
}
.assurance-grid {
grid-template-columns: 1fr;
}
.tech-grid {
grid-template-columns: repeat(2, 1fr);
}
.process-step {
flex-direction: column;
gap: 0.75rem;
}
.services-cta {
padding: 2.5rem 1.5rem;
}
.services-cta h2 {
font-size: 1.4rem;
}
}

353
src/pages/ServicesPage.tsx Normal file
View file

@ -0,0 +1,353 @@
import { useEffect, useState } from 'react';
import { motion } from 'framer-motion';
import { Helmet } from 'react-helmet-async';
import SEO from '../components/SEO';
import Modal from '../components/Modal';
import ContactForm from '../components/ContactForm';
import './ServicesPage.css';
const fadeUp = {
initial: { opacity: 0, y: 40 },
whileInView: { opacity: 1, y: 0 },
viewport: { once: true, margin: '-80px' },
transition: { duration: 0.5 },
};
const services = [
{
icon: (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
<polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/>
</svg>
),
title: 'Workflow Automation Implementation',
price: '£3,500 £12,000',
purpose: 'Automate repetitive business processes end-to-end so your team focuses on high-value work.',
includes: [
'Process discovery & mapping',
'Custom workflow design & build (n8n / Make.com)',
'Multi-step logic with conditional branching',
'Error handling & retry mechanisms',
'Testing, deployment & documentation',
],
},
{
icon: (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
<path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/>
<polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/>
</svg>
),
title: 'System Integration & Synchronisation',
price: '£2,500 £10,000+',
purpose: 'Connect your tools into a single source of truth — CRM, accounting, e-commerce, comms, and more.',
includes: [
'API integration between platforms',
'Bi-directional data sync',
'Data mapping & transformation',
'Webhook & event-driven triggers',
'Monitoring & alerting setup',
],
},
{
icon: (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
<path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/>
<circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/>
<path d="M16 3.13a4 4 0 0 1 0 7.75"/>
</svg>
),
title: 'CRM Workflow Optimisation',
price: '£3,000 £6,500',
purpose: 'Streamline your sales pipeline, automate follow-ups, and ensure no lead falls through the cracks.',
includes: [
'CRM audit & pipeline restructure',
'Automated lead scoring & routing',
'Email sequence automation',
'Task & reminder workflows',
'Reporting dashboard setup',
],
},
{
icon: (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
<path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/>
<polyline points="22,6 12,13 2,6"/>
</svg>
),
title: 'Marketing Automation Setup',
price: '£3,500 £8,000',
purpose: 'Put your campaigns, lead nurturing, and ads on autopilot with targeted, data-driven automation.',
includes: [
'Email drip campaign setup',
'Lead capture & form automation',
'Audience segmentation logic',
'Social media scheduling integration',
'Analytics & conversion tracking',
],
},
{
icon: (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
<polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/>
</svg>
),
title: 'AI Integration & Enhancement',
price: '£4,000 £12,000',
purpose: 'Add AI capabilities to your existing workflows — chatbots, content generation, document processing, and more.',
includes: [
'AI model selection & integration (OpenAI, Claude, etc.)',
'Custom chatbot / virtual assistant build',
'Document & data extraction with AI',
'AI-powered content generation pipelines',
'Prompt engineering & fine-tuning',
],
},
{
icon: (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
<rect x="2" y="3" width="20" height="14" rx="2" ry="2"/>
<line x1="8" y1="21" x2="16" y2="21"/><line x1="12" y1="17" x2="12" y2="21"/>
</svg>
),
title: 'Infrastructure Setup & Configuration',
price: '£1,500 £4,000',
purpose: 'Set up your automation infrastructure on servers you own — secure, scalable, and fully yours.',
includes: [
'Server provisioning (VPS / cloud)',
'n8n / automation platform deployment',
'SSL, firewall & security hardening',
'Backup & recovery configuration',
'Monitoring & uptime alerting',
],
},
];
const assurancePack = [
'Dedicated project manager',
'Weekly progress reports',
'Full technical documentation',
'End-user training session',
'Admin training session',
'30-day post-launch support',
'Bug fixes within SLA',
'Knowledge base & runbooks',
'Handover & transition plan',
];
const processSteps = [
{ step: '01', title: 'Discovery', desc: 'Free consultation to understand your goals, audit current workflows, and identify automation opportunities.' },
{ step: '02', title: 'Proposal & Scope', desc: 'Detailed project plan with fixed pricing, timelines, and deliverables. No surprises.' },
{ step: '03', title: 'Development', desc: 'We build and iterate on your automations with regular check-ins and progress demos.' },
{ step: '04', title: 'Testing & Launch', desc: 'Rigorous QA, UAT with your team, and a smooth go-live with monitoring in place.' },
{ step: '05', title: 'Post-Launch Support', desc: '30 days of included support, team training, full documentation, and optional retainer.' },
];
const techStack = [
{ category: 'Workflow', tools: 'n8n, Make.com, Zapier, Power Automate' },
{ category: 'CRM', tools: 'HubSpot, Salesforce, Pipedrive, Zoho' },
{ category: 'Marketing', tools: 'Mailchimp, ActiveCampaign, Brevo, Meta Ads' },
{ category: 'AI', tools: 'OpenAI, Claude, Google AI, Whisper, LangChain' },
{ category: 'Infrastructure', tools: 'AWS, Hetzner, Docker, Nginx, Cloudflare' },
{ category: 'Analytics', tools: 'Power BI, Google Analytics, Mixpanel, Looker' },
{ category: 'Communication', tools: 'Slack, Teams, Twilio, WhatsApp Business' },
];
const ServicesPage = () => {
useEffect(() => { window.scrollTo(0, 0); }, []);
const [isModalOpen, setIsModalOpen] = useState(false);
const [expandedCard, setExpandedCard] = useState<number | null>(null);
return (
<div className="services-page">
<SEO
title="AI & Automation Services for UK Businesses | AImpress"
description="Workflow automation, system integration, CRM optimisation, marketing automation, AI integration, and infrastructure setup. Fixed-price projects from £1,500."
url="https://ai-impress.com/services"
/>
<Helmet>
<script type="application/ld+json">{JSON.stringify({
'@context': 'https://schema.org',
'@type': 'Service',
provider: {
'@type': 'Organization',
name: 'AImpress Ltd',
url: 'https://ai-impress.com',
},
serviceType: 'AI & Automation Consulting',
areaServed: 'GB',
hasOfferCatalog: {
'@type': 'OfferCatalog',
name: 'Automation Services',
itemListElement: services.map((s, i) => ({
'@type': 'Offer',
itemOffered: {
'@type': 'Service',
name: s.title,
description: s.purpose,
},
position: i + 1,
})),
},
})}</script>
</Helmet>
{/* Hero */}
<section className="services-hero">
<div className="container">
<motion.h1 {...fadeUp}>Our Services</motion.h1>
<motion.p className="services-hero-sub" {...fadeUp} transition={{ duration: 0.5, delay: 0.1 }}>
End-to-end automation consulting from discovery to deployment and beyond.
</motion.p>
</div>
</section>
{/* Service Cards */}
<section className="services-section">
<div className="container">
<div className="services-grid">
{services.map((s, i) => {
const isExpanded = expandedCard === i;
return (
<motion.div
key={s.title}
className={`service-card ${isExpanded ? 'service-card--expanded' : ''}`}
initial={{ opacity: 0, y: 40 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: '-60px' }}
transition={{ duration: 0.5, delay: i * 0.08 }}
onClick={() => setExpandedCard(isExpanded ? null : i)}
>
<div className="service-card-header">
<div className="service-card-icon">{s.icon}</div>
<div className="service-card-price">{s.price}</div>
</div>
<h3>{s.title}</h3>
<p className="service-card-purpose">{s.purpose}</p>
{isExpanded && (
<motion.ul
className="service-card-includes"
initial={{ opacity: 0, height: 0 }}
animate={{ opacity: 1, height: 'auto' }}
transition={{ duration: 0.3 }}
>
{s.includes.map((item) => (
<li key={item}>{item}</li>
))}
</motion.ul>
)}
<span className="service-card-toggle">
{isExpanded ? 'Show less' : 'What\'s included'}
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" style={{ transform: isExpanded ? 'rotate(180deg)' : 'rotate(0)' }}>
<polyline points="6 9 12 15 18 9"/>
</svg>
</span>
</motion.div>
);
})}
</div>
</div>
</section>
{/* Assurance Pack */}
<section className="services-section">
<div className="container">
<motion.div className="assurance-pack" {...fadeUp}>
<div className="assurance-header">
<h2>AImpress Assurance Pack</h2>
<span className="assurance-badge">Included free in every project (value £1,500)</span>
</div>
<div className="assurance-grid">
{assurancePack.map((item, i) => (
<motion.div
key={item}
className="assurance-item"
initial={{ opacity: 0, x: -20 }}
whileInView={{ opacity: 1, x: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.3, delay: i * 0.05 }}
>
<svg viewBox="0 0 24 24" fill="none" stroke="var(--orange-100)" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
<polyline points="20 6 9 17 4 12"/>
</svg>
<span>{item}</span>
</motion.div>
))}
</div>
</motion.div>
</div>
</section>
{/* How We Work */}
<section className="services-section">
<div className="container">
<motion.h2 className="section-title" {...fadeUp}>How We Work</motion.h2>
<div className="process-steps">
{processSteps.map((s, i) => (
<motion.div
key={s.step}
className="process-step"
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: '-60px' }}
transition={{ duration: 0.4, delay: i * 0.1 }}
>
<div className="process-step-number">{s.step}</div>
<div className="process-step-content">
<h3>{s.title}</h3>
<p>{s.desc}</p>
</div>
</motion.div>
))}
</div>
</div>
</section>
{/* Technology Stack */}
<section className="services-section">
<div className="container">
<motion.h2 className="section-title" {...fadeUp}>Technology Stack</motion.h2>
<div className="tech-grid">
{techStack.map((t, i) => (
<motion.div
key={t.category}
className="tech-card"
initial={{ opacity: 0, scale: 0.95 }}
whileInView={{ opacity: 1, scale: 1 }}
viewport={{ once: true }}
transition={{ duration: 0.3, delay: i * 0.06 }}
>
<h3>{t.category}</h3>
<p>{t.tools}</p>
</motion.div>
))}
</div>
</div>
</section>
{/* CTA */}
<section className="services-section services-cta-section">
<div className="container">
<motion.div className="services-cta" {...fadeUp}>
<h2>Not Sure Where to Start?</h2>
<p>Book a free consultation and we'll map out the best automation strategy for your business.</p>
<motion.button
className="services-cta-btn"
onClick={() => setIsModalOpen(true)}
whileHover={{ scale: 1.03 }}
whileTap={{ scale: 0.97 }}
>
Get Your Free Consultation
</motion.button>
</motion.div>
</div>
</section>
<Modal isOpen={isModalOpen} onClose={() => setIsModalOpen(false)}>
<ContactForm onClose={() => setIsModalOpen(false)} />
</Modal>
</div>
);
};
export default ServicesPage;