@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"; @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'; --color-primary-50: oklch(0.98 0.01 280); --color-primary-100: oklch(0.95 0.03 280); --color-primary-200: oklch(0.89 0.08 280); --color-primary-300: oklch(0.80 0.15 280); --color-primary-400: oklch(0.70 0.22 280); --color-primary-500: oklch(0.60 0.25 280); --color-primary-600: oklch(0.50 0.22 280); --color-primary-700: oklch(0.42 0.18 280); --color-primary-800: oklch(0.34 0.14 280); --color-primary-900: oklch(0.28 0.10 280); --color-primary-950: oklch(0.18 0.06 280); } @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; } .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; } 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); } /* 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 */ [class*="VueSchool"], [class*="banner"][class*="promotional"], [data-v-inspector*="VueSchool"] { display: none !important; } } @layer components { h1, h2, h3 { @apply font-display tracking-tight font-bold; background: linear-gradient(135deg, currentColor 0%, color-mix(in oklch, currentColor, violet 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 { .primary-text { @apply text-violet-600 dark:text-violet-400; } .primary-text-muted { @apply text-zinc-500 dark:text-zinc-400; } .decorated { @apply underline underline-offset-8 decoration-violet-500 dark:decoration-violet-400 decoration-2; } /* Soft text color helpers */ .muted { @apply text-zinc-600 dark:text-zinc-300; } /* Gradient text effect */ .gradient-text { @apply bg-gradient-to-r from-violet-600 via-purple-600 to-fuchsia-600 dark:from-violet-400 dark:via-purple-400 dark:to-fuchsia-400 bg-clip-text text-transparent; } .chip-base { @apply inline-flex items-center gap-1.5 rounded-2xl px-3 py-1.5 text-xs font-semibold ring-1 ring-violet-200/70 bg-gradient-to-br from-white/90 to-violet-50/60 text-violet-700 shadow-lg shadow-violet-500/10 backdrop-blur-md dark:from-violet-950/40 dark:to-violet-900/20 dark:text-violet-200 dark:ring-violet-800/50 dark:shadow-violet-500/5 transition-all hover:scale-105 hover:shadow-xl hover:shadow-violet-500/20; } /* 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); } /* Modern glassmorphic card */ .glass-card { @apply rounded-3xl bg-white/80 dark:bg-zinc-900/50 backdrop-blur-xl shadow-xl shadow-violet-500/5 dark:shadow-violet-500/10 border border-white/20 dark:border-zinc-800/50 transition-all duration-300; } .glass-card:hover { @apply shadow-2xl shadow-violet-500/10 dark:shadow-violet-500/20 translate-y-[-2px]; } /* Global hover utilities for consistent interactions */ .hover-ring-tint { @apply transition-all duration-300 ease-out ring-0 hover:ring-2 hover:ring-violet-500 dark:hover:ring-violet-400 hover:bg-violet-50/60 dark:hover:bg-violet-400/10 focus-visible:ring-2 focus-visible:ring-violet-500 dark:focus-visible:ring-violet-400 focus-visible:ring-offset-2 focus-visible:ring-offset-white dark:focus-visible:ring-offset-zinc-900; } .link-hover-clean { @apply transition-all duration-300 hover:text-violet-600 dark:hover:text-violet-400 hover:underline underline-offset-4 decoration-violet-500/60 dark:decoration-violet-400/60; } } @layer utilities { /* Minimal hover: subtle bg tint, slight shadow, no ring/border change */ .hover-minimal { @apply transition-all duration-300 ease-out hover:bg-violet-50/50 dark:hover:bg-white/5 hover:shadow-lg hover:shadow-violet-500/5; } /* Modern button with gradient */ .btn-modern { @apply inline-flex items-center justify-center px-6 py-3 rounded-2xl font-semibold text-white bg-gradient-to-r from-violet-600 to-purple-600 hover:from-violet-700 hover:to-purple-700 shadow-lg shadow-violet-500/30 hover:shadow-xl hover:shadow-violet-500/40 transition-all duration-300 hover:scale-105; } } @layer utilities { /* Minimal outlined button: persistent subtle border and light background; hover handled separately */ .btn-outline-minimal { @apply border border-violet-200/60 dark:border-violet-800/50 bg-gradient-to-br from-white/60 to-violet-50/30 dark:from-white/5 dark:to-violet-950/20 backdrop-blur-sm transition-all duration-300 hover:shadow-lg hover:shadow-violet-500/10; } } @layer utilities { /* Chip-style icon button inspired by SkillGrid: subtle ring, soft bg, minimal hover */ .chip-button { @apply inline-flex items-center justify-center h-12 w-12 rounded-2xl ring-1 ring-violet-200/70 dark:ring-violet-800/50 bg-gradient-to-br from-white/90 to-violet-50/50 dark:from-white/10 dark:to-violet-950/30 text-violet-700 dark:text-violet-200 shadow-lg shadow-violet-500/10 backdrop-blur-md transition-all duration-300 ease-out hover:scale-110 hover:shadow-xl hover:shadow-violet-500/20 hover:from-violet-50 hover:to-violet-100 dark:hover:from-white/15 dark:hover:to-violet-900/40; } } /* 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; /* Use primary color gradient; adapt in dark mode */ background-image: linear-gradient(to right, rgb(99 102 241 / 0.9), /* indigo-500 */ rgb(139 92 246 / 0.9) /* violet-500 */ ); 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); } }