Fix marketing site mobile layout: responsive nav and content overflow

Nav links, icons, and CTA button overflowed the viewport on mobile.
Text in Workflow-as-Code and Multi-model sections was clipped because
wide SVG/pre children caused CSS grid blowout (min-width: auto default).

- Add hamburger menu for mobile nav on both pages (hidden md:, toggle JS)
- Add overflow-x-hidden to html/body/main to prevent horizontal scroll
- Add .grid > * { min-width: 0 } to prevent grid children from expanding
  beyond their container

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Bryan Helmkamp 2026-03-16 12:23:35 -04:00
parent 8101f948fc
commit 1a258242bd
No known key found for this signature in database
4 changed files with 84 additions and 20 deletions

View file

@ -9,11 +9,28 @@ const { title } = Astro.props;
---
<!doctype html>
<html lang="en" class="bg-navy-950 text-ice-50 antialiased">
<html lang="en" class="bg-navy-950 text-ice-50 antialiased overflow-x-hidden">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Fabro is the open source, dark software factory for expert engineers. Define your process as a workflow graph, let AI agents execute it, and intervene only where it matters." />
<meta name="description" content="Fabro is the open source dark software factory for expert engineers. Define your process as a workflow graph, let AI agents execute it, and intervene only where it matters." />
<!-- Open Graph -->
<meta property="og:type" content="website" />
<meta property="og:title" content={title} />
<meta property="og:description" content="Fabro is the open source dark software factory for expert engineers. Define your process as a workflow graph, let AI agents execute it, and intervene only where it matters." />
<meta property="og:image" content="https://fabro.sh/og-image.png" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:url" content="https://fabro.sh" />
<meta property="og:site_name" content="Fabro" />
<!-- Twitter Card -->
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content={title} />
<meta name="twitter:description" content="Fabro is the open source dark software factory for expert engineers. Define your process as a workflow graph, let AI agents execute it, and intervene only where it matters." />
<meta name="twitter:image" content="https://fabro.sh/og-image.png" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
@ -23,7 +40,7 @@ const { title } = Astro.props;
/>
<title>{title}</title>
</head>
<body class="min-h-screen">
<body class="min-h-screen overflow-x-hidden">
<slot />
</body>
</html>

View file

