diff --git a/apps/web/app/(site)/blog/layout.tsx b/apps/web/app/(site)/blog/layout.tsx new file mode 100644 index 0000000..1191fef --- /dev/null +++ b/apps/web/app/(site)/blog/layout.tsx @@ -0,0 +1,9 @@ +import { LegacyLightSurface } from "@/src/components/LegacyLightSurface"; + +export default function LegacyLayout({ + children, +}: { + children: React.ReactNode; +}) { + return {children}; +} diff --git a/apps/web/app/(site)/book/page.tsx b/apps/web/app/(site)/book/page.tsx new file mode 100644 index 0000000..de7fa0a --- /dev/null +++ b/apps/web/app/(site)/book/page.tsx @@ -0,0 +1,18 @@ +import type { Metadata } from "next"; +import { Container } from "@/src/components/site/Container"; +import { SectionHeader } from "@/src/components/site/SectionHeader"; + +export const metadata: Metadata = { title: "Book a call" }; + +export default function Page() { + return ( + + + + ); +} diff --git a/apps/web/app/(site)/case-studies/layout.tsx b/apps/web/app/(site)/case-studies/layout.tsx new file mode 100644 index 0000000..1191fef --- /dev/null +++ b/apps/web/app/(site)/case-studies/layout.tsx @@ -0,0 +1,9 @@ +import { LegacyLightSurface } from "@/src/components/LegacyLightSurface"; + +export default function LegacyLayout({ + children, +}: { + children: React.ReactNode; +}) { + return {children}; +} diff --git a/apps/web/app/(site)/contact/layout.tsx b/apps/web/app/(site)/contact/layout.tsx new file mode 100644 index 0000000..1191fef --- /dev/null +++ b/apps/web/app/(site)/contact/layout.tsx @@ -0,0 +1,9 @@ +import { LegacyLightSurface } from "@/src/components/LegacyLightSurface"; + +export default function LegacyLayout({ + children, +}: { + children: React.ReactNode; +}) { + return {children}; +} diff --git a/apps/web/app/(site)/globals.css b/apps/web/app/(site)/globals.css index 670000e..e1d1060 100644 --- a/apps/web/app/(site)/globals.css +++ b/apps/web/app/(site)/globals.css @@ -2,6 +2,40 @@ @tailwind components; @tailwind utilities; +/* Theme tokens. Dark is the site default; legacy pages (blog, legal, ...) opt into + the light variant by wrapping their content in `.theme-light` (LegacyLightSurface). */ +:root { + --color-bg: #0a0d12; + --color-surface: #0d1219; + --color-fg: #e6edf3; + --color-muted: #8b98a8; + --color-faint: #5b6879; + --color-border: #1f2630; + --color-border-strong: #2b3544; + --color-accent: #3fb98a; + --color-accent-hover: #55c99d; + --color-accent-fg: #0a0d12; + --color-code-bg: #0d1219; + --color-code-border: #1f2630; + --color-scrollbar-track: #0a0d12; + --color-scrollbar-thumb: #2b3544; +} + +.theme-light { + --color-bg: #ffffff; + --color-surface: #f8fafc; + --color-fg: #0f172a; + --color-muted: #334155; + --color-faint: #64748b; + --color-border: #e2e8f0; + --color-border-strong: #cbd5e1; + --color-code-bg: #f8fafc; + --color-code-border: #f1f5f9; + background-color: var(--color-bg); + color: #1e293b; + font-family: var(--font-newsreader), Georgia, serif; +} + /* Base styles - Tailwind only */ @layer base { html { @@ -9,7 +43,7 @@ } body { - @apply bg-white text-slate-800 font-serif antialiased selection:bg-slate-900 selection:text-white; + @apply bg-bg text-fg font-sans antialiased; line-height: 1.6; } @@ -20,7 +54,7 @@ h4, h5, h6 { - @apply font-sans font-bold text-slate-900 tracking-tighter; + @apply font-sans font-bold text-fg tracking-tighter; } h1 { @@ -40,7 +74,7 @@ } p { - @apply mb-6 text-base leading-relaxed text-slate-700; + @apply mb-6 text-base leading-relaxed text-muted; } .lead { @@ -49,7 +83,7 @@ } a { - @apply text-slate-900 hover:text-slate-700 transition-colors no-underline; + @apply text-fg hover:text-muted transition-colors no-underline; } ul, @@ -62,22 +96,34 @@ } code:not([class*="language-"]) { - @apply bg-slate-50 px-1.5 py-0.5 rounded-md font-mono text-[0.9em] text-slate-800 border border-slate-100; + @apply px-1.5 py-0.5 rounded-md font-mono text-[0.9em] text-fg border; + background-color: var(--color-code-bg); + border-color: var(--color-code-border); } blockquote { - @apply border-l-4 border-slate-900 pl-6 italic text-slate-700 my-8 text-lg md:text-2xl font-serif; + @apply border-l-4 border-fg pl-6 italic text-muted my-8 text-lg md:text-2xl font-serif; } /* Focus states */ - a:focus, - button:focus, input:focus, textarea:focus { outline: none !important; box-shadow: none !important; } + /* Keep mouse focus quiet, but never hide the keyboard focus ring */ + a:focus:not(:focus-visible), + button:focus:not(:focus-visible) { + outline: none; + } + + a:focus-visible, + button:focus-visible { + outline: 2px solid var(--color-accent); + outline-offset: 2px; + } + /* Interactive elements pointer */ a, button, @@ -328,11 +374,11 @@ } ::-webkit-scrollbar-track { - background: #f1f5f9; + background: var(--color-scrollbar-track); } ::-webkit-scrollbar-thumb { - background: #cbd5e1; + background: var(--color-scrollbar-thumb); border-radius: 4px; transition: background 0.2s ease; } @@ -343,8 +389,8 @@ /* Selection color */ ::selection { - background: #0f172a; - color: #ffffff; + background: var(--color-accent); + color: var(--color-accent-fg); } /* Tag Styles */ diff --git a/apps/web/app/(site)/layout.tsx b/apps/web/app/(site)/layout.tsx index ac56257..3d82c4f 100644 --- a/apps/web/app/(site)/layout.tsx +++ b/apps/web/app/(site)/layout.tsx @@ -1,5 +1,5 @@ import type { Metadata } from "next"; -import { Inter, Newsreader } from "next/font/google"; +import { Inter, JetBrains_Mono, Newsreader } from "next/font/google"; import { Analytics } from "@/src/components/Analytics"; import { Footer } from "@/src/components/Footer"; import { Header } from "@/src/components/Header"; @@ -7,6 +7,11 @@ import { InteractiveElements } from "@/src/components/InteractiveElements"; import "./globals.css"; const inter = Inter({ subsets: ["latin"], variable: "--font-inter" }); +const jetbrainsMono = JetBrains_Mono({ + subsets: ["latin"], + variable: "--font-jetbrains-mono", + display: "swap", +}); const newsreader = Newsreader({ subsets: ["latin"], variable: "--font-newsreader", @@ -14,14 +19,25 @@ const newsreader = Newsreader({ display: "swap", }); +const DESCRIPTION = + "Senior engineer for teams that build fast with AI and don't want chaos. Strong in design and frontend, provably clean in architecture and tests. Remote, booked in weekly capacity blocks."; + export const metadata: Metadata = { title: { - default: "Marc Mintel — Professionelle Websites für Unternehmen", + default: "Marc Mintel — Senior engineer for AI-built software", template: "%s | Marc Mintel", }, - description: - "Professionelle Websites zum Fixpreis. Ein Entwickler, ein Ansprechpartner — von der Idee bis zum fertigen Ergebnis. Inklusive Sorglos-Paket: Änderungen, Wartung und Sicherheit komplett abgedeckt.", + description: DESCRIPTION, metadataBase: new URL("https://mintel.me"), + openGraph: { + type: "website", + siteName: "Marc Mintel", + title: "Marc Mintel — Senior engineer for AI-built software", + description: DESCRIPTION, + url: "https://mintel.me", + locale: "en_US", + }, + twitter: { card: "summary_large_image" }, icons: { icon: "/favicon.svg", }, @@ -33,8 +49,11 @@ export default function RootLayout({ children: React.ReactNode; }) { return ( - - + +
{children}