@import "tailwindcss"; @theme { --color-bg: #0a0a0b; /* Elevated surfaces carry a ~1% indigo tint so panels read as part of the brand instead of flat gray. Kept close enough to the old #111114/#16161a that dashboard contrast ratios are unaffected. */ --color-bg-elevated: #121218; --color-bg-subtle: #17171d; --color-fg: #fafafa; --color-fg-muted: #a1a1aa; --color-fg-subtle: #71717a; --color-border: #1f1f22; --color-border-strong: #2a2a2e; --color-accent: #6366f1; /* Secondary brand hue — cyan endpoint of the identity gradient. Reserved for the gradient, kickers and "live" accents; never a surface color. */ --color-accent-2: #22d3ee; --color-accent-fg: #ffffff; --color-success: #22c55e; --color-warn: #f59e0b; --color-danger: #ef4444; --font-sans: var(--font-geist-sans), ui-sans-serif, system-ui, -apple-system, sans-serif; --font-mono: var(--font-geist-mono), ui-monospace, SFMono-Regular, Menlo, monospace; --radius-sm: 4px; --radius-md: 6px; --radius-lg: 8px; } @layer base { * { border-color: var(--color-border); } html { color-scheme: dark; background: var(--color-bg); -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; /* Safety net against a stray wide element causing horizontal scroll on mobile. `clip` (not `hidden`) does not create a scroll container, so it leaves position: sticky intact. */ overflow-x: clip; } body { background: var(--color-bg); color: var(--color-fg); font-family: var(--font-sans); font-feature-settings: "cv11", "ss01"; } ::selection { background: rgba(99, 102, 241, 0.3); color: var(--color-fg); } /* Focus rings */ :focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; } /* Force dark native UI for form controls — Chrome popdown otherwise reverts to OS light theme */ select, input, textarea, button { color-scheme: dark; } /* Style native select arrow + ensure the dropdown popdown uses our dark token */ select { background-image: url("data:image/svg+xml;utf8,"); background-repeat: no-repeat; background-position: right 8px center; background-size: 12px; -webkit-appearance: none; -moz-appearance: none; appearance: none; padding-right: 26px !important; } select option { background: var(--color-bg-elevated); color: var(--color-fg); } /* Scrollbars */ ::-webkit-scrollbar { width: 10px; height: 10px; } ::-webkit-scrollbar-track { background: transparent; } ::-webkit-scrollbar-thumb { background: var(--color-border-strong); border-radius: 5px; } ::-webkit-scrollbar-thumb:hover { background: var(--color-fg-subtle); } /* Textarea resize grip — light hatching on a dark square so it matches the theme instead of the OS default (light square with dark hatching). */ textarea::-webkit-resizer { background-color: var(--color-bg); background-image: repeating-linear-gradient( -45deg, var(--color-fg-muted) 0 1px, transparent 1px 4px ); border-bottom-right-radius: var(--radius-md); } } /* Identity gradient — indigo → cyan. Defined outside @theme (it's not a Tailwind token, just a shared value) and used ONLY for: primary CTAs, section kickers, the featured pricing card and one hero glow. Scarcity is what keeps it feeling like a brand mark instead of decoration. */ :root { --gradient-brand: linear-gradient(135deg, #6366f1 0%, #22d3ee 100%); } @layer components { /* Gradient-filled primary CTA. A dark inner overlay on hover (instead of a second gradient) keeps the transition GPU-cheap. */ .btn-brand { position: relative; background: var(--gradient-brand); color: #ffffff; isolation: isolate; } .btn-brand::after { content: ""; position: absolute; inset: 0; border-radius: inherit; background: rgba(10, 10, 11, 0); transition: background-color 0.2s ease-out; z-index: -1; } .btn-brand:hover::after { background: rgba(10, 10, 11, 0.18); } /* Gradient text for the rare display moment (final CTA heading). */ .text-brand-gradient { background: var(--gradient-brand); -webkit-background-clip: text; background-clip: text; color: transparent; } /* Mono section kicker, shell-comment style: `## how_it_works` */ .kicker { font-family: var(--font-mono); font-size: 12px; letter-spacing: 0.08em; color: var(--color-accent); } /* Elevated panel with an inner top highlight — reads as machined edge. */ .panel-raised { background: var(--color-bg-elevated); border: 1px solid var(--color-border); border-radius: var(--radius-lg); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.04); } .panel { background: var(--color-bg-elevated); border: 1px solid var(--color-border); border-radius: var(--radius-md); } .panel-subtle { background: var(--color-bg-subtle); border: 1px solid var(--color-border); border-radius: var(--radius-md); } .mono { font-family: var(--font-mono); font-size: 0.8125rem; letter-spacing: -0.01em; } /* Reduced motion */ @media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.001ms !important; animation-iteration-count: 1 !important; transition-duration: 0.001ms !important; } } /* A loading spinner reports system status — WCAG treats status indicators as an exception to reduced-motion, so keep it spinning after the rule above has damped every decorative animation. Same layer + higher specificity than the universal selector, so this !important wins. */ @media (prefers-reduced-motion: reduce) { .animate-spin { animation-duration: 1s !important; animation-iteration-count: infinite !important; } } } @keyframes pulse-dot { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: 0.5; transform: scale(0.9); } } @keyframes shimmer { 0% { background-position: -1000px 0; } 100% { background-position: 1000px 0; } } @keyframes fade-in { from { opacity: 0; transform: translateY(2px); } to { opacity: 1; transform: translateY(0); } } /* Click-pulse for primary actions (see components/pulse.tsx). Scales a small indigo dot from 1x to 80x over 650ms — on a 2px base that's ~160px max radius, comfortably larger than any button on the site. The translate(-50%, -50%) keeps the dot anchored to the click point as it grows. Reduced-motion users get an instant fade-out so the click action still proceeds without the bloom. */ @keyframes glow-pulse { 0% { transform: translate(-50%, -50%) scale(1); opacity: 0.85; } 100% { transform: translate(-50%, -50%) scale(80); opacity: 0; } } @media (prefers-reduced-motion: reduce) { @keyframes glow-pulse { 0%, 100% { transform: translate(-50%, -50%) scale(1); opacity: 0; } } }