First Init
Deploy to Production / Build & Verify (push) Failing after 5m56s
Ping Search Engines / Notify Search Engines (push) Successful in 2s
Deploy to Production / Pre-Deploy Tests (push) Has been skipped
Deploy to Production / Deploy to Railway (push) Has been skipped
Deploy to Production / Deploy to Render (push) Has been skipped
Deploy to Production / Deploy to VPS (PM2) (push) Has been skipped
Deploy to Production / Deploy to Fly.io (push) Has been skipped
Deploy to Production / Post-Deploy Verification (push) Has been skipped
Deploy to Production / Notify on Failure (push) Successful in 2s
E2E Test Suite / Critical User Journeys (push) Has been skipped
E2E Test Suite / API Integration Tests (push) Has been skipped
E2E Test Suite / Smoke Tests (P0) (push) Failing after 11m26s
E2E Test Suite / Form Interaction Tests (push) Failing after 11m42s
E2E Test Suite / Destructive & Chaos Tests (push) Failing after 12m2s
E2E Test Suite / Cross-Browser Regression (chromium) (push) Failing after 16m14s
E2E Test Suite / Cross-Browser Regression (webkit) (push) Failing after 17m45s
E2E Test Suite / Cross-Browser Regression (firefox) (push) Failing after 25m23s
E2E Test Suite / Security Header Tests (push) Failing after 7m55s
E2E Test Suite / Test Report Summary (push) Failing after 20s
E2E Test Suite / Mobile Device Tests (push) Failing after 2h49m9s
Uptime Monitor / Health & Response Time (push) Failing after 2s
Uptime Monitor / SSL Certificate (push) Successful in 2s
Uptime Monitor / Send Alerts (push) Failing after 3s
Uptime Monitor / Record Uptime Success (push) Has been skipped

