@tailwind base; @tailwind components; @tailwind utilities; @layer base { :root { --background: 0 0% 100%; --foreground: 222.2 84% 4.9%; --card: 0 0% 100%; --card-foreground: 222.2 84% 4.9%; --popover: 0 0% 100%; --popover-foreground: 222.2 84% 4.9%; --primary: 222.2 47.4% 11.2%; --primary-foreground: 210 40% 98%; --secondary: 210 40% 96.1%; --secondary-foreground: 222.2 47.4% 11.2%; --muted: 210 40% 96.1%; --muted-foreground: 215.4 16.3% 46.9%; --accent: 210 40% 96.1%; --accent-foreground: 222.2 47.4% 11.2%; --destructive: 0 84.2% 60.2%; --destructive-foreground: 210 40% 98%; --border: 214.3 31.8% 91.4%; --input: 214.3 31.8% 91.4%; --ring: 222.2 84% 4.9%; --radius: 0.5rem; } .dark { --background: 222.2 84% 4.9%; --foreground: 210 40% 98%; --card: 222.2 84% 4.9%; --card-foreground: 210 40% 98%; --popover: 222.2 84% 4.9%; --popover-foreground: 210 40% 98%; --primary: 210 40% 98%; --primary-foreground: 222.2 47.4% 11.2%; --secondary: 217.2 32.6% 17.5%; --secondary-foreground: 210 40% 98%; --muted: 217.2 32.6% 17.5%; --muted-foreground: 215 20.2% 65.1%; --accent: 217.2 32.6% 17.5%; --accent-foreground: 210 40% 98%; --destructive: 0 62.8% 30.6%; --destructive-foreground: 210 40% 98%; --border: 217.2 32.6% 17.5%; --input: 217.2 32.6% 17.5%; --ring: 212.7 26.8% 83.9%; } } @layer base { * { @apply border-border; } body { @apply bg-background text-foreground; } } @layer components { /* High-contrast content masking for accessibility and streamer protection */ .mask-backdrop { background-color: hsl(var(--card) / 0.98); backdrop-filter: blur(64px); -webkit-backdrop-filter: blur(64px); border-width: 2px; border-color: hsl(var(--border) / 0.5); box-shadow: 0 25px 50px -12px rgb(0 0 0 / 0.25); position: relative; overflow: hidden; transition: transform 300ms cubic-bezier(0.16, 1, 0.3, 1), box-shadow 300ms cubic-bezier(0.16, 1, 0.3, 1), border-color 300ms ease; } .section-container { @apply mask-backdrop rounded-[2.5rem] p-12 md:p-20 text-card-foreground; } .glass-card { @apply mask-backdrop rounded-[2rem] p-10 text-card-foreground; } .glass-card:hover { border-color: hsl(var(--primary) / 0.3); } /* Bento grid entrance animation */ @keyframes bento-enter { from { opacity: 0; transform: translateY(16px); } to { opacity: 1; transform: translateY(0); } } .bento-item { animation: bento-enter 0.5s cubic-bezier(0.16, 1, 0.3, 1) both; } /* Quiet bento: at rest the card chrome (opaque bg, 64px frost, border, shadow) is nearly invisible so only the title + the 3D render/image float on the page; the glass lights up on hover / focus / tap. Title + image keep their own visibility. Higher specificity than .mask-backdrop, so it wins at rest without !important. */ .bento-item .glass-card { background-color: transparent; backdrop-filter: none; -webkit-backdrop-filter: none; border-color: transparent; box-shadow: none; transition: background-color 0.3s ease, backdrop-filter 0.3s ease, border-color 0.3s ease, box-shadow 0.3s ease, transform 0.3s ease; } .bento-item:hover .glass-card, .bento-item:focus-within .glass-card { backdrop-filter: blur(64px); -webkit-backdrop-filter: blur(64px); transform: translateY(-4px); box-shadow: 0 32px 64px -16px rgb(0 0 0 / 0.3); } /* Focus-visible ring for keyboard navigation */ .bento-item:focus-visible { outline: 2px solid hsl(var(--ring)); outline-offset: 4px; border-radius: 2.5rem; } /* Respect reduced motion preferences */ @media (prefers-reduced-motion: reduce) { .bento-item { animation: none; } .bento-item:hover .glass-card { transform: none; } .glass-card { transition: border-color 300ms; } .glass-card .object-contain, .glass-card .object-cover { transition: none !important; } } /* Typography customization for blog posts */ .prose { --tw-prose-body: hsl(var(--foreground)); --tw-prose-headings: hsl(var(--foreground)); --tw-prose-lead: hsl(var(--muted-foreground)); --tw-prose-links: hsl(var(--primary)); --tw-prose-bold: hsl(var(--foreground)); --tw-prose-counters: hsl(var(--muted-foreground)); --tw-prose-bullets: hsl(var(--muted-foreground)); --tw-prose-hr: hsl(var(--border)); --tw-prose-quotes: hsl(var(--foreground)); --tw-prose-quote-borders: hsl(var(--border)); --tw-prose-captions: hsl(var(--muted-foreground)); --tw-prose-code: hsl(var(--foreground)); --tw-prose-pre-code: hsl(var(--foreground)); --tw-prose-pre-bg: hsl(var(--muted)); --tw-prose-th-borders: hsl(var(--border)); --tw-prose-td-borders: hsl(var(--border)); } .prose h2 { @apply text-xl font-semibold mt-10 mb-4 pb-2 border-b border-border; } .prose h3 { @apply text-lg font-medium mt-6 mb-3; } .prose p { @apply leading-relaxed mb-4; } .prose ul { @apply my-4 ml-4 space-y-2; } .prose li { @apply leading-relaxed; } .prose a { @apply text-emerald-600 dark:text-emerald-400 underline underline-offset-2 hover:text-emerald-700 dark:hover:text-emerald-300 transition-colors; } .prose strong { @apply font-semibold; } .prose hr { @apply my-8 border-border; } .prose table { @apply w-full my-6 text-sm; } .prose thead th { @apply text-left font-semibold p-3 bg-muted/50 border-b border-border; } .prose tbody td { @apply p-3 border-b border-border; } .prose tbody tr:hover { @apply bg-muted/30; } } /* Respect users who prefer reduced motion */ @media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; scroll-behavior: auto !important; } } /* Splash logo zoom on click-to-enter (CSS, so the logo needs no framer-motion wrapper and stays a clean LCP candidate). */ @keyframes splash-zoom { 0% { transform: scale(1); } 50% { transform: scale(1.06); } 100% { transform: scale(1.14); } } .splash-zoom { animation: splash-zoom 0.8s ease-in-out forwards; } /* Click-to-enter Cherenkov wash (was framer-motion; now CSS so the splash ships no JS animation library). */ @keyframes splash-wash { 0% { opacity: 0; } 50% { opacity: 0.9; } 100% { opacity: 0; } } .splash-wash { animation: splash-wash 0.8s ease-in-out forwards; } /* Tiny terminal inside the nebula monitor: type "such" once, backspace, then a blinking caret on the left. width via steps() is the typewriter; border-right is the caret. */ .nebula-term { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 9px; line-height: 1; letter-spacing: 0.5px; white-space: nowrap; overflow: hidden; width: 0; border-right: 1.5px solid currentColor; /* type "such", hold, backspace (nebula-type, once); blink a finite number of times (nebula-caret); then fade the whole thing out so it stops being distracting. */ /* blink ~4 times, type "such", backspace, blink ~4 more, then fade away. */ animation: nebula-type 2.2s steps(4, end) 3.2s forwards, nebula-caret 0.8s steps(1, end) 11, nebula-term-out 0.6s ease-in 8.4s forwards; } @keyframes nebula-type { 0% { width: 0; } 36% { width: 4ch; } 64% { width: 4ch; } 90% { width: 0; } 100% { width: 0; } } @keyframes nebula-caret { 0%, 50% { border-color: currentColor; } 50.01%, 100% { border-color: transparent; } } @keyframes nebula-term-out { to { opacity: 0; } } /* Hero title: an animated gradient sheen. LCP-safe — the text paints immediately with the gradient; only the gradient POSITION animates, which never delays the largest paint. The global reduced-motion rule freezes it to the base gradient. */ /* The brand's four-colour system (S green, U magenta, C blue, H teal), one per glyph. Light theme uses the light palette; .dark swaps in the dark palette, which is the same hues lifted for contrast on near-black -- from packs/such-software/pack.json. */ .hero-title { background-image: linear-gradient(110deg, #1a5c38 0%, #b83670 30%, #176a92 55%, #12857e 80%, #1a5c38 100%); background-size: 220% auto; -webkit-background-clip: text; background-clip: text; color: transparent; animation: hero-sheen 9s ease-in-out infinite; } .dark .hero-title { background-image: linear-gradient(110deg, #35925c 0%, #e8689e 30%, #4aade0 55%, #3ad4c6 80%, #35925c 100%); } .brand-gradient-text { background-image: linear-gradient(90deg, #1a5c38, #b83670, #176a92, #12857e); -webkit-background-clip: text; background-clip: text; color: transparent; } .dark .brand-gradient-text { background-image: linear-gradient(90deg, #35925c, #e8689e, #4aade0, #3ad4c6); } @keyframes hero-sheen { 0%, 100% { background-position: 0% center; } 50% { background-position: 100% center; } } /* Soft aura behind the hero title (decorative). Gentle breathing scale/opacity. */ @keyframes hero-aura { 0%, 100% { opacity: 0.55; transform: translateX(-50%) scale(1); } 50% { opacity: 0.8; transform: translateX(-50%) scale(1.08); } } .hero-aura { animation: hero-aura 7s ease-in-out infinite; }