Overview
The theming system uses CSS variables (custom properties) to create a flexible, maintainable design token architecture. All theme values are defined in src/index.css and referenced throughout the application.
Design Tokens
Design tokens are defined in the :root selector using HSL color format:
@layer base {
:root {
--background : 220 20 % 7 % ;
--foreground : 210 20 % 92 % ;
--primary : 207 90 % 54 % ;
--radius : 0.75 rem ;
/* ... more tokens */
}
}
HSL values are stored without the hsl() wrapper, allowing flexible composition with opacity modifiers.
Color Palette
Core Colors
The application uses a dark color scheme optimized for professional portfolios:
Background Colors
Card Colors
Primary Brand
Secondary
--background: 220 20% 7%; /* Dark navy blue */
--foreground: 210 20% 92%; /* Light gray text */
Semantic Colors
Token HSL Value Usage --muted220 15% 13%Subtle backgrounds --muted-foreground215 15% 55%Dimmed text --accent207 90% 54%Highlights, links --destructive0 84.2% 60.2%Error states --border220 15% 18%Borders, dividers --input220 15% 18%Input borders --ring207 90% 54%Focus rings
Dedicated color tokens for sidebar components:
--sidebar-background: 220 18% 10%;
--sidebar-foreground: 210 20% 92%;
--sidebar-primary: 207 90% 54%;
--sidebar-primary-foreground: 220 20% 7%;
--sidebar-accent: 220 15% 15%;
--sidebar-accent-foreground: 210 20% 85%;
--sidebar-border: 220 15% 18%;
--sidebar-ring: 207 90% 54%;
Custom Design Tokens
Border Radius
A single radius variable controls corner roundness:
--radius: 0.75rem; /* 12px */
Tailwind extends this with calculated variations:
rounded-lg: var(--radius) → 12px
rounded-md: calc(var(--radius) - 2px) → 10px
rounded-sm: calc(var(--radius) - 4px) → 8px
Gradient Tokens
Hero Gradient
--hero-gradient: linear-gradient(
135deg,
hsl(220 20% 7%) 0%,
hsl(220 18% 12%) 50%,
hsl(207 40% 12%) 100%
);
Usage:
< section style = { { background: "var(--hero-gradient)" } } >
Hero content
</ section >
Glow Effects
--glow-primary: 0 0 60px hsl(207 90% 54% / 0 .15 );
--glow-strong: 0 0 120px hsl(207 90% 54% / 0 .25 );
Glow effects create depth and visual interest around primary UI elements.
Dark Mode Configuration
The application uses class-based dark mode:
Currently, the portfolio uses a dark theme by default. Light mode can be implemented by adding a .light class variant in CSS.
Implementing Light Mode
To add light mode support:
@layer base {
:root {
/* Dark theme (default) */
}
.light {
--background : 0 0 % 100 % ;
--foreground : 222.2 84 % 4.9 % ;
--primary : 207 90 % 54 % ;
/* ... light theme tokens */
}
}
Typography System
Font Imports
Fonts are imported from Google Fonts:
@import url ( 'https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&family=Inter:wght@300;400;500;600&display=swap' );
Font Application
Base styles apply fonts globally:
@layer base {
body {
@ apply bg-background text-foreground ;
font-family : 'Inter' , sans-serif ;
}
h1 , h2 , h3 , h4 , h5 , h6 {
font-family : 'Space Grotesk' , sans-serif ;
}
}
Inter (Body)
Space Grotesk (Headings)
Weights: 300, 400, 500, 600
Usage: Paragraphs, UI text
Optimized for readability
Weights: 300, 400, 500, 600, 700
Usage: All heading levels
Modern, geometric style
Custom Utility Classes
Three custom utilities are defined in the @layer utilities block:
Text Gradient
.text-gradient {
@ apply bg-clip-text text-transparent ;
background-image : linear-gradient (
135 deg ,
hsl ( 207 90 % 54 % ),
hsl ( 207 80 % 70 % )
);
}
Usage:
< span className = "text-gradient" > Carrascosa </ span >
Creates a vibrant blue gradient text effect.
Border Glow
.border-glow {
border-color : hsl ( 207 90 % 54 % / 0.3 );
box-shadow : var ( --glow-primary );
}
Usage:
< div className = "border border-glow" >
Card with glowing border
</ div >
Section Divider
.section-divider {
@ apply w-full h-px ;
background : linear-gradient (
90 deg ,
transparent ,
hsl ( 207 90 % 54 % / 0.3 ),
transparent
);
}
Usage:
< div className = "section-divider" />
Creates a horizontal gradient divider line.
Color Usage in Components
HeroSection Example
< motion.p className = "text-primary font-heading text-sm tracking-[0.3em] uppercase mb-6" >
Chief Technology Officer
</ motion.p >
< motion.p className = "text-muted-foreground text-lg md:text-xl" >
+20 años liderando tecnología...
< span className = "text-primary font-medium" > Grupo SADE </ span > .
</ motion.p >
< motion.p className = "text-muted-foreground/60 text-sm" >
Madrid, España
</ motion.p >
Navbar Example
< motion.nav className = {
scrolled
? "bg-background/80 backdrop-blur-lg border-b border-border"
: ""
} >
< a className = "text-sm text-muted-foreground hover:text-foreground" >
Sobre mí
</ a >
</ motion.nav >
Why HSL? HSL (Hue, Saturation, Lightness) makes it easy to create color variations while maintaining visual harmony.
Opacity Modifiers
Tailwind’s opacity syntax works seamlessly:
< div className = "bg-background/80" > { /* 80% opacity */ }
< p className = "text-muted-foreground/60" > { /* 60% opacity */ }
Color Consistency
Changing a single CSS variable updates the color throughout:
/* Change primary color globally */
--primary: 142 76% 36%; /* Now green instead of blue */
Theming Best Practices
Use CSS Variables : Always reference tokens, never hardcode colors
Maintain Contrast : Ensure foreground/background pairs have sufficient contrast
Test Opacity : Verify colors work at different opacity levels
Semantic Naming : Use purpose-based names (primary, muted) over descriptive ones (blue, gray)
Customization Guide
Changing the Primary Color
:root {
--primary : 142 76 % 36 % ; /* Green */
--ring : 142 76 % 36 % ; /* Update focus ring */
--accent : 142 76 % 36 % ; /* Update accent */
--sidebar-primary : 142 76 % 36 % ; /* Update sidebar */
}
Update gradient utilities:
.text-gradient {
background-image : linear-gradient (
135 deg ,
hsl ( 142 76 % 36 % ),
hsl ( 142 70 % 50 % )
);
}
Adjusting Border Radius
--radius: 0.5rem; /* More subtle corners */
--radius: 1rem; /* Rounder corners */
--radius: 0; /* Sharp corners */