Refactoring CSS cards parcours : CSS partagé, propriétés logiques, suppression des !important et de la duplication 3x

This commit is contained in:
Jalil Arfaoui 2026-03-11 15:23:49 +01:00
parent 8728594347
commit 5b887c7926
5 changed files with 177 additions and 253 deletions

View file

@ -55,25 +55,33 @@ const locale = pathname.startsWith("/en")
color: rgba(255, 255, 255, 0.85) !important; color: rgba(255, 255, 255, 0.85) !important;
} }
/*
* Page-level text overrides for the purple gradient.
* Any component that manages its own colors should add
* the `.code-card` class — it will be excluded automatically.
*/
[data-facet="code"] > section h1, [data-facet="code"] > section h1,
[data-facet="code"] > section h2, [data-facet="code"] > section h2 {
[data-facet="code"] > section h3:not(.exp-card h3):not(.facet-card h3),
[data-facet="code"] > section strong:not(.exp-card strong):not(.facet-card strong) {
color: white !important; color: white !important;
} }
[data-facet="code"] > section a:not(.facet-card a) { [data-facet="code"] > section h3:not(.code-card h3),
[data-facet="code"] > section strong:not(.code-card strong) {
color: white !important;
}
[data-facet="code"] > section a:not(.code-card a) {
color: #d4b5ff !important; color: #d4b5ff !important;
text-decoration-color: rgba(212, 181, 255, 0.3) !important; text-decoration-color: rgba(212, 181, 255, 0.3) !important;
} }
[data-facet="code"] > section a:not(.facet-card a):hover { [data-facet="code"] > section a:not(.code-card a):hover {
color: white !important; color: white !important;
text-decoration-color: white !important; text-decoration-color: white !important;
} }
[data-facet="code"] > section p:not(.exp-card p):not(.facet-card p), [data-facet="code"] > section p:not(.code-card p),
[data-facet="code"] > section li:not(.exp-card li):not(.facet-card li) { [data-facet="code"] > section li:not(.code-card li) {
color: rgba(255, 255, 255, 0.75) !important; color: rgba(255, 255, 255, 0.75) !important;
} }

View file

