Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
01eb68d3e1 | ||
|
|
6364988f0f | ||
|
|
2f78c8d6f7 | ||
|
|
fc9f384b47 | ||
|
|
5199d8883d |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 1.7 MiB |
|
After Width: | Height: | Size: 2.0 MiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
@@ -1,10 +1,24 @@
|
|||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="fr">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>amado-redesign</title>
|
<title>AssurezMoi — Comparateur de mutuelles santé</title>
|
||||||
|
<meta name="description" content="Comparez les meilleures mutuelles santé 2026. Classement basé sur les garanties, tarifs et avis clients de 186 mutuelles analysées. Gratuit, sans engagement." />
|
||||||
|
|
||||||
|
<!-- Favicons -->
|
||||||
|
<link rel="icon" href="/favicon.ico" sizes="32x32" />
|
||||||
|
<link rel="icon" type="image/png" sizes="64x64" href="/img/ico.png" />
|
||||||
|
<link rel="icon" type="image/webp" href="/img/ico.webp" />
|
||||||
|
<link rel="apple-touch-icon" sizes="180x180" href="/img/ico-180.png" />
|
||||||
|
|
||||||
|
<!-- Preconnect pour le service favicon Google (logos mutuelles) -->
|
||||||
|
<link rel="preconnect" href="https://www.google.com" crossorigin />
|
||||||
|
<link rel="dns-prefetch" href="//www.google.com" />
|
||||||
|
|
||||||
|
<!-- Preload des assets critiques above-the-fold -->
|
||||||
|
<link rel="preload" href="/img/ico.webp" as="image" type="image/webp" />
|
||||||
|
<link rel="preload" href="/img/hero-bg.webp" as="image" type="image/webp" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
@@ -0,0 +1,85 @@
|
|||||||
|
# ─── Désactiver le listing des répertoires ──────────────────────────────────
|
||||||
|
Options -Indexes
|
||||||
|
|
||||||
|
# ─── Bloquer les fichiers sensibles ─────────────────────────────────────────
|
||||||
|
<FilesMatch "\.(zip|tar|gz|rar|7z|sql|log|env|bak|old|orig|save|swp|tmp|sh|py|rb|pl)$">
|
||||||
|
Order allow,deny
|
||||||
|
Deny from all
|
||||||
|
</FilesMatch>
|
||||||
|
|
||||||
|
# ─── Bloquer l'accès direct aux fichiers cachés ──────────────────────────────
|
||||||
|
<FilesMatch "^\.">
|
||||||
|
Order allow,deny
|
||||||
|
Deny from all
|
||||||
|
</FilesMatch>
|
||||||
|
|
||||||
|
# ─── Cache long terme pour assets statiques (hachés par Vite) ───────────────
|
||||||
|
<IfModule mod_expires.c>
|
||||||
|
ExpiresActive On
|
||||||
|
|
||||||
|
# HTML → toujours revalider
|
||||||
|
ExpiresByType text/html "access plus 0 seconds"
|
||||||
|
|
||||||
|
# JS / CSS (noms hachés par Vite → 1 an)
|
||||||
|
ExpiresByType application/javascript "access plus 1 year"
|
||||||
|
ExpiresByType text/javascript "access plus 1 year"
|
||||||
|
ExpiresByType text/css "access plus 1 year"
|
||||||
|
|
||||||
|
# Images
|
||||||
|
ExpiresByType image/webp "access plus 1 year"
|
||||||
|
ExpiresByType image/png "access plus 1 year"
|
||||||
|
ExpiresByType image/jpeg "access plus 1 year"
|
||||||
|
ExpiresByType image/svg+xml "access plus 1 year"
|
||||||
|
ExpiresByType image/x-icon "access plus 1 year"
|
||||||
|
ExpiresByType image/vnd.microsoft.icon "access plus 1 year"
|
||||||
|
|
||||||
|
# Vidéo
|
||||||
|
ExpiresByType video/mp4 "access plus 1 year"
|
||||||
|
ExpiresByType video/webm "access plus 1 year"
|
||||||
|
|
||||||
|
# Polices
|
||||||
|
ExpiresByType font/woff2 "access plus 1 year"
|
||||||
|
ExpiresByType font/woff "access plus 1 year"
|
||||||
|
|
||||||
|
# JSON (données dynamiques → courte durée)
|
||||||
|
ExpiresByType application/json "access plus 1 hour"
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
<IfModule mod_headers.c>
|
||||||
|
# Assets immutables (Vite génère des noms hachés)
|
||||||
|
<FilesMatch "\.(js|css|webp|png|jpg|jpeg|svg|ico|woff2|woff|mp4|webm)$">
|
||||||
|
Header set Cache-Control "public, max-age=31536000, immutable"
|
||||||
|
</FilesMatch>
|
||||||
|
|
||||||
|
# HTML → pas de cache
|
||||||
|
<FilesMatch "\.html$">
|
||||||
|
Header set Cache-Control "no-cache, no-store, must-revalidate"
|
||||||
|
Header set Pragma "no-cache"
|
||||||
|
</FilesMatch>
|
||||||
|
|
||||||
|
# JSON → courte durée
|
||||||
|
<FilesMatch "\.json$">
|
||||||
|
Header set Cache-Control "public, max-age=3600, must-revalidate"
|
||||||
|
</FilesMatch>
|
||||||
|
|
||||||
|
# Headers de sécurité
|
||||||
|
Header always set X-Content-Type-Options "nosniff"
|
||||||
|
Header always set X-Frame-Options "SAMEORIGIN"
|
||||||
|
Header always set Referrer-Policy "strict-origin-when-cross-origin"
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
# ─── Compression gzip ────────────────────────────────────────────────────────
|
||||||
|
<IfModule mod_deflate.c>
|
||||||
|
AddOutputFilterByType DEFLATE text/html text/css application/javascript application/json
|
||||||
|
AddOutputFilterByType DEFLATE image/svg+xml font/woff2 font/woff
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
# ─── SPA routing (React / Vite) ──────────────────────────────────────────────
|
||||||
|
<IfModule mod_rewrite.c>
|
||||||
|
RewriteEngine On
|
||||||
|
RewriteBase /
|
||||||
|
|
||||||
|
RewriteCond %{REQUEST_FILENAME} !-f
|
||||||
|
RewriteCond %{REQUEST_FILENAME} !-d
|
||||||
|
RewriteRule ^ index.html [L]
|
||||||
|
</IfModule>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"heroVideo": "/video/home.mp4",
|
||||||
|
"heroBg": "/img/hero-bg.webp",
|
||||||
|
"heroBgMobile": "/img/hero-bg-mobile.webp"
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 2.0 MiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
@@ -1,19 +1,31 @@
|
|||||||
|
import { useState, useEffect } from 'react'
|
||||||
import Navbar from './components/Navbar'
|
import Navbar from './components/Navbar'
|
||||||
import Hero from './components/Hero'
|
import Hero from './components/Hero'
|
||||||
import ComparisonSection from './components/ComparisonSection'
|
import ComparisonSection from './components/ComparisonSection'
|
||||||
import Testimonials from './components/Testimonials'
|
|
||||||
import GuideSection from './components/GuideSection'
|
import GuideSection from './components/GuideSection'
|
||||||
import Footer from './components/Footer'
|
import Footer from './components/Footer'
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
|
const [bgSrc, setBgSrc] = useState(null)
|
||||||
|
const [bgMobileSrc, setBgMobileSrc] = useState(null)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetch('/config.json')
|
||||||
|
.then(r => r.json())
|
||||||
|
.then(data => {
|
||||||
|
if (data.heroBg) setBgSrc(data.heroBg)
|
||||||
|
if (data.heroBgMobile) setBgMobileSrc(data.heroBgMobile)
|
||||||
|
})
|
||||||
|
.catch(() => {})
|
||||||
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-white">
|
<div className="min-h-screen bg-[#19392e]">
|
||||||
<Navbar />
|
<Navbar />
|
||||||
<main>
|
<main>
|
||||||
<Hero />
|
<Hero bgSrc={bgSrc} bgMobileSrc={bgMobileSrc} />
|
||||||
<ComparisonSection />
|
<ComparisonSection />
|
||||||
<Testimonials />
|
<GuideSection bgSrc={bgSrc} bgMobileSrc={bgMobileSrc} />
|
||||||
<GuideSection />
|
|
||||||
</main>
|
</main>
|
||||||
<Footer />
|
<Footer />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
import { useEffect } from 'react'
|
||||||
|
import { motion, useAnimation } from 'framer-motion'
|
||||||
|
|
||||||
|
const LETTERS_1 = 'Assurez'.split('')
|
||||||
|
const LETTERS_2 = 'Moi'.split('')
|
||||||
|
|
||||||
|
export default function AnimatedBrandName({ className = '', lightText = false }) {
|
||||||
|
const controls = useAnimation()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const play = () =>
|
||||||
|
controls.start(i => ({
|
||||||
|
y: [0, -9, 0],
|
||||||
|
transition: {
|
||||||
|
delay: i * 0.055,
|
||||||
|
duration: 0.38,
|
||||||
|
ease: 'easeInOut',
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
|
||||||
|
play()
|
||||||
|
const interval = setInterval(play, 5000)
|
||||||
|
return () => clearInterval(interval)
|
||||||
|
}, [controls])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span className={`font-extrabold text-xl tracking-tight inline-flex ${className}`}>
|
||||||
|
{LETTERS_1.map((letter, i) => (
|
||||||
|
<motion.span
|
||||||
|
key={i}
|
||||||
|
custom={i}
|
||||||
|
animate={controls}
|
||||||
|
className={`inline-block ${lightText ? 'text-[#fffef6]' : 'text-slate-900'}`}
|
||||||
|
>
|
||||||
|
{letter}
|
||||||
|
</motion.span>
|
||||||
|
))}
|
||||||
|
{LETTERS_2.map((letter, i) => (
|
||||||
|
<motion.span
|
||||||
|
key={`moi-${i}`}
|
||||||
|
custom={LETTERS_1.length + i}
|
||||||
|
animate={controls}
|
||||||
|
className="inline-block text-[#9CCC8A]"
|
||||||
|
>
|
||||||
|
{letter}
|
||||||
|
</motion.span>
|
||||||
|
))}
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -12,13 +12,13 @@ function TopCard({ mutuelle, index }) {
|
|||||||
<div
|
<div
|
||||||
className={`relative flex flex-col rounded-3xl border-2 p-6 transition-all hover:shadow-xl hover:-translate-y-1 cursor-pointer ${
|
className={`relative flex flex-col rounded-3xl border-2 p-6 transition-all hover:shadow-xl hover:-translate-y-1 cursor-pointer ${
|
||||||
isFirst
|
isFirst
|
||||||
? 'border-indigo-300 bg-gradient-to-b from-indigo-50 to-white shadow-lg shadow-indigo-100'
|
? 'border-[#9CCC8A]/50 bg-gradient-to-b from-[#9CCC8A]/5 to-white shadow-lg shadow-[#9CCC8A]/20'
|
||||||
: 'border-slate-100 bg-white hover:border-slate-200 shadow-sm'
|
: 'border-slate-100 bg-white hover:border-slate-200 shadow-sm'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{/* Badge meilleur choix */}
|
{/* Badge meilleur choix */}
|
||||||
{mutuelle.meilleurChoix && (
|
{mutuelle.meilleurChoix && (
|
||||||
<div className="absolute -top-3.5 left-1/2 -translate-x-1/2 bg-gradient-to-r from-indigo-600 to-indigo-700 text-white text-[11px] font-extrabold px-4 py-1.5 rounded-full shadow-md whitespace-nowrap">
|
<div className="absolute -top-3.5 left-1/2 -translate-x-1/2 bg-[#9CCC8A] text-white text-[11px] font-extrabold px-4 py-1.5 rounded-full shadow-md whitespace-nowrap">
|
||||||
⭐ Meilleur Choix 2026
|
⭐ Meilleur Choix 2026
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -98,23 +98,29 @@ export default function ComparisonSection() {
|
|||||||
const { mutuelles, loading, error } = useMutuelles()
|
const { mutuelles, loading, error } = useMutuelles()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section id="classement" className="pt-10 pb-20 bg-white">
|
<section id="classement" className="relative isolate pt-10 pb-20 bg-white">
|
||||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
|
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="text-center mb-14">
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 24 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
transition={{ duration: 0.5 }}
|
||||||
|
className="text-center mb-8 sm:mb-14"
|
||||||
|
>
|
||||||
<div className="inline-flex items-center gap-2 bg-amber-50 border border-amber-200 text-amber-700 text-xs font-bold px-3 py-1.5 rounded-full mb-5">
|
<div className="inline-flex items-center gap-2 bg-amber-50 border border-amber-200 text-amber-700 text-xs font-bold px-3 py-1.5 rounded-full mb-5">
|
||||||
<FiAward size={13} />
|
<FiAward size={13} />
|
||||||
Classement officiel 2026
|
Classement officiel 2026
|
||||||
</div>
|
</div>
|
||||||
<h2 className="text-4xl font-extrabold text-slate-900 tracking-tight mb-4">
|
<h2 className="text-2xl sm:text-4xl font-extrabold text-slate-900 tracking-tight mb-4">
|
||||||
Les meilleures mutuelles santé
|
Les meilleures mutuelles santé
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-slate-500 max-w-xl mx-auto leading-relaxed">
|
<p className="text-slate-500 max-w-xl mx-auto leading-relaxed">
|
||||||
Classement mis à jour chaque mois — basé sur les garanties, les tarifs
|
Classement mis à jour chaque mois — basé sur les garanties, les tarifs
|
||||||
et les avis clients de plus de 186 mutuelles analysées.
|
et les avis clients de plus de 186 mutuelles analysées.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</motion.div>
|
||||||
|
|
||||||
{/* Erreur */}
|
{/* Erreur */}
|
||||||
{error && (
|
{error && (
|
||||||
@@ -143,12 +149,10 @@ export default function ComparisonSection() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Séparateur */}
|
{/* Séparateur */}
|
||||||
<div className="flex items-center gap-4 mb-8">
|
<div className="flex items-center justify-center mb-8">
|
||||||
<div className="flex-1 h-px bg-slate-100" />
|
|
||||||
<span className="text-xs font-bold text-slate-400 uppercase tracking-widest">
|
<span className="text-xs font-bold text-slate-400 uppercase tracking-widest">
|
||||||
Classement complet
|
Classement complet
|
||||||
</span>
|
</span>
|
||||||
<div className="flex-1 h-px bg-slate-100" />
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Liste complète */}
|
{/* Liste complète */}
|
||||||
|
|||||||
@@ -1,12 +1,6 @@
|
|||||||
import { MdPets } from 'react-icons/md'
|
import { motion } from 'framer-motion'
|
||||||
import {
|
import AnimatedBrandName from './AnimatedBrandName'
|
||||||
FiFacebook,
|
import { FiArrowUpRight } from 'react-icons/fi'
|
||||||
FiTwitter,
|
|
||||||
FiInstagram,
|
|
||||||
FiLinkedin,
|
|
||||||
FiYoutube,
|
|
||||||
FiArrowUpRight,
|
|
||||||
} from 'react-icons/fi'
|
|
||||||
|
|
||||||
const colResources = ['FAQ', 'Guides', 'Lexique', 'Documents']
|
const colResources = ['FAQ', 'Guides', 'Lexique', 'Documents']
|
||||||
|
|
||||||
@@ -26,131 +20,130 @@ const colLegal = [
|
|||||||
"Conditions générales d'utilisation",
|
"Conditions générales d'utilisation",
|
||||||
]
|
]
|
||||||
|
|
||||||
const socials = [
|
|
||||||
{ Icon: FiFacebook, label: 'Facebook' },
|
|
||||||
{ Icon: FiTwitter, label: 'Twitter / X' },
|
|
||||||
{ Icon: FiInstagram, label: 'Instagram' },
|
|
||||||
{ Icon: FiLinkedin, label: 'LinkedIn' },
|
|
||||||
{ Icon: FiYoutube, label: 'YouTube' },
|
|
||||||
]
|
|
||||||
|
|
||||||
export default function Footer() {
|
export default function Footer() {
|
||||||
return (
|
return (
|
||||||
<footer className="bg-slate-900 text-slate-400 relative z-10">
|
<footer className="bg-[#19392e]">
|
||||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
<div className="relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
|
|
||||||
{/* Main grid */}
|
{/* Main grid */}
|
||||||
<div className="grid sm:grid-cols-2 lg:grid-cols-4 gap-10 py-16">
|
<div className="grid grid-cols-2 lg:grid-cols-4 gap-x-6 gap-y-8 py-10 lg:py-16">
|
||||||
|
|
||||||
{/* Brand */}
|
{/* Brand */}
|
||||||
<div className="sm:col-span-2 lg:col-span-1">
|
<motion.div
|
||||||
<div className="flex items-center gap-2.5 mb-5">
|
initial={{ opacity: 0, y: 24 }}
|
||||||
<div className="w-9 h-9 bg-indigo-500 rounded-xl flex items-center justify-center shadow-md">
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
<MdPets className="text-white text-lg" />
|
viewport={{ once: true }}
|
||||||
|
transition={{ duration: 0.45, delay: 0 }}
|
||||||
|
className="col-span-2 lg:col-span-1 flex flex-col items-center lg:items-start text-center lg:text-left"
|
||||||
|
>
|
||||||
|
<div className="flex items-center gap-2.5 mb-4">
|
||||||
|
<img
|
||||||
|
src="/img/ico.webp"
|
||||||
|
alt="AssurezMoi"
|
||||||
|
loading="lazy"
|
||||||
|
decoding="async"
|
||||||
|
className="w-9 h-9 rounded-xl object-contain"
|
||||||
|
/>
|
||||||
|
<AnimatedBrandName lightText />
|
||||||
</div>
|
</div>
|
||||||
<span className="font-extrabold text-xl text-white tracking-tight">
|
<address className="not-italic text-sm text-[#fffef6]/60 leading-relaxed mb-3">
|
||||||
Assurez<span className="text-indigo-400">Moi</span>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<address className="not-italic text-sm text-slate-500 leading-relaxed mb-4">
|
|
||||||
Votre comparateur d'assurances<br />
|
Votre comparateur d'assurances<br />
|
||||||
1 Rue john doe<br />
|
1 Rue john doe<br />
|
||||||
59100 Roubaix, France
|
59100 Roubaix, France
|
||||||
</address>
|
</address>
|
||||||
<a
|
<div className="flex flex-col gap-1 items-center lg:items-start">
|
||||||
href="mailto:contact@mongaston.com"
|
<a href="mailto:contact@assurezmoi.com" className="text-sm text-[#fffef6]/60 hover:text-[#9CCC8A] transition-colors">
|
||||||
className="text-sm text-slate-500 hover:text-indigo-400 transition-colors"
|
|
||||||
>
|
|
||||||
contact@assurezmoi.com
|
contact@assurezmoi.com
|
||||||
</a>
|
</a>
|
||||||
<div className="mt-2">
|
<a href="tel:+33180891030" className="text-sm text-[#fffef6]/60 hover:text-[#9CCC8A] transition-colors">
|
||||||
<a
|
|
||||||
href="tel:+33180891030"
|
|
||||||
className="text-sm text-slate-500 hover:text-indigo-400 transition-colors"
|
|
||||||
>
|
|
||||||
01 02 03 04 05
|
01 02 03 04 05
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</motion.div>
|
||||||
|
|
||||||
{/* Resources */}
|
{/* Ressources */}
|
||||||
<div>
|
<motion.div
|
||||||
<h4 className="text-white font-bold text-sm uppercase tracking-widest mb-5">
|
initial={{ opacity: 0, y: 24 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
transition={{ duration: 0.45, delay: 0.1 }}
|
||||||
|
className="flex flex-col items-center lg:items-start text-center lg:text-left"
|
||||||
|
>
|
||||||
|
<h4 className="text-[#fffef6] font-bold text-sm uppercase tracking-widest mb-4">
|
||||||
Ressources
|
Ressources
|
||||||
</h4>
|
</h4>
|
||||||
<ul className="space-y-3">
|
<ul className="space-y-2.5">
|
||||||
{colResources.map((r) => (
|
{colResources.map((r) => (
|
||||||
<li key={r}>
|
<li key={r}>
|
||||||
<a
|
<a href="#" className="text-sm text-[#fffef6]/60 hover:text-[#9CCC8A] transition-colors inline-flex items-center gap-1 group">
|
||||||
href="#"
|
|
||||||
className="text-sm text-slate-500 hover:text-white transition-colors flex items-center gap-1 group"
|
|
||||||
>
|
|
||||||
{r}
|
{r}
|
||||||
<FiArrowUpRight size={11} className="opacity-0 group-hover:opacity-100 transition-opacity" />
|
<FiArrowUpRight size={11} className="opacity-0 group-hover:opacity-100 transition-opacity" />
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</motion.div>
|
||||||
|
|
||||||
{/* Discover */}
|
{/* Nous découvrir */}
|
||||||
<div>
|
<motion.div
|
||||||
<h4 className="text-white font-bold text-sm uppercase tracking-widest mb-5">
|
initial={{ opacity: 0, y: 24 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
transition={{ duration: 0.45, delay: 0.2 }}
|
||||||
|
className="flex flex-col items-center lg:items-start text-center lg:text-left"
|
||||||
|
>
|
||||||
|
<h4 className="text-[#fffef6] font-bold text-sm uppercase tracking-widest mb-4">
|
||||||
Nous découvrir
|
Nous découvrir
|
||||||
</h4>
|
</h4>
|
||||||
<ul className="space-y-3">
|
<ul className="space-y-2.5">
|
||||||
{colDiscover.map((d) => (
|
{colDiscover.map((d) => (
|
||||||
<li key={d}>
|
<li key={d}>
|
||||||
<a
|
<a href="#" className="text-sm text-[#fffef6]/60 hover:text-[#9CCC8A] transition-colors inline-flex items-center gap-1 group">
|
||||||
href="#"
|
|
||||||
className="text-sm text-slate-500 hover:text-white transition-colors flex items-center gap-1 group"
|
|
||||||
>
|
|
||||||
{d}
|
{d}
|
||||||
<FiArrowUpRight size={11} className="opacity-0 group-hover:opacity-100 transition-opacity" />
|
<FiArrowUpRight size={11} className="opacity-0 group-hover:opacity-100 transition-opacity" />
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</motion.div>
|
||||||
|
|
||||||
{/* Legal */}
|
{/* Informations légales */}
|
||||||
<div>
|
<motion.div
|
||||||
<h4 className="text-white font-bold text-sm uppercase tracking-widest mb-5">
|
initial={{ opacity: 0, y: 24 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
transition={{ duration: 0.45, delay: 0.3 }}
|
||||||
|
className="col-span-2 lg:col-span-1 flex flex-col items-center lg:items-start text-center lg:text-left"
|
||||||
|
>
|
||||||
|
<h4 className="text-[#fffef6] font-bold text-sm uppercase tracking-widest mb-4">
|
||||||
Informations légales
|
Informations légales
|
||||||
</h4>
|
</h4>
|
||||||
<ul className="space-y-3">
|
<ul className="grid grid-cols-2 lg:block gap-x-6 gap-y-2.5 lg:space-y-2.5 w-full">
|
||||||
{colLegal.map((l) => (
|
{colLegal.map((l) => (
|
||||||
<li key={l}>
|
<li key={l} className="text-center lg:text-left">
|
||||||
<a href="#" className="text-sm text-slate-500 hover:text-white transition-colors">
|
<a href="#" className="text-sm text-[#fffef6]/60 hover:text-[#9CCC8A] transition-colors">
|
||||||
{l}
|
{l}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</motion.div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Bottom bar */}
|
{/* Bottom bar */}
|
||||||
<div className="border-t border-slate-800 py-6 flex flex-col sm:flex-row items-center justify-between gap-4">
|
<motion.div
|
||||||
<p className="text-xs text-slate-600 text-center sm:text-left">
|
initial={{ opacity: 0, y: 16 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
transition={{ duration: 0.4, delay: 0.1 }}
|
||||||
|
className="border-t border-white/10 py-5 flex items-center justify-center"
|
||||||
|
>
|
||||||
|
<p className="text-xs text-[#fffef6]/40 text-center">
|
||||||
© 2026 AssurezMoi — Tous droits réservés.
|
© 2026 AssurezMoi — Tous droits réservés.
|
||||||
<span className="mx-2 text-slate-700">·</span>
|
<span className="mx-2 text-[#9CCC8A]/50">·</span>
|
||||||
Comparateur de mutuelles santé & assurances
|
Comparateur de mutuelles santé & assurances
|
||||||
</p>
|
</p>
|
||||||
|
</motion.div>
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
{socials.map(({ Icon, label }) => (
|
|
||||||
<a
|
|
||||||
key={label}
|
|
||||||
href="#"
|
|
||||||
aria-label={label}
|
|
||||||
className="w-8 h-8 rounded-lg bg-slate-800 hover:bg-indigo-600 flex items-center justify-center transition-all hover:-translate-y-0.5"
|
|
||||||
>
|
|
||||||
<Icon size={14} className="text-slate-400 hover:text-white" />
|
|
||||||
</a>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -7,24 +7,24 @@ function FaqItem({ faq, index }) {
|
|||||||
const [open, setOpen] = useState(index === 0)
|
const [open, setOpen] = useState(index === 0)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="border border-slate-100 rounded-2xl overflow-hidden">
|
<div className="border border-white/10 rounded-2xl overflow-hidden bg-[#19392e]/80 backdrop-blur-sm">
|
||||||
<button
|
<button
|
||||||
onClick={() => setOpen((v) => !v)}
|
onClick={() => setOpen((v) => !v)}
|
||||||
className="w-full flex items-start gap-4 px-6 py-5 text-left hover:bg-slate-50 transition-colors"
|
className="w-full flex items-start gap-4 px-6 py-5 text-left hover:bg-white/5 transition-colors"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className="flex-shrink-0 w-7 h-7 rounded-full flex items-center justify-center text-xs font-extrabold mt-0.5 text-white"
|
className="flex-shrink-0 w-7 h-7 rounded-full flex items-center justify-center text-xs font-extrabold mt-0.5 text-white"
|
||||||
style={{ backgroundColor: open ? '#4F46E5' : '#CBD5E1' }}
|
style={{ backgroundColor: open ? '#9CCC8A' : 'rgba(255,254,246,0.2)' }}
|
||||||
>
|
>
|
||||||
{index + 1}
|
{index + 1}
|
||||||
</span>
|
</span>
|
||||||
<span className="flex-1 font-bold text-slate-900 leading-snug">{faq.question}</span>
|
<span className="flex-1 font-bold text-[#fffef6] leading-snug">{faq.question}</span>
|
||||||
<motion.div
|
<motion.div
|
||||||
animate={{ rotate: open ? 180 : 0 }}
|
animate={{ rotate: open ? 180 : 0 }}
|
||||||
transition={{ duration: 0.2 }}
|
transition={{ duration: 0.2 }}
|
||||||
className="flex-shrink-0 mt-0.5"
|
className="flex-shrink-0 mt-0.5"
|
||||||
>
|
>
|
||||||
<FiChevronDown className={`text-lg transition-colors ${open ? 'text-indigo-500' : 'text-slate-400'}`} />
|
<FiChevronDown className={`text-lg transition-colors ${open ? 'text-[#9CCC8A]' : 'text-[#fffef6]/40'}`} />
|
||||||
</motion.div>
|
</motion.div>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
@@ -36,9 +36,9 @@ function FaqItem({ faq, index }) {
|
|||||||
exit={{ height: 0, opacity: 0 }}
|
exit={{ height: 0, opacity: 0 }}
|
||||||
transition={{ duration: 0.25 }}
|
transition={{ duration: 0.25 }}
|
||||||
>
|
>
|
||||||
<div className="px-6 pb-6 space-y-3 border-t border-slate-100 pt-4">
|
<div className="px-6 pb-6 space-y-3 border-t border-white/10 pt-4">
|
||||||
{faq.content.map((para, i) => (
|
{faq.content.map((para, i) => (
|
||||||
<p key={i} className="text-sm text-slate-500 leading-relaxed">
|
<p key={i} className="text-sm text-[#fffef6]/60 leading-relaxed">
|
||||||
{para}
|
{para}
|
||||||
</p>
|
</p>
|
||||||
))}
|
))}
|
||||||
@@ -50,21 +50,58 @@ function FaqItem({ faq, index }) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function GuideSection() {
|
export default function GuideSection({ bgSrc, bgMobileSrc }) {
|
||||||
return (
|
return (
|
||||||
<section className="py-20 bg-white">
|
<section className="relative py-0" style={!bgSrc ? { backgroundColor: '#19392e' } : {}}>
|
||||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
{/* Fond mobile (portrait) */}
|
||||||
|
{(bgMobileSrc || bgSrc) && (
|
||||||
|
<div
|
||||||
|
className="md:hidden absolute inset-0 bg-cover bg-center"
|
||||||
|
style={{ backgroundImage: `url(${bgMobileSrc || bgSrc})` }}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{/* Fond desktop (paysage, parallax) */}
|
||||||
|
{bgSrc && (
|
||||||
|
<div
|
||||||
|
className="hidden md:block absolute inset-0 bg-cover bg-center bg-fixed"
|
||||||
|
style={{ backgroundImage: `url(${bgSrc})` }}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{/* Overlay */}
|
||||||
|
<div className="pointer-events-none absolute inset-0 bg-[#19392e]/70 backdrop-blur-[2px]" />
|
||||||
|
|
||||||
<div className="text-center mb-14">
|
{/* Wave ← ComparisonSection */}
|
||||||
<h2 className="text-4xl font-extrabold text-slate-900 tracking-tight mb-4">
|
<div className="absolute top-0 left-0 w-full overflow-hidden leading-[0] pointer-events-none">
|
||||||
Tout savoir sur la mutuelle santé
|
<svg className="block w-full h-20 fill-white" viewBox="0 0 1200 120" preserveAspectRatio="none">
|
||||||
</h2>
|
<path d="M0,0V46.29c47.79,22.2,103.59,32.17,158,28,70.36-5.37,136.33-33.31,206.8-37.5C438.64,32.43,512.34,53.67,583,72.05c69.27,18,138.3,24.88,209.4,13.08,36.15-6,69.85-17.84,104.45-29.34C989.49,25,1113-14.29,1200,52.47V0Z" />
|
||||||
<p className="text-slate-500 max-w-xl mx-auto">
|
</svg>
|
||||||
Nos guides répondent à toutes vos questions pour faire le bon choix.
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid lg:grid-cols-3 gap-12">
|
{/* Wave → Footer */}
|
||||||
|
<div className="absolute bottom-0 left-0 w-full overflow-hidden leading-[0] pointer-events-none">
|
||||||
|
<svg className="block w-full h-20" viewBox="0 0 1200 120" preserveAspectRatio="none" style={{ fill: '#19392e', transform: 'scaleY(-1)' }}>
|
||||||
|
<path d="M0,0V46.29c47.79,22.2,103.59,32.17,158,28,70.36-5.37,136.33-33.31,206.8-37.5C438.64,32.43,512.34,53.67,583,72.05c69.27,18,138.3,24.88,209.4,13.08,36.15-6,69.85-17.84,104.45-29.34C989.49,25,1113-14.29,1200,52.47V0Z" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 pt-24 md:pt-48 pb-24 md:pb-48">
|
||||||
|
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 24 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
transition={{ duration: 0.5 }}
|
||||||
|
className="text-center mb-14"
|
||||||
|
>
|
||||||
|
<h2 className="text-2xl sm:text-4xl font-extrabold text-[#fffef6] tracking-tight mb-4">
|
||||||
|
Tout savoir sur la mutuelle santé
|
||||||
|
</h2>
|
||||||
|
<p className="text-[#fffef6]/60 max-w-xl mx-auto">
|
||||||
|
Nos guides répondent à toutes vos questions pour faire le bon choix.
|
||||||
|
</p>
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
|
<div className="grid lg:grid-cols-3 gap-6 lg:gap-12">
|
||||||
|
|
||||||
{/* FAQ accordéon */}
|
{/* FAQ accordéon */}
|
||||||
<div className="lg:col-span-2 space-y-3">
|
<div className="lg:col-span-2 space-y-3">
|
||||||
@@ -86,43 +123,55 @@ export default function GuideSection() {
|
|||||||
<div className="sticky top-24 space-y-4">
|
<div className="sticky top-24 space-y-4">
|
||||||
|
|
||||||
{/* Guides card */}
|
{/* Guides card */}
|
||||||
<div className="bg-slate-50 rounded-2xl border border-slate-100 p-6">
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 24 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
transition={{ duration: 0.45, delay: 0.1 }}
|
||||||
|
className="bg-[#19392e]/80 backdrop-blur-sm rounded-2xl border border-white/10 p-6"
|
||||||
|
>
|
||||||
<div className="flex items-center gap-2 mb-5">
|
<div className="flex items-center gap-2 mb-5">
|
||||||
<div className="w-8 h-8 bg-indigo-100 rounded-xl flex items-center justify-center">
|
<div className="w-8 h-8 bg-[#9CCC8A]/20 rounded-xl flex items-center justify-center">
|
||||||
<FiBookOpen className="text-indigo-600 text-sm" />
|
<FiBookOpen className="text-[#9CCC8A] text-sm" />
|
||||||
</div>
|
</div>
|
||||||
<h3 className="font-bold text-slate-900">Tous nos guides</h3>
|
<h3 className="font-bold text-[#fffef6]">Tous nos guides</h3>
|
||||||
</div>
|
</div>
|
||||||
<ul className="space-y-1">
|
<ul className="space-y-1">
|
||||||
{guides.map((guide, i) => (
|
{guides.map((guide, i) => (
|
||||||
<li key={i}>
|
<li key={i}>
|
||||||
<a
|
<a
|
||||||
href="#"
|
href="#"
|
||||||
className="flex items-start gap-2 text-sm text-slate-600 hover:text-indigo-600 transition-colors py-2 group"
|
className="flex items-start gap-2 text-sm text-[#fffef6]/70 hover:text-[#9CCC8A] transition-colors py-2 group"
|
||||||
>
|
>
|
||||||
<FiChevronRight className="flex-shrink-0 mt-0.5 text-slate-300 group-hover:text-indigo-400 transition-colors" />
|
<FiChevronRight className="flex-shrink-0 mt-0.5 text-white/20 group-hover:text-[#9CCC8A] transition-colors" />
|
||||||
{guide}
|
{guide}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</motion.div>
|
||||||
|
|
||||||
{/* CTA card */}
|
{/* CTA card */}
|
||||||
<div className="bg-gradient-to-br from-indigo-600 to-indigo-700 rounded-2xl p-6 text-white">
|
<motion.div
|
||||||
<div className="font-extrabold text-lg mb-2">
|
initial={{ opacity: 0, y: 24 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
transition={{ duration: 0.45, delay: 0.2 }}
|
||||||
|
className="bg-[#19392e]/80 backdrop-blur-sm rounded-2xl border border-white/10 p-6"
|
||||||
|
>
|
||||||
|
<div className="font-extrabold text-lg mb-2 text-[#fffef6]">
|
||||||
Besoin d'un conseil personnalisé ?
|
Besoin d'un conseil personnalisé ?
|
||||||
</div>
|
</div>
|
||||||
<p className="text-indigo-200 text-sm mb-5 leading-relaxed">
|
<p className="text-[#fffef6]/60 text-sm mb-5 leading-relaxed">
|
||||||
Nos experts répondent à toutes vos questions gratuitement, sans engagement.
|
Nos experts répondent à toutes vos questions gratuitement, sans engagement.
|
||||||
</p>
|
</p>
|
||||||
<a
|
<a
|
||||||
href="tel:+33180891030"
|
href="tel:+33180891030"
|
||||||
className="flex items-center justify-center gap-2 bg-white text-indigo-700 font-bold text-sm py-3 rounded-xl hover:bg-indigo-50 transition-colors"
|
className="flex items-center justify-center gap-2 bg-[#9CCC8A] hover:bg-[#87BE73] text-black font-bold text-sm py-3 rounded-xl transition-colors"
|
||||||
>
|
>
|
||||||
📞 01 80 89 10 30
|
📞 01 80 89 10 30
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</motion.div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
|
import { useState, useEffect, useRef } from 'react'
|
||||||
import { motion } from 'framer-motion'
|
import { motion } from 'framer-motion'
|
||||||
import { FiArrowRight, FiShield, FiStar, FiUsers, FiCheckCircle } from 'react-icons/fi'
|
import {
|
||||||
|
FiArrowRight, FiShield, FiStar, FiUsers, FiCheckCircle,
|
||||||
|
FiPlay, FiPause, FiVolume2, FiVolumeX,
|
||||||
|
} from 'react-icons/fi'
|
||||||
|
|
||||||
const stats = [
|
const stats = [
|
||||||
{ value: '186', label: 'mutuelles analysées', icon: FiShield },
|
{ value: '186', label: 'mutuelles analysées', icon: FiShield },
|
||||||
@@ -7,78 +11,210 @@ const stats = [
|
|||||||
{ value: '250 000+', label: 'utilisateurs', icon: FiUsers },
|
{ value: '250 000+', label: 'utilisateurs', icon: FiUsers },
|
||||||
]
|
]
|
||||||
|
|
||||||
export default function Hero() {
|
function VideoPlayer({ src }) {
|
||||||
|
const videoRef = useRef(null)
|
||||||
|
const [playing, setPlaying] = useState(true)
|
||||||
|
const [muted, setMuted] = useState(true)
|
||||||
|
|
||||||
|
const togglePlay = () => {
|
||||||
|
if (!videoRef.current) return
|
||||||
|
if (playing) videoRef.current.pause()
|
||||||
|
else videoRef.current.play()
|
||||||
|
setPlaying(p => !p)
|
||||||
|
}
|
||||||
|
|
||||||
|
const toggleMute = () => {
|
||||||
|
if (!videoRef.current) return
|
||||||
|
videoRef.current.muted = !muted
|
||||||
|
setMuted(m => !m)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="relative overflow-hidden bg-gradient-to-br from-slate-50 via-indigo-50/40 to-white pt-14 pb-10">
|
<div className="relative rounded-2xl overflow-hidden shadow-2xl shadow-black/30 bg-slate-900 w-full h-full min-h-[220px] md:min-h-[320px]">
|
||||||
{/* Decorative blobs */}
|
{src ? (
|
||||||
|
<video
|
||||||
|
ref={videoRef}
|
||||||
|
src={src}
|
||||||
|
autoPlay
|
||||||
|
muted
|
||||||
|
loop
|
||||||
|
playsInline
|
||||||
|
preload="metadata"
|
||||||
|
onClick={togglePlay}
|
||||||
|
className="w-full h-full object-cover cursor-pointer"
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<div className="w-full h-full flex items-center justify-center bg-slate-800 animate-pulse">
|
||||||
|
<FiPlay className="text-slate-600 text-5xl" />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{src && !playing && (
|
||||||
|
<div className="pointer-events-none absolute inset-0 flex items-center justify-center">
|
||||||
|
<div className="w-16 h-16 rounded-full bg-black/50 flex items-center justify-center backdrop-blur-sm">
|
||||||
|
<FiPlay className="text-white text-2xl ml-1" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{src && (
|
||||||
|
<div className="absolute bottom-3 right-3 flex gap-2">
|
||||||
|
<button
|
||||||
|
onClick={togglePlay}
|
||||||
|
aria-label={playing ? 'Pause' : 'Play'}
|
||||||
|
className="w-9 h-9 flex items-center justify-center rounded-full bg-black/50 text-white backdrop-blur-sm hover:bg-black/70 transition-colors"
|
||||||
|
>
|
||||||
|
{playing ? <FiPause size={14} /> : <FiPlay size={14} />}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={toggleMute}
|
||||||
|
aria-label={muted ? 'Activer le son' : 'Couper le son'}
|
||||||
|
className="w-9 h-9 flex items-center justify-center rounded-full bg-black/50 text-white backdrop-blur-sm hover:bg-black/70 transition-colors"
|
||||||
|
>
|
||||||
|
{muted ? <FiVolumeX size={14} /> : <FiVolume2 size={14} />}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Hero({ bgSrc, bgMobileSrc }) {
|
||||||
|
const [videoSrc, setVideoSrc] = useState(null)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetch('/config.json')
|
||||||
|
.then(r => r.json())
|
||||||
|
.then(data => setVideoSrc(data.heroVideo ?? null))
|
||||||
|
.catch(() => {})
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section className="relative pt-20 md:pt-28 pb-36 md:pb-48">
|
||||||
|
{/* Fond mobile (portrait) */}
|
||||||
|
{(bgMobileSrc || bgSrc) && (
|
||||||
|
<div
|
||||||
|
className="md:hidden absolute inset-0 bg-cover bg-center"
|
||||||
|
style={{ backgroundImage: `url(${bgMobileSrc || bgSrc})` }}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{/* Fond desktop (paysage, parallax) */}
|
||||||
|
{bgSrc && (
|
||||||
|
<div
|
||||||
|
className="hidden md:block absolute inset-0 bg-cover bg-center bg-fixed"
|
||||||
|
style={{ backgroundImage: `url(${bgSrc})` }}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{/* Overlay */}
|
||||||
|
<div className="pointer-events-none absolute inset-0 bg-[#19392e]/70 backdrop-blur-[2px]" />
|
||||||
|
|
||||||
|
{/* Blobs décoratifs */}
|
||||||
<div className="pointer-events-none absolute inset-0 overflow-hidden">
|
<div className="pointer-events-none absolute inset-0 overflow-hidden">
|
||||||
<div className="absolute -top-48 -right-48 w-[600px] h-[600px] rounded-full bg-indigo-100/50 blur-3xl" />
|
<div className="absolute -top-48 -right-48 w-[600px] h-[600px] rounded-full bg-[#9CCC8A]/15 blur-3xl" />
|
||||||
<div className="absolute bottom-0 -left-32 w-[400px] h-[400px] rounded-full bg-sky-100/40 blur-3xl" />
|
<div className="absolute bottom-0 -left-32 w-[400px] h-[400px] rounded-full bg-[#9CCC8A]/10 blur-3xl" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 flex flex-col items-center text-center">
|
<div className="relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
|
|
||||||
|
{/* ── Titre + tagline centrés ── */}
|
||||||
<motion.div
|
<motion.div
|
||||||
initial={{ opacity: 0, y: 24 }}
|
initial={{ opacity: 0, y: 28 }}
|
||||||
animate={{ opacity: 1, y: 0 }}
|
animate={{ opacity: 1, y: 0 }}
|
||||||
transition={{ duration: 0.55 }}
|
transition={{ duration: 0.55 }}
|
||||||
className="max-w-3xl"
|
className="text-center mb-12"
|
||||||
>
|
>
|
||||||
<h1 className="text-5xl xl:text-6xl font-extrabold text-slate-900 leading-[1.08] tracking-tight mb-5">
|
<h1 className="text-3xl sm:text-5xl xl:text-7xl font-extrabold text-[#fffef6] leading-[1.05] tracking-tight mb-5">
|
||||||
Mutuelle santé{' '}
|
Mutuelle santé{' '}
|
||||||
<span className="relative">
|
<span className="relative inline-block">
|
||||||
<span className="relative z-10 text-transparent bg-clip-text bg-gradient-to-r from-indigo-600 to-sky-500">
|
<span className="relative z-10 text-transparent bg-clip-text bg-gradient-to-r from-[#9CCC8A] to-[#5BAF7A]">
|
||||||
pour tous
|
pour tous
|
||||||
</span>
|
</span>
|
||||||
<span className="absolute bottom-1 left-0 w-full h-3 bg-indigo-100/70 rounded-sm -z-0" />
|
<span className="absolute bottom-1 left-0 w-full h-3 bg-[#9CCC8A]/30 rounded-sm -z-0" />
|
||||||
</span>
|
</span>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<p className="text-lg text-slate-500 leading-relaxed mb-8 max-w-lg mx-auto">
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 12 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ duration: 0.45, delay: 0.2 }}
|
||||||
|
className="inline-block bg-[#19392e]/80 backdrop-blur-sm border border-white/20 text-[#fffef6] text-sm font-semibold px-5 py-2.5 rounded-full shadow-lg"
|
||||||
|
>
|
||||||
|
Payez moins. Le reste, on s'en bat les clauses.
|
||||||
|
</motion.div>
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
|
{/* ── Deux colonnes : carte gauche + vidéo droite ── */}
|
||||||
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8 lg:gap-10">
|
||||||
|
|
||||||
|
{/* Carte gauche */}
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, x: -28 }}
|
||||||
|
animate={{ opacity: 1, x: 0 }}
|
||||||
|
transition={{ duration: 0.55, delay: 0.3 }}
|
||||||
|
className="bg-[#19392e]/80 backdrop-blur-sm rounded-3xl border border-white/10 shadow-xl shadow-black/30 p-5 sm:p-8 flex flex-col justify-between"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<p className="text-lg text-[#fffef6]/80 leading-relaxed mb-6">
|
||||||
Jeune actif, parent, senior — comparez les garanties utiles et trouvez
|
Jeune actif, parent, senior — comparez les garanties utiles et trouvez
|
||||||
la couverture parfaite au meilleur prix, sans engagement.
|
la couverture parfaite au meilleur prix, sans engagement.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
{/* Trust points */}
|
{/* Trust points */}
|
||||||
<ul className="flex flex-wrap justify-center gap-x-6 gap-y-1.5 mb-8">
|
<ul className="flex flex-col gap-2 mb-8">
|
||||||
{['Comparaison 100% gratuite', 'Sans engagement', 'Réponse en 2 min'].map((t) => (
|
{['Comparaison 100% gratuite', 'Sans engagement', 'Réponse en 2 min'].map(t => (
|
||||||
<li key={t} className="flex items-center gap-1.5 text-sm text-slate-500">
|
<li key={t} className="flex items-center gap-2 text-sm text-[#fffef6]/80">
|
||||||
<FiCheckCircle className="text-emerald-500 flex-shrink-0" />
|
<FiCheckCircle className="text-[#9CCC8A] flex-shrink-0" size={15} />
|
||||||
{t}
|
{t}
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
{/* CTA */}
|
{/* CTAs */}
|
||||||
<div className="flex flex-wrap justify-center gap-3">
|
<div className="flex flex-col sm:flex-row flex-wrap gap-3 mb-8">
|
||||||
<motion.button
|
<motion.button
|
||||||
whileHover={{ scale: 1.025 }}
|
whileHover={{ scale: 1.025 }}
|
||||||
whileTap={{ scale: 0.97 }}
|
whileTap={{ scale: 0.97 }}
|
||||||
className="flex items-center gap-2 bg-gradient-to-r from-indigo-600 to-indigo-700 hover:from-indigo-700 hover:to-indigo-800 text-white font-bold text-base px-7 py-3.5 rounded-xl shadow-lg shadow-indigo-300/50 transition-all"
|
className="flex items-center justify-center gap-2 bg-[#9CCC8A] hover:bg-[#87BE73] text-black font-bold text-base px-7 py-3.5 rounded-xl shadow-lg shadow-[#9CCC8A]/40 transition-all w-full sm:w-auto"
|
||||||
>
|
>
|
||||||
Comparer les mutuelles
|
Comparer les mutuelles
|
||||||
<FiArrowRight />
|
<FiArrowRight />
|
||||||
</motion.button>
|
</motion.button>
|
||||||
<button className="flex items-center gap-2 font-semibold text-slate-700 text-base px-7 py-3.5 rounded-xl border border-slate-200 bg-white hover:border-indigo-300 hover:text-indigo-600 transition-all">
|
<button className="flex items-center justify-center gap-2 font-semibold text-[#fffef6]/80 text-base px-7 py-3.5 rounded-xl border border-white/20 bg-white/5 hover:border-[#9CCC8A] hover:text-[#9CCC8A] transition-all w-full sm:w-auto">
|
||||||
Voir le classement
|
Voir le classement
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</div>
|
||||||
|
|
||||||
{/* Stats bar */}
|
{/* Stats bar */}
|
||||||
<motion.div
|
<div className="grid grid-cols-3 gap-4 pt-6 border-t border-white/10">
|
||||||
initial={{ opacity: 0, y: 20 }}
|
|
||||||
animate={{ opacity: 1, y: 0 }}
|
|
||||||
transition={{ duration: 0.55, delay: 0.35 }}
|
|
||||||
className="mt-16 grid grid-cols-3 gap-6 max-w-2xl"
|
|
||||||
>
|
|
||||||
{stats.map(({ value, label, icon: Icon }) => (
|
{stats.map(({ value, label, icon: Icon }) => (
|
||||||
<div key={label} className="flex flex-col items-center gap-1">
|
<div key={label} className="flex flex-col gap-1">
|
||||||
<Icon className="text-indigo-400 text-lg mb-0.5" />
|
<Icon className="text-[#9CCC8A] text-base mb-0.5" />
|
||||||
<div className="text-2xl font-extrabold text-slate-900">{value}</div>
|
<div className="text-2xl font-extrabold text-[#fffef6]">{value}</div>
|
||||||
<div className="text-xs text-slate-400 font-medium">{label}</div>
|
<div className="text-xs text-[#fffef6]/50 font-medium">{label}</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
</div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
||||||
|
{/* Vidéo droite */}
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, x: 28 }}
|
||||||
|
animate={{ opacity: 1, x: 0 }}
|
||||||
|
transition={{ duration: 0.55, delay: 0.35 }}
|
||||||
|
className="min-h-0"
|
||||||
|
>
|
||||||
|
<VideoPlayer src={videoSrc} />
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Wave → ComparisonSection */}
|
||||||
|
<div className="absolute bottom-0 left-0 w-full overflow-hidden leading-[0] pointer-events-none">
|
||||||
|
<svg className="block w-full h-20 fill-white" viewBox="0 0 1200 120" preserveAspectRatio="none" style={{ transform: 'scaleY(-1)' }}>
|
||||||
|
<path d="M0,0V46.29c47.79,22.2,103.59,32.17,158,28,70.36-5.37,136.33-33.31,206.8-37.5C438.64,32.43,512.34,53.67,583,72.05c69.27,18,138.3,24.88,209.4,13.08,36.15-6,69.85-17.84,104.45-29.34C989.49,25,1113-14.29,1200,52.47V0Z" />
|
||||||
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ export function LogoMutuelle({ mutuelle, className = '' }) {
|
|||||||
<img
|
<img
|
||||||
src={faviconUrl}
|
src={faviconUrl}
|
||||||
alt=""
|
alt=""
|
||||||
|
loading="lazy"
|
||||||
|
decoding="async"
|
||||||
className="w-full h-full object-contain"
|
className="w-full h-full object-contain"
|
||||||
onError={() => setFaviconError(true)}
|
onError={() => setFaviconError(true)}
|
||||||
/>
|
/>
|
||||||
@@ -36,7 +38,7 @@ function FeatureDots({ count }) {
|
|||||||
<div
|
<div
|
||||||
key={i}
|
key={i}
|
||||||
className={`w-2.5 h-2.5 rounded-full transition-colors ${
|
className={`w-2.5 h-2.5 rounded-full transition-colors ${
|
||||||
i <= count ? 'bg-indigo-500' : 'bg-slate-200'
|
i <= count ? 'bg-[#9CCC8A]' : 'bg-slate-200'
|
||||||
}`}
|
}`}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
@@ -70,14 +72,14 @@ export default function MutuelleCard({ mutuelle }) {
|
|||||||
<div
|
<div
|
||||||
className={`bg-white rounded-2xl border transition-all hover:shadow-lg hover:-translate-y-0.5 p-5 flex items-center gap-4 ${
|
className={`bg-white rounded-2xl border transition-all hover:shadow-lg hover:-translate-y-0.5 p-5 flex items-center gap-4 ${
|
||||||
isFirst
|
isFirst
|
||||||
? 'border-indigo-200 shadow-md ring-1 ring-indigo-100'
|
? 'border-[#9CCC8A]/40 shadow-md ring-1 ring-[#9CCC8A]/20'
|
||||||
: 'border-slate-100 hover:border-slate-200'
|
: 'border-slate-100 hover:border-slate-200'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{/* Rang */}
|
{/* Rang */}
|
||||||
<div
|
<div
|
||||||
className={`w-8 h-8 rounded-xl flex items-center justify-center text-sm font-bold flex-shrink-0 ${
|
className={`w-8 h-8 rounded-xl flex items-center justify-center text-sm font-bold flex-shrink-0 ${
|
||||||
isFirst ? 'bg-indigo-600 text-white shadow-md shadow-indigo-300' : 'bg-slate-100 text-slate-500'
|
isFirst ? 'bg-[#9CCC8A] text-white shadow-md shadow-[#9CCC8A]/40' : 'bg-slate-100 text-slate-500'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{mutuelle.rang}
|
{mutuelle.rang}
|
||||||
@@ -137,10 +139,10 @@ export default function MutuelleCard({ mutuelle }) {
|
|||||||
href={mutuelle.lien}
|
href={mutuelle.lien}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
className="flex items-center gap-2 text-white font-bold text-sm px-5 py-2.5 rounded-xl flex-shrink-0 hover:opacity-90 active:scale-95 transition-all shadow-md"
|
className="flex items-center gap-1.5 text-white font-bold text-sm px-3 sm:px-5 py-2.5 rounded-xl flex-shrink-0 hover:opacity-90 active:scale-95 transition-all shadow-md"
|
||||||
style={{ backgroundColor: mutuelle.couleur }}
|
style={{ backgroundColor: mutuelle.couleur }}
|
||||||
>
|
>
|
||||||
Voir l'offre
|
<span className="hidden sm:inline">Voir l'offre</span>
|
||||||
<FiArrowRight />
|
<FiArrowRight />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { motion, AnimatePresence } from 'framer-motion'
|
import { motion, AnimatePresence } from 'framer-motion'
|
||||||
import { FiPhone, FiMenu, FiX } from 'react-icons/fi'
|
import { FiPhone, FiMenu, FiX } from 'react-icons/fi'
|
||||||
import { MdPets } from 'react-icons/md'
|
import AnimatedBrandName from './AnimatedBrandName'
|
||||||
|
|
||||||
const navLinks = [
|
const navLinks = [
|
||||||
{ label: 'Mutuelle santé', href: '#' },
|
{ label: 'Mutuelle santé', href: '#' },
|
||||||
@@ -16,17 +16,17 @@ export default function Navbar() {
|
|||||||
const [open, setOpen] = useState(false)
|
const [open, setOpen] = useState(false)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header className="sticky top-0 z-50 bg-white/95 backdrop-blur border-b border-slate-100 shadow-sm">
|
<header className="sticky top-0 z-50 bg-[#19392e] border-b border-white/10 shadow-sm">
|
||||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
<div className="flex items-center justify-between h-16">
|
<div className="flex items-center justify-between h-16">
|
||||||
{/* Logo */}
|
{/* Logo */}
|
||||||
<a href="#" className="flex items-center gap-2.5">
|
<a href="#" className="flex items-center gap-2.5">
|
||||||
<div className="w-9 h-9 bg-gradient-to-br from-indigo-500 to-indigo-700 rounded-xl flex items-center justify-center shadow-md shadow-indigo-200">
|
<img
|
||||||
<MdPets className="text-white text-lg" />
|
src="/img/ico.webp"
|
||||||
</div>
|
alt="AssurezMoi"
|
||||||
<span className="font-extrabold text-xl tracking-tight text-slate-900">
|
className="w-9 h-9 rounded-xl object-contain"
|
||||||
Assurez<span className="text-indigo-600">Moi</span>
|
/>
|
||||||
</span>
|
<AnimatedBrandName lightText />
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
{/* Desktop nav */}
|
{/* Desktop nav */}
|
||||||
@@ -35,7 +35,7 @@ export default function Navbar() {
|
|||||||
<a
|
<a
|
||||||
key={link.label}
|
key={link.label}
|
||||||
href={link.href}
|
href={link.href}
|
||||||
className="px-3 py-2 text-sm text-slate-600 hover:text-indigo-600 hover:bg-indigo-50 rounded-lg transition-all font-medium"
|
className="px-3 py-2 text-sm text-[#fffef6]/80 hover:text-[#9CCC8A] hover:bg-[#9CCC8A]/10 rounded-lg transition-all font-medium"
|
||||||
>
|
>
|
||||||
{link.label}
|
{link.label}
|
||||||
</a>
|
</a>
|
||||||
@@ -46,7 +46,7 @@ export default function Navbar() {
|
|||||||
<div className="hidden lg:flex items-center gap-3">
|
<div className="hidden lg:flex items-center gap-3">
|
||||||
<a
|
<a
|
||||||
href="tel:+33180891030"
|
href="tel:+33180891030"
|
||||||
className="flex items-center gap-2 bg-indigo-600 hover:bg-indigo-700 active:bg-indigo-800 text-white text-sm font-bold px-4 py-2.5 rounded-xl transition-all shadow-md shadow-indigo-200"
|
className="flex items-center gap-2 bg-[#9CCC8A] hover:bg-[#87BE73] active:bg-[#74AB61] text-white text-sm font-bold px-4 py-2.5 rounded-xl transition-all shadow-md shadow-[#9CCC8A]/40"
|
||||||
>
|
>
|
||||||
<FiPhone className="text-base" />
|
<FiPhone className="text-base" />
|
||||||
01 80 89 10 30
|
01 80 89 10 30
|
||||||
@@ -55,7 +55,7 @@ export default function Navbar() {
|
|||||||
|
|
||||||
{/* Mobile toggle */}
|
{/* Mobile toggle */}
|
||||||
<button
|
<button
|
||||||
className="lg:hidden p-2 rounded-lg text-slate-600 hover:bg-slate-100 transition-colors"
|
className="lg:hidden p-2 rounded-lg text-[#fffef6] hover:bg-white/10 transition-colors"
|
||||||
onClick={() => setOpen((v) => !v)}
|
onClick={() => setOpen((v) => !v)}
|
||||||
aria-label="Menu"
|
aria-label="Menu"
|
||||||
>
|
>
|
||||||
@@ -72,20 +72,20 @@ export default function Navbar() {
|
|||||||
animate={{ opacity: 1, y: 0 }}
|
animate={{ opacity: 1, y: 0 }}
|
||||||
exit={{ opacity: 0, y: -8 }}
|
exit={{ opacity: 0, y: -8 }}
|
||||||
transition={{ duration: 0.18 }}
|
transition={{ duration: 0.18 }}
|
||||||
className="lg:hidden border-t border-slate-100 bg-white px-4 pt-3 pb-5 space-y-1"
|
className="lg:hidden border-t border-white/10 bg-[#19392e] px-4 pt-3 pb-5 space-y-1"
|
||||||
>
|
>
|
||||||
{navLinks.map((link) => (
|
{navLinks.map((link) => (
|
||||||
<a
|
<a
|
||||||
key={link.label}
|
key={link.label}
|
||||||
href={link.href}
|
href={link.href}
|
||||||
className="block px-3 py-2.5 text-sm text-slate-600 hover:text-indigo-600 hover:bg-indigo-50 rounded-lg font-medium transition-colors"
|
className="block px-3 py-2.5 text-sm text-[#fffef6]/80 hover:text-[#9CCC8A] hover:bg-[#9CCC8A]/10 rounded-lg font-medium transition-colors"
|
||||||
>
|
>
|
||||||
{link.label}
|
{link.label}
|
||||||
</a>
|
</a>
|
||||||
))}
|
))}
|
||||||
<a
|
<a
|
||||||
href="tel:+33180891030"
|
href="tel:+33180891030"
|
||||||
className="mt-3 flex items-center justify-center gap-2 bg-indigo-600 text-white text-sm font-bold px-4 py-3 rounded-xl w-full"
|
className="mt-3 flex items-center justify-center gap-2 bg-[#9CCC8A] text-white text-sm font-bold px-4 py-3 rounded-xl w-full"
|
||||||
>
|
>
|
||||||
<FiPhone />
|
<FiPhone />
|
||||||
01 80 89 10 30
|
01 80 89 10 30
|
||||||
|
|||||||
@@ -22,7 +22,13 @@ export default function Testimonials() {
|
|||||||
<section className="py-20 bg-slate-50">
|
<section className="py-20 bg-slate-50">
|
||||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
|
|
||||||
<div className="text-center mb-14">
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 24 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: false }}
|
||||||
|
transition={{ duration: 0.5 }}
|
||||||
|
className="text-center mb-14"
|
||||||
|
>
|
||||||
<h2 className="text-4xl font-extrabold text-slate-900 tracking-tight mb-4">
|
<h2 className="text-4xl font-extrabold text-slate-900 tracking-tight mb-4">
|
||||||
Ce que nos clients disent de nous
|
Ce que nos clients disent de nous
|
||||||
</h2>
|
</h2>
|
||||||
@@ -30,7 +36,7 @@ export default function Testimonials() {
|
|||||||
Découvrez les témoignages de clients satisfaits qui nous font confiance
|
Découvrez les témoignages de clients satisfaits qui nous font confiance
|
||||||
pour leurs assurances santé.
|
pour leurs assurances santé.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</motion.div>
|
||||||
|
|
||||||
<div className="grid md:grid-cols-3 gap-6">
|
<div className="grid md:grid-cols-3 gap-6">
|
||||||
{testimonials.map((t, i) => (
|
{testimonials.map((t, i) => (
|
||||||
@@ -38,12 +44,12 @@ export default function Testimonials() {
|
|||||||
key={t.id}
|
key={t.id}
|
||||||
initial={{ opacity: 0, y: 24 }}
|
initial={{ opacity: 0, y: 24 }}
|
||||||
whileInView={{ opacity: 1, y: 0 }}
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
viewport={{ once: true }}
|
viewport={{ once: false }}
|
||||||
transition={{ delay: i * 0.12, duration: 0.45 }}
|
transition={{ delay: i * 0.12, duration: 0.45 }}
|
||||||
className="bg-white rounded-2xl border border-slate-100 p-6 shadow-sm hover:shadow-md hover:-translate-y-0.5 transition-all"
|
className="bg-white rounded-2xl border border-slate-100 p-6 shadow-sm hover:shadow-md hover:-translate-y-0.5 transition-all"
|
||||||
>
|
>
|
||||||
{/* Quote mark */}
|
{/* Quote mark */}
|
||||||
<div className="text-4xl font-serif text-indigo-100 leading-none mb-2 select-none">
|
<div className="text-4xl font-serif text-[#9CCC8A]/30 leading-none mb-2 select-none">
|
||||||
"
|
"
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -75,7 +81,7 @@ export default function Testimonials() {
|
|||||||
<motion.div
|
<motion.div
|
||||||
initial={{ opacity: 0, y: 16 }}
|
initial={{ opacity: 0, y: 16 }}
|
||||||
whileInView={{ opacity: 1, y: 0 }}
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
viewport={{ once: true }}
|
viewport={{ once: false }}
|
||||||
transition={{ duration: 0.45, delay: 0.3 }}
|
transition={{ duration: 0.45, delay: 0.3 }}
|
||||||
className="mt-12 flex flex-col sm:flex-row items-center justify-center gap-4 bg-white rounded-2xl border border-slate-100 shadow-sm px-8 py-5"
|
className="mt-12 flex flex-col sm:flex-row items-center justify-center gap-4 bg-white rounded-2xl border border-slate-100 shadow-sm px-8 py-5"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
font-family: Inter, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
|
font-family: Inter, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
background-color: #19392e;
|
||||||
|
color: #fffef6;
|
||||||
}
|
}
|
||||||
* {
|
* {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
|||||||