diff --git a/public/favicon.svg b/public/favicon.svg
new file mode 100644
index 0000000..27dbdc5
--- /dev/null
+++ b/public/favicon.svg
@@ -0,0 +1,5 @@
+
diff --git a/public/og.svg b/public/og.svg
new file mode 100644
index 0000000..6d155cf
--- /dev/null
+++ b/public/og.svg
@@ -0,0 +1,20 @@
+
diff --git a/src/components/mika/Logo.tsx b/src/components/mika/Logo.tsx
new file mode 100644
index 0000000..0388116
--- /dev/null
+++ b/src/components/mika/Logo.tsx
@@ -0,0 +1,19 @@
+import { Link } from "@tanstack/react-router";
+import { cn } from "@/lib/utils";
+
+export function Logo({ className, size = "md" }: { className?: string; size?: "sm" | "md" | "lg" }) {
+ const sizes = {
+ sm: "text-xl",
+ md: "text-2xl",
+ lg: "text-3xl",
+ };
+ return (
+
+ Mika.
+
+ );
+}
diff --git a/src/components/mika/ThemeToggle.tsx b/src/components/mika/ThemeToggle.tsx
new file mode 100644
index 0000000..ec19fe1
--- /dev/null
+++ b/src/components/mika/ThemeToggle.tsx
@@ -0,0 +1,21 @@
+"use client";
+
+import { Moon, Sun } from "lucide-react";
+import { Button } from "@/components/ui/button";
+import { useTheme } from "@/components/theme-provider";
+
+export function ThemeToggle() {
+ const { theme, toggleTheme } = useTheme();
+ return (
+
+ );
+}
diff --git a/src/components/theme-provider.tsx b/src/components/theme-provider.tsx
new file mode 100644
index 0000000..20a32a3
--- /dev/null
+++ b/src/components/theme-provider.tsx
@@ -0,0 +1,65 @@
+"use client";
+
+import { createContext, useContext, useEffect, useState, type ReactNode } from "react";
+
+type Theme = "light" | "dark";
+type ThemeContextValue = {
+ theme: Theme;
+ setTheme: (t: Theme) => void;
+ toggleTheme: () => void;
+};
+
+const ThemeContext = createContext(null);
+const STORAGE_KEY = "mika-theme";
+
+function applyTheme(theme: Theme) {
+ if (typeof document === "undefined") return;
+ const root = document.documentElement;
+ if (theme === "dark") root.classList.add("dark");
+ else root.classList.remove("dark");
+ root.style.colorScheme = theme;
+}
+
+function getInitialTheme(): Theme {
+ if (typeof window === "undefined") return "light";
+ try {
+ const stored = window.localStorage.getItem(STORAGE_KEY);
+ if (stored === "light" || stored === "dark") return stored;
+ } catch {}
+ if (window.matchMedia?.("(prefers-color-scheme: dark)").matches) return "dark";
+ return "light";
+}
+
+export function ThemeProvider({ children }: { children: ReactNode }) {
+ const [theme, setThemeState] = useState("light");
+ const [mounted, setMounted] = useState(false);
+
+ useEffect(() => {
+ const t = getInitialTheme();
+ setThemeState(t);
+ applyTheme(t);
+ setMounted(true);
+ }, []);
+
+ const setTheme = (t: Theme) => {
+ setThemeState(t);
+ applyTheme(t);
+ try {
+ window.localStorage.setItem(STORAGE_KEY, t);
+ } catch {}
+ };
+
+ const toggleTheme = () => setTheme(theme === "dark" ? "light" : "dark");
+
+ return (
+
+ {children}
+
+ );
+}
+
+export function useTheme() {
+ const ctx = useContext(ThemeContext);
+ if (!ctx) throw new Error("useTheme deve ser usado dentro de ThemeProvider");
+ return ctx;
+}
diff --git a/src/routeTree.gen.ts b/src/routeTree.gen.ts
index d204c26..dceedff 100644
--- a/src/routeTree.gen.ts
+++ b/src/routeTree.gen.ts
@@ -57,3 +57,12 @@ const rootRouteChildren: RootRouteChildren = {
export const routeTree = rootRouteImport
._addFileChildren(rootRouteChildren)
._addFileTypes()
+
+import type { getRouter } from './router.tsx'
+import type { createStart } from '@tanstack/react-start'
+declare module '@tanstack/react-start' {
+ interface Register {
+ ssr: true
+ router: Awaited>
+ }
+}
diff --git a/src/styles.css b/src/styles.css
index a9806b4..dfd4671 100644
--- a/src/styles.css
+++ b/src/styles.css
@@ -5,47 +5,48 @@
@custom-variant dark (&:is(.dark *));
/*
- * Design system definition.
- *
- * The @theme inline block maps CSS custom properties to Tailwind utility
- * classes (e.g. --color-primary -> bg-primary, text-primary).
- *
- * The :root and .dark blocks define the actual color values using oklch.
- * All colors MUST use oklch format.
- *
- * To add a new semantic color:
- * 1. Add the variable to :root (light value) and .dark (dark value)
- * 2. Register it in @theme inline as --color-: var(--)
+ * Mika Design System
+ * Paleta inspirada em Linear / Supabase / Cal.com.
+ * - Primary: Indigo (#6366F1) — confiança e tecnologia
+ * - Secondary: Emerald (#10B981) — sucesso/check
+ * - Accent: Amber (#F59E0B) — destaque, ponto final do wordmark
+ * Todas as cores em oklch.
*/
@theme inline {
+ --font-sans: "Inter", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
+
--radius-sm: calc(var(--radius) - 4px);
--radius-md: calc(var(--radius) - 2px);
--radius-lg: var(--radius);
--radius-xl: calc(var(--radius) + 4px);
--radius-2xl: calc(var(--radius) + 8px);
--radius-3xl: calc(var(--radius) + 12px);
- --radius-4xl: calc(var(--radius) + 16px);
+
--color-background: var(--background);
--color-foreground: var(--foreground);
+ --color-surface: var(--surface);
--color-card: var(--card);
--color-card-foreground: var(--card-foreground);
--color-popover: var(--popover);
--color-popover-foreground: var(--popover-foreground);
--color-primary: var(--primary);
--color-primary-foreground: var(--primary-foreground);
+ --color-primary-dark: var(--primary-dark);
+ --color-primary-light: var(--primary-light);
--color-secondary: var(--secondary);
--color-secondary-foreground: var(--secondary-foreground);
- --color-muted: var(--muted);
- --color-muted-foreground: var(--muted-foreground);
--color-accent: var(--accent);
--color-accent-foreground: var(--accent-foreground);
+ --color-muted: var(--muted);
+ --color-muted-foreground: var(--muted-foreground);
--color-destructive: var(--destructive);
--color-destructive-foreground: var(--destructive-foreground);
+ --color-success: var(--success);
+ --color-warning: var(--warning);
--color-border: var(--border);
--color-input: var(--input);
--color-ring: var(--ring);
- --color-ring-offset-background: var(--background);
--color-chart-1: var(--chart-1);
--color-chart-2: var(--chart-2);
--color-chart-3: var(--chart-3);
@@ -63,73 +64,115 @@
:root {
--radius: 0.625rem;
- --background: oklch(1 0 0);
- --foreground: oklch(0.129 0.042 264.695);
+
+ /* Mika light tokens */
+ --background: oklch(0.985 0 0); /* #FAFAFA */
+ --foreground: oklch(0.18 0.04 265); /* #0F172A */
+ --surface: oklch(1 0 0); /* #FFFFFF */
+
--card: oklch(1 0 0);
- --card-foreground: oklch(0.129 0.042 264.695);
+ --card-foreground: oklch(0.18 0.04 265);
--popover: oklch(1 0 0);
- --popover-foreground: oklch(0.129 0.042 264.695);
- --primary: oklch(0.208 0.042 265.755);
- --primary-foreground: oklch(0.984 0.003 247.858);
- --secondary: oklch(0.968 0.007 247.896);
- --secondary-foreground: oklch(0.208 0.042 265.755);
- --muted: oklch(0.968 0.007 247.896);
- --muted-foreground: oklch(0.554 0.046 257.417);
- --accent: oklch(0.968 0.007 247.896);
- --accent-foreground: oklch(0.208 0.042 265.755);
- --destructive: oklch(0.577 0.245 27.325);
- --destructive-foreground: oklch(0.984 0.003 247.858);
- --border: oklch(0.929 0.013 255.508);
- --input: oklch(0.929 0.013 255.508);
- --ring: oklch(0.704 0.04 256.788);
- --chart-1: oklch(0.646 0.222 41.116);
- --chart-2: oklch(0.6 0.118 184.704);
- --chart-3: oklch(0.398 0.07 227.392);
- --chart-4: oklch(0.828 0.189 84.429);
- --chart-5: oklch(0.769 0.188 70.08);
- --sidebar: oklch(0.984 0.003 247.858);
- --sidebar-foreground: oklch(0.129 0.042 264.695);
- --sidebar-primary: oklch(0.208 0.042 265.755);
- --sidebar-primary-foreground: oklch(0.984 0.003 247.858);
- --sidebar-accent: oklch(0.968 0.007 247.896);
- --sidebar-accent-foreground: oklch(0.208 0.042 265.755);
- --sidebar-border: oklch(0.929 0.013 255.508);
- --sidebar-ring: oklch(0.704 0.04 256.788);
+ --popover-foreground: oklch(0.18 0.04 265);
+
+ --primary: oklch(0.62 0.19 277); /* #6366F1 indigo-500 */
+ --primary-foreground: oklch(0.99 0 0);
+ --primary-dark: oklch(0.55 0.21 277); /* #4F46E5 indigo-600 */
+ --primary-light: oklch(0.74 0.13 277); /* #818CF8 indigo-400 */
+
+ --secondary: oklch(0.72 0.17 162); /* #10B981 emerald-500 */
+ --secondary-foreground: oklch(0.99 0 0);
+
+ --accent: oklch(0.78 0.16 75); /* #F59E0B amber-500 */
+ --accent-foreground: oklch(0.18 0.04 265);
+
+ --muted: oklch(0.96 0.005 256);
+ --muted-foreground: oklch(0.55 0.03 256);/* #64748B */
+
+ --destructive: oklch(0.63 0.23 25); /* #EF4444 */
+ --destructive-foreground: oklch(0.99 0 0);
+ --success: oklch(0.72 0.17 162);
+ --warning: oklch(0.78 0.16 75);
+
+ --border: oklch(0.92 0.01 256); /* #E2E8F0 */
+ --input: oklch(0.92 0.01 256);
+ --ring: oklch(0.62 0.19 277);
+
+ --chart-1: oklch(0.62 0.19 277);
+ --chart-2: oklch(0.72 0.17 162);
+ --chart-3: oklch(0.78 0.16 75);
+ --chart-4: oklch(0.55 0.21 277);
+ --chart-5: oklch(0.74 0.13 277);
+
+ --sidebar: oklch(1 0 0);
+ --sidebar-foreground: oklch(0.18 0.04 265);
+ --sidebar-primary: oklch(0.62 0.19 277);
+ --sidebar-primary-foreground: oklch(0.99 0 0);
+ --sidebar-accent: oklch(0.96 0.005 256);
+ --sidebar-accent-foreground: oklch(0.18 0.04 265);
+ --sidebar-border: oklch(0.92 0.01 256);
+ --sidebar-ring: oklch(0.62 0.19 277);
+
+ /* Gradientes & sombras Mika */
+ --gradient-hero: radial-gradient(circle at 30% 20%, oklch(0.62 0.19 277 / 0.18), transparent 60%),
+ radial-gradient(circle at 80% 80%, oklch(0.72 0.17 162 / 0.12), transparent 55%);
+ --gradient-primary: linear-gradient(135deg, oklch(0.62 0.19 277), oklch(0.55 0.21 277));
+ --shadow-soft: 0 1px 2px oklch(0.18 0.04 265 / 0.04), 0 4px 12px oklch(0.18 0.04 265 / 0.06);
+ --shadow-glow: 0 10px 40px -10px oklch(0.62 0.19 277 / 0.45);
}
.dark {
- --background: oklch(0.129 0.042 264.695);
- --foreground: oklch(0.984 0.003 247.858);
- --card: oklch(0.208 0.042 265.755);
- --card-foreground: oklch(0.984 0.003 247.858);
- --popover: oklch(0.208 0.042 265.755);
- --popover-foreground: oklch(0.984 0.003 247.858);
- --primary: oklch(0.929 0.013 255.508);
- --primary-foreground: oklch(0.208 0.042 265.755);
- --secondary: oklch(0.279 0.041 260.031);
- --secondary-foreground: oklch(0.984 0.003 247.858);
- --muted: oklch(0.279 0.041 260.031);
- --muted-foreground: oklch(0.704 0.04 256.788);
- --accent: oklch(0.279 0.041 260.031);
- --accent-foreground: oklch(0.984 0.003 247.858);
- --destructive: oklch(0.704 0.191 22.216);
- --destructive-foreground: oklch(0.984 0.003 247.858);
- --border: oklch(1 0 0 / 10%);
- --input: oklch(1 0 0 / 15%);
- --ring: oklch(0.551 0.027 264.364);
- --chart-1: oklch(0.488 0.243 264.376);
- --chart-2: oklch(0.696 0.17 162.48);
- --chart-3: oklch(0.769 0.188 70.08);
- --chart-4: oklch(0.627 0.265 303.9);
- --chart-5: oklch(0.645 0.246 16.439);
- --sidebar: oklch(0.208 0.042 265.755);
- --sidebar-foreground: oklch(0.984 0.003 247.858);
- --sidebar-primary: oklch(0.488 0.243 264.376);
- --sidebar-primary-foreground: oklch(0.984 0.003 247.858);
- --sidebar-accent: oklch(0.279 0.041 260.031);
- --sidebar-accent-foreground: oklch(0.984 0.003 247.858);
- --sidebar-border: oklch(1 0 0 / 10%);
- --sidebar-ring: oklch(0.551 0.027 264.364);
+ --background: oklch(0.18 0.04 265); /* #0F172A */
+ --foreground: oklch(0.96 0.01 247); /* #F1F5F9 */
+ --surface: oklch(0.25 0.04 260); /* #1E293B */
+
+ --card: oklch(0.25 0.04 260);
+ --card-foreground: oklch(0.96 0.01 247);
+ --popover: oklch(0.25 0.04 260);
+ --popover-foreground: oklch(0.96 0.01 247);
+
+ --primary: oklch(0.62 0.19 277);
+ --primary-foreground: oklch(0.99 0 0);
+ --primary-dark: oklch(0.55 0.21 277);
+ --primary-light: oklch(0.74 0.13 277);
+
+ --secondary: oklch(0.72 0.17 162);
+ --secondary-foreground: oklch(0.99 0 0);
+
+ --accent: oklch(0.78 0.16 75);
+ --accent-foreground: oklch(0.18 0.04 265);
+
+ --muted: oklch(0.28 0.04 260);
+ --muted-foreground: oklch(0.65 0.03 256);
+
+ --destructive: oklch(0.63 0.23 25);
+ --destructive-foreground: oklch(0.99 0 0);
+ --success: oklch(0.72 0.17 162);
+ --warning: oklch(0.78 0.16 75);
+
+ --border: oklch(0.32 0.03 256); /* #334155 */
+ --input: oklch(0.32 0.03 256);
+ --ring: oklch(0.74 0.13 277);
+
+ --chart-1: oklch(0.74 0.13 277);
+ --chart-2: oklch(0.72 0.17 162);
+ --chart-3: oklch(0.78 0.16 75);
+ --chart-4: oklch(0.55 0.21 277);
+ --chart-5: oklch(0.62 0.19 277);
+
+ --sidebar: oklch(0.22 0.04 262);
+ --sidebar-foreground: oklch(0.96 0.01 247);
+ --sidebar-primary: oklch(0.74 0.13 277);
+ --sidebar-primary-foreground: oklch(0.99 0 0);
+ --sidebar-accent: oklch(0.28 0.04 260);
+ --sidebar-accent-foreground: oklch(0.96 0.01 247);
+ --sidebar-border: oklch(0.32 0.03 256);
+ --sidebar-ring: oklch(0.74 0.13 277);
+
+ --gradient-hero: radial-gradient(circle at 30% 20%, oklch(0.62 0.19 277 / 0.25), transparent 60%),
+ radial-gradient(circle at 80% 80%, oklch(0.72 0.17 162 / 0.18), transparent 55%);
+ --shadow-soft: 0 1px 2px oklch(0 0 0 / 0.3), 0 8px 24px oklch(0 0 0 / 0.35);
+ --shadow-glow: 0 10px 40px -10px oklch(0.62 0.19 277 / 0.55);
}
@layer base {
@@ -137,8 +180,38 @@
border-color: var(--color-border);
}
+ html {
+ font-family: var(--font-sans);
+ -webkit-font-smoothing: antialiased;
+ text-rendering: optimizeLegibility;
+ }
+
body {
background-color: var(--color-background);
color: var(--color-foreground);
+ font-feature-settings: "cv02", "cv03", "cv04", "cv11";
+ }
+
+ ::selection {
+ background-color: oklch(0.62 0.19 277 / 0.25);
+ color: var(--color-foreground);
+ }
+}
+
+@layer utilities {
+ .bg-gradient-hero {
+ background-image: var(--gradient-hero);
+ }
+ .bg-gradient-primary {
+ background-image: var(--gradient-primary);
+ }
+ .shadow-soft {
+ box-shadow: var(--shadow-soft);
+ }
+ .shadow-glow {
+ box-shadow: var(--shadow-glow);
+ }
+ .text-balance {
+ text-wrap: balance;
}
}