diff --git a/src/components/CTAButtons.astro b/src/components/CTAButtons.astro
new file mode 100644
index 0000000..a3bd469
--- /dev/null
+++ b/src/components/CTAButtons.astro
@@ -0,0 +1,47 @@
+---
+import { getAuthConfig } from '../config/auth';
+
+interface Props {
+ variant?: 'primary' | 'inverted';
+ size?: 'md' | 'lg';
+ showSecondary?: boolean;
+ primaryLabel?: string;
+ secondaryLabel?: string;
+ secondaryHref?: string;
+}
+
+const auth = getAuthConfig();
+
+const {
+ variant = 'primary',
+ size = 'md',
+ showSecondary = true,
+ primaryLabel = 'Start free trial',
+ secondaryLabel = 'Sign in',
+ secondaryHref = auth.signInUrl,
+} = Astro.props;
+
+const padY = size === 'lg' ? 'py-3' : 'py-2';
+const padX = size === 'lg' ? 'px-6' : 'px-5';
+const fontSize = size === 'lg' ? 'text-base' : 'text-sm';
+---
+
diff --git a/src/components/SiteFooter.astro b/src/components/SiteFooter.astro
new file mode 100644
index 0000000..78fd19e
--- /dev/null
+++ b/src/components/SiteFooter.astro
@@ -0,0 +1,23 @@
+---
+const year = new Date().getFullYear();
+---
+
diff --git a/src/components/SiteHeader.astro b/src/components/SiteHeader.astro
new file mode 100644
index 0000000..c809a00
--- /dev/null
+++ b/src/components/SiteHeader.astro
@@ -0,0 +1,22 @@
+---
+import CTAButtons from './CTAButtons.astro';
+---
+
diff --git a/src/components/TopographicBg.astro b/src/components/TopographicBg.astro
new file mode 100644
index 0000000..b67228e
--- /dev/null
+++ b/src/components/TopographicBg.astro
@@ -0,0 +1,26 @@
+---
+interface Props {
+ opacity?: number;
+ lines?: number;
+}
+const { opacity = 0.12, lines = 8 } = Astro.props;
+
+const paths: string[] = [];
+const stepY = 100 / (lines + 1);
+for (let i = 1; i <= lines; i++) {
+ const y = i * stepY;
+ const amp = 4 + (i % 3) * 2;
+ paths.push(`M0,${y} Q25,${y - amp} 50,${y + amp * 0.6} T100,${y}`);
+}
+---
+