@farm.js/create-app 0.1.0-beta.7 → 0.1.0-beta.71

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (173) hide show
  1. package/README.md +38 -6
  2. package/bin/create-farm-app.js +7 -2
  3. package/dist/index.js +3298 -16
  4. package/dist/index.js.map +1 -1
  5. package/dist/index.mjs +3294 -14
  6. package/dist/index.mjs.map +1 -1
  7. package/dist/utils.js +9 -6
  8. package/dist/utils.js.map +1 -1
  9. package/dist/utils.mjs +9 -6
  10. package/dist/utils.mjs.map +1 -1
  11. package/package.json +2 -2
  12. package/templates/_integrations/better-auth/preact/farm.config.ts +17 -0
  13. package/templates/_integrations/better-auth/preact/src/app/dashboard/page.tsx +73 -0
  14. package/templates/_integrations/better-auth/preact/src/app/layout.tsx +14 -0
  15. package/templates/_integrations/better-auth/preact/src/app/page.tsx +36 -0
  16. package/templates/_integrations/better-auth/preact/src/app/sign-in/page.tsx +10 -0
  17. package/templates/_integrations/better-auth/preact/src/app/sign-up/page.tsx +10 -0
  18. package/templates/_integrations/better-auth/preact/src/components/auth-form.tsx +92 -0
  19. package/templates/_integrations/better-auth/preact/src/components/auth-shell.tsx +16 -0
  20. package/templates/_integrations/better-auth/preact/src/lib/auth-client.ts +5 -0
  21. package/templates/_integrations/better-auth/solid/farm.config.ts +17 -0
  22. package/templates/_integrations/better-auth/solid/src/app/dashboard/page.tsx +67 -0
  23. package/templates/_integrations/better-auth/solid/src/app/layout.tsx +14 -0
  24. package/templates/_integrations/better-auth/solid/src/app/page.tsx +36 -0
  25. package/templates/_integrations/better-auth/solid/src/app/sign-in/page.tsx +10 -0
  26. package/templates/_integrations/better-auth/solid/src/app/sign-up/page.tsx +10 -0
  27. package/templates/_integrations/better-auth/solid/src/components/auth-form.tsx +91 -0
  28. package/templates/_integrations/better-auth/solid/src/components/auth-shell.tsx +16 -0
  29. package/templates/_integrations/better-auth/solid/src/lib/auth-client.ts +5 -0
  30. package/templates/_integrations/better-auth/svelte/farm.config.ts +17 -0
  31. package/templates/_integrations/better-auth/svelte/src/app/dashboard/page.svelte +62 -0
  32. package/templates/_integrations/better-auth/svelte/src/app/layout.svelte +20 -0
  33. package/templates/_integrations/better-auth/svelte/src/app/page.svelte +32 -0
  34. package/templates/_integrations/better-auth/svelte/src/app/sign-in/page.svelte +10 -0
  35. package/templates/_integrations/better-auth/svelte/src/app/sign-up/page.svelte +10 -0
  36. package/templates/_integrations/better-auth/svelte/src/components/auth-form.svelte +83 -0
  37. package/templates/_integrations/better-auth/svelte/src/components/auth-shell.svelte +16 -0
  38. package/templates/_integrations/better-auth/svelte/src/components/resource-links.svelte +47 -0
  39. package/templates/_integrations/better-auth/svelte/src/lib/auth-client.ts +5 -0
  40. package/templates/_integrations/better-auth/vue/farm.config.ts +17 -0
  41. package/templates/_integrations/better-auth/vue/src/app/dashboard/page.vue +62 -0
  42. package/templates/_integrations/better-auth/vue/src/app/layout.vue +20 -0
  43. package/templates/_integrations/better-auth/vue/src/app/page.vue +34 -0
  44. package/templates/_integrations/better-auth/vue/src/app/sign-in/page.vue +12 -0
  45. package/templates/_integrations/better-auth/vue/src/app/sign-up/page.vue +12 -0
  46. package/templates/_integrations/better-auth/vue/src/components/auth-form.vue +86 -0
  47. package/templates/_integrations/better-auth/vue/src/components/auth-shell.vue +15 -0
  48. package/templates/_integrations/better-auth/vue/src/components/resource-links.vue +43 -0
  49. package/templates/_integrations/better-auth/vue/src/lib/auth-client.ts +5 -0
  50. package/templates/_renderers/preact/farm.config.ts +12 -0
  51. package/templates/_renderers/preact/package.json +26 -0
  52. package/templates/_renderers/preact/src/app/api/greeting/route.ts +15 -0
  53. package/templates/_renderers/preact/src/app/layout.tsx +16 -0
  54. package/templates/_renderers/preact/src/app/page.tsx +66 -0
  55. package/templates/_renderers/preact/src/app/preact.css +26 -0
  56. package/templates/_renderers/preact/src/components/resource-links.tsx +71 -0
  57. package/templates/_renderers/preact/src/lib/api-client.ts +4 -0
  58. package/templates/_renderers/preact/src/lib/api.generated.ts +7 -0
  59. package/templates/_renderers/preact/tsconfig.json +25 -0
  60. package/templates/_renderers/solid/farm.config.ts +12 -0
  61. package/templates/_renderers/solid/package.json +25 -0
  62. package/templates/_renderers/solid/src/app/api/greeting/route.ts +15 -0
  63. package/templates/_renderers/solid/src/app/layout.tsx +15 -0
  64. package/templates/_renderers/solid/src/app/page.tsx +56 -0
  65. package/templates/_renderers/solid/src/app/solid.css +22 -0
  66. package/templates/_renderers/solid/src/components/resource-links.tsx +71 -0
  67. package/templates/_renderers/solid/src/lib/api-client.ts +4 -0
  68. package/templates/_renderers/solid/src/lib/api.generated.ts +7 -0
  69. package/templates/_renderers/solid/tsconfig.json +25 -0
  70. package/templates/_renderers/svelte/farm.config.ts +9 -0
  71. package/templates/_renderers/svelte/package.json +28 -0
  72. package/templates/_renderers/svelte/src/app/api/greeting/route.ts +15 -0
  73. package/templates/_renderers/svelte/src/app/layout.svelte +21 -0
  74. package/templates/_renderers/svelte/src/app/page.svelte +64 -0
  75. package/templates/_renderers/svelte/src/app/svelte.css +26 -0
  76. package/templates/_renderers/svelte/src/components/resource-links.svelte +31 -0
  77. package/templates/_renderers/svelte/src/lib/api-client.ts +4 -0
  78. package/templates/_renderers/svelte/src/lib/api.generated.ts +7 -0
  79. package/templates/_renderers/svelte/tsconfig.json +23 -0
  80. package/templates/_renderers/vue/farm.config.ts +12 -0
  81. package/templates/_renderers/vue/package.json +26 -0
  82. package/templates/_renderers/vue/src/app/api/greeting/route.ts +15 -0
  83. package/templates/_renderers/vue/src/app/layout.vue +21 -0
  84. package/templates/_renderers/vue/src/app/page.vue +69 -0
  85. package/templates/_renderers/vue/src/app/vue.css +26 -0
  86. package/templates/_renderers/vue/src/components/resource-links.vue +33 -0
  87. package/templates/_renderers/vue/src/env.d.ts +7 -0
  88. package/templates/_renderers/vue/src/lib/api-client.ts +4 -0
  89. package/templates/_renderers/vue/src/lib/api.generated.ts +7 -0
  90. package/templates/_renderers/vue/tsconfig.json +23 -0
  91. package/templates/auth/.env.example +6 -0
  92. package/templates/auth/README.md +95 -0
  93. package/templates/auth/docs.config.ts +33 -0
  94. package/templates/auth/docs.json +36 -0
  95. package/templates/auth/farm.config.ts +20 -0
  96. package/templates/auth/gitignore +10 -0
  97. package/templates/auth/package.json +34 -0
  98. package/templates/auth/pnpm-workspace.yaml +13 -0
  99. package/templates/auth/src/app/dashboard/middleware.ts +13 -0
  100. package/templates/auth/src/app/dashboard/page.tsx +140 -0
  101. package/templates/auth/src/app/docs/page.md +29 -0
  102. package/templates/auth/src/app/error.tsx +25 -0
  103. package/templates/auth/src/app/globals.css +1064 -0
  104. package/templates/auth/src/app/layout.tsx +11 -0
  105. package/templates/auth/src/app/loading.tsx +15 -0
  106. package/templates/auth/src/app/not-found.tsx +26 -0
  107. package/templates/auth/src/app/page.tsx +46 -0
  108. package/templates/auth/src/app/sign-in/page.tsx +16 -0
  109. package/templates/auth/src/app/sign-up/page.tsx +16 -0
  110. package/templates/auth/src/components/auth-form.tsx +120 -0
  111. package/templates/auth/src/components/auth-shell.tsx +21 -0
  112. package/templates/auth/src/components/resource-links.tsx +78 -0
  113. package/templates/auth/src/components/sign-out-button.tsx +45 -0
  114. package/templates/auth/src/components/site-header.tsx +46 -0
  115. package/templates/auth/tsconfig.json +20 -0
  116. package/templates/basic/docs.config.ts +33 -0
  117. package/templates/basic/docs.json +36 -0
  118. package/templates/basic/farm.config.ts +9 -0
  119. package/templates/basic/package.json +7 -3
  120. package/templates/basic/pnpm-workspace.yaml +8 -0
  121. package/templates/basic/src/app/docs/page.md +29 -0
  122. package/templates/basic/src/app/globals.css +241 -0
  123. package/templates/basic/src/app/layout.tsx +3 -5
  124. package/templates/basic/src/app/page.tsx +20 -61
  125. package/templates/basic/src/components/resource-links.tsx +78 -0
  126. package/templates/basic/tsconfig.json +4 -0
  127. package/templates/better-auth/.env.example +3 -0
  128. package/templates/better-auth/README.md +89 -0
  129. package/templates/better-auth/docs.config.ts +33 -0
  130. package/templates/better-auth/docs.json +36 -0
  131. package/templates/better-auth/farm.config.ts +38 -0
  132. package/templates/better-auth/gitignore +10 -0
  133. package/templates/better-auth/package.json +36 -0
  134. package/templates/better-auth/pnpm-workspace.yaml +13 -0
  135. package/templates/better-auth/src/app/dashboard/middleware.ts +15 -0
  136. package/templates/better-auth/src/app/dashboard/page.tsx +188 -0
  137. package/templates/better-auth/src/app/docs/page.md +29 -0
  138. package/templates/better-auth/src/app/error.tsx +25 -0
  139. package/templates/better-auth/src/app/globals.css +1064 -0
  140. package/templates/better-auth/src/app/layout.tsx +11 -0
  141. package/templates/better-auth/src/app/loading.tsx +15 -0
  142. package/templates/better-auth/src/app/not-found.tsx +26 -0
  143. package/templates/better-auth/src/app/page.tsx +50 -0
  144. package/templates/better-auth/src/app/sign-in/page.tsx +16 -0
  145. package/templates/better-auth/src/app/sign-up/page.tsx +16 -0
  146. package/templates/better-auth/src/components/auth-form.tsx +120 -0
  147. package/templates/better-auth/src/components/auth-shell.tsx +21 -0
  148. package/templates/better-auth/src/components/resource-links.tsx +78 -0
  149. package/templates/better-auth/src/components/sign-out-button.tsx +45 -0
  150. package/templates/better-auth/src/components/site-header.tsx +46 -0
  151. package/templates/better-auth/src/lib/auth-client.ts +5 -0
  152. package/templates/better-auth/src/lib/auth.ts +50 -0
  153. package/templates/better-auth/src/lib/session.ts +8 -0
  154. package/templates/better-auth/tsconfig.json +20 -0
  155. package/templates/react-compiler/README.md +62 -0
  156. package/templates/react-compiler/docs.config.ts +33 -0
  157. package/templates/react-compiler/docs.json +36 -0
  158. package/templates/react-compiler/farm.config.ts +29 -0
  159. package/templates/react-compiler/gitignore +23 -0
  160. package/templates/react-compiler/package.json +34 -0
  161. package/templates/react-compiler/pnpm-workspace.yaml +8 -0
  162. package/templates/react-compiler/public/favicon.svg +5 -0
  163. package/templates/react-compiler/scripts/verify-experiment.mjs +113 -0
  164. package/templates/react-compiler/src/app/docs/page.md +29 -0
  165. package/templates/react-compiler/src/app/globals.css +470 -0
  166. package/templates/react-compiler/src/app/layout.tsx +22 -0
  167. package/templates/react-compiler/src/app/page.tsx +47 -0
  168. package/templates/react-compiler/src/components/compiler-comparison.tsx +93 -0
  169. package/templates/react-compiler/src/components/resource-links.tsx +78 -0
  170. package/templates/react-compiler/src/farm.d.ts +74 -0
  171. package/templates/react-compiler/src/lib/api.generated.ts +10 -0
  172. package/templates/react-compiler/tsconfig.json +24 -0
  173. package/templates/basic/src/app/about/page.tsx +0 -32
