diff --git a/.gitignore b/.gitignore index 37ed4b7..efa0626 100644 --- a/.gitignore +++ b/.gitignore @@ -30,4 +30,6 @@ pnpm-debug.log* .DS_Store # jetbrains setting folder -.idea/ \ No newline at end of file +.idea/ + +tmp/ \ No newline at end of file diff --git a/qumo-website-rebuild-plan.md b/README.md similarity index 100% rename from qumo-website-rebuild-plan.md rename to README.md diff --git a/openspec/changes/step-003-navigation-bar/.openspec.yaml b/openspec/changes/step-003-navigation-bar/.openspec.yaml new file mode 100644 index 0000000..e49efd1 --- /dev/null +++ b/openspec/changes/step-003-navigation-bar/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-04-10 diff --git a/openspec/changes/step-003-navigation-bar/design.md b/openspec/changes/step-003-navigation-bar/design.md new file mode 100644 index 0000000..fb0b5d5 --- /dev/null +++ b/openspec/changes/step-003-navigation-bar/design.md @@ -0,0 +1,111 @@ +## Context + +Step 002 produced a `BaseLayout.astro` that imports `Nav.astro` and `Footer.astro` stubs — both render nothing. The navigation bar is the first visible UI element needed on every page. It must: + +- Render correctly on a Midnight (`#102022`) dark background +- Work at build time (Astro SSG — no server runtime) +- Derive the current locale from the URL path (no runtime props) +- Use zero client-side framework code + +Available assets confirmed: +- `src/assets/logos/logo-wide.svg` — full "qumo" wordmark, paths filled with `#161616` (near-black — needs override) +- `src/assets/icons/wum-arrow.svg` — chevron arrow, already `stroke="#f3f3f3"` (Snow — correct for dark nav) + +## Goals / Non-Goals + +**Goals:** +- Fully functional `Nav.astro` replacing the empty stub +- Logo visible on Midnight background +- Three nav links + language switcher + Connect CTA +- Scroll-triggered background transition (transparent → Midnight) +- Mobile hamburger menu with open/close behavior +- All text strings from `en.json` / `nl.json` + +**Non-Goals:** +- Animated underline or hover effects beyond Tailwind utilities +- Active page highlighting (deferred — pages don't exist yet to test against) +- Dropdown sub-menus (not on staging site) +- Separate `LanguageSwitcher.astro` component (simple enough to inline) + +## Decisions + +### 1. Logo: inline SVG with fill override + +**Decision:** Inline the `logo-wide.svg` SVG directly in `Nav.astro`. Change all `fill="#161616"` attributes to `fill="currentColor"`. Set `class="text-snow"` on the `` element so `currentColor` resolves to Snow (`#F3F3F3`). + +**Rationale:** The logo is a small, purely decorative SVG — inlining it avoids an extra HTTP request and allows CSS-controlled coloring without filters. `fill="currentColor"` + Tailwind text color is the idiomatic approach. An `` tag cannot be recolored without CSS filters, which look worse. + +**Alternative considered:** `` component with a separate white-fill SVG asset. Rejected: requires maintaining two copies of the same logo. + +### 2. Locale detection: Astro.url at build time + +**Decision:** In `Nav.astro`, derive locale from `Astro.url.pathname`: +```ts +const isNl = Astro.url.pathname.startsWith('/nl'); +const locale = isNl ? 'nl' : 'en'; +const alternatePath = isNl + ? Astro.url.pathname.replace(/^\/nl/, '') || '/' + : '/nl' + Astro.url.pathname; +``` +Pass `locale` to `getContent()` for nav strings. Use `alternatePath` for the language switcher link. + +**Rationale:** Astro SSG renders each page at build time with its own `Astro.url`. This approach is zero-JS, works for every route without configuration, and the prefix rule (`/nl/...` ↔ `/...`) holds for all routes on this site. Confirmed with user during explore session (Option B). + +**Alternative considered:** Prop threading from `BaseLayout` (Option A). Rejected by user — more verbose, non-standard for nav components. + +### 3. Scroll behavior: window scroll event + CSS class toggle + +**Decision:** A ` diff --git a/website/src/content/en.json b/website/src/content/en.json index 8b8160a..ee6bf13 100644 --- a/website/src/content/en.json +++ b/website/src/content/en.json @@ -4,5 +4,15 @@ "defaultTitle": "Qumo — Data & AI for Dutch MKB", "defaultDescription": "Qumo helps Dutch mid-market companies turn data into decisions. From BI dashboards to AI-powered workflows, we make data work for your business.", "defaultOgImage": "" + }, + "nav": { + "links": [ + { "label": "Services", "href": "/#services" }, + { "label": "AI Launchpad", "href": "/ai-launchpad" }, + { "label": "About", "href": "/about" } + ], + "cta": "Connect", + "ctaHref": "/contact", + "langSwitch": { "en": "EN", "nl": "NL" } } } diff --git a/website/src/content/nl.json b/website/src/content/nl.json index 4f0b32b..24c761a 100644 --- a/website/src/content/nl.json +++ b/website/src/content/nl.json @@ -4,5 +4,15 @@ "defaultTitle": "Qumo — Data & AI voor Nederlands MKB", "defaultDescription": "Qumo helpt Nederlandse middelgrote bedrijven data omzetten in beslissingen. Van BI-dashboards tot AI-gedreven workflows — wij laten data werken voor uw bedrijf.", "defaultOgImage": "" + }, + "nav": { + "links": [ + { "label": "Diensten", "href": "/nl#services" }, + { "label": "AI Launchpad", "href": "/nl/ai-launchpad" }, + { "label": "Over Ons", "href": "/nl/about" } + ], + "cta": "Verbind", + "ctaHref": "/nl/contact", + "langSwitch": { "en": "EN", "nl": "NL" } } } diff --git a/website/src/styles/global.css b/website/src/styles/global.css index 77b9aa2..4cda560 100644 --- a/website/src/styles/global.css +++ b/website/src/styles/global.css @@ -1,18 +1,74 @@ @import "tailwindcss"; @theme { + /* ─── Colors ─────────────────────────────────────────────────────────────── */ --color-midnight: #102022; --color-snow: #F3F3F3; + + /* + * brand-blue and brand-red are GRADIENT ENDPOINTS ONLY. + * Never use them as standalone flat colors — always via --gradient-brand. + */ --color-brand-blue: #5257E4; --color-brand-red: #F71E3E; + /* ─── Typography: font families ──────────────────────────────────────────── */ --font-archia: "Archia", ui-sans-serif, system-ui, sans-serif; + + /* ─── Typography: font sizes ─────────────────────────────────────────────── */ + /* + * Tailwind's default scale (text-xs → text-9xl) covers general use. + * These semantic aliases map to the Qumo heading hierarchy. + */ + --text-display: 4.5rem; /* Hero heading — desktop */ + --text-display--line-height: 1.05; + --text-headline: 3rem; /* Section headings (h2) */ + --text-headline--line-height: 1.1; + --text-subheading: 1.75rem; /* Card titles, sub-headings (h3) */ + --text-subheading--line-height: 1.2; + --text-label: 0.75rem; /* Uppercase labels / tags */ + --text-label--line-height: 1; + + /* ─── Typography: letter spacing ─────────────────────────────────────────── */ + /* + * Tailwind defaults: tight (-0.025em), normal (0em), wide (0.025em), + * wider (0.05em), widest (0.1em). + * Brand heading style uses uppercase + medium tracking: + */ + --tracking-heading: 0.06em; /* Qumo uppercase headings */ + --tracking-label: 0.12em; /* Uppercase label / tag text */ + + /* ─── Typography: font weights ───────────────────────────────────────────── */ + /* + * Tailwind defaults (font-thin → font-black) cover all weights. + * Archia weights available: Thin (100), Light (300), Regular (400), + * Medium (500), SemiBold (600), Bold (700). + * No custom weight overrides needed — use font-semibold / font-bold. + */ } +/* ─── Gradient ────────────────────────────────────────────────────────────── + * Defined in :root (not @theme) because Tailwind processes @theme as raw + * values and can't resolve var() references at extraction time. + * Always reference color tokens — never hardcode hex values here. + * ─────────────────────────────────────────────────────────────────────────── */ :root { - --gradient-brand: linear-gradient(135deg, #5257E4, #F71E3E); + --gradient-brand: linear-gradient(135deg, var(--color-brand-blue), var(--color-brand-red)); } +/* ─── Gradient utilities ─────────────────────────────────────────────────── */ +@utility bg-brand-gradient { + background-image: var(--gradient-brand); +} + +@utility text-brand-gradient { + background: var(--gradient-brand); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; +} + +/* ─── Font faces ─────────────────────────────────────────────────────────── */ @font-face { font-family: "Archia"; src: url("../assets/fonts/archia/archia-thin-webfont.woff2") format("woff2");