Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 2 additions & 5 deletions app/blog/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,7 @@ export default async function Blog() {
</div>

<h2 className="mt-4 text-2xl font-semibold tracking-tight text-gray-900">
<Link
href={`/blog/${post.slug}` as Route}
className="hover:text-openai-green"
>
<Link href={`/blog/${post.slug}` as Route} className="hover:text-action">
{post.title}
</Link>
</h2>
Expand All @@ -90,7 +87,7 @@ export default async function Blog() {

<Link
href={`/blog/${post.slug}` as Route}
className="mt-6 inline-flex items-center text-sm font-medium text-openai-green hover:text-opacity-80"
className="mt-6 inline-flex items-center text-sm font-medium text-action hover:text-opacity-80"
>
Read more
<svg
Expand Down
18 changes: 9 additions & 9 deletions app/contact/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export default function ContactPage() {
<div>
<h3 className="mb-2 text-lg font-medium text-gray-900">Email</h3>
<p className="text-gray-600">
<a href="mailto:info@botsmann.com" className="text-openai-green hover:underline">
<a href="mailto:info@botsmann.com" className="text-action hover:underline">
info@botsmann.com
</a>
</p>
Expand All @@ -87,7 +87,7 @@ export default function ContactPage() {
solutions in action.
</p>
<button
className="rounded-md bg-white px-4 py-2 text-sm font-medium text-openai-green border border-openai-green hover:bg-openai-green hover:text-white transition-colors"
className="rounded-md bg-white px-4 py-2 text-sm font-medium text-action border border-action hover:bg-action hover:text-white transition-colors"
onClick={() => window.open('https://calendly.com/botsmann/demo', '_blank')}
>
Schedule a Demo
Expand All @@ -101,7 +101,7 @@ export default function ContactPage() {
{isSubmitted ? (
<div className="text-center py-8">
<svg
className="mx-auto h-12 w-12 text-openai-green"
className="mx-auto h-12 w-12 text-action"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
Expand All @@ -118,7 +118,7 @@ export default function ContactPage() {
We've received your message and will get back to you soon.
</p>
<button
className="mt-5 rounded-md bg-openai-green px-4 py-2 text-sm font-medium text-white hover:bg-opacity-90 transition-opacity"
className="mt-5 rounded-md bg-action px-4 py-2 text-sm font-medium text-white hover:bg-opacity-90 transition-opacity"
onClick={() => setIsSubmitted(false)}
>
Send another message
Expand All @@ -141,7 +141,7 @@ export default function ContactPage() {
required
value={formState.name}
onChange={handleChange}
className="w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-openai-green focus:outline-none focus:ring-1 focus:ring-openai-green"
className="w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-action focus:outline-none focus:ring-1 focus:ring-action"
/>
</div>

Expand All @@ -156,7 +156,7 @@ export default function ContactPage() {
required
value={formState.email}
onChange={handleChange}
className="w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-openai-green focus:outline-none focus:ring-1 focus:ring-openai-green"
className="w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-action focus:outline-none focus:ring-1 focus:ring-action"
/>
</div>

Expand All @@ -170,7 +170,7 @@ export default function ContactPage() {
name="company"
value={formState.company}
onChange={handleChange}
className="w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-openai-green focus:outline-none focus:ring-1 focus:ring-openai-green"
className="w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-action focus:outline-none focus:ring-1 focus:ring-action"
/>
</div>

Expand All @@ -185,14 +185,14 @@ export default function ContactPage() {
required
value={formState.message}
onChange={handleChange}
className="w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-openai-green focus:outline-none focus:ring-1 focus:ring-openai-green"
className="w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-action focus:outline-none focus:ring-1 focus:ring-action"
/>
</div>

<button
type="submit"
disabled={isSubmitting}
className="w-full rounded-md bg-openai-green px-4 py-2 text-sm font-medium text-white hover:bg-opacity-90 transition-opacity disabled:bg-opacity-70"
className="w-full rounded-md bg-action px-4 py-2 text-sm font-medium text-white hover:bg-opacity-90 transition-opacity disabled:bg-opacity-70"
>
{isSubmitting ? 'Sending...' : 'Send Message'}
</button>
Expand Down
66 changes: 55 additions & 11 deletions app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,57 @@
@tailwind components;
@tailwind utilities;

/*
* ============================================================================
* BOTSMANN DESIGN TOKENS — SINGLE SOURCE OF TRUTH
* ============================================================================
* Identity: serious, credible AI professionals — counsel you'd trust, not a
* toy chatbot. Editorial ink + one authoritative warm accent (notarial ochre).
* No generic "AI gradient" blue/purple. Typography (serif display) carries it.
*
* Every color/radius/shadow used in the product is defined HERE. tailwind.config
* maps utilities to these vars; components consume semantic classes only.
* Retheme = edit this block. Nothing else.
*/
:root {
--foreground-rgb: 0, 0, 0;
--background-rgb: 255, 255, 255;
/* Tier 1 — Primitive palette (raw values; never used directly by components) */
--primitive-ink-950: #1a1714; /* near-black warm ink — text & wordmark */
--primitive-ink-700: #4a423b;
--primitive-ink-500: #6f655c; /* muted body copy */
--primitive-ochre-600: #b45309; /* authoritative warm accent */
--primitive-ochre-700: #92400e; /* accent hover / pressed */
--primitive-ochre-50: #fdf6ec; /* accent tint surface */
--primitive-paper: #faf8f4; /* warm off-white page */
--primitive-surface: #ffffff;
--primitive-border: #e8e2d8; /* warm hairline */

/* Tier 2 — Semantic tokens (what things MEAN — always use these) */
--color-brand: var(--primitive-ink-950); /* the Botsmann mark / authority */
--color-action: var(--primitive-ochre-600); /* primary CTAs, links, accents */
--color-action-hover: var(--primitive-ochre-700);
--color-action-tint: var(--primitive-ochre-50);
--color-bg: var(--primitive-paper);
--color-surface: var(--primitive-surface);
--color-border: var(--primitive-border);
--color-text: var(--primitive-ink-950);
--color-text-muted: var(--primitive-ink-500);

/* Radii — restrained, editorial (not bubbly) */
--radius-card: 12px;
--radius-btn: 8px;

/* Shadows — subtle, paper-like (no glassmorphism glow) */
--shadow-card: 0 1px 2px rgb(26 23 20 / 0.04), 0 1px 3px rgb(26 23 20 / 0.06);
--shadow-card-hover: 0 4px 12px rgb(26 23 20 / 0.08), 0 2px 4px rgb(26 23 20 / 0.06);

/* Back-compat for any legacy rgb() consumers */
--foreground-rgb: 26, 23, 20;
--background-rgb: 250, 248, 244;
}

body {
color: rgb(var(--foreground-rgb));
background: rgb(var(--background-rgb));
color: var(--color-text);
background: var(--color-bg);
}

/* Smooth scrolling for anchor links */
Expand All @@ -24,29 +67,30 @@ html {
}

@layer base {
/* Serif display carries the editorial identity for headings & wordmark */
h1 {
@apply text-4xl font-semibold tracking-tight;
@apply font-serif text-4xl font-semibold tracking-tight text-ink;
}
h2 {
@apply text-3xl font-medium tracking-tight;
@apply font-serif text-3xl font-semibold tracking-tight text-ink;
}
h3 {
@apply text-2xl font-medium;
@apply text-2xl font-semibold text-ink;
}
p {
@apply text-gray-600;
@apply text-ink-muted;
}
}

@layer components {
.btn-primary {
@apply rounded-md bg-green-600 px-4 py-2 text-sm md:text-base font-medium text-white hover:bg-opacity-90 transition-all shadow-sm hover:shadow md:px-5 md:py-2.5 focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-opacity-50;
@apply rounded-btn bg-action px-4 py-2 text-sm md:text-base font-medium text-white hover:bg-action-hover transition-colors shadow-card hover:shadow-card-hover md:px-5 md:py-2.5 focus:outline-none focus:ring-2 focus:ring-action focus:ring-opacity-40;
}
.btn-secondary {
@apply rounded-md border border-gray-200 px-4 py-2 text-sm md:text-base font-medium text-gray-600 hover:bg-gray-50 transition-all shadow-sm hover:shadow-md md:px-5 md:py-2.5 focus:outline-none focus:ring-2 focus:ring-gray-200 focus:ring-opacity-50;
@apply rounded-btn border border-edge px-4 py-2 text-sm md:text-base font-medium text-ink hover:bg-action-tint transition-colors shadow-card hover:shadow-card-hover md:px-5 md:py-2.5 focus:outline-none focus:ring-2 focus:ring-action focus:ring-opacity-20;
}
.input-primary {
@apply w-full rounded-xl border-2 border-gray-200 bg-transparent px-4 py-3 text-gray-900 outline-none transition-colors focus:border-green-600 focus:ring-2 focus:ring-green-100;
@apply w-full rounded-btn border border-edge bg-surface px-4 py-3 text-ink outline-none transition-colors focus:border-action focus:ring-2 focus:ring-action focus:ring-opacity-20;
}
}

Expand Down
24 changes: 21 additions & 3 deletions app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,34 @@ import { site } from '@/lib/site';
import './globals.css';
import { Toaster } from 'sonner';
import { Analytics } from '@vercel/analytics/react';
import { Inter, Fraunces } from 'next/font/google';

// Brand typeface: a serif display (Fraunces) carries the editorial / "real
// counsel" identity for headings & wordmark; Inter handles UI/body copy.
// Bound to CSS vars consumed by tailwind.config (font-serif / font-sans).
const sans = Inter({
subsets: ['latin'],
variable: '--font-sans',
display: 'swap',
});

const serif = Fraunces({
subsets: ['latin'],
weight: ['400', '500', '600', '700'],
style: ['normal', 'italic'],
variable: '--font-serif',
display: 'swap',
});

export const metadata = {
title: `${site.name} - ${site.tagline}`,
title: `${site.name} ${site.tagline}`,
description: site.description,
};

export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body className="font-sans">
<html lang="en" className={`${sans.variable} ${serif.variable}`}>
<body className="bg-paper font-sans text-ink">
<Providers>
<Header />
<main className="pt-16">{children}</main>
Expand Down
Loading
Loading