diff --git a/website/astro.config.mjs b/website/astro.config.mjs
index 643583c2..509198a7 100644
--- a/website/astro.config.mjs
+++ b/website/astro.config.mjs
@@ -70,8 +70,12 @@ export default defineConfig({
const path = new URL(page).pathname.replace(/\/$/, "") || "/";
const isTeamIndex =
path === "/team" || /\/[a-z]{2}-[A-Z]{2}\/team$/.test(path);
+ // Squeeze page: indexable and shareable, but kept out of the sitemap.
+ const isLaunch =
+ path === "/launch" || /\/[a-z]{2}-[A-Z]{2}\/launch$/.test(path);
return (
!isTeamIndex &&
+ !isLaunch &&
!page.includes("/tags/") &&
!page.includes("/account/") &&
!page.includes("/oauth/") &&
diff --git a/website/src/api/client.ts b/website/src/api/client.ts
index ae6d1c21..d383e8b8 100644
--- a/website/src/api/client.ts
+++ b/website/src/api/client.ts
@@ -35,6 +35,10 @@ interface ContactData {
interface SubscribeData {
email: string;
+ firstName: string;
+ lastName: string;
+ /** Which list this signup belongs to. Omitted by the site newsletter. */
+ source?: string;
}
export interface Entrant {
@@ -106,11 +110,15 @@ const createApiClient = () => {
/**
* Subscribe to waitlist
+ *
+ * `source` identifies which list the signup belongs to. Omitting it
+ * produces the original payload, so existing callers are unaffected.
*/
subscribe: (
email: string,
firstName: string,
lastName: string,
+ source?: string,
): ApiResponse => {
return fetch(`${env.API_URL}/waitlist`, {
headers: {
@@ -121,6 +129,7 @@ const createApiClient = () => {
email,
firstName,
lastName,
+ ...(source ? { source } : {}),
} as SubscribeData),
});
},
diff --git a/website/src/components/features/launch/AsciiFrame.astro b/website/src/components/features/launch/AsciiFrame.astro
new file mode 100644
index 00000000..0e288de4
--- /dev/null
+++ b/website/src/components/features/launch/AsciiFrame.astro
@@ -0,0 +1,95 @@
+---
+/**
+ * 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/FactsSection.astro b/website/src/components/features/launch/FactsSection.astro
new file mode 100644
index 00000000..8a688f37
--- /dev/null
+++ b/website/src/components/features/launch/FactsSection.astro
@@ -0,0 +1,93 @@
+---
+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
new file mode 100644
index 00000000..7d1e6ab1
--- /dev/null
+++ b/website/src/components/features/launch/HeroSection.astro
@@ -0,0 +1,49 @@
+---
+import LogoLong from "@/assets/brand/logo-long.svg";
+import { createTranslator, getLocaleFromUrl } from "@/utils/i18n";
+
+const locale = getLocaleFromUrl(Astro.url.pathname);
+const t = await createTranslator(locale);
+---
+
+
+
+ {t("launch.hero.eyebrow")}
+
+
+
diff --git a/website/src/components/features/launch/SignupForm.astro b/website/src/components/features/launch/SignupForm.astro
new file mode 100644
index 00000000..07e1a0ee
--- /dev/null
+++ b/website/src/components/features/launch/SignupForm.astro
@@ -0,0 +1,309 @@
+---
+import Button from "@/components/ui/Button.astro";
+import { createTranslator, getLocaleFromUrl } from "@/utils/i18n";
+import { WAITLIST_SOURCE, type WaitlistSource } from "@/constants/waitlist";
+
+interface Props {
+ /** Which waitlist these signups belong to. */
+ source?: WaitlistSource;
+}
+
+const { source = WAITLIST_SOURCE.LAUNCH } = Astro.props;
+
+const locale = getLocaleFromUrl(Astro.url.pathname);
+const t = await createTranslator(locale);
+---
+
+
+
+
+
+
+ {t("launch.signup.success.headline")}
+
+
+ {t("launch.signup.success.sub")}
+
+
+
+
+
+
+
diff --git a/website/src/components/layout/Layout.astro b/website/src/components/layout/Layout.astro
index c761ad42..f3a581ee 100644
--- a/website/src/components/layout/Layout.astro
+++ b/website/src/components/layout/Layout.astro
@@ -39,9 +39,11 @@ import env from "@/config";
interface Props extends SEOProps {
jsonLd?: WithContext | Graph;
+ /** Render the navbar and footer. Off for standalone pages like /launch. */
+ showChrome?: boolean;
}
-const { jsonLd, ...metadata } = Astro.props;
+const { jsonLd, showChrome = true, ...metadata } = Astro.props;
const currentLocale = getLocaleFromUrl(Astro.url.pathname);
const t = await createTranslator(currentLocale);
@@ -115,11 +117,11 @@ const breadcrumbs = generateBreadcrumbs({
)
}
-
+ {showChrome && }
-
+ {showChrome && }
diff --git a/website/src/constants/waitlist.ts b/website/src/constants/waitlist.ts
new file mode 100644
index 00000000..d6ab7620
--- /dev/null
+++ b/website/src/constants/waitlist.ts
@@ -0,0 +1,16 @@
+/**
+ * Identifies which list a POST /waitlist submission belongs to.
+ *
+ * The site newsletter omits this and keeps the original payload shape; the
+ * launch squeeze page sends LAUNCH. Switching the launch page to a different
+ * list is a one-line change here.
+ *
+ * NOTE: the API does not read this field yet. Until it does, launch signups
+ * land in the same list as the newsletter — the field is inert, not wrong.
+ */
+export const WAITLIST_SOURCE = {
+ LAUNCH: "launch",
+} as const;
+
+export type WaitlistSource =
+ (typeof WAITLIST_SOURCE)[keyof typeof WAITLIST_SOURCE];
diff --git a/website/src/i18n/de-DE.json b/website/src/i18n/de-DE.json
index 67571377..2da2c4fc 100644
--- a/website/src/i18n/de-DE.json
+++ b/website/src/i18n/de-DE.json
@@ -828,6 +828,36 @@
"copy": "Empfehlungscode kopiert!"
}
},
+ "launch": {
+ "meta": {
+ "title": "Quantus Launch",
+ "description": "Quantensicheres verschlüsseltes Geld. 21 Millionen Angebotsgrenze, Proof of Work. Erhalten Sie die Launch-Details."
+ },
+ "hero": {
+ "eyebrow": "Quantensicheres verschlüsseltes Geld"
+ },
+ "signup": {
+ "headline": "Launch-Details erhalten.",
+ "email_placeholder": "your@email.com",
+ "email_aria": "E-Mail-Adresse",
+ "submit_label": "BENACHRICHTIGEN",
+ "error_message": "Bitte geben Sie eine gültige E-Mail-Adresse ein.",
+ "success": {
+ "headline": "Sie stehen auf der Liste.",
+ "sub": "Die Launch-Details kommen in Ihr Postfach."
+ }
+ },
+ "facts": {
+ "supply": {
+ "label": "ANGEBOTSGRENZE",
+ "value": "21,000,000"
+ },
+ "consensus": {
+ "label": "PROOF OF WORK"
+ }
+ },
+ "mining_cta": "MINING-GUIDE LESEN"
+ },
"blog": {
"title": "Die neuesten Nachrichten von Quantus.",
"hero": {
diff --git a/website/src/i18n/en-US.json b/website/src/i18n/en-US.json
index 966b997c..fb2585aa 100644
--- a/website/src/i18n/en-US.json
+++ b/website/src/i18n/en-US.json
@@ -828,6 +828,36 @@
"copy": "Referral code copied!"
}
},
+ "launch": {
+ "meta": {
+ "title": "Quantus Launch",
+ "description": "Quantum secure encrypted money. 21 million supply cap, Proof of Work. Get launch details."
+ },
+ "hero": {
+ "eyebrow": "Quantum Secure Encrypted Money"
+ },
+ "signup": {
+ "headline": "Get launch details.",
+ "email_placeholder": "your@email.com",
+ "email_aria": "Email address",
+ "submit_label": "NOTIFY ME",
+ "error_message": "Please enter a valid email address.",
+ "success": {
+ "headline": "You're on the list.",
+ "sub": "Launch details will land in your inbox."
+ }
+ },
+ "facts": {
+ "supply": {
+ "label": "SUPPLY CAP",
+ "value": "21,000,000"
+ },
+ "consensus": {
+ "label": "PROOF OF WORK"
+ }
+ },
+ "mining_cta": "READ THE MINING GUIDE"
+ },
"blog": {
"title": "The latest news from the Quantus.",
"hero": {
diff --git a/website/src/i18n/es-ES.json b/website/src/i18n/es-ES.json
index 286f6033..994f3cfb 100644
--- a/website/src/i18n/es-ES.json
+++ b/website/src/i18n/es-ES.json
@@ -828,6 +828,36 @@
"copy": "¡Código de referido copiado!"
}
},
+ "launch": {
+ "meta": {
+ "title": "Lanzamiento de Quantus",
+ "description": "Dinero encriptado seguro cuánticamente. Suministro máximo de 21 millones, Proof of Work. Reciba los detalles del lanzamiento."
+ },
+ "hero": {
+ "eyebrow": "Dinero Encriptado Seguro Cuánticamente"
+ },
+ "signup": {
+ "headline": "Reciba los detalles del lanzamiento.",
+ "email_placeholder": "your@email.com",
+ "email_aria": "Dirección de correo electrónico",
+ "submit_label": "AVÍSAME",
+ "error_message": "Por favor, introduzca una dirección de correo electrónico válida.",
+ "success": {
+ "headline": "Está en la lista.",
+ "sub": "Los detalles del lanzamiento llegarán a su bandeja de entrada."
+ }
+ },
+ "facts": {
+ "supply": {
+ "label": "SUMINISTRO MÁXIMO",
+ "value": "21,000,000"
+ },
+ "consensus": {
+ "label": "PROOF OF WORK"
+ }
+ },
+ "mining_cta": "LEER LA GUÍA DE MINERÍA"
+ },
"blog": {
"title": "Las últimas noticias de Quantus.",
"hero": {
diff --git a/website/src/i18n/hi-IN.json b/website/src/i18n/hi-IN.json
index a724e152..1a95b4fc 100644
--- a/website/src/i18n/hi-IN.json
+++ b/website/src/i18n/hi-IN.json
@@ -828,6 +828,36 @@
"copy": "रेफरल कोड कॉपी किया गया!"
}
},
+ "launch": {
+ "meta": {
+ "title": "Quantus लॉन्च",
+ "description": "क्वांटम-सुरक्षित एन्क्रिप्टेड मनी। 21 मिलियन सप्लाई कैप, Proof of Work। लॉन्च की जानकारी पाएं।"
+ },
+ "hero": {
+ "eyebrow": "क्वांटम-सुरक्षित एन्क्रिप्टेड मनी"
+ },
+ "signup": {
+ "headline": "लॉन्च की जानकारी पाएं।",
+ "email_placeholder": "your@email.com",
+ "email_aria": "ईमेल पता",
+ "submit_label": "मुझे सूचित करें",
+ "error_message": "कृपया एक मान्य ईमेल पता दर्ज करें।",
+ "success": {
+ "headline": "आप सूची में हैं।",
+ "sub": "लॉन्च की जानकारी आपके इनबॉक्स में पहुंचेगी।"
+ }
+ },
+ "facts": {
+ "supply": {
+ "label": "सप्लाई कैप",
+ "value": "21,000,000"
+ },
+ "consensus": {
+ "label": "PROOF OF WORK"
+ }
+ },
+ "mining_cta": "माइनिंग गाइड पढ़ें"
+ },
"blog": {
"title": "Quantus की नवीनतम खबरें।",
"hero": {
diff --git a/website/src/i18n/id-ID.json b/website/src/i18n/id-ID.json
index ed60fcda..3a282271 100644
--- a/website/src/i18n/id-ID.json
+++ b/website/src/i18n/id-ID.json
@@ -828,6 +828,36 @@
"copy": "Kode referal disalin!"
}
},
+ "launch": {
+ "meta": {
+ "title": "Peluncuran Quantus",
+ "description": "Uang terenkripsi aman secara kuantum. Batas pasokan 21 juta, Proof of Work. Dapatkan detail peluncuran."
+ },
+ "hero": {
+ "eyebrow": "Uang Terenkripsi Aman Secara Kuantum"
+ },
+ "signup": {
+ "headline": "Dapatkan detail peluncuran.",
+ "email_placeholder": "your@email.com",
+ "email_aria": "Alamat email",
+ "submit_label": "BERI TAHU SAYA",
+ "error_message": "Harap masukkan alamat email yang valid.",
+ "success": {
+ "headline": "Anda sudah terdaftar.",
+ "sub": "Detail peluncuran akan dikirim ke kotak masuk Anda."
+ }
+ },
+ "facts": {
+ "supply": {
+ "label": "BATAS PASOKAN",
+ "value": "21,000,000"
+ },
+ "consensus": {
+ "label": "PROOF OF WORK"
+ }
+ },
+ "mining_cta": "BACA PANDUAN MINING"
+ },
"blog": {
"title": "Berita terbaru dari Quantus.",
"hero": {
diff --git a/website/src/i18n/ja-JP.json b/website/src/i18n/ja-JP.json
index acb58165..2105821a 100644
--- a/website/src/i18n/ja-JP.json
+++ b/website/src/i18n/ja-JP.json
@@ -828,6 +828,36 @@
"copy": "紹介コードをコピーしました!"
}
},
+ "launch": {
+ "meta": {
+ "title": "Quantus ローンチ",
+ "description": "量子セキュアな暗号化通貨。供給上限2,100万、Proof of Work。ローンチ情報を受け取る。"
+ },
+ "hero": {
+ "eyebrow": "量子セキュアな暗号化通貨"
+ },
+ "signup": {
+ "headline": "ローンチ情報を受け取る。",
+ "email_placeholder": "your@email.com",
+ "email_aria": "メールアドレス",
+ "submit_label": "通知を受け取る",
+ "error_message": "有効なメールアドレスを入力してください。",
+ "success": {
+ "headline": "登録が完了しました。",
+ "sub": "ローンチ情報をメールでお届けします。"
+ }
+ },
+ "facts": {
+ "supply": {
+ "label": "供給上限",
+ "value": "21,000,000"
+ },
+ "consensus": {
+ "label": "PROOF OF WORK"
+ }
+ },
+ "mining_cta": "マイニングガイドを読む"
+ },
"blog": {
"title": "Quantusからの最新ニュース。",
"hero": {
diff --git a/website/src/i18n/ko-KR.json b/website/src/i18n/ko-KR.json
index 5e0c3f21..d4424195 100644
--- a/website/src/i18n/ko-KR.json
+++ b/website/src/i18n/ko-KR.json
@@ -828,6 +828,36 @@
"copy": "추천 코드가 복사되었습니다!"
}
},
+ "launch": {
+ "meta": {
+ "title": "Quantus 출시",
+ "description": "양자 보안 암호화 화폐. 총 발행 한도 2,100만, Proof of Work. 출시 소식을 받아보세요."
+ },
+ "hero": {
+ "eyebrow": "양자 보안 암호화 화폐"
+ },
+ "signup": {
+ "headline": "출시 소식을 받아보세요.",
+ "email_placeholder": "your@email.com",
+ "email_aria": "이메일 주소",
+ "submit_label": "알림 받기",
+ "error_message": "유효한 이메일 주소를 입력하세요.",
+ "success": {
+ "headline": "등록되었습니다.",
+ "sub": "출시 소식을 이메일로 보내드립니다."
+ }
+ },
+ "facts": {
+ "supply": {
+ "label": "총 발행 한도",
+ "value": "21,000,000"
+ },
+ "consensus": {
+ "label": "PROOF OF WORK"
+ }
+ },
+ "mining_cta": "채굴 가이드 읽기"
+ },
"blog": {
"title": "Quantus의 최신 소식.",
"hero": {
diff --git a/website/src/i18n/ru-RU.json b/website/src/i18n/ru-RU.json
index 3f8901c8..3e7fbda7 100644
--- a/website/src/i18n/ru-RU.json
+++ b/website/src/i18n/ru-RU.json
@@ -828,6 +828,36 @@
"copy": "Реферальный код скопирован!"
}
},
+ "launch": {
+ "meta": {
+ "title": "Запуск Quantus",
+ "description": "Квантово-безопасные зашифрованные деньги. Максимальная эмиссия 21 млн, Proof of Work. Получите детали запуска."
+ },
+ "hero": {
+ "eyebrow": "Квантово-безопасные зашифрованные деньги"
+ },
+ "signup": {
+ "headline": "Получите детали запуска.",
+ "email_placeholder": "your@email.com",
+ "email_aria": "Адрес электронной почты",
+ "submit_label": "СООБЩИТЬ МНЕ",
+ "error_message": "Пожалуйста, введите корректный адрес электронной почты.",
+ "success": {
+ "headline": "Вы в списке.",
+ "sub": "Детали запуска придут на вашу почту."
+ }
+ },
+ "facts": {
+ "supply": {
+ "label": "МАКСИМАЛЬНАЯ ЭМИССИЯ",
+ "value": "21,000,000"
+ },
+ "consensus": {
+ "label": "PROOF OF WORK"
+ }
+ },
+ "mining_cta": "ЧИТАТЬ РУКОВОДСТВО ПО МАЙНИНГУ"
+ },
"blog": {
"title": "Последние новости от Quantus.",
"hero": {
diff --git a/website/src/i18n/zh-CN.json b/website/src/i18n/zh-CN.json
index 15f47781..a53c6dbe 100644
--- a/website/src/i18n/zh-CN.json
+++ b/website/src/i18n/zh-CN.json
@@ -828,6 +828,36 @@
"copy": "推荐码已复制!"
}
},
+ "launch": {
+ "meta": {
+ "title": "Quantus 上线",
+ "description": "量子安全加密货币。供应上限 2,100 万,工作量证明(Proof of Work)。获取上线详情。"
+ },
+ "hero": {
+ "eyebrow": "量子安全加密货币"
+ },
+ "signup": {
+ "headline": "获取上线详情。",
+ "email_placeholder": "your@email.com",
+ "email_aria": "电子邮件地址",
+ "submit_label": "通知我",
+ "error_message": "请输入有效的电子邮件地址。",
+ "success": {
+ "headline": "您已加入名单。",
+ "sub": "上线详情将发送至您的邮箱。"
+ }
+ },
+ "facts": {
+ "supply": {
+ "label": "供应上限",
+ "value": "21,000,000"
+ },
+ "consensus": {
+ "label": "工作量证明"
+ }
+ },
+ "mining_cta": "阅读挖矿指南"
+ },
"blog": {
"title": "来自 Quantus 的最新消息。",
"hero": {
diff --git a/website/src/pages/[lang]/launch.astro b/website/src/pages/[lang]/launch.astro
new file mode 100644
index 00000000..8ca542bc
--- /dev/null
+++ b/website/src/pages/[lang]/launch.astro
@@ -0,0 +1,85 @@
+---
+import Layout from "@/components/layout/Layout.astro";
+import {
+ createTranslator,
+ getLocaleFromUrl,
+ PREFIXED_LOCALES,
+} from "@/utils/i18n";
+import { createMetadata } from "@/utils/create-metadata";
+import { JsonLdGraph } from "@/utils/build-json-ld";
+import {
+ organizationJsonLd,
+ websiteJsonLd,
+} from "@/constants/default-jsonld";
+import HeroSection from "@/components/features/launch/HeroSection.astro";
+import SignupForm from "@/components/features/launch/SignupForm.astro";
+import FactsSection from "@/components/features/launch/FactsSection.astro";
+import AsciiFrame from "@/components/features/launch/AsciiFrame.astro";
+
+export async function getStaticPaths() {
+ return PREFIXED_LOCALES.map((lang) => ({ params: { lang } }));
+}
+
+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],
+});
+---
+
+
+
+
+
+
diff --git a/website/src/pages/launch.astro b/website/src/pages/launch.astro
new file mode 100644
index 00000000..bf64dee4
--- /dev/null
+++ b/website/src/pages/launch.astro
@@ -0,0 +1,77 @@
+---
+import Layout from "@/components/layout/Layout.astro";
+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 HeroSection from "@/components/features/launch/HeroSection.astro";
+import SignupForm from "@/components/features/launch/SignupForm.astro";
+import FactsSection from "@/components/features/launch/FactsSection.astro";
+import AsciiFrame from "@/components/features/launch/AsciiFrame.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],
+});
+---
+
+
+
+
+
+
diff --git a/website/src/styles/fonts.css b/website/src/styles/fonts.css
index 51958606..9fc9033b 100644
--- a/website/src/styles/fonts.css
+++ b/website/src/styles/fonts.css
@@ -39,7 +39,7 @@
@utility font-cta-mono {
font-family: var(--font-mono);
font-size: 12px;
- font-weight: medium;
+ font-weight: 500;
letter-spacing: 0.12em;
text-transform: uppercase;
}