feat: update fintech card styles with modern design enhancements; add subtle texture effects and adjust gradient backgrounds for improved visual appeal in overview and statistics cards
All checks were successful
Deploy with Docker Compose / deploy (push) Successful in 1m52s

This commit is contained in:
Julien Froidefond
2025-12-21 13:29:43 +01:00
parent 2887a6a750
commit c4707e5511
3 changed files with 282 additions and 150 deletions

View File

@@ -459,21 +459,50 @@
z-index: 1;
}
/* Fintech card styles avec glassmorphism très prononcé */
/* Fintech card styles avec design moderne et élégant */
.fintech-card {
background: var(--card);
backdrop-filter: blur(50px) saturate(200%);
-webkit-backdrop-filter: blur(50px) saturate(200%);
border: 1px solid var(--border);
border-radius: var(--radius);
backdrop-filter: blur(40px) saturate(180%);
-webkit-backdrop-filter: blur(40px) saturate(180%);
border: 1px solid color-mix(in srgb, var(--border) 60%, transparent);
border-radius: calc(var(--radius) + 0.25rem);
box-shadow:
0 8px 32px -8px color-mix(in srgb, var(--primary) 8%, transparent),
0 2px 8px -2px color-mix(in srgb, var(--foreground) 3%, transparent),
inset 0 1px 0 0 color-mix(in srgb, white 25%, transparent);
0 1px 3px 0 color-mix(in srgb, var(--foreground) 4%, transparent),
0 4px 12px -2px color-mix(in srgb, var(--primary) 6%, transparent),
0 8px 24px -4px color-mix(in srgb, var(--foreground) 2%, transparent),
inset 0 1px 0 0 color-mix(in srgb, white 30%, transparent);
position: relative;
overflow: hidden;
}
/* Texture subtile avec grain/noise */
.fintech-card::before {
content: "";
position: absolute;
inset: 0;
background-image:
radial-gradient(circle at 1px 1px, color-mix(in srgb, var(--foreground) 2%, transparent) 1px, transparent 0);
background-size: 20px 20px;
opacity: 0.15;
pointer-events: none;
z-index: 1;
}
.dark .fintech-card::before {
background-image:
radial-gradient(circle at 1px 1px, color-mix(in srgb, white 3%, transparent) 1px, transparent 0);
opacity: 0.1;
}
.dark .fintech-card {
border-color: color-mix(in srgb, var(--border) 40%, transparent);
box-shadow:
0 1px 3px 0 color-mix(in srgb, var(--foreground) 8%, transparent),
0 4px 12px -2px color-mix(in srgb, var(--primary) 8%, transparent),
0 8px 24px -4px color-mix(in srgb, black 40%, transparent),
inset 0 1px 0 0 color-mix(in srgb, white 8%, transparent);
}
.fintech-card::after {
content: "";
position: absolute;
@@ -484,140 +513,220 @@
background: linear-gradient(
90deg,
transparent 0%,
color-mix(in srgb, white 40%, transparent) 50%,
color-mix(in srgb, white 50%, transparent) 50%,
transparent 100%
);
opacity: 0.5;
opacity: 0.6;
z-index: 2;
}
/* Gradient backgrounds for stat cards très vibrants */
.dark .fintech-card::after {
opacity: 0.2;
}
/* Gradient backgrounds for stat cards - design moderne et subtil */
.stat-card-gradient-1 {
background: linear-gradient(
135deg,
color-mix(in srgb, var(--primary) 8%, var(--card)) 0%,
color-mix(in srgb, var(--primary-light) 5%, var(--card)) 50%,
color-mix(in srgb, var(--primary) 4%, var(--card)) 100%
);
position: relative;
overflow: hidden;
border-color: color-mix(in srgb, var(--primary) 20%, var(--border));
}
.stat-card-gradient-1::before {
content: "";
position: absolute;
top: -30%;
right: -20%;
width: 150%;
height: 150%;
background: radial-gradient(
circle,
color-mix(in srgb, var(--primary) 15%, transparent) 0%,
transparent 60%
);
opacity: 0.4;
}
.dark .stat-card-gradient-1 {
background: linear-gradient(
135deg,
color-mix(in srgb, var(--primary) 12%, var(--card)) 0%,
color-mix(in srgb, var(--primary-light) 8%, var(--card)) 50%,
color-mix(in srgb, var(--primary) 6%, var(--card)) 100%
);
position: relative;
overflow: hidden;
border-color: color-mix(in srgb, var(--primary) 30%, var(--border));
}
.stat-card-gradient-1::before {
content: "";
position: absolute;
top: -50%;
right: -50%;
width: 200%;
height: 200%;
background: radial-gradient(
circle,
color-mix(in srgb, var(--primary) 20%, transparent) 0%,
transparent 70%
);
opacity: 0.3;
.dark .stat-card-gradient-1::before {
opacity: 0.25;
}
.stat-card-gradient-2 {
background: linear-gradient(
135deg,
color-mix(in srgb, var(--success) 8%, var(--card)) 0%,
color-mix(in srgb, var(--success) 5%, var(--card)) 50%,
color-mix(in srgb, var(--success) 4%, var(--card)) 100%
);
position: relative;
overflow: hidden;
border-color: color-mix(in srgb, var(--success) 20%, var(--border));
}
.stat-card-gradient-2::before {
content: "";
position: absolute;
top: -30%;
right: -20%;
width: 150%;
height: 150%;
background: radial-gradient(
circle,
color-mix(in srgb, var(--success) 15%, transparent) 0%,
transparent 60%
);
opacity: 0.4;
}
.dark .stat-card-gradient-2 {
background: linear-gradient(
135deg,
color-mix(in srgb, var(--success) 12%, var(--card)) 0%,
color-mix(in srgb, var(--success) 8%, var(--card)) 50%,
color-mix(in srgb, var(--success) 6%, var(--card)) 100%
);
position: relative;
overflow: hidden;
border-color: color-mix(in srgb, var(--success) 30%, var(--border));
}
.stat-card-gradient-2::before {
content: "";
position: absolute;
top: -50%;
right: -50%;
width: 200%;
height: 200%;
background: radial-gradient(
circle,
color-mix(in srgb, var(--success) 20%, transparent) 0%,
transparent 70%
);
opacity: 0.3;
.dark .stat-card-gradient-2::before {
opacity: 0.25;
}
.stat-card-gradient-3 {
background: linear-gradient(
135deg,
color-mix(in srgb, var(--destructive) 8%, var(--card)) 0%,
color-mix(in srgb, var(--destructive) 5%, var(--card)) 50%,
color-mix(in srgb, var(--destructive) 4%, var(--card)) 100%
);
position: relative;
overflow: hidden;
border-color: color-mix(in srgb, var(--destructive) 20%, var(--border));
}
.stat-card-gradient-3::before {
content: "";
position: absolute;
top: -30%;
right: -20%;
width: 150%;
height: 150%;
background: radial-gradient(
circle,
color-mix(in srgb, var(--destructive) 15%, transparent) 0%,
transparent 60%
);
opacity: 0.4;
}
.dark .stat-card-gradient-3 {
background: linear-gradient(
135deg,
color-mix(in srgb, var(--destructive) 12%, var(--card)) 0%,
color-mix(in srgb, var(--destructive) 8%, var(--card)) 50%,
color-mix(in srgb, var(--destructive) 6%, var(--card)) 100%
);
position: relative;
overflow: hidden;
border-color: color-mix(in srgb, var(--destructive) 30%, var(--border));
}
.stat-card-gradient-3::before {
content: "";
position: absolute;
top: -50%;
right: -50%;
width: 200%;
height: 200%;
background: radial-gradient(
circle,
color-mix(in srgb, var(--destructive) 20%, transparent) 0%,
transparent 70%
);
opacity: 0.3;
.dark .stat-card-gradient-3::before {
opacity: 0.25;
}
.stat-card-gradient-4 {
background: linear-gradient(
135deg,
color-mix(in srgb, var(--chart-4) 8%, var(--card)) 0%,
color-mix(in srgb, var(--chart-4) 5%, var(--card)) 50%,
color-mix(in srgb, var(--chart-4) 4%, var(--card)) 100%
);
position: relative;
overflow: hidden;
border-color: color-mix(in srgb, var(--chart-4) 20%, var(--border));
}
.stat-card-gradient-4::before {
content: "";
position: absolute;
top: -30%;
right: -20%;
width: 150%;
height: 150%;
background: radial-gradient(
circle,
color-mix(in srgb, var(--chart-4) 15%, transparent) 0%,
transparent 60%
);
opacity: 0.4;
}
.dark .stat-card-gradient-4 {
background: linear-gradient(
135deg,
color-mix(in srgb, var(--chart-4) 12%, var(--card)) 0%,
color-mix(in srgb, var(--chart-4) 8%, var(--card)) 50%,
color-mix(in srgb, var(--chart-4) 6%, var(--card)) 100%
);
position: relative;
overflow: hidden;
border-color: color-mix(in srgb, var(--chart-4) 30%, var(--border));
}
.stat-card-gradient-4::before {
content: "";
position: absolute;
top: -50%;
right: -50%;
width: 200%;
height: 200%;
background: radial-gradient(
circle,
color-mix(in srgb, var(--chart-4) 20%, transparent) 0%,
transparent 70%
);
opacity: 0.3;
.dark .stat-card-gradient-4::before {
opacity: 0.25;
}
.stat-card-gradient-5 {
background: linear-gradient(
135deg,
color-mix(in srgb, var(--chart-5) 8%, var(--card)) 0%,
color-mix(in srgb, var(--chart-5) 5%, var(--card)) 50%,
color-mix(in srgb, var(--chart-5) 4%, var(--card)) 100%
);
position: relative;
overflow: hidden;
border-color: color-mix(in srgb, var(--chart-5) 20%, var(--border));
}
.stat-card-gradient-5::before {
content: "";
position: absolute;
top: -30%;
right: -20%;
width: 150%;
height: 150%;
background: radial-gradient(
circle,
color-mix(in srgb, var(--chart-5) 15%, transparent) 0%,
transparent 60%
);
opacity: 0.4;
}
.dark .stat-card-gradient-5 {
background: linear-gradient(
135deg,
color-mix(in srgb, var(--chart-5) 12%, var(--card)) 0%,
color-mix(in srgb, var(--chart-5) 8%, var(--card)) 50%,
color-mix(in srgb, var(--chart-5) 6%, var(--card)) 100%
);
position: relative;
overflow: hidden;
border-color: color-mix(in srgb, var(--chart-5) 30%, var(--border));
}
.stat-card-gradient-5::before {
content: "";
position: absolute;
top: -50%;
right: -50%;
width: 200%;
height: 200%;
background: radial-gradient(
circle,
color-mix(in srgb, var(--chart-5) 20%, transparent) 0%,
transparent 70%
);
opacity: 0.3;
.dark .stat-card-gradient-5::before {
opacity: 0.25;
}
}

View File

@@ -59,18 +59,19 @@ export function OverviewCards({ data }: OverviewCardsProps) {
return (
<div className="grid gap-4 sm:gap-6 grid-cols-1 sm:grid-cols-2 lg:grid-cols-5">
<Card className="stat-card-gradient-1 card-hover group relative overflow-hidden">
<CardHeader className="flex flex-row items-start justify-between space-y-0 pb-4 px-6 pt-6 sm:px-7 sm:pt-7 lg:px-5 lg:pt-5 relative z-10">
<CardTitle className="text-xs font-bold text-muted-foreground/70 leading-tight uppercase tracking-widest flex-1 min-w-0 pr-2">
{/* Icône en arrière-plan */}
<div className="absolute bottom-2 right-2 opacity-[0.04] dark:opacity-[0.03] z-0 pointer-events-none">
<Wallet className="h-20 w-20 sm:h-24 sm:w-24 md:h-28 md:w-28 text-primary" strokeWidth={1} />
</div>
<CardHeader className="flex flex-row items-start justify-between space-y-0 pb-3 px-5 pt-5 sm:px-6 sm:pt-6 relative z-10">
<CardTitle className="text-[10px] sm:text-xs font-semibold text-muted-foreground/80 leading-tight uppercase tracking-wider flex-1 min-w-0">
Solde Total
</CardTitle>
<div className="rounded-2xl bg-gradient-to-br from-primary/30 via-primary/20 to-primary/10 p-3 shrink-0 shadow-lg shadow-primary/20">
<Wallet className="h-5 w-5 text-primary" />
</div>
</CardHeader>
<CardContent className="px-6 pb-6 sm:px-7 sm:pb-7 lg:px-5 lg:pb-5 pt-0 relative z-10">
<CardContent className="px-5 pb-5 sm:px-6 sm:pb-6 pt-0 relative z-10">
<div
className={cn(
"text-2xl sm:text-3xl md:text-3xl lg:text-xl xl:text-xl font-black tracking-tight mb-4 leading-none break-words",
"text-2xl sm:text-3xl md:text-3xl lg:text-2xl xl:text-3xl font-black tracking-tight mb-3 leading-tight break-words",
totalBalance >= 0
? "text-emerald-600 dark:text-emerald-400"
: "text-red-600 dark:text-red-400"
@@ -78,26 +79,27 @@ export function OverviewCards({ data }: OverviewCardsProps) {
>
{formatCurrency(totalBalance)}
</div>
<p className="text-xs sm:text-sm font-semibold text-muted-foreground/60">
<p className="text-xs sm:text-sm font-medium text-muted-foreground/70">
{data.accounts.length} compte{data.accounts.length > 1 ? "s" : ""}
</p>
</CardContent>
</Card>
<Card className="stat-card-gradient-2 card-hover group relative overflow-hidden">
<CardHeader className="flex flex-row items-start justify-between space-y-0 pb-4 px-6 pt-6 sm:px-7 sm:pt-7 lg:px-5 lg:pt-5 relative z-10">
<CardTitle className="text-xs font-bold text-muted-foreground/70 leading-tight uppercase tracking-widest flex-1 min-w-0 pr-2">
{/* Icône en arrière-plan */}
<div className="absolute bottom-2 right-2 opacity-[0.04] dark:opacity-[0.03] z-0 pointer-events-none">
<TrendingUp className="h-20 w-20 sm:h-24 sm:w-24 md:h-28 md:w-28 text-success" strokeWidth={1} />
</div>
<CardHeader className="flex flex-row items-start justify-between space-y-0 pb-3 px-5 pt-5 sm:px-6 sm:pt-6 relative z-10">
<CardTitle className="text-[10px] sm:text-xs font-semibold text-muted-foreground/80 leading-tight uppercase tracking-wider flex-1 min-w-0">
Revenus du mois
</CardTitle>
<div className="rounded-2xl bg-gradient-to-br from-success/30 via-success/20 to-success/10 p-3 shrink-0 shadow-lg shadow-success/20">
<TrendingUp className="h-5 w-5 text-success" />
</div>
</CardHeader>
<CardContent className="px-6 pb-6 sm:px-7 sm:pb-7 lg:px-5 lg:pb-5 pt-0 relative z-10">
<div className="text-2xl sm:text-3xl md:text-3xl lg:text-xl xl:text-xl font-black tracking-tight text-success mb-4 leading-none break-words">
<CardContent className="px-5 pb-5 sm:px-6 sm:pb-6 pt-0 relative z-10">
<div className="text-2xl sm:text-3xl md:text-3xl lg:text-2xl xl:text-3xl font-black tracking-tight text-success mb-3 leading-tight break-words">
{formatCurrency(income)}
</div>
<p className="text-xs sm:text-sm font-semibold text-muted-foreground/60">
<p className="text-xs sm:text-sm font-medium text-muted-foreground/70">
{monthTransactions.filter((t) => t.amount > 0).length} opération
{monthTransactions.filter((t) => t.amount > 0).length > 1
? "s"
@@ -107,19 +109,20 @@ export function OverviewCards({ data }: OverviewCardsProps) {
</Card>
<Card className="stat-card-gradient-3 card-hover group relative overflow-hidden">
<CardHeader className="flex flex-row items-start justify-between space-y-0 pb-4 px-6 pt-6 sm:px-7 sm:pt-7 lg:px-5 lg:pt-5 relative z-10">
<CardTitle className="text-xs font-bold text-muted-foreground/70 leading-tight uppercase tracking-widest flex-1 min-w-0 pr-2">
{/* Icône en arrière-plan */}
<div className="absolute bottom-2 right-2 opacity-[0.04] dark:opacity-[0.03] z-0 pointer-events-none">
<TrendingDown className="h-20 w-20 sm:h-24 sm:w-24 md:h-28 md:w-28 text-destructive" strokeWidth={1} />
</div>
<CardHeader className="flex flex-row items-start justify-between space-y-0 pb-3 px-5 pt-5 sm:px-6 sm:pt-6 relative z-10">
<CardTitle className="text-[10px] sm:text-xs font-semibold text-muted-foreground/80 leading-tight uppercase tracking-wider flex-1 min-w-0">
Dépenses du mois
</CardTitle>
<div className="rounded-2xl bg-gradient-to-br from-destructive/30 via-destructive/20 to-destructive/10 p-3 shrink-0 shadow-lg shadow-destructive/20">
<TrendingDown className="h-5 w-5 text-destructive" />
</div>
</CardHeader>
<CardContent className="px-6 pb-6 sm:px-7 sm:pb-7 lg:px-5 lg:pb-5 pt-0 relative z-10">
<div className="text-2xl sm:text-3xl md:text-3xl lg:text-xl xl:text-xl font-black tracking-tight text-destructive mb-4 leading-none break-words">
<CardContent className="px-5 pb-5 sm:px-6 sm:pb-6 pt-0 relative z-10">
<div className="text-2xl sm:text-3xl md:text-3xl lg:text-2xl xl:text-3xl font-black tracking-tight text-destructive mb-3 leading-tight break-words">
{formatCurrency(expenses)}
</div>
<p className="text-xs sm:text-sm font-semibold text-muted-foreground/60">
<p className="text-xs sm:text-sm font-medium text-muted-foreground/70">
{monthTransactions.filter((t) => t.amount < 0).length} opération
{monthTransactions.filter((t) => t.amount < 0).length > 1
? "s"
@@ -129,38 +132,40 @@ export function OverviewCards({ data }: OverviewCardsProps) {
</Card>
<Card className="stat-card-gradient-4 card-hover group relative overflow-hidden">
<CardHeader className="flex flex-row items-start justify-between space-y-0 pb-4 px-6 pt-6 sm:px-7 sm:pt-7 lg:px-5 lg:pt-5 relative z-10">
<CardTitle className="text-xs font-bold text-muted-foreground/70 leading-tight uppercase tracking-widest flex-1 min-w-0 pr-2">
{/* Icône en arrière-plan */}
<div className="absolute bottom-2 right-2 opacity-[0.04] dark:opacity-[0.03] z-0 pointer-events-none">
<CreditCard className="h-20 w-20 sm:h-24 sm:w-24 md:h-28 md:w-28 text-chart-4" strokeWidth={1} />
</div>
<CardHeader className="flex flex-row items-start justify-between space-y-0 pb-3 px-5 pt-5 sm:px-6 sm:pt-6 relative z-10">
<CardTitle className="text-[10px] sm:text-xs font-semibold text-muted-foreground/80 leading-tight uppercase tracking-wider flex-1 min-w-0">
Pointage
</CardTitle>
<div className="rounded-2xl bg-gradient-to-br from-chart-4/30 via-chart-4/20 to-chart-4/10 p-3 shrink-0 shadow-lg shadow-chart-4/20">
<CreditCard className="h-5 w-5 text-chart-4" />
</div>
</CardHeader>
<CardContent className="px-6 pb-6 sm:px-7 sm:pb-7 lg:px-5 lg:pb-5 pt-0 relative z-10">
<div className="text-2xl sm:text-3xl md:text-3xl lg:text-xl xl:text-xl font-black tracking-tight mb-4 leading-none break-words">
<CardContent className="px-5 pb-5 sm:px-6 sm:pb-6 pt-0 relative z-10">
<div className="text-2xl sm:text-3xl md:text-3xl lg:text-2xl xl:text-3xl font-black tracking-tight mb-3 leading-tight break-words">
{reconciledPercent}%
</div>
<p className="text-xs sm:text-sm font-semibold text-muted-foreground/60">
<p className="text-xs sm:text-sm font-medium text-muted-foreground/70">
{reconciled} / {total} opérations pointées
</p>
</CardContent>
</Card>
<Card className="stat-card-gradient-5 card-hover group relative overflow-hidden">
<CardHeader className="flex flex-row items-start justify-between space-y-0 pb-4 px-6 pt-6 sm:px-7 sm:pt-7 lg:px-5 lg:pt-5 relative z-10">
<CardTitle className="text-xs font-bold text-muted-foreground/70 leading-tight uppercase tracking-widest flex-1 min-w-0 pr-2">
{/* Icône en arrière-plan */}
<div className="absolute bottom-2 right-2 opacity-[0.04] dark:opacity-[0.03] z-0 pointer-events-none">
<Tag className="h-20 w-20 sm:h-24 sm:w-24 md:h-28 md:w-28 text-chart-5" strokeWidth={1} />
</div>
<CardHeader className="flex flex-row items-start justify-between space-y-0 pb-3 px-5 pt-5 sm:px-6 sm:pt-6 relative z-10">
<CardTitle className="text-[10px] sm:text-xs font-semibold text-muted-foreground/80 leading-tight uppercase tracking-wider flex-1 min-w-0">
Catégorisation
</CardTitle>
<div className="rounded-2xl bg-gradient-to-br from-chart-5/30 via-chart-5/20 to-chart-5/10 p-3 shrink-0 shadow-lg shadow-chart-5/20">
<Tag className="h-5 w-5 text-chart-5" />
</div>
</CardHeader>
<CardContent className="px-6 pb-6 sm:px-7 sm:pb-7 lg:px-5 lg:pb-5 pt-0 relative z-10">
<div className="text-2xl sm:text-3xl md:text-3xl lg:text-xl xl:text-xl font-black tracking-tight mb-4 leading-none break-words">
<CardContent className="px-5 pb-5 sm:px-6 sm:pb-6 pt-0 relative z-10">
<div className="text-2xl sm:text-3xl md:text-3xl lg:text-2xl xl:text-3xl font-black tracking-tight mb-3 leading-tight break-words">
{categorizedPercent}%
</div>
<p className="text-xs sm:text-sm font-semibold text-muted-foreground/60">
<p className="text-xs sm:text-sm font-medium text-muted-foreground/70">
{categorized} / {total} opérations catégorisées
</p>
</CardContent>

View File

@@ -21,59 +21,77 @@ export function StatsSummaryCards({
return (
<div className="grid gap-3 md:gap-4 grid-cols-2 md:grid-cols-4">
<Card>
<CardHeader className="pb-2">
<CardTitle className="text-xs md:text-sm font-medium text-muted-foreground flex items-center gap-1.5 md:gap-2">
<TrendingUp className="w-3 h-3 md:w-4 md:h-4 text-emerald-600" />
<Card className="relative overflow-hidden">
{/* Icône en arrière-plan */}
<div className="absolute bottom-2 right-2 opacity-[0.04] dark:opacity-[0.03] z-0 pointer-events-none">
<TrendingUp className="h-16 w-16 md:h-20 md:w-20 text-emerald-600 dark:text-emerald-400" strokeWidth={1} />
</div>
<CardHeader className="pb-3 px-5 pt-5 relative z-10">
<CardTitle className="text-[10px] md:text-xs font-semibold text-muted-foreground/80 uppercase tracking-wider">
Total Revenus
</CardTitle>
</CardHeader>
<CardContent>
<div className="text-lg md:text-2xl font-bold text-emerald-600">
<CardContent className="px-5 pb-5 pt-0 relative z-10">
<div className="text-xl md:text-2xl font-black text-emerald-600 dark:text-emerald-400 tracking-tight">
{formatCurrency(totalIncome)}
</div>
</CardContent>
</Card>
<Card>
<CardHeader className="pb-2">
<CardTitle className="text-xs md:text-sm font-medium text-muted-foreground flex items-center gap-1.5 md:gap-2">
<TrendingDown className="w-3 h-3 md:w-4 md:h-4 text-red-600" />
<Card className="relative overflow-hidden">
{/* Icône en arrière-plan */}
<div className="absolute bottom-2 right-2 opacity-[0.04] dark:opacity-[0.03] z-0 pointer-events-none">
<TrendingDown className="h-16 w-16 md:h-20 md:w-20 text-red-600 dark:text-red-400" strokeWidth={1} />
</div>
<CardHeader className="pb-3 px-5 pt-5 relative z-10">
<CardTitle className="text-[10px] md:text-xs font-semibold text-muted-foreground/80 uppercase tracking-wider">
Total Dépenses
</CardTitle>
</CardHeader>
<CardContent>
<div className="text-lg md:text-2xl font-bold text-red-600">
<CardContent className="px-5 pb-5 pt-0 relative z-10">
<div className="text-xl md:text-2xl font-black text-red-600 dark:text-red-400 tracking-tight">
{formatCurrency(totalExpenses)}
</div>
</CardContent>
</Card>
<Card>
<CardHeader className="pb-2">
<CardTitle className="text-xs md:text-sm font-medium text-muted-foreground flex items-center gap-1.5 md:gap-2">
<ArrowRight className="w-3 h-3 md:w-4 md:h-4" />
<Card className="relative overflow-hidden">
{/* Icône en arrière-plan */}
<div className="absolute bottom-2 right-2 opacity-[0.04] dark:opacity-[0.03] z-0 pointer-events-none">
<ArrowRight className="h-16 w-16 md:h-20 md:w-20 text-muted-foreground/40" strokeWidth={1} />
</div>
<CardHeader className="pb-3 px-5 pt-5 relative z-10">
<CardTitle className="text-[10px] md:text-xs font-semibold text-muted-foreground/80 uppercase tracking-wider">
Moyenne mensuelle
</CardTitle>
</CardHeader>
<CardContent>
<div className="text-lg md:text-2xl font-bold">
<CardContent className="px-5 pb-5 pt-0 relative z-10">
<div className="text-xl md:text-2xl font-black tracking-tight">
{formatCurrency(avgMonthlyExpenses)}
</div>
</CardContent>
</Card>
<Card>
<CardHeader className="pb-2">
<CardTitle className="text-xs md:text-sm font-medium text-muted-foreground">
<Card className="relative overflow-hidden">
{/* Icône en arrière-plan */}
<div className="absolute bottom-2 right-2 opacity-[0.04] dark:opacity-[0.03] z-0 pointer-events-none">
<div className={cn(
"h-16 w-16 md:h-20 md:w-20 rounded-full border-2",
savings >= 0
? "border-emerald-600 dark:border-emerald-400"
: "border-red-600 dark:border-red-400"
)} />
</div>
<CardHeader className="pb-3 px-5 pt-5 relative z-10">
<CardTitle className="text-[10px] md:text-xs font-semibold text-muted-foreground/80 uppercase tracking-wider">
Économies
</CardTitle>
</CardHeader>
<CardContent>
<CardContent className="px-5 pb-5 pt-0 relative z-10">
<div
className={cn(
"text-lg md:text-2xl font-bold",
savings >= 0 ? "text-emerald-600" : "text-red-600",
"text-xl md:text-2xl font-black tracking-tight",
savings >= 0 ? "text-emerald-600 dark:text-emerald-400" : "text-red-600 dark:text-red-400",
)}
>
{formatCurrency(savings)}