@@ -0,0 +1,29 @@
1
+ import { defineConfig } from "@farm.js/core";
2
+ import { react } from "@farm.js/react";
3
+
4
+ const compilerEnabled = process.env.FARM_REACT_COMPILER !== "false";
5
+
6
+ export default defineConfig({
7
+ env: {
8
+ public: {
9
+ FARM_REACT_COMPILER_ENABLED: () => compilerEnabled,
10
+ },
11
+ },
12
+ renderer: react({
13
+ experimental: {
14
+ compiler: compilerEnabled,
15
+ },
16
+ }),
17
+ theme: {
18
+ default: "dark",
19
+ },
20
+ // Docs are powered by the @farming-labs/farmjs framework. Farm auto-detects
21
+ // the installed adapter and reads docs.config.ts (docs.json is kept as a
22
+ // language-agnostic fallback/manifest); content lives in src/app/docs.
23
+ docs: {
24
+ enabled: true,
25
+ },
26
+ deploy: {
27
+ target: "node",
28
+ },
29
+ });
@@ -0,0 +1,23 @@
1
+ # Dependencies
2
+ node_modules/
3
+
4
+ # Farm and deployment output
5
+ .farm/
6
+ .output/
7
+ .vercel/
8
+ dist/
9
+
10
+ # Local environment files
11
+ .env
12
+ .env.local
13
+ .env.*.local
14
+
15
+ # Local databases
16
+ *.sqlite
17
+ *.sqlite-*
18
+ *.db
19
+ *.db-*
20
+
21
+ # Logs and TypeScript cache
22
+ *.log
23
+ *.tsbuildinfo
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "farmjs-react-compiler-starter",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "farm dev",
8
+ "build": "farm build",
9
+ "start": "farm start",
10
+ "experiment": "pnpm run build && node scripts/verify-experiment.mjs",
11
+ "type-check": "tsc --noEmit"
12
+ },
13
+ "dependencies": {
14
+ "@farm.js/core": "0.1.0-beta.71",
15
+ "@farm.js/react": "0.1.0-beta.6",
16
+ "@farming-labs/docs": "0.2.111",
17
+ "@farming-labs/farmjs": "0.2.111",
18
+ "@farming-labs/theme": "0.2.111",
19
+ "@fontsource-variable/geist": "5.3.0",
20
+ "@fontsource-variable/geist-mono": "5.3.0",
21
+ "react": "19.2.8",
22
+ "react-dom": "19.2.8"
23
+ },
24
+ "devDependencies": {
25
+ "@farm.js/cli": "0.1.0-beta.71",
26
+ "@playwright/test": "^1.52.0",
27
+ "@types/react": "^19.0.0",
28
+ "@types/react-dom": "^19.0.0",
29
+ "tailwindcss": "^4.0.0",
30
+ "typescript": "^5.3.3",
31
+ "vite": "^5.0.10"
32
+ },
33
+ "packageManager": "pnpm@8.12.1"
34
+ }
@@ -0,0 +1,8 @@
1
+ packages:
2
+ - "."
3
+
4
+ allowBuilds:
5
+ "@prisma/client": true
6
+ esbuild: true
7
+ sharp: true
8
+ vue-demi: true
@@ -0,0 +1,5 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" role="img" aria-labelledby="title">
2
+ <title id="title">FARMJS React AOT</title>
3
+ <rect width="64" height="64" rx="14" fill="#0a0a09"/>
4
+ <path d="M18 16h30v8H28v8h17v8H28v16H18z" fill="#b8ff5b"/>
5
+ </svg>
@@ -0,0 +1,113 @@
1
+ import assert from "node:assert/strict";
2
+ import { spawn } from "node:child_process";
3
+ import { access } from "node:fs/promises";
4
+ import path from "node:path";
5
+ import { chromium } from "@playwright/test";
6
+
7
+ const port = Number(process.env.FARM_EXPERIMENT_PORT || 4327);
8
+ const origin = `http://127.0.0.1:${port}`;
9
+ const compilerEnabled = process.env.FARM_REACT_COMPILER !== "false";
10
+ const serverEntry = path.resolve(".farm/.output/server/index.mjs");
11
+ const screenshotPath =
12
+ process.env.FARM_EXPERIMENT_SCREENSHOT || "/tmp/farm-react-compiler-starter.png";
13
+
14
+ await access(serverEntry);
15
+
16
+ let serverOutput = "";
17
+ const server = spawn(process.execPath, [serverEntry], {
18
+ env: {
19
+ ...process.env,
20
+ HOST: "127.0.0.1",
21
+ NITRO_HOST: "127.0.0.1",
22
+ NITRO_PORT: String(port),
23
+ PORT: String(port),
24
+ },
25
+ stdio: ["ignore", "pipe", "pipe"],
26
+ });
27
+
28
+ server.stdout.on("data", (chunk) => {
29
+ serverOutput += chunk;
30
+ });
31
+ server.stderr.on("data", (chunk) => {
32
+ serverOutput += chunk;
33
+ });
34
+
35
+ async function waitForServer() {
36
+ for (let attempt = 0; attempt < 120; attempt += 1) {
37
+ if (server.exitCode !== null) {
38
+ throw new Error(`Production server exited early.\n${serverOutput}`);
39
+ }
40
+ try {
41
+ const response = await fetch(origin);
42
+ if (response.ok) return;
43
+ } catch {
44
+ // The server is still starting.
45
+ }
46
+ await new Promise((resolve) => setTimeout(resolve, 100));
47
+ }
48
+ throw new Error(`Production server did not start.\n${serverOutput}`);
49
+ }
50
+
51
+ async function readNumber(page, selector) {
52
+ return Number((await page.locator(selector).textContent())?.trim());
53
+ }
54
+
55
+ let browser;
56
+ try {
57
+ await waitForServer();
58
+ browser = await chromium.launch({ headless: true });
59
+ const page = await browser.newPage({ viewport: { width: 1280, height: 900 } });
60
+ const browserErrors = [];
61
+
62
+ page.on("console", (message) => {
63
+ if (message.type() === "error") browserErrors.push(message.text());
64
+ });
65
+ page.on("pageerror", (error) => browserErrors.push(error.message));
66
+
67
+ await page.goto(origin, { waitUntil: "networkidle" });
68
+ await page.getByRole("heading", { name: /compiler handles the rest/i }).waitFor();
69
+ assert.equal(
70
+ (await page.locator("[data-compiler-status]").textContent())?.trim(),
71
+ `experimental.compiler: ${String(compilerEnabled)}`,
72
+ );
73
+
74
+ const executions = {};
75
+ for (const pathName of ["compiled", "react"]) {
76
+ const root = `[data-path="${pathName}"]`;
77
+ executions[pathName] = {
78
+ initial: await readNumber(page, `${root} [data-metric="executions"]`),
79
+ };
80
+ await page.locator(`${root} [data-action="update"]`).click();
81
+ await page.locator(`${root} [data-action="update"]`).click();
82
+ await page.waitForFunction(
83
+ (selector) => document.querySelector(selector)?.textContent?.trim() === "2",
84
+ `${root} [data-metric="state"]`,
85
+ );
86
+ executions[pathName].final = await readNumber(page, `${root} [data-metric="executions"]`);
87
+ executions[pathName].added = executions[pathName].final - executions[pathName].initial;
88
+ }
89
+
90
+ assert.equal(executions.compiled.added, compilerEnabled ? 0 : 2);
91
+ assert.equal(executions.react.added, 2);
92
+ assert.deepEqual(browserErrors, []);
93
+
94
+ await page.screenshot({ path: screenshotPath, fullPage: true });
95
+
96
+ console.log(
97
+ JSON.stringify(
98
+ {
99
+ result: "PASS",
100
+ productionUrl: origin,
101
+ screenshot: screenshotPath,
102
+ compilerEnabled,
103
+ compiledUpdateExecutions: executions.compiled.added,
104
+ reactUpdateExecutions: executions.react.added,
105
+ },
106
+ null,
107
+ 2,
108
+ ),
109
+ );
110
+ } finally {
111
+ await browser?.close();
112
+ server.kill("SIGTERM");
113
+ }
@@ -0,0 +1,29 @@
1
+ ---
2
+ title: "Getting Started"
3
+ description: "Your Farm.js documentation, powered by the @farming-labs/farmjs docs framework."
4
+ ---
5
+
6
+ # Getting Started
7
+
8
+ These docs are served by the Farm docs runtime, powered by the
9
+ [@farming-labs/farmjs](https://www.npmjs.com/package/@farming-labs/farmjs) docs
10
+ framework. The same Markdown files power human pages, Markdown routes,
11
+ `llms.txt`, the sitemap, search, and agent discovery through `/api/docs`.
12
+
13
+ ## Edit this page
14
+
15
+ This page lives at `src/app/docs/page.md`. Add more pages as folders with their
16
+ own `page.md` — for example `src/app/docs/configuration/page.md` is served at
17
+ `/docs/configuration`.
18
+
19
+ ## Configure
20
+
21
+ Site-wide docs settings live in `docs.config.ts` at the project root (title,
22
+ navigation, search, `llms.txt`, sitemap, and robots). Farm auto-detects the
23
+ installed adapter because `farm.config.ts` sets `docs: { enabled: true }` — no
24
+ manual wiring required.
25
+
26
+ ## Learn more
27
+
28
+ - [Farm.js documentation](https://farm.js.dev/docs)
29
+ - [Configuration guide](https://farm.js.dev/docs/configuration)
@@ -0,0 +1,470 @@
1
+ @import "@fontsource-variable/geist/wght.css";
2
+ @import "@fontsource-variable/geist-mono/wght.css";
3
+ @import "tailwindcss";
4
+
5
+ :root {
6
+ --paper: #000000;
7
+ --paper-soft: #080808;
8
+ --ink: #f5f5f5;
9
+ --ink-soft: #a1a1a1;
10
+ --ink-faint: #686868;
11
+ --line: rgb(255 255 255 / 0.12);
12
+ --line-strong: rgb(255 255 255 / 0.22);
13
+ --accent: #b8ff5b;
14
+ --accent-soft: rgb(184 255 91 / 0.1);
15
+ --focus: #ffffff;
16
+ --font-sans: "Geist Variable", ui-sans-serif, system-ui, sans-serif;
17
+ --font-mono: "Geist Mono Variable", ui-monospace, monospace;
18
+ color-scheme: dark;
19
+ color: var(--ink);
20
+ font-family: var(--font-sans);
21
+ font-synthesis: none;
22
+ }
23
+
24
+ * {
25
+ box-sizing: border-box;
26
+ }
27
+
28
+ html {
29
+ min-width: 320px;
30
+ min-height: 100%;
31
+ background: var(--paper);
32
+ }
33
+
34
+ body {
35
+ min-height: 100vh;
36
+ margin: 0;
37
+ background: var(--paper);
38
+ color: var(--ink);
39
+ font-family: var(--font-sans);
40
+ text-rendering: optimizeLegibility;
41
+ }
42
+
43
+ button,
44
+ input {
45
+ font: inherit;
46
+ }
47
+
48
+ button,
49
+ a {
50
+ -webkit-tap-highlight-color: transparent;
51
+ }
52
+
53
+ button {
54
+ color: inherit;
55
+ }
56
+
57
+ a {
58
+ color: inherit;
59
+ text-decoration: none;
60
+ }
61
+
62
+ code {
63
+ font-family: var(--font-mono);
64
+ }
65
+
66
+ ::selection {
67
+ background: white;
68
+ color: black;
69
+ }
70
+
71
+ :focus-visible {
72
+ outline: 2px solid var(--focus);
73
+ outline-offset: 3px;
74
+ }
75
+
76
+ .landing-main {
77
+ position: relative;
78
+ isolation: isolate;
79
+ width: 100%;
80
+ min-height: 100vh;
81
+ overflow: hidden;
82
+ background: var(--paper);
83
+ }
84
+
85
+ .hero-section {
86
+ position: relative;
87
+ display: flex;
88
+ width: 100%;
89
+ min-height: 100vh;
90
+ align-items: center;
91
+ justify-content: flex-start;
92
+ padding: clamp(2.5rem, 6vh, 5rem) clamp(1.25rem, 7vw, 6rem);
93
+ }
94
+
95
+ .hero-section::before,
96
+ .hero-section::after {
97
+ position: absolute;
98
+ width: 9px;
99
+ height: 9px;
100
+ border-color: rgb(255 255 255 / 0.3);
101
+ content: "";
102
+ pointer-events: none;
103
+ }
104
+
105
+ .hero-section::before {
106
+ top: -1px;
107
+ left: -1px;
108
+ border-top: 1px solid;
109
+ border-left: 1px solid;
110
+ }
111
+
112
+ .hero-section::after {
113
+ right: 0;
114
+ bottom: -1px;
115
+ border-right: 1px solid;
116
+ border-bottom: 1px solid;
117
+ }
118
+
119
+ .hero-copy {
120
+ width: min(100%, 760px);
121
+ margin: 0;
122
+ }
123
+
124
+ .eyebrow-row {
125
+ display: flex;
126
+ flex-wrap: wrap;
127
+ align-items: center;
128
+ gap: 0.65rem;
129
+ color: var(--ink-faint);
130
+ font-family: var(--font-mono);
131
+ font-size: 0.67rem;
132
+ text-transform: uppercase;
133
+ }
134
+
135
+ .eyebrow-row > span:first-child {
136
+ color: var(--ink);
137
+ }
138
+
139
+ .experimental-label {
140
+ border-left: 1px solid var(--line-strong);
141
+ padding-left: 0.65rem;
142
+ color: var(--accent);
143
+ }
144
+
145
+ .hero-copy h1 {
146
+ max-width: 700px;
147
+ margin: 1.4rem 0 0;
148
+ font-size: clamp(2.15rem, 4vw, 3.55rem);
149
+ font-weight: 510;
150
+ letter-spacing: -0.055em;
151
+ line-height: 1.02;
152
+ }
153
+
154
+ .hero-copy h1 code {
155
+ border: 1px solid var(--line);
156
+ background: rgb(255 255 255 / 0.07);
157
+ padding: 0.04em 0.2em;
158
+ font-size: 0.76em;
159
+ font-weight: 450;
160
+ letter-spacing: -0.035em;
161
+ white-space: nowrap;
162
+ }
163
+
164
+ .hero-summary {
165
+ max-width: 590px;
166
+ margin: 1rem 0 0;
167
+ color: var(--ink-soft);
168
+ font-size: 0.91rem;
169
+ line-height: 1.6;
170
+ }
171
+
172
+ .command-list {
173
+ max-width: 590px;
174
+ margin-top: 1.65rem;
175
+ border-block: 1px solid var(--line);
176
+ }
177
+
178
+ .command-row {
179
+ display: grid;
180
+ min-width: 0;
181
+ grid-template-columns: auto minmax(0, 1fr);
182
+ align-items: center;
183
+ gap: 0.8rem;
184
+ padding: 0.82rem 0;
185
+ }
186
+
187
+ .command-row + .command-row {
188
+ border-top: 1px solid var(--line);
189
+ }
190
+
191
+ .command-row > span {
192
+ color: var(--ink-faint);
193
+ font-family: var(--font-mono);
194
+ font-size: 0.62rem;
195
+ }
196
+
197
+ .command-row code {
198
+ color: var(--ink);
199
+ font-size: 0.75rem;
200
+ overflow-wrap: anywhere;
201
+ }
202
+
203
+ .compiler-status {
204
+ display: inline-flex;
205
+ min-width: 0;
206
+ align-items: center;
207
+ gap: 0.65rem;
208
+ }
209
+
210
+ .status-dot {
211
+ width: 7px;
212
+ height: 7px;
213
+ flex: 0 0 auto;
214
+ border-radius: 50%;
215
+ background: var(--accent);
216
+ box-shadow: 0 0 0 3px var(--accent-soft);
217
+ }
218
+
219
+ .status-dot[data-enabled="false"] {
220
+ background: var(--ink-faint);
221
+ box-shadow: 0 0 0 3px rgb(255 255 255 / 6%);
222
+ }
223
+
224
+ .compiler-check {
225
+ margin-top: 1.9rem;
226
+ border: 1px solid var(--line);
227
+ background: var(--paper-soft);
228
+ }
229
+
230
+ .check-heading {
231
+ display: flex;
232
+ align-items: flex-end;
233
+ justify-content: space-between;
234
+ gap: 1.5rem;
235
+ border-bottom: 1px solid var(--line);
236
+ padding: 0.95rem 1rem;
237
+ }
238
+
239
+ .check-heading span {
240
+ color: var(--accent);
241
+ font-family: var(--font-mono);
242
+ font-size: 0.58rem;
243
+ letter-spacing: 0.05em;
244
+ text-transform: uppercase;
245
+ }
246
+
247
+ .check-heading h2 {
248
+ margin: 0.24rem 0 0;
249
+ font-size: 1rem;
250
+ font-weight: 560;
251
+ letter-spacing: -0.025em;
252
+ }
253
+
254
+ .check-heading p {
255
+ margin: 0;
256
+ color: var(--ink-faint);
257
+ font-family: var(--font-mono);
258
+ font-size: 0.62rem;
259
+ }
260
+
261
+ .comparison-grid {
262
+ display: grid;
263
+ grid-template-columns: repeat(2, minmax(0, 1fr));
264
+ }
265
+
266
+ .counter-path {
267
+ min-width: 0;
268
+ padding: 1rem;
269
+ }
270
+
271
+ .counter-path + .counter-path {
272
+ border-left: 1px solid var(--line);
273
+ }
274
+
275
+ .counter-path-compiled {
276
+ box-shadow: inset 0 2px 0 var(--accent);
277
+ }
278
+
279
+ .counter-heading {
280
+ display: flex;
281
+ align-items: center;
282
+ gap: 0.7rem;
283
+ }
284
+
285
+ .path-index {
286
+ display: inline-grid;
287
+ width: 23px;
288
+ height: 23px;
289
+ flex: 0 0 auto;
290
+ place-items: center;
291
+ border: 1px solid var(--line-strong);
292
+ border-radius: 50%;
293
+ color: var(--ink-soft);
294
+ font-family: var(--font-mono);
295
+ font-size: 0.58rem;
296
+ }
297
+
298
+ .counter-path-compiled .path-index {
299
+ border-color: rgb(184 255 91 / 0.35);
300
+ color: var(--accent);
301
+ }
302
+
303
+ .counter-heading h3,
304
+ .counter-heading p {
305
+ margin: 0;
306
+ }
307
+
308
+ .counter-heading h3 {
309
+ font-size: 0.82rem;
310
+ font-weight: 570;
311
+ }
312
+
313
+ .counter-heading p {
314
+ margin-top: 0.12rem;
315
+ color: var(--ink-faint);
316
+ font-family: var(--font-mono);
317
+ font-size: 0.56rem;
318
+ text-transform: uppercase;
319
+ }
320
+
321
+ .counter-metrics {
322
+ display: grid;
323
+ grid-template-columns: repeat(2, minmax(0, 1fr));
324
+ margin: 1rem 0;
325
+ border-block: 1px solid var(--line);
326
+ }
327
+
328
+ .counter-metrics > div {
329
+ padding: 0.75rem 0;
330
+ }
331
+
332
+ .counter-metrics > div + div {
333
+ border-left: 1px solid var(--line);
334
+ padding-left: 0.85rem;
335
+ }
336
+
337
+ .counter-metrics dt {
338
+ color: var(--ink-faint);
339
+ font-family: var(--font-mono);
340
+ font-size: 0.54rem;
341
+ text-transform: uppercase;
342
+ }
343
+
344
+ .counter-metrics dd {
345
+ margin: 0.2rem 0 0;
346
+ font-size: 1.45rem;
347
+ font-weight: 520;
348
+ letter-spacing: -0.04em;
349
+ }
350
+
351
+ .counter-path button {
352
+ display: inline-flex;
353
+ width: 100%;
354
+ min-height: 42px;
355
+ align-items: center;
356
+ justify-content: space-between;
357
+ gap: 1rem;
358
+ border: 1px solid var(--line-strong);
359
+ background: transparent;
360
+ padding: 0.65rem 0.75rem;
361
+ font-family: var(--font-mono);
362
+ font-size: 0.62rem;
363
+ cursor: pointer;
364
+ transition:
365
+ background-color 150ms ease,
366
+ border-color 150ms ease,
367
+ color 150ms ease,
368
+ transform 100ms ease;
369
+ }
370
+
371
+ .counter-path-compiled button {
372
+ border-color: rgb(184 255 91 / 0.42);
373
+ }
374
+
375
+ .counter-path button:active {
376
+ transform: translateY(1px);
377
+ }
378
+
379
+ .resource-links {
380
+ display: flex;
381
+ flex-wrap: wrap;
382
+ gap: 0.65rem;
383
+ margin-top: 1.35rem;
384
+ color: var(--ink-soft);
385
+ font-family: var(--font-mono);
386
+ font-size: 0.68rem;
387
+ text-transform: uppercase;
388
+ }
389
+
390
+ .resource-link-item {
391
+ display: inline-flex;
392
+ align-items: center;
393
+ gap: 0.65rem;
394
+ white-space: nowrap;
395
+ }
396
+
397
+ .resource-separator {
398
+ color: var(--ink-faint);
399
+ user-select: none;
400
+ }
401
+
402
+ .resource-links a {
403
+ display: inline-flex;
404
+ align-items: center;
405
+ gap: 0.45rem;
406
+ border-bottom: 1px solid transparent;
407
+ padding-block: 0.2rem;
408
+ transition:
409
+ border-color 150ms ease,
410
+ color 150ms ease;
411
+ }
412
+
413
+ .resource-icon {
414
+ width: 0.85rem;
415
+ height: 0.85rem;
416
+ flex: 0 0 auto;
417
+ }
418
+
419
+ @media (hover: hover) and (pointer: fine) {
420
+ .counter-path button:hover {
421
+ border-color: var(--ink-soft);
422
+ background: rgb(255 255 255 / 0.05);
423
+ }
424
+
425
+ .counter-path-compiled button:hover {
426
+ border-color: var(--accent);
427
+ background: var(--accent-soft);
428
+ }
429
+
430
+ .resource-links a:hover {
431
+ border-color: currentColor;
432
+ color: var(--ink);
433
+ }
434
+ }
435
+
436
+ @media (max-width: 680px) {
437
+ .hero-section {
438
+ align-items: flex-start;
439
+ padding: 2.25rem 1.25rem;
440
+ }
441
+
442
+ .hero-copy h1 {
443
+ font-size: clamp(2rem, 10vw, 2.75rem);
444
+ overflow-wrap: anywhere;
445
+ }
446
+
447
+ .check-heading {
448
+ align-items: flex-start;
449
+ flex-direction: column;
450
+ gap: 0.45rem;
451
+ }
452
+
453
+ .comparison-grid {
454
+ grid-template-columns: 1fr;
455
+ }
456
+
457
+ .counter-path + .counter-path {
458
+ border-top: 1px solid var(--line);
459
+ border-left: 0;
460
+ }
461
+ }
462
+
463
+ @media (prefers-reduced-motion: reduce) {
464
+ *,
465
+ *::before,
466
+ *::after {
467
+ scroll-behavior: auto !important;
468
+ transition-duration: 0.01ms !important;
469
+ }
470
+ }