This commit is contained in:
2026-03-21 16:46:46 +05:30
commit d402256547
216 changed files with 48375 additions and 0 deletions
+490
View File
@@ -0,0 +1,490 @@
---
// About Us Page for WorkRoot IT Solutions
// Features: Company story, team member cards, mission/vision statements, company timeline
import BaseLayout from '../layouts/BaseLayout.astro';
import SEO from '../components/SEO.astro';
// Team member data
const teamMembers = [
{
name: 'Sarah Chen',
role: 'CEO & Founder',
bio: 'Visionary leader with 15+ years in enterprise technology. Former VP at Fortune 500 tech company.',
image: 'https://images.unsplash.com/photo-1573496359142-b8d87734a5a2?w=400&h=400&fit=crop&crop=face&auto=format&q=75',
linkedin: '#',
twitter: '#',
},
{
name: 'Michael Rodriguez',
role: 'CTO',
bio: 'Cloud architecture expert and open-source contributor. Passionate about scalable solutions.',
image: 'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=400&h=400&fit=crop&crop=face&auto=format&q=75',
linkedin: '#',
twitter: '#',
},
{
name: 'Emily Watson',
role: 'Head of Design',
bio: 'Award-winning UX designer focused on creating intuitive, accessible digital experiences.',
image: 'https://images.unsplash.com/photo-1580489944761-15a19d654956?w=400&h=400&fit=crop&crop=face&auto=format&q=75',
linkedin: '#',
twitter: '#',
},
{
name: 'David Park',
role: 'Lead Developer',
bio: 'Full-stack engineer specializing in React and Node.js. Mentors junior developers.',
image: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=400&h=400&fit=crop&crop=face&auto=format&q=75',
linkedin: '#',
twitter: '#',
},
{
name: 'Lisa Thompson',
role: 'Project Manager',
bio: 'PMP-certified professional delivering projects on time and within budget for 10+ years.',
image: 'https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=400&h=400&fit=crop&crop=face&auto=format&q=75',
linkedin: '#',
twitter: '#',
},
{
name: 'James Wilson',
role: 'DevOps Engineer',
bio: 'Infrastructure automation specialist. Kubernetes and AWS certified solutions architect.',
image: 'https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=400&h=400&fit=crop&crop=face&auto=format&q=75',
linkedin: '#',
twitter: '#',
},
];
// Company stats
const stats = [
{ value: '10+', label: 'Years of Experience' },
{ value: '200+', label: 'Projects Delivered' },
{ value: '50+', label: 'Team Members' },
{ value: '98%', label: 'Client Satisfaction' },
];
// Company timeline
const timeline = [
{
year: '2014',
title: 'The Beginning',
description: 'WorkRoot founded by three passionate developers in a small garage office.',
},
{
year: '2016',
title: 'First Major Client',
description: 'Secured our first enterprise contract, launching our growth trajectory.',
},
{
year: '2018',
title: 'Team Expansion',
description: 'Grew to 20+ team members and opened our first dedicated office space.',
},
{
year: '2020',
title: 'Global Reach',
description: 'Expanded operations internationally, serving clients across 15 countries.',
},
{
year: '2022',
title: 'AI Innovation',
description: 'Launched AI/ML division, pioneering intelligent automation solutions.',
},
{
year: '2024',
title: 'Industry Leader',
description: 'Recognized as top IT solutions provider with 200+ successful projects.',
},
];
// Core values
const values = [
{
title: 'Innovation',
description: 'We embrace cutting-edge technologies to deliver future-proof solutions.',
icon: 'lightbulb',
},
{
title: 'Integrity',
description: 'Transparency and honesty are the foundation of every client relationship.',
icon: 'shield',
},
{
title: 'Excellence',
description: 'We pursue quality in every line of code and every interaction.',
icon: 'star',
},
{
title: 'Collaboration',
description: 'Great solutions emerge from diverse perspectives working together.',
icon: 'users',
},
];
---
<BaseLayout
title="About Us — Our Story & Team"
description="WorkRoot IT Solutions: founded 2014, 50+ team members, 200+ projects, 15 countries served. Meet the technologists behind your digital transformation. Innovation, integrity, excellence."
>
<SEO
slot="head"
type="AboutPage"
breadcrumbs={[
{ name: 'Home', url: '/' },
{ name: 'About Us', url: '/about' }
]}
/>
<!-- Hero Section -->
<section class="relative min-h-[70vh] flex items-center overflow-hidden bg-gradient-to-br from-secondary-900 via-secondary-800 to-primary-900">
<!-- Background decorative elements -->
<div class="absolute inset-0 overflow-hidden pointer-events-none" aria-hidden="true">
<div class="absolute -top-40 -right-40 w-96 h-96 bg-primary/20 rounded-full blur-3xl"></div>
<div class="absolute -bottom-40 -left-40 w-96 h-96 bg-accent/10 rounded-full blur-3xl"></div>
<div class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[800px] h-[800px] bg-primary/5 rounded-full blur-3xl"></div>
<!-- Grid pattern overlay -->
<div class="absolute inset-0 bg-[linear-gradient(rgba(255,255,255,0.03)_1px,transparent_1px),linear-gradient(90deg,rgba(255,255,255,0.03)_1px,transparent_1px)] bg-[size:64px_64px]"></div>
</div>
<div class="container-wrapper relative z-10 py-20">
<div class="max-w-4xl">
<span class="inline-block px-4 py-1.5 mb-6 text-sm font-medium text-primary-300 bg-primary-500/10 rounded-full border border-primary-500/20">
About WorkRoot
</span>
<h1 class="text-4xl sm:text-5xl lg:text-6xl xl:text-7xl font-bold text-white leading-tight mb-6">
Building the Future of
<span class="block text-transparent bg-clip-text bg-gradient-to-r from-primary-300 to-accent-400 mt-2">
Digital Innovation
</span>
</h1>
<p class="text-lg sm:text-xl text-secondary-200 max-w-2xl mb-8">
We're a team of passionate technologists dedicated to transforming businesses through innovative IT solutions.
</p>
<!-- Quick stats in hero -->
<div class="grid grid-cols-2 sm:grid-cols-4 gap-6 mt-10 max-w-3xl">
{stats.map((stat) => (
<div class="text-center sm:text-left">
<p class="text-3xl sm:text-4xl font-bold text-primary-300 mb-1">{stat.value}</p>
<p class="text-secondary-300 text-sm font-medium">{stat.label}</p>
</div>
))}
</div>
</div>
</div>
</section>
<!-- Company Story Section -->
<section class="py-16 lg:py-24 bg-white">
<div class="container-wrapper">
<div class="grid lg:grid-cols-2 gap-12 lg:gap-16 items-center">
<div class="order-2 lg:order-1" data-animate="fade-right">
<span class="text-primary-500 font-semibold text-sm uppercase tracking-wider">Our Story</span>
<h2 class="text-3xl sm:text-4xl font-bold text-secondary-900 mt-2 mb-6">
From Startup to Industry Leader
</h2>
<div class="space-y-4 text-secondary-600 leading-relaxed">
<p>
Founded in 2014, WorkRoot IT Solutions began with a simple mission: to make enterprise-grade technology accessible to businesses of all sizes. What started as a small team of three passionate developers has grown into a full-service IT consultancy trusted by companies worldwide.
</p>
<p>
Our journey hasn't always been easy. We've navigated economic downturns, technological shifts, and global challenges. But each obstacle has strengthened our resolve and sharpened our expertise. Today, we're proud to serve over 200 clients across diverse industries.
</p>
<p>
What sets us apart isn't just our technical skills—it's our commitment to understanding your business. We don't believe in one-size-fits-all solutions. Every project we undertake is tailored to your unique needs, goals, and constraints.
</p>
</div>
</div>
<div class="order-1 lg:order-2 relative" data-animate="fade-left" data-delay="150">
<div class="aspect-[4/3] rounded-2xl overflow-hidden shadow-2xl bg-secondary-200">
<img
src="https://images.unsplash.com/photo-1522071820081-009f0129c71c?w=800&h=600&fit=crop&auto=format&q=75"
alt="WorkRoot team collaborating in office"
width="800"
height="600"
class="w-full h-full object-cover"
loading="eager"
decoding="async"
fetchpriority="high"
/>
</div>
<div class="absolute -bottom-6 -left-6 bg-primary-500 text-white p-6 rounded-xl shadow-xl hidden sm:block">
<p class="text-4xl font-bold">10+</p>
<p class="text-primary-100">Years of Excellence</p>
</div>
</div>
</div>
</div>
</section>
<!-- Company Timeline Section -->
<section class="py-16 lg:py-24 bg-white">
<div class="container-wrapper">
<div class="text-center max-w-2xl mx-auto mb-12 lg:mb-16" data-animate="fade-up">
<span class="text-primary-500 font-semibold text-sm uppercase tracking-wider">Our Journey</span>
<h2 class="text-3xl sm:text-4xl font-bold text-secondary-900 mt-2 mb-4">Company Timeline</h2>
<p class="text-secondary-600">
A decade of innovation, growth, and excellence in technology solutions.
</p>
</div>
<div class="max-w-5xl mx-auto">
<!-- Timeline container -->
<div class="relative">
<!-- Vertical line (hidden on mobile, visible on md+) -->
<div class="hidden md:block absolute left-1/2 top-0 bottom-0 w-0.5 bg-gradient-to-b from-primary-500 via-primary-300 to-primary-500 transform -translate-x-1/2" aria-hidden="true"></div>
<div class="space-y-8 md:space-y-12">
{timeline.map((item, index) => (
<div class={`relative ${index % 2 === 0 ? 'md:mr-auto md:pr-12' : 'md:ml-auto md:pl-12'} md:w-1/2`} data-animate={index % 2 === 0 ? 'fade-right' : 'fade-left'} data-delay={String(index * 100)}>
<!-- Timeline dot -->
<div class="hidden md:flex absolute top-0 w-4 h-4 bg-primary-500 rounded-full border-4 border-white shadow-lg z-10"
style={index % 2 === 0 ? 'right: -2.25rem;' : 'left: -2.25rem;'}
aria-hidden="true">
</div>
<!-- Content card -->
<div class={`relative bg-white border-2 border-secondary-100 rounded-2xl p-6 shadow-sm hover:shadow-lg transition-all duration-300 group hover:border-primary-200 ${index % 2 === 0 ? 'md:text-right' : 'md:text-left'}`}>
<div class="absolute -top-3 left-6 md:left-auto md:right-6 px-4 py-1 bg-gradient-to-r from-primary-500 to-primary-600 text-white text-sm font-bold rounded-full shadow-md">
{item.year}
</div>
<h3 class="text-xl font-bold text-secondary-900 mt-4 mb-2 group-hover:text-primary-600 transition-colors">
{item.title}
</h3>
<p class="text-secondary-600 leading-relaxed">
{item.description}
</p>
</div>
</div>
))}
</div>
</div>
</div>
</div>
</section>
<!-- Mission & Vision Section -->
<section class="py-16 lg:py-24 bg-gradient-to-b from-secondary-50 to-white">
<div class="container-wrapper">
<div class="text-center mb-12 lg:mb-16" data-animate="fade-up">
<span class="text-primary-500 font-semibold text-sm uppercase tracking-wider">Our Purpose</span>
<h2 class="text-3xl sm:text-4xl font-bold text-secondary-900 mt-2">Mission & Vision</h2>
</div>
<div class="grid lg:grid-cols-2 gap-8 lg:gap-12">
<!-- Mission -->
<div class="relative group" data-animate="fade-right" data-delay="100">
<div class="absolute inset-0 bg-gradient-to-br from-primary-500 to-primary-700 rounded-3xl transform transition-transform group-hover:scale-105"></div>
<div class="relative p-8 lg:p-12 bg-gradient-to-br from-primary-500 to-primary-700 rounded-3xl text-white overflow-hidden">
<div class="absolute top-0 right-0 w-64 h-64 bg-white/10 rounded-full -translate-y-1/2 translate-x-1/2 blur-2xl"></div>
<div class="relative">
<div class="w-16 h-16 bg-white/20 backdrop-blur-sm rounded-2xl flex items-center justify-center mb-6 shadow-lg">
<svg xmlns="http://www.w3.org/2000/svg" class="w-8 h-8 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M13 10V3L4 14h7v7l9-11h-7z" />
</svg>
</div>
<h3 class="text-2xl lg:text-3xl font-bold mb-4">Our Mission</h3>
<p class="text-primary-50 leading-relaxed text-lg">
To empower businesses through innovative technology solutions that drive growth, enhance efficiency, and create lasting value. We bridge the gap between complex technology and practical business outcomes.
</p>
</div>
</div>
</div>
<!-- Vision -->
<div class="relative group" data-animate="fade-left" data-delay="250">
<div class="absolute inset-0 bg-gradient-to-br from-secondary-800 to-secondary-900 rounded-3xl transform transition-transform group-hover:scale-105"></div>
<div class="relative p-8 lg:p-12 bg-gradient-to-br from-secondary-800 to-secondary-900 rounded-3xl text-white overflow-hidden">
<div class="absolute top-0 right-0 w-64 h-64 bg-primary-500/10 rounded-full -translate-y-1/2 translate-x-1/2 blur-2xl"></div>
<div class="relative">
<div class="w-16 h-16 bg-white/10 backdrop-blur-sm rounded-2xl flex items-center justify-center mb-6 shadow-lg">
<svg xmlns="http://www.w3.org/2000/svg" class="w-8 h-8 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
<path stroke-linecap="round" stroke-linejoin="round" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />
</svg>
</div>
<h3 class="text-2xl lg:text-3xl font-bold mb-4">Our Vision</h3>
<p class="text-secondary-200 leading-relaxed text-lg">
To be the most trusted technology partner for businesses worldwide, known for our integrity, innovation, and unwavering commitment to client success. We envision a future where every business can harness the full potential of technology.
</p>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- Core Values Section -->
<section class="py-16 lg:py-24 bg-white relative overflow-hidden">
<!-- Background decoration -->
<div class="absolute inset-0 overflow-hidden pointer-events-none" aria-hidden="true">
<div class="absolute top-0 right-0 w-96 h-96 bg-primary-500/5 rounded-full blur-3xl"></div>
<div class="absolute bottom-0 left-0 w-96 h-96 bg-accent-500/5 rounded-full blur-3xl"></div>
</div>
<div class="container-wrapper relative">
<div class="text-center max-w-2xl mx-auto mb-12 lg:mb-16" data-animate="fade-up">
<span class="text-primary-500 font-semibold text-sm uppercase tracking-wider">What Drives Us</span>
<h2 class="text-3xl sm:text-4xl font-bold text-secondary-900 mt-2 mb-4">Our Core Values</h2>
<p class="text-secondary-600">
These principles guide every decision we make and every solution we deliver.
</p>
</div>
<div class="grid sm:grid-cols-2 lg:grid-cols-4 gap-6 lg:gap-8">
{values.map((value, index) => (
<div class="group relative" data-animate="fade-up" data-delay={String(index * 100)}>
<!-- Gradient background on hover -->
<div class="absolute inset-0 bg-gradient-to-br from-primary-500 to-primary-700 rounded-2xl opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>
<!-- Card content -->
<div class="relative bg-white p-6 lg:p-8 rounded-2xl shadow-sm group-hover:shadow-xl transition-all duration-300 border-2 border-secondary-100 group-hover:border-primary-200 group-hover:translate-y-[-4px]">
<div class="w-14 h-14 bg-gradient-to-br from-primary-50 to-primary-100 text-primary-600 rounded-xl flex items-center justify-center mb-6 group-hover:bg-white group-hover:text-white transition-all duration-300 shadow-md">
{value.icon === 'lightbulb' && (
<svg xmlns="http://www.w3.org/2000/svg" class="w-7 h-7" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z" />
</svg>
)}
{value.icon === 'shield' && (
<svg xmlns="http://www.w3.org/2000/svg" class="w-7 h-7" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z" />
</svg>
)}
{value.icon === 'star' && (
<svg xmlns="http://www.w3.org/2000/svg" class="w-7 h-7" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M11.049 2.927c.3-.921 1.603-.921 1.902 0l1.519 4.674a1 1 0 00.95.69h4.915c.969 0 1.371 1.24.588 1.81l-3.976 2.888a1 1 0 00-.363 1.118l1.518 4.674c.3.922-.755 1.688-1.538 1.118l-3.976-2.888a1 1 0 00-1.176 0l-3.976 2.888c-.783.57-1.838-.197-1.538-1.118l1.518-4.674a1 1 0 00-.363-1.118l-3.976-2.888c-.784-.57-.38-1.81.588-1.81h4.914a1 1 0 00.951-.69l1.519-4.674z" />
</svg>
)}
{value.icon === 'users' && (
<svg xmlns="http://www.w3.org/2000/svg" class="w-7 h-7" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z" />
</svg>
)}
</div>
<h3 class="text-xl font-bold text-secondary-900 mb-3 group-hover:text-white transition-colors duration-300">{value.title}</h3>
<p class="text-secondary-600 leading-relaxed group-hover:text-primary-50 transition-colors duration-300">{value.description}</p>
</div>
</div>
))}
</div>
</div>
</section>
<!-- Team Section -->
<section class="py-16 lg:py-24 bg-secondary-50">
<div class="container-wrapper">
<div class="text-center max-w-2xl mx-auto mb-12 lg:mb-16" data-animate="fade-up">
<span class="text-primary-500 font-semibold text-sm uppercase tracking-wider">The Team</span>
<h2 class="text-3xl sm:text-4xl font-bold text-secondary-900 mt-2 mb-4">Meet Our Leadership</h2>
<p class="text-secondary-600">
Talented professionals who bring diverse expertise and shared passion for technology excellence.
</p>
</div>
<div class="grid sm:grid-cols-2 lg:grid-cols-3 gap-8 lg:gap-10">
{teamMembers.map((member, index) => (
<article class="group relative" data-animate="fade-up" data-delay={String((index % 3) * 100)}>
<!-- Card wrapper with gradient border effect -->
<div class="absolute inset-0 bg-gradient-to-br from-primary-400 to-accent-400 rounded-3xl opacity-0 group-hover:opacity-100 transition-opacity duration-300 blur-sm"></div>
<div class="relative bg-white rounded-3xl overflow-hidden shadow-md hover:shadow-2xl transition-all duration-300 transform group-hover:-translate-y-2">
<!-- Image container -->
<div class="relative aspect-[4/5] overflow-hidden bg-secondary-200">
<img
src={member.image}
alt={`${member.name} - ${member.role}`}
width="400"
height="500"
class="w-full h-full object-cover group-hover:scale-110 transition-transform duration-700"
loading={index === 0 ? 'eager' : 'lazy'}
fetchpriority={index === 0 ? 'high' : 'auto'}
decoding="async"
/>
<!-- Gradient overlay -->
<div class="absolute inset-0 bg-gradient-to-t from-secondary-900/90 via-secondary-900/30 to-transparent opacity-60 group-hover:opacity-80 transition-opacity duration-300"></div>
<!-- Social links overlay -->
<div class="absolute inset-x-0 bottom-0 p-6 transform translate-y-full group-hover:translate-y-0 transition-transform duration-300">
<div class="flex justify-center gap-3">
<a
href={member.linkedin}
class="w-11 h-11 bg-white/95 hover:bg-white rounded-xl flex items-center justify-center text-secondary-700 hover:text-primary-500 transition-all shadow-lg hover:scale-110"
aria-label={`${member.name}'s LinkedIn profile`}
>
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
<path d="M19 0h-14c-2.761 0-5 2.239-5 5v14c0 2.761 2.239 5 5 5h14c2.762 0 5-2.239 5-5v-14c0-2.761-2.238-5-5-5zm-11 19h-3v-11h3v11zm-1.5-12.268c-.966 0-1.75-.79-1.75-1.764s.784-1.764 1.75-1.764 1.75.79 1.75 1.764-.783 1.764-1.75 1.764zm13.5 12.268h-3v-5.604c0-3.368-4-3.113-4 0v5.604h-3v-11h3v1.765c1.396-2.586 7-2.777 7 2.476v6.759z"/>
</svg>
</a>
<a
href={member.twitter}
class="w-11 h-11 bg-white/95 hover:bg-white rounded-xl flex items-center justify-center text-secondary-700 hover:text-primary-500 transition-all shadow-lg hover:scale-110"
aria-label={`${member.name}'s Twitter profile`}
>
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
<path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"/>
</svg>
</a>
</div>
</div>
</div>
<!-- Content -->
<div class="p-6 lg:p-7">
<h3 class="text-xl font-bold text-secondary-900 mb-1 group-hover:text-primary-600 transition-colors">{member.name}</h3>
<p class="text-primary-500 font-semibold text-sm mb-3 uppercase tracking-wide">{member.role}</p>
<p class="text-secondary-600 leading-relaxed text-sm">{member.bio}</p>
</div>
</div>
</article>
))}
</div>
</div>
</section>
<!-- CTA Section -->
<section class="relative py-20 lg:py-28 overflow-hidden">
<!-- Gradient background -->
<div class="absolute inset-0 bg-gradient-to-br from-primary-600 via-primary-700 to-secondary-800"></div>
<!-- Decorative elements -->
<div class="absolute inset-0 overflow-hidden pointer-events-none" aria-hidden="true">
<div class="absolute -top-40 -right-40 w-96 h-96 bg-accent-500/20 rounded-full blur-3xl"></div>
<div class="absolute -bottom-40 -left-40 w-96 h-96 bg-primary-400/20 rounded-full blur-3xl"></div>
<div class="absolute inset-0 bg-[linear-gradient(rgba(255,255,255,0.05)_1px,transparent_1px),linear-gradient(90deg,rgba(255,255,255,0.05)_1px,transparent_1px)] bg-[size:64px_64px]"></div>
</div>
<div class="container-wrapper relative z-10">
<div class="max-w-4xl mx-auto text-center">
<div class="inline-block px-4 py-1.5 mb-6 text-sm font-medium text-primary-200 bg-white/10 rounded-full border border-white/20 backdrop-blur-sm">
Let's Build Together
</div>
<h2 class="text-3xl sm:text-4xl lg:text-5xl font-bold text-white mb-6">
Ready to Work With Us?
</h2>
<p class="text-primary-50 text-lg sm:text-xl max-w-2xl mx-auto mb-10">
Let's discuss how we can help transform your business with innovative technology solutions.
</p>
<div class="flex flex-col sm:flex-row gap-4 justify-center">
<a
href="/contact"
class="group inline-flex items-center justify-center px-8 py-4 bg-white text-primary-600 font-semibold rounded-xl hover:bg-primary-50 transition-all shadow-xl hover:shadow-2xl hover:scale-105 focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-primary-600"
>
Get in Touch
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 ml-2 group-hover:translate-x-1 transition-transform" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M17 8l4 4m0 0l-4 4m4-4H3" />
</svg>
</a>
<a
href="/services"
class="inline-flex items-center justify-center px-8 py-4 border-2 border-white/40 text-white font-semibold rounded-xl hover:bg-white/10 hover:border-white/60 transition-all backdrop-blur-sm focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-primary-600"
>
View Our Services
</a>
</div>
</div>
</div>
</section>
</BaseLayout>
+326
View File
@@ -0,0 +1,326 @@
import type { APIRoute } from 'astro';
import { logger, logApiRequest } from '../../utils/logger';
import { captureException } from '../../utils/sentry';
// ============================================================
// In-memory rate limiter (sliding window, per IP)
// ============================================================
interface RateLimitEntry {
timestamps: number[];
}
const rateLimitStore = new Map<string, RateLimitEntry>();
const RATE_LIMIT_WINDOW_MS = 60 * 60 * 1000; // 1 hour
const RATE_LIMIT_MAX_REQUESTS = 5; // max 5 contact submissions per hour per IP
function checkRateLimit(ip: string): { allowed: boolean; remaining: number; resetAt: number } {
const now = Date.now();
const windowStart = now - RATE_LIMIT_WINDOW_MS;
const entry = rateLimitStore.get(ip) ?? { timestamps: [] };
// Remove timestamps outside the window
entry.timestamps = entry.timestamps.filter((ts) => ts > windowStart);
const remaining = RATE_LIMIT_MAX_REQUESTS - entry.timestamps.length;
const resetAt = entry.timestamps.length > 0
? entry.timestamps[0] + RATE_LIMIT_WINDOW_MS
: now + RATE_LIMIT_WINDOW_MS;
if (entry.timestamps.length >= RATE_LIMIT_MAX_REQUESTS) {
rateLimitStore.set(ip, entry);
return { allowed: false, remaining: 0, resetAt };
}
entry.timestamps.push(now);
rateLimitStore.set(ip, entry);
return { allowed: true, remaining: remaining - 1, resetAt };
}
// ============================================================
// Input validation
// ============================================================
const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
const PHONE_REGEX = /^[\+]?[(]?[0-9]{1,3}[)]?[-\s\.]?[(]?[0-9]{1,4}[)]?[-\s\.]?[0-9]{1,4}[-\s\.]?[0-9]{1,9}$/;
const VALID_SUBJECTS = [
'web-development',
'mobile-development',
'cloud-services',
'ai-ml',
'consulting',
'support',
'other',
];
interface ContactFormData {
name: string;
email: string;
phone?: string;
subject: string;
message: string;
website?: string; // honeypot
}
function validateContactForm(data: ContactFormData): string | null {
if (!data.name || data.name.trim().length < 2) {
return 'Name must be at least 2 characters.';
}
if (data.name.trim().length > 100) {
return 'Name must be under 100 characters.';
}
if (!data.email || !EMAIL_REGEX.test(data.email.trim())) {
return 'A valid email address is required.';
}
if (data.email.trim().length > 254) {
return 'Email address is too long.';
}
if (data.phone && data.phone.trim() !== '' && !PHONE_REGEX.test(data.phone.trim())) {
return 'Phone number format is invalid.';
}
if (!data.subject || !VALID_SUBJECTS.includes(data.subject)) {
return 'Please select a valid subject.';
}
if (!data.message || data.message.trim().length < 10) {
return 'Message must be at least 10 characters.';
}
if (data.message.trim().length > 5000) {
return 'Message must be under 5000 characters.';
}
return null;
}
// ============================================================
// Email sending via SMTP (nodemailer) or no-op in development
// ============================================================
async function sendContactEmail(data: ContactFormData): Promise<void> {
const smtpHost = import.meta.env.SMTP_HOST;
const smtpUser = import.meta.env.SMTP_USER;
const smtpPass = import.meta.env.SMTP_PASS;
const smtpPort = parseInt(import.meta.env.SMTP_PORT ?? '587', 10);
const recipientEmail = import.meta.env.CONTACT_EMAIL ?? import.meta.env.SMTP_USER;
if (!smtpHost || !smtpUser || !smtpPass || !recipientEmail) {
// SMTP not configured - log and continue (graceful degradation)
logger.info('api.contact', 'SMTP not configured — form submission logged only', {
email: data.email,
subject: data.subject,
name: data.name,
});
return;
}
// Dynamic import to avoid bundling issues when nodemailer isn't installed
try {
const nodemailer = await import('nodemailer');
const transporter = nodemailer.default.createTransport({
host: smtpHost,
port: smtpPort,
secure: smtpPort === 465,
auth: { user: smtpUser, pass: smtpPass },
});
const subjectLabels: Record<string, string> = {
'web-development': 'Web Development',
'mobile-development': 'Mobile Development',
'cloud-services': 'Cloud Services',
'ai-ml': 'AI & Machine Learning',
'consulting': 'IT Consulting',
'support': 'Technical Support',
'other': 'Other',
};
await transporter.sendMail({
from: `"WorkRoot Contact Form" <${smtpUser}>`,
to: recipientEmail,
replyTo: data.email,
subject: `[Contact Form] ${subjectLabels[data.subject] ?? data.subject} - ${data.name}`,
text: [
`New contact form submission`,
``,
`Name: ${data.name}`,
`Email: ${data.email}`,
`Phone: ${data.phone || 'Not provided'}`,
`Subject: ${subjectLabels[data.subject] ?? data.subject}`,
``,
`Message:`,
data.message,
``,
`---`,
`Submitted at: ${new Date().toISOString()}`,
].join('\n'),
html: `
<h2>New Contact Form Submission</h2>
<table style="border-collapse:collapse;width:100%;max-width:600px">
<tr><td style="padding:8px;font-weight:bold;border-bottom:1px solid #eee">Name</td><td style="padding:8px;border-bottom:1px solid #eee">${escapeHtml(data.name)}</td></tr>
<tr><td style="padding:8px;font-weight:bold;border-bottom:1px solid #eee">Email</td><td style="padding:8px;border-bottom:1px solid #eee"><a href="mailto:${escapeHtml(data.email)}">${escapeHtml(data.email)}</a></td></tr>
<tr><td style="padding:8px;font-weight:bold;border-bottom:1px solid #eee">Phone</td><td style="padding:8px;border-bottom:1px solid #eee">${escapeHtml(data.phone || 'Not provided')}</td></tr>
<tr><td style="padding:8px;font-weight:bold;border-bottom:1px solid #eee">Subject</td><td style="padding:8px;border-bottom:1px solid #eee">${escapeHtml(subjectLabels[data.subject] ?? data.subject)}</td></tr>
<tr><td style="padding:8px;font-weight:bold;vertical-align:top">Message</td><td style="padding:8px;white-space:pre-wrap">${escapeHtml(data.message)}</td></tr>
</table>
<p style="color:#888;font-size:12px;margin-top:16px">Submitted at: ${new Date().toISOString()}</p>
`,
});
} catch (err) {
// If nodemailer isn't installed, treat as graceful degradation (log only)
if (err instanceof Error && err.message.includes('Cannot find module')) {
logger.warn('api.contact', 'nodemailer not available — form submission logged only', {
email: data.email,
subject: data.subject,
});
return;
}
await captureException(err, {
scope: 'api.contact',
extra: { email: data.email, subject: data.subject },
});
throw new Error('Email delivery failed');
}
}
function escapeHtml(str: string): string {
return str
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;');
}
// ============================================================
// CORS headers helper
// ============================================================
function corsHeaders(): HeadersInit {
const origin = import.meta.env.PROD ? 'https://workroot.in' : '*';
return {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': origin,
'Access-Control-Allow-Methods': 'POST, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type',
};
}
// ============================================================
// OPTIONS preflight handler
// ============================================================
export const OPTIONS: APIRoute = async () => {
return new Response(null, { status: 204, headers: corsHeaders() });
};
// ============================================================
// POST handler
// ============================================================
export const POST: APIRoute = async ({ request, clientAddress }) => {
const ip = clientAddress ?? 'unknown';
const startTime = Date.now();
// Rate limiting check
const rateLimit = checkRateLimit(ip);
const rateLimitHeaders = {
...corsHeaders(),
'X-RateLimit-Limit': String(RATE_LIMIT_MAX_REQUESTS),
'X-RateLimit-Remaining': String(rateLimit.remaining),
'X-RateLimit-Reset': String(Math.ceil(rateLimit.resetAt / 1000)),
};
if (!rateLimit.allowed) {
logApiRequest({ scope: 'api.contact', method: 'POST', path: '/api/contact', status: 429, ip });
return new Response(
JSON.stringify({
success: false,
error: 'Too many requests. Please try again later.',
}),
{ status: 429, headers: rateLimitHeaders }
);
}
// Reject oversized payloads (max 16KB)
const contentLength = parseInt(request.headers.get('content-length') ?? '0', 10);
if (contentLength > 16384) {
return new Response(
JSON.stringify({ success: false, error: 'Request body too large.' }),
{ status: 413, headers: rateLimitHeaders }
);
}
// Parse request body
let body: Record<string, unknown>;
try {
const contentType = request.headers.get('content-type') ?? '';
if (contentType.includes('application/json')) {
body = await request.json();
} else {
const formData = await request.formData();
body = Object.fromEntries(formData.entries());
}
} catch {
return new Response(
JSON.stringify({ success: false, error: 'Invalid request body.' }),
{ status: 400, headers: rateLimitHeaders }
);
}
// Honeypot check (spam bot detection)
// Bots typically fill all fields; the honeypot field should always be empty
if (body.website && String(body.website).trim() !== '') {
// Silently succeed to not reveal spam detection
return new Response(
JSON.stringify({ success: true, message: 'Message received. Thank you!' }),
{ status: 200, headers: rateLimitHeaders }
);
}
// Build and validate form data
const formData: ContactFormData = {
name: String(body.name ?? '').trim(),
email: String(body.email ?? '').trim(),
phone: body.phone ? String(body.phone).trim() : undefined,
subject: String(body.subject ?? '').trim(),
message: String(body.message ?? '').trim(),
};
const validationError = validateContactForm(formData);
if (validationError) {
return new Response(
JSON.stringify({ success: false, error: validationError }),
{ status: 422, headers: rateLimitHeaders }
);
}
// Send email
try {
await sendContactEmail(formData);
} catch {
logApiRequest({
scope: 'api.contact',
method: 'POST',
path: '/api/contact',
status: 500,
ip,
durationMs: Date.now() - startTime,
});
return new Response(
JSON.stringify({
success: false,
error: 'Failed to send message. Please try again or email us directly.',
}),
{ status: 500, headers: rateLimitHeaders }
);
}
logApiRequest({
scope: 'api.contact',
method: 'POST',
path: '/api/contact',
status: 200,
ip,
durationMs: Date.now() - startTime,
});
return new Response(
JSON.stringify({
success: true,
message: "Message sent successfully! We'll get back to you within 24 hours.",
}),
{ status: 200, headers: rateLimitHeaders }
);
};
+37
View File
@@ -0,0 +1,37 @@
import type { APIRoute } from 'astro';
const startTime = Date.now();
export const GET: APIRoute = async () => {
const uptimeSeconds = Math.floor((Date.now() - startTime) / 1000);
const memUsage = process.memoryUsage();
const payload = {
status: 'ok',
timestamp: new Date().toISOString(),
uptime: uptimeSeconds,
version: import.meta.env.npm_package_version ?? '1.0.0',
mode: 'ssr',
adapter: 'node-standalone',
domain: 'workroot.in',
memory: {
heapUsedMB: Math.round(memUsage.heapUsed / 1024 / 1024),
heapTotalMB: Math.round(memUsage.heapTotal / 1024 / 1024),
rssMB: Math.round(memUsage.rss / 1024 / 1024),
},
checks: {
server: 'ok',
},
};
return new Response(JSON.stringify(payload), {
status: 200,
headers: {
'Content-Type': 'application/json',
'Cache-Control': 'no-cache, no-store, must-revalidate',
'Access-Control-Allow-Origin': 'https://workroot.in',
'Access-Control-Allow-Methods': 'GET',
'Access-Control-Allow-Headers': 'Content-Type',
},
});
};
+96
View File
@@ -0,0 +1,96 @@
import type { APIRoute } from 'astro';
// Module-level counters (persist across requests within same process)
let requestCount = 0;
let errorCount = 0;
const processStartTime = Date.now();
// Simple response time tracking (last 100 samples)
const responseTimes: number[] = [];
const MAX_SAMPLES = 100;
export function recordRequest(durationMs: number, isError = false) {
requestCount++;
if (isError) errorCount++;
responseTimes.push(durationMs);
if (responseTimes.length > MAX_SAMPLES) responseTimes.shift();
}
function percentile(sorted: number[], p: number): number {
if (sorted.length === 0) return 0;
const idx = Math.ceil((p / 100) * sorted.length) - 1;
return sorted[Math.max(0, idx)];
}
export const GET: APIRoute = async ({ request }) => {
// Restrict metrics to internal/authorized access only
const authHeader = request.headers.get('Authorization');
const metricsToken = import.meta.env.METRICS_TOKEN;
if (metricsToken && authHeader !== `Bearer ${metricsToken}`) {
return new Response(JSON.stringify({ error: 'Unauthorized' }), {
status: 401,
headers: { 'Content-Type': 'application/json' },
});
}
const memUsage = process.memoryUsage();
const uptimeSeconds = Math.floor((Date.now() - processStartTime) / 1000);
const sorted = [...responseTimes].sort((a, b) => a - b);
const avgResponseTime = sorted.length > 0
? Math.round(sorted.reduce((a, b) => a + b, 0) / sorted.length)
: 0;
const metrics = {
timestamp: new Date().toISOString(),
uptime: {
seconds: uptimeSeconds,
human: formatUptime(uptimeSeconds),
},
requests: {
total: requestCount,
errors: errorCount,
errorRate: requestCount > 0 ? ((errorCount / requestCount) * 100).toFixed(2) + '%' : '0%',
},
responseTime: {
avgMs: avgResponseTime,
p50Ms: percentile(sorted, 50),
p95Ms: percentile(sorted, 95),
p99Ms: percentile(sorted, 99),
samples: sorted.length,
},
memory: {
heapUsedMB: Math.round(memUsage.heapUsed / 1024 / 1024),
heapTotalMB: Math.round(memUsage.heapTotal / 1024 / 1024),
externalMB: Math.round(memUsage.external / 1024 / 1024),
rssMB: Math.round(memUsage.rss / 1024 / 1024),
},
process: {
pid: process.pid,
nodeVersion: process.version,
platform: process.platform,
},
};
return new Response(JSON.stringify(metrics, null, 2), {
status: 200,
headers: {
'Content-Type': 'application/json',
'Cache-Control': 'no-cache, no-store, must-revalidate',
},
});
};
function formatUptime(seconds: number): string {
const d = Math.floor(seconds / 86400);
const h = Math.floor((seconds % 86400) / 3600);
const m = Math.floor((seconds % 3600) / 60);
const s = seconds % 60;
const parts = [];
if (d > 0) parts.push(`${d}d`);
if (h > 0) parts.push(`${h}h`);
if (m > 0) parts.push(`${m}m`);
parts.push(`${s}s`);
return parts.join(' ');
}
+273
View File
@@ -0,0 +1,273 @@
import type { APIRoute } from 'astro';
import { logger, logApiRequest } from '../../utils/logger';
import { captureException } from '../../utils/sentry';
// ============================================================
// In-memory rate limiter (sliding window, per IP)
// ============================================================
interface RateLimitEntry {
timestamps: number[];
}
const rateLimitStore = new Map<string, RateLimitEntry>();
const RATE_LIMIT_WINDOW_MS = 60 * 60 * 1000; // 1 hour
const RATE_LIMIT_MAX_REQUESTS = 3; // max 3 newsletter signups per hour per IP
function checkRateLimit(ip: string): { allowed: boolean; remaining: number; resetAt: number } {
const now = Date.now();
const windowStart = now - RATE_LIMIT_WINDOW_MS;
const entry = rateLimitStore.get(ip) ?? { timestamps: [] };
entry.timestamps = entry.timestamps.filter((ts) => ts > windowStart);
const remaining = RATE_LIMIT_MAX_REQUESTS - entry.timestamps.length;
const resetAt = entry.timestamps.length > 0
? entry.timestamps[0] + RATE_LIMIT_WINDOW_MS
: now + RATE_LIMIT_WINDOW_MS;
if (entry.timestamps.length >= RATE_LIMIT_MAX_REQUESTS) {
rateLimitStore.set(ip, entry);
return { allowed: false, remaining: 0, resetAt };
}
entry.timestamps.push(now);
rateLimitStore.set(ip, entry);
return { allowed: true, remaining: remaining - 1, resetAt };
}
// ============================================================
// Input validation
// ============================================================
const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
function validateEmail(email: string): string | null {
if (!email || email.trim() === '') {
return 'Email address is required.';
}
if (!EMAIL_REGEX.test(email.trim())) {
return 'Please enter a valid email address.';
}
if (email.trim().length > 254) {
return 'Email address is too long.';
}
return null;
}
// ============================================================
// Newsletter subscription handlers
// Supports: Mailchimp, ConvertKit, or simple SMTP notification
// ============================================================
async function subscribeToNewsletter(email: string): Promise<void> {
const mailchimpApiKey = import.meta.env.MAILCHIMP_API_KEY;
const mailchimpListId = import.meta.env.MAILCHIMP_LIST_ID;
const mailchimpDataCenter = import.meta.env.MAILCHIMP_DC; // e.g. "us1"
const convertkitApiKey = import.meta.env.CONVERTKIT_API_KEY;
const convertkitFormId = import.meta.env.CONVERTKIT_FORM_ID;
// Option 1: Mailchimp integration
if (mailchimpApiKey && mailchimpListId && mailchimpDataCenter) {
const url = `https://${mailchimpDataCenter}.api.mailchimp.com/3.0/lists/${mailchimpListId}/members`;
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Basic ${Buffer.from(`anystring:${mailchimpApiKey}`).toString('base64')}`,
},
body: JSON.stringify({
email_address: email,
status: 'pending', // Double opt-in
tags: ['website-signup'],
}),
});
if (!response.ok) {
const error = await response.json() as { title?: string };
// Handle already-subscribed gracefully
if (error.title === 'Member Exists') {
return;
}
throw new Error(`Mailchimp error: ${error.title}`);
}
return;
}
// Option 2: ConvertKit integration
if (convertkitApiKey && convertkitFormId) {
const url = `https://api.convertkit.com/v3/forms/${convertkitFormId}/subscribe`;
const response = await fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
api_key: convertkitApiKey,
email,
}),
});
if (!response.ok) {
const error = await response.json() as { message?: string };
throw new Error(`ConvertKit error: ${error.message}`);
}
return;
}
// Option 3: SMTP notification fallback
const smtpHost = import.meta.env.SMTP_HOST;
const smtpUser = import.meta.env.SMTP_USER;
const smtpPass = import.meta.env.SMTP_PASS;
const smtpPort = parseInt(import.meta.env.SMTP_PORT ?? '587', 10);
const recipientEmail = import.meta.env.CONTACT_EMAIL ?? import.meta.env.SMTP_USER;
if (smtpHost && smtpUser && smtpPass && recipientEmail) {
try {
const nodemailer = await import('nodemailer');
const transporter = nodemailer.default.createTransport({
host: smtpHost,
port: smtpPort,
secure: smtpPort === 465,
auth: { user: smtpUser, pass: smtpPass },
});
await transporter.sendMail({
from: `"WorkRoot Newsletter" <${smtpUser}>`,
to: recipientEmail,
subject: `[Newsletter] New subscriber: ${email}`,
text: `New newsletter subscription\n\nEmail: ${email}\nSubscribed at: ${new Date().toISOString()}`,
});
return;
} catch (err) {
// If nodemailer isn't installed, fall through to console log path
if (err instanceof Error && err.message.includes('Cannot find module')) {
logger.warn('api.newsletter', 'nodemailer not available — subscriber logged only', { email });
return;
}
await captureException(err, { scope: 'api.newsletter', extra: { provider: 'smtp' } });
throw new Error('Failed to process subscription');
}
}
// No integration configured — log and continue (dev/staging)
logger.info('api.newsletter', 'No provider configured — subscriber logged only', { email });
}
// ============================================================
// CORS headers helper
// ============================================================
function corsHeaders(): HeadersInit {
const origin = import.meta.env.PROD ? 'https://workroot.in' : '*';
return {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': origin,
'Access-Control-Allow-Methods': 'POST, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type',
};
}
// ============================================================
// OPTIONS preflight handler
// ============================================================
export const OPTIONS: APIRoute = async () => {
return new Response(null, { status: 204, headers: corsHeaders() });
};
// ============================================================
// POST handler
// ============================================================
export const POST: APIRoute = async ({ request, clientAddress }) => {
const ip = clientAddress ?? 'unknown';
const startTime = Date.now();
// Rate limiting
const rateLimit = checkRateLimit(ip);
const rateLimitHeaders = {
...corsHeaders(),
'X-RateLimit-Limit': String(RATE_LIMIT_MAX_REQUESTS),
'X-RateLimit-Remaining': String(rateLimit.remaining),
'X-RateLimit-Reset': String(Math.ceil(rateLimit.resetAt / 1000)),
};
if (!rateLimit.allowed) {
logApiRequest({ scope: 'api.newsletter', method: 'POST', path: '/api/newsletter', status: 429, ip });
return new Response(
JSON.stringify({
success: false,
error: 'Too many requests. Please try again later.',
}),
{ status: 429, headers: rateLimitHeaders }
);
}
// Reject oversized payloads (max 4KB for email-only endpoint)
const contentLength = parseInt(request.headers.get('content-length') ?? '0', 10);
if (contentLength > 4096) {
return new Response(
JSON.stringify({ success: false, error: 'Request body too large.' }),
{ status: 413, headers: rateLimitHeaders }
);
}
// Parse request body
let email: string;
try {
const contentType = request.headers.get('content-type') ?? '';
if (contentType.includes('application/json')) {
const body = await request.json() as { email?: unknown };
email = String(body.email ?? '').trim();
} else {
const formData = await request.formData();
email = String(formData.get('email') ?? '').trim();
}
} catch {
return new Response(
JSON.stringify({ success: false, error: 'Invalid request body.' }),
{ status: 400, headers: rateLimitHeaders }
);
}
// Validate email
const validationError = validateEmail(email);
if (validationError) {
return new Response(
JSON.stringify({ success: false, error: validationError }),
{ status: 422, headers: rateLimitHeaders }
);
}
// Subscribe
try {
await subscribeToNewsletter(email.toLowerCase());
} catch {
logApiRequest({
scope: 'api.newsletter',
method: 'POST',
path: '/api/newsletter',
status: 500,
ip,
durationMs: Date.now() - startTime,
});
return new Response(
JSON.stringify({
success: false,
error: 'Unable to process your subscription. Please try again.',
}),
{ status: 500, headers: rateLimitHeaders }
);
}
logApiRequest({
scope: 'api.newsletter',
method: 'POST',
path: '/api/newsletter',
status: 200,
ip,
durationMs: Date.now() - startTime,
});
return new Response(
JSON.stringify({
success: true,
message: 'Thanks for subscribing! Check your inbox to confirm.',
}),
{ status: 200, headers: rateLimitHeaders }
);
};
+341
View File
@@ -0,0 +1,341 @@
---
import { getCollection, type CollectionEntry } from 'astro:content';
import BaseLayout from '../../layouts/BaseLayout.astro';
import SEO from '../../components/SEO.astro';
export async function getStaticPaths() {
const posts = await getCollection('blog', ({ data }) => !data.draft);
return posts.map((post) => ({
params: { slug: post.slug },
props: { post },
}));
}
type Props = { post: CollectionEntry<'blog'> };
const { post } = Astro.props;
const { Content } = await post.render();
function getReadingTime(content: string): number {
const wordsPerMinute = 200;
const words = content.split(/\s+/).length;
return Math.ceil(words / wordsPerMinute);
}
function formatDate(date: Date): string {
return date.toLocaleDateString('en-US', {
year: 'numeric',
month: 'long',
day: 'numeric',
});
}
const readingTime = getReadingTime(post.body);
const shareUrl = encodeURIComponent(Astro.url.href);
const shareTitle = encodeURIComponent(post.data.title);
const shareDescription = encodeURIComponent(post.data.description);
---
<BaseLayout
title={post.data.title}
description={post.data.description}
ogImage={post.data.heroImage}
>
<SEO
slot="head"
type="BlogPosting"
title={post.data.title}
description={post.data.description}
breadcrumbs={[
{ name: 'Home', url: '/' },
{ name: 'Blog', url: '/blog' },
{ name: post.data.title, url: `/blog/${post.slug}` }
]}
article={{
author: post.data.author.name,
datePublished: post.data.pubDate.toISOString(),
dateModified: post.data.updatedDate?.toISOString(),
category: post.data.category,
tags: post.data.tags,
image: post.data.heroImage,
wordCount: post.body.split(/\s+/).length
}}
/>
<article class="bg-white">
<!-- Hero Section -->
<header class="relative bg-gradient-to-br from-secondary-900 via-secondary-800 to-secondary-900 py-16 md:py-24 overflow-hidden">
<div class="absolute inset-0 opacity-20">
<div class="absolute top-10 left-10 w-64 h-64 bg-primary-500 rounded-full blur-[100px]"></div>
<div class="absolute bottom-10 right-10 w-80 h-80 bg-accent-500 rounded-full blur-[120px]"></div>
</div>
<div class="relative max-w-4xl mx-auto px-4 sm:px-6 lg:px-8">
<!-- Breadcrumb -->
<nav class="mb-6" aria-label="Breadcrumb">
<ol class="flex items-center gap-2 text-sm text-secondary-400">
<li><a href="/" class="hover:text-white transition-colors">Home</a></li>
<li><span class="mx-2">/</span></li>
<li><a href="/blog" class="hover:text-white transition-colors">Blog</a></li>
<li><span class="mx-2">/</span></li>
<li class="text-secondary-300 truncate max-w-[200px]">{post.data.title}</li>
</ol>
</nav>
<!-- Category -->
<span class="inline-block px-4 py-1.5 bg-primary-500/20 text-primary-300 text-sm font-semibold rounded-full mb-4">
{post.data.category}
</span>
<!-- Title -->
<h1 class="text-3xl md:text-4xl lg:text-5xl font-bold text-white mb-6 leading-tight">
{post.data.title}
</h1>
<!-- Description -->
<p class="text-xl text-secondary-300 mb-8 max-w-3xl">
{post.data.description}
</p>
<!-- Meta -->
<div class="flex flex-wrap items-center gap-6 text-secondary-400">
<!-- Author -->
<div class="flex items-center gap-3">
<div class="w-10 h-10 rounded-full bg-gradient-to-br from-primary-400 to-primary-600 flex items-center justify-center text-white font-bold">
{post.data.author.name.charAt(0)}
</div>
<div>
<p class="text-white font-medium">{post.data.author.name}</p>
<p class="text-sm">Author</p>
</div>
</div>
<!-- Divider -->
<div class="hidden sm:block w-px h-10 bg-secondary-600"></div>
<!-- Date -->
<div class="flex items-center gap-2">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>
<time datetime={post.data.pubDate.toISOString()}>
{formatDate(post.data.pubDate)}
</time>
</div>
<!-- Reading Time -->
<div class="flex items-center gap-2">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
<span>{readingTime} min read</span>
</div>
</div>
</div>
</header>
<!-- Hero Image -->
{post.data.heroImage && (
<div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8 -mt-8 relative z-10">
<img
src={post.data.heroImage}
alt={post.data.title}
width="1200"
height="675"
class="w-full aspect-video object-cover rounded-2xl shadow-2xl bg-secondary-200"
loading="eager"
fetchpriority="high"
decoding="async"
/>
</div>
)}
<!-- Content -->
<div class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-12 md:py-16">
<div class="flex gap-8">
<!-- Social Share Sidebar (Desktop) -->
<aside class="hidden lg:block w-16 flex-shrink-0">
<div class="sticky top-24 flex flex-col gap-3">
<span class="text-xs text-secondary-400 font-medium mb-1">Share</span>
<!-- Twitter/X -->
<a
href={`https://twitter.com/intent/tweet?url=${shareUrl}&text=${shareTitle}`}
target="_blank"
rel="noopener noreferrer"
class="w-10 h-10 rounded-full bg-secondary-100 hover:bg-[#1DA1F2] text-secondary-600 hover:text-white flex items-center justify-center transition-colors"
aria-label="Share on Twitter"
>
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
<path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z" />
</svg>
</a>
<!-- LinkedIn -->
<a
href={`https://www.linkedin.com/sharing/share-offsite/?url=${shareUrl}`}
target="_blank"
rel="noopener noreferrer"
class="w-10 h-10 rounded-full bg-secondary-100 hover:bg-[#0A66C2] text-secondary-600 hover:text-white flex items-center justify-center transition-colors"
aria-label="Share on LinkedIn"
>
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
<path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z" />
</svg>
</a>
<!-- Facebook -->
<a
href={`https://www.facebook.com/sharer/sharer.php?u=${shareUrl}`}
target="_blank"
rel="noopener noreferrer"
class="w-10 h-10 rounded-full bg-secondary-100 hover:bg-[#1877F2] text-secondary-600 hover:text-white flex items-center justify-center transition-colors"
aria-label="Share on Facebook"
>
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
<path d="M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z" />
</svg>
</a>
<!-- Copy Link -->
<button
type="button"
id="copy-link-btn"
class="w-10 h-10 rounded-full bg-secondary-100 hover:bg-primary-500 text-secondary-600 hover:text-white flex items-center justify-center transition-colors"
aria-label="Copy link"
>
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" />
</svg>
</button>
</div>
</aside>
<!-- Main Content -->
<div class="flex-1 min-w-0">
<!-- Tags -->
<div class="flex flex-wrap gap-2 mb-8 pb-8 border-b border-secondary-200">
{post.data.tags.map((tag) => (
<span class="px-3 py-1 bg-secondary-100 text-secondary-600 text-sm rounded-full hover:bg-secondary-200 transition-colors">
#{tag}
</span>
))}
</div>
<!-- Article Content -->
<div class="prose prose-lg max-w-none prose-headings:text-secondary-900 prose-headings:font-bold prose-p:text-secondary-700 prose-a:text-primary-600 prose-a:no-underline hover:prose-a:underline prose-strong:text-secondary-900 prose-code:text-primary-700 prose-code:bg-primary-50 prose-code:px-1.5 prose-code:py-0.5 prose-code:rounded prose-code:font-mono prose-code:before:content-none prose-code:after:content-none prose-pre:bg-secondary-900 prose-pre:text-secondary-100 prose-pre:rounded-xl prose-pre:shadow-lg prose-img:rounded-xl prose-img:shadow-md prose-blockquote:border-primary-500 prose-blockquote:bg-primary-50 prose-blockquote:rounded-r-lg prose-blockquote:py-1 prose-blockquote:not-italic prose-li:marker:text-primary-500">
<Content />
</div>
<!-- Mobile Social Share -->
<div class="lg:hidden mt-12 pt-8 border-t border-secondary-200">
<p class="text-sm text-secondary-500 font-medium mb-4">Share this article</p>
<div class="flex gap-3">
<a
href={`https://twitter.com/intent/tweet?url=${shareUrl}&text=${shareTitle}`}
target="_blank"
rel="noopener noreferrer"
class="flex-1 py-3 rounded-lg bg-secondary-100 hover:bg-[#1DA1F2] text-secondary-600 hover:text-white flex items-center justify-center gap-2 transition-colors"
>
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
<path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z" />
</svg>
<span class="text-sm font-medium">Twitter</span>
</a>
<a
href={`https://www.linkedin.com/sharing/share-offsite/?url=${shareUrl}`}
target="_blank"
rel="noopener noreferrer"
class="flex-1 py-3 rounded-lg bg-secondary-100 hover:bg-[#0A66C2] text-secondary-600 hover:text-white flex items-center justify-center gap-2 transition-colors"
>
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
<path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z" />
</svg>
<span class="text-sm font-medium">LinkedIn</span>
</a>
<button
type="button"
id="copy-link-btn-mobile"
class="flex-1 py-3 rounded-lg bg-secondary-100 hover:bg-primary-500 text-secondary-600 hover:text-white flex items-center justify-center gap-2 transition-colors"
>
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" />
</svg>
<span class="text-sm font-medium">Copy</span>
</button>
</div>
</div>
<!-- Author Bio -->
<div class="mt-12 p-6 bg-secondary-50 rounded-2xl">
<div class="flex items-start gap-4">
<div class="w-16 h-16 rounded-full bg-gradient-to-br from-primary-400 to-primary-600 flex items-center justify-center text-white text-2xl font-bold flex-shrink-0">
{post.data.author.name.charAt(0)}
</div>
<div>
<p class="text-sm text-secondary-500 mb-1">Written by</p>
<h3 class="text-xl font-bold text-secondary-900 mb-2">{post.data.author.name}</h3>
<p class="text-secondary-600">
A passionate technologist sharing insights on modern software development, cloud architecture, and digital innovation.
</p>
</div>
</div>
</div>
<!-- Back to Blog -->
<div class="mt-8">
<a
href="/blog"
class="inline-flex items-center gap-2 text-primary-600 hover:text-primary-700 font-medium transition-colors"
>
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18" />
</svg>
Back to all articles
</a>
</div>
</div>
</div>
</div>
</article>
</BaseLayout>
<style is:global>
/* Code blocks with JetBrains Mono */
.prose pre {
font-family: 'JetBrains Mono', monospace;
font-size: 0.875rem;
line-height: 1.7;
padding: 1.5rem;
}
.prose pre code {
background: transparent;
padding: 0;
font-family: inherit;
color: inherit;
}
/* Inline code */
.prose :not(pre) > code {
font-family: 'JetBrains Mono', monospace;
font-size: 0.875em;
}
/* Syntax highlighting colors */
.prose pre .comment { color: #6a737d; }
.prose pre .keyword { color: #ff7b72; }
.prose pre .string { color: #a5d6ff; }
.prose pre .function { color: #d2a8ff; }
.prose pre .number { color: #79c0ff; }
</style>
<script>
function copyToClipboard() {
navigator.clipboard.writeText(window.location.href).then(() => {
alert('Link copied to clipboard!');
});
}
document.getElementById('copy-link-btn')?.addEventListener('click', copyToClipboard);
document.getElementById('copy-link-btn-mobile')?.addEventListener('click', copyToClipboard);
</script>
+212
View File
@@ -0,0 +1,212 @@
---
import { getCollection } from 'astro:content';
import BaseLayout from '../../layouts/BaseLayout.astro';
import SEO from '../../components/SEO.astro';
const allPosts = await getCollection('blog', ({ data }) => !data.draft);
const sortedPosts = allPosts.sort((a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf());
const categories = ['All', 'Web Development', 'Mobile Apps', 'AI/ML', 'Cloud', 'DevOps', 'Security'] as const;
function getReadingTime(content: string): number {
const wordsPerMinute = 200;
const words = content.split(/\s+/).length;
return Math.ceil(words / wordsPerMinute);
}
function formatDate(date: Date): string {
return date.toLocaleDateString('en-US', {
year: 'numeric',
month: 'long',
day: 'numeric',
});
}
---
<BaseLayout
title="Blog"
description="Insights and articles on web development, AI, cloud computing, and digital transformation from the WorkRoot team."
>
<SEO
slot="head"
type="WebPage"
breadcrumbs={[
{ name: 'Home', url: '/' },
{ name: 'Blog', url: '/blog' }
]}
/>
<!-- Hero Section -->
<section class="relative bg-gradient-to-br from-secondary-900 via-secondary-800 to-secondary-900 py-20 overflow-hidden">
<div class="absolute inset-0 opacity-30">
<div class="absolute top-20 left-10 w-72 h-72 bg-primary-500 rounded-full blur-[120px]"></div>
<div class="absolute bottom-10 right-20 w-96 h-96 bg-accent-500 rounded-full blur-[150px]"></div>
</div>
<div class="relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
<h1 class="text-4xl md:text-5xl lg:text-6xl font-bold text-white mb-6">
Our <span class="text-transparent bg-clip-text bg-gradient-to-r from-primary-400 to-accent-400">Blog</span>
</h1>
<p class="text-xl text-secondary-300 max-w-3xl mx-auto">
Insights, tutorials, and industry trends from our team of experts. Stay ahead with the latest in technology.
</p>
</div>
</section>
<!-- Category Filter -->
<section class="bg-secondary-50 border-b border-secondary-200">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4">
<div class="flex flex-wrap gap-2 justify-center" role="tablist" aria-label="Filter posts by category">
{categories.map((category, index) => (
<button
type="button"
role="tab"
aria-selected={index === 0 ? 'true' : 'false'}
data-category={category}
class:list={[
'filter-btn px-4 py-2 rounded-full text-sm font-medium transition-all duration-200',
index === 0
? 'bg-primary-500 text-white'
: 'bg-white text-secondary-600 hover:bg-secondary-100 border border-secondary-200',
]}
>
{category}
</button>
))}
</div>
</div>
</section>
<!-- Blog Posts Grid -->
<section class="py-16 bg-white">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8" id="posts-grid">
{sortedPosts.map((post) => {
const readingTime = getReadingTime(post.body);
return (
<article
class="post-card group bg-white rounded-2xl shadow-lg overflow-hidden border border-secondary-100 hover:shadow-xl hover:border-primary-200 transition-all duration-300"
data-category={post.data.category}
>
<!-- Post Image -->
<a href={`/blog/${post.slug}`} class="block aspect-video overflow-hidden bg-secondary-200">
{post.data.heroImage ? (
<img
src={post.data.heroImage}
alt={post.data.title}
width="640"
height="360"
class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300"
loading="lazy"
decoding="async"
/>
) : (
<div class="w-full h-full flex items-center justify-center bg-gradient-to-br from-primary-500 to-primary-700">
<svg class="w-16 h-16 text-white/50" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M19 20H5a2 2 0 01-2-2V6a2 2 0 012-2h10a2 2 0 012 2v1m2 13a2 2 0 01-2-2V7m2 13a2 2 0 002-2V9a2 2 0 00-2-2h-2m-4-3H9M7 16h6M7 8h6v4H7V8z" />
</svg>
</div>
)}
</a>
<!-- Post Content -->
<div class="p-6">
<!-- Category & Reading Time -->
<div class="flex items-center gap-3 mb-3">
<span class="px-3 py-1 bg-primary-50 text-primary-700 text-xs font-semibold rounded-full">
{post.data.category}
</span>
<span class="text-secondary-400 text-sm flex items-center gap-1">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
{readingTime} min read
</span>
</div>
<!-- Title -->
<h2 class="text-xl font-bold text-secondary-900 mb-3 line-clamp-2 group-hover:text-primary-600 transition-colors">
<a href={`/blog/${post.slug}`}>{post.data.title}</a>
</h2>
<!-- Description -->
<p class="text-secondary-600 text-sm mb-4 line-clamp-3">
{post.data.description}
</p>
<!-- Tags -->
<div class="flex flex-wrap gap-2 mb-4">
{post.data.tags.slice(0, 3).map((tag) => (
<span class="text-xs text-secondary-500 bg-secondary-100 px-2 py-1 rounded">
#{tag}
</span>
))}
</div>
<!-- Author & Date -->
<div class="flex items-center justify-between pt-4 border-t border-secondary-100">
<div class="flex items-center gap-2">
<div class="w-8 h-8 rounded-full bg-gradient-to-br from-primary-400 to-primary-600 flex items-center justify-center text-white text-sm font-bold">
{post.data.author.name.charAt(0)}
</div>
<span class="text-sm text-secondary-600">{post.data.author.name}</span>
</div>
<time class="text-sm text-secondary-400" datetime={post.data.pubDate.toISOString()}>
{formatDate(post.data.pubDate)}
</time>
</div>
</div>
</article>
);
})}
</div>
<!-- Empty State -->
<div id="empty-state" class="hidden text-center py-16">
<svg class="w-16 h-16 text-secondary-300 mx-auto mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M9.172 16.172a4 4 0 015.656 0M9 10h.01M15 10h.01M12 2C6.477 2 2 6.477 2 12s4.477 10 10 10 10-4.477 10-10S17.523 2 12 2z" />
</svg>
<h3 class="text-xl font-semibold text-secondary-600 mb-2">No posts found</h3>
<p class="text-secondary-400">Try selecting a different category.</p>
</div>
</div>
</section>
</BaseLayout>
<script>
const filterButtons = document.querySelectorAll('.filter-btn');
const postCards = document.querySelectorAll('.post-card');
const emptyState = document.getElementById('empty-state');
filterButtons.forEach((btn) => {
btn.addEventListener('click', () => {
const category = btn.getAttribute('data-category');
// Update button states
filterButtons.forEach((b) => {
b.classList.remove('bg-primary-500', 'text-white');
b.classList.add('bg-white', 'text-secondary-600', 'border', 'border-secondary-200');
b.setAttribute('aria-selected', 'false');
});
btn.classList.remove('bg-white', 'text-secondary-600', 'border', 'border-secondary-200');
btn.classList.add('bg-primary-500', 'text-white');
btn.setAttribute('aria-selected', 'true');
// Filter posts
let visibleCount = 0;
postCards.forEach((card) => {
const postCategory = card.getAttribute('data-category');
if (category === 'All' || postCategory === category) {
card.classList.remove('hidden');
visibleCount++;
} else {
card.classList.add('hidden');
}
});
// Show empty state if no posts
if (emptyState) {
emptyState.classList.toggle('hidden', visibleCount > 0);
}
});
});
</script>
File diff suppressed because it is too large Load Diff
+909
View File
@@ -0,0 +1,909 @@
---
// Home page - WorkRoot IT Solutions
import BaseLayout from '../layouts/BaseLayout.astro';
import SEO from '../components/SEO.astro';
// Benefits/Features data
const benefits = [
{
icon: 'rocket',
title: 'Rapid Development',
description: 'Launch your product 3x faster with our agile methodology and proven frameworks.',
},
{
icon: 'shield',
title: 'Enterprise Security',
description: 'Bank-grade security protocols protecting your data and user privacy.',
},
{
icon: 'scale',
title: 'Built to Scale',
description: 'Infrastructure that grows with your business, from startup to enterprise.',
},
{
icon: 'support',
title: '24/7 Support',
description: 'Round-the-clock technical support ensuring your systems run smoothly.',
},
];
// Services data
const services = [
{
icon: 'code',
title: 'Web Development',
description: 'Custom web applications built with modern frameworks and best practices.',
features: ['React/Next.js', 'API Development', 'Progressive Web Apps'],
},
{
icon: 'smartphone',
title: 'Mobile Apps',
description: 'Native and cross-platform mobile solutions for iOS and Android.',
features: ['iOS & Android', 'React Native', 'Flutter'],
},
{
icon: 'brain',
title: 'AI & Machine Learning',
description: 'Intelligent automation and predictive analytics for your business.',
features: ['NLP & Computer Vision', 'Predictive Analytics', 'Automation'],
},
{
icon: 'cloud',
title: 'Cloud Solutions',
description: 'Scalable cloud infrastructure and migration services.',
features: ['AWS & Azure', 'DevOps & CI/CD', 'Migration Services'],
},
];
// How it works steps
const steps = [
{
number: '01',
title: 'Discovery',
description: 'We understand your business goals, challenges, and technical requirements.',
},
{
number: '02',
title: 'Planning',
description: 'Strategic roadmap with clear milestones, timelines, and deliverables.',
},
{
number: '03',
title: 'Development',
description: 'Agile sprints with regular check-ins and iterative improvements.',
},
{
number: '04',
title: 'Launch & Support',
description: 'Smooth deployment with ongoing maintenance and optimization.',
},
];
// Testimonials data
const testimonials = [
{
quote: 'WorkRoot transformed our digital presence completely. Their team delivered beyond our expectations with a modern, scalable solution.',
author: 'Sarah Chen',
role: 'CTO, TechVentures Inc.',
avatar: 'SC',
rating: 5,
},
{
quote: 'The AI integration they built for us has increased our operational efficiency by 40%. Truly game-changing partnership.',
author: 'Michael Roberts',
role: 'CEO, DataFlow Systems',
avatar: 'MR',
rating: 5,
},
{
quote: 'Professional, responsive, and technically excellent. WorkRoot is now our go-to partner for all development needs.',
author: 'Emily Watson',
role: 'Director of IT, GlobalRetail',
avatar: 'EW',
rating: 5,
},
{
quote: 'Their cloud migration expertise saved us months of work. The transition was seamless and our costs dropped 30%.',
author: 'James Liu',
role: 'VP Engineering, CloudFirst',
avatar: 'JL',
rating: 5,
},
];
// Stats data
const stats = [
{ value: 150, suffix: '+', label: 'Projects Delivered', icon: 'briefcase' },
{ value: 98, suffix: '%', label: 'Client Satisfaction', icon: 'heart' },
{ value: 50, suffix: '+', label: 'Enterprise Clients', icon: 'building' },
{ value: 24, suffix: '/7', label: 'Support Available', icon: 'clock' },
];
// FAQ data
const faqs = [
{
question: 'What technologies do you specialize in?',
answer: 'We specialize in modern web technologies including React, Next.js, Node.js, Python, and cloud platforms like AWS and Azure. Our team stays current with the latest industry trends and best practices.',
},
{
question: 'How long does a typical project take?',
answer: 'Project timelines vary based on complexity. A simple website might take 4-6 weeks, while a complex web application could take 3-6 months. We provide detailed timelines during the planning phase.',
},
{
question: 'Do you offer ongoing support after launch?',
answer: 'Yes! We offer comprehensive support packages including bug fixes, security updates, performance monitoring, and feature enhancements. Our 24/7 support ensures your systems run smoothly.',
},
{
question: 'What is your development process?',
answer: 'We follow an agile methodology with 2-week sprints, regular check-ins, and iterative development. You\'ll have full visibility into progress with access to staging environments and regular demos.',
},
{
question: 'Can you work with our existing team?',
answer: 'Absolutely! We excel at collaborating with in-house teams. Whether you need to augment your team or prefer a fully managed solution, we adapt to your workflow and tools.',
},
{
question: 'How do you ensure project security?',
answer: 'Security is built into every phase. We follow OWASP guidelines, conduct regular security audits, implement encryption, and ensure compliance with industry standards like GDPR and SOC 2.',
},
];
---
<BaseLayout
title="Home"
description="WorkRoot IT Solutions — Build software that scales. Expert web development, mobile apps, AI/ML & cloud services. 150+ projects, 98% satisfaction, 50+ enterprise clients. Get started today."
>
<SEO
slot="head"
type="WebPage"
faq={faqs}
/>
<!-- Hero Section - Enhanced -->
<section class="relative min-h-screen flex items-center overflow-hidden bg-gradient-to-br from-secondary-900 via-secondary-800 to-primary-900">
<!-- Background decorative elements -->
<div class="absolute inset-0 overflow-hidden pointer-events-none" aria-hidden="true">
<div class="absolute -top-40 -right-40 w-[600px] h-[600px] bg-primary/20 rounded-full blur-3xl animate-pulse-slow"></div>
<div class="absolute -bottom-40 -left-40 w-[500px] h-[500px] bg-accent/10 rounded-full blur-3xl animate-pulse-slower"></div>
<div class="absolute top-1/3 right-1/4 w-[400px] h-[400px] bg-primary/10 rounded-full blur-3xl"></div>
<!-- Grid pattern overlay -->
<div class="absolute inset-0 bg-[linear-gradient(rgba(255,255,255,0.02)_1px,transparent_1px),linear-gradient(90deg,rgba(255,255,255,0.02)_1px,transparent_1px)] bg-[size:80px_80px]"></div>
<!-- Spotlight effect -->
<div class="absolute inset-0 bg-gradient-to-b from-transparent via-transparent to-secondary-900/50"></div>
</div>
<div class="container-wrapper relative z-10 py-24">
<div class="max-w-5xl mx-auto text-center">
<!-- Trust badge -->
<div class="inline-flex items-center gap-2 px-4 py-2 rounded-full bg-white/10 backdrop-blur-sm border border-white/20 mb-8 opacity-0 animate-slide-up">
<svg class="w-5 h-5 text-accent-400" fill="currentColor" viewBox="0 0 20 20" aria-hidden="true">
<path fill-rule="evenodd" d="M6.267 3.455a3.066 3.066 0 001.745-.723 3.066 3.066 0 013.976 0 3.066 3.066 0 001.745.723 3.066 3.066 0 012.812 2.812c.051.643.304 1.254.723 1.745a3.066 3.066 0 010 3.976 3.066 3.066 0 00-.723 1.745 3.066 3.066 0 01-2.812 2.812 3.066 3.066 0 00-1.745.723 3.066 3.066 0 01-3.976 0 3.066 3.066 0 00-1.745-.723 3.066 3.066 0 01-2.812-2.812 3.066 3.066 0 00-.723-1.745 3.066 3.066 0 010-3.976 3.066 3.066 0 00.723-1.745 3.066 3.066 0 012.812-2.812zm7.44 5.252a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"/>
</svg>
<span class="text-sm font-medium text-white">Trusted by 50+ Enterprise Clients</span>
</div>
<!-- Main heading with gradient -->
<h1 class="text-5xl sm:text-6xl lg:text-7xl xl:text-8xl font-bold text-white leading-[1.1] tracking-tight">
<span class="block opacity-0 animate-slide-up" style="animation-delay: 0.2s;">Build Software</span>
<span class="block opacity-0 animate-slide-up" style="animation-delay: 0.4s;">That <span class="text-transparent bg-clip-text bg-gradient-to-r from-primary-400 via-primary-300 to-accent-400">Scales</span></span>
</h1>
<p class="mt-8 text-xl sm:text-2xl text-secondary-200 max-w-3xl mx-auto opacity-0 animate-slide-up leading-relaxed" style="animation-delay: 0.6s;">
From startup MVP to enterprise platform, we build modern software solutions that grow with your business. Fast, secure, and built to last.
</p>
<!-- Dual CTA Buttons -->
<div class="mt-12 flex flex-wrap justify-center gap-4 opacity-0 animate-slide-up" style="animation-delay: 0.8s;">
<a
href="/contact"
class="group inline-flex items-center justify-center rounded-xl bg-gradient-to-r from-primary-500 to-primary-600 px-10 py-5 text-lg font-bold text-white transition-all hover:shadow-2xl hover:shadow-primary/50 hover:scale-105 focus:outline-none focus:ring-2 focus:ring-primary-400 focus:ring-offset-2 focus:ring-offset-secondary-900"
>
Start Your Project
<svg class="ml-2 w-5 h-5 group-hover:translate-x-1 transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 8l4 4m0 0l-4 4m4-4H3"></path>
</svg>
</a>
<a
href="/portfolio"
class="group inline-flex items-center justify-center rounded-xl border-2 border-white/30 bg-white/5 backdrop-blur-sm px-10 py-5 text-lg font-bold text-white transition-all hover:bg-white/10 hover:border-white/50 focus:outline-none focus:ring-2 focus:ring-white/50 focus:ring-offset-2 focus:ring-offset-secondary-900"
>
<svg class="mr-2 w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"></path>
</svg>
View Our Work
</a>
</div>
<!-- Social Proof Logos/Stats -->
<div class="mt-20 opacity-0 animate-slide-up" style="animation-delay: 1s;">
<p class="text-sm text-secondary-400 uppercase tracking-wider mb-8">Powered By Industry Leaders</p>
<div class="flex flex-wrap justify-center items-center gap-12 opacity-60" role="list" aria-label="Technologies we use">
<div class="text-2xl font-bold text-white" role="listitem">AWS</div>
<div class="text-2xl font-bold text-white" role="listitem">Azure</div>
<div class="text-2xl font-bold text-white" role="listitem">React</div>
<div class="text-2xl font-bold text-white" role="listitem">Next.js</div>
<div class="text-2xl font-bold text-white" role="listitem">Node.js</div>
</div>
</div>
</div>
</div>
<!-- Scroll indicator -->
<div class="absolute bottom-8 left-1/2 -translate-x-1/2 opacity-0 animate-fade-in" style="animation-delay: 1.2s;">
<a href="#benefits" class="flex flex-col items-center text-white/60 hover:text-white transition-colors group" aria-label="Scroll to benefits">
<span class="text-sm mb-2">Discover More</span>
<svg class="w-6 h-6 animate-bounce" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 14l-7 7m0 0l-7-7m7 7V3"></path>
</svg>
</a>
</div>
</section>
<!-- Benefits Section - NEW -->
<section id="benefits" class="py-24 bg-white">
<div class="container-wrapper">
<div class="text-center max-w-3xl mx-auto mb-20" data-animate="fade-up">
<span class="inline-block px-4 py-2 rounded-full bg-primary-50 text-primary-700 text-sm font-bold uppercase tracking-wider mb-4">Why Choose Us</span>
<h2 class="text-4xl sm:text-5xl font-bold text-secondary-900 mb-6">Built for Your Success</h2>
<p class="text-xl text-secondary-600">
We don't just write code. We build solutions that drive measurable business results.
</p>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8">
{benefits.map((benefit, index) => (
<div class="group relative bg-gradient-to-br from-secondary-50 to-white rounded-2xl p-8 border border-secondary-100 hover:border-primary/30 hover:shadow-2xl transition-all duration-500 hover:-translate-y-2 card-interactive" data-animate="fade-up" data-delay={String(index * 100)}>
<!-- Icon -->
<div class="w-16 h-16 rounded-2xl bg-gradient-to-br from-primary-500 to-primary-600 flex items-center justify-center mb-6 group-hover:scale-110 group-hover:rotate-6 transition-all duration-500 shadow-lg">
{benefit.icon === 'rocket' && (
<svg class="w-8 h-8 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"></path>
</svg>
)}
{benefit.icon === 'shield' && (
<svg class="w-8 h-8 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"></path>
</svg>
)}
{benefit.icon === 'scale' && (
<svg class="w-8 h-8 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 12l3-3 3 3 4-4M8 21l4-4 4 4M3 4h18M4 4h16v12a1 1 0 01-1 1H5a1 1 0 01-1-1V4z"></path>
</svg>
)}
{benefit.icon === 'support' && (
<svg class="w-8 h-8 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M18.364 5.636l-3.536 3.536m0 5.656l3.536 3.536M9.172 9.172L5.636 5.636m3.536 9.192l-3.536 3.536M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-5 0a4 4 0 11-8 0 4 4 0 018 0z"></path>
</svg>
)}
</div>
<h3 class="text-2xl font-bold text-secondary-900 mb-3">{benefit.title}</h3>
<p class="text-secondary-600 leading-relaxed">{benefit.description}</p>
<!-- Decorative corner -->
<div class="absolute top-4 right-4 w-2 h-2 bg-primary-400 rounded-full opacity-0 group-hover:opacity-100 transition-opacity"></div>
</div>
))}
</div>
</div>
</section>
<!-- Services Section - Enhanced -->
<section id="services" class="py-24 bg-gradient-to-b from-secondary-50 to-white">
<div class="container-wrapper">
<div class="text-center max-w-3xl mx-auto mb-20" data-animate="fade-up">
<span class="inline-block px-4 py-2 rounded-full bg-primary-50 text-primary-700 text-sm font-bold uppercase tracking-wider mb-4">Our Services</span>
<h2 class="text-4xl sm:text-5xl font-bold text-secondary-900 mb-6">Comprehensive Technology Solutions</h2>
<p class="text-xl text-secondary-600">
From concept to deployment, we deliver end-to-end solutions tailored to your unique business needs.
</p>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-8 max-w-6xl mx-auto">
{services.map((service, index) => (
<div class="group relative bg-white rounded-3xl p-10 shadow-lg border-2 border-secondary-100 hover:border-primary-400 hover:shadow-2xl transition-all duration-500 overflow-hidden card-interactive" data-animate="fade-up" data-delay={String(index % 2 === 0 ? 0 : 150)}>
<!-- Background gradient on hover -->
<div class="absolute inset-0 bg-gradient-to-br from-primary-50/0 to-primary-50/0 group-hover:from-primary-50/50 group-hover:to-transparent transition-all duration-500"></div>
<div class="relative z-10">
<!-- Icon -->
<div class="w-20 h-20 rounded-2xl bg-gradient-to-br from-primary-500 to-primary-600 flex items-center justify-center mb-6 group-hover:scale-110 transition-transform duration-500 shadow-xl">
{service.icon === 'code' && (
<svg class="w-10 h-10 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4"></path>
</svg>
)}
{service.icon === 'smartphone' && (
<svg class="w-10 h-10 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 18h.01M8 21h8a2 2 0 002-2V5a2 2 0 00-2-2H8a2 2 0 00-2 2v14a2 2 0 002 2z"></path>
</svg>
)}
{service.icon === 'brain' && (
<svg class="w-10 h-10 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z"></path>
</svg>
)}
{service.icon === 'cloud' && (
<svg class="w-10 h-10 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 15a4 4 0 004 4h9a5 5 0 10-.1-9.999 5.002 5.002 0 10-9.78 2.096A4.001 4.001 0 003 15z"></path>
</svg>
)}
</div>
<h3 class="text-2xl font-bold text-secondary-900 mb-4">{service.title}</h3>
<p class="text-secondary-600 text-lg mb-6 leading-relaxed">{service.description}</p>
<!-- Features list -->
<ul class="space-y-3">
{service.features?.map((feature) => (
<li class="flex items-center text-secondary-700">
<svg class="w-5 h-5 text-primary-500 mr-3 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20" aria-hidden="true">
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"/>
</svg>
<span class="font-medium">{feature}</span>
</li>
))}
</ul>
<!-- Learn more arrow -->
<div class="mt-6 flex items-center text-primary-600 font-semibold group-hover:text-primary-700 transition-colors">
<span>Learn More</span>
<svg class="w-5 h-5 ml-2 group-hover:translate-x-2 transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 8l4 4m0 0l-4 4m4-4H3"></path>
</svg>
</div>
</div>
<!-- Number badge -->
<div class="absolute top-6 right-6 w-12 h-12 rounded-full bg-primary-100 flex items-center justify-center text-primary-700 font-bold text-lg opacity-50 group-hover:opacity-100 transition-opacity">
{(index + 1).toString().padStart(2, '0')}
</div>
</div>
))}
</div>
<div class="text-center mt-16">
<a href="/services" class="inline-flex items-center justify-center rounded-xl bg-primary px-10 py-5 text-lg font-bold text-white transition-all hover:bg-primary-600 hover:shadow-2xl hover:shadow-primary/30 hover:scale-105 focus:outline-none focus:ring-2 focus:ring-primary-400 focus:ring-offset-2">
Explore All Services
<svg class="ml-2 w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 8l4 4m0 0l-4 4m4-4H3"></path>
</svg>
</a>
</div>
</div>
</section>
<!-- How It Works Section - NEW -->
<section class="py-24 bg-gradient-to-br from-secondary-900 via-secondary-800 to-primary-900 relative overflow-hidden">
<!-- Background pattern -->
<div class="absolute inset-0 opacity-5">
<div class="absolute inset-0 bg-[linear-gradient(rgba(255,255,255,0.1)_1px,transparent_1px),linear-gradient(90deg,rgba(255,255,255,0.1)_1px,transparent_1px)] bg-[size:64px_64px]"></div>
</div>
<div class="container-wrapper relative z-10">
<div class="text-center max-w-3xl mx-auto mb-20">
<span class="inline-block px-4 py-2 rounded-full bg-primary-400/20 text-primary-300 text-sm font-bold uppercase tracking-wider mb-4">Our Process</span>
<h2 class="text-4xl sm:text-5xl font-bold text-white mb-6">How We Work</h2>
<p class="text-xl text-secondary-300">
A proven methodology that delivers results, on time and on budget.
</p>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8 max-w-7xl mx-auto">
{steps.map((step, index) => (
<div class="relative" data-animate="fade-up" data-delay={String(index * 150)}>
{/* Connecting line */}
{index < steps.length - 1 && (
<div class="hidden lg:block absolute top-20 left-[60%] w-full h-0.5 bg-gradient-to-r from-primary-500/50 to-transparent"></div>
)}
<div class="group relative bg-white/5 backdrop-blur-sm rounded-2xl p-8 border border-white/10 hover:bg-white/10 hover:border-primary-400/50 transition-all duration-500">
{/* Number badge */}
<div class="w-16 h-16 rounded-2xl bg-gradient-to-br from-primary-500 to-primary-600 flex items-center justify-center mb-6 shadow-lg group-hover:scale-110 transition-transform duration-500">
<span class="text-2xl font-bold text-white">{step.number}</span>
</div>
<h3 class="text-2xl font-bold text-white mb-4">{step.title}</h3>
<p class="text-secondary-300 leading-relaxed">{step.description}</p>
{/* Decorative dot */}
<div class="absolute bottom-6 right-6 w-2 h-2 bg-primary-400 rounded-full opacity-0 group-hover:opacity-100 transition-opacity"></div>
</div>
</div>
))}
</div>
<div class="text-center mt-16">
<a href="/contact" class="inline-flex items-center justify-center rounded-xl bg-white px-10 py-5 text-lg font-bold text-secondary-900 transition-all hover:shadow-2xl hover:scale-105 focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-secondary-900">
Start Your Journey
<svg class="ml-2 w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 8l4 4m0 0l-4 4m4-4H3"></path>
</svg>
</a>
</div>
</div>
</section>
<!-- Stats/Metrics Section - Enhanced -->
<section class="py-24 bg-white">
<div class="container-wrapper">
<div class="text-center max-w-3xl mx-auto mb-16" data-animate="fade-up">
<span class="inline-block px-4 py-2 rounded-full bg-accent-50 text-accent-700 text-sm font-bold uppercase tracking-wider mb-4">Track Record</span>
<h2 class="text-4xl sm:text-5xl font-bold text-secondary-900 mb-6">Numbers That Matter</h2>
<p class="text-xl text-secondary-600">
Our success is measured by the impact we create for our clients.
</p>
</div>
<div class="grid grid-cols-2 lg:grid-cols-4 gap-8">
{stats.map((stat, index) => (
<div class="group text-center bg-gradient-to-br from-secondary-50 to-white rounded-3xl p-10 border-2 border-secondary-100 hover:border-primary-400 hover:shadow-2xl transition-all duration-500 hover:-translate-y-2" data-animate="scale-up" data-delay={String(index * 100)}>
{/* Icon */}
<div class="w-16 h-16 rounded-2xl bg-gradient-to-br from-primary-500 to-primary-600 flex items-center justify-center mx-auto mb-6 group-hover:scale-110 group-hover:rotate-12 transition-all duration-500 shadow-lg">
{stat.icon === 'briefcase' && (
<svg class="w-8 h-8 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 13.255A23.931 23.931 0 0112 15c-3.183 0-6.22-.62-9-1.745M16 6V4a2 2 0 00-2-2h-4a2 2 0 00-2 2v2m4 6h.01M5 20h14a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"></path>
</svg>
)}
{stat.icon === 'heart' && (
<svg class="w-8 h-8 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z"></path>
</svg>
)}
{stat.icon === 'building' && (
<svg class="w-8 h-8 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4"></path>
</svg>
)}
{stat.icon === 'clock' && (
<svg class="w-8 h-8 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"></path>
</svg>
)}
</div>
<div class="stat-counter text-5xl font-bold text-secondary-900 mb-2" data-target={stat.value} data-suffix={stat.suffix}>
0{stat.suffix}
</div>
<div class="text-secondary-600 font-semibold">{stat.label}</div>
</div>
))}
</div>
</div>
</section>
<!-- Testimonials Section - Enhanced -->
<section class="py-24 bg-gradient-to-b from-secondary-50 to-white">
<div class="container-wrapper">
<div class="text-center max-w-3xl mx-auto mb-20" data-animate="fade-up">
<span class="inline-block px-4 py-2 rounded-full bg-accent-50 text-accent-700 text-sm font-bold uppercase tracking-wider mb-4">Client Stories</span>
<h2 class="text-4xl sm:text-5xl font-bold text-secondary-900 mb-6">Loved by Teams Worldwide</h2>
<p class="text-xl text-secondary-600">
Don't just take our word for it. Here's what our clients have to say about working with us.
</p>
</div>
<!-- Testimonials Carousel -->
<div class="relative max-w-5xl mx-auto" data-animate="fade-up" data-delay="200">
<div class="testimonial-carousel overflow-hidden rounded-3xl" aria-roledescription="carousel" aria-label="Client testimonials">
<div class="testimonial-track flex transition-transform duration-500 ease-in-out" aria-live="polite" aria-atomic="false">
{testimonials.map((testimonial, index) => (
<div class="testimonial-slide w-full flex-shrink-0 px-4" data-index={index} role="group" aria-roledescription="slide" aria-label={`Testimonial ${index + 1} of ${testimonials.length}`}>
<div class="bg-gradient-to-br from-white to-secondary-50 rounded-3xl p-10 sm:p-14 border-2 border-secondary-100 shadow-xl">
<!-- Star rating -->
<div class="flex gap-1 mb-6" aria-label={`${testimonial.rating || 5} out of 5 stars`}>
{[...Array(testimonial.rating || 5)].map(() => (
<svg class="w-6 h-6 text-accent-500" fill="currentColor" viewBox="0 0 20 20" aria-hidden="true">
<path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"></path>
</svg>
))}
</div>
<!-- Quote icon -->
<svg class="w-16 h-16 text-primary-500/20 mb-6" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path d="M14.017 21v-7.391c0-5.704 3.731-9.57 8.983-10.609l.995 2.151c-2.432.917-3.995 3.638-3.995 5.849h4v10h-9.983zm-14.017 0v-7.391c0-5.704 3.748-9.57 9-10.609l.996 2.151c-2.433.917-3.996 3.638-3.996 5.849h3.983v10h-9.983z"></path>
</svg>
<blockquote class="text-2xl sm:text-3xl text-secondary-800 font-medium leading-relaxed mb-10">
"{testimonial.quote}"
</blockquote>
<div class="flex items-center">
<div class="w-16 h-16 rounded-full bg-gradient-to-br from-primary-500 to-primary-600 flex items-center justify-center text-white font-bold text-xl shadow-lg" aria-hidden="true">
{testimonial.avatar}
</div>
<div class="ml-5">
<div class="font-bold text-secondary-900 text-lg">{testimonial.author}</div>
<div class="text-secondary-600">{testimonial.role}</div>
</div>
</div>
</div>
</div>
))}
</div>
</div>
<!-- Carousel Controls -->
<div class="flex items-center justify-center mt-10 gap-6">
<button
class="carousel-prev w-14 h-14 rounded-full bg-white border-2 border-secondary-200 flex items-center justify-center text-secondary-600 hover:border-primary hover:text-primary hover:bg-primary-50 transition-all shadow-lg hover:shadow-xl"
aria-label="Previous testimonial"
>
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M15 19l-7-7 7-7"></path>
</svg>
</button>
<!-- Dots indicator -->
<div class="carousel-dots flex gap-3">
{testimonials.map((_, index) => (
<button
class={`h-3 rounded-full transition-all ${index === 0 ? 'bg-primary w-10' : 'bg-secondary-300 hover:bg-secondary-400 w-3'}`}
data-index={index}
aria-label={`Go to testimonial ${index + 1}`}
>
</button>
))}
</div>
<button
class="carousel-next w-14 h-14 rounded-full bg-white border-2 border-secondary-200 flex items-center justify-center text-secondary-600 hover:border-primary hover:text-primary hover:bg-primary-50 transition-all shadow-lg hover:shadow-xl"
aria-label="Next testimonial"
>
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M9 5l7 7-7 7"></path>
</svg>
</button>
</div>
</div>
</div>
</section>
<!-- FAQ Section - NEW -->
<section class="py-24 bg-white">
<div class="container-wrapper">
<div class="grid grid-cols-1 lg:grid-cols-2 gap-16 items-start max-w-7xl mx-auto">
<!-- Left column - Header -->
<div class="lg:sticky lg:top-8" data-animate="fade-right">
<span class="inline-block px-4 py-2 rounded-full bg-primary-50 text-primary-700 text-sm font-bold uppercase tracking-wider mb-4">FAQ</span>
<h2 class="text-4xl sm:text-5xl font-bold text-secondary-900 mb-6">Common Questions</h2>
<p class="text-xl text-secondary-600 mb-8">
Everything you need to know about working with us. Can't find the answer you're looking for?
</p>
<a href="/contact" class="inline-flex items-center text-primary-600 font-semibold hover:text-primary-700 transition-colors">
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"></path>
</svg>
Chat with our team
</a>
</div>
<!-- Right column - Accordion -->
<div class="space-y-4" data-animate="fade-left" data-delay="150">
{faqs.map((faq, index) => (
<div class="group bg-secondary-50 rounded-2xl border-2 border-secondary-100 hover:border-primary-300 transition-all duration-300 overflow-hidden">
<button
class="faq-question w-full text-left px-8 py-6 flex items-start justify-between gap-4"
data-faq-index={index}
aria-expanded="false"
aria-controls={`faq-answer-${index}`}
id={`faq-question-${index}`}
>
<span class="font-bold text-lg text-secondary-900 pr-4">{faq.question}</span>
<svg class="faq-icon w-6 h-6 text-primary-500 flex-shrink-0 transition-transform duration-300" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M19 9l-7 7-7-7"></path>
</svg>
</button>
<div class="faq-answer max-h-0 overflow-hidden transition-all duration-300" id={`faq-answer-${index}`} role="region" aria-labelledby={`faq-question-${index}`}>
<div class="px-8 pb-6 text-secondary-600 leading-relaxed">
{faq.answer}
</div>
</div>
</div>
))}
</div>
</div>
</div>
</section>
<!-- Final CTA Section - Enhanced -->
<section class="py-24 bg-gradient-to-br from-secondary-900 via-primary-900 to-primary-800 relative overflow-hidden">
<!-- Background decorations -->
<div class="absolute inset-0 overflow-hidden pointer-events-none">
<div class="absolute -top-40 -right-40 w-[500px] h-[500px] bg-accent/20 rounded-full blur-3xl"></div>
<div class="absolute -bottom-40 -left-40 w-[500px] h-[500px] bg-primary/20 rounded-full blur-3xl"></div>
<div class="absolute inset-0 bg-[linear-gradient(rgba(255,255,255,0.03)_1px,transparent_1px),linear-gradient(90deg,rgba(255,255,255,0.03)_1px,transparent_1px)] bg-[size:64px_64px]"></div>
</div>
<div class="container-wrapper text-center relative z-10">
<div class="max-w-4xl mx-auto" data-animate="fade-up">
<h2 class="text-4xl sm:text-5xl lg:text-6xl font-bold text-white mb-8 leading-tight">
Ready to Build Something <span class="text-transparent bg-clip-text bg-gradient-to-r from-primary-300 to-accent-400">Amazing?</span>
</h2>
<p class="text-xl sm:text-2xl text-secondary-200 mb-12 max-w-2xl mx-auto leading-relaxed">
Let's turn your vision into reality. Get in touch and we'll schedule a free consultation to discuss your project.
</p>
<div class="flex flex-wrap justify-center gap-6">
<a
href="/contact"
class="group inline-flex items-center justify-center rounded-xl bg-white px-12 py-6 text-lg font-bold text-secondary-900 transition-all hover:shadow-2xl hover:shadow-white/30 hover:scale-105 focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-primary-900"
>
Get Started Today
<svg class="ml-2 w-5 h-5 group-hover:translate-x-1 transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M17 8l4 4m0 0l-4 4m4-4H3"></path>
</svg>
</a>
<a
href="/portfolio"
class="inline-flex items-center justify-center rounded-xl border-2 border-white/30 bg-white/5 backdrop-blur-sm px-12 py-6 text-lg font-bold text-white transition-all hover:bg-white/10 hover:border-white/50 focus:outline-none focus:ring-2 focus:ring-white/50 focus:ring-offset-2 focus:ring-offset-primary-900"
>
<svg class="mr-2 w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10"></path>
</svg>
View Case Studies
</a>
</div>
<!-- Contact info -->
<div class="mt-16 pt-12 border-t border-white/10">
<p class="text-secondary-300 mb-6">Prefer to reach out directly?</p>
<div class="flex flex-wrap justify-center gap-8 text-white">
<a href="mailto:info@workroot.in" class="flex items-center gap-2 hover:text-primary-300 transition-colors">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"></path>
</svg>
<span class="font-semibold">info@workroot.in</span>
</a>
<a href="tel:+918860077551" class="flex items-center gap-2 hover:text-primary-300 transition-colors">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z"></path>
</svg>
<span class="font-semibold">+91 88600 77551</span>
</a>
</div>
</div>
</div>
</div>
</section>
</BaseLayout>
<style>
/* Animation keyframes */
@keyframes slide-up {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes pulse-slow {
0%, 100% {
opacity: 0.4;
}
50% {
opacity: 0.6;
}
}
@keyframes pulse-slower {
0%, 100% {
opacity: 0.2;
}
50% {
opacity: 0.4;
}
}
.animate-slide-up {
animation: slide-up 0.8s ease-out forwards;
}
.animate-fade-in {
animation: fade-in 0.8s ease-out forwards;
}
.animate-pulse-slow {
animation: pulse-slow 4s ease-in-out infinite;
}
.animate-pulse-slower {
animation: pulse-slower 6s ease-in-out infinite;
}
/* Stat counter animation */
.stat-counter {
font-variant-numeric: tabular-nums;
}
/* FAQ accordion styles */
.faq-answer {
transition: max-height 0.3s ease-out;
}
.faq-question[aria-expanded="true"] + .faq-answer {
max-height: 500px;
}
.faq-question[aria-expanded="true"] .faq-icon {
transform: rotate(180deg);
}
</style>
<script>
// Stats counter animation
function animateCounters() {
const counters = document.querySelectorAll('.stat-counter');
const duration = 2000;
counters.forEach((counter) => {
const target = parseInt(counter.getAttribute('data-target') || '0');
const suffix = counter.getAttribute('data-suffix') || '';
const startTime = performance.now();
function updateCounter(currentTime: number) {
const elapsed = currentTime - startTime;
const progress = Math.min(elapsed / duration, 1);
const easeOutQuart = 1 - Math.pow(1 - progress, 4);
const current = Math.floor(easeOutQuart * target);
counter.textContent = current + suffix;
if (progress < 1) {
requestAnimationFrame(updateCounter);
}
}
requestAnimationFrame(updateCounter);
});
}
// Testimonials carousel
function initCarousel() {
const track = document.querySelector('.testimonial-track') as HTMLElement;
const slides = document.querySelectorAll('.testimonial-slide');
const dots = document.querySelectorAll('.carousel-dots button');
const prevBtn = document.querySelector('.carousel-prev');
const nextBtn = document.querySelector('.carousel-next');
if (!track || slides.length === 0) return;
let currentIndex = 0;
let autoplayInterval: ReturnType<typeof setInterval>;
const totalSlides = slides.length;
const autoplayDelay = 6000;
function goToSlide(index: number) {
currentIndex = (index + totalSlides) % totalSlides;
track.style.transform = `translateX(-${currentIndex * 100}%)`;
dots.forEach((dot, i) => {
if (i === currentIndex) {
dot.classList.remove('bg-secondary-300', 'hover:bg-secondary-400', 'w-3');
dot.classList.add('bg-primary', 'w-10');
} else {
dot.classList.add('bg-secondary-300', 'hover:bg-secondary-400', 'w-3');
dot.classList.remove('bg-primary', 'w-10');
}
});
}
function nextSlide() {
goToSlide(currentIndex + 1);
}
function prevSlide() {
goToSlide(currentIndex - 1);
}
function startAutoplay() {
autoplayInterval = setInterval(nextSlide, autoplayDelay);
}
function stopAutoplay() {
clearInterval(autoplayInterval);
}
function resetAutoplay() {
stopAutoplay();
startAutoplay();
}
// Event listeners
prevBtn?.addEventListener('click', () => {
prevSlide();
resetAutoplay();
});
nextBtn?.addEventListener('click', () => {
nextSlide();
resetAutoplay();
});
dots.forEach((dot, index) => {
dot.addEventListener('click', () => {
goToSlide(index);
resetAutoplay();
});
});
// Pause on hover
track.addEventListener('mouseenter', stopAutoplay);
track.addEventListener('mouseleave', startAutoplay);
// Start autoplay
startAutoplay();
}
// FAQ Accordion
function initFAQ() {
const faqButtons = document.querySelectorAll('.faq-question');
faqButtons.forEach((button) => {
button.addEventListener('click', () => {
const isExpanded = button.getAttribute('aria-expanded') === 'true';
// Close all FAQs
faqButtons.forEach((btn) => {
btn.setAttribute('aria-expanded', 'false');
});
// Toggle current FAQ
if (!isExpanded) {
button.setAttribute('aria-expanded', 'true');
}
});
});
}
// Intersection Observer for counter animation
const statsSection = document.querySelector('.stat-counter')?.closest('section');
if (statsSection) {
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
animateCounters();
observer.disconnect();
}
});
},
{ threshold: 0.3 }
);
observer.observe(statsSection);
}
// Initialize components
initCarousel();
initFAQ();
// Smooth scroll for anchor links
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', function (e) {
const href = this.getAttribute('href');
if (href && href !== '#') {
e.preventDefault();
const target = document.querySelector(href);
if (target) {
target.scrollIntoView({
behavior: 'smooth',
block: 'start'
});
}
}
});
});
</script>
+82
View File
@@ -0,0 +1,82 @@
---
import BaseLayout from '../layouts/BaseLayout.astro';
---
<BaseLayout
title="You're Offline"
description="It looks like you're offline. Please check your internet connection."
noIndex={true}
>
<section class="min-h-[60vh] flex items-center justify-center px-4">
<div class="text-center max-w-lg mx-auto">
<!-- Icon -->
<div class="mb-8 flex justify-center">
<div class="w-24 h-24 rounded-full bg-primary/10 flex items-center justify-center">
<svg
class="w-12 h-12 text-primary"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
aria-hidden="true"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="1.5"
d="M18.364 5.636a9 9 0 010 12.728M15.536 8.464a5 5 0 010 7.072M12 12h.01M6.343 17.657a9 9 0 010-12.728M8.464 15.536a5 5 0 010-7.072"
/>
<line x1="3" y1="3" x2="21" y2="21" stroke-width="1.5" stroke-linecap="round" />
</svg>
</div>
</div>
<!-- Heading -->
<h1 class="text-3xl font-bold text-secondary-900 mb-4">You're Offline</h1>
<!-- Message -->
<p class="text-secondary-600 text-lg mb-8">
It looks like you've lost your internet connection. Some content may still be available
from your last visit.
</p>
<!-- Actions -->
<div class="flex flex-col sm:flex-row gap-4 justify-center">
<button
id="retry-btn"
class="btn-primary px-8 py-3 rounded-lg font-semibold transition-all"
onclick="window.location.reload()"
>
Try Again
</button>
<a
href="/"
class="btn-secondary px-8 py-3 rounded-lg font-semibold transition-all text-center"
>
Go to Home
</a>
</div>
<!-- Cached pages hint -->
<p class="mt-8 text-sm text-secondary-400">
Previously visited pages may still be accessible from your browser cache.
</p>
</div>
</section>
</BaseLayout>
<style>
.btn-primary {
background-color: theme('colors.primary.DEFAULT');
color: white;
}
.btn-primary:hover {
background-color: theme('colors.primary.600');
}
.btn-secondary {
border: 2px solid theme('colors.primary.DEFAULT');
color: theme('colors.primary.DEFAULT');
}
.btn-secondary:hover {
background-color: theme('colors.primary.50');
}
</style>
File diff suppressed because it is too large Load Diff
+224
View File
@@ -0,0 +1,224 @@
---
// Privacy Policy Page for WorkRoot IT Solutions
// Features: Legal content with proper formatting for readability
import BaseLayout from '../layouts/BaseLayout.astro';
const lastUpdated = 'March 20, 2026';
---
<BaseLayout
title="Privacy Policy"
description="WorkRoot IT Solutions Privacy Policy - Learn how we collect, use, and protect your personal information."
noIndex={true}
>
<!-- Hero Section -->
<section class="relative bg-gradient-to-br from-secondary-900 via-secondary-800 to-secondary-900 py-16 lg:py-20">
<div class="absolute inset-0 overflow-hidden">
<div class="absolute top-0 left-1/4 w-96 h-96 bg-primary-500/10 rounded-full blur-3xl"></div>
<div class="absolute bottom-0 right-1/4 w-96 h-96 bg-accent-500/10 rounded-full blur-3xl"></div>
</div>
<div class="container mx-auto px-4 sm:px-6 lg:px-8 relative z-10">
<div class="max-w-3xl mx-auto text-center">
<h1 class="text-4xl md:text-5xl font-bold text-white mb-4">
Privacy <span class="text-transparent bg-clip-text bg-gradient-to-r from-primary-400 to-accent-400">Policy</span>
</h1>
<p class="text-lg text-secondary-300">
Last updated: {lastUpdated}
</p>
</div>
</div>
</section>
<!-- Content Section -->
<section class="py-16 lg:py-24 bg-secondary-950">
<div class="container mx-auto px-4 sm:px-6 lg:px-8">
<div class="max-w-4xl mx-auto">
<div class="prose prose-lg prose-invert prose-headings:text-white prose-p:text-secondary-300 prose-li:text-secondary-300 prose-strong:text-white max-w-none">
<!-- Introduction -->
<div class="bg-secondary-900/50 border border-secondary-800 rounded-2xl p-8 mb-8">
<p class="text-secondary-300 leading-relaxed">
At WorkRoot IT Solutions ("we," "our," or "us"), we are committed to protecting your privacy and ensuring the security of your personal information. This Privacy Policy explains how we collect, use, disclose, and safeguard your information when you visit our website or use our services.
</p>
</div>
<!-- Section 1 -->
<div class="mb-12">
<h2 class="text-2xl font-bold text-white mb-4 flex items-center gap-3">
<span class="flex items-center justify-center w-10 h-10 rounded-full bg-primary-500/20 text-primary-400 text-lg font-bold">1</span>
Information We Collect
</h2>
<div class="pl-13 space-y-4">
<h3 class="text-xl font-semibold text-white mt-6 mb-3">Personal Information</h3>
<p class="text-secondary-300">We may collect personal information that you voluntarily provide to us, including:</p>
<ul class="list-disc pl-6 space-y-2 text-secondary-300">
<li>Name and contact information (email address, phone number, mailing address)</li>
<li>Company name and job title</li>
<li>Account credentials (username and password)</li>
<li>Payment and billing information</li>
<li>Communication preferences</li>
</ul>
<h3 class="text-xl font-semibold text-white mt-6 mb-3">Automatically Collected Information</h3>
<p class="text-secondary-300">When you visit our website, we may automatically collect:</p>
<ul class="list-disc pl-6 space-y-2 text-secondary-300">
<li>IP address and device identifiers</li>
<li>Browser type and operating system</li>
<li>Pages visited and time spent on our site</li>
<li>Referring website addresses</li>
<li>Cookies and similar tracking technologies</li>
</ul>
</div>
</div>
<!-- Section 2 -->
<div class="mb-12">
<h2 class="text-2xl font-bold text-white mb-4 flex items-center gap-3">
<span class="flex items-center justify-center w-10 h-10 rounded-full bg-primary-500/20 text-primary-400 text-lg font-bold">2</span>
How We Use Your Information
</h2>
<div class="pl-13">
<p class="text-secondary-300 mb-4">We use the information we collect to:</p>
<ul class="list-disc pl-6 space-y-2 text-secondary-300">
<li>Provide, operate, and maintain our services</li>
<li>Process transactions and send related information</li>
<li>Respond to your inquiries and provide customer support</li>
<li>Send promotional communications (with your consent)</li>
<li>Improve our website and services</li>
<li>Detect and prevent fraud or security threats</li>
<li>Comply with legal obligations</li>
</ul>
</div>
</div>
<!-- Section 3 -->
<div class="mb-12">
<h2 class="text-2xl font-bold text-white mb-4 flex items-center gap-3">
<span class="flex items-center justify-center w-10 h-10 rounded-full bg-primary-500/20 text-primary-400 text-lg font-bold">3</span>
Information Sharing and Disclosure
</h2>
<div class="pl-13">
<p class="text-secondary-300 mb-4">We may share your information with:</p>
<ul class="list-disc pl-6 space-y-2 text-secondary-300">
<li><strong class="text-white">Service Providers:</strong> Third parties who perform services on our behalf (hosting, analytics, payment processing)</li>
<li><strong class="text-white">Business Partners:</strong> Trusted partners for joint marketing initiatives (with your consent)</li>
<li><strong class="text-white">Legal Requirements:</strong> When required by law or to protect our rights</li>
<li><strong class="text-white">Business Transfers:</strong> In connection with a merger, acquisition, or sale of assets</li>
</ul>
<p class="text-secondary-300 mt-4">We do not sell your personal information to third parties.</p>
</div>
</div>
<!-- Section 4 -->
<div class="mb-12">
<h2 class="text-2xl font-bold text-white mb-4 flex items-center gap-3">
<span class="flex items-center justify-center w-10 h-10 rounded-full bg-primary-500/20 text-primary-400 text-lg font-bold">4</span>
Cookies and Tracking Technologies
</h2>
<div class="pl-13">
<p class="text-secondary-300 mb-4">We use cookies and similar technologies to:</p>
<ul class="list-disc pl-6 space-y-2 text-secondary-300">
<li>Remember your preferences and settings</li>
<li>Analyze website traffic and usage patterns</li>
<li>Deliver targeted advertising</li>
<li>Improve user experience</li>
</ul>
<p class="text-secondary-300 mt-4">You can manage cookie preferences through your browser settings. Note that disabling cookies may affect website functionality.</p>
</div>
</div>
<!-- Section 5 -->
<div class="mb-12">
<h2 class="text-2xl font-bold text-white mb-4 flex items-center gap-3">
<span class="flex items-center justify-center w-10 h-10 rounded-full bg-primary-500/20 text-primary-400 text-lg font-bold">5</span>
Data Security
</h2>
<div class="pl-13">
<p class="text-secondary-300">We implement appropriate technical and organizational measures to protect your personal information, including:</p>
<ul class="list-disc pl-6 space-y-2 text-secondary-300 mt-4">
<li>SSL/TLS encryption for data in transit</li>
<li>Secure data storage with access controls</li>
<li>Regular security assessments and updates</li>
<li>Employee training on data protection</li>
</ul>
<p class="text-secondary-300 mt-4">While we strive to protect your information, no method of transmission over the Internet is 100% secure.</p>
</div>
</div>
<!-- Section 6 -->
<div class="mb-12">
<h2 class="text-2xl font-bold text-white mb-4 flex items-center gap-3">
<span class="flex items-center justify-center w-10 h-10 rounded-full bg-primary-500/20 text-primary-400 text-lg font-bold">6</span>
Your Rights and Choices
</h2>
<div class="pl-13">
<p class="text-secondary-300 mb-4">Depending on your location, you may have the right to:</p>
<ul class="list-disc pl-6 space-y-2 text-secondary-300">
<li>Access and obtain a copy of your personal data</li>
<li>Correct inaccurate or incomplete information</li>
<li>Request deletion of your personal data</li>
<li>Object to or restrict certain processing</li>
<li>Data portability (receive your data in a structured format)</li>
<li>Withdraw consent at any time</li>
<li>Opt-out of marketing communications</li>
</ul>
<p class="text-secondary-300 mt-4">To exercise these rights, please contact us using the information below.</p>
</div>
</div>
<!-- Section 7 -->
<div class="mb-12">
<h2 class="text-2xl font-bold text-white mb-4 flex items-center gap-3">
<span class="flex items-center justify-center w-10 h-10 rounded-full bg-primary-500/20 text-primary-400 text-lg font-bold">7</span>
Data Retention
</h2>
<div class="pl-13">
<p class="text-secondary-300">We retain your personal information for as long as necessary to fulfill the purposes outlined in this Privacy Policy, unless a longer retention period is required or permitted by law. When we no longer need your information, we will securely delete or anonymize it.</p>
</div>
</div>
<!-- Section 8 -->
<div class="mb-12">
<h2 class="text-2xl font-bold text-white mb-4 flex items-center gap-3">
<span class="flex items-center justify-center w-10 h-10 rounded-full bg-primary-500/20 text-primary-400 text-lg font-bold">8</span>
Children's Privacy
</h2>
<div class="pl-13">
<p class="text-secondary-300">Our services are not intended for individuals under the age of 16. We do not knowingly collect personal information from children. If you believe we have collected information from a child, please contact us immediately.</p>
</div>
</div>
<!-- Section 9 -->
<div class="mb-12">
<h2 class="text-2xl font-bold text-white mb-4 flex items-center gap-3">
<span class="flex items-center justify-center w-10 h-10 rounded-full bg-primary-500/20 text-primary-400 text-lg font-bold">9</span>
Changes to This Policy
</h2>
<div class="pl-13">
<p class="text-secondary-300">We may update this Privacy Policy from time to time. We will notify you of any material changes by posting the new policy on this page and updating the "Last updated" date. Your continued use of our services after such changes constitutes acceptance of the updated policy.</p>
</div>
</div>
<!-- Section 10 -->
<div class="mb-12">
<h2 class="text-2xl font-bold text-white mb-4 flex items-center gap-3">
<span class="flex items-center justify-center w-10 h-10 rounded-full bg-primary-500/20 text-primary-400 text-lg font-bold">10</span>
Contact Us
</h2>
<div class="pl-13">
<p class="text-secondary-300 mb-4">If you have questions about this Privacy Policy or our data practices, please contact us:</p>
<div class="bg-secondary-900/50 border border-secondary-800 rounded-xl p-6">
<p class="text-secondary-300"><strong class="text-white">WorkRoot IT Solutions</strong></p>
<p class="text-secondary-300">Email: privacy@workroot.in</p>
<p class="text-secondary-300">Phone: +1 (555) 123-4567</p>
<p class="text-secondary-300">Address: 123 Tech Avenue, Suite 500, San Francisco, CA 94102</p>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
</BaseLayout>
+949
View File
@@ -0,0 +1,949 @@
---
// Services Page for WorkRoot IT Solutions
// Enhanced: Service cards with tech stack, pricing tiers, case study highlights, scroll animations
import BaseLayout from '../layouts/BaseLayout.astro';
import SEO from '../components/SEO.astro';
// Service data with extended details
const services = [
{
id: 'web-development',
title: 'Web Development',
shortDescription: 'Custom web applications built with modern frameworks for performance and scalability.',
fullDescription: 'From responsive websites to complex web applications, we deliver solutions that drive results. Our team specializes in React, Next.js, and Node.js to build fast, secure, and maintainable web experiences that convert visitors into customers.',
icon: 'web',
features: [
'Custom web application development',
'E-commerce solutions',
'Progressive Web Apps (PWA)',
'API development & integration',
'Performance optimization',
'SEO-friendly architecture',
],
techStack: ['React', 'Next.js', 'Node.js', 'TypeScript', 'PostgreSQL'],
stats: { projects: '80+', clients: '50+', uptime: '99.9%' },
gradient: 'from-primary-500 to-primary-700',
bgLight: 'bg-primary-50',
iconColor: 'text-primary-500',
accentBorder: 'border-primary-500',
tagBg: 'bg-primary-100 text-primary-700',
},
{
id: 'mobile-development',
title: 'Mobile Development',
shortDescription: 'Native and cross-platform mobile apps that deliver exceptional user experiences.',
fullDescription: 'We create mobile applications that users love. Whether you need iOS, Android, or cross-platform solutions, our developers use React Native and Flutter to build apps that perform flawlessly across all devices and screen sizes.',
icon: 'mobile',
features: [
'iOS & Android native apps',
'Cross-platform development',
'UI/UX design for mobile',
'App Store optimization',
'Push notifications & analytics',
'Offline-first architecture',
],
techStack: ['React Native', 'Flutter', 'Swift', 'Kotlin', 'Firebase'],
stats: { projects: '40+', clients: '30+', rating: '4.8★' },
gradient: 'from-accent-500 to-accent-700',
bgLight: 'bg-accent-50',
iconColor: 'text-accent-500',
accentBorder: 'border-accent-500',
tagBg: 'bg-amber-100 text-amber-700',
},
{
id: 'ai-ml',
title: 'AI & Machine Learning',
shortDescription: 'Intelligent solutions powered by cutting-edge artificial intelligence technologies.',
fullDescription: 'Harness the power of AI to transform your business. From predictive analytics to natural language processing, we implement machine learning solutions that provide actionable insights and automate complex processes at scale.',
icon: 'ai',
features: [
'Predictive analytics',
'Natural Language Processing',
'Computer vision solutions',
'Recommendation engines',
'Chatbots & virtual assistants',
'ML model deployment & monitoring',
],
techStack: ['Python', 'TensorFlow', 'PyTorch', 'OpenAI API', 'LangChain'],
stats: { models: '25+', accuracy: '94%', savings: '60%' },
gradient: 'from-emerald-500 to-emerald-700',
bgLight: 'bg-emerald-50',
iconColor: 'text-emerald-600',
accentBorder: 'border-emerald-500',
tagBg: 'bg-emerald-100 text-emerald-700',
},
{
id: 'cloud-services',
title: 'Cloud Services',
shortDescription: 'Scalable cloud infrastructure and DevOps solutions for modern businesses.',
fullDescription: 'Migrate, scale, and optimize with confidence. Our cloud experts help you leverage AWS, Azure, and Google Cloud to build resilient, cost-effective infrastructure that grows with your business and adapts to any load.',
icon: 'cloud',
features: [
'Cloud migration & strategy',
'Infrastructure as Code (IaC)',
'Kubernetes & container orchestration',
'CI/CD pipeline setup',
'Cloud security & compliance',
'24/7 monitoring & support',
],
techStack: ['AWS', 'Azure', 'GCP', 'Kubernetes', 'Terraform'],
stats: { migrations: '35+', savings: '40%', uptime: '99.99%' },
gradient: 'from-secondary-600 to-secondary-800',
bgLight: 'bg-secondary-50',
iconColor: 'text-secondary-600',
accentBorder: 'border-secondary-500',
tagBg: 'bg-slate-100 text-slate-700',
},
];
// Pricing tiers
const pricingTiers = [
{
name: 'Starter',
price: '$2,500',
period: 'per project',
description: 'Perfect for startups and small businesses launching their digital presence.',
features: [
'Up to 5 pages / screens',
'Responsive design',
'Basic SEO setup',
'Contact form integration',
'1 month post-launch support',
'Source code handoff',
],
cta: 'Get Started',
highlighted: false,
},
{
name: 'Growth',
price: '$8,500',
period: 'per project',
description: 'For businesses ready to scale with advanced features and integrations.',
features: [
'Unlimited pages / screens',
'Custom UI/UX design',
'API & third-party integrations',
'Performance optimization',
'3 months post-launch support',
'Analytics dashboard',
'Priority support',
],
cta: 'Most Popular',
highlighted: true,
},
{
name: 'Enterprise',
price: 'Custom',
period: 'tailored quote',
description: 'Full-scale solutions for complex, high-traffic enterprise applications.',
features: [
'End-to-end architecture',
'Dedicated development team',
'SLA-backed uptime',
'Security audits & compliance',
'12 months support & maintenance',
'Training & documentation',
'White-glove onboarding',
],
cta: 'Contact Sales',
highlighted: false,
},
];
// Case study highlights
const caseStudies = [
{
service: 'Web Development',
client: 'FinTech Platform',
result: '3x faster load times, 45% increase in conversion rate',
description: 'Rebuilt a legacy banking dashboard with Next.js and real-time WebSocket updates, cutting page load from 8s to under 2s.',
metric: '+45%',
metricLabel: 'Conversion Rate',
tag: 'Web',
tagColor: 'bg-primary-100 text-primary-700',
icon: 'web',
gradient: 'from-primary-500/10 to-primary-600/5',
borderColor: 'border-primary-200',
},
{
service: 'Mobile Development',
client: 'Retail App',
result: '200K+ downloads in first month, 4.9★ App Store rating',
description: 'Built a cross-platform shopping app with AR try-on features using React Native, launching simultaneously on iOS and Android.',
metric: '200K+',
metricLabel: 'Downloads',
tag: 'Mobile',
tagColor: 'bg-accent-100 text-accent-700',
icon: 'mobile',
gradient: 'from-accent-500/10 to-accent-600/5',
borderColor: 'border-accent-200',
},
{
service: 'AI & ML',
client: 'Healthcare Provider',
result: '60% reduction in manual processing, 94% diagnostic accuracy',
description: 'Deployed a computer vision model for medical imaging analysis, reducing radiologist review time and improving early detection rates.',
metric: '60%',
metricLabel: 'Time Saved',
tag: 'AI/ML',
tagColor: 'bg-emerald-100 text-emerald-700',
icon: 'ai',
gradient: 'from-emerald-500/10 to-emerald-600/5',
borderColor: 'border-emerald-200',
},
];
// Process steps
const processSteps = [
{
number: '01',
title: 'Discovery',
description: 'We analyze your requirements, goals, and challenges to define the project scope.',
icon: 'search',
},
{
number: '02',
title: 'Strategy',
description: 'Our team develops a comprehensive roadmap tailored to your business objectives.',
icon: 'map',
},
{
number: '03',
title: 'Development',
description: 'We build your solution using agile methodologies with regular progress updates.',
icon: 'code',
},
{
number: '04',
title: 'Launch & Support',
description: 'We deploy, monitor, and continuously improve your solution post-launch.',
icon: 'rocket',
},
];
---
<BaseLayout
title="IT Services & Solutions"
description="Expert web development, mobile apps, AI/ML solutions & cloud services from WorkRoot IT Solutions. 100+ projects delivered, 50+ happy clients. From $2,500 — get a free quote today."
>
<SEO
slot="head"
type="Service"
breadcrumbs={[
{ name: 'Home', url: '/' },
{ name: 'Services', url: '/services' }
]}
service={{
name: 'IT Solutions & Software Development',
description: 'Full-stack software development services including web development, mobile apps, AI & machine learning, and cloud infrastructure. Serving startups and enterprises worldwide.'
}}
faq={[
{
question: 'What IT services does WorkRoot offer?',
answer: 'WorkRoot offers four core services: Web Development (React, Next.js, Node.js), Mobile App Development (iOS, Android, React Native, Flutter), AI & Machine Learning (Python, TensorFlow, LangChain), and Cloud Services (AWS, Azure, GCP, Kubernetes).'
},
{
question: 'How much does a web development project cost?',
answer: 'Our pricing starts at $2,500 for Starter projects (up to 5 pages), $8,500 for Growth projects with custom features and integrations, and custom quotes for Enterprise solutions. Contact us for a free estimate tailored to your requirements.'
},
{
question: 'How long does software development take?',
answer: 'Project timelines depend on scope. A simple website takes 46 weeks, a complex web app 36 months, and an enterprise solution can take 612 months. We provide detailed timelines during the discovery phase.'
},
{
question: 'Do you offer post-launch support and maintenance?',
answer: 'Yes. All packages include post-launch support: 1 month for Starter, 3 months for Growth, and 12 months for Enterprise. We also offer ongoing SLA-backed maintenance retainers for continued peace of mind.'
},
{
question: 'Can WorkRoot build AI-powered features into my application?',
answer: 'Absolutely. Our AI/ML team integrates natural language processing, computer vision, recommendation engines, and predictive analytics into web and mobile products. We have delivered 25+ AI models with 94% average accuracy.'
}
]}
/>
<!-- Hero Section -->
<section class="relative bg-gradient-to-br from-secondary-900 via-secondary-800 to-secondary-900 py-24 lg:py-32 overflow-hidden">
<div class="absolute inset-0 overflow-hidden pointer-events-none" aria-hidden="true">
<div class="absolute top-1/4 left-0 w-80 h-80 bg-primary-500/10 rounded-full blur-3xl animate-pulse-slower"></div>
<div class="absolute bottom-0 right-1/4 w-96 h-96 bg-accent-500/8 rounded-full blur-3xl animate-pulse-slow"></div>
<div class="absolute top-0 right-0 w-64 h-64 bg-emerald-500/8 rounded-full blur-3xl"></div>
<!-- Grid pattern overlay -->
<div class="absolute inset-0 opacity-5" style="background-image: linear-gradient(rgba(255,255,255,.05) 1px, transparent 1px), linear-gradient(90deg, rgba(255,255,255,.05) 1px, transparent 1px); background-size: 60px 60px;"></div>
</div>
<div class="container-wrapper relative">
<div class="max-w-3xl mx-auto text-center reveal-on-scroll">
<span class="inline-flex items-center gap-2 px-4 py-1.5 mb-6 text-sm font-semibold text-primary-300 bg-primary-500/10 rounded-full border border-primary-500/20">
<span class="w-1.5 h-1.5 rounded-full bg-primary-400 animate-pulse"></span>
Our Services
</span>
<h1 class="text-4xl sm:text-5xl lg:text-6xl font-bold text-white mb-6 leading-tight">
Solutions That
<span class="text-transparent bg-clip-text bg-gradient-to-r from-primary-400 via-primary-300 to-accent-400">
Power Growth
</span>
</h1>
<p class="text-lg sm:text-xl text-secondary-300 max-w-2xl mx-auto mb-10 leading-relaxed">
From concept to deployment, we deliver end-to-end technology solutions that transform businesses and drive measurable results.
</p>
<!-- Quick service nav pills -->
<div class="flex flex-wrap gap-2 justify-center">
{services.map((service) => (
<a
href={`#${service.id}`}
class="px-4 py-1.5 text-sm font-medium text-white/70 hover:text-white bg-white/5 hover:bg-white/10 rounded-full border border-white/10 hover:border-white/20 transition-all duration-200"
>
{service.title}
</a>
))}
</div>
</div>
<!-- Floating stats bar -->
<div class="mt-16 grid grid-cols-2 sm:grid-cols-4 gap-4 lg:gap-6 reveal-on-scroll reveal-delay-2">
{[
{ value: '100+', label: 'Projects Delivered' },
{ value: '50+', label: 'Happy Clients' },
{ value: '4', label: 'Core Services' },
{ value: '5★', label: 'Average Rating' },
].map((stat) => (
<div class="bg-white/5 backdrop-blur-sm rounded-xl p-4 lg:p-5 text-center border border-white/10">
<p class="text-2xl lg:text-3xl font-bold text-white">{stat.value}</p>
<p class="text-secondary-400 text-sm mt-1">{stat.label}</p>
</div>
))}
</div>
</div>
</section>
<!-- Services Cards Section -->
<section class="py-16 lg:py-24 bg-white">
<div class="container-wrapper">
<div class="text-center max-w-2xl mx-auto mb-12 lg:mb-16 reveal-on-scroll">
<span class="text-primary-500 font-semibold text-sm uppercase tracking-wider">What We Offer</span>
<h2 class="text-3xl sm:text-4xl font-bold text-secondary-900 mt-2 mb-4">Our Core Services</h2>
<p class="text-secondary-600 text-lg">
Comprehensive technology solutions designed to accelerate your digital transformation journey.
</p>
</div>
<div class="grid sm:grid-cols-2 gap-6 lg:gap-8">
{services.map((service, idx) => (
<a
href={`#${service.id}`}
class={`service-card group relative bg-white rounded-2xl p-8 shadow-sm border border-secondary-100 hover:shadow-2xl hover:border-transparent hover:-translate-y-2 transition-all duration-300 focus:outline-none focus:ring-2 focus:ring-primary-400 focus:ring-offset-2 reveal-on-scroll reveal-delay-${idx + 1}`}
aria-label={`Learn more about ${service.title}`}
>
<!-- Hover gradient overlay -->
<div class={`absolute inset-0 bg-gradient-to-br ${service.gradient} rounded-2xl opacity-0 group-hover:opacity-100 transition-opacity duration-300`} aria-hidden="true"></div>
<!-- Top border accent -->
<div class={`absolute top-0 left-8 right-8 h-0.5 bg-gradient-to-r ${service.gradient} rounded-full opacity-0 group-hover:opacity-100 transition-opacity duration-300`} aria-hidden="true"></div>
<div class="relative">
<!-- Icon + stats row -->
<div class="flex items-start justify-between mb-6">
<div class={`w-14 h-14 ${service.bgLight} ${service.iconColor} rounded-xl flex items-center justify-center group-hover:bg-white/20 group-hover:text-white transition-all duration-300 flex-shrink-0`}>
{service.icon === 'web' && (
<svg xmlns="http://www.w3.org/2000/svg" class="w-7 h-7" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M21 12a9 9 0 01-9 9m9-9a9 9 0 00-9-9m9 9H3m9 9a9 9 0 01-9-9m9 9c1.657 0 3-4.03 3-9s-1.343-9-3-9m0 18c-1.657 0-3-4.03-3-9s1.343-9 3-9m-9 9a9 9 0 019-9" />
</svg>
)}
{service.icon === 'mobile' && (
<svg xmlns="http://www.w3.org/2000/svg" class="w-7 h-7" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 18h.01M8 21h8a2 2 0 002-2V5a2 2 0 00-2-2H8a2 2 0 00-2 2v14a2 2 0 002 2z" />
</svg>
)}
{service.icon === 'ai' && (
<svg xmlns="http://www.w3.org/2000/svg" class="w-7 h-7" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
</svg>
)}
{service.icon === 'cloud' && (
<svg xmlns="http://www.w3.org/2000/svg" class="w-7 h-7" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M3 15a4 4 0 004 4h9a5 5 0 10-.1-9.999 5.002 5.002 0 10-9.78 2.096A4.001 4.001 0 003 15z" />
</svg>
)}
</div>
<!-- Mini stats -->
<div class="text-right">
{Object.entries(service.stats).slice(0, 1).map(([key, val]) => (
<div>
<p class="text-xl font-bold text-secondary-900 group-hover:text-white transition-colors duration-300">{val}</p>
<p class="text-xs text-secondary-500 group-hover:text-white/70 transition-colors duration-300 capitalize">{key.replace(/([A-Z])/g, ' $1').trim()}</p>
</div>
))}
</div>
</div>
<!-- Content -->
<h3 class="text-xl font-bold text-secondary-900 group-hover:text-white mb-2 transition-colors duration-300">
{service.title}
</h3>
<p class="text-secondary-600 group-hover:text-white/80 mb-5 transition-colors duration-300 text-sm leading-relaxed">
{service.shortDescription}
</p>
<!-- Tech stack tags -->
<div class="flex flex-wrap gap-1.5 mb-5">
{service.techStack.map((tech) => (
<span class={`px-2.5 py-1 text-xs font-medium ${service.tagBg} group-hover:bg-white/20 group-hover:text-white rounded-md transition-colors duration-300`}>
{tech}
</span>
))}
</div>
<!-- Learn more link -->
<span class="inline-flex items-center text-primary-500 group-hover:text-white font-semibold text-sm transition-colors duration-300">
Explore Service
<svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4 ml-1.5 group-hover:translate-x-1.5 transition-transform duration-300" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M17 8l4 4m0 0l-4 4m4-4H3" />
</svg>
</span>
</div>
</a>
))}
</div>
</div>
</section>
<!-- Service Details Sections -->
{services.map((service, index) => (
<section
id={service.id}
class={`py-16 lg:py-24 ${index % 2 === 0 ? 'bg-secondary-50' : 'bg-white'}`}
>
<div class="container-wrapper">
<div class="grid lg:grid-cols-2 gap-12 lg:gap-16 items-center">
<!-- Content column -->
<div class={`reveal-on-scroll ${index % 2 === 1 ? 'lg:order-2' : ''}`}>
<div class={`inline-flex items-center gap-2 px-4 py-2 ${service.bgLight} ${service.iconColor} rounded-full text-sm font-semibold mb-4`}>
{service.icon === 'web' && (
<svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M21 12a9 9 0 01-9 9m9-9a9 9 0 00-9-9m9 9H3m9 9a9 9 0 01-9-9m9 9c1.657 0 3-4.03 3-9s-1.343-9-3-9m0 18c-1.657 0-3-4.03-3-9s1.343-9 3-9m-9 9a9 9 0 019-9" />
</svg>
)}
{service.icon === 'mobile' && (
<svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 18h.01M8 21h8a2 2 0 002-2V5a2 2 0 00-2-2H8a2 2 0 00-2 2v14a2 2 0 002 2z" />
</svg>
)}
{service.icon === 'ai' && (
<svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
</svg>
)}
{service.icon === 'cloud' && (
<svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M3 15a4 4 0 004 4h9a5 5 0 10-.1-9.999 5.002 5.002 0 10-9.78 2.096A4.001 4.001 0 003 15z" />
</svg>
)}
{service.title}
</div>
<h2 class="text-3xl sm:text-4xl font-bold text-secondary-900 mb-4">
{service.title}
</h2>
<p class="text-secondary-600 text-lg leading-relaxed mb-6">
{service.fullDescription}
</p>
<!-- Service stats row -->
<div class="flex flex-wrap gap-4 mb-8">
{Object.entries(service.stats).map(([key, val]) => (
<div class={`flex flex-col px-4 py-3 ${service.bgLight} rounded-lg`}>
<span class={`text-xl font-bold ${service.iconColor}`}>{val}</span>
<span class="text-secondary-500 text-xs capitalize">{key.replace(/([A-Z])/g, ' $1').trim()}</span>
</div>
))}
</div>
<!-- Features list -->
<ul class="space-y-2.5 mb-8">
{service.features.map((feature) => (
<li class="flex items-start gap-3">
<span class={`w-5 h-5 ${service.iconColor} mt-0.5 flex-shrink-0`} aria-hidden="true">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5">
<path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" />
</svg>
</span>
<span class="text-secondary-700">{feature}</span>
</li>
))}
</ul>
<!-- Tech stack -->
<div class="mb-8">
<p class="text-xs font-semibold text-secondary-400 uppercase tracking-wider mb-2">Technologies</p>
<div class="flex flex-wrap gap-2">
{service.techStack.map((tech) => (
<span class={`px-3 py-1 text-sm font-medium ${service.tagBg} rounded-md`}>{tech}</span>
))}
</div>
</div>
<a
href="/contact"
class={`inline-flex items-center justify-center px-7 py-3.5 bg-gradient-to-r ${service.gradient} text-white font-semibold rounded-lg hover:shadow-lg hover:opacity-95 transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-primary-400 focus:ring-offset-2`}
>
Get Started
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 ml-2" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M17 8l4 4m0 0l-4 4m4-4H3" />
</svg>
</a>
</div>
<!-- Visual element -->
<div class={`relative reveal-on-scroll reveal-delay-2 ${index % 2 === 1 ? 'lg:order-1' : ''}`}>
<div class={`aspect-square rounded-2xl bg-gradient-to-br ${service.gradient} p-8 lg:p-12 flex items-center justify-center`}>
<div class="relative w-full h-full bg-white/10 rounded-xl backdrop-blur-sm p-6 lg:p-8">
<!-- Window chrome decoration -->
<div class="absolute top-4 left-4 flex gap-1.5" aria-hidden="true">
<div class="w-3 h-3 rounded-full bg-red-400/60"></div>
<div class="w-3 h-3 rounded-full bg-yellow-400/60"></div>
<div class="w-3 h-3 rounded-full bg-green-400/60"></div>
</div>
<!-- Service-specific visual illustration -->
<div class="h-full flex flex-col justify-center items-center text-white pt-6">
{service.icon === 'web' && (
<div class="w-full space-y-3">
<div class="h-3 bg-white/30 rounded-full w-3/4 mx-auto"></div>
<div class="h-3 bg-white/20 rounded-full w-full"></div>
<div class="h-3 bg-white/20 rounded-full w-5/6 mx-auto"></div>
<div class="mt-4 grid grid-cols-3 gap-2">
<div class="h-16 bg-white/20 rounded-lg"></div>
<div class="h-16 bg-white/20 rounded-lg"></div>
<div class="h-16 bg-white/20 rounded-lg"></div>
</div>
<div class="h-2 bg-white/15 rounded-full w-1/2 mx-auto mt-2"></div>
</div>
)}
{service.icon === 'mobile' && (
<div class="flex gap-4 items-end justify-center w-full">
<div class="w-20 h-36 bg-white/20 rounded-2xl border-2 border-white/30 flex flex-col items-center pt-3 gap-2">
<div class="w-6 h-1 bg-white/40 rounded-full"></div>
<div class="w-12 h-2 bg-white/25 rounded-full"></div>
<div class="w-10 h-2 bg-white/20 rounded-full"></div>
<div class="w-12 h-8 bg-white/15 rounded-lg mt-1"></div>
</div>
<div class="w-24 h-44 bg-white/25 rounded-2xl border-2 border-white/40 flex flex-col items-center pt-3 gap-2">
<div class="w-8 h-1 bg-white/50 rounded-full"></div>
<div class="w-16 h-2 bg-white/30 rounded-full"></div>
<div class="w-14 h-2 bg-white/25 rounded-full"></div>
<div class="w-16 h-10 bg-white/20 rounded-lg mt-1"></div>
<div class="w-12 h-2 bg-white/20 rounded-full"></div>
</div>
<div class="w-20 h-36 bg-white/20 rounded-2xl border-2 border-white/30 flex flex-col items-center pt-3 gap-2">
<div class="w-6 h-1 bg-white/40 rounded-full"></div>
<div class="w-12 h-2 bg-white/25 rounded-full"></div>
<div class="w-10 h-2 bg-white/20 rounded-full"></div>
<div class="w-12 h-8 bg-white/15 rounded-lg mt-1"></div>
</div>
</div>
)}
{service.icon === 'ai' && (
<div class="w-full space-y-3 px-2">
<div class="flex items-center gap-2">
<div class="w-8 h-8 rounded-full bg-white/30 flex-shrink-0"></div>
<div class="flex-1 h-8 bg-white/20 rounded-lg"></div>
</div>
<div class="flex items-center gap-2 flex-row-reverse">
<div class="w-8 h-8 rounded-full bg-white/20 flex-shrink-0"></div>
<div class="flex-1 h-10 bg-white/15 rounded-lg"></div>
</div>
<div class="flex items-center gap-2">
<div class="w-8 h-8 rounded-full bg-white/30 flex-shrink-0"></div>
<div class="flex-1 h-8 bg-white/20 rounded-lg"></div>
</div>
<div class="flex items-center gap-2 flex-row-reverse">
<div class="w-8 h-8 rounded-full bg-white/20 flex-shrink-0"></div>
<div class="w-2/3 h-8 bg-white/15 rounded-lg"></div>
</div>
</div>
)}
{service.icon === 'cloud' && (
<div class="w-full space-y-3">
<div class="flex justify-center">
<div class="w-24 h-12 bg-white/30 rounded-2xl flex items-center justify-center">
<svg xmlns="http://www.w3.org/2000/svg" class="w-8 h-8 text-white/70" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M3 15a4 4 0 004 4h9a5 5 0 10-.1-9.999 5.002 5.002 0 10-9.78 2.096A4.001 4.001 0 003 15z" />
</svg>
</div>
</div>
<div class="flex justify-center gap-1">
<div class="w-0.5 h-6 bg-white/30"></div>
<div class="w-0.5 h-6 bg-white/30 mx-6"></div>
<div class="w-0.5 h-6 bg-white/30 mx-6"></div>
</div>
<div class="grid grid-cols-3 gap-2">
{['AWS', 'K8s', 'GCP'].map((label) => (
<div class="h-10 bg-white/20 rounded-lg flex items-center justify-center">
<span class="text-white/70 text-xs font-medium">{label}</span>
</div>
))}
</div>
</div>
)}
</div>
</div>
</div>
<!-- Floating stats badge -->
<div class="absolute -bottom-4 -right-4 sm:-bottom-6 sm:-right-6 bg-white rounded-xl shadow-xl p-4 sm:p-5 hidden sm:block border border-secondary-100">
<div class="flex items-center gap-3">
<div class={`w-10 h-10 ${service.bgLight} ${service.iconColor} rounded-lg flex items-center justify-center flex-shrink-0`} aria-hidden="true">
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M9 12l2 2 4-4M7.835 4.697a3.42 3.42 0 001.946-.806 3.42 3.42 0 014.438 0 3.42 3.42 0 001.946.806 3.42 3.42 0 013.138 3.138 3.42 3.42 0 00.806 1.946 3.42 3.42 0 010 4.438 3.42 3.42 0 00-.806 1.946 3.42 3.42 0 01-3.138 3.138 3.42 3.42 0 00-1.946.806 3.42 3.42 0 01-4.438 0 3.42 3.42 0 00-1.946-.806 3.42 3.42 0 01-3.138-3.138 3.42 3.42 0 00-.806-1.946 3.42 3.42 0 010-4.438 3.42 3.42 0 00.806-1.946 3.42 3.42 0 013.138-3.138z" />
</svg>
</div>
<div>
<p class="text-lg font-bold text-secondary-900">{Object.values(service.stats)[0]}</p>
<p class="text-secondary-500 text-xs">{Object.keys(service.stats)[0].replace(/([A-Z])/g, ' $1').trim()}</p>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
))}
<!-- Case Studies Section -->
<section class="py-16 lg:py-24 bg-secondary-50">
<div class="container-wrapper">
<div class="text-center max-w-2xl mx-auto mb-12 lg:mb-16 reveal-on-scroll">
<span class="text-accent-500 font-semibold text-sm uppercase tracking-wider">Real Results</span>
<h2 class="text-3xl sm:text-4xl font-bold text-secondary-900 mt-2 mb-4">Client Success Stories</h2>
<p class="text-secondary-600 text-lg">
Don't take our word for it — see the measurable impact we've delivered for our clients.
</p>
</div>
<div class="grid sm:grid-cols-2 lg:grid-cols-3 gap-6 lg:gap-8">
{caseStudies.map((study, idx) => (
<div class={`case-study-card group relative bg-white rounded-2xl p-6 lg:p-8 border ${study.borderColor} hover:shadow-xl hover:-translate-y-1 transition-all duration-300 overflow-hidden reveal-on-scroll reveal-delay-${idx + 1}`}>
<!-- Background gradient -->
<div class={`absolute inset-0 bg-gradient-to-br ${study.gradient} opacity-50 group-hover:opacity-70 transition-opacity duration-300`} aria-hidden="true"></div>
<div class="relative">
<!-- Tag + icon -->
<div class="flex items-center justify-between mb-4">
<span class={`px-2.5 py-1 text-xs font-semibold ${study.tagColor} rounded-md`}>{study.tag}</span>
<div class="text-secondary-300" aria-hidden="true">
{study.icon === 'web' && (
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5">
<path stroke-linecap="round" stroke-linejoin="round" d="M21 12a9 9 0 01-9 9m9-9a9 9 0 00-9-9m9 9H3m9 9a9 9 0 01-9-9m9 9c1.657 0 3-4.03 3-9s-1.343-9-3-9m0 18c-1.657 0-3-4.03-3-9s1.343-9 3-9m-9 9a9 9 0 019-9" />
</svg>
)}
{study.icon === 'mobile' && (
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 18h.01M8 21h8a2 2 0 002-2V5a2 2 0 00-2-2H8a2 2 0 00-2 2v14a2 2 0 002 2z" />
</svg>
)}
{study.icon === 'ai' && (
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5">
<path stroke-linecap="round" stroke-linejoin="round" d="M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
</svg>
)}
</div>
</div>
<!-- Big metric -->
<p class="text-4xl font-bold text-secondary-900 mb-1">{study.metric}</p>
<p class="text-sm font-medium text-secondary-500 mb-4">{study.metricLabel}</p>
<!-- Client & description -->
<p class="font-semibold text-secondary-800 mb-2">{study.client}</p>
<p class="text-secondary-600 text-sm leading-relaxed mb-4">{study.description}</p>
<!-- Result pill -->
<div class="inline-flex items-center gap-1.5 px-3 py-1 bg-secondary-100 rounded-full text-xs text-secondary-600 font-medium">
<svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5 text-emerald-500" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" />
</svg>
{study.result}
</div>
</div>
</div>
))}
</div>
<div class="mt-10 text-center">
<a
href="/contact"
class="inline-flex items-center gap-2 text-primary-600 hover:text-primary-700 font-semibold text-sm transition-colors duration-200 group"
>
Start your success story
<svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4 group-hover:translate-x-1 transition-transform duration-200" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M17 8l4 4m0 0l-4 4m4-4H3" />
</svg>
</a>
</div>
</div>
</section>
<!-- Pricing Section -->
<section class="py-16 lg:py-24 bg-white">
<div class="container-wrapper">
<div class="text-center max-w-2xl mx-auto mb-12 lg:mb-16 reveal-on-scroll">
<span class="text-primary-500 font-semibold text-sm uppercase tracking-wider">Transparent Pricing</span>
<h2 class="text-3xl sm:text-4xl font-bold text-secondary-900 mt-2 mb-4">Investment Tiers</h2>
<p class="text-secondary-600 text-lg">
Straightforward pricing to fit businesses at every stage. All plans include dedicated project management.
</p>
</div>
<div class="grid md:grid-cols-3 gap-6 lg:gap-8 items-stretch">
{pricingTiers.map((tier, idx) => (
<div
class={`relative flex flex-col rounded-2xl p-7 lg:p-8 reveal-on-scroll reveal-delay-${idx + 1} transition-all duration-300 ${
tier.highlighted
? 'bg-secondary-900 shadow-2xl ring-2 ring-primary-500 md:scale-105'
: 'bg-white border border-secondary-200 hover:shadow-xl hover:-translate-y-1'
}`}
>
{tier.highlighted && (
<div class="absolute -top-3.5 left-1/2 -translate-x-1/2">
<span class="px-4 py-1 bg-primary-500 text-white text-xs font-bold rounded-full uppercase tracking-wide shadow-lg">
Most Popular
</span>
</div>
)}
<div class="mb-6">
<h3 class={`text-xl font-bold mb-1 ${tier.highlighted ? 'text-white' : 'text-secondary-900'}`}>
{tier.name}
</h3>
<p class={`text-sm mb-4 ${tier.highlighted ? 'text-secondary-400' : 'text-secondary-500'}`}>
{tier.description}
</p>
<div class="flex items-baseline gap-2">
<span class={`text-4xl font-bold ${tier.highlighted ? 'text-white' : 'text-secondary-900'}`}>
{tier.price}
</span>
<span class={`text-sm ${tier.highlighted ? 'text-secondary-400' : 'text-secondary-500'}`}>
{tier.period}
</span>
</div>
</div>
<ul class="space-y-3 mb-8 flex-1">
{tier.features.map((feature) => (
<li class="flex items-start gap-3">
<svg
xmlns="http://www.w3.org/2000/svg"
class={`w-5 h-5 flex-shrink-0 mt-0.5 ${tier.highlighted ? 'text-primary-400' : 'text-primary-500'}`}
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
stroke-width="2.5"
aria-hidden="true"
>
<path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" />
</svg>
<span class={`text-sm ${tier.highlighted ? 'text-secondary-300' : 'text-secondary-700'}`}>
{feature}
</span>
</li>
))}
</ul>
<a
href="/contact"
class={`w-full inline-flex items-center justify-center px-6 py-3.5 rounded-lg font-semibold transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 ${
tier.highlighted
? 'bg-primary-500 text-white hover:bg-primary-400 focus:ring-primary-400 focus:ring-offset-secondary-900'
: 'bg-secondary-900 text-white hover:bg-secondary-800 focus:ring-secondary-400'
}`}
>
{tier.cta === 'Most Popular' ? 'Get Started' : tier.cta}
<svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4 ml-2" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M17 8l4 4m0 0l-4 4m4-4H3" />
</svg>
</a>
</div>
))}
</div>
<p class="text-center text-secondary-500 text-sm mt-8">
All prices are estimates. Final scope and pricing determined after discovery call.
<a href="/contact" class="text-primary-600 hover:text-primary-700 font-medium ml-1">Schedule a free consultation →</a>
</p>
</div>
</section>
<!-- Process Section -->
<section class="py-16 lg:py-24 bg-gradient-to-br from-secondary-900 via-secondary-800 to-secondary-900">
<div class="container-wrapper">
<div class="text-center max-w-2xl mx-auto mb-12 lg:mb-16 reveal-on-scroll">
<span class="text-primary-400 font-semibold text-sm uppercase tracking-wider">How We Work</span>
<h2 class="text-3xl sm:text-4xl font-bold text-white mt-2 mb-4">Our Proven Process</h2>
<p class="text-secondary-300 text-lg">
A battle-tested methodology that delivers consistent, high-quality results — on time, every time.
</p>
</div>
<div class="grid sm:grid-cols-2 lg:grid-cols-4 gap-6 lg:gap-4">
{processSteps.map((step, index) => (
<div class={`relative reveal-on-scroll reveal-delay-${index + 1}`}>
<div class="group bg-white/5 backdrop-blur-sm rounded-2xl p-6 lg:p-7 border border-white/10 hover:bg-white/10 hover:border-white/20 hover:-translate-y-1 transition-all duration-300 h-full">
<!-- Step number with glow -->
<div class="relative mb-4">
<span class="text-6xl font-bold text-primary-500/20 leading-none">{step.number}</span>
<div class="absolute -top-1 -left-1 w-8 h-8 bg-primary-500/10 rounded-full blur-md"></div>
</div>
<h3 class="text-lg font-bold text-white mb-2">{step.title}</h3>
<p class="text-secondary-400 text-sm leading-relaxed">{step.description}</p>
</div>
{/* Connector arrow between steps */}
{index < processSteps.length - 1 && (
<div class="hidden lg:flex absolute top-1/2 -right-5 transform -translate-y-1/2 z-10 items-center justify-center w-10">
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 text-primary-500/40" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M9 5l7 7-7 7" />
</svg>
</div>
)}
</div>
))}
</div>
</div>
</section>
<!-- CTA Section -->
<section class="py-16 lg:py-24 bg-gradient-to-r from-primary-600 via-primary-500 to-primary-600 relative overflow-hidden">
<div class="absolute inset-0 pointer-events-none" aria-hidden="true">
<div class="absolute top-0 left-1/4 w-64 h-64 bg-white/5 rounded-full blur-3xl"></div>
<div class="absolute bottom-0 right-1/4 w-80 h-80 bg-white/5 rounded-full blur-3xl"></div>
</div>
<div class="container-wrapper text-center relative reveal-on-scroll">
<span class="inline-block px-4 py-1.5 mb-4 text-sm font-medium text-white/80 bg-white/10 rounded-full border border-white/20">
Ready to get started?
</span>
<h2 class="text-3xl sm:text-4xl lg:text-5xl font-bold text-white mb-4">
Let's Build Something
<span class="italic font-normal"> Great </span>
Together
</h2>
<p class="text-primary-100 text-lg max-w-2xl mx-auto mb-10 leading-relaxed">
Schedule a free 30-minute discovery call and let's discuss how our services can accelerate your business goals.
</p>
<div class="flex flex-col sm:flex-row gap-4 justify-center">
<a
href="/contact"
class="inline-flex items-center justify-center px-8 py-4 bg-white text-primary-600 font-bold rounded-xl hover:bg-primary-50 hover:shadow-xl transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-primary-600"
>
Schedule a Free Call
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 ml-2" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>
</a>
<a
href="/about"
class="inline-flex items-center justify-center px-8 py-4 border-2 border-white/40 text-white font-semibold rounded-xl hover:bg-white/10 hover:border-white/60 transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-primary-600"
>
Learn About Us
</a>
</div>
<!-- Trust signals -->
<div class="mt-10 flex flex-wrap items-center justify-center gap-6 text-white/60 text-sm">
<span class="flex items-center gap-1.5">
<svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" />
</svg>
No commitment required
</span>
<span class="flex items-center gap-1.5">
<svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" />
</svg>
Free project estimate
</span>
<span class="flex items-center gap-1.5">
<svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" />
</svg>
Response within 24 hours
</span>
</div>
</div>
</section>
</BaseLayout>
<style>
/* Scroll-reveal base state */
.reveal-on-scroll {
opacity: 0;
transform: translateY(24px);
transition: opacity 0.6s ease, transform 0.6s ease;
}
.reveal-on-scroll.revealed {
opacity: 1;
transform: translateY(0);
}
/* Staggered delays */
.reveal-delay-1 { transition-delay: 0.1s; }
.reveal-delay-2 { transition-delay: 0.2s; }
.reveal-delay-3 { transition-delay: 0.3s; }
.reveal-delay-4 { transition-delay: 0.4s; }
/* Respect reduced motion */
@media (prefers-reduced-motion: reduce) {
.reveal-on-scroll {
opacity: 1;
transform: none;
transition: none;
}
}
/* Service card inner border accent animation */
.service-card::before {
content: '';
position: absolute;
inset: 0;
border-radius: 1rem;
padding: 1.5px;
background: linear-gradient(135deg, transparent 0%, transparent 50%);
-webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
-webkit-mask-composite: xor;
mask-composite: exclude;
pointer-events: none;
transition: background 0.3s ease;
}
/* Case study card hover */
.case-study-card {
contain: layout style;
}
</style>
<script>
// Intersection Observer for scroll-reveal animations
(function() {
const elements = document.querySelectorAll('.reveal-on-scroll');
if (!elements.length) return;
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.classList.add('revealed');
observer.unobserve(entry.target);
}
});
},
{
threshold: 0.12,
rootMargin: '0px 0px -40px 0px',
}
);
elements.forEach((el) => observer.observe(el));
})();
</script>
+28
View File
@@ -0,0 +1,28 @@
import type { APIRoute } from 'astro';
const site = 'https://workroot.in';
/**
* Sitemap Index - Provides links to individual sitemaps
* Use this when you have multiple content types or large amounts of content
* Currently serves as documentation for future scalability
*/
export const GET: APIRoute = async () => {
const lastmod = new Date().toISOString();
const sitemapIndex = `<?xml version="1.0" encoding="UTF-8"?>
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<sitemap>
<loc>${site}/sitemap.xml</loc>
<lastmod>${lastmod}</lastmod>
</sitemap>
</sitemapindex>`;
return new Response(sitemapIndex, {
headers: {
'Content-Type': 'application/xml; charset=utf-8',
'Cache-Control': 'public, max-age=3600',
'X-Robots-Tag': 'noindex',
},
});
};
+159
View File
@@ -0,0 +1,159 @@
---
// Sitemap Page for WorkRoot IT Solutions
// Features: Visual sitemap with links to all pages organized by category
import BaseLayout from '../layouts/BaseLayout.astro';
// Sitemap structure
const sitemapSections = [
{
title: 'Main Pages',
icon: 'home',
links: [
{ name: 'Home', url: '/', description: 'Welcome to WorkRoot IT Solutions' },
{ name: 'About Us', url: '/about', description: 'Our story, team, and mission' },
{ name: 'Services', url: '/services', description: 'Our IT service offerings' },
{ name: 'Portfolio', url: '/portfolio', description: 'Featured projects and case studies' },
{ name: 'Blog', url: '/blog', description: 'Insights and articles' },
{ name: 'Contact', url: '/contact', description: 'Get in touch with us' },
],
},
{
title: 'Services',
icon: 'briefcase',
links: [
{ name: 'Web Development', url: '/services#web-development', description: 'Custom web applications and e-commerce' },
{ name: 'Mobile Development', url: '/services#mobile-development', description: 'iOS, Android, and cross-platform apps' },
{ name: 'AI & Machine Learning', url: '/services#ai-ml', description: 'Intelligent solutions and automation' },
{ name: 'Cloud Services', url: '/services#cloud', description: 'Cloud migration and infrastructure' },
],
},
{
title: 'Resources',
icon: 'book',
links: [
{ name: 'Blog', url: '/blog', description: 'Latest articles and insights' },
{ name: 'Case Studies', url: '/portfolio', description: 'Detailed project analyses' },
],
},
{
title: 'Company',
icon: 'building',
links: [
{ name: 'About Us', url: '/about', description: 'Learn about our company' },
{ name: 'Our Team', url: '/about#team', description: 'Meet our experts' },
{ name: 'Careers', url: '/contact', description: 'Join our team' },
],
},
{
title: 'Legal',
icon: 'shield',
links: [
{ name: 'Privacy Policy', url: '/privacy', description: 'How we handle your data' },
{ name: 'Terms of Service', url: '/terms', description: 'Terms and conditions' },
{ name: 'Sitemap', url: '/sitemap', description: 'This page' },
],
},
{
title: 'Connect',
icon: 'share',
links: [
{ name: 'Contact Us', url: '/contact', description: 'Send us a message' },
{ name: 'LinkedIn', url: '#', description: 'Follow us on LinkedIn', external: true },
{ name: 'Twitter', url: '#', description: 'Follow us on Twitter', external: true },
{ name: 'GitHub', url: '#', description: 'View our open source projects', external: true },
],
},
];
// Icons mapping
const icons: Record<string, string> = {
home: `<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"></path></svg>`,
briefcase: `<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 13.255A23.931 23.931 0 0112 15c-3.183 0-6.22-.62-9-1.745M16 6V4a2 2 0 00-2-2h-4a2 2 0 00-2 2v2m4 6h.01M5 20h14a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"></path></svg>`,
book: `<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253"></path></svg>`,
building: `<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4"></path></svg>`,
shield: `<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"></path></svg>`,
share: `<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8.684 13.342C8.886 12.938 9 12.482 9 12c0-.482-.114-.938-.316-1.342m0 2.684a3 3 0 110-2.684m0 2.684l6.632 3.316m-6.632-6l6.632-3.316m0 0a3 3 0 105.367-2.684 3 3 0 00-5.367 2.684zm0 9.316a3 3 0 105.368 2.684 3 3 0 00-5.368-2.684z"></path></svg>`,
};
---
<BaseLayout
title="Sitemap"
description="WorkRoot IT Solutions Sitemap - Navigate to all pages and resources on our website."
>
<!-- Hero Section -->
<section class="relative bg-gradient-to-br from-secondary-900 via-secondary-800 to-secondary-900 py-16 lg:py-20">
<div class="absolute inset-0 overflow-hidden">
<div class="absolute top-0 left-1/4 w-96 h-96 bg-primary-500/10 rounded-full blur-3xl"></div>
<div class="absolute bottom-0 right-1/4 w-96 h-96 bg-accent-500/10 rounded-full blur-3xl"></div>
</div>
<div class="container mx-auto px-4 sm:px-6 lg:px-8 relative z-10">
<div class="max-w-3xl mx-auto text-center">
<h1 class="text-4xl md:text-5xl font-bold text-white mb-4">
Site<span class="text-transparent bg-clip-text bg-gradient-to-r from-primary-400 to-accent-400">map</span>
</h1>
<p class="text-lg text-secondary-300">
Find your way around our website
</p>
</div>
</div>
</section>
<!-- Sitemap Grid Section -->
<section class="py-16 lg:py-24 bg-secondary-950">
<div class="container mx-auto px-4 sm:px-6 lg:px-8">
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
{sitemapSections.map((section) => (
<div class="bg-secondary-900/50 border border-secondary-800 rounded-2xl p-6 hover:border-primary-500/30 transition-colors duration-300">
<div class="flex items-center gap-3 mb-6">
<div class="flex items-center justify-center w-12 h-12 rounded-xl bg-primary-500/20 text-primary-400" set:html={icons[section.icon]} />
<h2 class="text-xl font-bold text-white">{section.title}</h2>
</div>
<ul class="space-y-3">
{section.links.map((link) => (
<li>
<a
href={link.url}
class="group flex items-start gap-3 p-3 rounded-lg hover:bg-secondary-800/50 transition-colors duration-200"
target={link.external ? '_blank' : undefined}
rel={link.external ? 'noopener noreferrer' : undefined}
>
<svg class="w-5 h-5 mt-0.5 text-primary-400 group-hover:translate-x-1 transition-transform duration-200" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path>
</svg>
<div>
<span class="text-white font-medium group-hover:text-primary-400 transition-colors duration-200">
{link.name}
{link.external && (
<svg class="w-4 h-4 inline-block ml-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"></path>
</svg>
)}
</span>
<p class="text-sm text-secondary-400 mt-0.5">{link.description}</p>
</div>
</a>
</li>
))}
</ul>
</div>
))}
</div>
<!-- XML Sitemap Note -->
<div class="mt-16 text-center">
<div class="inline-flex items-center gap-3 bg-secondary-900/50 border border-secondary-800 rounded-xl px-6 py-4">
<svg class="w-6 h-6 text-primary-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
</svg>
<span class="text-secondary-300">
Looking for the XML sitemap? Visit
<a href="/sitemap.xml" class="text-primary-400 hover:text-primary-300 underline underline-offset-2">
/sitemap.xml
</a>
</span>
</div>
</div>
</div>
</section>
</BaseLayout>
+83
View File
@@ -0,0 +1,83 @@
import type { APIRoute } from 'astro';
import { getCollection } from 'astro:content';
const site = 'https://workroot.in';
interface SitemapEntry {
url: string;
lastmod?: string;
changefreq: 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never';
priority: number;
}
export const GET: APIRoute = async () => {
// Fetch blog posts (exclude drafts)
const posts = await getCollection('blog', ({ data }) => !data.draft);
// Fetch portfolio items if collection exists
let portfolioItems: any[] = [];
try {
portfolioItems = await getCollection('portfolio');
} catch (e) {
// Portfolio collection doesn't exist yet
}
const staticPages: SitemapEntry[] = [
{ url: '/', changefreq: 'weekly', priority: 1.0 },
{ url: '/services/', changefreq: 'monthly', priority: 0.9 },
{ url: '/portfolio/', changefreq: 'weekly', priority: 0.8 },
{ url: '/about/', changefreq: 'monthly', priority: 0.8 },
{ url: '/blog/', changefreq: 'weekly', priority: 0.8 },
{ url: '/contact/', changefreq: 'monthly', priority: 0.7 },
{ url: '/privacy/', changefreq: 'yearly', priority: 0.3 },
{ url: '/terms/', changefreq: 'yearly', priority: 0.3 },
{ url: '/sitemap/', changefreq: 'monthly', priority: 0.3 },
];
const blogPages: SitemapEntry[] = posts.map((post) => ({
url: `/blog/${post.slug}/`,
lastmod: post.data.updatedDate
? post.data.updatedDate.toISOString().split('T')[0]
: post.data.pubDate.toISOString().split('T')[0],
changefreq: 'monthly' as const,
priority: 0.7,
}));
const portfolioPages: SitemapEntry[] = portfolioItems.map((item) => ({
url: `/portfolio/${item.slug}/`,
lastmod: item.data.updatedDate
? item.data.updatedDate.toISOString().split('T')[0]
: item.data.date?.toISOString().split('T')[0],
changefreq: 'monthly' as const,
priority: 0.7,
}));
const allPages = [...staticPages, ...blogPages, ...portfolioPages];
const sitemap = `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:news="http://www.google.com/schemas/sitemap-news/0.9"
xmlns:xhtml="http://www.w3.org/1999/xhtml"
xmlns:image="http://www.google.com/schemas/sitemap-image/1.1"
xmlns:video="http://www.google.com/schemas/sitemap-video/1.1">
${allPages
.map(
(page) => ` <url>
<loc>${site}${page.url}</loc>${page.lastmod ? `
<lastmod>${page.lastmod}</lastmod>` : `
<lastmod>${new Date().toISOString().split('T')[0]}</lastmod>`}
<changefreq>${page.changefreq}</changefreq>
<priority>${page.priority}</priority>
</url>`
)
.join('\n')}
</urlset>`;
return new Response(sitemap, {
headers: {
'Content-Type': 'application/xml; charset=utf-8',
'Cache-Control': 'public, max-age=3600', // Cache for 1 hour
'X-Robots-Tag': 'noindex', // Don't index the sitemap itself
},
});
};
+310
View File
@@ -0,0 +1,310 @@
---
// Terms of Service Page for WorkRoot IT Solutions
// Features: Legal content with proper formatting for readability
import BaseLayout from '../layouts/BaseLayout.astro';
const lastUpdated = 'March 20, 2026';
---
<BaseLayout
title="Terms of Service"
description="WorkRoot IT Solutions Terms of Service - Read our terms and conditions for using our website and services."
noIndex={true}
>
<!-- Hero Section -->
<section class="relative bg-gradient-to-br from-secondary-900 via-secondary-800 to-secondary-900 py-16 lg:py-20">
<div class="absolute inset-0 overflow-hidden">
<div class="absolute top-0 left-1/4 w-96 h-96 bg-primary-500/10 rounded-full blur-3xl"></div>
<div class="absolute bottom-0 right-1/4 w-96 h-96 bg-accent-500/10 rounded-full blur-3xl"></div>
</div>
<div class="container mx-auto px-4 sm:px-6 lg:px-8 relative z-10">
<div class="max-w-3xl mx-auto text-center">
<h1 class="text-4xl md:text-5xl font-bold text-white mb-4">
Terms of <span class="text-transparent bg-clip-text bg-gradient-to-r from-primary-400 to-accent-400">Service</span>
</h1>
<p class="text-lg text-secondary-300">
Last updated: {lastUpdated}
</p>
</div>
</div>
</section>
<!-- Content Section -->
<section class="py-16 lg:py-24 bg-secondary-950">
<div class="container mx-auto px-4 sm:px-6 lg:px-8">
<div class="max-w-4xl mx-auto">
<div class="prose prose-lg prose-invert prose-headings:text-white prose-p:text-secondary-300 prose-li:text-secondary-300 prose-strong:text-white max-w-none">
<!-- Introduction -->
<div class="bg-secondary-900/50 border border-secondary-800 rounded-2xl p-8 mb-8">
<p class="text-secondary-300 leading-relaxed">
Welcome to WorkRoot IT Solutions. These Terms of Service ("Terms") govern your access to and use of our website, products, and services. By accessing or using our services, you agree to be bound by these Terms. If you do not agree to these Terms, please do not use our services.
</p>
</div>
<!-- Section 1 -->
<div class="mb-12">
<h2 class="text-2xl font-bold text-white mb-4 flex items-center gap-3">
<span class="flex items-center justify-center w-10 h-10 rounded-full bg-primary-500/20 text-primary-400 text-lg font-bold">1</span>
Acceptance of Terms
</h2>
<div class="pl-13">
<p class="text-secondary-300 mb-4">By accessing or using our services, you represent that:</p>
<ul class="list-disc pl-6 space-y-2 text-secondary-300">
<li>You are at least 18 years of age or the age of majority in your jurisdiction</li>
<li>You have the legal capacity to enter into a binding agreement</li>
<li>If accepting on behalf of an organization, you have authority to bind that organization</li>
<li>You will comply with all applicable laws and regulations</li>
</ul>
</div>
</div>
<!-- Section 2 -->
<div class="mb-12">
<h2 class="text-2xl font-bold text-white mb-4 flex items-center gap-3">
<span class="flex items-center justify-center w-10 h-10 rounded-full bg-primary-500/20 text-primary-400 text-lg font-bold">2</span>
Description of Services
</h2>
<div class="pl-13">
<p class="text-secondary-300 mb-4">WorkRoot IT Solutions provides a range of IT services, including but not limited to:</p>
<ul class="list-disc pl-6 space-y-2 text-secondary-300">
<li>Custom web and mobile application development</li>
<li>Cloud computing and infrastructure services</li>
<li>AI and machine learning solutions</li>
<li>IT consulting and digital transformation</li>
<li>DevOps and continuous integration/deployment</li>
<li>Maintenance and support services</li>
</ul>
<p class="text-secondary-300 mt-4">Specific services are subject to separate agreements, statements of work, or service level agreements.</p>
</div>
</div>
<!-- Section 3 -->
<div class="mb-12">
<h2 class="text-2xl font-bold text-white mb-4 flex items-center gap-3">
<span class="flex items-center justify-center w-10 h-10 rounded-full bg-primary-500/20 text-primary-400 text-lg font-bold">3</span>
User Accounts
</h2>
<div class="pl-13">
<p class="text-secondary-300 mb-4">If you create an account with us, you agree to:</p>
<ul class="list-disc pl-6 space-y-2 text-secondary-300">
<li>Provide accurate, current, and complete information</li>
<li>Maintain and promptly update your account information</li>
<li>Keep your password secure and confidential</li>
<li>Accept responsibility for all activities under your account</li>
<li>Notify us immediately of any unauthorized access</li>
</ul>
<p class="text-secondary-300 mt-4">We reserve the right to suspend or terminate accounts that violate these Terms.</p>
</div>
</div>
<!-- Section 4 -->
<div class="mb-12">
<h2 class="text-2xl font-bold text-white mb-4 flex items-center gap-3">
<span class="flex items-center justify-center w-10 h-10 rounded-full bg-primary-500/20 text-primary-400 text-lg font-bold">4</span>
Intellectual Property Rights
</h2>
<div class="pl-13">
<h3 class="text-xl font-semibold text-white mt-6 mb-3">Our Content</h3>
<p class="text-secondary-300">All content on our website, including text, graphics, logos, images, software, and other materials, is the property of WorkRoot IT Solutions or its licensors and is protected by intellectual property laws. You may not copy, modify, distribute, or create derivative works without our prior written consent.</p>
<h3 class="text-xl font-semibold text-white mt-6 mb-3">Your Content</h3>
<p class="text-secondary-300">You retain ownership of content you provide to us. By submitting content, you grant us a non-exclusive, worldwide, royalty-free license to use, reproduce, and display such content in connection with providing our services.</p>
<h3 class="text-xl font-semibold text-white mt-6 mb-3">Deliverables</h3>
<p class="text-secondary-300">Ownership of custom deliverables (code, designs, documentation) is governed by the specific project agreement between you and WorkRoot IT Solutions.</p>
</div>
</div>
<!-- Section 5 -->
<div class="mb-12">
<h2 class="text-2xl font-bold text-white mb-4 flex items-center gap-3">
<span class="flex items-center justify-center w-10 h-10 rounded-full bg-primary-500/20 text-primary-400 text-lg font-bold">5</span>
Prohibited Conduct
</h2>
<div class="pl-13">
<p class="text-secondary-300 mb-4">You agree not to:</p>
<ul class="list-disc pl-6 space-y-2 text-secondary-300">
<li>Use our services for any illegal or unauthorized purpose</li>
<li>Violate any laws, regulations, or third-party rights</li>
<li>Transmit viruses, malware, or harmful code</li>
<li>Attempt to gain unauthorized access to our systems</li>
<li>Interfere with or disrupt our services or servers</li>
<li>Scrape, harvest, or collect data without permission</li>
<li>Impersonate any person or entity</li>
<li>Use our services to send spam or unsolicited messages</li>
<li>Reverse engineer or decompile our software</li>
</ul>
</div>
</div>
<!-- Section 6 -->
<div class="mb-12">
<h2 class="text-2xl font-bold text-white mb-4 flex items-center gap-3">
<span class="flex items-center justify-center w-10 h-10 rounded-full bg-primary-500/20 text-primary-400 text-lg font-bold">6</span>
Payment Terms
</h2>
<div class="pl-13">
<p class="text-secondary-300 mb-4">For paid services:</p>
<ul class="list-disc pl-6 space-y-2 text-secondary-300">
<li>Fees are specified in your service agreement or statement of work</li>
<li>Payment is due according to the agreed schedule</li>
<li>All fees are non-refundable unless otherwise stated</li>
<li>We reserve the right to suspend services for non-payment</li>
<li>You are responsible for all applicable taxes</li>
<li>Prices may be subject to change with reasonable notice</li>
</ul>
</div>
</div>
<!-- Section 7 -->
<div class="mb-12">
<h2 class="text-2xl font-bold text-white mb-4 flex items-center gap-3">
<span class="flex items-center justify-center w-10 h-10 rounded-full bg-primary-500/20 text-primary-400 text-lg font-bold">7</span>
Confidentiality
</h2>
<div class="pl-13">
<p class="text-secondary-300">Both parties agree to maintain the confidentiality of any proprietary or confidential information disclosed during the course of our engagement. This obligation survives the termination of these Terms. Confidential information does not include information that is publicly available, independently developed, or rightfully received from third parties.</p>
</div>
</div>
<!-- Section 8 -->
<div class="mb-12">
<h2 class="text-2xl font-bold text-white mb-4 flex items-center gap-3">
<span class="flex items-center justify-center w-10 h-10 rounded-full bg-primary-500/20 text-primary-400 text-lg font-bold">8</span>
Disclaimer of Warranties
</h2>
<div class="pl-13">
<div class="bg-accent-500/10 border border-accent-500/20 rounded-xl p-6 text-secondary-300">
<p class="mb-4">OUR SERVICES ARE PROVIDED "AS IS" AND "AS AVAILABLE" WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO:</p>
<ul class="list-disc pl-6 space-y-2">
<li>MERCHANTABILITY</li>
<li>FITNESS FOR A PARTICULAR PURPOSE</li>
<li>NON-INFRINGEMENT</li>
<li>ACCURACY OR COMPLETENESS</li>
</ul>
<p class="mt-4">We do not warrant that our services will be uninterrupted, error-free, or secure.</p>
</div>
</div>
</div>
<!-- Section 9 -->
<div class="mb-12">
<h2 class="text-2xl font-bold text-white mb-4 flex items-center gap-3">
<span class="flex items-center justify-center w-10 h-10 rounded-full bg-primary-500/20 text-primary-400 text-lg font-bold">9</span>
Limitation of Liability
</h2>
<div class="pl-13">
<div class="bg-accent-500/10 border border-accent-500/20 rounded-xl p-6 text-secondary-300">
<p class="mb-4">TO THE MAXIMUM EXTENT PERMITTED BY LAW:</p>
<ul class="list-disc pl-6 space-y-2">
<li>WorkRoot IT Solutions shall not be liable for any indirect, incidental, special, consequential, or punitive damages</li>
<li>Our total liability shall not exceed the amounts paid by you in the twelve (12) months preceding the claim</li>
<li>We are not liable for damages arising from your use of third-party services or content</li>
</ul>
</div>
</div>
</div>
<!-- Section 10 -->
<div class="mb-12">
<h2 class="text-2xl font-bold text-white mb-4 flex items-center gap-3">
<span class="flex items-center justify-center w-10 h-10 rounded-full bg-primary-500/20 text-primary-400 text-lg font-bold">10</span>
Indemnification
</h2>
<div class="pl-13">
<p class="text-secondary-300">You agree to indemnify, defend, and hold harmless WorkRoot IT Solutions, its officers, directors, employees, and agents from any claims, damages, losses, or expenses (including reasonable attorney's fees) arising from:</p>
<ul class="list-disc pl-6 space-y-2 text-secondary-300 mt-4">
<li>Your use of our services</li>
<li>Your violation of these Terms</li>
<li>Your violation of any third-party rights</li>
<li>Your content or materials provided to us</li>
</ul>
</div>
</div>
<!-- Section 11 -->
<div class="mb-12">
<h2 class="text-2xl font-bold text-white mb-4 flex items-center gap-3">
<span class="flex items-center justify-center w-10 h-10 rounded-full bg-primary-500/20 text-primary-400 text-lg font-bold">11</span>
Termination
</h2>
<div class="pl-13">
<p class="text-secondary-300 mb-4">Either party may terminate these Terms:</p>
<ul class="list-disc pl-6 space-y-2 text-secondary-300">
<li>For convenience with thirty (30) days written notice</li>
<li>Immediately upon material breach by the other party</li>
<li>Immediately if required by law</li>
</ul>
<p class="text-secondary-300 mt-4">Upon termination, your right to use our services ceases. Sections relating to intellectual property, confidentiality, warranties, liability, and indemnification survive termination.</p>
</div>
</div>
<!-- Section 12 -->
<div class="mb-12">
<h2 class="text-2xl font-bold text-white mb-4 flex items-center gap-3">
<span class="flex items-center justify-center w-10 h-10 rounded-full bg-primary-500/20 text-primary-400 text-lg font-bold">12</span>
Dispute Resolution
</h2>
<div class="pl-13">
<p class="text-secondary-300 mb-4">Any disputes arising from these Terms shall be resolved as follows:</p>
<ul class="list-disc pl-6 space-y-2 text-secondary-300">
<li><strong class="text-white">Informal Resolution:</strong> The parties will first attempt to resolve disputes through good-faith negotiation</li>
<li><strong class="text-white">Mediation:</strong> If negotiation fails, disputes may be submitted to mediation</li>
<li><strong class="text-white">Arbitration:</strong> Binding arbitration under the rules of the American Arbitration Association</li>
</ul>
<p class="text-secondary-300 mt-4">These Terms shall be governed by the laws of the State of California, without regard to conflict of law principles.</p>
</div>
</div>
<!-- Section 13 -->
<div class="mb-12">
<h2 class="text-2xl font-bold text-white mb-4 flex items-center gap-3">
<span class="flex items-center justify-center w-10 h-10 rounded-full bg-primary-500/20 text-primary-400 text-lg font-bold">13</span>
Changes to Terms
</h2>
<div class="pl-13">
<p class="text-secondary-300">We reserve the right to modify these Terms at any time. We will provide notice of material changes by posting the updated Terms on our website and updating the "Last updated" date. Your continued use of our services after such changes constitutes acceptance of the modified Terms.</p>
</div>
</div>
<!-- Section 14 -->
<div class="mb-12">
<h2 class="text-2xl font-bold text-white mb-4 flex items-center gap-3">
<span class="flex items-center justify-center w-10 h-10 rounded-full bg-primary-500/20 text-primary-400 text-lg font-bold">14</span>
General Provisions
</h2>
<div class="pl-13">
<ul class="list-disc pl-6 space-y-2 text-secondary-300">
<li><strong class="text-white">Entire Agreement:</strong> These Terms constitute the entire agreement between you and WorkRoot IT Solutions</li>
<li><strong class="text-white">Severability:</strong> If any provision is found invalid, the remaining provisions remain in effect</li>
<li><strong class="text-white">Waiver:</strong> Failure to enforce any right does not constitute a waiver</li>
<li><strong class="text-white">Assignment:</strong> You may not assign these Terms without our written consent</li>
<li><strong class="text-white">Force Majeure:</strong> Neither party is liable for delays caused by circumstances beyond reasonable control</li>
</ul>
</div>
</div>
<!-- Section 15 -->
<div class="mb-12">
<h2 class="text-2xl font-bold text-white mb-4 flex items-center gap-3">
<span class="flex items-center justify-center w-10 h-10 rounded-full bg-primary-500/20 text-primary-400 text-lg font-bold">15</span>
Contact Information
</h2>
<div class="pl-13">
<p class="text-secondary-300 mb-4">For questions about these Terms, please contact us:</p>
<div class="bg-secondary-900/50 border border-secondary-800 rounded-xl p-6">
<p class="text-secondary-300"><strong class="text-white">WorkRoot IT Solutions</strong></p>
<p class="text-secondary-300">Email: legal@workroot.in</p>
<p class="text-secondary-300">Phone: +1 (555) 123-4567</p>
<p class="text-secondary-300">Address: 123 Tech Avenue, Suite 500, San Francisco, CA 94102</p>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
</BaseLayout>