@custom-variant dark (&:where(.dark &, :root.dark &, [data-theme="dark"] &)); @import "tailwindcss"; @import "@nuxt/ui"; @import "./transitions.css"; @import "./prose.css"; @import "./blog-content.css"; @import "./resume-button.css"; @source "../../components/**/*.{vue,js,ts}"; @source "../../layouts/**/*.vue"; @source "../../pages/**/*.vue"; @source "../../app.vue"; @source "../../error.vue"; @source "../../composables/**/*.{js,ts}"; @source "../../plugins/**/*.{js,ts}"; @source "../../utils/**/*.{js,ts}"; @source "../../data/**/*.{js,ts}"; @source "../../../content/**/*.{md,json,yaml,yml}"; @theme { --font-sans: 'Geist', 'DM Sans', '-apple-system', 'ui-sans-serif', 'system-ui', 'sans-serif'; --font-display: 'Space Grotesk', 'Geist', 'ui-sans-serif', 'sans-serif'; } @layer base { @font-face { font-family: "Roobert"; font-style: normal; font-weight: 400; src: local(""), url("/fonts/Roobert-Regular.woff2") format("woff2"); } @font-face { font-family: "Roobert"; font-style: normal; font-weight: 500; src: local(""), url("/fonts/Roobert-Medium.woff2") format("woff2"); } @font-face { font-family: "Roobert"; font-style: normal; font-weight: 600; src: local(""), url("/fonts/Roobert-SemiBold.woff2") format("woff2"); } /* Persian variable font (Vazirmatn) — variable woff2 for best performance */ @font-face { font-family: "Vazirmatn"; font-style: normal; font-weight: 100 900; font-display: swap; src: local(""), url("/fonts/vazirmatn/webfonts/Vazirmatn[wght].woff2") format("woff2"); } html { overflow-y: scroll; /* Avoid width variation */ scroll-padding-top: 2rem; /* Offset for fixed navbar when using anchor links */ } html, body, #__nuxt, #__layout { @apply min-h-screen w-full; background: linear-gradient(135deg, #f8f9fc 0%, #faf5ff 50%, #fdf4ff 100%); color-scheme: light; } @media print { html, body, #__nuxt, #__layout { background: white !important; min-height: auto !important; } } .dark html, .dark body, .dark #__nuxt, .dark #__layout { /* fallback for SSR edge cases */ } :root.dark #__nuxt, :root.dark #__layout, html.dark, html.dark body, html.dark #__nuxt, html.dark #__layout { background: linear-gradient(135deg, #0a0a0f 0%, #18181b 50%, #1c1425 100%); color-scheme: dark; } @media print { :root.dark #__nuxt, :root.dark #__layout, html.dark, html.dark body, html.dark #__nuxt, html.dark #__layout { background: white !important; color-scheme: light !important; } } div, span, input, textarea, button, select, a { @apply focus:outline-hidden; -webkit-tap-highlight-color: rgba(0, 0, 0, 0); } /* Use the sans variable globally; switches automatically when we override variables */ html, body { font-family: var(--font-sans); } :root { --scrollbar-track: color-mix(in srgb, var(--ui-color-primary-100) 35%, transparent); --scrollbar-thumb: color-mix(in srgb, var(--ui-color-primary-500) 65%, var(--ui-color-primary-600) 35%); --scrollbar-thumb-hover: color-mix(in srgb, var(--ui-color-primary-500) 80%, var(--ui-color-primary-400) 20%); } :root.dark { --scrollbar-track: color-mix(in srgb, #0b1020 80%, var(--ui-color-primary-500) 20%); --scrollbar-thumb: color-mix(in srgb, var(--ui-color-primary-400) 65%, var(--ui-color-primary-500) 35%); --scrollbar-thumb-hover: color-mix(in srgb, var(--ui-color-primary-300) 75%, var(--ui-color-primary-400) 25%); } /* Global scrollbar styling */ * { scrollbar-width: thin; scrollbar-color: var(--scrollbar-thumb) var(--scrollbar-track); } *::-webkit-scrollbar { width: 8px; height: 8px; } *::-webkit-scrollbar-track { background: var(--scrollbar-track); border-radius: 9999px; } *::-webkit-scrollbar-thumb { background: linear-gradient(135deg, var(--scrollbar-thumb), color-mix(in oklch, var(--scrollbar-thumb), black 10%)); border-radius: 9999px; border: 2px solid color-mix(in oklch, var(--scrollbar-track), transparent 50%); } *::-webkit-scrollbar-thumb:hover { background: var(--scrollbar-thumb-hover); } /* In Persian/RTL, prefer Vazirmatn for both body and headings via variables */ html[dir="rtl"], html[lang^="fa"] { --font-sans: 'Vazirmatn', 'Geist', 'ui-sans-serif', 'system-ui', 'sans-serif'; --font-display: 'Vazirmatn', 'Space Grotesk', 'ui-sans-serif', 'sans-serif'; } /* Hide promotional banners from @nuxt/ui and certificates.dev */ [class*="VueSchool"], [class*="banner"][class*="promotional"], [data-v-inspector*="VueSchool"], #bb-banner, [id^="bb-"], [class*="bb-campaign"], [class*="bb-close"], a[href*="certificates.dev"] { display: none !important; visibility: hidden !important; height: 0 !important; overflow: hidden !important; } } @layer components { h1, h2, h3 { @apply font-display tracking-tight font-bold; background: linear-gradient(135deg, currentColor 0%, color-mix(in oklch, currentColor, var(--ui-color-primary-500) 30%) 100%); -webkit-background-clip: text; background-clip: text; } h1 { @apply text-4xl sm:text-5xl lg:text-6xl; letter-spacing: -0.02em; } h2 { @apply text-3xl sm:text-4xl lg:text-5xl; letter-spacing: -0.01em; } h3 { @apply text-2xl sm:text-3xl lg:text-4xl; } } @layer utilities { /** * THEME COLOR USAGE GUIDE * * Always use Nuxt UI CSS variables for primary colors: * - var(--ui-color-primary-500) for main primary color * - var(--ui-color-primary-400) for lighter shade * - var(--ui-color-primary-600) for darker shade * * Or use semantic Tailwind classes: * - text-primary, bg-primary, border-primary * * Never use hardcoded colors like: * - purple-500, violet-600, #a855f7 * * For gradients, use CSS variables: * background: linear-gradient(to right, * var(--ui-color-primary-600), * var(--ui-color-primary-500) * ); * * See docs/THEME-COLOR-GUIDE.md for detailed documentation. */ .primary-text { @apply text-primary; } .section-spacing { @apply pt-5 pb-8 sm:pt-8 sm:pb-12; } .section-title { @apply text-xl sm:text-2xl font-semibold leading-tight text-gray-900 dark:text-gray-100; } .section-header { @apply flex flex-wrap items-center gap-3 mb-5 sm:mb-6; } .primary-text-muted { @apply text-zinc-500 dark:text-zinc-400; } .decorated { @apply underline underline-offset-8 decoration-primary decoration-2; } /* Soft text color helpers */ .muted { @apply text-zinc-600 dark:text-zinc-300; } .gradient-text { background: linear-gradient( to right, var(--ui-color-primary-600), var(--ui-color-primary-500), var(--ui-color-primary-400) ); -webkit-background-clip: text; background-clip: text; color: transparent; } .dark .gradient-text { background: linear-gradient( to right, var(--ui-color-primary-400), var(--ui-color-primary-300), var(--ui-color-primary-200) ); -webkit-background-clip: text; background-clip: text; } .chip-base { @apply inline-flex items-center gap-1.5 rounded-2xl px-3 py-1.5 text-xs font-semibold ring-2 transition-all hover:scale-105 hover:shadow-xl backdrop-blur-md; --tw-ring-color: color-mix(in oklch, var(--ui-color-primary-400) 60%, transparent); background: linear-gradient( to bottom right, color-mix(in oklch, white 75%, transparent), color-mix(in oklch, var(--ui-color-primary-100) 80%, transparent) ); color: var(--ui-color-primary-700); box-shadow: 0 10px 15px -3px color-mix(in oklch, var(--ui-color-primary-500) 15%, transparent), 0 4px 6px -2px color-mix(in oklch, var(--ui-color-primary-500) 10%, transparent); border: 1px solid color-mix(in oklch, var(--ui-color-primary-300) 40%, transparent); } .chip-base:hover { --tw-ring-color: color-mix(in oklch, var(--ui-color-primary-500) 70%, transparent); box-shadow: 0 20px 25px -5px color-mix(in oklch, var(--ui-color-primary-500) 25%, transparent), 0 8px 10px -6px color-mix(in oklch, var(--ui-color-primary-500) 20%, transparent); } .dark .chip-base { --tw-ring-color: color-mix(in oklch, var(--ui-color-primary-600) 50%, transparent); background: linear-gradient( to bottom right, color-mix(in oklch, var(--ui-color-primary-950) 60%, transparent), color-mix(in oklch, var(--ui-color-primary-900) 40%, transparent) ); color: var(--ui-color-primary-200); box-shadow: 0 10px 15px -3px color-mix(in oklch, var(--ui-color-primary-500) 10%, transparent), 0 4px 6px -2px color-mix(in oklch, var(--ui-color-primary-500) 8%, transparent); border: 1px solid color-mix(in oklch, var(--ui-color-primary-700) 40%, transparent); } .dark .chip-base:hover { --tw-ring-color: color-mix(in oklch, var(--ui-color-primary-500) 60%, transparent); box-shadow: 0 20px 25px -5px color-mix(in oklch, var(--ui-color-primary-500) 15%, transparent), 0 8px 10px -6px color-mix(in oklch, var(--ui-color-primary-500) 12%, transparent); } /* Hide scrollbars for overflow containers */ .no-scrollbar, .scrollbar-hide { -ms-overflow-style: none; /* IE and Edge */ scrollbar-width: none; /* Firefox */ } .no-scrollbar::-webkit-scrollbar, .scrollbar-hide::-webkit-scrollbar { display: none; /* Chrome, Safari, Opera */ } /* Safe area bottom padding for devices with home indicator */ .safe-bottom { padding-bottom: env(safe-area-inset-bottom); } .glass-card { @apply rounded-3xl bg-white/80 dark:bg-zinc-900/50 backdrop-blur-xl border border-white/20 dark:border-zinc-800/50 transition-all duration-300; box-shadow: 0 20px 25px -5px color-mix(in oklch, var(--ui-color-primary-500) 5%, transparent); } .dark .glass-card { box-shadow: 0 20px 25px -5px color-mix(in oklch, var(--ui-color-primary-500) 10%, transparent); } .glass-card:hover { @apply translate-y-[-2px]; box-shadow: 0 25px 50px -12px color-mix(in srgb, var(--ui-color-primary-500) 10%, transparent); } .dark .glass-card:hover { box-shadow: 0 25px 50px -12px color-mix(in srgb, var(--ui-color-primary-500) 20%, transparent); } /* Global hover utilities for consistent interactions - using dynamic theme colors */ .hover-ring-tint { @apply transition-all duration-300 ease-out focus-visible:ring-offset-2 focus-visible:ring-offset-white dark:focus-visible:ring-offset-zinc-900; } .hover-ring-tint:hover { box-shadow: 0 0 0 2px var(--ui-color-primary-500); background-color: color-mix(in srgb, var(--ui-color-primary-50) 60%, transparent); } .dark .hover-ring-tint:hover { box-shadow: 0 0 0 2px var(--ui-color-primary-400); background-color: color-mix(in srgb, var(--ui-color-primary-400) 10%, transparent); } .hover-ring-tint:focus-visible { box-shadow: 0 0 0 2px var(--ui-color-primary-500); } .dark .hover-ring-tint:focus-visible { box-shadow: 0 0 0 2px var(--ui-color-primary-400); } .link-hover-clean { @apply transition-all duration-300 hover:underline underline-offset-4; } .link-hover-clean:hover { color: var(--ui-color-primary-600); text-decoration-color: color-mix(in srgb, var(--ui-color-primary-500) 60%, transparent); } .dark .link-hover-clean:hover { color: var(--ui-color-primary-400); text-decoration-color: color-mix(in srgb, var(--ui-color-primary-400) 60%, transparent); } } @layer utilities { /* Minimal hover: subtle bg tint, slight shadow, no ring/border change */ .hover-minimal { @apply transition-all duration-300 ease-out dark:hover:bg-white/5 hover:shadow-lg; } .hover-minimal:hover { background-color: color-mix(in srgb, var(--ui-color-primary-50) 50%, transparent); box-shadow: 0 10px 15px -3px color-mix(in srgb, var(--ui-color-primary-500) 5%, transparent); } .btn-modern { @apply inline-flex items-center justify-center px-6 py-3 rounded-2xl font-semibold text-white transition-all duration-300 hover:scale-105; background: linear-gradient(to right, var(--ui-color-primary-600), var(--ui-color-primary-500)); box-shadow: 0 10px 15px -3px color-mix(in oklch, var(--ui-color-primary-500) 30%, transparent); } .btn-modern:hover { background: linear-gradient(to right, var(--ui-color-primary-700), var(--ui-color-primary-600)); box-shadow: 0 20px 25px -5px color-mix(in oklch, var(--ui-color-primary-500) 40%, transparent); } } @layer utilities { .btn-outline-minimal { @apply backdrop-blur-sm transition-all duration-300 hover:shadow-lg; border: 1px solid color-mix(in oklch, var(--ui-color-primary-200) 60%, transparent); background: linear-gradient( to bottom right, color-mix(in oklch, white 60%, transparent), color-mix(in oklch, var(--ui-color-primary-50) 30%, transparent) ); } .btn-outline-minimal:hover { box-shadow: 0 10px 15px -3px color-mix(in oklch, var(--ui-color-primary-500) 10%, transparent); } .dark .btn-outline-minimal { border-color: color-mix(in oklch, var(--ui-color-primary-800) 50%, transparent); background: linear-gradient( to bottom right, color-mix(in oklch, white 5%, transparent), color-mix(in oklch, var(--ui-color-primary-950) 20%, transparent) ); } } @layer utilities { .chip-button { @apply inline-flex items-center justify-center h-12 w-12 rounded-2xl ring-2 backdrop-blur-md transition-all duration-300 ease-out hover:scale-110; --tw-ring-color: color-mix(in oklch, var(--ui-color-primary-400) 55%, transparent); background: linear-gradient( to bottom right, color-mix(in oklch, white 70%, transparent), color-mix(in oklch, var(--ui-color-primary-100) 75%, transparent) ); color: var(--ui-color-primary-700); box-shadow: 0 10px 15px -3px color-mix(in oklch, var(--ui-color-primary-500) 15%, transparent), 0 4px 6px -2px color-mix(in oklch, var(--ui-color-primary-500) 10%, transparent); border: 1px solid color-mix(in oklch, var(--ui-color-primary-300) 35%, transparent); } .chip-button:hover { --tw-ring-color: color-mix(in oklch, var(--ui-color-primary-500) 70%, transparent); background: linear-gradient( to bottom right, color-mix(in oklch, var(--ui-color-primary-50) 90%, transparent), color-mix(in oklch, var(--ui-color-primary-100) 95%, transparent) ); box-shadow: 0 20px 25px -5px color-mix(in oklch, var(--ui-color-primary-500) 25%, transparent), 0 8px 10px -6px color-mix(in oklch, var(--ui-color-primary-500) 20%, transparent); } .dark .chip-button { --tw-ring-color: color-mix(in oklch, var(--ui-color-primary-600) 45%, transparent); background: linear-gradient( to bottom right, color-mix(in oklch, white 15%, transparent), color-mix(in oklch, var(--ui-color-primary-950) 50%, transparent) ); color: var(--ui-color-primary-200); box-shadow: 0 10px 15px -3px color-mix(in oklch, var(--ui-color-primary-500) 10%, transparent), 0 4px 6px -2px color-mix(in oklch, var(--ui-color-primary-500) 8%, transparent); border: 1px solid color-mix(in oklch, var(--ui-color-primary-700) 35%, transparent); } .dark .chip-button:hover { --tw-ring-color: color-mix(in oklch, var(--ui-color-primary-500) 60%, transparent); background: linear-gradient( to bottom right, color-mix(in oklch, white 20%, transparent), color-mix(in oklch, var(--ui-color-primary-900) 60%, transparent) ); box-shadow: 0 20px 25px -5px color-mix(in oklch, var(--ui-color-primary-500) 15%, transparent), 0 8px 10px -6px color-mix(in oklch, var(--ui-color-primary-500) 12%, transparent); } /* GitHub Activity Contribution Graph - Dynamic Primary Color */ /* Level 0: No contributions - very neutral/muted color */ .contrib-level-0 { background-color: var(--ui-color-neutral-100); } /* Levels 1-4: More contributions = darker/more vibrant primary */ .contrib-level-1 { background-color: var(--ui-color-primary-200); } .contrib-level-2 { background-color: var(--ui-color-primary-400); } .contrib-level-3 { background-color: var(--ui-color-primary-600); } .contrib-level-4 { background-color: var(--ui-color-primary-800); } /* Dark mode overrides for contribution graph */ /* In dark mode: brighter = more contributions (same visual logic as light) */ .dark .contrib-level-0 { background-color: var(--ui-color-neutral-800); } .dark .contrib-level-1 { background-color: var(--ui-color-primary-950); } .dark .contrib-level-2 { background-color: var(--ui-color-primary-800); } .dark .contrib-level-3 { background-color: var(--ui-color-primary-600); } .dark .contrib-level-4 { background-color: var(--ui-color-primary-400); } } /* View Transitions ripple for theme switch (best-practice) */ @supports (view-transition-name: theme) { :root { view-transition-name: theme; } /* Configure transition pseudo-elements */ ::view-transition-old(theme), ::view-transition-new(theme) { animation-duration: var(--vtx-duration, 500ms); animation-timing-function: var(--vtx-easing, ease-in-out); } /* Old view: let new view reveal with ripple */ ::view-transition-old(theme) { animation: none; } /* New view: reveal from click origin via expanding circle */ ::view-transition-new(theme) { animation-name: vtx-reveal; } @keyframes vtx-reveal { from { clip-path: circle(0 at var(--vtx-x, 50vw) var(--vtx-y, 50vh)); } to { clip-path: circle(var(--vtx-end, 200vmax) at var(--vtx-x, 50vw) var(--vtx-y, 50vh)); } } } /* Fallback fade when View Transitions unsupported or prefers-reduced-motion */ .vtx-fade #__nuxt { animation: vtx-fade var(--vtx-duration, 500ms) var(--vtx-easing, ease-in-out); } @keyframes vtx-fade { from { opacity: 0.92; } to { opacity: 1; } } /* Reduced motion guard */ @media (prefers-reduced-motion: reduce) { :root { view-transition-name: none; } } /* Locale switch UX: top progress bar and quick page fade */ @layer utilities { .locale-progress { position: fixed; top: 0; left: 0; height: 3px; width: 100%; z-index: 1000; pointer-events: none; background-image: linear-gradient( to right, color-mix(in oklch, var(--ui-color-primary-500) 90%, transparent), color-mix(in oklch, var(--ui-color-primary-600) 90%, transparent) ); transform-origin: left center; animation: locale-progress-grow 600ms ease-out forwards; } @keyframes locale-progress-grow { from { transform: scaleX(0); opacity: 0.85; } to { transform: scaleX(1); opacity: 1; } } } /* Quick page fade during locale switching (client-only via documentElement class) */ .locale-switching #__nuxt { animation: locale-fade 600ms ease-out both; } @keyframes locale-fade { from { opacity: 0.92; filter: saturate(0.98); } to { opacity: 1; filter: saturate(1); } }