@ -2,6 +2,7 @@
import { getCollection, render } from "astro:content"; import { getCollection, render } from "astro:content";
import { Image } from "astro:assets"; import { Image } from "astro:assets";
import Layout from "../../../layouts/main.astro"; import Layout from "../../../layouts/main.astro";
import "../../../styles/exp-card.css";
const logos = import.meta.glob<{ default: ImageMetadata }>('../../../assets/images/companies/*.png', { eager: true }); const logos = import.meta.glob<{ default: ImageMetadata }>('../../../assets/images/companies/*.png', { eager: true });
@ -91,12 +92,12 @@ function computeDuration(startStr: string, endStr?: string) {
</div> </div>
<div class:list={[ <div class:list={[
"exp-card relative rounded-2xl p-6 transition-colors duration-200 border-r-[3px]", "code-card exp-card relative rounded-2xl p-6 transition-colors duration-200 border-s-[3px]",
isOngoing ? "exp-card--ongoing" : "", isOngoing ? "exp-card--ongoing" : "",
colors.border colors.border
]}> ]}>
{getLogo(exp.data.logo) ? ( {getLogo(exp.data.logo) ? (
<div class="exp-logo absolute top-5 left-5 w-16 h-16 rounded-xl flex items-center justify-center p-2"> <div class="exp-logo absolute top-5 end-5 w-16 h-16 rounded-xl flex items-center justify-center p-2">
<Image <Image
src={getLogo(exp.data.logo)!} src={getLogo(exp.data.logo)!}
alt={`شعار ${exp.data.company}`} alt={`شعار ${exp.data.company}`}
@ -106,12 +107,12 @@ function computeDuration(startStr: string, endStr?: string) {
/> />
</div> </div>
) : ( ) : (
<div class="exp-logo-fallback absolute top-5 left-5 w-16 h-16 rounded-xl flex items-center justify-center"> <div class="exp-logo-fallback absolute top-5 end-5 w-16 h-16 rounded-xl flex items-center justify-center">
<span class="text-base font-bold">{getInitials(exp.data.company)}</span> <span class="text-base font-bold">{getInitials(exp.data.company)}</span>
</div> </div>
)} )}
<div class="mb-3 flex items-center gap-2 flex-wrap pl-20"> <div class="mb-3 flex items-center gap-2 flex-wrap pe-20">
<span class:list={["inline-block px-2 py-0.5 text-[11px] font-medium rounded-full border", colors.badge]}> <span class:list={["inline-block px-2 py-0.5 text-[11px] font-medium rounded-full border", colors.badge]}>
{label} {label}
</span> </span>
@ -122,7 +123,7 @@ function computeDuration(startStr: string, endStr?: string) {
{exp.data.location && <span class="exp-meta text-xs">· {exp.data.location}</span>} {exp.data.location && <span class="exp-meta text-xs">· {exp.data.location}</span>}
</div> </div>
<h3 class="text-xl font-bold pl-20">{exp.data.role}</h3> <h3 class="text-xl font-bold pe-20">{exp.data.role}</h3>
<p class="exp-company text-sm font-medium mt-1 mb-3"> <p class="exp-company text-sm font-medium mt-1 mb-3">
{exp.data.companyUrl ? ( {exp.data.companyUrl ? (
<a href={exp.data.companyUrl} target="_blank" rel="noopener noreferrer" class="transition-colors">{exp.data.company}</a> <a href={exp.data.companyUrl} target="_blank" rel="noopener noreferrer" class="transition-colors">{exp.data.company}</a>
@ -149,80 +150,3 @@ function computeDuration(startStr: string, endStr?: string) {
</div> </div>
</section> </section>
</Layout> </Layout>
<style>
/* ── Light mode (default): white cards on purple gradient ── */
.exp-card {
background: white;
border: 1px solid rgba(0, 0, 0, 0.06);
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
}
.exp-card--ongoing { box-shadow: 0 0 0 1px rgba(168, 85, 247, 0.25), 0 1px 3px rgba(0, 0, 0, 0.08); }
.exp-card h3 { color: #111827 !important; }
.exp-card .exp-meta { color: #9ca3af; }
.exp-card .exp-company { color: #6b21a8; }
.exp-card .exp-company a { color: #6b21a8 !important; text-decoration: none !important; }
.exp-card .exp-company a:hover { color: #581c87 !important; }
.exp-card .exp-content,
.exp-card .exp-content p { color: #4b5563 !important; }
.exp-card .exp-content a { color: #6b21a8 !important; text-decoration-color: rgba(107, 33, 168, 0.3) !important; }
.exp-card .exp-content a:hover { color: #581c87 !important; }
.exp-card .exp-tech { background: #f3f4f6; color: #6b7280; border-color: #e5e7eb; }
.exp-logo { background: #f9fafb; border: 1px solid #e5e7eb; }
.exp-logo-fallback { background: #f3f4f6; border: 1px solid #e5e7eb; }
.exp-logo-fallback span { color: #9ca3af; }
/* Type badges light */
.type-badge-blue { background: #eff6ff; color: #1d4ed8; border-color: #bfdbfe; }
.type-badge-amber { background: #fffbeb; color: #b45309; border-color: #fde68a; }
.type-badge-emerald { background: #ecfdf5; color: #047857; border-color: #a7f3d0; }
.type-badge-pink { background: #fdf2f8; color: #be185d; border-color: #fbcfe8; }
.type-badge-purple { background: #faf5ff; color: #7e22ce; border-color: #e9d5ff; }
/* Type borders light (RTL: border-right) */
.type-border-blue { border-right-color: #3b82f6 !important; }
.type-border-amber { border-right-color: #f59e0b !important; }
.type-border-emerald { border-right-color: #10b981 !important; }
.type-border-pink { border-right-color: #ec4899 !important; }
.type-border-purple { border-right-color: #a855f7 !important; }
/* ── Dark mode: translucent cards ── */
:global(.dark) .exp-card {
background: rgba(255, 255, 255, 0.03);
border-color: rgba(255, 255, 255, 0.08);
box-shadow: none;
}
:global(.dark) .exp-card:hover { background: rgba(255, 255, 255, 0.06); }
:global(.dark) .exp-card--ongoing {
background: rgba(255, 255, 255, 0.07);
border-color: rgba(255, 255, 255, 0.12);
box-shadow: none;
}
:global(.dark) .exp-card h3 { color: white !important; }
:global(.dark) .exp-card .exp-meta { color: rgba(255, 255, 255, 0.3); }
:global(.dark) .exp-card .exp-company { color: #d4b5ff; }
:global(.dark) .exp-card .exp-company a { color: #d4b5ff !important; }
:global(.dark) .exp-card .exp-company a:hover { color: white !important; }
:global(.dark) .exp-card .exp-content,
:global(.dark) .exp-card .exp-content p { color: rgba(255, 255, 255, 0.6) !important; }
:global(.dark) .exp-card .exp-content a { color: #d4b5ff !important; }
:global(.dark) .exp-card .exp-content a:hover { color: white !important; }
:global(.dark) .exp-card .exp-tech { background: rgba(255, 255, 255, 0.06); color: rgba(255, 255, 255, 0.45); border-color: rgba(255, 255, 255, 0.06); }
:global(.dark) .exp-logo { background: white; border-color: rgba(255, 255, 255, 0.2); box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2); }
:global(.dark) .exp-logo-fallback { background: rgba(255, 255, 255, 0.08); border-color: rgba(255, 255, 255, 0.1); }
:global(.dark) .exp-logo-fallback span { color: rgba(255, 255, 255, 0.4); }
/* Type badges dark */
:global(.dark) .type-badge-blue { background: rgba(96, 165, 250, 0.15); color: #93c5fd; border-color: rgba(96, 165, 250, 0.2); }
:global(.dark) .type-badge-amber { background: rgba(251, 191, 36, 0.15); color: #fcd34d; border-color: rgba(251, 191, 36, 0.2); }
:global(.dark) .type-badge-emerald { background: rgba(52, 211, 153, 0.15); color: #6ee7b7; border-color: rgba(52, 211, 153, 0.2); }
:global(.dark) .type-badge-pink { background: rgba(244, 114, 182, 0.15); color: #f9a8d4; border-color: rgba(244, 114, 182, 0.2); }
:global(.dark) .type-badge-purple { background: rgba(168, 85, 247, 0.15); color: #d4b5ff; border-color: rgba(168, 85, 247, 0.2); }
/* Type borders dark (RTL: border-right) */
:global(.dark) .type-border-blue { border-right-color: rgba(96, 165, 250, 0.4) !important; }
:global(.dark) .type-border-amber { border-right-color: rgba(251, 191, 36, 0.4) !important; }
:global(.dark) .type-border-emerald { border-right-color: rgba(52, 211, 153, 0.4) !important; }
:global(.dark) .type-border-pink { border-right-color: rgba(244, 114, 182, 0.4) !important; }
:global(.dark) .type-border-purple { border-right-color: rgba(168, 85, 247, 0.4) !important; }
</style>

View file

@ -2,6 +2,7 @@
import { getCollection, render } from "astro:content"; import { getCollection, render } from "astro:content";
import { Image } from "astro:assets"; import { Image } from "astro:assets";
import Layout from "../../layouts/main.astro"; import Layout from "../../layouts/main.astro";
import "../../styles/exp-card.css";
const logos = import.meta.glob<{ default: ImageMetadata }>('../../assets/images/companies/*.png', { eager: true }); const logos = import.meta.glob<{ default: ImageMetadata }>('../../assets/images/companies/*.png', { eager: true });
@ -91,12 +92,12 @@ function computeDuration(startStr: string, endStr?: string) {
</div> </div>
<div class:list={[ <div class:list={[
"exp-card relative rounded-2xl p-6 transition-colors duration-200 border-l-[3px]", "code-card exp-card relative rounded-2xl p-6 transition-colors duration-200 border-s-[3px]",
isOngoing ? "exp-card--ongoing" : "", isOngoing ? "exp-card--ongoing" : "",
colors.border colors.border
]}> ]}>
{getLogo(exp.data.logo) ? ( {getLogo(exp.data.logo) ? (
<div class="exp-logo absolute top-5 right-5 w-16 h-16 rounded-xl flex items-center justify-center p-2"> <div class="exp-logo absolute top-5 end-5 w-16 h-16 rounded-xl flex items-center justify-center p-2">
<Image <Image
src={getLogo(exp.data.logo)!} src={getLogo(exp.data.logo)!}
alt={`Logo ${exp.data.company}`} alt={`Logo ${exp.data.company}`}
@ -106,12 +107,12 @@ function computeDuration(startStr: string, endStr?: string) {
/> />
</div> </div>
) : ( ) : (
<div class="exp-logo-fallback absolute top-5 right-5 w-16 h-16 rounded-xl flex items-center justify-center"> <div class="exp-logo-fallback absolute top-5 end-5 w-16 h-16 rounded-xl flex items-center justify-center">
<span class="text-base font-bold">{getInitials(exp.data.company)}</span> <span class="text-base font-bold">{getInitials(exp.data.company)}</span>
</div> </div>
)} )}
<div class="mb-3 flex items-center gap-2 flex-wrap pr-20"> <div class="mb-3 flex items-center gap-2 flex-wrap pe-20">
<span class:list={["inline-block px-2 py-0.5 text-[11px] font-medium rounded-full border", colors.badge]}> <span class:list={["inline-block px-2 py-0.5 text-[11px] font-medium rounded-full border", colors.badge]}>
{label} {label}
</span> </span>
@ -122,7 +123,7 @@ function computeDuration(startStr: string, endStr?: string) {
{exp.data.location && <span class="exp-meta text-xs">· {exp.data.location}</span>} {exp.data.location && <span class="exp-meta text-xs">· {exp.data.location}</span>}
</div> </div>
<h3 class="text-xl font-bold pr-20">{exp.data.role}</h3> <h3 class="text-xl font-bold pe-20">{exp.data.role}</h3>
<p class="exp-company text-sm font-medium mt-1 mb-3"> <p class="exp-company text-sm font-medium mt-1 mb-3">
{exp.data.companyUrl ? ( {exp.data.companyUrl ? (
<a href={exp.data.companyUrl} target="_blank" rel="noopener noreferrer" class="transition-colors">{exp.data.company}</a> <a href={exp.data.companyUrl} target="_blank" rel="noopener noreferrer" class="transition-colors">{exp.data.company}</a>
@ -149,80 +150,3 @@ function computeDuration(startStr: string, endStr?: string) {
</div> </div>
</section> </section>
</Layout> </Layout>
<style>
/* ── Light mode (default): white cards on purple gradient ── */
.exp-card {
background: white;
border: 1px solid rgba(0, 0, 0, 0.06);
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
}
.exp-card--ongoing { box-shadow: 0 0 0 1px rgba(168, 85, 247, 0.25), 0 1px 3px rgba(0, 0, 0, 0.08); }
.exp-card h3 { color: #111827 !important; }
.exp-card .exp-meta { color: #9ca3af; }
.exp-card .exp-company { color: #6b21a8; }
.exp-card .exp-company a { color: #6b21a8 !important; text-decoration: none !important; }
.exp-card .exp-company a:hover { color: #581c87 !important; }
.exp-card .exp-content,
.exp-card .exp-content p { color: #4b5563 !important; }
.exp-card .exp-content a { color: #6b21a8 !important; text-decoration-color: rgba(107, 33, 168, 0.3) !important; }
.exp-card .exp-content a:hover { color: #581c87 !important; }
.exp-card .exp-tech { background: #f3f4f6; color: #6b7280; border-color: #e5e7eb; }
.exp-logo { background: #f9fafb; border: 1px solid #e5e7eb; }
.exp-logo-fallback { background: #f3f4f6; border: 1px solid #e5e7eb; }
.exp-logo-fallback span { color: #9ca3af; }
/* Type badges light */
.type-badge-blue { background: #eff6ff; color: #1d4ed8; border-color: #bfdbfe; }
.type-badge-amber { background: #fffbeb; color: #b45309; border-color: #fde68a; }
.type-badge-emerald { background: #ecfdf5; color: #047857; border-color: #a7f3d0; }
.type-badge-pink { background: #fdf2f8; color: #be185d; border-color: #fbcfe8; }
.type-badge-purple { background: #faf5ff; color: #7e22ce; border-color: #e9d5ff; }
/* Type borders light */
.type-border-blue { border-left-color: #3b82f6 !important; }
.type-border-amber { border-left-color: #f59e0b !important; }
.type-border-emerald { border-left-color: #10b981 !important; }
.type-border-pink { border-left-color: #ec4899 !important; }
.type-border-purple { border-left-color: #a855f7 !important; }
/* ── Dark mode: translucent cards ── */
:global(.dark) .exp-card {
background: rgba(255, 255, 255, 0.03);
border-color: rgba(255, 255, 255, 0.08);
box-shadow: none;
}
:global(.dark) .exp-card:hover { background: rgba(255, 255, 255, 0.06); }
:global(.dark) .exp-card--ongoing {
background: rgba(255, 255, 255, 0.07);
border-color: rgba(255, 255, 255, 0.12);
box-shadow: none;
}
:global(.dark) .exp-card h3 { color: white !important; }
:global(.dark) .exp-card .exp-meta { color: rgba(255, 255, 255, 0.3); }
:global(.dark) .exp-card .exp-company { color: #d4b5ff; }
:global(.dark) .exp-card .exp-company a { color: #d4b5ff !important; }
:global(.dark) .exp-card .exp-company a:hover { color: white !important; }
:global(.dark) .exp-card .exp-content,
:global(.dark) .exp-card .exp-content p { color: rgba(255, 255, 255, 0.6) !important; }
:global(.dark) .exp-card .exp-content a { color: #d4b5ff !important; }
:global(.dark) .exp-card .exp-content a:hover { color: white !important; }
:global(.dark) .exp-card .exp-tech { background: rgba(255, 255, 255, 0.06); color: rgba(255, 255, 255, 0.45); border-color: rgba(255, 255, 255, 0.06); }
:global(.dark) .exp-logo { background: white; border-color: rgba(255, 255, 255, 0.2); box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2); }
:global(.dark) .exp-logo-fallback { background: rgba(255, 255, 255, 0.08); border-color: rgba(255, 255, 255, 0.1); }
:global(.dark) .exp-logo-fallback span { color: rgba(255, 255, 255, 0.4); }
/* Type badges dark */
:global(.dark) .type-badge-blue { background: rgba(96, 165, 250, 0.15); color: #93c5fd; border-color: rgba(96, 165, 250, 0.2); }
:global(.dark) .type-badge-amber { background: rgba(251, 191, 36, 0.15); color: #fcd34d; border-color: rgba(251, 191, 36, 0.2); }
:global(.dark) .type-badge-emerald { background: rgba(52, 211, 153, 0.15); color: #6ee7b7; border-color: rgba(52, 211, 153, 0.2); }
:global(.dark) .type-badge-pink { background: rgba(244, 114, 182, 0.15); color: #f9a8d4; border-color: rgba(244, 114, 182, 0.2); }
:global(.dark) .type-badge-purple { background: rgba(168, 85, 247, 0.15); color: #d4b5ff; border-color: rgba(168, 85, 247, 0.2); }
/* Type borders dark */
:global(.dark) .type-border-blue { border-left-color: rgba(96, 165, 250, 0.4) !important; }
:global(.dark) .type-border-amber { border-left-color: rgba(251, 191, 36, 0.4) !important; }
:global(.dark) .type-border-emerald { border-left-color: rgba(52, 211, 153, 0.4) !important; }
:global(.dark) .type-border-pink { border-left-color: rgba(244, 114, 182, 0.4) !important; }
:global(.dark) .type-border-purple { border-left-color: rgba(168, 85, 247, 0.4) !important; }
</style>

View file

@ -2,6 +2,7 @@
import { getCollection, render } from "astro:content"; import { getCollection, render } from "astro:content";
import { Image } from "astro:assets"; import { Image } from "astro:assets";
import Layout from "../../../layouts/main.astro"; import Layout from "../../../layouts/main.astro";
import "../../../styles/exp-card.css";
const logos = import.meta.glob<{ default: ImageMetadata }>('../../../assets/images/companies/*.png', { eager: true }); const logos = import.meta.glob<{ default: ImageMetadata }>('../../../assets/images/companies/*.png', { eager: true });
@ -91,12 +92,12 @@ function computeDuration(startStr: string, endStr?: string) {
</div> </div>
<div class:list={[ <div class:list={[
"exp-card relative rounded-2xl p-6 transition-colors duration-200 border-l-[3px]", "code-card exp-card relative rounded-2xl p-6 transition-colors duration-200 border-s-[3px]",
isOngoing ? "exp-card--ongoing" : "", isOngoing ? "exp-card--ongoing" : "",
colors.border colors.border
]}> ]}>
{getLogo(exp.data.logo) ? ( {getLogo(exp.data.logo) ? (
<div class="exp-logo absolute top-5 right-5 w-16 h-16 rounded-xl flex items-center justify-center p-2"> <div class="exp-logo absolute top-5 end-5 w-16 h-16 rounded-xl flex items-center justify-center p-2">
<Image <Image
src={getLogo(exp.data.logo)!} src={getLogo(exp.data.logo)!}
alt={`${exp.data.company} logo`} alt={`${exp.data.company} logo`}
@ -106,12 +107,12 @@ function computeDuration(startStr: string, endStr?: string) {
/> />
</div> </div>
) : ( ) : (
<div class="exp-logo-fallback absolute top-5 right-5 w-16 h-16 rounded-xl flex items-center justify-center"> <div class="exp-logo-fallback absolute top-5 end-5 w-16 h-16 rounded-xl flex items-center justify-center">
<span class="text-base font-bold">{getInitials(exp.data.company)}</span> <span class="text-base font-bold">{getInitials(exp.data.company)}</span>
</div> </div>
)} )}
<div class="mb-3 flex items-center gap-2 flex-wrap pr-20"> <div class="mb-3 flex items-center gap-2 flex-wrap pe-20">
<span class:list={["inline-block px-2 py-0.5 text-[11px] font-medium rounded-full border", colors.badge]}> <span class:list={["inline-block px-2 py-0.5 text-[11px] font-medium rounded-full border", colors.badge]}>
{label} {label}
</span> </span>
@ -122,7 +123,7 @@ function computeDuration(startStr: string, endStr?: string) {
{exp.data.location && <span class="exp-meta text-xs">· {exp.data.location}</span>} {exp.data.location && <span class="exp-meta text-xs">· {exp.data.location}</span>}
</div> </div>
<h3 class="text-xl font-bold pr-20">{exp.data.role}</h3> <h3 class="text-xl font-bold pe-20">{exp.data.role}</h3>
<p class="exp-company text-sm font-medium mt-1 mb-3"> <p class="exp-company text-sm font-medium mt-1 mb-3">
{exp.data.companyUrl ? ( {exp.data.companyUrl ? (
<a href={exp.data.companyUrl} target="_blank" rel="noopener noreferrer" class="transition-colors">{exp.data.company}</a> <a href={exp.data.companyUrl} target="_blank" rel="noopener noreferrer" class="transition-colors">{exp.data.company}</a>
@ -149,80 +150,3 @@ function computeDuration(startStr: string, endStr?: string) {
</div> </div>
</section> </section>
</Layout> </Layout>
<style>
/* ── Light mode (default): white cards on purple gradient ── */
.exp-card {
background: white;
border: 1px solid rgba(0, 0, 0, 0.06);
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
}
.exp-card--ongoing { box-shadow: 0 0 0 1px rgba(168, 85, 247, 0.25), 0 1px 3px rgba(0, 0, 0, 0.08); }
.exp-card h3 { color: #111827 !important; }
.exp-card .exp-meta { color: #9ca3af; }
.exp-card .exp-company { color: #6b21a8; }
.exp-card .exp-company a { color: #6b21a8 !important; text-decoration: none !important; }
.exp-card .exp-company a:hover { color: #581c87 !important; }
.exp-card .exp-content,
.exp-card .exp-content p { color: #4b5563 !important; }
.exp-card .exp-content a { color: #6b21a8 !important; text-decoration-color: rgba(107, 33, 168, 0.3) !important; }
.exp-card .exp-content a:hover { color: #581c87 !important; }
.exp-card .exp-tech { background: #f3f4f6; color: #6b7280; border-color: #e5e7eb; }
.exp-logo { background: #f9fafb; border: 1px solid #e5e7eb; }
.exp-logo-fallback { background: #f3f4f6; border: 1px solid #e5e7eb; }
.exp-logo-fallback span { color: #9ca3af; }
/* Type badges light */
.type-badge-blue { background: #eff6ff; color: #1d4ed8; border-color: #bfdbfe; }
.type-badge-amber { background: #fffbeb; color: #b45309; border-color: #fde68a; }
.type-badge-emerald { background: #ecfdf5; color: #047857; border-color: #a7f3d0; }
.type-badge-pink { background: #fdf2f8; color: #be185d; border-color: #fbcfe8; }
.type-badge-purple { background: #faf5ff; color: #7e22ce; border-color: #e9d5ff; }
/* Type borders light */
.type-border-blue { border-left-color: #3b82f6 !important; }
.type-border-amber { border-left-color: #f59e0b !important; }
.type-border-emerald { border-left-color: #10b981 !important; }
.type-border-pink { border-left-color: #ec4899 !important; }
.type-border-purple { border-left-color: #a855f7 !important; }
/* ── Dark mode: translucent cards ── */
:global(.dark) .exp-card {
background: rgba(255, 255, 255, 0.03);
border-color: rgba(255, 255, 255, 0.08);
box-shadow: none;
}
:global(.dark) .exp-card:hover { background: rgba(255, 255, 255, 0.06); }
:global(.dark) .exp-card--ongoing {
background: rgba(255, 255, 255, 0.07);
border-color: rgba(255, 255, 255, 0.12);
box-shadow: none;
}
:global(.dark) .exp-card h3 { color: white !important; }
:global(.dark) .exp-card .exp-meta { color: rgba(255, 255, 255, 0.3); }
:global(.dark) .exp-card .exp-company { color: #d4b5ff; }
:global(.dark) .exp-card .exp-company a { color: #d4b5ff !important; }
:global(.dark) .exp-card .exp-company a:hover { color: white !important; }
:global(.dark) .exp-card .exp-content,
:global(.dark) .exp-card .exp-content p { color: rgba(255, 255, 255, 0.6) !important; }
:global(.dark) .exp-card .exp-content a { color: #d4b5ff !important; }
:global(.dark) .exp-card .exp-content a:hover { color: white !important; }
:global(.dark) .exp-card .exp-tech { background: rgba(255, 255, 255, 0.06); color: rgba(255, 255, 255, 0.45); border-color: rgba(255, 255, 255, 0.06); }
:global(.dark) .exp-logo { background: white; border-color: rgba(255, 255, 255, 0.2); box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2); }
:global(.dark) .exp-logo-fallback { background: rgba(255, 255, 255, 0.08); border-color: rgba(255, 255, 255, 0.1); }
:global(.dark) .exp-logo-fallback span { color: rgba(255, 255, 255, 0.4); }
/* Type badges dark */
:global(.dark) .type-badge-blue { background: rgba(96, 165, 250, 0.15); color: #93c5fd; border-color: rgba(96, 165, 250, 0.2); }
:global(.dark) .type-badge-amber { background: rgba(251, 191, 36, 0.15); color: #fcd34d; border-color: rgba(251, 191, 36, 0.2); }
:global(.dark) .type-badge-emerald { background: rgba(52, 211, 153, 0.15); color: #6ee7b7; border-color: rgba(52, 211, 153, 0.2); }
:global(.dark) .type-badge-pink { background: rgba(244, 114, 182, 0.15); color: #f9a8d4; border-color: rgba(244, 114, 182, 0.2); }
:global(.dark) .type-badge-purple { background: rgba(168, 85, 247, 0.15); color: #d4b5ff; border-color: rgba(168, 85, 247, 0.2); }
/* Type borders dark */
:global(.dark) .type-border-blue { border-left-color: rgba(96, 165, 250, 0.4) !important; }
:global(.dark) .type-border-amber { border-left-color: rgba(251, 191, 36, 0.4) !important; }
:global(.dark) .type-border-emerald { border-left-color: rgba(52, 211, 153, 0.4) !important; }
:global(.dark) .type-border-pink { border-left-color: rgba(244, 114, 182, 0.4) !important; }
:global(.dark) .type-border-purple { border-left-color: rgba(168, 85, 247, 0.4) !important; }
</style>

144
src/styles/exp-card.css Normal file
View file

@ -0,0 +1,144 @@
/*
* Experience card styles shared by FR, EN, AR career pages.
* Cards use the `.code-card` class to opt out of the layout's
* white-on-purple overrides (see main.astro).
*
* Light mode: white cards on purple gradient background.
* Dark mode: translucent cards blending into the gradient.
*/
/*
Card container
*/
.exp-card {
background: white;
border: 1px solid rgba(0, 0, 0, 0.06);
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
}
.exp-card--ongoing {
box-shadow: 0 0 0 1px rgba(168, 85, 247, 0.25),
0 1px 3px rgba(0, 0, 0, 0.08);
}
.dark .exp-card {
background: rgba(255, 255, 255, 0.03);
border-color: rgba(255, 255, 255, 0.08);
box-shadow: none;
}
.dark .exp-card:hover {
background: rgba(255, 255, 255, 0.06);
}
.dark .exp-card--ongoing {
background: rgba(255, 255, 255, 0.07);
border-color: rgba(255, 255, 255, 0.12);
box-shadow: none;
}
/*
Typography
*/
.exp-card h3 { color: #111827; }
.exp-card .exp-meta { color: #9ca3af; }
.exp-card .exp-company { color: #6b21a8; }
.exp-card .exp-company a { color: #6b21a8; text-decoration: none; }
.exp-card .exp-company a:hover { color: #581c87; }
.exp-card .exp-content,
.exp-card .exp-content p { color: #4b5563; }
.exp-card .exp-content a { color: #6b21a8; text-decoration-color: rgba(107, 33, 168, 0.3); }
.exp-card .exp-content a:hover { color: #581c87; }
.dark .exp-card h3 { color: white; }
.dark .exp-card .exp-meta { color: rgba(255, 255, 255, 0.3); }
.dark .exp-card .exp-company { color: #d4b5ff; }
.dark .exp-card .exp-company a { color: #d4b5ff; }
.dark .exp-card .exp-company a:hover { color: white; }
.dark .exp-card .exp-content,
.dark .exp-card .exp-content p { color: rgba(255, 255, 255, 0.6); }
.dark .exp-card .exp-content a { color: #d4b5ff; }
.dark .exp-card .exp-content a:hover { color: white; }
/*
Tech badges
*/
.exp-card .exp-tech {
background: #f3f4f6;
color: #6b7280;
border-color: #e5e7eb;
}
.dark .exp-card .exp-tech {
background: rgba(255, 255, 255, 0.06);
color: rgba(255, 255, 255, 0.45);
border-color: rgba(255, 255, 255, 0.06);
}
/*
Logo container
*/
.exp-logo {
background: #f9fafb;
border: 1px solid #e5e7eb;
}
.exp-logo-fallback {
background: #f3f4f6;
border: 1px solid #e5e7eb;
}
.exp-logo-fallback span {
color: #9ca3af;
}
.dark .exp-logo {
background: white;
border-color: rgba(255, 255, 255, 0.2);
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
}
.dark .exp-logo-fallback {
background: rgba(255, 255, 255, 0.08);
border-color: rgba(255, 255, 255, 0.1);
}
.dark .exp-logo-fallback span {
color: rgba(255, 255, 255, 0.4);
}
/*
Type badges
*/
.type-badge-blue { background: #eff6ff; color: #1d4ed8; border-color: #bfdbfe; }
.type-badge-amber { background: #fffbeb; color: #b45309; border-color: #fde68a; }
.type-badge-emerald { background: #ecfdf5; color: #047857; border-color: #a7f3d0; }
.type-badge-pink { background: #fdf2f8; color: #be185d; border-color: #fbcfe8; }
.type-badge-purple { background: #faf5ff; color: #7e22ce; border-color: #e9d5ff; }
.dark .type-badge-blue { background: rgba(96, 165, 250, 0.15); color: #93c5fd; border-color: rgba(96, 165, 250, 0.2); }
.dark .type-badge-amber { background: rgba(251, 191, 36, 0.15); color: #fcd34d; border-color: rgba(251, 191, 36, 0.2); }
.dark .type-badge-emerald { background: rgba(52, 211, 153, 0.15); color: #6ee7b7; border-color: rgba(52, 211, 153, 0.2); }
.dark .type-badge-pink { background: rgba(244, 114, 182, 0.15); color: #f9a8d4; border-color: rgba(244, 114, 182, 0.2); }
.dark .type-badge-purple { background: rgba(168, 85, 247, 0.15); color: #d4b5ff; border-color: rgba(168, 85, 247, 0.2); }
/*
Type border (left for LTR, right for RTL)
*/
.type-border-blue { border-inline-start-color: #3b82f6; }
.type-border-amber { border-inline-start-color: #f59e0b; }
.type-border-emerald { border-inline-start-color: #10b981; }
.type-border-pink { border-inline-start-color: #ec4899; }
.type-border-purple { border-inline-start-color: #a855f7; }
.dark .type-border-blue { border-inline-start-color: rgba(96, 165, 250, 0.4); }
.dark .type-border-amber { border-inline-start-color: rgba(251, 191, 36, 0.4); }
.dark .type-border-emerald { border-inline-start-color: rgba(52, 211, 153, 0.4); }
.dark .type-border-pink { border-inline-start-color: rgba(244, 114, 182, 0.4); }
.dark .type-border-purple { border-inline-start-color: rgba(168, 85, 247, 0.4); }