## Context Step 001 produced a working Astro project with Tailwind v4 brand tokens, Archia font-face declarations, and a smoke-test `index.astro` that manually constructs its own `` document. Every subsequent page (homepage, about, AI Launchpad, contact, privacy — plus `/nl/*` variants) will need the same HTML shell with correct `
` meta, hreflang, OG tags, and body defaults. Without a shared layout this is copied per page, creating drift and SEO inconsistency. Current state of note: - `global.css` is Tailwind v4 (`@import "tailwindcss"` + `@theme`) — no `tailwind.config.mjs` - Archia `@font-face` declarations already live in `global.css` - `public/` has `favicon.svg` and `favicon.ico` - No `src/layouts/`, `src/components/`, or `src/content/` directories yet ## Goals / Non-Goals **Goals:** - Single `BaseLayout.astro` that every page wraps its content in - Correct SEO ``: charset, viewport, favicon, font preloads, canonical, hreflang, OG, Twitter card - Body defaults applied once (Midnight bg, Snow text, Archia font) - JSON-LD injection mechanism (both prop and named slot) - Stub `Nav.astro` and `Footer.astro` so BaseLayout can import them (filled in steps 003+) - `en.json` / `nl.json` content files + `i18n.ts` loader for global meta fields - `index.astro` updated to use `BaseLayout` **Non-Goals:** - Actual nav or footer UI (step 003) - Page-specific JSON-LD schemas (each page step handles its own) - OG image file creation (deferred — `ogImage` prop will be empty string initially) - Any client-side JavaScript - `@astrojs/image` or picture optimisation (images not needed in this step) ## Decisions ### 1. hreflang: explicit props, not derived **Decision**: `BaseLayout` accepts two explicit props — `canonicalUrl: string` and `alternateUrl: string`. The component does not compute the alternate URL. **Rationale**: EN routes are `/about`, NL routes are `/nl/about` — a simple `/nl/` prefix works for most paths, but `/contact` vs `/nl/contact` or future edge cases (slugs, catch-alls) could diverge. Explicit props make each page's intent clear and avoid regex surprises. Callers always know their own routes. **Alternative considered**: Auto-derive by prepending/stripping `/nl/` based on `locale` prop. Rejected: fragile for edge cases, magic at a distance. ### 2. Font preloads: critical weights only **Decision**: Preload only Archia Regular (400), SemiBold (600), and Bold (700). Thin (100) and Light (300) load on demand. **Rationale**: Each `` is an unconditional network request. Regular is needed for all body copy; SemiBold and Bold are used for headings and CTAs — the elements visible above the fold. Thin and Light appear only in specific decorative contexts (if at all) and are not worth the preload cost. ### 3. JSON-LD: prop for common case + named slot for extras **Decision**: BaseLayout accepts an optional `jsonLd?: Record