@ -50,20 +50,49 @@ const cssExample = `<span class="text-ice-300">/* All nodes default to fast + ch
<a href="/" class="flex items-center">
<img src="/logotype.svg" alt="Fabro" class="h-7" />
</a>
<a href="https://docs.fabro.sh" class="text-sm font-medium text-ice-100 hover:text-ice-50 transition-colors">Docs</a>
<a href="https://docs.fabro.sh/changelog" class="text-sm font-medium text-ice-100 hover:text-ice-50 transition-colors">Changelog</a>
<a href="/roadmap" class="text-sm font-medium text-ice-100 hover:text-ice-50 transition-colors">Roadmap</a>
<a href="https://docs.fabro.sh" class="hidden md:inline-flex text-sm font-medium text-ice-100 hover:text-ice-50 transition-colors">Docs</a>
<a href="/roadmap" class="hidden md:inline-flex text-sm font-medium text-ice-100 hover:text-ice-50 transition-colors">Roadmap</a>
<a href="https://docs.fabro.sh/changelog" class="hidden md:inline-flex text-sm font-medium text-ice-100 hover:text-ice-50 transition-colors">Changelog</a>
</div>
<div class="flex items-center gap-5">
<a href="/discord" class="text-ice-300 hover:text-ice-50 transition-colors" aria-label="Discord">
<a href="/discord" class="hidden md:block text-ice-300 hover:text-ice-50 transition-colors" aria-label="Discord">
<svg class="h-5 w-5" fill="currentColor" viewBox="0 0 24 24"><path d="M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057 19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028c.462-.63.874-1.295 1.226-1.994a.076.076 0 0 0-.041-.106 13.107 13.107 0 0 1-1.872-.892.077.077 0 0 1-.008-.128 10.2 10.2 0 0 0 .372-.292.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127 12.299 12.299 0 0 1-1.873.892.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.839 19.839 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.956-2.419 2.157-2.419 1.21 0 2.176 1.095 2.157 2.42 0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.955-2.419 2.157-2.419 1.21 0 2.176 1.095 2.157 2.42 0 1.333-.946 2.418-2.157 2.418z"/></svg>
</a>
<a href="https://github.com/fabro-sh/fabro" class="text-ice-300 hover:text-ice-50 transition-colors" aria-label="GitHub">
<a href="https://github.com/fabro-sh/fabro" class="hidden md:block text-ice-300 hover:text-ice-50 transition-colors" aria-label="GitHub">
<svg class="h-5 w-5" fill="currentColor" viewBox="0 0 24 24"><path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z"/></svg>
</a>
<a
href="https://docs.fabro.sh/getting-started/quick-start"
class="rounded-lg bg-teal-700 px-4 py-2 text-sm font-semibold text-white transition-all hover:bg-teal-500 hover:shadow-[0_0_20px_-4px_rgba(53,127,158,0.5)]"
class="hidden md:inline-flex rounded-lg bg-teal-700 px-4 py-2 text-sm font-semibold text-white transition-all hover:bg-teal-500 hover:shadow-[0_0_20px_-4px_rgba(53,127,158,0.5)]"
>
Get started
</a>
<!-- Mobile menu button -->
<button id="mobile-menu-btn" class="md:hidden text-ice-300 hover:text-ice-50 transition-colors" aria-label="Open menu">
<svg class="h-6 w-6" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24">
<line x1="3" y1="6" x2="21" y2="6" /><line x1="3" y1="12" x2="21" y2="12" /><line x1="3" y1="18" x2="21" y2="18" />
</svg>
</button>
</div>
</div>
<!-- Mobile menu panel -->
<div id="mobile-menu" class="md:hidden hidden border-t border-navy-800/60 bg-navy-950/95 backdrop-blur-xl">
<div class="px-6 py-5 space-y-4">
<a href="https://docs.fabro.sh" class="block text-sm font-medium text-ice-100 hover:text-ice-50 transition-colors">Docs</a>
<a href="/roadmap" class="block text-sm font-medium text-ice-100 hover:text-ice-50 transition-colors">Roadmap</a>
<a href="https://docs.fabro.sh/changelog" class="block text-sm font-medium text-ice-100 hover:text-ice-50 transition-colors">Changelog</a>
<hr class="border-navy-800/60" />
<div class="flex items-center gap-5">
<a href="/discord" class="text-ice-300 hover:text-ice-50 transition-colors" aria-label="Discord">
<svg class="h-5 w-5" fill="currentColor" viewBox="0 0 24 24"><path d="M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057 19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028c.462-.63.874-1.295 1.226-1.994a.076.076 0 0 0-.041-.106 13.107 13.107 0 0 1-1.872-.892.077.077 0 0 1-.008-.128 10.2 10.2 0 0 0 .372-.292.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127 12.299 12.299 0 0 1-1.873.892.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.839 19.839 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.956-2.419 2.157-2.419 1.21 0 2.176 1.095 2.157 2.42 0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.955-2.419 2.157-2.419 1.21 0 2.176 1.095 2.157 2.42 0 1.333-.946 2.418-2.157 2.418z"/></svg>
</a>
<a href="https://github.com/fabro-sh/fabro" class="text-ice-300 hover:text-ice-50 transition-colors" aria-label="GitHub">
<svg class="h-5 w-5" fill="currentColor" viewBox="0 0 24 24"><path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z"/></svg>
</a>
</div>
<a
href="https://docs.fabro.sh/getting-started/quick-start"
class="block w-full text-center rounded-lg bg-teal-700 px-4 py-2.5 text-sm font-semibold text-white transition-all hover:bg-teal-500"
>
Get started
</a>
@ -71,7 +100,7 @@ const cssExample = `<span class="text-ice-300">/* All nodes default to fast + ch
</div>
</nav>
<main>
<main class="overflow-x-hidden">
<!-- Hero -->
<section class="relative overflow-hidden pt-40 pb-24">
<!-- Atmosphere -->
@ -608,8 +637,8 @@ const cssExample = `<span class="text-ice-300">/* All nodes default to fast + ch
<ul class="space-y-2 text-sm">
<li><a href="https://docs.fabro.sh/getting-started/quick-start" class="text-ice-300 hover:text-ice-50 transition-colors">Quick Start</a></li>
<li><a href="https://docs.fabro.sh" class="text-ice-300 hover:text-ice-50 transition-colors">Docs</a></li>
<li><a href="https://docs.fabro.sh/changelog" class="text-ice-300 hover:text-ice-50 transition-colors">Changelog</a></li>
<li><a href="/roadmap" class="text-ice-300 hover:text-ice-50 transition-colors">Roadmap</a></li>
<li><a href="https://docs.fabro.sh/changelog" class="text-ice-300 hover:text-ice-50 transition-colors">Changelog</a></li>
<li><a href="https://github.com/fabro-sh/fabro/releases" class="text-ice-300 hover:text-ice-50 transition-colors">Releases</a></li>
</ul>
</div>
@ -636,6 +665,19 @@ const cssExample = `<span class="text-ice-300">/* All nodes default to fast + ch
</div>
<script>
// Mobile menu toggle
const mobileMenuBtn = document.getElementById("mobile-menu-btn")!;
const mobileMenu = document.getElementById("mobile-menu")!;
mobileMenuBtn.addEventListener("click", () => {
const isOpen = !mobileMenu.classList.contains("hidden");
mobileMenu.classList.toggle("hidden");
mobileMenuBtn.setAttribute("aria-label", isOpen ? "Open menu" : "Close menu");
// Swap icon between hamburger and X
mobileMenuBtn.innerHTML = isOpen
? '<svg class="h-6 w-6" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24"><line x1="3" y1="6" x2="21" y2="6" /><line x1="3" y1="12" x2="21" y2="12" /><line x1="3" y1="18" x2="21" y2="18" /></svg>'
: '<svg class="h-6 w-6" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24"><line x1="18" y1="6" x2="6" y2="18" /><line x1="6" y1="6" x2="18" y2="18" /></svg>';
});
// Lightbox with opacity transition
const lightbox = document.getElementById("lightbox")!;
const lightboxImg = document.getElementById("lightbox-img")! as HTMLImageElement;

View file

@ -38,13 +38,13 @@ const statusConfig = {
<!-- Nav -->
<nav class="fixed top-0 z-50 w-full border-b border-navy-800/60 bg-navy-950/70 backdrop-blur-xl">
<div class="mx-auto flex max-w-6xl items-center justify-between px-6 py-4">
<a href="/" class="flex items-center">
<img src="/logotype.svg" alt="Fabro" class="h-7" />
</a>
<div class="hidden md:flex items-center gap-8">
<a href="https://docs.fabro.sh" class="text-sm font-medium text-ice-100 hover:text-ice-50 transition-colors">Docs</a>
<a href="https://docs.fabro.sh/changelog" class="text-sm font-medium text-ice-100 hover:text-ice-50 transition-colors">Changelog</a>
<a href="/roadmap" class="text-sm font-medium text-ice-50 transition-colors">Roadmap</a>
<div class="flex items-center gap-8">
<a href="/" class="flex items-center">
<img src="/logotype.svg" alt="Fabro" class="h-7" />
</a>
<a href="https://docs.fabro.sh" class="hidden md:inline-flex text-sm font-medium text-ice-100 hover:text-ice-50 transition-colors">Docs</a>
<a href="/roadmap" class="hidden md:inline-flex text-sm font-medium text-ice-50 transition-colors">Roadmap</a>
<a href="https://docs.fabro.sh/changelog" class="hidden md:inline-flex text-sm font-medium text-ice-100 hover:text-ice-50 transition-colors">Changelog</a>
</div>
<div class="flex items-center gap-5">
<a href="/discord" class="hidden md:block text-ice-300 hover:text-ice-50 transition-colors" aria-label="Discord">
@ -69,8 +69,8 @@ const statusConfig = {
<div id="mobile-menu" class="md:hidden hidden border-t border-navy-800/60 bg-navy-950/95 backdrop-blur-xl">
<div class="px-6 py-5 space-y-4">
<a href="https://docs.fabro.sh" class="block text-sm font-medium text-ice-100 hover:text-ice-50 transition-colors">Docs</a>
<a href="https://docs.fabro.sh/changelog" class="block text-sm font-medium text-ice-100 hover:text-ice-50 transition-colors">Changelog</a>
<a href="/roadmap" class="block text-sm font-medium text-ice-50 transition-colors">Roadmap</a>
<a href="https://docs.fabro.sh/changelog" class="block text-sm font-medium text-ice-100 hover:text-ice-50 transition-colors">Changelog</a>
<hr class="border-navy-800/60" />
<div class="flex items-center gap-5">
<a href="/discord" class="text-ice-300 hover:text-ice-50 transition-colors" aria-label="Discord">
@ -272,8 +272,8 @@ const statusConfig = {
<ul class="space-y-2 text-sm">
<li><a href="https://docs.fabro.sh/getting-started/quick-start" class="text-ice-300 hover:text-ice-50 transition-colors">Quick Start</a></li>
<li><a href="https://docs.fabro.sh" class="text-ice-300 hover:text-ice-50 transition-colors">Docs</a></li>
<li><a href="https://docs.fabro.sh/changelog" class="text-ice-300 hover:text-ice-50 transition-colors">Changelog</a></li>
<li><a href="/roadmap" class="text-ice-300 hover:text-ice-50 transition-colors">Roadmap</a></li>
<li><a href="https://docs.fabro.sh/changelog" class="text-ice-300 hover:text-ice-50 transition-colors">Changelog</a></li>
<li><a href="https://github.com/fabro-sh/fabro/releases" class="text-ice-300 hover:text-ice-50 transition-colors">Releases</a></li>
</ul>
</div>

View file

@ -79,6 +79,11 @@
pointer-events: none;
}
/* Prevent grid/flex blowout from wide children (SVGs, pre blocks) */
.grid > * {
min-width: 0;
}
/* Feature card hover glow */
.glow-card {
transition: border-color 0.4s ease, box-shadow 0.4s ease, transform 0.4s ease;