diff --git a/website/src/components/features/launch/AsciiFrame.astro b/website/src/components/features/launch/AsciiFrame.astro
deleted file mode 100644
index 0e288de4..00000000
--- a/website/src/components/features/launch/AsciiFrame.astro
+++ /dev/null
@@ -1,95 +0,0 @@
----
-/**
- * ASCII backdrop for /launch.
- *
- * This is Home's hero field, not a copy of it: the element carries
- * id="ascii-hero" and the script drives it through the very same
- * `calcHeroDims` / `heroLoop` exports in scripts/home/hero.ts, which render
- * via renderASCIIRect over chladniRect with the shared RAMP.
- *
- * hero.ts resolves #ascii-hero at module scope and gates its loop behind
- * `heroActive`, which on Home is flipped by the terminal loader. There is no
- * loader here, so we flip it ourselves. `updateMousePosition` is deliberately
- * not wired — it is the one export that writes to Home's #fval readout and
- * would throw on this page.
- *
- * Framing is done with a radial mask rather than by slicing the field, so the
- * pattern stays whole and simply fades out behind the content.
- */
----
-
-
-
-
-
-
diff --git a/website/src/components/features/launch/CardsSection.astro b/website/src/components/features/launch/CardsSection.astro
new file mode 100644
index 00000000..b8e68fa9
--- /dev/null
+++ b/website/src/components/features/launch/CardsSection.astro
@@ -0,0 +1,72 @@
+---
+import { createTranslator, getLocaleFromUrl } from "@/utils/i18n";
+
+const locale = getLocaleFromUrl(Astro.url.pathname);
+const t = await createTranslator(locale);
+
+const CARDS = ["quantum_secure", "encrypted", "sound_money"] as const;
+---
+
+
+ {
+ CARDS.map((card) => (
+
+
{t(`launch.cards.${card}.title`)}
+
{t(`launch.cards.${card}.body`)}
+
+ ))
+ }
+
+
+
diff --git a/website/src/components/features/launch/FactsSection.astro b/website/src/components/features/launch/FactsSection.astro
deleted file mode 100644
index be8e07bb..00000000
--- a/website/src/components/features/launch/FactsSection.astro
+++ /dev/null
@@ -1,95 +0,0 @@
----
-import Button from "@/components/ui/Button.astro";
-import { createTranslator, getLocaleFromUrl } from "@/utils/i18n";
-
-const locale = getLocaleFromUrl(Astro.url.pathname);
-const t = await createTranslator(locale);
----
-
-
-
- {t("launch.facts.supply.label")}
- {t("launch.facts.supply.value")}
-
-
-
- {t("launch.facts.consensus.label")}
-
-
- {t("launch.mining_cta")}
-
-
-
-
-
diff --git a/website/src/components/features/launch/HeroSection.astro b/website/src/components/features/launch/HeroSection.astro
index 7d1e6ab1..7048a637 100644
--- a/website/src/components/features/launch/HeroSection.astro
+++ b/website/src/components/features/launch/HeroSection.astro
@@ -1,49 +1,48 @@
---
-import LogoLong from "@/assets/brand/logo-long.svg";
+import SignupForm from "./SignupForm.astro";
import { createTranslator, getLocaleFromUrl } from "@/utils/i18n";
const locale = getLocaleFromUrl(Astro.url.pathname);
const t = await createTranslator(locale);
---
-
-
- {t("launch.hero.eyebrow")}
-
+
+ {/* The key predates the redesign, when this line was the eyebrow. */}
+ {t("launch.hero.eyebrow")}
+ {t("launch.hero.sub")}
+
+
diff --git a/website/src/components/features/launch/LaunchField.astro b/website/src/components/features/launch/LaunchField.astro
new file mode 100644
index 00000000..fb7d696c
--- /dev/null
+++ b/website/src/components/features/launch/LaunchField.astro
@@ -0,0 +1,49 @@
+---
+/**
+ * Fixed Chladni field behind the /launch frame. Driven by
+ * scripts/launch/field.ts, which is independent of Home's hero field.
+ */
+---
+
+
+
+
+
+
diff --git a/website/src/components/features/launch/LaunchPage.astro b/website/src/components/features/launch/LaunchPage.astro
new file mode 100644
index 00000000..737ccfcf
--- /dev/null
+++ b/website/src/components/features/launch/LaunchPage.astro
@@ -0,0 +1,172 @@
+---
+/**
+ * Everything /launch renders. Shared by pages/launch.astro and
+ * pages/[lang]/launch.astro, which differ only in getStaticPaths.
+ *
+ * Section wrappers live here rather than in each section so the dividers
+ * between them can be styled in one place.
+ */
+import Layout from "@/components/layout/Layout.astro";
+import LogoLong from "@/assets/brand/logo-long.svg";
+import { createTranslator, getLocaleFromUrl } from "@/utils/i18n";
+import { createMetadata } from "@/utils/create-metadata";
+import { JsonLdGraph } from "@/utils/build-json-ld";
+import { organizationJsonLd, websiteJsonLd } from "@/constants/default-jsonld";
+import LaunchField from "./LaunchField.astro";
+import HeroSection from "./HeroSection.astro";
+import CardsSection from "./CardsSection.astro";
+import MiningSection from "./MiningSection.astro";
+import WaysSection from "./WaysSection.astro";
+import SignupForm from "./SignupForm.astro";
+
+const locale = getLocaleFromUrl(Astro.url.pathname);
+const t = await createTranslator(locale);
+
+const metadata = createMetadata({
+ title: t("launch.meta.title"),
+ description: t("launch.meta.description"),
+ pathname: Astro.url.pathname,
+});
+
+const jsonLd = JsonLdGraph({
+ "@context": "https://schema.org",
+ "@graph": [websiteJsonLd, organizationJsonLd],
+});
+---
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {t("launch.final.title")}
+
+
+
+
+
+
+
+
diff --git a/website/src/components/features/launch/MiningSection.astro b/website/src/components/features/launch/MiningSection.astro
new file mode 100644
index 00000000..6f2aa83f
--- /dev/null
+++ b/website/src/components/features/launch/MiningSection.astro
@@ -0,0 +1,149 @@
+---
+import { createTranslator, getLocaleFromUrl } from "@/utils/i18n";
+
+const locale = getLocaleFromUrl(Astro.url.pathname);
+const t = await createTranslator(locale);
+
+const MINING_DOCS_URL = "https://docs.quantus.com/guides/mining/";
+const ARROW_PATH =
+ "M13.376 11.552l-.264-10.44-10.44-.24.024 2.28 6.96-.048L.2 12.56l1.488 1.488 9.432-9.432-.048 6.912 2.304.024z";
+---
+
+
+
+
diff --git a/website/src/components/features/launch/SignupForm.astro b/website/src/components/features/launch/SignupForm.astro
index 07e1a0ee..147e8370 100644
--- a/website/src/components/features/launch/SignupForm.astro
+++ b/website/src/components/features/launch/SignupForm.astro
@@ -1,232 +1,285 @@
---
-import Button from "@/components/ui/Button.astro";
import { createTranslator, getLocaleFromUrl } from "@/utils/i18n";
import { WAITLIST_SOURCE, type WaitlistSource } from "@/constants/waitlist";
interface Props {
+ /** Unique per instance; prefixes the input and error ids. */
+ id: string;
/** Which waitlist these signups belong to. */
source?: WaitlistSource;
+ /** Optional line under the field, hidden once signed up. */
+ note?: string;
}
-const { source = WAITLIST_SOURCE.LAUNCH } = Astro.props;
+const { id, source = WAITLIST_SOURCE.LAUNCH, note } = Astro.props;
const locale = getLocaleFromUrl(Astro.url.pathname);
const t = await createTranslator(locale);
---
-