diff --git a/landing-astro/astro.config.mjs b/landing-astro/astro.config.mjs
index 19c2326..78838de 100644
--- a/landing-astro/astro.config.mjs
+++ b/landing-astro/astro.config.mjs
@@ -7,8 +7,8 @@ import { readFile, writeFile } from 'node:fs/promises';
// Mirrors fleet/sarthakagrawal/astro.config.mjs, the reference 360 ms-LCP
// Astro setup. Pure static output (no SSR adapter) — the rolepatch.com
-// landing is fully static markup. Inline styles to avoid a render-blocking
-// request after the document; the overlay copies /_astro assets alongside it.
+// landing is fully static markup. The postbuild critical-CSS pass splits the
+// inlined home styles; the overlay copies /_astro assets alongside it.
//
// Tailwind v4 via the official Vite plugin (fleet web stack standard,
// VoidZero ecosystem). Lightning CSS replaces the default PostCSS
diff --git a/landing-astro/package.json b/landing-astro/package.json
index 4c03c57..eab5b1a 100644
--- a/landing-astro/package.json
+++ b/landing-astro/package.json
@@ -6,7 +6,7 @@
"description": "Static Astro port of the rolepatch.com landing page. Deploys to Cloudflare Pages and (post-cutover) serves the `/` route in front of the Next.js Worker.",
"scripts": {
"dev": "astro dev",
- "build": "astro build",
+ "build": "astro build && node ../scripts/run-inline-critical-css.mjs --astro",
"preview": "astro preview",
"astro": "astro",
"deploy": "wrangler pages deploy dist/ --project-name resume-tailor-landing --commit-dirty=true"
diff --git a/landing-astro/scripts/inline-critical-css.mjs b/landing-astro/scripts/inline-critical-css.mjs
new file mode 100644
index 0000000..1d9985f
--- /dev/null
+++ b/landing-astro/scripts/inline-critical-css.mjs
@@ -0,0 +1,334 @@
+import { createHash } from 'node:crypto';
+import { readFile, writeFile } from 'node:fs/promises';
+import { transform } from 'lightningcss';
+import { parseHTML } from 'linkedom';
+
+// Home alone uses the Workbench bundle. Keep static-page styles (including layout
+// below the fold, so an early scroll never exposes unstyled content), while the
+// library's other blocks, themes and dynamic states load asynchronously.
+export async function runAstroInlineCss() {
+ const file = new URL('../dist/index.html', import.meta.url);
+ const source = await readFile(file, 'utf8');
+ const styles = /`;
+ // Use identical responsive attributes on preload and img. The viewport picks
+ // one candidate for both; no mobile/full-size duplicate download.
+ const hero = html.match(/
]*\bsrc="\/images\/patch-stage\.webp"[^>]*>/)?.[0];
+ if (!hero) throw new Error('Expected the responsive Workbench hero');
+ const attribute = (name) => hero.match(new RegExp(`\\b${name}="([^"]+)"`, 'i'))?.[1];
+ if (!attribute('srcset') || !attribute('sizes')) {
+ throw new Error('Workbench hero is missing responsive attributes');
+ }
+ const preload = ``;
+ const result = html
+ .replace(/(?=]*id="proof")/, ``)
+ .replace('', `${links}`);
+ if (Buffer.byteLength(result.split('')[0]) >= 40_000) {
+ throw new Error(
+ `Home head exceeds the 40 KB critical-CSS budget: ${Buffer.byteLength(result.split('')[0])} bytes (${critical.length} CSS)`
+ );
+ }
+ await writeFile(file, result);
+ console.log(
+ `[inline-critical-css] Astro home: ${Buffer.byteLength(source)} → ${Buffer.byteLength(result)} bytes; head ${Buffer.byteLength(result.split('')[0])} bytes`
+ );
+}
diff --git a/landing-astro/src/components/DeferredScripts.astro b/landing-astro/src/components/DeferredScripts.astro
new file mode 100644
index 0000000..885cc2f
--- /dev/null
+++ b/landing-astro/src/components/DeferredScripts.astro
@@ -0,0 +1,60 @@
+
diff --git a/landing-astro/src/pages/index.astro b/landing-astro/src/pages/index.astro
index c237791..685a513 100644
--- a/landing-astro/src/pages/index.astro
+++ b/landing-astro/src/pages/index.astro
@@ -5,6 +5,7 @@ import { baseProps } from '@saas-maker/templates/page';
import { workbenchContent } from '@saas-maker/templates/schema';
import { APP_HEALTH_CLICK_SCRIPT, PRODUCT_FAQS, productJsonLd, REDIRECT_AUTHENTICATED_SCRIPT } from '@/lib/product';
import home from '../content/home.json';
+import DeferredScripts from '../components/DeferredScripts.astro';
const content = workbenchContent.parse(home);
const faqs = PRODUCT_FAQS.slice(0, 4);
@@ -48,7 +49,7 @@ content.page.jsonLd = [jsonLd, {
data-vitals-routes="changelog,docs,faq"
>
@@ -89,4 +90,5 @@ content.page.jsonLd = [jsonLd, {
+
diff --git a/scripts/run-inline-critical-css.mjs b/scripts/run-inline-critical-css.mjs
index c8e4201..b6ab961 100644
--- a/scripts/run-inline-critical-css.mjs
+++ b/scripts/run-inline-critical-css.mjs
@@ -1,4 +1,9 @@
#!/usr/bin/env node
import { runInlineCss } from './inline-critical-css.mjs';
-await runInlineCss({ strict: process.argv.includes('--strict') });
+if (process.argv.includes('--astro')) {
+ const { runAstroInlineCss } = await import('../landing-astro/scripts/inline-critical-css.mjs');
+ await runAstroInlineCss();
+} else {
+ await runInlineCss({ strict: process.argv.includes('--strict') });
+}