@tailwind base; @tailwind components; @tailwind utilities; @layer base { :root { /* RASAD Premium Dark Design System */ --background: 220 20% 5%; /* #0A0C0F INK */ --foreground: 40 25% 92%; --surface: 215 30% 9%; /* #0F1722 deep navy */ --surface-2: 215 25% 12%; --paper: 42 27% 92%; /* #F0EDE6 */ --card: 215 30% 9%; --card-foreground: 40 25% 92%; --popover: 215 30% 9%; --popover-foreground: 40 25% 92%; --primary: 5 65% 48%; /* signal red #C8392D */ --primary-foreground: 0 0% 100%; --primary-glow: 5 80% 58%; --secondary: 215 25% 14%; --secondary-foreground: 40 25% 92%; --muted: 215 20% 14%; --muted-foreground: 0 0% 60%; --accent: 5 65% 48%; --accent-foreground: 0 0% 100%; --verified: 152 68% 32%; /* #1A8A5A */ --verified-foreground: 0 0% 100%; --warning: 36 80% 52%; /* #E8A020 */ --warning-foreground: 0 0% 8%; --info: 212 50% 63%; /* #6B9BD4 */ --info-foreground: 0 0% 8%; --destructive: 5 65% 48%; --destructive-foreground: 0 0% 100%; --border: 0 0% 100% / 0.08; --input: 215 25% 14%; --ring: 5 65% 48%; --radius: 0.75rem; --gradient-hero: radial-gradient(ellipse at top right, hsl(5 65% 48% / 0.15), transparent 60%), radial-gradient(ellipse at bottom left, hsl(212 50% 30% / 0.18), transparent 55%); --gradient-signal: linear-gradient(135deg, hsl(5 65% 48%), hsl(5 80% 58%)); --gradient-card: linear-gradient(180deg, hsl(215 30% 11% / 0.9), hsl(215 30% 7% / 0.95)); --shadow-glow: 0 0 40px hsl(5 65% 48% / 0.25); --shadow-elev: 0 12px 40px -12px hsl(0 0% 0% / 0.6); --sidebar-background: 215 30% 9%; --sidebar-foreground: 40 25% 92%; --sidebar-primary: 5 65% 48%; --sidebar-primary-foreground: 0 0% 100%; --sidebar-accent: 215 25% 14%; --sidebar-accent-foreground: 40 25% 92%; --sidebar-border: 0 0% 100% / 0.06; --sidebar-ring: 5 65% 48%; /* Surface tokens used by themed UI primitives */ --surface-elev: 215 30% 11%; --surface-elev-2: 215 30% 14%; --hairline: 0 0% 100% / 0.08; --hairline-strong: 0 0% 100% / 0.14; --hover-overlay: 0 0% 100% / 0.04; --scroll-track: 0 0% 100% / 0.06; --scroll-thumb: 0 0% 100% / 0.12; } /* ─── LIGHT THEME — modern clean palette (Linear/Stripe/Notion-feel) ─── */ html.light { --background: 220 20% 98%; /* #F8FAFB — clean neutral */ --foreground: 222 47% 11%; /* slate-900 */ --surface: 0 0% 100%; /* pure white card */ --surface-2: 220 14% 96%; /* slate-100 */ --paper: 220 20% 98%; --card: 0 0% 100%; --card-foreground: 222 47% 11%; --popover: 0 0% 100%; --popover-foreground: 222 47% 11%; --primary: 5 78% 46%; /* brand red, slightly desaturated */ --primary-foreground: 0 0% 100%; --primary-glow: 5 84% 56%; --secondary: 220 14% 95%; --secondary-foreground: 222 47% 11%; --muted: 220 14% 96%; --muted-foreground: 215 16% 47%; /* slate-600 — readable but soft */ --accent: 5 78% 46%; --accent-foreground: 0 0% 100%; --verified: 152 60% 32%; --verified-foreground: 0 0% 100%; --warning: 32 95% 44%; --warning-foreground: 0 0% 100%; --info: 212 70% 42%; --info-foreground: 0 0% 100%; --destructive: 5 78% 46%; --destructive-foreground: 0 0% 100%; --border: 220 13% 91%; /* slate-200 — crisp hairline */ --input: 220 14% 95%; --ring: 5 78% 46%; --gradient-hero: radial-gradient(ellipse at top right, hsl(5 84% 56% / 0.10), transparent 65%), radial-gradient(ellipse at bottom left, hsl(212 70% 56% / 0.10), transparent 65%); --gradient-signal: linear-gradient(135deg, hsl(5 78% 46%), hsl(5 84% 56%)); --gradient-card: linear-gradient(180deg, #ffffff, #fdfdfd); --shadow-glow: 0 8px 24px -10px hsl(5 78% 46% / 0.25); --shadow-elev: 0 1px 2px hsl(222 47% 11% / 0.04), 0 4px 12px -4px hsl(222 47% 11% / 0.06), 0 12px 32px -16px hsl(222 47% 11% / 0.06); --sidebar-background: 0 0% 100%; --sidebar-foreground: 222 47% 11%; --sidebar-primary: 5 78% 46%; --sidebar-primary-foreground: 0 0% 100%; --sidebar-accent: 220 14% 96%; --sidebar-accent-foreground: 222 47% 11%; --sidebar-border: 220 13% 91%; --sidebar-ring: 5 78% 46%; --surface-elev: 0 0% 100%; /* pure white */ --surface-elev-2: 220 14% 96%; /* slate-100 */ --hairline: 220 13% 91%; /* solid, no alpha — predictable */ --hairline-strong: 220 13% 82%; --hover-overlay: 220 14% 94%; --scroll-track: 220 14% 94%; --scroll-thumb: 220 10% 70%; } } @layer base { * { @apply border-border; } html { font-family: 'Noto Kufi Arabic', system-ui, sans-serif; scroll-behavior: smooth; } @media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } *, *::before, *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; scroll-behavior: auto !important; } } /* Anchor offsets so headers don't get hidden under the sticky navbar */ :target, [id^="verify-"], [id^="section-"] { scroll-margin-top: 96px; } /* Better focus rings */ *:focus-visible { outline: 2px solid hsl(var(--primary) / 0.6); outline-offset: 2px; border-radius: 6px; } /* Custom scrollbar (subtle, theme-aware) */ ::-webkit-scrollbar { width: 10px; height: 10px; } ::-webkit-scrollbar-track { background: hsl(var(--scroll-track)); } ::-webkit-scrollbar-thumb { background: hsl(var(--scroll-thumb)); border-radius: 999px; border: 2px solid transparent; background-clip: padding-box; } ::-webkit-scrollbar-thumb:hover { background: hsl(var(--primary) / 0.4); background-clip: padding-box; } body { @apply bg-background text-foreground antialiased; background-image: radial-gradient(ellipse at 20% -10%, hsl(var(--primary) / 0.08), transparent 50%), radial-gradient(ellipse at 90% 10%, hsl(var(--info) / 0.06), transparent 50%), linear-gradient(hsl(var(--foreground) / 0.015) 1px, transparent 1px), linear-gradient(90deg, hsl(var(--foreground) / 0.015) 1px, transparent 1px); background-size: auto, auto, 56px 56px, 56px 56px; transition: background-color 280ms ease, color 280ms ease; } html.light body { background-image: radial-gradient(ellipse 100% 60% at 20% -20%, hsl(5 84% 60% / 0.06), transparent 60%), radial-gradient(ellipse 100% 60% at 90% 5%, hsl(212 70% 56% / 0.05), transparent 60%); background-attachment: fixed; } /* Light-mode: rewrite hardcoded white-opacity tailwind classes that exist throughout the legacy pages so they don't render as pure-white overlays on the warm-paper background. We re-map them to a dark-ink overlay tuned to feel similar to the original dark-mode contrast ratio. */ html.light .bg-white\/\[0\.02\] { background-color: hsl(220 15% 20% / 0.025) !important; } html.light .bg-white\/\[0\.03\] { background-color: hsl(220 15% 20% / 0.035) !important; } html.light .bg-white\/\[0\.04\] { background-color: hsl(220 15% 20% / 0.045) !important; } html.light .bg-white\/\[0\.05\] { background-color: hsl(220 15% 20% / 0.05) !important; } html.light .bg-white\/\[0\.06\] { background-color: hsl(220 15% 20% / 0.06) !important; } html.light .bg-white\/\[0\.08\] { background-color: hsl(220 15% 20% / 0.07) !important; } html.light .bg-white\/\[0\.10\] { background-color: hsl(220 15% 20% / 0.09) !important; } html.light .bg-white\/\[0\.12\] { background-color: hsl(220 15% 20% / 0.11) !important; } html.light .border-white\/\[0\.04\] { border-color: hsl(220 15% 40% / 0.18) !important; } html.light .border-white\/\[0\.05\] { border-color: hsl(220 15% 40% / 0.20) !important; } html.light .border-white\/\[0\.06\] { border-color: hsl(220 15% 40% / 0.22) !important; } html.light .border-white\/\[0\.08\] { border-color: hsl(220 15% 40% / 0.24) !important; } html.light .border-white\/\[0\.10\] { border-color: hsl(220 15% 40% / 0.28) !important; } html.light .border-white\/\[0\.12\] { border-color: hsl(220 15% 40% / 0.32) !important; } html.light .border-white\/\[0\.14\] { border-color: hsl(220 15% 40% / 0.36) !important; } html.light .ring-white\/10 { --tw-ring-color: hsl(220 15% 40% / 0.22) !important; } html.light .ring-white\/20 { --tw-ring-color: hsl(220 15% 40% / 0.30) !important; } /* Shadow blocks tuned with rgba(0,0,0,...) become invisible on paper; lift them */ html.light .shadow-\[0_24px_60px_-12px_rgba\(0\,0\,0\,0\.55\)\], html.light .shadow-\[0_8px_32px_-8px_rgba\(0\,0\,0\,0\.5\)\] { box-shadow: 0 18px 40px -16px hsl(220 30% 30% / 0.22) !important; } /* Dark navy [hsl(215 30% 8%)] / [hsl(215 30% 10%)] inline backgrounds → warm card */ html.light [class*="bg-\\[hsl\\(215_30\\%_8\\%\\)\\]"], html.light [class*="bg-\\[hsl\\(215_30\\%_10\\%\\)\\]"], html.light [class*="bg-\\[hsl\\(215_30\\%_11\\%\\)\\]"], html.light [class*="bg-\\[hsl\\(215_30\\%_12\\%\\)\\]"], html.light [class*="bg-\\[hsl\\(215_30\\%_13\\%\\)\\]"] { background-color: hsl(var(--surface)) !important; } /* ─── Light mode polish — tame glows, soften shadows, reduce signal noise. Dark-on-bright glows look amateurish; in light mode we replace red/blue bloom with subtle warm drop-shadows that read as "elevation" instead of "neon". */ /* Tone down ALL primary/info halo glow shadows in light. The legacy code uses `signal-glow`, hand-rolled `0 0 N hsl(--primary)` shadows, and big blurry "ambient" map shadows — they all need to feel like a printed atlas, not a tradeshow LED wall. */ html.light .signal-glow { box-shadow: 0 6px 18px -8px hsl(5 70% 30% / 0.32), 0 2px 6px -2px hsl(5 70% 30% / 0.18) !important; } /* cta-glow keyframe (light variant) — keep the gentle expansion, drop the colored halo. */ html.light .cta-glow { animation: cta-glow-light 2.6s ease-in-out infinite !important; } @keyframes cta-glow-light { 0%, 100% { box-shadow: 0 6px 18px -8px hsl(5 70% 30% / 0.32), 0 1px 3px -1px hsl(5 70% 30% / 0.15); } 50% { box-shadow: 0 10px 24px -10px hsl(5 70% 30% / 0.40), 0 2px 6px -2px hsl(5 70% 30% / 0.22); } } /* pulse-ring keyframe — switch to a smaller, lower-opacity ring. */ html.light .pulse-ring { animation: pulse-ring-light 2.2s infinite !important; } @keyframes pulse-ring-light { 0% { box-shadow: 0 0 0 0 hsl(5 70% 40% / 0.28); } 70% { box-shadow: 0 0 0 12px hsl(5 70% 40% / 0); } 100% { box-shadow: 0 0 0 0 hsl(5 70% 40% / 0); } } /* Hard-coded blurry chunky shadows used by some panels — replace with a restrained ink-tinted drop shadow. */ html.light .shadow-\[0_24px_60px_-12px_rgba\(0\,0\,0\,0\.55\)\], html.light .shadow-\[0_8px_32px_-8px_rgba\(0\,0\,0\,0\.5\)\], html.light .shadow-\[0_8px_32px_-8px_rgba\(0\,0\,0\,0\.4\)\] { box-shadow: 0 12px 28px -16px hsl(220 30% 25% / 0.18), 0 4px 10px -6px hsl(220 30% 25% / 0.12) !important; } /* The world-map container has a giant primary-tinted box-shadow that becomes a red bloom on paper. Soften the *element with surface-card* plus the 100px shadow — calmer drop shadow. */ html.light .surface-card[style*="0 40px 100px"] { box-shadow: 0 18px 40px -20px hsl(220 30% 25% / 0.18) !important; } /* Reduce ring opacity on glowing buttons (`ring-white/10` etc) — already covered above, but `ring-1 ring-white/15` and `ring-white/20` need it too. */ html.light .ring-white\/15 { --tw-ring-color: hsl(220 15% 40% / 0.28) !important; } /* Lighter card-glow border highlight — the rotating gradient frame */ html.light .card-glow::before { background: linear-gradient( 135deg, transparent 30%, hsl(var(--primary) / 0.0) 50%, hsl(var(--primary) / 0.28) 75%, transparent 100% ) !important; } /* radar-bg & grid-bg — make a touch more visible on paper without going red. */ html.light .grid-bg { background-image: linear-gradient(hsl(220 15% 25% / 0.05) 1px, transparent 1px), linear-gradient(90deg, hsl(220 15% 25% / 0.05) 1px, transparent 1px) !important; } html.light .radar-bg { background: radial-gradient(circle at center, transparent 0, transparent 30%, hsl(5 65% 48% / 0.04) 31%, transparent 32%), radial-gradient(circle at center, transparent 0, transparent 50%, hsl(5 65% 48% / 0.035) 51%, transparent 52%), radial-gradient(circle at center, transparent 0, transparent 70%, hsl(5 65% 48% / 0.03) 71%, transparent 72%) !important; } /* SVG feGaussianBlur glow filters wash out on paper. Soften by composing with brightness adjustment. We target the WorldNewsMap node-glow id. */ html.light filter#node-glow feGaussianBlur { /* spec hint, browsers may ignore */ } /* Cheaper approach: drop the marker box-shadow halos by overriding tone */ html.light .surface-card svg circle[filter="url(#node-glow)"] { filter: drop-shadow(0 0 4px currentColor) !important; } /* Buttons using `bg-gradient-to-b from-primary to-primary/80` keep their vibrant red — but the `ring-1 ring-white/10` makes them look like a dropped-in sticker. Replace with a hairline darker rim. */ html.light .ring-1.ring-white\/10 { --tw-ring-color: hsl(5 70% 30% / 0.18) !important; } /* Map container backdrop-blur on dark glass-card looks frosted on paper — remove backdrop-blur in light to keep typography crisp. */ html.light .glass-panel { backdrop-filter: none !important; -webkit-backdrop-filter: none !important; } /* CSS image-veil (used on hero/live cards) is tuned for dark; soften the stronger black gradient. */ html.light .image-veil::after { background: linear-gradient(180deg, hsl(var(--surface) / 0.0) 0%, hsl(var(--surface) / 0.28) 55%, hsl(var(--surface) / 0.85) 100%) !important; } /* Final touch: subtle scrollbar tweak so it isn't aggressive in light */ html.light ::-webkit-scrollbar-thumb { background: hsl(220 15% 45% / 0.32) !important; } html.light ::-webkit-scrollbar-thumb:hover { background: hsl(var(--primary) / 0.55) !important; } /* "Soft blob" decoration overlay (used on stat cards) — too saturated on paper background. Drop opacity to a hint. */ html.light .light-mode-soft-blob { opacity: 0.10 !important; filter: blur(36px) !important; } /* The hero `text-shimmer` heading uses a fast primary→glow→primary gradient. On paper the bright orange/red shimmer looks unprofessional — freeze it to a solid primary tone. */ html.light .text-shimmer { background: none !important; color: hsl(var(--primary)) !important; -webkit-text-fill-color: hsl(var(--primary)) !important; animation: none !important; } /* Live page hero gradient — slightly dial it down. */ html.light section .grid-bg { opacity: 0.6 !important; } h1, h2, h3, h4 { font-family: 'Noto Kufi Arabic', sans-serif; font-weight: 800; letter-spacing: -0.005em; } /* Latin display (numbers, codes, EN labels) — Bebas for impact */ .display, .font-display { font-family: 'Bebas Neue', 'Noto Kufi Arabic', sans-serif; letter-spacing: 0.02em; } .font-mono, code, .mono { font-family: 'IBM Plex Mono', ui-monospace, monospace; } } @layer components { .glass-panel { @apply rounded-2xl border backdrop-blur-xl; border-color: hsl(var(--hairline)); background: var(--gradient-card); box-shadow: var(--shadow-elev); } .signal-glow { box-shadow: var(--shadow-glow); } .hairline { border: 1px solid hsl(var(--hairline)); } .chip { @apply inline-flex items-center gap-1.5 rounded-full border px-3 py-1 text-xs text-foreground/80; border-color: hsl(var(--hairline)); background: hsl(var(--hover-overlay)); } .surface-card { background: hsl(var(--surface-elev)); border: 1px solid hsl(var(--hairline)); } .surface-card-2 { background: hsl(var(--surface-elev-2)); border: 1px solid hsl(var(--hairline)); } .ring-border { box-shadow: inset 0 0 0 1px hsl(var(--hairline)); } .grid-bg { background-image: linear-gradient(hsl(0 0% 100% / 0.03) 1px, transparent 1px), linear-gradient(90deg, hsl(0 0% 100% / 0.03) 1px, transparent 1px); background-size: 32px 32px; } .radar-bg { background: radial-gradient(circle at center, transparent 0, transparent 30%, hsl(5 65% 48% / 0.06) 31%, transparent 32%), radial-gradient(circle at center, transparent 0, transparent 50%, hsl(5 65% 48% / 0.05) 51%, transparent 52%), radial-gradient(circle at center, transparent 0, transparent 70%, hsl(5 65% 48% / 0.04) 71%, transparent 72%); } } @keyframes pulse-ring { 0% { box-shadow: 0 0 0 0 hsl(5 65% 48% / 0.55); } 70% { box-shadow: 0 0 0 18px hsl(5 65% 48% / 0); } 100% { box-shadow: 0 0 0 0 hsl(5 65% 48% / 0); } } .pulse-ring { animation: pulse-ring 2.2s infinite; } @keyframes radar-sweep { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } .radar-sweep { animation: radar-sweep 6s linear infinite; transform-origin: center; } @keyframes spin-slow { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } .animate-spin-slow { animation: spin-slow 3s linear infinite; } @keyframes wire-scroll { from { transform: translateX(0); } to { transform: translateX(50%); } } .animate-wire-scroll { animation: wire-scroll 60s linear infinite; } .animate-wire-scroll:hover { animation-play-state: paused; } /* Editorial rule — newspaper-style horizontal divider with end caps */ .editorial-rule { display: flex; align-items: center; gap: 0.75rem; color: hsl(var(--muted-foreground)); } .editorial-rule::before, .editorial-rule::after { content: ""; flex: 1; height: 1px; background: hsl(var(--hairline)); } /* ─── Live Page Visualizations ─── */ @keyframes scan-line { 0% { transform: translateY(-100%); opacity: 0; } 50% { opacity: 1; } 100% { transform: translateY(100%); opacity: 0; } } .scan-line::after { content: ""; position: absolute; inset-inline: 0; height: 30%; top: 0; background: linear-gradient(180deg, transparent, hsl(var(--primary) / 0.35), transparent); pointer-events: none; animation: scan-line 3.6s ease-in-out infinite; } @keyframes glow-pan { 0%, 100% { background-position: 0% 50%; } 50% { background-position: 100% 50%; } } .glow-pan { background-size: 200% 200%; animation: glow-pan 6s ease-in-out infinite; } @keyframes meter-fill { from { width: 0%; } to { width: var(--fill, 50%); } } .meter-bar { animation: meter-fill 900ms cubic-bezier(0.22, 1, 0.36, 1) both; } @keyframes pulse-dot { 0%, 100% { transform: scale(1); opacity: 1; } 50% { transform: scale(1.4); opacity: 0.6; } } .pulse-dot { animation: pulse-dot 1.8s ease-in-out infinite; } @keyframes ticker-marquee { from { transform: translateX(0); } to { transform: translateX(-50%); } } .ticker-marquee { animation: ticker-marquee 45s linear infinite; } .ticker-marquee:hover { animation-play-state: paused; } /* Hero image gradient overlay for live cards */ .image-veil::after { content: ""; position: absolute; inset: 0; background: linear-gradient(180deg, hsl(var(--surface) / 0.05) 0%, hsl(var(--surface) / 0.55) 60%, hsl(var(--surface) / 0.95) 100%); pointer-events: none; } html.light .image-veil::after { background: linear-gradient(180deg, hsl(var(--surface) / 0.0) 0%, hsl(var(--surface) / 0.35) 55%, hsl(var(--surface) / 0.88) 100%); } /* Inverted "paper" surface for the contrast section. In light mode this would * be the same color as the page background, so we flip it to a dark ink panel. */ .paper-surface { background: hsl(var(--paper)); color: hsl(220 20% 12%); } .paper-surface .muted { color: hsl(220 10% 38%); } .paper-surface a { color: hsl(5 65% 38%); } html.light .paper-surface { background: hsl(220 30% 12%); color: hsl(40 25% 92%); } html.light .paper-surface .muted { color: hsl(40 12% 70%); } html.light .paper-surface a { color: hsl(5 80% 65%); } /* Subtle hover lift used across cards */ .hover-lift { transition: transform 240ms cubic-bezier(0.22, 1, 0.36, 1), border-color 240ms ease, box-shadow 240ms ease; } .hover-lift:hover { transform: translateY(-2px); border-color: hsl(var(--primary) / 0.3); box-shadow: 0 12px 32px -8px hsl(var(--primary) / 0.18); } /* Shimmer effect for highlighted text on hero */ @keyframes shimmer { 0% { background-position: -100% 50%; } 100% { background-position: 200% 50%; } } .text-shimmer { background: linear-gradient( 90deg, hsl(var(--primary)) 0%, hsl(var(--primary-glow)) 35%, hsl(var(--primary)) 65%, hsl(var(--primary-glow)) 100% ); background-size: 200% 100%; background-clip: text; -webkit-background-clip: text; color: transparent; -webkit-text-fill-color: transparent; animation: shimmer 4.5s linear infinite; } /* Soft floating motion */ @keyframes float-y { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-6px); } } .float-y { animation: float-y 4s ease-in-out infinite; } /* ─── Mount entrance animations (stagger via inline animation-delay) ─── */ @keyframes enter-up { from { opacity: 0; transform: translateY(22px); } to { opacity: 1; transform: translateY(0); } } @keyframes enter-down { from { opacity: 0; transform: translateY(-14px); } to { opacity: 1; transform: translateY(0); } } @keyframes enter-fade { from { opacity: 0; } to { opacity: 1; } } @keyframes enter-left { /* In RTL the visual "left" column slides in from the left edge */ from { opacity: 0; transform: translateX(-32px) scale(0.985); } to { opacity: 1; transform: translateX(0) scale(1); } } @keyframes enter-right { from { opacity: 0; transform: translateX(32px) scale(0.985); } to { opacity: 1; transform: translateX(0) scale(1); } } @keyframes enter-pop { 0% { opacity: 0; transform: scale(0.9); } 60% { opacity: 1; transform: scale(1.04); } 100% { opacity: 1; transform: scale(1); } } @keyframes hero-glow-fade { from { opacity: 0; } to { opacity: 1; } } .enter-up { animation: enter-up 720ms cubic-bezier(0.22, 1, 0.36, 1) both; } .enter-down { animation: enter-down 600ms cubic-bezier(0.22, 1, 0.36, 1) both; } .enter-fade { animation: enter-fade 900ms cubic-bezier(0.22, 1, 0.36, 1) both; } .enter-left { animation: enter-left 900ms cubic-bezier(0.22, 1, 0.36, 1) both; } .enter-right { animation: enter-right 900ms cubic-bezier(0.22, 1, 0.36, 1) both; } .enter-pop { animation: enter-pop 620ms cubic-bezier(0.34, 1.56, 0.64, 1) both; } /* Animated underline that draws in once on mount */ @keyframes underline-draw { from { transform: scaleX(0); } to { transform: scaleX(1); } } .underline-draw { position: relative; display: inline-block; } .underline-draw::after { content: ""; position: absolute; inset-inline: 0; bottom: -4px; height: 3px; border-radius: 2px; background: linear-gradient(90deg, hsl(var(--primary)), hsl(var(--primary-glow))); transform-origin: right; animation: underline-draw 800ms cubic-bezier(0.22, 1, 0.36, 1) 900ms both; } @media (prefers-reduced-motion: reduce) { .enter-up, .enter-down, .enter-fade, .enter-left, .enter-right, .enter-pop, .underline-draw::after, .float-y, .text-shimmer, .cta-glow, .pulse-ring, .radar-sweep, .animate-spin-slow { animation: none !important; opacity: 1 !important; transform: none !important; } } /* Glow pulse for primary CTA */ @keyframes cta-glow { 0%, 100% { box-shadow: 0 0 0 0 hsl(var(--primary) / 0.4), 0 12px 28px -8px hsl(var(--primary) / 0.35); } 50% { box-shadow: 0 0 0 8px hsl(var(--primary) / 0), 0 16px 40px -10px hsl(var(--primary) / 0.55); } } .cta-glow { animation: cta-glow 2.6s ease-in-out infinite; } /* Card edge gradient on hover (overlays the border subtly) */ .card-glow { position: relative; } .card-glow::before { content: ""; position: absolute; inset: 0; border-radius: inherit; padding: 1px; background: linear-gradient( 135deg, transparent 30%, hsl(var(--primary) / 0.0) 50%, hsl(var(--primary) / 0.5) 75%, transparent 100% ); -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0); -webkit-mask-composite: xor; mask-composite: exclude; opacity: 0; transition: opacity 280ms ease; pointer-events: none; } .card-glow:hover::before { opacity: 1; }