From a08e58fbcbd4074643cb5bb2e44e945a946904eb Mon Sep 17 00:00:00 2001 From: axiomlogicnexus Date: Fri, 3 Jul 2026 03:32:15 +0000 Subject: [PATCH] Harden HyperTwist website access and public copy --- ...T_AND_OPERATOR_MANUAL_PACKET_2026-06-22.md | 21 + ..._RUNTIME_CONFIGURATION_GUIDE_2026-06-22.md | 20 + .../HyperTwist/ROADMAP.md | 40 ++ website/package-lock.json | 11 + website/package.json | 1 + website/src/App.tsx | 1 + .../__tests__/DashboardOverviewPage.test.tsx | 20 +- .../src/__tests__/PublicLaunchStatus.test.tsx | 27 +- website/src/__tests__/app-route-tree.test.tsx | 18 +- .../__tests__/protected-app-pages.test.tsx | 34 +- .../src/__tests__/public-auth-pages.test.tsx | 6 +- website/src/__tests__/public-launch.test.ts | 4 +- .../__tests__/public-marketing-pages.test.tsx | 75 ++- website/src/__tests__/route-shells.test.tsx | 4 +- website/src/components/ErrorBoundary.tsx | 11 +- website/src/components/layout/AppShell.tsx | 11 +- .../src/components/layout/MarketingShell.tsx | 94 +++- .../src/components/routes/ProtectedRoute.tsx | 13 +- .../components/ui/BrowserAuthMethodsGuide.tsx | 8 +- .../src/components/ui/HyperTwistButton.tsx | 119 +++++ .../ui/OperationalStatusCallout.tsx | 12 +- .../src/components/ui/PublicLaunchStatus.tsx | 69 ++- website/src/pages/app-pages.tsx | 246 +++++----- website/src/pages/auth-pages.tsx | 151 +++++-- website/src/pages/public-page-helpers.tsx | 123 ++--- website/src/pages/public-pages-commerce.tsx | 141 +++--- website/src/pages/public-pages-features.tsx | 38 +- website/src/pages/public-pages-guides.tsx | 39 +- website/src/pages/public-pages-launch.tsx | 32 +- website/src/pages/public-pages-marketing.tsx | 119 ++--- website/src/public-launch.ts | 14 +- website/src/public-route-registry.json | 20 +- website/src/release-manifest.ts | 2 +- website/src/router/AppRouteTree.tsx | 8 +- website/src/shared/public-launch.ts | 4 +- website/src/site-config.ts | 32 +- website/src/site-data.ts | 426 +++++++++--------- website/src/styles/global.css | 170 ++++++- .../responsive-protected-app-routes.spec.ts | 2 +- .../tests/e2e/responsive-public-pages.spec.ts | 6 +- 40 files changed, 1341 insertions(+), 851 deletions(-) create mode 100644 website/src/components/ui/HyperTwistButton.tsx diff --git a/docs/ops/HYPERTWIST_PUBLIC_WEBSITE_CONTENT_AND_OPERATOR_MANUAL_PACKET_2026-06-22.md b/docs/ops/HYPERTWIST_PUBLIC_WEBSITE_CONTENT_AND_OPERATOR_MANUAL_PACKET_2026-06-22.md index 57a670d..1d81a51 100644 --- a/docs/ops/HYPERTWIST_PUBLIC_WEBSITE_CONTENT_AND_OPERATOR_MANUAL_PACKET_2026-06-22.md +++ b/docs/ops/HYPERTWIST_PUBLIC_WEBSITE_CONTENT_AND_OPERATOR_MANUAL_PACKET_2026-06-22.md @@ -2,6 +2,27 @@ Created on `2026-06-22`. +Updated on `2026-07-03`: + +- signup/login must be presented as a working account path, not as a diagnostic + placeholder surface +- the public homepage, browser guide, pricing, download, help, resources, docs, + legal, and support pages should describe HyperTwist to users in product terms + instead of exposing raw preview/fallback/no-go/developer vocabulary +- remaining launch gaps are retained in the roadmap rather than hidden in public + marketing pages +- public pages explain supported targets and the product model; protected account + routes own entitled downloads, release notices, account state, desktop-link + pairing, and billing follow-through +- the web version is valuable but intentionally inferior for simulator execution: + it handles account, docs, pricing, notices, support, protected handoff, and + pairing; the downloadable owns real training behavior +- the downloadable should not become a standalone password island or checkout + surface; it should consume browser-issued account or desktop-link authority +- the public style system now uses the shared Performative UI-backed HyperTwist + button wrappers, public light/dark mode controls, enlarged brand logo, and the + HyperTwist-adapted pricing-frame glow treatment + ## Purpose This continuation strengthens the public `hypertwist.app` surface so the site diff --git a/docs/ops/HYPERTWIST_WEBSITE_RUNTIME_CONFIGURATION_GUIDE_2026-06-22.md b/docs/ops/HYPERTWIST_WEBSITE_RUNTIME_CONFIGURATION_GUIDE_2026-06-22.md index 42c6ac3..43689a7 100644 --- a/docs/ops/HYPERTWIST_WEBSITE_RUNTIME_CONFIGURATION_GUIDE_2026-06-22.md +++ b/docs/ops/HYPERTWIST_WEBSITE_RUNTIME_CONFIGURATION_GUIDE_2026-06-22.md @@ -2,6 +2,26 @@ Created on `2026-06-22`. +Updated on `2026-07-03`: + +- public marketing pages should not expose raw preview, placeholder, fallback, or + developer-posture language as the primary visitor experience +- incomplete launch items stay in roadmap and protected/operator diagnostics, + while anonymous public pages use user-facing early-access, account, release, + download, and support language +- account creation or sign-in is the intended boundary before protected desktop + package delivery +- subscription purchase and entitlement authority stay on the website/dashboard + through Paddle-backed billing; the downloadable consumes account/desktop-link + authority instead of becoming a checkout or password island +- public anonymous release manifests must not expose raw package URLs +- the browser version is the public/protected access, documentation, account, + pricing, notices, billing, support, and pairing shell; it is deliberately less + powerful than the downloadable simulator +- the desktop app remains the primary simulator surface for recognition, replay, + coaching, higher-dimensional runtime execution, diagnostics, package proof, and + serious training sessions + ## Purpose This note records the recommended production runtime posture for the first-party diff --git a/docs/v6_5_deep_manual_pack/HyperTwist/ROADMAP.md b/docs/v6_5_deep_manual_pack/HyperTwist/ROADMAP.md index 720ab6a..1b60fd5 100644 --- a/docs/v6_5_deep_manual_pack/HyperTwist/ROADMAP.md +++ b/docs/v6_5_deep_manual_pack/HyperTwist/ROADMAP.md @@ -22,6 +22,46 @@ Canonical discovery surfaces for roadmap interpretation: for the currently verified VPS-to-Windows reverse-tunnel Unreal build lane (primary `localhost:22022`, fallback `localhost:22023`) +## Public Website Launch Gaps Extracted From Public Copy (2026-07-03) + +The production website must not use public-facing marketing copy as the place to +list raw preview, placeholder, fallback, or developer posture vocabulary. As of +the `2026-07-03` website cleanup packet, those terms are retained here as roadmap +truth instead of being shown as visitor-facing page copy. + +Current incomplete launch and rollout items retained for roadmap authority: + +- publish the live Windows desktop release URL, release metadata, checksum, and + signed package reference through the protected release-manifest lane +- configure live Paddle operator and studio checkout URLs plus the corresponding + product-to-plan and price-to-plan maps +- install and validate the live `PADDLE_WEBHOOK_SECRET` plus billing-event + reflection proof before treating paid self-service checkout as public +- publish the final corresponding-source URL and public notices/repository URL + for any downloadable build containing covered code +- clear the remaining public-auth runtime warnings, especially loopback-only + SuperTokens-core deployment warnings, before claiming full public-launch auth +- keep anonymous release manifests free of raw download URLs; package delivery + remains protected-dashboard first +- keep the desktop app login model as a browser-issued desktop-link/pairing-token + handoff, not a separate downloadable password island +- keep subscription purchase and entitlement authority on the website/dashboard + with Paddle-backed billing; the downloadable should consume the resulting + account or desktop-link token rather than owning checkout itself +- complete packaged headset/controller validation before marketing a finished + broad VR/controller branch +- keep the optional full-browser simulator branch future-facing until a separate + product packet proves backend/runtime parity and launch quality +- keep MagicTile native renderer widening closed unless a later packet proves a + real browser-host gap, `Phase 7C` behavior parity, and full Windows validation +- treat macOS and Linux packages as future signed-package rows until the release + manifest and package proof carry them as published targets + +Public-page copy should say the same truth in user-facing terms: public pages +explain the product; account creation/sign-in opens protected dashboard, +downloads, notices, billing, release status, and desktop pairing; the desktop +runtime remains the powerful simulator surface. + Current consolidated milestone snapshot: - the curated HyperTwist portfolio still evaluates against `75` retained repo rows diff --git a/website/package-lock.json b/website/package-lock.json index 34335dc..165fc5e 100644 --- a/website/package-lock.json +++ b/website/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "@tanstack/react-query": "^5.83.0", "lucide-react": "^0.525.0", + "performative-ui": "^0.7.0", "react": "^18.3.1", "react-dom": "^18.3.1", "react-router-dom": "^6.30.1", @@ -2115,6 +2116,16 @@ "node": ">= 14.16" } }, + "node_modules/performative-ui": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/performative-ui/-/performative-ui-0.7.0.tgz", + "integrity": "sha512-hW53A/lhKdxMUCYXsVZ5pWTAjgNGlHaXerVICRTzZY2PTXULTFby8DXozImDtj55HCn5VbPb9zrtS4WihvzU7g==", + "license": "MIT", + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", diff --git a/website/package.json b/website/package.json index 42f6576..268d73d 100644 --- a/website/package.json +++ b/website/package.json @@ -26,6 +26,7 @@ "dependencies": { "@tanstack/react-query": "^5.83.0", "lucide-react": "^0.525.0", + "performative-ui": "^0.7.0", "react": "^18.3.1", "react-dom": "^18.3.1", "react-router-dom": "^6.30.1", diff --git a/website/src/App.tsx b/website/src/App.tsx index 66f98fd..80eec99 100644 --- a/website/src/App.tsx +++ b/website/src/App.tsx @@ -7,6 +7,7 @@ import { isSuperTokensConfigured } from './auth/supertokens-runtime' import { AppRouteTree } from './router/AppRouteTree' import { AuthShellBackdropSync } from './router/AuthShellBackdropSync' import { ROUTER_FUTURE_FLAGS } from './router/router-future' +import 'performative-ui' import './styles/global.css' const LazySuperTokensRouteWrapper = lazy(async () => ({ diff --git a/website/src/__tests__/DashboardOverviewPage.test.tsx b/website/src/__tests__/DashboardOverviewPage.test.tsx index 2bc6ab0..ca63d68 100644 --- a/website/src/__tests__/DashboardOverviewPage.test.tsx +++ b/website/src/__tests__/DashboardOverviewPage.test.tsx @@ -182,7 +182,7 @@ describe('DashboardOverviewPage', () => { expect(screen.queryByText(/Checking auth server health/i)).toBeNull() }) - expect(screen.getByText(/This session is currently using local fallback posture/i)).toBeTruthy() + expect(screen.getByText(/This session is currently using local recovery mode/i)).toBeTruthy() expect(screen.getByText(/Shared auth core is not fully ready right now/i)).toBeTruthy() expect(screen.getByText('Auth and session authority')).toBeTruthy() expect(screen.getByText('Signed-in method: Email and password')).toBeTruthy() @@ -191,15 +191,15 @@ describe('DashboardOverviewPage', () => { expect(screen.getByText('What stays intentionally bounded')).toBeTruthy() expect(screen.getByText('Recommended recovery order')).toBeTruthy() expect(screen.getByText(/Public launch is not fully configured yet:/i)).toBeTruthy() - expect(screen.getByText('Billing product-plan map: missing')).toBeTruthy() - expect(screen.getByText('Billing price-plan map: missing')).toBeTruthy() - expect(screen.getByText('Paddle webhook secret: missing')).toBeTruthy() - expect(screen.getByText('Public auth runtime posture: local-or-mixed')).toBeTruthy() - expect(screen.getByText('Current preview blockers from the live auth runtime')).toBeTruthy() - expect(screen.getByText('Shared browser-auth runtime is not yet production-ready on the live deployment.')).toBeTruthy() - expect(screen.getByText('Paddle webhook secret is not configured yet.')).toBeTruthy() - expect(screen.getByText('Billing product-plan map is not configured yet.')).toBeTruthy() - expect(screen.getByText('Billing price-plan map is not configured yet.')).toBeTruthy() + expect(screen.getByText('Billing product-plan map: pending')).toBeTruthy() + expect(screen.getByText('Billing price-plan map: pending')).toBeTruthy() + expect(screen.getByText('Paddle webhook secret: pending')).toBeTruthy() + expect(screen.getByText('Public auth runtime status: local-or-mixed')).toBeTruthy() + expect(screen.getByText('Current early-access blockers from the live auth runtime')).toBeTruthy() + expect(screen.getByText('Shared browser-auth runtime still needs production readiness confirmation on the current deployment.')).toBeTruthy() + expect(screen.getByText('Paddle webhook verification still needs to be enabled for fully automated billing updates.')).toBeTruthy() + expect(screen.getByText('Billing product-plan mapping still needs to be connected to the live subscription catalog.')).toBeTruthy() + expect(screen.getByText('Billing price-plan mapping still needs to be connected to the live subscription catalog.')).toBeTruthy() expect(screen.getByText('Runtime error: API_DOMAIN still points at localhost')).toBeTruthy() expect(screen.getByText('Runtime warning: COOKIE_SECURE disabled')).toBeTruthy() expect(screen.getByText('Current release action')).toBeTruthy() diff --git a/website/src/__tests__/PublicLaunchStatus.test.tsx b/website/src/__tests__/PublicLaunchStatus.test.tsx index 433da53..ef4dc7d 100644 --- a/website/src/__tests__/PublicLaunchStatus.test.tsx +++ b/website/src/__tests__/PublicLaunchStatus.test.tsx @@ -108,18 +108,15 @@ describe('PublicLaunchStatus', () => { renderComponent() await waitFor(() => { - expect(screen.queryByText(/Checking live launch-readiness posture/i)).toBeNull() + expect(screen.queryByText(/Checking current account and release access status/i)).toBeNull() }) - expect(screen.getByText('Current preview blockers from the live auth runtime')).toBeTruthy() - expect(screen.getByText('Windows release lane is not configured on the live preview deployment yet.')).toBeTruthy() - expect(screen.getByText('Operator checkout is still on support fallback in the live preview deployment.')).toBeTruthy() - expect(screen.getByText('Studio checkout is still on support fallback in the live preview deployment.')).toBeTruthy() - expect(screen.getByText('Shared browser-auth runtime is not yet production-ready on the live deployment.')).toBeTruthy() - expect(screen.getByText('Paddle webhook secret is not configured yet.')).toBeTruthy() - expect(screen.getByText('Billing product-plan map is not configured yet.')).toBeTruthy() - expect(screen.getByText('Billing price-plan map is not configured yet.')).toBeTruthy() - expect(screen.getByText('Runtime warning: SUPERTOKENS_CORE_URI still targets a loopback/local-development host.')).toBeTruthy() + expect(screen.getByText('Account-gated early access')).toBeTruthy() + expect(screen.getByText(/signed-in dashboard routes handle download access, subscription state, and desktop pairing/i)).toBeTruthy() + expect(screen.getByText('Desktop app access: routed through account creation or sign-in before package delivery.')).toBeTruthy() + expect(screen.getByText('Browser version: available as the public/protected account, docs, release, pricing, and pairing shell, not as simulator parity.')).toBeTruthy() + expect(screen.getByRole('link', { name: 'Open signed-in downloads' }).getAttribute('href')).toBe('/app/downloads?platform=windows') + expect(screen.getByRole('link', { name: 'Open protected notices' }).getAttribute('href')).toBe('/app/notices') }) it('keeps the marketing banner compact while still surfacing concrete live blockers', async () => { @@ -194,11 +191,11 @@ describe('PublicLaunchStatus', () => { renderComponent() await waitFor(() => { - expect(screen.getByText(/Live preview lane: Operator checkout is still on support fallback/i)).toBeTruthy() + expect(screen.getByText(/HyperTwist is in account-gated early access/i)).toBeTruthy() }) - expect(screen.getByText(/Studio checkout is still on support fallback/i)).toBeTruthy() - expect(screen.getByText(/4 more live blockers remain on the deployment/i)).toBeTruthy() + expect(screen.getByText(/Some release and commerce steps are still handled through signed-in dashboard or support follow-up/i)).toBeTruthy() + expect(screen.getByRole('link', { name: 'Open signed-in downloads' }).getAttribute('href')).toBe('/app/downloads?platform=windows') }) it('omits the blocker section when the live launch posture is ready and warning-free', async () => { @@ -273,10 +270,10 @@ describe('PublicLaunchStatus', () => { renderComponent() await waitFor(() => { - expect(screen.queryByText(/Checking live launch-readiness posture/i)).toBeNull() + expect(screen.queryByText(/Checking current account and release access status/i)).toBeNull() }) - expect(screen.queryByText('Current preview blockers from the live auth runtime')).toBeNull() + expect(screen.queryByText('Current early-access blockers from the live auth runtime')).toBeNull() expect(screen.queryByText('Live runtime notes')).toBeNull() }) }) diff --git a/website/src/__tests__/app-route-tree.test.tsx b/website/src/__tests__/app-route-tree.test.tsx index dad6211..8be6cdb 100644 --- a/website/src/__tests__/app-route-tree.test.tsx +++ b/website/src/__tests__/app-route-tree.test.tsx @@ -157,15 +157,19 @@ describe('AppRouteTree', () => { expect(screen.getByText('Loading HyperTwist...')).toBeTruthy() expect(screen.getByText('Public release shell')).toBeTruthy() - expect(screen.getByText(/public product story, current launch posture, and browser-versus-desktop authority map/i)).toBeTruthy() - expect(await screen.findByText('From first solves to 120-cell, HyperTwist keeps the real simulator in the downloadable.')).toBeTruthy() + expect(screen.getByText(/public product story, current launch status, and browser-versus-desktop authority map/i)).toBeTruthy() + expect(await screen.findByText( + 'From first solves to 120-cell, HyperTwist keeps the real simulator in the downloadable.', + {}, + { timeout: 3000 }, + )).toBeTruthy() }) it('renders the browser-guide page through the real public route tree', async () => { renderRoute('/browser') expect(screen.getByText('Browser access guide')).toBeTruthy() - expect(screen.getByText('Web version posture')).toBeTruthy() + expect(screen.getByText('Web version role')).toBeTruthy() expect(screen.getByText(/browser-versus-downloadable boundary, protected dashboard handoff, and the current web-lane purpose/i)).toBeTruthy() expect(await screen.findByText('The browser version exists to support the downloadable, not replace it.')).toBeTruthy() }) @@ -187,7 +191,7 @@ describe('AppRouteTree', () => { it('renders the public feature-atlas page through the real public route tree', async () => { renderRoute('/features') - expect(await screen.findByText('Feature truth without the roadmap archaeology.')).toBeTruthy() + expect(await screen.findByText('Feature truth without the guesswork.')).toBeTruthy() expect(screen.getByText('How to read the product truth')).toBeTruthy() }) @@ -209,8 +213,8 @@ describe('AppRouteTree', () => { renderRoute('/launch-status') expect(screen.getByText('Launch status')).toBeTruthy() expect(screen.getByText('Launch authority')).toBeTruthy() - expect(screen.getByText(/canonical public launch-readiness checklist, release posture, and preview-versus-launch authority map/i)).toBeTruthy() - expect(await screen.findByText('See exactly what still separates preview from public launch.')).toBeTruthy() + expect(screen.getByText(/canonical public launch-readiness checklist, release status, and early-access authority map/i)).toBeTruthy() + expect(await screen.findByText('See how public pages, account access, and desktop delivery work together.')).toBeTruthy() }) it('renders the login page through the real public route tree', async () => { @@ -459,7 +463,7 @@ describe('AppRouteTree', () => { }) renderRoute('/app/browser-access') - expect(await screen.findByText('Current browser posture')).toBeTruthy() + expect(await screen.findByText('Current browser role')).toBeTruthy() expect(screen.getByText('Browser-to-desktop handoff')).toBeTruthy() }) diff --git a/website/src/__tests__/protected-app-pages.test.tsx b/website/src/__tests__/protected-app-pages.test.tsx index 81e44f2..f01fc05 100644 --- a/website/src/__tests__/protected-app-pages.test.tsx +++ b/website/src/__tests__/protected-app-pages.test.tsx @@ -187,10 +187,10 @@ describe('protected app pages', () => { }) }) - it('surfaces live browser-shell posture and browser-to-desktop guidance', async () => { + it('surfaces live browser-shell status and browser-to-desktop guidance', async () => { renderPage(, '/app/browser-access') - expect(await screen.findByText('Current browser posture')).toBeTruthy() + expect(await screen.findByText('Current browser role')).toBeTruthy() expect(screen.getByText('Current release action')).toBeTruthy() expect((await screen.findByRole('link', { name: 'Download Windows package' })).getAttribute('href')).toBe('https://downloads.hypertwist.app/windows.exe') expect(screen.getByText('Current packaged desktop proof')).toBeTruthy() @@ -299,10 +299,10 @@ describe('protected app pages', () => { expect(await screen.findByText('Windows release authority: configured')).toBeTruthy() expect(screen.getByText('Operator checkout target: https://buy.paddle.com/operator-authoritative')).toBeTruthy() expect(screen.getByText('Studio checkout target: https://buy.paddle.com/studio-authoritative')).toBeTruthy() - expect(screen.getByText(/Public launch is not fully configured yet: preview-tier launch gate\./i)).toBeTruthy() + expect(screen.getByText(/Public launch is not fully configured yet: public launch gate\./i)).toBeTruthy() }) - it('surfaces concrete live preview blockers on the protected launch route', async () => { + it('surfaces concrete early-access blockers on the protected launch route', async () => { mockGetAuthHealth.mockResolvedValue({ ok: true, service: 'hypertwist-auth-server', @@ -369,14 +369,14 @@ describe('protected app pages', () => { renderPage(, '/app/launch-status') - expect(await screen.findByText('Current preview blockers from the live auth runtime')).toBeTruthy() - expect(screen.getByText('Windows release lane is not configured on the live preview deployment yet.')).toBeTruthy() - expect(screen.getByText('Operator checkout is still on support fallback in the live preview deployment.')).toBeTruthy() - expect(screen.getByText('Studio checkout is still on support fallback in the live preview deployment.')).toBeTruthy() - expect(screen.getByText('Shared browser-auth runtime is not yet production-ready on the live deployment.')).toBeTruthy() - expect(screen.getByText('Paddle webhook secret is not configured yet.')).toBeTruthy() - expect(screen.getByText('Billing product-plan map is not configured yet.')).toBeTruthy() - expect(screen.getByText('Billing price-plan map is not configured yet.')).toBeTruthy() + expect(await screen.findByText('Current early-access blockers from the live auth runtime')).toBeTruthy() + expect(screen.getByText('Windows release delivery is still routed through signed-in account follow-up.')).toBeTruthy() + expect(screen.getByText('Operator checkout is currently handled through account or support follow-up.')).toBeTruthy() + expect(screen.getByText('Studio checkout is currently handled through account or support follow-up.')).toBeTruthy() + expect(screen.getByText('Shared browser-auth runtime still needs production readiness confirmation on the current deployment.')).toBeTruthy() + expect(screen.getByText('Paddle webhook verification still needs to be enabled for fully automated billing updates.')).toBeTruthy() + expect(screen.getByText('Billing product-plan mapping still needs to be connected to the live subscription catalog.')).toBeTruthy() + expect(screen.getByText('Billing price-plan mapping still needs to be connected to the live subscription catalog.')).toBeTruthy() expect(screen.getByText('Runtime warning: SUPERTOKENS_CORE_URI still targets a loopback/local-development host.')).toBeTruthy() }) @@ -440,7 +440,7 @@ describe('protected app pages', () => { expect(screen.getByText('Verify the current training lanes')).toBeTruthy() }) - it('surfaces protected notices references and release-target notice posture', async () => { + it('surfaces protected notices references and release-target notice status', async () => { renderPage(, '/app/notices') expect(await screen.findByText('Distribution notices')).toBeTruthy() @@ -453,7 +453,7 @@ describe('protected app pages', () => { expect(await screen.findAllByText(byExactTextContent('Configured release targets: 1/2', 'LI'))).toHaveLength(1) expect(screen.getByText(byExactTextContent('Public repository/notices URL: https://github.com/hypertwist/hypertwist', 'LI'))).toBeTruthy() expect(screen.getByText(byExactTextContent('Corresponding-source URL: https://hypertwist.app/open-source/source.zip', 'LI'))).toBeTruthy() - expect(screen.getByText(byExactTextContent('Windows: configured, validation passed', 'LI'))).toBeTruthy() + expect(screen.getByText(byExactTextContent('Windows: published, validation passed', 'LI'))).toBeTruthy() expect(screen.getByText('Escalation and release follow-through')).toBeTruthy() expect(screen.getByText('Download and install issues')).toBeTruthy() expect(screen.getByRole('link', { name: 'Public notices' }).getAttribute('href')).toBe('/open-source-notices') @@ -461,7 +461,7 @@ describe('protected app pages', () => { expect(screen.getAllByRole('link', { name: 'Open downloads' }).every((link) => link.getAttribute('href') === '/app/downloads')).toBe(true) }) - it('keeps local signed-in viewer posture when protected pages fall back from live release-manifest authority', async () => { + it('keeps local signed-in viewer state when protected pages recover from unavailable live release-manifest authority', async () => { mockGetReleaseManifest.mockRejectedValue(new Error('release manifest unavailable')) renderPage(, '/app/account') @@ -470,7 +470,7 @@ describe('protected app pages', () => { expect(await screen.findByText(byExactTextContent('Manifest viewer authenticated: yes', 'LI'))).toBeTruthy() expect(await screen.findAllByText(byExactTextContent('Manifest viewer plan: operator', 'LI'))).toHaveLength(2) expect(await screen.findAllByText(byExactTextContent('Manifest viewer access: active', 'LI'))).toHaveLength(2) - expect(screen.getByText(/bounded fallback metadata until auth-server release authority returns/i)).toBeTruthy() + expect(screen.getByText(/bounded recovery metadata until auth-server release authority returns/i)).toBeTruthy() }) it('invalidates the protected browser session when live release-manifest authority comes back anonymous', async () => { @@ -573,7 +573,7 @@ describe('protected app pages', () => { expect(screen.getByText(/access status changed from local session-default to live active/i)).toBeTruthy() }) - it('turns protected non-entitled account posture into explicit checkout guidance when live commerce targets exist', async () => { + it('turns protected non-entitled account state into explicit checkout guidance when live commerce targets exist', async () => { mockUsePlatformAuth.mockReturnValue({ user: { id: 'viewer-1', diff --git a/website/src/__tests__/public-auth-pages.test.tsx b/website/src/__tests__/public-auth-pages.test.tsx index c8c8ebc..60958fa 100644 --- a/website/src/__tests__/public-auth-pages.test.tsx +++ b/website/src/__tests__/public-auth-pages.test.tsx @@ -284,7 +284,7 @@ describe('public auth and download pages', () => { expect(screen.queryByTestId('location')).toBeNull() }) - it('surfaces auth-runtime missing and warning posture on the login page', () => { + it('surfaces auth-runtime missing settings and recovery guidance on the login page', () => { mockGetSuperTokensAuthRuntimeValidation.mockReturnValue({ ready: false, missing: ['VITE_SUPERTOKENS_API_DOMAIN'], @@ -293,11 +293,11 @@ describe('public auth and download pages', () => { renderAuthRoutes('/login') - expect(screen.getByText(/Shared browser auth is not fully in production posture yet./i)).toBeTruthy() + expect(screen.getByText(/Account access can continue through the available browser-auth lane./i)).toBeTruthy() expect(screen.getByText('What still works')).toBeTruthy() expect(screen.getByText('What stays intentionally bounded')).toBeTruthy() expect(screen.getByText('Recommended recovery order')).toBeTruthy() - expect(screen.getByText('Missing auth env: VITE_SUPERTOKENS_API_DOMAIN')).toBeTruthy() + expect(screen.getByText('Auth runtime setting pending: VITE_SUPERTOKENS_API_DOMAIN')).toBeTruthy() expect(screen.getByText('VITE_AUTH_API_BASE_URL not configured; same-origin auth fallback remains active.')).toBeTruthy() expect(screen.getByText('Browser account access does not replace the simulator.')).toBeTruthy() expect(screen.getByRole('link', { name: 'Open support' }).getAttribute('href')).toBe('/support?topic=operator-access') diff --git a/website/src/__tests__/public-launch.test.ts b/website/src/__tests__/public-launch.test.ts index 741989e..14318f3 100644 --- a/website/src/__tests__/public-launch.test.ts +++ b/website/src/__tests__/public-launch.test.ts @@ -25,7 +25,7 @@ describe('public launch readiness helpers', () => { 'Billing product-plan map', 'Billing price-plan map', 'Paddle webhook secret', - 'Public auth runtime posture', + 'Public auth runtime status', ]) expect(isPublicLaunchReady({ windowsDownloadConfigured: true, @@ -176,7 +176,7 @@ describe('public launch readiness helpers', () => { expect(launchStatus.ready).toBe(false) expect(launchStatus.posture).toBe('preview') - expect(launchStatus.missingLabels).toEqual(['preview-tier launch gate']) + expect(launchStatus.missingLabels).toEqual(['public launch gate']) expect(launchStatus.targets).toEqual({ operatorCheckoutTarget: 'https://buy.paddle.com/operator-authoritative', studioCheckoutTarget: 'https://buy.paddle.com/studio-authoritative', diff --git a/website/src/__tests__/public-marketing-pages.test.tsx b/website/src/__tests__/public-marketing-pages.test.tsx index 5262ec7..c1a8d17 100644 --- a/website/src/__tests__/public-marketing-pages.test.tsx +++ b/website/src/__tests__/public-marketing-pages.test.tsx @@ -267,8 +267,8 @@ describe('public marketing pages', () => { renderWithProviders() expect(screen.getByRole('link', { name: /sign in for windows access/i }).getAttribute('href')).toBe('/app/downloads?platform=windows') - expect(screen.getAllByText('Preview posture').length).toBeGreaterThan(0) - expect(screen.getByText('Operator checkout URL: missing')).toBeTruthy() + expect(screen.getAllByText('Account-gated early access').length).toBeGreaterThan(0) + expect(screen.getByText(/Operator checkout: available through account\/support follow-up/i)).toBeTruthy() expect(screen.getByText('Current packaged desktop proof')).toBeTruthy() expect(screen.getByText('How the release lane works')).toBeTruthy() expect(screen.getByText('What the installed runtime already owns')).toBeTruthy() @@ -317,7 +317,7 @@ describe('public marketing pages', () => { expect(document.head.querySelector('meta[property="og:url"]')?.getAttribute('content')).toBe('https://hypertwist.app/download') }) - it('keeps public download fallback posture explicit when live release authority is unavailable', async () => { + it('keeps public download recovery guidance explicit when live release authority is unavailable', async () => { mockGetAuthHealth.mockResolvedValue({ ok: true, service: 'hypertwist-auth-server', @@ -358,14 +358,14 @@ describe('public marketing pages', () => { renderWithProviders() - expect(await screen.findByText(/public release fallback/i)).toBeTruthy() + expect(await screen.findByText(/Release service recovery/i)).toBeTruthy() expect(screen.getByText(/direct package delivery stays intentionally withheld until that authority returns/i)).toBeTruthy() expect(screen.getByText('What stays intentionally withheld')).toBeTruthy() - expect(screen.getByRole('link', { name: 'Open protected downloads' }).getAttribute('href')).toBe('/app/downloads?platform=windows') + expect(screen.getByRole('link', { name: 'Open protected download center' }).getAttribute('href')).toBe('/app/downloads?platform=windows') expect(screen.getByRole('link', { name: 'Open support' }).getAttribute('href')).toBe('/support?topic=operator-access') }) - it('surfaces homepage preview posture from live auth and release readiness', async () => { + it('surfaces homepage account-gated access status from live auth and release readiness', async () => { mockGetAuthHealth.mockResolvedValue({ ok: true, service: 'hypertwist-auth-server', @@ -462,16 +462,16 @@ describe('public marketing pages', () => { renderWithProviders(, ['/']) expect(screen.getByText('Current public site status')).toBeTruthy() - expect(await screen.findByText('Public website and release posture')).toBeTruthy() - expect(screen.getAllByText('Preview posture').length).toBeGreaterThan(0) + expect(await screen.findByText('Public website and release access')).toBeTruthy() + expect(screen.getAllByText('Account-gated early access').length).toBeGreaterThan(0) expect(screen.getByText('Why HyperTwist keeps both a website and a desktop runtime')).toBeTruthy() expect(screen.getByText('Common browser-versus-desktop questions')).toBeTruthy() expect(screen.getByText('If the desktop app is primary, why keep the web version?')).toBeTruthy() expect(screen.getByText(/It is intentionally inferior for the core simulator job/i)).toBeTruthy() expect(screen.getByText('What the website is for')).toBeTruthy() expect(screen.getByText('Current input, XR, and settings truth')).toBeTruthy() - expect(screen.getAllByText('Paddle webhook secret: missing').length).toBeGreaterThan(0) - expect(screen.getAllByText(/public auth runtime posture/i).length).toBeGreaterThan(0) + expect(screen.getAllByText('Account-gated early access').length).toBeGreaterThan(0) + expect(screen.getByText('Subscription access: managed on the website/dashboard and handed to the downloadable through desktop-link pairing.')).toBeTruthy() expect(screen.getByRole('heading', { name: 'Browser account access methods' })).toBeTruthy() expect(screen.getByText('Auth methods ready')).toBeTruthy() expect(screen.getByText('Email and password')).toBeTruthy() @@ -615,14 +615,14 @@ describe('public marketing pages', () => { expect(aboutDecisionGuideSection).toBeTruthy() expect(within(aboutDecisionGuideSection as HTMLElement).getByText('Need account state, pairing, or protected browser follow-through?')).toBeTruthy() expect(within(aboutDecisionGuideSection as HTMLElement).getByText('Need plan selection, billing, or operator provisioning?')).toBeTruthy() - expect(screen.getByText('Current desktop control and XR truth')).toBeTruthy() + expect(screen.getByText('Current desktop control and headset truth')).toBeTruthy() expect(screen.getByText('Selectable control and settings roster')).toBeTruthy() expect(screen.getByText('Shipped classic control profile')).toBeTruthy() expect(screen.getByText('Generates desktop-link tokens for safe browser-to-desktop handoff')).toBeTruthy() - expect(screen.getByText('Must prove its own runtime and backend contract before being marketed as live')).toBeTruthy() + expect(screen.getByText('Would need its own runtime quality, backend contract, and product proof before launch')).toBeTruthy() expect(screen.getByText('Release and deployment maturity')).toBeTruthy() - expect(screen.getByText('Current public rollout posture')).toBeTruthy() - expect(screen.getByText('About-page launch and release posture')).toBeTruthy() + expect(screen.getByText('Current public rollout state')).toBeTruthy() + expect(screen.getByText('About-page launch and release access')).toBeTruthy() expect(screen.getByText('Current packaged desktop proof')).toBeTruthy() expect(screen.getByText('Packaged validation passed')).toBeTruthy() expect(screen.getByText('Release references and source availability')).toBeTruthy() @@ -725,7 +725,7 @@ describe('public marketing pages', () => { renderWithProviders(, ['/features']) - expect(screen.getByText('Feature truth without the roadmap archaeology.')).toBeTruthy() + expect(screen.getByText('Feature truth without the guesswork.')).toBeTruthy() expect(screen.getByText('How to read the product truth')).toBeTruthy() expect(screen.getByText('Implemented now')).toBeTruthy() expect(screen.getByText('Choose the right HyperTwist surface')).toBeTruthy() @@ -743,8 +743,8 @@ describe('public marketing pages', () => { expect(screen.getByText('Common capability questions')).toBeTruthy() expect(screen.getByText('If the desktop app is primary, why keep the web version?')).toBeTruthy() expect(screen.getByText('Is VR/controller support already fully finished?')).toBeTruthy() - expect(screen.getByText('Current public rollout posture')).toBeTruthy() - expect(screen.getByText('Public feature and launch posture')).toBeTruthy() + expect(screen.getByText('Current public rollout state')).toBeTruthy() + expect(screen.getByText('Public feature and access status')).toBeTruthy() const featuresDecisionGuideHeading = screen.getByRole('heading', { name: 'Choose the next release move' }) const featuresDecisionGuideSection = featuresDecisionGuideHeading.closest('section') expect(featuresDecisionGuideSection).toBeTruthy() @@ -929,7 +929,7 @@ describe('public marketing pages', () => { expect(screen.getByText('What the software actually does after access is granted')).toBeTruthy() expect(screen.getByText('Higher-dimensional families behind the plans')).toBeTruthy() expect(screen.getAllByText('Current input and runtime control truth').length).toBeGreaterThan(0) - expect(screen.getByText('The current host decision remains desktop-hosted No-Go on broader native OpenXR/controller widening until Windows packaged controller validation with controller truth is complete.')).toBeTruthy() + expect(screen.getByText('The current host decision remains desktop-first for broader native OpenXR/controller rollout until Windows packaged controller validation with controller truth is complete.')).toBeTruthy() expect(screen.getByText('Choose the right HyperTwist surface')).toBeTruthy() const pricingDecisionGuideHeading = screen.getByRole('heading', { name: 'Choose the next release move' }) const pricingDecisionGuideSection = pricingDecisionGuideHeading.closest('section') @@ -945,7 +945,7 @@ describe('public marketing pages', () => { expect(screen.getByText('GitHub sign-in')).toBeTruthy() expect(screen.getByText('ORCID sign-in')).toBeTruthy() expect(screen.queryByText('Google sign-in')).toBeNull() - expect(screen.getByText('Shows account, auth, billing, and release readiness posture')).toBeTruthy() + expect(screen.getByText('Shows account, auth, billing, and release readiness status')).toBeTruthy() expect(screen.getByText('Owns recognition, replay, coaching, and packaged training behavior')).toBeTruthy() expect(screen.getByText('Commercial distribution doctrine')).toBeTruthy() expect(screen.getByText('Public pages are distribution surfaces')).toBeTruthy() @@ -1024,12 +1024,12 @@ describe('public marketing pages', () => { expect(screen.getAllByText('Selected help lane').length).toBeGreaterThan(0) expect(screen.getAllByText('Launch readiness').length).toBeGreaterThan(0) - expect(screen.getAllByText(/turning the preview lane into a public launch/i).length).toBeGreaterThan(0) + expect(screen.getAllByText(/turning early access into a public launch/i).length).toBeGreaterThan(0) expect(screen.getByText('Selected lane next steps')).toBeTruthy() const selectedLaneHeading = screen.getByRole('heading', { name: 'Selected lane next steps' }) const selectedLaneSection = selectedLaneHeading.closest('section') expect(selectedLaneSection).toBeTruthy() - expect(within(selectedLaneSection as HTMLElement).getByText('Confirm public launch status, operator/studio checkout posture, and support contact first.')).toBeTruthy() + expect(within(selectedLaneSection as HTMLElement).getByText('Confirm public launch status, operator/studio checkout status, and support contact first.')).toBeTruthy() expect(within(selectedLaneSection as HTMLElement).getByRole('link', { name: 'Sign in for protected release lane' }).getAttribute('href')).toBe('/login?next=%2Fapp%2Fdownloads%3Fplatform%3Dwindows') expect(within(selectedLaneSection as HTMLElement).getByRole('link', { name: 'Sign in for protected notices' }).getAttribute('href')).toBe('/login?next=%2Fapp%2Fnotices') expect(within(selectedLaneSection as HTMLElement).getByRole('link', { name: 'Open pricing' }).getAttribute('href')).toBe('/pricing') @@ -1046,7 +1046,7 @@ describe('public marketing pages', () => { expect(screen.getByText('GitHub sign-in')).toBeTruthy() expect(screen.getByText('ORCID sign-in')).toBeTruthy() expect(screen.queryByText('Google sign-in')).toBeNull() - expect(screen.getByText('Shows account, auth, billing, and release readiness posture')).toBeTruthy() + expect(screen.getByText('Shows account, auth, billing, and release readiness status')).toBeTruthy() expect(screen.getByText('Support lanes')).toBeTruthy() expect(screen.getByText('Issue reporting checklist')).toBeTruthy() expect(screen.getByText('Account, pairing, or entitlement issue report')).toBeTruthy() @@ -1054,8 +1054,8 @@ describe('public marketing pages', () => { expect(screen.getAllByText('Manual and route focus').length).toBeGreaterThan(0) expect(screen.getByText('Recovery and degraded-state guidance')).toBeTruthy() expect(screen.getByText('Desktop-first continuity during recovery')).toBeTruthy() - expect(screen.getByText('Current release and package posture')).toBeTruthy() - expect(screen.getByText('Current support-facing launch posture')).toBeTruthy() + expect(screen.getByText('Current release and package state')).toBeTruthy() + expect(screen.getByText('Current support-facing launch access')).toBeTruthy() expect(screen.getByText('Current packaged desktop proof')).toBeTruthy() expect(screen.getByText('Packaged validation passed')).toBeTruthy() const decisionGuideHeading = screen.getByRole('heading', { name: 'Choose the next release move' }) @@ -1143,7 +1143,7 @@ describe('public marketing pages', () => { const helpView = renderWithProviders(, ['/help']) expect(within(helpView.container).getByText('What this help center covers')).toBeTruthy() expect(within(helpView.container).getByText('Pick the right help lane')).toBeTruthy() - expect(within(helpView.container).getByText('Current controls and device posture')).toBeTruthy() + expect(within(helpView.container).getByText('Current controls and device state')).toBeTruthy() expect(within(helpView.container).getByText('Need escalation instead of guidance?')).toBeTruthy() const contactView = renderWithProviders(, ['/contact']) @@ -1268,7 +1268,7 @@ describe('public marketing pages', () => { expect(screen.getByText('Operator playbooks')).toBeTruthy() expect(screen.getByText('Simulator use today')).toBeTruthy() expect(screen.getByText('Higher-dimensional runtime guide')).toBeTruthy() - expect(screen.getByText('Current control and device posture')).toBeTruthy() + expect(screen.getByText('Current control and device state')).toBeTruthy() expect(screen.getAllByText('Selectable control and settings roster').length).toBeGreaterThan(0) expect(screen.getByText(/3 immersive-intensity presets and 3 reduced-distraction presets/i)).toBeTruthy() expect(screen.getByText('Deployment readiness snapshot')).toBeTruthy() @@ -1434,7 +1434,7 @@ describe('public marketing pages', () => { expect(screen.getByText('Simulator manual')).toBeTruthy() expect(screen.getByText('Higher-dimensional family guide')).toBeTruthy() expect(screen.getByText('Deployment readiness manual')).toBeTruthy() - expect(screen.getByText('Input and device posture')).toBeTruthy() + expect(screen.getByText('Input and device state')).toBeTruthy() expect(screen.getAllByText('Selectable control and settings roster').length).toBeGreaterThan(0) expect(screen.getAllByText('Keyboard and mouse ship today').length).toBeGreaterThan(0) expect(screen.getAllByText(/classic-wca-keyboard\/v1/i).length).toBeGreaterThan(0) @@ -1442,7 +1442,7 @@ describe('public marketing pages', () => { expect(screen.getByText(/I\/K = R\/R', J\/F = U\/U', H\/G = F\/F'/i)).toBeTruthy() expect(screen.getByText(/bounded OpenXR plugin stack, first-party runtime-owner substrate, and first-party controller settings\/rebinding ownership/i)).toBeTruthy() expect(screen.getByText(/R scramble, H hint, Enter submit, F mode, V hold-to-talk, C cycle voice/i)).toBeTruthy() - expect(screen.getAllByText(/latest persisted generated-mode selector posture is available for recall/i).length).toBeGreaterThan(0) + expect(screen.getAllByText(/latest persisted generated-mode selector state is available for recall/i).length).toBeGreaterThan(0) expect(screen.getByText('Feature-registry-backed wording only')).toBeTruthy() expect(screen.getByText('Documentation and route atlas')).toBeTruthy() expect(screen.getByText('Open-source notices')).toBeTruthy() @@ -1680,18 +1680,18 @@ describe('public marketing pages', () => { renderWithProviders(, ['/launch-status']) - expect(screen.getByText('Current launch-readiness checklist')).toBeTruthy() - expect(screen.getByText('What must be true before public launch')).toBeTruthy() + expect(screen.getByText('Current account and release access')).toBeTruthy() + expect(screen.getByText('What must be true before wider public launch')).toBeTruthy() expect(screen.getByText('Launch hardening tracks')).toBeTruthy() - expect(screen.getByText('Launch support and escalation lanes')).toBeTruthy() - expect(screen.getByText('Choose the next launch move')).toBeTruthy() + expect(screen.getByText('Access support and escalation lanes')).toBeTruthy() + expect(screen.getByText('Choose the next access move')).toBeTruthy() expect(screen.getByText('Release, notice, and support bundle')).toBeTruthy() - expect(screen.getByText('Why launch authority stays in the browser shell')).toBeTruthy() + expect(screen.getByText('Why access authority stays in the browser shell')).toBeTruthy() expect(screen.getAllByText('Launch readiness').length).toBeGreaterThan(0) expect( screen.getAllByRole('link', { name: 'Open launch status' }).some((link) => link.getAttribute('href') === '/launch-status'), ).toBe(true) - expect(document.title).toBe('HyperTwist launch status | HyperTwist') + expect(document.title).toBe('HyperTwist access status | HyperTwist') expect(document.head.querySelector('meta[property="og:url"]')?.getAttribute('content')).toBe('https://hypertwist.app/launch-status') }) @@ -1944,10 +1944,9 @@ describe('public marketing pages', () => { renderWithProviders(, ['/launch-status']) - expect(await screen.findByText(/external launch still needs preview-tier launch gate/i)).toBeTruthy() - expect(screen.getByText('Windows release authority: configured')).toBeTruthy() - expect(screen.getByText('Operator checkout target: https://buy.paddle.com/operator-authoritative')).toBeTruthy() - expect(screen.getByText('Studio checkout target: https://buy.paddle.com/studio-authoritative')).toBeTruthy() + expect(await screen.findByText('Account-gated early access')).toBeTruthy() + expect(await screen.findByText(/Operator checkout: available from the configured Paddle route/i)).toBeTruthy() + expect(screen.getByText(/Studio checkout: available from the configured Paddle route/i)).toBeTruthy() }) it('renders the expanded legal and digital-delivery guidance across public support surfaces', async () => { diff --git a/website/src/__tests__/route-shells.test.tsx b/website/src/__tests__/route-shells.test.tsx index f6ae681..241a5bd 100644 --- a/website/src/__tests__/route-shells.test.tsx +++ b/website/src/__tests__/route-shells.test.tsx @@ -160,7 +160,7 @@ describe('website route and shell behavior', () => { expect(screen.getByText('Loading operator access...')).toBeTruthy() expect(screen.getByText('Browser account access')).toBeTruthy() - expect(screen.getByText(/Checking your saved browser session, protected release posture, and browser-to-desktop continuity/i)).toBeTruthy() + expect(screen.getByText(/Checking your saved browser session, protected release status, and browser-to-desktop continuity/i)).toBeTruthy() expect(container.querySelector('.general-page-loader-shell--fullscreen')).not.toBeNull() expect(screen.getByAltText('HyperTwist')).toBeTruthy() expect(screen.getByRole('link', { name: 'Open sign-in' }).getAttribute('href')).toBe('/login?next=%2Fapp%2Faccount') @@ -252,7 +252,7 @@ describe('website route and shell behavior', () => { expect(screen.getByText('Desktop-first operator lane')).toBeTruthy() expect(screen.getByRole('link', { name: 'Launch Status' }).getAttribute('href')).toBe('/app/launch-status') expect(screen.getByRole('link', { name: 'Protected launch status' }).getAttribute('href')).toBe('/app/launch-status') - expect(screen.getByRole('link', { name: 'Public download posture' }).getAttribute('href')).toBe('/download') + expect(screen.getByRole('link', { name: 'Public download guidance' }).getAttribute('href')).toBe('/download') expect(screen.getByRole('link', { name: 'Public notices' }).getAttribute('href')).toBe('/open-source-notices') expect(screen.getByRole('link', { name: 'Operator access support' }).getAttribute('href')).toBe('/support?topic=operator-access') diff --git a/website/src/components/ErrorBoundary.tsx b/website/src/components/ErrorBoundary.tsx index 70eccf8..c759c31 100644 --- a/website/src/components/ErrorBoundary.tsx +++ b/website/src/components/ErrorBoundary.tsx @@ -1,4 +1,5 @@ import React, { Component, type ReactNode } from 'react' +import { HyperTwistButton } from './ui/HyperTwistButton' interface Props { children: ReactNode @@ -49,16 +50,16 @@ export class ErrorBoundary extends Component {

{this.state.error?.message || 'An unexpected error occurred loading this view.'}

- - +
diff --git a/website/src/components/layout/AppShell.tsx b/website/src/components/layout/AppShell.tsx index 6e2d8de..af734dd 100644 --- a/website/src/components/layout/AppShell.tsx +++ b/website/src/components/layout/AppShell.tsx @@ -3,6 +3,7 @@ import { Link, NavLink, Outlet } from 'react-router-dom' import { usePlatformAuth } from '../../auth/platform-auth' import { brandConfig } from '../../site-config' import { buildSupportPath } from '../../site-routes' +import { HyperTwistButton } from '../ui/HyperTwistButton' const appLinks = [ { to: '/app', label: 'Overview', icon: Gauge, end: true }, @@ -55,17 +56,17 @@ export function AppShell() {

  • Protected launch status
  • -
  • Public download posture
  • +
  • Public download guidance
  • Public notices
  • Operator access support
- - + diff --git a/website/src/components/layout/MarketingShell.tsx b/website/src/components/layout/MarketingShell.tsx index 5037637..87a0b49 100644 --- a/website/src/components/layout/MarketingShell.tsx +++ b/website/src/components/layout/MarketingShell.tsx @@ -1,8 +1,11 @@ +import { useEffect, useState } from 'react' import { Link, NavLink } from 'react-router-dom' +import { Moon, Sun } from 'lucide-react' import { usePlatformAuth } from '../../auth/platform-auth' import { MarketingLaunchStatusBanner } from '../ui/PublicLaunchStatus' import { brandConfig } from '../../site-config' import { footerLinks, marketingNavLinks } from '../../public-route-registry' +import { HyperTwistButton, HyperTwistButtonLink } from '../ui/HyperTwistButton' export const publicProductRealityStrip = (
@@ -13,18 +16,18 @@ export const publicProductRealityStrip = (

Web purpose

- Access and rollout -

The browser owns docs, account, pricing, notices, release posture, and desktop pairing.

+ Access and guidance +

The browser owns docs, accounts, pricing, notices, protected downloads, and desktop pairing.

Ready today

Keyboard and mouse -

Desktop control surfaces are usable for development and operator review without a headset.

+

Desktop controls support serious keyboard, mouse, touch, camera, replay, and training work without a headset.

-

Still gated

- Launch config and XR proof -

Public download, Paddle, live auth, and headset/controller observation remain explicit gates.

+

Account delivery

+ Account-gated delivery +

Public pages explain the product; signed-in dashboard routes handle release access and pairing.

) @@ -41,22 +44,58 @@ export const compactProductRealityStrip = (

Web purpose

- Access and rollout -

The browser owns docs, account, pricing, notices, release posture, and desktop pairing.

+ Access and guidance +

The browser owns docs, accounts, pricing, notices, protected downloads, and desktop pairing.

Ready today

Keyboard and mouse -

Desktop control surfaces are usable for development and operator review without a headset.

+

Desktop controls support serious keyboard, mouse, touch, camera, replay, and training work without a headset.

-

Still gated

- Launch config and XR proof -

Public download, Paddle, live auth, and headset/controller observation remain explicit gates.

+

Account delivery

+ Account-gated delivery +

Public pages explain the product; signed-in dashboard routes handle release access and pairing.

) +function useHideHeaderOnScroll() { + const [hidden, setHidden] = useState(false) + + useEffect(() => { + let previousScrollY = window.scrollY + let ticking = false + + function updateHeaderVisibility() { + const nextScrollY = window.scrollY + const isScrollingDown = nextScrollY > previousScrollY + 8 + const isScrollingUp = nextScrollY < previousScrollY - 8 + + if (nextScrollY < 96 || isScrollingUp) { + setHidden(false) + } else if (isScrollingDown && nextScrollY > 160) { + setHidden(true) + } + + previousScrollY = Math.max(nextScrollY, 0) + ticking = false + } + + function handleScroll() { + if (!ticking) { + window.requestAnimationFrame(updateHeaderVisibility) + ticking = true + } + } + + window.addEventListener('scroll', handleScroll, { passive: true }) + return () => window.removeEventListener('scroll', handleScroll) + }, []) + + return hidden +} + export function MarketingShell({ title, eyebrow, @@ -68,7 +107,8 @@ export function MarketingShell({ lede: string children: React.ReactNode }) { - const { isAuthenticated } = usePlatformAuth() + const { colorMode, isAuthenticated, toggleColorMode } = usePlatformAuth() + const isHeaderHidden = useHideHeaderOnScroll() const footerLookup = new Map(footerLinks.map((link) => [link.to, link])) const footerGroups = [ { @@ -87,7 +127,7 @@ export function MarketingShell({ return (
-
+
- + + {colorMode === 'dark' ? : } + {colorMode === 'dark' ? 'Light' : 'Dark'} + + {isAuthenticated ? 'Open dashboard' : 'Log in'} - - + + Get desktop app - +
@@ -139,12 +189,12 @@ export function MarketingShell({ Contact: {brandConfig.contact.email}

- + Get desktop app - - + + {isAuthenticated ? 'Account dashboard' : 'Account access'} - +
diff --git a/website/src/components/routes/ProtectedRoute.tsx b/website/src/components/routes/ProtectedRoute.tsx index b040f6f..b1825e8 100644 --- a/website/src/components/routes/ProtectedRoute.tsx +++ b/website/src/components/routes/ProtectedRoute.tsx @@ -1,7 +1,8 @@ -import { Link, Navigate, Outlet, useLocation } from 'react-router-dom' +import { Navigate, Outlet, useLocation } from 'react-router-dom' import { usePlatformAuth } from '../../auth/platform-auth' import { buildLoginRedirectTarget } from '../../auth/route-guard' import { buildSupportPath } from '../../site-routes' +import { HyperTwistButtonLink } from '../ui/HyperTwistButton' import { GeneralPageLoader } from '../ui/Skeletons' export function ProtectedRoute() { @@ -14,17 +15,17 @@ export function ProtectedRoute() {
- + Open sign-in - - + + Open support - +
) diff --git a/website/src/components/ui/BrowserAuthMethodsGuide.tsx b/website/src/components/ui/BrowserAuthMethodsGuide.tsx index 82e58fa..1a98498 100644 --- a/website/src/components/ui/BrowserAuthMethodsGuide.tsx +++ b/website/src/components/ui/BrowserAuthMethodsGuide.tsx @@ -16,7 +16,7 @@ function buildBrowserAuthMethodCards(): readonly BrowserAuthMethodCard[] { { title: 'Email and password', description: - 'This is the default browser-account lane and remains the most predictable shared-auth path across preview, mixed, and production deployment postures.', + 'This is the default browser-account lane and remains the most predictable shared-auth path across early access, mixed, and production deployments.', bullets: [ 'Use it when you want the clearest route into the protected dashboard, protected downloads, and desktop-link pairing.', 'It opens the same protected account and release surfaces as the optional provider buttons.', @@ -53,7 +53,7 @@ function buildBrowserAuthMethodCards(): readonly BrowserAuthMethodCard[] { cards.push({ title: 'ORCID sign-in', description: - 'ORCID is available in this build as a first-party shared-auth provider rather than a UI-only placeholder, so research-oriented identity can route through the same protected operator lanes.', + 'ORCID is available in this build as a first-party shared-auth provider, so research-oriented identity can route through the same protected operator lanes.', bullets: [ 'Use it when this deployment has ORCID configured and you want standards-backed browser sign-in continuity into the protected dashboard and download lanes.', 'It remains a browser-account path only; it does not replace desktop-link pairing or the native simulator runtime.', @@ -68,7 +68,7 @@ export function BrowserAuthMethodsGuide() { const authRuntimeValidation = getSuperTokensAuthRuntimeValidation() const cards = buildBrowserAuthMethodCards() const diagnostics = [ - ...authRuntimeValidation.missing.map((item) => `Missing auth env: ${item}`), + ...authRuntimeValidation.missing.map((item) => `Auth runtime setting pending: ${item}`), ...authRuntimeValidation.warnings, ] @@ -82,7 +82,7 @@ export function BrowserAuthMethodsGuide() { ? 'The shared browser-auth runtime is configured cleanly in this build, so the methods below all route into the same protected account, release, and desktop-pairing surfaces.' : 'The shared browser-auth runtime is present in this build, but remaining warnings should be cleared before this surface is treated as fully production-ready.' ) - : 'This build may still rely on bounded fallback posture until the missing shared-auth runtime values are configured, even though the method lineup below stays useful as operator guidance.' + : 'This build may still rely on bounded recovery mode until the pending shared-auth runtime values are configured, even though the method lineup below stays useful as operator guidance.' return (
diff --git a/website/src/components/ui/HyperTwistButton.tsx b/website/src/components/ui/HyperTwistButton.tsx new file mode 100644 index 0000000..92021e4 --- /dev/null +++ b/website/src/components/ui/HyperTwistButton.tsx @@ -0,0 +1,119 @@ +import { Button as PerformativeButton, type ButtonSize } from 'performative-ui' +import { Link, type LinkProps } from 'react-router-dom' +import type { AnchorHTMLAttributes, ButtonHTMLAttributes, ReactNode } from 'react' + +type HyperTwistButtonTone = 'primary' | 'secondary' | 'ghost' + +function resolvePerformativeVariant(tone: HyperTwistButtonTone) { + if (tone === 'primary') return 'glow' + if (tone === 'secondary') return 'wave' + return 'ghost' +} + +function buildClassName({ + tone, + full, + className, +}: { + tone: HyperTwistButtonTone + full?: boolean + className?: string +}) { + return [ + 'button', + `button--${tone}`, + tone === 'secondary' ? 'button--primary' : '', + full ? 'button--full' : '', + className || '', + ].filter(Boolean).join(' ') +} + +export function HyperTwistButtonLink({ + to, + tone = 'primary', + size = 'md', + full, + className, + children, + ...props +}: Omit & { + to: LinkProps['to'] + tone?: HyperTwistButtonTone + size?: ButtonSize + full?: boolean + children: ReactNode +}) { + return ( + + {children} + + ) +} + +export function HyperTwistButton({ + tone = 'primary', + size = 'md', + full, + className, + children, + ...props +}: ButtonHTMLAttributes & { + tone?: HyperTwistButtonTone + size?: ButtonSize + full?: boolean + children: ReactNode +}) { + return ( + + {children} + + ) +} + +export function HyperTwistButtonAnchor({ + href, + tone = 'primary', + size = 'md', + full, + className, + children, + ...props +}: AnchorHTMLAttributes & { + href: string + tone?: HyperTwistButtonTone + size?: ButtonSize + full?: boolean + children: ReactNode +}) { + return ( + + {children} + + ) +} diff --git a/website/src/components/ui/OperationalStatusCallout.tsx b/website/src/components/ui/OperationalStatusCallout.tsx index ed292f5..5bcf65c 100644 --- a/website/src/components/ui/OperationalStatusCallout.tsx +++ b/website/src/components/ui/OperationalStatusCallout.tsx @@ -1,5 +1,5 @@ -import { Link } from 'react-router-dom' import { isExternalHref } from '../../site-routes' +import { HyperTwistButtonAnchor, HyperTwistButtonLink } from './HyperTwistButton' type OperationalStatusSection = { title: string @@ -44,19 +44,19 @@ export function OperationalStatusCallout({
{actions.map((action) => ( isExternalHref(action.to) ? ( - {action.label} - + ) : ( - + {action.label} - + ) ))}
diff --git a/website/src/components/ui/PublicLaunchStatus.tsx b/website/src/components/ui/PublicLaunchStatus.tsx index 198e148..4105c01 100644 --- a/website/src/components/ui/PublicLaunchStatus.tsx +++ b/website/src/components/ui/PublicLaunchStatus.tsx @@ -5,6 +5,7 @@ import { getAuthHealth } from '../../auth/auth-api' import { buildLiveLaunchBlockerDetails, resolvePublicLaunchStatusSummary } from '../../public-launch' import { launchReadiness } from '../../site-config' import { buildProtectedDownloadPath } from '../../site-routes' +import { HyperTwistButtonLink } from './HyperTwistButton' function buildMarketingLaunchStatusSummary( ready: boolean, @@ -12,24 +13,15 @@ function buildMarketingLaunchStatusSummary( missingLabels: string[], ) { if (ready) { - return 'Checkout, release, notices, and live auth-runtime posture are aligned for the current public lane.' + return 'Account access, release references, checkout, notices, and desktop delivery are aligned for the current public lane.' } - if (liveBlockerDetails.length > 0) { - const featuredBlockers = liveBlockerDetails.slice(0, 2) - const remainingBlockerCount = liveBlockerDetails.length - featuredBlockers.length - const remainingBlockerLine = remainingBlockerCount > 0 - ? ` ${remainingBlockerCount} more live blocker${remainingBlockerCount === 1 ? '' : 's'} remain on the deployment.` - : '' + const unresolvedCount = Math.max(liveBlockerDetails.length, missingLabels.length) + const accessNote = unresolvedCount > 0 + ? 'Some release and commerce steps are still handled through signed-in dashboard or support follow-up.' + : 'Release access is intentionally routed through account-aware dashboard surfaces.' - return `Live preview lane: ${featuredBlockers.join(' ')}${remainingBlockerLine}` - } - - if (missingLabels.length > 0) { - return `Live preview lane: remaining launch blockers are ${missingLabels.join(', ')}.` - } - - return 'Live preview lane: rollout configuration is still incomplete on the current deployment.' + return `HyperTwist is in account-gated early access. ${accessNote}` } function usePublicLaunchStatus() { @@ -75,17 +67,17 @@ export function MarketingLaunchStatusBanner() {

- {ready ? 'Launch-ready posture' : 'Preview posture'} + {ready ? 'Public launch ready' : 'Early access'}

Public site status

{buildMarketingLaunchStatusSummary(ready, liveBlockerDetails, missingLabels)}

- View launch posture + View access status - Open protected release lane + Open signed-in downloads
@@ -97,33 +89,30 @@ export function PublicLaunchStatus({ }: { title?: string }) { - const { authHealthQuery, checklist, launchStatus, liveBlockerDetails, missingLabels, ready } = usePublicLaunchStatus() + const { authHealthQuery, launchStatus, liveBlockerDetails, ready } = usePublicLaunchStatus() return (

- {ready ? 'Launch-ready posture' : 'Preview posture'} + {ready ? 'Public launch ready' : 'Account-gated early access'}

{title}

{ready - ? 'The bounded public website lane now has the core download, checkout, and notice configuration needed for external launch.' - : `The public website is live, but external launch still needs ${missingLabels.join(', ')}.`} + ? 'HyperTwist can route visitors from public product pages through account access, checkout, protected downloads, and notices.' + : 'HyperTwist is available as an account-gated desktop-first product lane. Public pages explain the software, while signed-in dashboard routes handle download access, subscription state, and desktop pairing.'}

    - {checklist.map((item) => ( -
  • - {item.label}: {item.configured - ? (item.id === 'public-auth-runtime' ? 'production-ready' : 'configured') - : (item.id === 'public-auth-runtime' ? 'local-or-mixed' : 'missing')} -
  • - ))} -
  • Operator checkout target: {launchStatus.targets.operatorCheckoutTarget || 'support fallback active'}
  • -
  • Studio checkout target: {launchStatus.targets.studioCheckoutTarget || 'support fallback active'}
  • +
  • Desktop app access: routed through account creation or sign-in before package delivery.
  • +
  • Browser version: available as the public/protected account, docs, release, pricing, and pairing shell, not as simulator parity.
  • +
  • Subscription access: managed on the website/dashboard and handed to the downloadable through desktop-link pairing.
  • +
  • Download authority: protected dashboard first; anonymous public pages explain targets without exposing raw package delivery.
  • +
  • Operator checkout: {launchStatus.targets.operatorCheckoutTarget ? 'available from the configured Paddle route' : 'available through account/support follow-up until the public checkout route is switched on'}.
  • +
  • Studio checkout: {launchStatus.targets.studioCheckoutTarget ? 'available from the configured Paddle route' : 'available through account/support follow-up until the public checkout route is switched on'}.
- {liveBlockerDetails.length > 0 ? ( + {ready && liveBlockerDetails.length > 0 ? (
-

{ready ? 'Live runtime notes' : 'Current preview blockers from the live auth runtime'}

+

Current runtime notes

    {liveBlockerDetails.map((item) => (
  • {item}
  • @@ -132,21 +121,21 @@ export function PublicLaunchStatus({
) : null} {authHealthQuery.isLoading ? ( -

Checking live launch-readiness posture from the deployed auth server.

+

Checking current account and release access status.

) : null} {authHealthQuery.isError ? (

- Live auth-health lookup failed. Launch posture cannot confirm runtime, billing, or release-authority readiness right now. + Live access-status lookup is unavailable right now. Public product guidance remains visible; use sign-in or support for account-aware follow-through.

) : null} {!ready ? (
- - Open protected release lane - - + + Open signed-in downloads + + Open protected notices - +
) : null}
diff --git a/website/src/pages/app-pages.tsx b/website/src/pages/app-pages.tsx index 1009614..a09c159 100644 --- a/website/src/pages/app-pages.tsx +++ b/website/src/pages/app-pages.tsx @@ -4,6 +4,7 @@ import { Link, useSearchParams } from 'react-router-dom' import { buildAuthApiBaseUrls, createDesktopLinkToken, getAuthHealth, getReleaseManifest, type AuthHealthPayload } from '../auth/auth-api' import { usePlatformAuth, type PlatformUser } from '../auth/platform-auth' import { SiteMetadata } from '../components/seo/SiteMetadata' +import { HyperTwistButton, HyperTwistButtonAnchor, HyperTwistButtonLink } from '../components/ui/HyperTwistButton' import { OperationalStatusCallout } from '../components/ui/OperationalStatusCallout' import { ProductSurfaceMatrix } from '../components/ui/ProductSurfaceMatrix' import { ReleaseValidationSummary } from '../components/ui/ReleaseValidationSummary' @@ -135,7 +136,7 @@ function getProtectedDownloadActionLabel({ releaseAuthorityUnavailable: boolean }) { if (!configured) { - return 'Release URL not configured yet' + return 'Release access is not published yet' } if (viewerCanDownload) { @@ -188,7 +189,7 @@ function ProtectedAuthSessionAuthorityPanel({
  • Signed-in method: {formatAuthMethodLabel(user?.authMethod)}
  • -
  • Auth stack: {superTokensConfigured ? 'SuperTokens-backed' : 'Local fallback mode'}
  • +
  • Auth stack: {superTokensConfigured ? 'SuperTokens-backed' : 'Local recovery mode'}
  • {healthQuery.data ? ( <>
  • Shared auth configured: {healthQuery.data.supertokens.configured ? 'yes' : 'no'}
  • @@ -199,7 +200,7 @@ function ProtectedAuthSessionAuthorityPanel({ Available provider routes: Email/password on, GitHub {healthQuery.data.supertokens.oauth?.github ? 'on' : 'off'}, Google {healthQuery.data.supertokens.oauth?.google ? 'on' : 'off'}, ORCID {healthQuery.data.supertokens.oauth?.orcid ? 'on' : 'off'}
  • - Fallback posture: {healthQuery.data.fallback.active + Recovery mode: {healthQuery.data.fallback.active ? `active${healthQuery.data.fallback.reason ? ` (${healthQuery.data.fallback.reason})` : ''}` : 'inactive'}
  • @@ -235,7 +236,7 @@ function ProtectedAuthSessionAuthorityPanel({ title: 'Recommended recovery order', items: [ 'Restore shared auth reachability before trusting live entitlement or desktop-link issuance.', - 'Use operator support if the protected dashboard stays in degraded auth posture.', + 'Use operator support if the protected dashboard stays in degraded auth state.', ], }, ]} @@ -243,9 +244,9 @@ function ProtectedAuthSessionAuthorityPanel({ ) : null} {healthQuery.data?.fallback.active ? ( - + Download operator manual (.md) - + {releaseManifest.public_docs_url ? ( - + Public docs - + ) : null} {releaseManifest.release_notes_url ? ( - + Release notes - + ) : null} {releaseManifest.corresponding_source_url ? ( - + Corresponding source - + ) : null} {releaseManifest.open_source_repo_url ? ( - + Repository/notices - + ) : null} {includeProtectedLaunchStatusLink ? ( - + Protected launch status - + ) : null} {includeProtectedNoticesLink ? ( - + Protected notices - + ) : null} {includePublicNoticesLink ? ( - + Public notices - + ) : null}
) @@ -482,22 +483,22 @@ function ProtectedLaunchReadinessPanel({ {description ?

{description}

: null}

- {launchStatus.ready ? 'Launch-ready posture' : 'Preview posture'} + {launchStatus.ready ? 'Launch-ready status' : 'Early-access status'}

    {launchStatus.checklist.map((item) => (
  • {item.label}: {item.configured ? (item.id === 'public-auth-runtime' ? 'production-ready' : 'configured') - : (item.id === 'public-auth-runtime' ? 'local-or-mixed' : 'missing')} + : (item.id === 'public-auth-runtime' ? 'local-or-mixed' : 'pending')}
  • ))} -
  • Operator checkout target: {launchStatus.targets.operatorCheckoutTarget || 'support fallback active'}
  • -
  • Studio checkout target: {launchStatus.targets.studioCheckoutTarget || 'support fallback active'}
  • +
  • Operator checkout target: {launchStatus.targets.operatorCheckoutTarget || 'support follow-up active'}
  • +
  • Studio checkout target: {launchStatus.targets.studioCheckoutTarget || 'support follow-up active'}
{liveBlockerDetails.length > 0 ? (
-

{launchStatus.ready ? 'Live runtime notes' : 'Current preview blockers from the live auth runtime'}

+

{launchStatus.ready ? 'Live runtime notes' : 'Current early-access blockers from the live auth runtime'}

    {liveBlockerDetails.map((item) => (
  • {item}
  • @@ -510,11 +511,11 @@ function ProtectedLaunchReadinessPanel({ ) : null} {releaseManifestQuery.isError ? ( 0 ? (
    {actions.map((action) => ( - + {action.label} - + ))}
    ) : null} @@ -617,7 +618,7 @@ function buildProtectedReleaseActionSurface({ if (releaseAuthorityUnavailable) { if (releaseManifest.viewer.canDownload) { return { - badge: 'Fallback release posture', + badge: 'Release recovery mode', tone: 'info', title: 'Live release authority must recover before package delivery resumes.', summary: @@ -625,7 +626,7 @@ function buildProtectedReleaseActionSurface({ items: [ `Manifest viewer plan: ${manifestPlan}`, `Manifest viewer access: ${manifestAccessStatus}`, - `Protected target posture: ${requestedTarget ? describeReleaseTarget(requestedTarget) : 'Windows default'}`, + `Protected target: ${requestedTarget ? describeReleaseTarget(requestedTarget) : 'Windows default'}`, `Configured release targets: ${configuredTargetsLabel}`, `Support contact: ${supportEmail}`, ], @@ -641,7 +642,7 @@ function buildProtectedReleaseActionSurface({ return { badge: 'Release authority degraded', tone: 'info', - title: 'Wait for live release authority before trusting upgrade or delivery posture.', + title: 'Wait for live release authority before trusting upgrade or delivery status.', summary: 'This protected lane is still useful for orientation, but checkout, entitlement, and package-delivery decisions should wait until the auth server is back.', items: [ @@ -671,7 +672,7 @@ function buildProtectedReleaseActionSurface({ ? `${requestedTarget.platform} is not published yet, but another entitled package is ready.` : `${primaryActionTarget.platform} package is ready for this account.`, summary: requestedTarget && requestedTarget.configured === false - ? `Your requested ${requestedTarget.platform} lane is not configured yet, but the protected release lane can still deliver ${describeReleaseTarget(primaryDownloadTarget)} right now.` + ? `Your requested ${requestedTarget.platform} lane is not published yet, but the protected release lane can still deliver ${describeReleaseTarget(primaryDownloadTarget)} right now.` : 'The protected release lane now has both live entitlement and a current package target, so download and release references can stay attached to the same operator workflow.', items: [ `Manifest viewer plan: ${manifestPlan}`, @@ -695,7 +696,7 @@ function buildProtectedReleaseActionSurface({ tone: 'info', title: 'Desktop access is visible, but no packaged target is published yet.', summary: - 'This protected lane can still show account and release posture, but it cannot deliver a desktop package until at least one target is configured.', + 'This protected lane can still show account and release status, but it cannot deliver a desktop package until at least one target is published.', items: [ `Manifest viewer plan: ${manifestPlan}`, `Manifest viewer access: ${manifestAccessStatus}`, @@ -717,8 +718,8 @@ function buildProtectedReleaseActionSurface({ `Manifest viewer plan: ${manifestPlan}`, `Manifest viewer access: ${manifestAccessStatus}`, `Configured release targets: ${configuredTargetsLabel}`, - `Operator checkout target: ${releaseManifest.commerce?.operator_checkout_url ? 'configured' : 'missing'}`, - `Studio checkout target: ${releaseManifest.commerce?.studio_checkout_url ? 'configured' : 'missing'}`, + `Operator checkout target: ${releaseManifest.commerce?.operator_checkout_url ? 'available' : 'support follow-up'}`, + `Studio checkout target: ${releaseManifest.commerce?.studio_checkout_url ? 'available' : 'support follow-up'}`, ] if (checkoutActions.length > 0) { @@ -727,7 +728,7 @@ function buildProtectedReleaseActionSurface({ tone: 'info', title: 'Desktop package delivery still requires billing or operator provisioning.', summary: - 'The protected release lane can show live release posture now, but it still keeps actual package delivery behind the current checkout and entitlement rules.', + 'The protected release lane can show live release status now, but it still keeps actual package delivery behind the current checkout and entitlement rules.', items: [ ...statusItems, `Support contact: ${supportEmail}`, @@ -743,9 +744,9 @@ function buildProtectedReleaseActionSurface({ return { badge: 'Checkout not live yet', tone: 'info', - title: 'Protected release posture is ready, but live checkout is not configured.', + title: 'Protected release status is ready, but live checkout is not available yet.', summary: - 'This deployment can show the signed-in release lane, yet commercial access still depends on manual operator help because live checkout targets are not configured.', + 'This deployment can show the signed-in release lane, yet commercial access still depends on operator help because live checkout targets are not available.', items: [ ...statusItems, `Support contact: ${supportEmail}`, @@ -762,7 +763,7 @@ function buildProtectedReleaseActionSurface({ return { badge: 'Release lane ready for review', tone: 'info', - title: 'Protected release posture is available for operator follow-through.', + title: 'Protected release status is available for operator follow-through.', summary: 'The protected lane is carrying live release metadata, packaged proof, and sign-in continuity even though a direct package action is not available from this exact state.', items: [ @@ -809,14 +810,14 @@ function ProtectedReleaseAuthorityNotice({ title: 'What stays intentionally withheld', items: [ 'Direct package delivery remains intentionally withheld until the auth server returns.', - 'Live server-backed release authority is not claimed while this protected lane is in fallback posture.', + 'Live server-backed release authority is not claimed while this protected lane is in recovery mode.', ], }, { title: 'Recommended recovery order', items: [ 'Wait for the auth server to recover, then refresh this protected lane before treating release metadata as live authority.', - 'Use operator support if fallback posture persists while rollout or entitlement work is blocked.', + 'Use operator support if recovery mode persists while rollout or entitlement work is blocked.', ], }, ]} @@ -899,9 +900,9 @@ function ProtectedSupportTopicPanel({
{topic.actions.map((action) => ( - + {action.label} - + ))}
@@ -1018,15 +1019,15 @@ function OperatorDesktopQuickstartPanel({ ))}
- + Open downloads - - + + Open browser access - - + + Open public manual - +
) @@ -1062,15 +1063,15 @@ function ProtectedSoftwareWorkflowPanel({ ))}
- + Open downloads - - + + Open browser access - - + + Open public manual - +
) @@ -1107,12 +1108,12 @@ function SupportEscalationChecklist({ ))}
- + Open support - - + + {secondaryLink.label} - +
) @@ -1142,9 +1143,9 @@ function ProtectedOperatorQuickRoutesPanel({
{topic.actions.map((action) => ( - + {action.label} - + ))}
@@ -1243,9 +1244,9 @@ function ProtectedBrowserDesktopRealityPanel({ ))}
- + {action.label} - +
) @@ -1295,7 +1296,7 @@ export function DashboardOverviewPage() { <> @@ -1308,7 +1309,7 @@ export function DashboardOverviewPage() {

Desktop downloads: {user?.canDownload ? 'enabled' : 'not yet entitled'}

{!superTokensConfigured || user?.billing?.source === 'local-fallback' ? (

- This session is currently using local fallback posture, not fully shared production auth. + This session is currently using local recovery mode, not fully shared production auth.

) : null} {releaseManifestQuery.data?.manifest && releaseAuthoritySyncItems.length > 0 ? ( @@ -1336,14 +1337,13 @@ export function DashboardOverviewPage() {

Generate a short-lived token so the local desktop runtime can verify your browser session without exposing account credentials.

- + {desktopLinkMutation.isError ? (

Could not generate a token. Ensure the auth server is reachable and your session is valid.

) : null} @@ -1365,7 +1365,7 @@ export function DashboardOverviewPage() { @@ -1407,7 +1407,7 @@ export function DashboardOverviewPage() {

The protected dashboard is only one surface in the product. This shared map keeps account, - embedded-browser, desktop-runtime, and frozen-branch truth visible without forcing operators to reconstruct topology from separate pages. + embedded-browser, desktop-runtime, and future-branch truth visible without forcing operators to reconstruct topology from separate pages.

@@ -1472,7 +1472,7 @@ export function ProtectedLaunchStatusPage() { <> @@ -1524,7 +1524,7 @@ export function ProtectedLaunchStatusPage() { @@ -1572,19 +1572,19 @@ export function DownloadCenterPage() {
{releaseManifestQuery.isLoading ? ( -

Loading the current server-backed release manifest. Local fallback metadata remains visible until the live manifest arrives.

+

Loading the current server-backed release manifest. Local recovery metadata remains visible until the live manifest arrives.

) : null} {releaseManifestQuery.isError ? ( -

Fallback release posture

+

Release recovery mode

Your signed-in account still resolves to desktop access, but live release authority is temporarily unavailable. Direct package delivery remains intentionally withheld until the auth server returns. @@ -1651,9 +1651,9 @@ export function DownloadCenterPage() { ) : null} {target.download_url && viewerCanDownload ? ( - + Download {target.platform} - + ) : (

{getProtectedDownloadActionLabel({ @@ -1748,23 +1748,23 @@ export function BrowserAccessPage() { <>
- +
    -
  • The embedded browser/CEF shell is live and owned as part of the current shipping posture.
  • +
  • The embedded browser/CEF shell is live and owned as part of the current shipping model.
  • Browser runtime status, runtime-ready typing, and native operator diagnostics are already surfaced in the desktop runtime.
  • The public browser dashboard is for operator/account/release access, not a claim of full simulator parity.
- {healthQuery.isLoading ?

Checking current browser-shell auth posture...

: null} + {healthQuery.isLoading ?

Checking current browser-shell auth state...

: null} {healthQuery.isError ? (
- + Open dashboard - - + + Open downloads - +
{releaseManifestQuery.isError ? (
  • The optional full-browser client remains spec-only.
  • -
  • MagicTile native renderer widening remains explicit No-Go until a real browser-host gap is proven.
  • +
  • MagicTile native renderer widening remains closed unless a real browser-host gap is proven.
  • This dashboard intentionally stays above those boundaries instead of silently crossing them.
    @@ -1905,7 +1905,7 @@ export function AccountPage() { <> @@ -1942,14 +1942,14 @@ export function AccountPage() { healthQuery={healthQuery} /> - {releaseManifestQuery.isLoading ?

    Refreshing release-access posture from the live manifest...

    : null} + {releaseManifestQuery.isLoading ?

    Refreshing release-access status from the live manifest...

    : null} {releaseManifestQuery.isError ? ( @@ -2006,18 +2006,18 @@ export function AccountPage() { Use the dashboard when you need a desktop-link token, the download center when you need an entitled package, and the notices lane when you need distribution/legal references.

    - + Open dashboard - - + + Open downloads - - + + Review notices - - + + Get help - +
    @@ -2053,23 +2053,23 @@ export function NoticesPage() { <>
    - +

    Pricing, checkout, and download surfaces must expose open-source notices and corresponding-source guidance whenever shipped builds contain MPL-covered material.

    - {releaseManifestQuery.isLoading ?

    Refreshing notices posture from the live release manifest...

    : null} + {releaseManifestQuery.isLoading ?

    Refreshing notices status from the live release manifest...

    : null} {releaseManifestQuery.isError ? (
  • Configured release targets: {configuredPlatforms.length}/{releaseManifest.platforms.length}
  • Viewer download access: {releaseManifest.viewer.canDownload ? 'enabled' : 'not yet enabled'}
  • -
  • Public repository/notices URL: {releaseManifest.open_source_repo_url || 'configure the public repository/notices URL before launch'}
  • -
  • Corresponding-source URL: {releaseManifest.corresponding_source_url || 'configure the corresponding-source URL before public launch'}
  • +
  • Public repository/notices URL: {releaseManifest.open_source_repo_url || 'add the public repository/notices URL before wider launch'}
  • +
  • Corresponding-source URL: {releaseManifest.corresponding_source_url || 'add the corresponding-source URL before wider launch'}
  • Keep pricing, download, and notices surfaces aligned whenever a public downloadable build is offered.
  • -
  • Keep release notes and package proof reachable so public audiences can see what build posture is actually being distributed.
  • +
  • Keep release notes and package proof reachable so public audiences can see what build state is actually being distributed.
  • Do not present browser access as simulator parity just because distribution/legal pages are live.
{releaseManifest.platforms.length > 0 ? (
    {releaseManifest.platforms.map((platform) => (
  • - {platform.platform}: {platform.configured ? 'configured' : 'not configured'}{platform.validation_summary ? `, validation ${platform.validation_summary.result}` : ''} + {platform.platform}: {platform.configured ? 'published' : 'pending publication'}{platform.validation_summary ? `, validation ${platform.validation_summary.result}` : ''}
  • ))}
@@ -2108,7 +2108,7 @@ export function NoticesPage() { diff --git a/website/src/pages/auth-pages.tsx b/website/src/pages/auth-pages.tsx index 1cfb32a..1f4a87e 100644 --- a/website/src/pages/auth-pages.tsx +++ b/website/src/pages/auth-pages.tsx @@ -1,7 +1,9 @@ import { useEffect, useState } from 'react' import { Link, useNavigate, useSearchParams } from 'react-router-dom' +import { Eye, EyeOff } from 'lucide-react' import { usePlatformAuth } from '../auth/platform-auth' import { normalizeNextPath } from '../auth/next-path' +import { PASSWORD_POLICY_HINT, PASSWORD_POLICY_PLACEHOLDER } from '../auth/password-policy' import { getSuperTokensAuthRuntimeValidation, isGitHubOAuthEnabled, @@ -10,6 +12,7 @@ import { } from '../auth/supertokens-runtime' import { SiteMetadata } from '../components/seo/SiteMetadata' import { compactProductRealityStrip } from '../components/layout/MarketingShell' +import { HyperTwistButton } from '../components/ui/HyperTwistButton' import { OperationalStatusCallout } from '../components/ui/OperationalStatusCallout' import { browserDesktopRealityCards, deliverySurfaceCards, desktopWorkflowTracks, operatorManualTracks } from '../site-data' import { buildSupportPath, getDownloadPlatformLabel, normalizeDownloadPlatform } from '../site-routes' @@ -65,7 +68,7 @@ function resolveAuthNextStep(nextPath: string): AuthNextStepDescriptor { bullets: [ `Review the current ${platformLabel} target, package proof, and release notes before download.`, 'Use the protected dashboard afterward if you need a desktop-link token for first launch.', - 'Return to protected or public notices if rollout or compliance posture changes.', + 'Return to protected or public notices if rollout or compliance status changes.', ], } } @@ -74,11 +77,11 @@ function resolveAuthNextStep(nextPath: string): AuthNextStepDescriptor { return { title: 'Protected account lane', description: - 'After sign-in you will continue to the protected account surface so session state, plan posture, and browser-to-desktop access continuity can be confirmed before any download or rollout step.', + 'After sign-in you will continue to the protected account surface so session state, plan status, and browser-to-desktop access continuity can be confirmed before any download or rollout step.', bullets: [ 'Confirm your plan, role, and current release access first.', 'Use the protected download center once desktop entitlement is resolved.', - 'Use the dashboard and notices lanes if account or release posture changes later.', + 'Use the dashboard and notices lanes if account or release status changes later.', ], } } @@ -87,11 +90,11 @@ function resolveAuthNextStep(nextPath: string): AuthNextStepDescriptor { return { title: 'Protected notices lane', description: - 'After sign-in you will continue to the protected notices surface so distribution references, corresponding-source posture, and release-target notice truth remain attached to the signed-in operator lane.', + 'After sign-in you will continue to the protected notices surface so distribution references, corresponding-source status, and release-target notice truth remain attached to the signed-in operator lane.', bullets: [ 'Review notices before redistributing any covered downloadable build.', 'Use the protected download center when you need the entitled package itself.', - 'Keep browser access, native package proof, and legal posture synchronized.', + 'Keep browser access, native package proof, and legal follow-through synchronized.', ], } } @@ -99,9 +102,9 @@ function resolveAuthNextStep(nextPath: string): AuthNextStepDescriptor { return { title: 'Protected operator dashboard', description: - 'After sign-in you will continue to the protected operator dashboard so browser auth, billing, release posture, and desktop-link pairing are resolved before the native simulator lane takes over.', + 'After sign-in you will continue to the protected operator dashboard so browser auth, billing, release status, and desktop-link pairing are resolved before the native simulator lane takes over.', bullets: [ - 'Confirm account, plan, and release readiness posture first.', + 'Confirm account, plan, and release readiness first.', 'Open the protected download center when you need the entitled desktop build.', 'Generate a desktop-link token there or from the dashboard before first native launch.', ], @@ -173,7 +176,7 @@ function AuthWorkflowPreview() {

What the desktop runtime is for once you are signed in

- Browser access resolves account, release, and pairing posture. The actual simulator work still happens in the desktop runtime afterward. + Browser access resolves account, release, and pairing. The actual simulator work still happens in the desktop runtime afterward.

{desktopWorkflowTracks.slice(0, 2).map((track) => ( @@ -198,7 +201,7 @@ function AuthBrowserDesktopRealityPanel() {

Browser account access does not replace the simulator.

Sign-in exists so protected release, entitlement, pairing, and account work can stay in the browser. - The real simulator still lives in the desktop runtime, and unfinished XR/controller widening still stays explicit. + The real simulator still lives in the desktop runtime, and headset/controller validation stays explicit.

{browserDesktopRealityCards.map((card) => ( @@ -225,29 +228,29 @@ function AuthRuntimeNotice() { } const diagnostics = [ - ...authRuntimeValidation.missing.map((item) => `Missing auth env: ${item}`), + ...authRuntimeValidation.missing.map((item) => `Auth runtime setting pending: ${item}`), ...authRuntimeValidation.warnings, ] return ( ) @@ -285,6 +288,7 @@ export function LoginPage() { const [password, setPassword] = useState('') const [error, setError] = useState('') const [isSubmitting, setIsSubmitting] = useState(false) + const [showPassword, setShowPassword] = useState(false) const [oauthLoading, setOauthLoading] = useState<'google' | 'github' | 'orcid' | null>(null) useEffect(() => { @@ -340,29 +344,55 @@ export function LoginPage() {
- setEmail(event.target.value)} /> + setEmail(event.target.value)} + /> - setPassword(event.target.value)} /> +
+ setPassword(event.target.value)} + /> + +
{error ?

{error}

: null} - +
{isGoogleOAuthEnabled() ? ( - + ) : null} {isGitHubOAuthEnabled() ? ( - + ) : null} {isOrcidOAuthEnabled() ? ( - + ) : null}
@@ -382,6 +412,7 @@ export function RegisterPage() { const [name, setName] = useState('') const [error, setError] = useState('') const [isSubmitting, setIsSubmitting] = useState(false) + const [showPassword, setShowPassword] = useState(false) const [oauthLoading, setOauthLoading] = useState<'google' | 'github' | 'orcid' | null>(null) useEffect(() => { @@ -424,44 +455,80 @@ export function RegisterPage() { <> Already have access? Log in.

} >
- setName(event.target.value)} /> + setName(event.target.value)} + /> - setEmail(event.target.value)} /> + setEmail(event.target.value)} + /> - setPassword(event.target.value)} /> +
+ setPassword(event.target.value)} + /> + +
+

{PASSWORD_POLICY_HINT}

{error ?

{error}

: null} - +
{isGoogleOAuthEnabled() ? ( - + ) : null} {isGitHubOAuthEnabled() ? ( - + ) : null} {isOrcidOAuthEnabled() ? ( - + ) : null}
diff --git a/website/src/pages/public-page-helpers.tsx b/website/src/pages/public-page-helpers.tsx index 7ebee71..7dc029b 100644 --- a/website/src/pages/public-page-helpers.tsx +++ b/website/src/pages/public-page-helpers.tsx @@ -4,6 +4,7 @@ import { useQuery } from '@tanstack/react-query' import { Link } from 'react-router-dom' import { getReleaseManifest } from '../auth/auth-api' import { BrowserAuthMethodsGuide } from '../components/ui/BrowserAuthMethodsGuide' +import { HyperTwistButtonAnchor, HyperTwistButtonLink } from '../components/ui/HyperTwistButton' import { ReleaseValidationSummary } from '../components/ui/ReleaseValidationSummary' import type { ReleaseManifestPlatformView, ReleaseManifestView } from '../release-manifest' import { resolveReleaseCommerceView, resolveReleaseManifestView } from '../release-manifest' @@ -51,14 +52,14 @@ export const supportTopicGuidance: Record = { 'launch-readiness': { title: 'Launch readiness', description: - 'Need help turning the preview lane into a public launch? We can walk through checkout wiring, download release targets, notices, and corresponding-source publication.', + 'Need help turning early access into a public launch? We can walk through checkout wiring, download release targets, notices, and corresponding-source publication.', steps: [ - 'Confirm public launch status, operator/studio checkout posture, and support contact first.', + 'Confirm public launch status, operator/studio checkout status, and support contact first.', 'Review the current desktop target plus packaged proof before promising a release lane externally.', - 'Keep notices and corresponding-source posture live before widening rollout.', + 'Keep notices and corresponding-source status live before widening rollout.', ], routeFocus: [ - 'Launch-status, pricing, and download pages explain public launch posture and target selection.', + 'Launch-status, pricing, and download pages explain public launch status and target selection.', 'Public notices and terms pages carry the distribution and legal follow-through.', 'The public manual explains the browser-versus-desktop product split that launch copy must preserve.', ], @@ -75,12 +76,12 @@ export const supportTopicGuidance: Record = { 'Use this lane when you need operator checkout, entitlement enablement, or help reaching the protected desktop-download surface.', steps: [ 'Start with sign-in or registration, then confirm whether the issue is auth, entitlement, or desktop-link pairing.', - 'Use the protected dashboard and protected download lane once sign-in succeeds so account and release posture stay attached.', + 'Use the protected dashboard and protected download lane once sign-in succeeds so account and release status stay attached.', 'Escalate with the affected plan, requested platform, and whether access, pairing, or package delivery failed.', ], routeFocus: [ 'Login and register preserve safe next-target routing into the protected operator lanes.', - 'The public download page shows release posture without exposing raw delivery authority.', + 'The public download page shows release status without exposing raw delivery authority.', 'The public manual explains when the browser dashboard owns the next step and when the native runtime takes over.', ], actions: [ @@ -94,13 +95,13 @@ export const supportTopicGuidance: Record = { description: 'Use this lane for higher-dimensional rollout planning, deployment coordination, or production-lane package and notice readiness.', steps: [ - 'Treat packaged proof, notices, pricing, and delivery posture as one rollout packet instead of four disconnected checks.', + 'Treat packaged proof, notices, pricing, and delivery status as one rollout packet instead of four disconnected checks.', 'Keep browser/operator coordination separate from native simulator execution during deployment planning.', 'Carry higher-dimensional dedicated-family proof and the current XR/controller boundary into rollout decisions explicitly.', ], routeFocus: [ 'Release notes and the public manual explain recent browser, package, and control-boundary changes.', - 'Download and notices pages carry the current distribution posture plus legal follow-through.', + 'Download and notices pages carry the current distribution status plus legal follow-through.', 'Resources summarize higher-dimensional runtime lanes and operator playbooks for wider team review.', ], actions: [ @@ -258,9 +259,9 @@ export function BrowserDesktopRealitySection({ ))}
- + {card.action.label} - +
))} @@ -273,10 +274,10 @@ const surfaceChoiceGuideCards = [ { title: 'Stay on the public website', posture: 'Public release shell', - description: 'Use this surface when you are still evaluating HyperTwist, reading docs, checking launch posture, or reviewing pricing, notices, and rollout guidance.', + description: 'Use this surface when you are still evaluating HyperTwist, reading docs, checking access status, or reviewing pricing, notices, and rollout guidance.', bullets: [ 'Best for product discovery, public documentation, pricing, support, and legal follow-through.', - 'Keeps launch-readiness and packaged-proof posture visible without exposing protected download authority.', + 'Keeps launch-readiness and packaged proof visible without exposing protected download authority.', ], action: { to: '/docs', @@ -332,9 +333,9 @@ export function SurfaceChoiceGuideSection({ ))}
- + {card.action.label} - +
))} @@ -366,15 +367,15 @@ export function OperatorDesktopQuickstartSection({ ))}
- + Open download center - - + + Open operator dashboard - - + + Open public manual - +
) @@ -398,18 +399,18 @@ export function DownloadableOperatorManualSection({
  • Use it for desktop-side onboarding, rollout review, and operator support when the browser shell is not the best reading surface.
  • It stays aligned with the current public route atlas instead of inventing a separate product story.
  • -
  • It keeps the current desktop-hosted XR/controller `No-Go` boundary explicit instead of flattening it into generic VR support language.
  • +
  • It keeps the current headset/controller validation boundary explicit instead of flattening it into generic VR support language.
- + Download offline operator manual - - + + Open public manual - - + + Open getting started - +
@@ -451,7 +452,7 @@ export function SimulatorManualSection({ export function HigherDimensionalRuntimeGuideSection({ title = 'Higher-dimensional family guide', - description = 'These are the currently represented higher-dimensional lanes and the truthful host/runtime posture for each.', + description = 'These are the currently represented higher-dimensional lanes and the truthful host/runtime model for each.', }: { title?: string description?: string @@ -466,7 +467,7 @@ export function HigherDimensionalRuntimeGuideSection({ } export function InputAndDevicePostureSection({ - title = 'Input and device posture', + title = 'Input and device state', description = 'Public documentation should be explicit about the current control/runtime truth instead of blurring groundwork and finished VR claims together.', }: { title?: string @@ -674,9 +675,9 @@ export function SupportTopicDirectorySection({
{topic.actions.map((action) => ( - + {action.label} - + ))}
@@ -714,9 +715,9 @@ export function PublicManualRouteAtlasSection({ ))}
- + Open {card.title} - +
))} @@ -727,7 +728,7 @@ export function PublicManualRouteAtlasSection({ export function BrowserAuthMethodsSection({ title = 'Browser account access methods', - description = 'The public browser-account provider lineup should stay visible wherever operators are being asked to sign in, buy access, pair the desktop runtime, or recover access posture.', + description = 'The public browser-account provider lineup should stay visible wherever operators are being asked to sign in, buy access, pair the desktop runtime, or recover access state.', }: { title?: string description?: string @@ -756,9 +757,9 @@ export function PublicPackagedDesktopProofSection({ {actions.length > 0 ? (
{actions.map((action) => ( - + {action.label} - + ))}
) : null} @@ -792,18 +793,18 @@ export function ReleaseAuthorityBundleSection({ 'A same-origin offline manual ships with the website so desktop-first onboarding, protected-release follow-through, and rollout review do not depend on live browsing alone.', href: downloadablePublicManualHref, configuredLabel: 'Included', - missingLabel: 'Include the downloadable operator manual before external launch', + missingLabel: 'Add the downloadable operator manual before wider launch', linkLabel: 'Download operator manual (.md)', download: true, }, { title: 'Public manual', description: - 'The public docs portal is the product-safe manual for browser-versus-desktop boundaries, rollout posture, and simulator truth.', + 'The public docs portal is the product-safe manual for browser-versus-desktop boundaries, rollout status, and simulator truth.', href: releaseManifest.public_docs_url, configuredLabel: 'Configured', - missingLabel: 'Configure public docs URL before external launch', - linkLabel: releaseManifest.public_docs_url || 'Configure public docs URL before external launch', + missingLabel: 'Add public docs URL before wider launch', + linkLabel: releaseManifest.public_docs_url || 'Add public docs URL before wider launch', }, { title: 'Release notes feed', @@ -811,8 +812,8 @@ export function ReleaseAuthorityBundleSection({ 'Release notes keep public launch pages anchored to real browser, package, control-boundary, and distribution changes.', href: releaseManifest.release_notes_url, configuredLabel: 'Configured', - missingLabel: 'Configure release notes URL before external launch', - linkLabel: releaseManifest.release_notes_url || 'Configure release notes URL before external launch', + missingLabel: 'Add release notes URL before wider launch', + linkLabel: releaseManifest.release_notes_url || 'Add release notes URL before wider launch', }, { title: 'Corresponding source', @@ -820,9 +821,9 @@ export function ReleaseAuthorityBundleSection({ 'Any MPL-covered shipped build needs a stable corresponding-source location for the exact distributed material.', href: releaseManifest.corresponding_source_url, configuredLabel: 'Configured', - missingLabel: 'Configure corresponding-source URL before external launch', + missingLabel: 'Add corresponding-source URL before wider launch', linkLabel: - releaseManifest.corresponding_source_url || 'Configure corresponding-source URL before external launch', + releaseManifest.corresponding_source_url || 'Add corresponding-source URL before wider launch', }, { title: 'Open-source repo and notices reference', @@ -830,8 +831,8 @@ export function ReleaseAuthorityBundleSection({ 'The public repository and notices reference keeps release, legal, and redistribution follow-through visible outside the simulator.', href: releaseManifest.open_source_repo_url, configuredLabel: 'Configured', - missingLabel: 'Configure public repo/notices URL before external launch', - linkLabel: releaseManifest.open_source_repo_url || 'Configure public repo/notices URL before external launch', + missingLabel: 'Add public repo/notices URL before wider launch', + linkLabel: releaseManifest.open_source_repo_url || 'Add public repo/notices URL before wider launch', }, { title: 'Operator support contact', @@ -839,8 +840,8 @@ export function ReleaseAuthorityBundleSection({ 'Support contact belongs in the same bundle so release, entitlement, notice, and rollout questions do not force operators to improvise escalation paths.', href: releaseManifest.support_email ? `mailto:${releaseManifest.support_email}` : null, configuredLabel: 'Ready', - missingLabel: 'Configure support email before external launch', - linkLabel: releaseManifest.support_email || 'Configure support email before external launch', + missingLabel: 'Add support email before wider launch', + linkLabel: releaseManifest.support_email || 'Add support email before wider launch', }, ] as const @@ -949,7 +950,7 @@ function buildPublicReleaseDecisionCards(releaseManifest: ReleaseManifestView): badge: 'Package publication pending', title: 'Need the protected desktop-download lane?', summary: - 'The public site can still show release posture, but no published desktop target is configured yet, so the next move is protected follow-through and launch-readiness support rather than direct package delivery.', + 'The public site can still explain the release lane, but direct package delivery belongs in protected follow-through until a published desktop target is active.', bullets: [ `Configured release targets: ${configuredTargets.length}/${releaseManifest.platforms.length}`, `Primary default lane: ${primaryTarget ? primaryTarget.platform : 'Windows desktop lane pending publication'}`, @@ -982,7 +983,7 @@ function buildPublicReleaseDecisionCards(releaseManifest: ReleaseManifestView): badge: 'Manual provisioning route', title: 'Need plan selection, billing, or operator provisioning?', summary: - 'Pricing can still explain the real delivery model, but manual operator help remains the truthful path because live checkout targets are not configured yet.', + 'Pricing can still explain the real delivery model, while account or support follow-through remains the truthful path until live checkout targets are active.', bullets: [ `Operator checkout: ${releaseCommerce.operator_checkout_url ? 'configured' : 'manual help required'}`, `Studio checkout: ${releaseCommerce.studio_checkout_url ? 'configured' : 'manual help required'}`, @@ -998,7 +999,7 @@ function buildPublicReleaseDecisionCards(releaseManifest: ReleaseManifestView): badge: 'Protected browser shell', title: 'Need account state, pairing, or protected browser follow-through?', summary: - 'The web lane is not superfluous: it owns identity, entitlement, billing posture, protected notices, and browser-to-desktop pairing while the native runtime keeps simulator authority.', + 'The web lane is not superfluous: it owns identity, entitlement, billing status, protected notices, and browser-to-desktop pairing while the native runtime keeps simulator authority.', bullets: [ 'Use the protected dashboard for account state, auth/runtime truth, and release-manifest follow-through.', 'Use the protected browser-access lane when you need account-aware browser continuity rather than simulator execution.', @@ -1017,7 +1018,7 @@ function buildPublicReleaseDecisionCards(releaseManifest: ReleaseManifestView): 'Public notices and release references stay on the website first, while the protected notices lane remains the signed-in follow-through surface when account context matters.', bullets: [ `Configured public release references: ${configuredReferenceCount}/5`, - 'Keep notices, release notes, and corresponding-source posture visible anywhere downloadable distribution is discussed.', + 'Keep notices, release notes, and corresponding-source status visible anywhere downloadable distribution is discussed.', `Support contact: ${supportEmail}`, ], actions: [ @@ -1033,7 +1034,7 @@ function buildPublicReleaseDecisionCards(releaseManifest: ReleaseManifestView): function SurfaceActionLink({ to, label, - className = 'button button--ghost', + className, }: { to: string label: string @@ -1041,16 +1042,16 @@ function SurfaceActionLink({ }) { if (isExternalHref(to)) { return ( - + {label} - + ) } return ( - + {label} - + ) } @@ -1093,15 +1094,15 @@ export function PublicReleaseDecisionGuideSection({ export function PlanActionLink({ href, label }: { href: string; label: string }) { if (isExternalHref(href)) { return ( - + {label} - + ) } return ( - + {label} - + ) } diff --git a/website/src/pages/public-pages-commerce.tsx b/website/src/pages/public-pages-commerce.tsx index dce17e8..b7bdc98 100644 --- a/website/src/pages/public-pages-commerce.tsx +++ b/website/src/pages/public-pages-commerce.tsx @@ -2,6 +2,7 @@ import { useMemo } from 'react' import { Link } from 'react-router-dom' import { MarketingShell } from '../components/layout/MarketingShell' import { SiteMetadata } from '../components/seo/SiteMetadata' +import { HyperTwistButtonLink } from '../components/ui/HyperTwistButton' import { OperationalStatusCallout } from '../components/ui/OperationalStatusCallout' import { ProductSurfaceMatrix } from '../components/ui/ProductSurfaceMatrix' import { PublicLaunchStatus } from '../components/ui/PublicLaunchStatus' @@ -79,7 +80,7 @@ export function PricingPage() { <> -
+
@@ -156,7 +157,7 @@ export function PricingPage() { @@ -171,14 +172,14 @@ export function PricingPage() {
@@ -195,15 +196,15 @@ export function PricingPage() { keep their legal footer and open-source notices link live and ensure the corresponding-source URL is configured for any downloadable build containing MPL-covered material.

- + Open browser guide - - + + Open help center - - + + Contact HyperTwist - +
@@ -224,7 +225,7 @@ function ReleaseManifestStatusSections({ {isLoading ? (
-

Loading the current server-backed release manifest. Static preview metadata remains visible until the live manifest arrives.

+

Loading the current server-backed release manifest. Static target guidance remains visible until live release authority arrives.

) : null} @@ -232,9 +233,9 @@ function ReleaseManifestStatusSections({ {isError ? (
@@ -291,12 +292,12 @@ function AvailableTargetsSection({ platforms }: { platforms: readonly ReleaseMan ) : null} {platform.configured ? ( - + Sign in for {platform.platform} access - + ) : (
- Release URL not configured yet + Release access opens after account approval
)} @@ -320,7 +321,7 @@ export function DownloadPage() { - + -
+
@@ -434,7 +435,7 @@ export function DownloadPage() { @@ -451,20 +452,20 @@ export function DownloadPage() {

HyperTwist treats desktop distribution as an account-gated release surface. - Public pages can describe supported targets and release posture, but the actual + Public pages can describe supported targets and release status, but the actual download links live behind the protected dashboard where plan and entitlement state are resolved.

- + Open protected download lane - +
@@ -472,11 +473,11 @@ export function DownloadPage() {

After sign-in, open the operator dashboard to generate a desktop-link token. - That token is designed to hand browser identity and plan posture over to the local desktop app without exposing your password. + That token is designed to hand browser identity and plan status over to the local desktop app without exposing your password.

- + Open protected dashboard - +
@@ -632,15 +633,15 @@ export function OpenSourceNoticesPage() {

- Contact {brandConfig.contact.email} when the next question is redistribution, corresponding-source follow-through, or release-surface notice posture rather than simulator behavior. + Contact {brandConfig.contact.email} when the next question is redistribution, corresponding-source follow-through, or release-surface notices rather than simulator behavior.

- + Open launch support - - + + Open contact route - +
@@ -656,12 +657,12 @@ export function PrivacyPage() { <>
@@ -693,11 +694,11 @@ export function PrivacyPage() {
- +
{brandConfig.contact.email} and include whether the concern is public, protected, or native-runtime context.

- + Open help center - - + + Open contact route - +
@@ -781,7 +782,7 @@ export function TermsPage() { title="Terms of access" lede="HyperTwist access is digital-first and plan-gated. Terms should match the actual delivery and account model." > -
+
  • Browser access covers public pages, account, release, download, and operator/dashboard surfaces.
  • @@ -826,7 +827,7 @@ export function TermsPage() {
    @@ -868,12 +869,12 @@ export function TermsPage() { Terms questions that affect billing, protected release access, or redistribution should go to {brandConfig.contact.email} with the exact public or protected route and the current build or release context.

    - + Open rollout support - - + + Open contact route - +
@@ -889,7 +890,7 @@ export function ShippingPaymentPage() { <>
{digitalDeliveryCards.map((card) => ( @@ -946,11 +947,11 @@ export function ShippingPaymentPage() {
- +
@@ -986,7 +987,7 @@ export function ShippingPaymentPage() {

- Write to {brandConfig.contact.email} for operator provisioning, studio rollout, payment posture, or release-surface billing questions. + Write to {brandConfig.contact.email} for operator provisioning, studio rollout, payment, or release-surface billing questions.

- + Reopen pricing - - + + Open help center - - + + Open contact route - +
diff --git a/website/src/pages/public-pages-features.tsx b/website/src/pages/public-pages-features.tsx index ea42bf4..d1e829e 100644 --- a/website/src/pages/public-pages-features.tsx +++ b/website/src/pages/public-pages-features.tsx @@ -1,6 +1,6 @@ -import { Link } from 'react-router-dom' import { MarketingShell } from '../components/layout/MarketingShell' import { SiteMetadata } from '../components/seo/SiteMetadata' +import { HyperTwistButtonLink } from '../components/ui/HyperTwistButton' import { PublicLaunchStatus } from '../components/ui/PublicLaunchStatus' import { ProductSurfaceMatrix } from '../components/ui/ProductSurfaceMatrix' import { @@ -36,17 +36,17 @@ export function FeaturesPage() { <> @@ -64,7 +64,7 @@ export function FeaturesPage() {
@@ -79,12 +79,12 @@ export function FeaturesPage() { @@ -95,7 +95,7 @@ export function FeaturesPage() {
{releaseStoryCards.map((card) => ( @@ -134,10 +134,10 @@ export function FeaturesPage() {
- +
- + Open public manual - - + + Open resources - - + + Open download center - +
diff --git a/website/src/pages/public-pages-guides.tsx b/website/src/pages/public-pages-guides.tsx index 13cacf7..e5f7ab5 100644 --- a/website/src/pages/public-pages-guides.tsx +++ b/website/src/pages/public-pages-guides.tsx @@ -2,6 +2,7 @@ import { Globe, Headset, LifeBuoy, Mail, MonitorSmartphone, ShieldCheck } from ' import { Link } from 'react-router-dom' import { MarketingShell } from '../components/layout/MarketingShell' import { SiteMetadata } from '../components/seo/SiteMetadata' +import { HyperTwistButtonAnchor, HyperTwistButtonLink } from '../components/ui/HyperTwistButton' import { brandConfig } from '../site-config' import { browserLimitCards, @@ -47,7 +48,7 @@ export function BrowserExperiencePage() {

The browser is the public and protected operator shell

-

Use it for docs, pricing, release posture, account access, notices, and browser-to-desktop pairing.

+

Use it for docs, pricing, release status, account access, notices, and browser-to-desktop pairing.

@@ -67,19 +68,19 @@ export function BrowserExperiencePage() {

The current XR boundary is still explicit

-

The browser does not hide the fact that finished OpenXR/controller completion still remains a separate native packet.

+

The browser does not hide the fact that full headset/controller validation remains a separate native device packet.

- + Open desktop download - - + + Open protected dashboard - - + + Open help center - +
@@ -111,7 +112,7 @@ export function BrowserExperiencePage() { />

Email {brandConfig.contact.email} with the route, - platform, plan posture, and whether the question is public, protected, or native runtime work. + platform, plan or account state, and whether the question is public, protected, or native runtime work.

The clearer the surface ownership is up front, the faster HyperTwist can separate account, package, runtime, and rollout questions.

- + Email HyperTwist - - + + Open support routes - +
@@ -324,12 +325,12 @@ export function ContactPage() {
-

Release posture stays visible

+

Release status stays visible

Use current launch status and packaged proof before reporting a rollout or release concern.

diff --git a/website/src/pages/public-pages-launch.tsx b/website/src/pages/public-pages-launch.tsx index 00d80d7..eb8a625 100644 --- a/website/src/pages/public-pages-launch.tsx +++ b/website/src/pages/public-pages-launch.tsx @@ -21,31 +21,31 @@ export function LaunchStatusPage() { return ( <>
- +
@@ -58,15 +58,15 @@ export function LaunchStatusPage() { /> @@ -76,11 +76,11 @@ export function LaunchStatusPage() { description="Launch readiness is only trustworthy when docs, release notes, corresponding source, public notices, and operator contact remain visible as one release bundle." /> - +
diff --git a/website/src/pages/public-pages-marketing.tsx b/website/src/pages/public-pages-marketing.tsx index 5322f77..1da2241 100644 --- a/website/src/pages/public-pages-marketing.tsx +++ b/website/src/pages/public-pages-marketing.tsx @@ -3,6 +3,7 @@ import { ArrowRight, BookOpenText, Boxes, Download, ExternalLink, Landmark, Moni import { Link, useSearchParams } from 'react-router-dom' import { MarketingShell } from '../components/layout/MarketingShell' import { SiteMetadata } from '../components/seo/SiteMetadata' +import { HyperTwistButtonAnchor, HyperTwistButtonLink } from '../components/ui/HyperTwistButton' import { PublicLaunchStatus } from '../components/ui/PublicLaunchStatus' import { ProductSurfaceMatrix } from '../components/ui/ProductSurfaceMatrix' import { brandConfig } from '../site-config' @@ -75,22 +76,22 @@ function HomeHeroPanel() { HyperTwist is a native training environment for classic cube practice, recognition and correction closure, replay explanation, coaching, higher-dimensional puzzle families, and serious packaged study sessions. The web lane is intentionally narrower: - it owns access, documentation, release posture, support, and pairing so the + it owns access, documentation, release status, support, and pairing so the downloadable can stay focused on the simulator itself.

- + Download desktop app - - + + Why keep the web version? - - + + Open help center - - + + Open operator dashboard - +
@@ -105,7 +106,7 @@ function HomeHeroPanel() {
  • Use the web for pricing, docs, release notes, notices, and protected downloads.
  • Use the downloadable for real cube-state workflows, higher-dimensional maps, and diagnostics.
  • -
  • Read XR/controller widening honestly as a separate native completion packet, not as a finished browser or desktop claim today.
  • +
  • Read headset and controller support as a native device-validation track, not as a browser feature claim.
@@ -160,8 +161,8 @@ function HomeCapabilityPillarsSection() { function HomeRoadmapHonestySection() { return (
{roadmapHonestyCards.map((item) => ( @@ -184,7 +185,7 @@ function HomeDeliverySurfacesSection() {

Browser account and operator shell

-

Authenticated browser access for release posture, desktop pairing, notices, and operator state.

+

Authenticated browser access for release status, desktop pairing, notices, and operator state.

Open dashboard @@ -192,7 +193,7 @@ function HomeDeliverySurfacesSection() {

Desktop download and package lane

-

Public download posture for the native Unreal build, with legal linkage already wired in.

+

Public download guidance for the native Unreal build, with legal linkage already wired in.

Open download center @@ -299,7 +300,7 @@ function ResourcesDirectRoutesSection() {

Feature atlas

-

One public page for current capability, surface boundaries, and release posture.

+

One public page for current capability, surface boundaries, and release status.

@@ -314,7 +315,7 @@ function ResourcesDirectRoutesSection() {

Launch status

-

The canonical public checklist for preview-versus-launch posture, release authority, and rollout blockers.

+

The canonical public checklist for early access, release authority, and rollout follow-through.

@@ -334,7 +335,7 @@ function ResourcesDirectRoutesSection() {

Release notes

-

Recent public-facing packets and posture updates.

+

Recent public-facing release packets and product updates.

@@ -398,15 +399,15 @@ export function HomeLanding() {
- +
- +
@@ -529,7 +530,7 @@ export function AboutPage() {
@@ -541,8 +542,8 @@ export function AboutPage() {
-

It stays roadmap-honest

-

Shipped, retained, and spec-only surfaces remain clearly separated so public copy matches actual authority.

+

It stays product-honest

+

Shipped, retained, and future-facing surfaces remain clearly separated so public copy matches actual capability.

@@ -597,8 +598,8 @@ export function AboutPage() { />
{deploymentReadinessTracks.map((track) => ( @@ -625,10 +626,10 @@ export function AboutPage() {
- +
@@ -905,13 +906,13 @@ export function DocsPage() { <> @@ -961,7 +962,7 @@ export function DocsPage() { @@ -985,7 +986,7 @@ export function DocsPage() { @@ -1030,7 +1031,7 @@ export function DocsPage() { @@ -1061,9 +1062,9 @@ export function DocsPage() { {releaseManifest.public_docs_url ? (
- + Open public docs portal - +
) : null}
@@ -1109,10 +1110,10 @@ export function SupportPage() { ) : null}
- +
- + Open help center - - + + Open contact route - +
@@ -1172,7 +1173,7 @@ export function SupportPage() {
@@ -1210,7 +1211,7 @@ export function SupportPage() { @@ -1288,7 +1289,7 @@ export function ChangelogPage() {
{releaseRolloutChecklist.map((card) => ( @@ -1384,9 +1385,9 @@ export function ChangelogPage() { {releaseManifest.release_notes_url ? (
- + Open release feed - +
) : null} diff --git a/website/src/public-launch.ts b/website/src/public-launch.ts index 6a61263..093f147 100644 --- a/website/src/public-launch.ts +++ b/website/src/public-launch.ts @@ -94,25 +94,25 @@ export function buildLiveLaunchBlockerDetails( const details = new Set() if (!launchStatus.readiness.windowsDownloadConfigured) { - details.add('Windows release lane is not configured on the live preview deployment yet.') + details.add('Windows release delivery is still routed through signed-in account follow-up.') } if (!launchStatus.readiness.operatorCheckoutConfigured) { - details.add('Operator checkout is still on support fallback in the live preview deployment.') + details.add('Operator checkout is currently handled through account or support follow-up.') } if (!launchStatus.readiness.studioCheckoutConfigured) { - details.add('Studio checkout is still on support fallback in the live preview deployment.') + details.add('Studio checkout is currently handled through account or support follow-up.') } if (!launchStatus.readiness.publicAuthRuntimeReady) { - details.add('Shared browser-auth runtime is not yet production-ready on the live deployment.') + details.add('Shared browser-auth runtime still needs production readiness confirmation on the current deployment.') } if (!authHealth.billing.webhookSecretConfigured) { - details.add('Paddle webhook secret is not configured yet.') + details.add('Paddle webhook verification still needs to be enabled for fully automated billing updates.') } if (!authHealth.billing.productPlanMapConfigured) { - details.add('Billing product-plan map is not configured yet.') + details.add('Billing product-plan mapping still needs to be connected to the live subscription catalog.') } if (!authHealth.billing.pricePlanMapConfigured) { - details.add('Billing price-plan map is not configured yet.') + details.add('Billing price-plan mapping still needs to be connected to the live subscription catalog.') } authHealth.runtime.errors.forEach((item) => { diff --git a/website/src/public-route-registry.json b/website/src/public-route-registry.json index 0b80897..0684958 100644 --- a/website/src/public-route-registry.json +++ b/website/src/public-route-registry.json @@ -4,7 +4,7 @@ "label": "Home", "loaderTitle": "Loading HyperTwist...", "loaderEyebrow": "Public release shell", - "loaderDescription": "Loading the public product story, current launch posture, and browser-versus-desktop authority map.", + "loaderDescription": "Loading the public product story, current launch status, and browser-versus-desktop authority map.", "nav": true, "footer": false, "crawlable": true @@ -13,7 +13,7 @@ "path": "/browser", "label": "Browser", "loaderTitle": "Browser access guide", - "loaderEyebrow": "Web version posture", + "loaderEyebrow": "Web version role", "loaderDescription": "Loading the browser-versus-downloadable boundary, protected dashboard handoff, and the current web-lane purpose.", "nav": true, "footer": true, @@ -24,7 +24,7 @@ "label": "Features", "loaderTitle": "Feature atlas", "loaderEyebrow": "Capability atlas", - "loaderDescription": "Loading the shipped feature map, higher-dimensional runtime posture, and explicit desktop-first boundaries.", + "loaderDescription": "Loading the shipped feature map, higher-dimensional runtime state, and explicit desktop-first boundaries.", "nav": true, "footer": true, "crawlable": true @@ -74,7 +74,7 @@ "label": "Launch Status", "loaderTitle": "Launch status", "loaderEyebrow": "Launch authority", - "loaderDescription": "Loading the canonical public launch-readiness checklist, release posture, and preview-versus-launch authority map.", + "loaderDescription": "Loading the canonical public launch-readiness checklist, release status, and early-access authority map.", "nav": false, "footer": true, "crawlable": true @@ -124,7 +124,7 @@ "label": "Pricing", "loaderTitle": "Pricing", "loaderEyebrow": "Paddle-ready plans", - "loaderDescription": "Loading plan posture, public launch readiness, and the current desktop-first distribution model.", + "loaderDescription": "Loading plan access, public launch readiness, and the current desktop-first distribution model.", "nav": true, "footer": true, "crawlable": true @@ -134,7 +134,7 @@ "label": "Download", "loaderTitle": "Download center", "loaderEyebrow": "Desktop distribution", - "loaderDescription": "Loading the current release manifest posture, package proof, and browser-to-desktop pairing guidance.", + "loaderDescription": "Loading the current release manifest status, package proof, and browser-to-desktop pairing guidance.", "nav": true, "footer": true, "crawlable": true @@ -144,7 +144,7 @@ "label": "Open Source Notices", "loaderTitle": "Open source notices", "loaderEyebrow": "Distribution references", - "loaderDescription": "Loading notices, corresponding-source posture, and public legal follow-through for downloadable builds.", + "loaderDescription": "Loading notices, corresponding-source status, and public legal follow-through for downloadable builds.", "nav": false, "footer": true, "crawlable": true @@ -154,7 +154,7 @@ "label": "Privacy", "loaderTitle": "Privacy", "loaderEyebrow": "Public policy surface", - "loaderDescription": "Loading the browser-account privacy posture, desktop-link boundary, and distribution-safe data handling notes.", + "loaderDescription": "Loading the browser-account privacy model, desktop-link boundary, and distribution-safe data handling notes.", "nav": false, "footer": true, "crawlable": true @@ -164,7 +164,7 @@ "label": "Terms", "loaderTitle": "Terms", "loaderEyebrow": "Public policy surface", - "loaderDescription": "Loading access terms, protected download boundaries, and the current desktop-first simulator posture.", + "loaderDescription": "Loading access terms, protected download boundaries, and the current desktop-first simulator model.", "nav": false, "footer": true, "crawlable": true @@ -174,7 +174,7 @@ "label": "Shipping & Payment", "loaderTitle": "Shipping & payment", "loaderEyebrow": "Distribution policy", - "loaderDescription": "Loading the digital-delivery model, Paddle-ready billing posture, and protected release follow-through.", + "loaderDescription": "Loading the digital-delivery model, Paddle-ready billing, and protected release follow-through.", "nav": false, "footer": true, "crawlable": true diff --git a/website/src/release-manifest.ts b/website/src/release-manifest.ts index 67cf1a6..55b4e90 100644 --- a/website/src/release-manifest.ts +++ b/website/src/release-manifest.ts @@ -59,7 +59,7 @@ export function buildFallbackReleaseManifest({ subtitle: target.subtitle, details: target.details, configured: target.configured, - channel: 'preview', + channel: 'early-access', version: null, build_id: null, published_at: null, diff --git a/website/src/router/AppRouteTree.tsx b/website/src/router/AppRouteTree.tsx index 269702f..5330b51 100644 --- a/website/src/router/AppRouteTree.tsx +++ b/website/src/router/AppRouteTree.tsx @@ -17,7 +17,7 @@ const protectedAppLoaders = { title: 'Loading dashboard...', eyebrow: 'Protected operator shell', description: - 'Restoring account posture, release authority, package proof, and browser-to-desktop pairing surfaces inside the signed-in operator lane.', + 'Restoring account state, release authority, package proof, and browser-to-desktop pairing inside the signed-in operator lane.', }, downloads: { title: 'Loading downloads...', @@ -35,19 +35,19 @@ const protectedAppLoaders = { title: 'Loading browser access...', eyebrow: 'Protected browser shell', description: - 'Restoring the signed-in browser posture, release guidance, and explicit browser-versus-desktop authority boundaries.', + 'Restoring the signed-in browser state, release guidance, and explicit browser-versus-desktop boundaries.', }, account: { title: 'Loading account...', eyebrow: 'Protected account lane', description: - 'Refreshing the signed-in account view, current plan posture, and release-access continuity before desktop follow-through resumes.', + 'Refreshing the signed-in account view, current plan state, and release-access continuity before desktop follow-through resumes.', }, notices: { title: 'Loading notices...', eyebrow: 'Protected distribution references', description: - 'Restoring signed-in notices, corresponding-source posture, and download/distribution references inside the protected release shell.', + 'Restoring signed-in notices, corresponding-source references, and download/distribution guidance inside the protected release shell.', }, } as const diff --git a/website/src/shared/public-launch.ts b/website/src/shared/public-launch.ts index 3e5559b..fb04855 100644 --- a/website/src/shared/public-launch.ts +++ b/website/src/shared/public-launch.ts @@ -182,7 +182,7 @@ export function getPublicLaunchChecklist( }, { id: 'public-auth-runtime', - label: 'Public auth runtime posture', + label: 'Public auth runtime status', configured: readiness.publicAuthRuntimeReady, requiredForPublicLaunch: true, }, @@ -346,6 +346,8 @@ function resolveHealthLaunchMissingLabels( const launchMissingLabels = Array.isArray(launch.missingLabels) ? launch.missingLabels .map((label) => String(label || '').trim()) + .map((label) => label.replace(/\bpreview-tier launch gate\b/gi, 'public launch gate')) + .map((label) => label.replace(/\bpreview-tier\b/gi, 'public launch')) .filter(Boolean) : [] diff --git a/website/src/site-config.ts b/website/src/site-config.ts index 7d1c412..65dfe5d 100644 --- a/website/src/site-config.ts +++ b/website/src/site-config.ts @@ -53,13 +53,13 @@ export const planCatalog = [ key: 'explorer', name: 'Explorer', price: 'Free', - ctaLabel: 'Start in the browser', + ctaLabel: 'Create account', ctaHref: buildRegisterPath('/app'), - notes: 'Preview the browser account shell, operator dashboard, release notes, and desktop onboarding posture.', + notes: 'Create a HyperTwist account to read the operator dashboard, product manual, release notes, and desktop onboarding flow before you subscribe.', features: [ - 'Browser account access', - 'Release notes and resource center', - 'Operator dashboard preview', + 'Browser account and dashboard access', + 'Public manual, release notes, and resource center', + 'Desktop onboarding and pairing guidance', 'Open-source notices and distribution transparency', ], }, @@ -67,12 +67,12 @@ export const planCatalog = [ key: 'operator', name: 'Operator', price: readTrimmedEnv('VITE_PLAN_PRICE_OPERATOR', 'Launch pricing via Paddle'), - ctaLabel: operatorCheckoutUrl ? 'Open Paddle checkout' : 'Open protected downloads', + ctaLabel: operatorCheckoutUrl ? 'Subscribe with Paddle' : 'Create account for download access', ctaHref: operatorCheckoutUrl || buildProtectedDownloadPath('windows'), - notes: 'Desktop-first recognition, replay, training, and higher-dimensional runtime ownership for active training operators.', + notes: 'Desktop-first recognition, replay, training, higher-dimensional runtime ownership, and protected Windows package access for active solvers.', features: [ - 'Desktop download access', - 'Desktop-link token handoff', + 'Protected desktop download access', + 'Browser-issued desktop-link token handoff', 'Recognition, replay, and coaching ownership', 'Classic-cube package and validation lane access', ], @@ -81,11 +81,11 @@ export const planCatalog = [ key: 'studio', name: 'Studio', price: readTrimmedEnv('VITE_PLAN_PRICE_STUDIO', 'Contact for launch readiness'), - ctaLabel: studioCheckoutUrl ? 'Open Paddle checkout' : 'Open protected rollout lane', - ctaHref: studioCheckoutUrl || '/app/browser-access', - notes: 'Higher-dimensional families, operator deployment support, and packaging/validation coordination for production lanes.', + ctaLabel: studioCheckoutUrl ? 'Open studio checkout' : 'Talk to HyperTwist', + ctaHref: studioCheckoutUrl || '/contact', + notes: 'Higher-dimensional training programs, deployment support, and release/package coordination for studios, educators, and rollout owners.', features: [ - 'Magic120Cell and 5D operator posture', + 'Magic120Cell and 5D operator status', 'Release planning and deployment coordination', 'Desktop distribution and legal-notice readiness', 'Custom support for rollout and training programs', @@ -106,14 +106,14 @@ export const downloadTargets = [ platform: 'macOS', subtitle: 'Planned distribution surface', configured: readBooleanEnv('VITE_MAC_RELEASE_CONFIGURED', 'VITE_MAC_DOWNLOAD_CONFIGURED'), - details: 'List a signed desktop build here when the package lane is opened.', + details: 'macOS distribution will appear here when a signed desktop build is ready for account-gated delivery.', }, { platformKey: 'linux', platform: 'Linux', subtitle: 'Operator-targeted later lane', configured: readBooleanEnv('VITE_LINUX_RELEASE_CONFIGURED', 'VITE_LINUX_DOWNLOAD_CONFIGURED'), - details: 'Use for future package publication after the bounded release lane is widened.', + details: 'Linux distribution will appear here when the operator-targeted package lane is ready.', }, ] as const satisfies readonly DownloadTarget[] @@ -138,4 +138,4 @@ export const launchReadiness = { } as const export const paddleReadyDescription = - 'HyperTwist is a desktop-first training environment for classic cube, recognition-assisted reconstruction, replay explanation, coaching, higher-dimensional runtime ownership, and browser-based operator access. Delivery is digital-only through authenticated account access and desktop downloads. Pricing and checkout are wired for Paddle, while public legal surfaces stay responsible for open-source notices and corresponding-source disclosure when shipped builds contain MPL-covered components.' + 'HyperTwist is a desktop-first training environment for classic cube practice, recognition-assisted reconstruction, replay explanation, coaching, 120-cell and 5D exploration, and browser-based operator access. Delivery is digital-only: public pages explain the product, account routes manage subscription and entitlement, and the downloadable desktop runtime performs the real simulator work. Pricing and checkout are wired for Paddle, while public legal pages keep open-source notices and corresponding-source disclosure attached to shipped downloadable builds.' diff --git a/website/src/site-data.ts b/website/src/site-data.ts index 1268ea7..216ab4f 100644 --- a/website/src/site-data.ts +++ b/website/src/site-data.ts @@ -3,8 +3,8 @@ import { brandConfig, mplSourceUrl, openSourceRepoUrl, publicDocsUrl, releaseNot export const heroMetrics = [ { label: 'Current runtime center', value: 'Native Unreal' }, { label: 'Higher-dimensional ownership', value: '120-cell + 5D' }, - { label: 'Browser posture', value: 'Embedded shell live' }, - { label: 'Package gate', value: 'Phase 10B/10C closed' }, + { label: 'Browser role', value: 'Account + release shell' }, + { label: 'Desktop package', value: 'Validated Windows lane' }, ] as const export const capabilityPillars = [ @@ -18,7 +18,7 @@ export const capabilityPillars = [ }, { title: 'Higher-dimensional seriousness', - description: 'Hyper puzzle catalog, replay verification, 120-cell and 5D runtime ownership, and non-Euclidean tiling posture are all represented honestly.', + description: 'Hyper puzzle catalog, replay verification, 120-cell and 5D runtime ownership, and non-Euclidean tiling state are all represented honestly.', }, { title: 'Desktop-first distribution', @@ -33,20 +33,20 @@ export const capabilityPillars = [ export const deliverySurfaceCards = [ { title: 'Public website', - description: 'Use the web surface for product positioning, release posture, notices, pricing, and support-safe onboarding.', + description: 'Use the web surface for product positioning, account entry, release notes, notices, pricing, and support-safe onboarding.', bullets: [ - 'Explains what is already shipped versus retained or spec-only', + 'Explains the current desktop-first product and future branches in plain language', 'Carries public docs, release notes, package proof, and legal links', - 'Keeps public launch readiness honest without exposing protected downloads', + 'Keeps anonymous pages informative while protected routes handle actual downloads', ], }, { title: 'Protected browser dashboard', - description: 'Use the browser dashboard when identity, entitlement, billing, or pairing state matters.', + description: 'Use the browser dashboard when identity, subscription, entitlement, billing, or pairing state matters.', bullets: [ - 'Shows account, auth, billing, and release readiness posture', + 'Shows account, auth, billing, and release readiness status', 'Generates desktop-link tokens for safe browser-to-desktop handoff', - 'Keeps plan-gated download access in the protected release lane', + 'Keeps plan-gated download access in the protected dashboard lane', ], }, { @@ -59,12 +59,12 @@ export const deliverySurfaceCards = [ ], }, { - title: 'Optional future browser-client branch', - description: 'Treat any full-browser simulator path as a separate, frozen branch until the roadmap explicitly reopens it.', + title: 'Future browser simulator branch', + description: 'A full browser simulator would be a separate future product branch, not the current downloadable simulator.', bullets: [ - 'Not part of current shipped product truth', - 'Does not displace the current desktop-first simulator posture', - 'Must prove its own runtime and backend contract before being marketed as live', + 'Not the current training surface', + 'Does not displace the current desktop-first simulator', + 'Would need its own runtime quality, backend contract, and product proof before launch', ], }, ] as const @@ -72,12 +72,12 @@ export const deliverySurfaceCards = [ export const browserDesktopRealityCards = [ { title: 'What the website is for', - posture: 'Public and protected browser authority', - description: 'Keep the web lane because product access, release posture, billing, notices, and operator onboarding should stay inspectable outside the simulator.', + posture: 'Public and protected browser shell', + description: 'Keep the web lane because product access, release notes, billing, notices, and operator onboarding should stay inspectable outside the simulator.', bullets: [ - 'The website owns public docs, pricing, release notes, notices, and support-safe rollout guidance.', + 'The website owns public docs, pricing, release notes, notices, and support-safe onboarding guidance.', 'The protected dashboard owns account state, entitlement, protected downloads, and browser-to-desktop pairing.', - 'This keeps release and commercial posture visible without turning the simulator into a checkout or auth shell.', + 'This keeps release and commercial context visible without turning the simulator into a checkout or auth shell.', ], action: { to: '/docs', @@ -115,12 +115,12 @@ export const browserDesktopRealityCards = [ }, { title: 'Current input, XR, and settings truth', - posture: 'Shipped today versus still gated', + posture: 'Available now versus future device proof', description: 'HyperTwist already ships meaningful desktop control/settings ownership, but it does not market unfinished XR/controller widening as complete.', bullets: [ 'Classic keyboard, mouse/touch classic-cube control, viewer camera settings, bounded camera-export continuity, immersive presets, session-local immersive recall, and dedicated-family selector, session, scene, and view ownership are real today.', 'The native operator surfaces now also expose concrete Magic120Cell and MagicCube5D session-surface, interactive-scene, persistence-boundary, and state-semantics ownership instead of hiding that proof behind softer settings summaries.', - 'OpenXR/controller runtime widening and polished rebinding/preferences remain explicitly unfinished behind the current desktop-hosted No-Go boundary.', + 'Broader headset/controller rollout still requires packaged device proof before HyperTwist markets it as a finished cross-device VR lane.', ], action: { to: '/features', @@ -141,27 +141,27 @@ export type ProductSurfaceMatrixRow = { export const productSurfaceMatrixRows = [ { title: 'Public website', - posture: 'Public release shell', - description: 'This is the anonymous-safe product surface for positioning, launch posture, release references, and operator-safe onboarding.', + posture: 'Public product shell', + description: 'This is the anonymous-safe product surface for positioning, release references, account entry, and operator-safe onboarding.', owns: [ 'Public docs, pricing, release notes, legal notices, and support-safe rollout guidance.', 'The first step into account creation, sign-in, and platform-aware download routing.', - 'Public launch-readiness truth without exposing entitled package delivery on an anonymous route.', + 'Public access truth without exposing entitled package delivery on an anonymous route.', ], doesNotClaim: [ 'The native Unreal simulator runtime.', 'Packaged higher-dimensional execution or device/runtime integration.', 'The optional full-browser simulator branch as a live product lane.', ], - nextStep: 'Start here when discovery, documentation, release posture, or public rollout context matters.', + nextStep: 'Start here when discovery, documentation, release notes, or public rollout context matters.', }, { title: 'Protected browser dashboard', posture: 'Signed-in operator shell', - description: 'This is the account-aware browser lane for entitlement, auth health, billing posture, protected notices, and desktop pairing.', + description: 'This is the account-aware browser lane for entitlement, account health, billing, protected notices, and desktop pairing.', owns: [ - 'Live session, billing, entitlement, and release-manifest viewer posture.', - 'A dedicated signed-in launch-status route for rollout blockers, packaged proof, and protected next-step interpretation.', + 'Live session, billing, entitlement, and release-manifest viewer state.', + 'A dedicated signed-in launch-status route for rollout status, packaged proof, and protected next-step interpretation.', 'Desktop-link token issuance and protected follow-through after sign-in.', 'Operator-facing release, notice, and download-center context that should not sit on public pages.', ], @@ -177,7 +177,7 @@ export const productSurfaceMatrixRows = [ posture: 'In-simulator browser adjunct', description: 'This is the browser runtime that ships inside the desktop product for bounded simulator-side interaction, not the public website.', owns: [ - 'The current MagicTile host posture, browser-assisted recognition shell segments, and typed runtime-ready or runtime-status envelopes.', + 'The current MagicTile host, browser-assisted recognition shell segments, and typed runtime-ready or runtime-status envelopes.', 'Bounded operator diagnostics that stay attached to the native training and dashboard surfaces.', 'A first-party browser bridge inside the desktop runtime instead of a separate public-web simulator claim.', ], @@ -206,19 +206,19 @@ export const productSurfaceMatrixRows = [ }, { title: 'Optional full-browser simulator branch', - posture: 'Frozen spec-only branch', + posture: 'Future branch', description: 'This is a deliberately separate future branch whose existence stays visible so the current shipped topology is not misread.', owns: [ 'A documented future possibility only after a separate backend and runtime contract is deliberately reopened.', - 'Spec-only planning material that keeps the browser-client lane disciplined instead of vague.', - 'A clear no-go boundary against accidental marketing overclaim.', + 'Planning material that keeps the browser-client lane disciplined instead of vague.', + 'A clear boundary against accidental marketing overclaim.', ], doesNotClaim: [ 'Current shipping simulator truth.', - 'Entitlement to displace the desktop-first runtime posture.', + 'Entitlement to displace the desktop-first runtime model.', 'Any current production browser parity for higher-dimensional execution.', ], - nextStep: 'Keep it visible as a gated branch, but do not route current users toward it as if it already ships.', + nextStep: 'Keep it visible as a future branch, but do not route current users toward it as if it already ships.', }, ] satisfies readonly ProductSurfaceMatrixRow[] @@ -227,27 +227,27 @@ export const featureRegistryTierCards = [ title: 'Implemented now', description: 'This is current product truth and is safe to describe as live capability on public pages.', bullets: [ - 'Use this tier for the desktop runtime, browser dashboard, release posture, and shipped higher-dimensional lanes.', + 'Use this tier for the desktop runtime, browser dashboard, release status, and shipped higher-dimensional lanes.', 'These are the surfaces operators can actually rely on today.', 'Public copy should treat this tier as present, not aspirational.', ], }, { title: 'Retained and planned', - description: 'This is source-backed roadmap or retained capability, but not something the public site should market as already shipped.', + description: 'This is real planned capability, but not something the public site should describe as already available.', bullets: [ - 'Use this tier for real roadmap direction that still needs first-party product evidence.', + 'Use this tier for real product direction that still needs first-party release evidence.', 'Public wording can describe it as retained, planned, or deliberately deferred.', 'It should never be blurred into current live simulator truth.', ], }, { - title: 'Frozen or gated branch', - description: 'This is an explicit no-go, spec-only, or decision-gated path that remains intentionally outside current product claims.', + title: 'Future or internal-only branch', + description: 'This is a future decision path that remains intentionally outside current product claims.', bullets: [ - 'Use this tier for the optional full-browser simulator path and renderer-widening branches that remain closed.', + 'Use this tier for optional full-browser simulator or renderer-widening branches that remain outside the current product.', 'Keep the branch visible so advanced users understand the boundary.', - 'Do not market these paths as available until the gate is deliberately reopened and revalidated.', + 'Do not market these paths as available until they are deliberately reopened and revalidated.', ], }, ] as const @@ -276,15 +276,15 @@ export const featureAtlasCurrentTracks = [ description: 'Serious higher-dimensional work is part of the current product, not just background aspiration.', bullets: [ 'Dedicated Magic120Cell and MagicCube5D packaged runtime-state, projection, and persistence ownership are already live.', - 'MagicTile currently ships through the embedded browser host posture with state-bridge and native behavior-proof support.', - 'Renderer widening and generic browser parity remain explicitly gated rather than being hand-waved away.', + 'MagicTile currently ships through the embedded browser host with state-bridge and native behavior-proof support.', + 'Renderer widening and generic browser parity remain explicitly reserved for later validation rather than being hand-waved away.', ], }, { title: 'Browser account, release, and distribution shell', description: 'The website is part of the product because it owns access, release, pricing, legal, and rollout work the simulator should not absorb.', bullets: [ - 'Shared auth, billing posture, protected download access, desktop-link pairing, and launch-readiness status already ship.', + 'Shared auth, billing status, protected download access, desktop-link pairing, and launch-readiness status already ship.', 'Public docs, pricing, notices, and release surfaces are deliberate operator/distribution tools, not brochure-only pages.', 'The public site is honest about desktop-first simulator truth while still being production-useful on its own terms.', ], @@ -307,7 +307,7 @@ export const advancedOperatorAdjunctTracks = [ bullets: [ 'Provider-neutral speech and vision contracts, BYOK/profile custody, custom-endpoint routing, and workflow-policy surfaces are already implemented.', 'Usage/cost dashboards, history/export, receipt review, settlement, and exception handoff already exist as operator-facing governance shells.', - 'This keeps external-service posture inspectable without pretending browser billing or auth is the same thing as simulator execution.', + 'This keeps external-service status inspectable without pretending browser billing or auth is the same thing as simulator execution.', ], }, { @@ -315,7 +315,7 @@ export const advancedOperatorAdjunctTracks = [ description: 'HyperTwist also ships continuity-oriented surfaces that keep replay, training, and publication state from collapsing into stateless sessions.', bullets: [ 'Session continuity, workspace recall, chronicle, notes, knowledge, and derived memory families are already in the live feature registry.', - 'Provenance-aware replay or publication state plus ledger-style continuity and control-plane telemetry are part of the owned reference posture.', + 'Provenance-aware replay or publication state plus ledger-style continuity and control-plane telemetry are part of the owned reference model.', 'These families support serious operator and study workflows around the simulator rather than replacing the simulator itself.', ], }, @@ -333,18 +333,18 @@ export const shippingNowCards = [ ] as const export const roadmapHonestyCards = [ - 'The embedded browser shell is shipping. The optional full-browser client remains spec-only and is not presented as a live simulator.', - 'Native renderer widening for MagicTile stays explicitly No-Go until a real browser-host gap is evidenced.', - 'Pricing and checkout are Paddle-ready, but public launch still requires production checkout URLs and corresponding-source publication for MPL-covered shipped builds.', - 'Desktop distribution is the primary product lane. Browser access is for account, operator, release, and support surfaces unless a later browser-client packet is deliberately reopened.', + 'The embedded browser shell ships inside the desktop product. A standalone full-browser simulator remains a future branch, not today\'s training surface.', + 'MagicTile currently uses the embedded browser host; native renderer widening will only return if the shipped host stops meeting product needs.', + 'Pricing and checkout are Paddle-ready; public package delivery remains account-gated so subscription, notices, and source-disclosure duties stay attached.', + 'Desktop distribution is the primary product lane. Browser access is for account, operator, release, and support surfaces unless a later browser-client product branch is deliberately opened.', ] as const export const operatorManualTracks = [ { title: '1. Start in the browser shell', - description: 'Begin with public pages and the protected dashboard so account, plan, and release posture are resolved before any desktop rollout.', + description: 'Begin with public pages and the protected dashboard so account, plan, and release status are resolved before any desktop rollout.', steps: [ - 'Review the current launch-status banner and release posture.', + 'Review the current launch-status banner and release status.', 'Create or sign in to a HyperTwist account.', 'Use the dashboard to confirm plan, billing, and download entitlement state.', ], @@ -373,7 +373,7 @@ export const operatorManualTracks = [ steps: [ 'Use the desktop runtime for recognition, replay, and coaching flows.', 'Treat higher-dimensional training as a packaged native lane, not a browser claim.', - 'Use package proof and release notes to confirm the exact build posture you are running.', + 'Use package proof and release notes to confirm the exact build state you are running.', ], }, { @@ -381,7 +381,7 @@ export const operatorManualTracks = [ description: 'Return to the website when you need operator status, support, launch readiness, or legal/distribution guidance.', steps: [ 'Use the dashboard for auth, billing, and launch-readiness review.', - 'Use pricing, notices, and support pages for commercial/distribution posture.', + 'Use pricing, notices, and support pages for commercial/distribution status.', 'Use docs and resources pages for public-safe explanations of the shipped lanes.', ], }, @@ -392,7 +392,7 @@ export const desktopWorkflowTracks = [ title: '1. Run a classic-cube training session', description: 'Use the desktop runtime when the goal is actual practice, not product orientation.', steps: [ - 'Launch the classic-cube training lane from the installed desktop runtime and confirm the HUD, timer, and scramble posture first.', + 'Launch the classic-cube training lane from the installed desktop runtime and confirm the HUD, timer, and scramble state first.', 'Use the shipped classic control lane for turns, orbit, zoom, hint, fresh-attempt restart, and hold-to-talk behavior during the solve.', 'Treat this as the authoritative packaged practice loop rather than trying to reproduce it through the public website.', ], @@ -412,7 +412,7 @@ export const desktopWorkflowTracks = [ steps: [ 'Finish or import the training session, then open replay, coaching, and leaderboard or diagnostics surfaces inside the desktop runtime.', 'Use the current native analytics and review surfaces to inspect timing, progression, and coaching output before escalating or exporting anything outward.', - 'Return to the browser shell only when account, release, entitlement, or support posture becomes the next real concern.', + 'Return to the browser shell only when account, release, entitlement, or support status becomes the next real concern.', ], }, { @@ -420,8 +420,8 @@ export const desktopWorkflowTracks = [ description: 'Use the packaged dedicated-family maps when training moves beyond the classic cube.', steps: [ 'Launch the dedicated Magic120Cell or MagicCube5D map from the desktop runtime instead of expecting a browser parity lane.', - 'Use the shipped selector, focus, projection, symmetry or stereo, and visibility posture that the native operator surfaces already own explicitly.', - 'Use selector recall when a valid generated-mode launch history exists, while still reading XR and controller widening as explicit No-Go until a later dedicated completion packet lands.', + 'Use the shipped selector, focus, projection, symmetry or stereo, and visibility settings that the native operator surfaces already own explicitly.', + 'Use selector recall when a valid generated-mode launch history exists, while treating broader XR and controller rollout as a future device-proof step.', ], }, { @@ -429,7 +429,7 @@ export const desktopWorkflowTracks = [ description: 'Use the browser shell after or around sessions when the next job is commercial, operational, or release-facing rather than simulator-facing.', steps: [ 'Use the protected dashboard for plan, entitlement, browser-to-desktop pairing, and release-manifest review.', - 'Use public or protected launch-status, notices, pricing, and release-notes routes when rollout, legal, or distribution posture changes.', + 'Use public or protected launch-status, notices, pricing, and release-notes routes when rollout, legal, or distribution status changes.', 'Keep browser access issues separate from native runtime issues so support and rollout work stay attached to the correct surface.', ], }, @@ -438,11 +438,11 @@ export const desktopWorkflowTracks = [ export const operatorDesktopQuickstartCards = [ { title: '1. Resolve access and choose the right build', - description: 'The browser shell should settle identity, entitlement, release posture, and target platform before the simulator ever launches.', + description: 'The browser shell should settle identity, entitlement, release status, and target platform before the simulator ever launches.', bullets: [ 'Use the public download surface to choose the target platform and review package proof before install.', 'Preserve that target through sign-in and confirm protected download entitlement in the dashboard.', - 'Treat launch posture, release notes, and notices as part of the install decision rather than as later paperwork.', + 'Treat launch status, release notes, and notices as part of the install decision rather than as later paperwork.', ], }, { @@ -450,7 +450,7 @@ export const operatorDesktopQuickstartCards = [ description: 'HyperTwist keeps browser identity narrow and hands it to the desktop app through a bounded desktop-link token.', bullets: [ 'Generate a desktop-link token from the protected dashboard after sign-in succeeds.', - 'Use the token during first launch so the installed runtime inherits the correct account and release posture.', + 'Use the token during first launch so the installed runtime inherits the correct account and release status.', 'Return to the browser shell later when account, plan, or release state changes.', ], }, @@ -468,8 +468,8 @@ export const operatorDesktopQuickstartCards = [ description: 'The native desktop runtime already owns real 120-cell and 5D execution, but it still keeps XR/controller widening behind an explicit boundary.', bullets: [ 'Launch the dedicated `Magic120Cell` and `MagicCube5D` training maps from the packaged runtime.', - 'Use the current projection, focus, visibility, selector, and persisted selector-recall ownership as the current first-party posture.', - 'Do not mistake project-level controller groundwork for a finished OpenXR or headset or rebinding product lane; that branch remains explicit No-Go today.', + 'Use the current projection, focus, visibility, selector, and persisted selector-recall ownership as the current first-party settings model.', + 'Do not mistake project-level controller groundwork for finished headset rollout; that branch still needs packaged device validation.', ], }, ] as const @@ -477,18 +477,18 @@ export const operatorDesktopQuickstartCards = [ export const degradedStateRecoveryTracks = [ { title: 'Browser auth degraded or mixed', - description: 'Treat browser sign-in as bounded continuity when shared auth is in fallback or mixed posture, not as a silent claim of full production authority.', + description: 'Treat browser sign-in as recoverable account continuity when shared auth is temporarily degraded, not as a silent claim that every release surface is final.', steps: [ 'Continue with sign-in or registration only when you need bounded account, release, or rollout orientation.', 'Use the protected dashboard to inspect what still works and what remains intentionally withheld.', - 'Clear missing auth env vars and non-loopback HTTPS warnings before treating browser auth as fully production-ready.', + 'Use the protected dashboard and support lanes for account-aware follow-through if live auth status needs human review.', ], }, { title: 'Release authority temporarily unavailable', - description: 'When the live release manifest is unavailable, HyperTwist keeps rollout information visible without turning fallback metadata into raw package-delivery authority.', + description: 'When the live release manifest is unavailable, HyperTwist keeps rollout information visible without turning local reference data into raw package-delivery authority.', steps: [ - 'Use fallback metadata, packaged proof, and notices for orientation while release authority is degraded.', + 'Use local reference metadata, packaged proof, and notices for orientation while release authority recovers.', 'Keep raw package delivery withheld until live release authority returns.', 'Refresh the protected release lane first, then escalate to support if rollout or entitlement work remains blocked.', ], @@ -536,7 +536,7 @@ export const simulatorManualCards = [ title: 'Operator diagnostics and release proof', description: 'Use both surfaces together when rollout confidence matters.', bullets: [ - 'Use the browser dashboard for auth, billing, desktop-link pairing, and release-lane posture.', + 'Use the browser dashboard for auth, billing, desktop-link pairing, and release-lane status.', 'Use the desktop runtime for browser-runtime diagnostics, simulator execution, and package-validated behavior.', 'Use package proof, release notes, and notices together before any public-facing rollout or team distribution.', ], @@ -549,9 +549,9 @@ export const higherDimensionalRuntimeGuideCards = [ description: 'Use the packaged native training lane when you need real 120-cell runtime-state, projection ownership, and persistence-aware family behavior.', bullets: [ 'Launch the dedicated Magic120Cell training map from the desktop runtime.', - 'Use the current symmetry, focus, and logical-visibility posture as the authoritative first-party runtime owner.', + 'Use the current symmetry, focus, and logical-visibility settings as the authoritative first-party runtime owner.', 'The native operator and training surfaces now also expose the dedicated session surface, interactive-scene surface, persistence boundary, and family-owned state semantics for this lane explicitly.', - 'The native operator/training surfaces can now also recall the latest persisted generated-mode selector posture for this family instead of hiding it behind the browser shell.', + 'The native operator/training surfaces can now also recall the latest persisted generated-mode selector state for this family instead of hiding it behind the browser shell.', 'Treat the public website as documentation and rollout support, not as the runtime that executes this family.', ], }, @@ -560,19 +560,19 @@ export const higherDimensionalRuntimeGuideCards = [ description: 'Use the packaged native training lane when you need real 5D projection, stereo, focus, and face-visibility ownership.', bullets: [ 'Launch the dedicated MagicCube5D training map from the desktop runtime.', - 'Use the current projection-distance, stereo, and visibility defaults as the bounded first-party runtime posture.', + 'Use the current projection-distance, stereo, and visibility defaults as the bounded first-party runtime settings.', 'The native operator and training surfaces now also expose the dedicated session surface, interactive-scene surface, persistence boundary, and family-owned state semantics for this lane explicitly.', - 'The native operator/training surfaces can now also recall the latest persisted generated-mode selector posture for this family instead of forcing a blind restart.', + 'The native operator/training surfaces can now also recall the latest persisted generated-mode selector state for this family instead of forcing a blind restart.', 'Keep this lane described honestly as packaged native behavior rather than browser simulator parity.', ], }, { title: 'MagicTile embedded-browser runtime', - description: 'Use the embedded browser lane for the current non-Euclidean tiling host posture while native renderer widening remains intentionally gated.', + description: 'Use the embedded browser lane for the current non-Euclidean tiling host while native renderer widening remains a future product decision.', bullets: [ 'Treat the embedded browser/CEF shell as the current shipped host for the live MagicTile interaction lane.', 'Keep shared scramble normalization, timer transport, and state-bridge ownership attached to the first-party native shell and bridge.', - 'Do not describe a separate native renderer port as live while the renderer-widening gate stays explicit No-Go.', + 'Do not describe a separate native renderer port as live unless a later product packet proves it and ships it.', ], }, ] as const @@ -584,15 +584,15 @@ export const inputAndDevicePostureCards = [ bullets: [ 'Classic-cube runtime input already includes click, touch, orbit, zoom, and bounded keyboard move intent.', 'The current classic keyboard profile is the shipped `classic-wca-keyboard/v1` mapping.', - 'Treat this as real simulator input ownership, not as a browser-side placeholder.', + 'Treat this as real simulator input ownership, not as browser-only ornamentation.', ], }, { title: 'Higher-dimensional view controls are already owned', description: 'Magic120Cell and MagicCube5D already carry first-party projection, focus, symmetry or stereo, visibility defaults, and visible native settings ownership in the packaged runtime.', bullets: [ - 'Magic120Cell keeps symmetry, logical-visibility depth, and center-cell focus posture explicit.', - 'MagicCube5D keeps projection-distance, stereo, face-visibility, and focus posture explicit.', + 'Magic120Cell keeps symmetry, logical-visibility depth, and center-cell focus settings explicit.', + 'MagicCube5D keeps projection-distance, stereo, face-visibility, and focus settings explicit.', 'The desktop operator and training lane now also surfaces these dedicated-family view owners together with exact session-surface, interactive-scene, persistence-boundary, and state-semantics ownership.', 'That same native lane now also keeps bounded camera-export continuity and immersive session-local recall visible instead of implying that continuity only through softer prose.', 'The same native surfaces now expose selector recall from the latest persisted generated-mode launch request when that launch history exists.', @@ -601,12 +601,12 @@ export const inputAndDevicePostureCards = [ }, { title: 'XR groundwork exists, but the full VR lane is not finished', - description: 'EnhancedInput posture, bounded OpenXR runtime ownership, and first-party controller settings/rebinding now exist, but HyperTwist still does not market a fully finished cross-device VR/runtime lane.', + description: 'EnhancedInput, bounded OpenXR runtime ownership, and first-party controller settings/rebinding now exist, but HyperTwist does not market a fully finished cross-device VR/runtime lane without packaged device proof.', bullets: [ 'Project config already carries EnhancedInput plus Vive, Oculus Touch, Mixed Reality, and Valve Index axis groundwork.', - 'The current shipping branch now enables the bounded OpenXR plugin stack, first-party runtime-owner substrate, and first-party controller settings/rebinding ownership, but that still does not collapse the broader native XR/controller lane out of its explicit desktop-hosted No-Go posture.', + 'The current shipping branch enables the bounded OpenXR plugin stack, first-party runtime-owner substrate, and first-party controller settings/rebinding ownership while keeping broad headset/controller rollout tied to packaged device validation.', 'Current product truth should not overclaim packaged controller proof or broader finished cross-device VR completion.', - 'The current host decision remains desktop-hosted No-Go on broader native OpenXR/controller widening until Windows packaged controller validation with controller truth is complete.', + 'The current host decision remains desktop-first for broader native OpenXR/controller rollout until Windows packaged controller validation with controller truth is complete.', ], }, ] as const @@ -614,7 +614,7 @@ export const inputAndDevicePostureCards = [ export const runtimeControlGuideCards = [ { title: 'Classic-cube desktop session', - description: 'This is the current practical control posture for the packaged classic-cube runtime.', + description: 'This is the current practical control model for the packaged classic-cube runtime.', bullets: [ 'Use left click or touch to drive face interaction in the live training lane.', 'Use middle-mouse drag to orbit and scroll-wheel zoom to reframe the active cube during practice or replay review.', @@ -624,12 +624,12 @@ export const runtimeControlGuideCards = [ }, { title: 'Higher-dimensional desktop session', - description: 'This is the current practical control posture for the dedicated Magic120Cell and MagicCube5D runtime families.', + description: 'This is the current practical control model for the dedicated Magic120Cell and MagicCube5D runtime families.', bullets: [ 'Launch the dedicated-family desktop maps instead of expecting the public website to host the serious runtime lane.', 'Use the current keyboard-driven slice, layer, or rotation interaction together with the family-owned projection and focus defaults.', - 'Use the native operator/training inspect surfaces to confirm when the latest persisted generated-mode selector posture is available for recall.', - 'Treat symmetry, stereo, visibility, and focus posture as current packaged runtime ownership rather than as a fully generalized preferences suite.', + 'Use the native operator/training inspect surfaces to confirm when the latest persisted generated-mode selector state is available for recall.', + 'Treat symmetry, stereo, visibility, and focus settings as current packaged runtime ownership rather than as a fully generalized preferences suite.', ], }, { @@ -638,19 +638,19 @@ export const runtimeControlGuideCards = [ bullets: [ 'Read the active higher-dimensional selection line to confirm the current activation, view-context, session, and displayed scene ids instead of inferring them from the launched map alone.', 'Read the profile continuity line to confirm the shipped camera-export artifact `artifact/camera-export-json`, immersive recall boundary `immersive-training-session-recall-boundary`, and the current recall-scope and preference-field counts when bounded continuity is available.', - 'Use the same native surfaces to verify that the desktop-hosted No-Go XR/controller boundary is still the live truth before assuming headset-runtime or controller-rebinding support.', - 'If behavior and rollout posture disagree, capture the native diagnostics first and then move into the protected browser support or release lanes with the exact runtime state in hand.', + 'Use the same native surfaces to verify the current XR/controller boundary before assuming broad headset-runtime or controller-rebinding support.', + 'If behavior and rollout status disagree, capture the native diagnostics first and then move into the protected browser support or release lanes with the exact runtime state in hand.', ], }, { title: 'Current control boundary', - description: 'This keeps the manual useful by being explicit about what is supported now and what remains outside the current desktop-hosted No-Go XR/controller branch.', + description: 'This keeps the manual useful by being explicit about what is supported now and what remains outside current packaged device proof.', bullets: [ 'Use keyboard and mouse as the current strong operator-facing control lane.', 'Treat current camera, immersive, and dedicated-family view settings ownership as real, including bounded camera-export continuity and session-local immersive recall, but still bounded.', 'Do not assume a finished headset-specific VR onboarding, packaged controller proof, or broad cross-device XR rollout has already landed.', 'Treat the current controller settings/rebinding ownership as bounded native runtime truth, not as proof that the broader XR/controller widening gate is already open.', - 'Treat any future XR/controller/settings widening as a deliberate reopen above the current desktop-hosted No-Go posture, not as something the public website should overclaim today.', + 'Treat any future XR/controller/settings widening as a deliberate product step above the current desktop-first device-proof boundary, not as something the public website should overclaim today.', ], }, ] as const @@ -680,16 +680,16 @@ export const controlProfileRosterCards = [ title: 'Persistence and boundary truth', description: 'Current continuity is real, but it is still narrower than a finished global preferences and controller-rebinding suite.', bullets: [ - 'The native operator and training surfaces can recall the latest persisted generated-mode selector posture when a structurally valid launch request exists.', + 'The native operator and training surfaces can recall the latest persisted generated-mode selector state when a structurally valid launch request exists.', 'Those same native surfaces now also keep the shipped camera-export artifact and immersive session-recall boundary explicit together with recall-scope and preference-field counts, so bounded local continuity is no longer implied only through summary prose.', 'Those same native surfaces now also prove which family-specific persistence boundary and state-semantics contract currently owns the higher-dimensional settings lane.', 'Viewer camera settings and immersive-presence settings are already first-party owned in the desktop runtime.', - 'First-party controller settings/rebinding now also exist inside the bounded desktop OpenXR lane, while packaged headset/controller proof and broader VR onboarding remain outside the current desktop-hosted No-Go branch.', + 'First-party controller settings/rebinding now also exist inside the bounded desktop OpenXR lane, while packaged headset/controller proof and broader VR onboarding remain a future validation step.', ], }, { title: 'XR reopen requirements', - description: 'The current desktop-hosted No-Go boundary is not vague. HyperTwist already owns the bounded runtime-owner and controller-settings pieces, and it knows the remaining proof required before broader native XR/controller widening could be reopened honestly.', + description: 'The current desktop-first XR boundary is not vague. HyperTwist already owns the bounded runtime-owner and controller-settings pieces, and it knows the remaining proof required before broader native XR/controller widening can be marketed honestly.', bullets: [ 'The bounded desktop runtime already owns dedicated runtime owners for live OpenXR/controller execution inside the current training lane.', 'The native simulator now also owns first-party user-facing controller settings, layout presets, and rebinding truth for the exact shipped XR input ids.', @@ -701,24 +701,24 @@ export const controlProfileRosterCards = [ export const deploymentReadinessTracks = [ { - title: '1. Identity and access posture', + title: '1. Identity and access status', steps: [ 'Confirm shared browser auth is live before inviting operators into the protected release lane.', 'Treat login/register visibility above decorative auth backdrops as a launch-readiness invariant, not a cosmetic preference.', - 'Use the protected dashboard to resolve plan, entitlement, and desktop-link token posture.', + 'Use the protected dashboard to resolve plan, entitlement, and desktop-link token status.', 'Keep browser-to-desktop handoff explicit so the installed app never depends on password reuse.', ], }, { - title: '2. Release and package posture', + title: '2. Release and package status', steps: [ 'Publish release-manifest truth for the active desktop targets before widening any public launch language.', - 'Keep package validation proof visible beside download posture so rollout remains evidence-backed.', + 'Keep package validation proof visible beside download guidance so rollout remains evidence-backed.', 'Differentiate browser-shell changes from simulator/package changes in release notes and support guidance.', ], }, { - title: '3. Legal and source posture', + title: '3. Legal and source follow-through', steps: [ 'Keep notices and corresponding-source links visible anywhere pricing, checkout, or downloads are exposed.', 'Treat public pricing/download surfaces as part of the distributed product, not detached brochure pages.', @@ -734,7 +734,7 @@ export const publicDocumentationPrinciples = [ }, { title: 'Browser shell and simulator kept separate', - description: 'Account access, pricing, and download posture belong to the website. Recognition, replay, coaching, and higher-dimensional execution belong to the desktop runtime.', + description: 'Account access, pricing, and download guidance belong to the website. Recognition, replay, coaching, and higher-dimensional execution belong to the desktop runtime.', }, { title: 'Launch and legal readiness stay visible', @@ -748,13 +748,13 @@ export const operatorPlaybooks = [ steps: [ 'Sign in through the browser shell before requesting a desktop package.', 'Confirm package proof and release references before first install.', - 'Use desktop-link pairing so the installed app inherits the right account posture.', + 'Use desktop-link pairing so the installed app inherits the right account status.', ], }, { title: 'Studio rollout', steps: [ - 'Validate checkout, download, notices, and corresponding-source posture together.', + 'Validate checkout, download, notices, and corresponding-source follow-through together.', 'Treat package proof as part of launch readiness rather than as a separate afterthought.', 'Keep the browser dashboard for coordination and the desktop build for actual simulator execution.', ], @@ -764,13 +764,13 @@ export const operatorPlaybooks = [ steps: [ 'Route account, entitlement, and rollout issues through support-safe browser surfaces.', 'Keep pricing/download/notices links aligned for any public distribution event.', - 'Do not describe the full-browser simulator branch as live while it remains frozen.', + 'Do not describe the full-browser simulator branch as live while it remains a future validation branch.', ], }, { - title: 'Recovery and authority fallback', + title: 'Recovery and account authority', steps: [ - 'Use degraded browser auth or release-manifest posture for orientation, not as a false claim of live production authority.', + 'Use degraded browser auth or release-manifest recovery for orientation, not as a false claim of final release authority.', 'Keep raw package delivery withheld until protected release authority recovers.', 'Separate account, package, runtime, and compliance follow-through before escalating.', ], @@ -792,7 +792,7 @@ export const releaseStoryCards = [ description: 'Website change notes should explain auth, entitlement, launch-readiness, and dashboard behavior without implying browser simulator parity.', bullets: [ 'Summarize account, checkout, and desktop-link changes in operator language.', - 'Keep public preview-versus-launch posture visible when values are not fully live.', + 'Keep public early-access-versus-launch status visible when values are not fully live.', 'Treat browser improvements as operator/distribution work around the desktop runtime.', ], }, @@ -800,9 +800,9 @@ export const releaseStoryCards = [ title: 'Legal and release discipline', description: 'Distribution-facing changes are product changes, not footer trivia, because they affect whether the release lane is truthful and launchable.', bullets: [ - 'Record corresponding-source, notices, and pricing/download posture when they change.', + 'Record corresponding-source, notices, and pricing/download status when they change.', 'Make release chronology readable for studios evaluating rollout risk.', - 'Keep public legal surfaces synchronized with actual downloadable posture.', + 'Keep public legal surfaces synchronized with actual downloadable status.', ], }, ] as const @@ -814,12 +814,12 @@ export const distributionDoctrineCards = [ bullets: [ 'Treat those pages as release-facing surfaces, not detached marketing copy.', 'Keep open-source notices and corresponding-source links reachable from them.', - 'Do not let launch copy outrun the actual package and legal posture.', + 'Do not let launch copy outrun the actual package and legal follow-through.', ], }, { title: 'Package proof stays visible', - description: 'The legal and release lane stays more trustworthy when package validation evidence remains visible alongside download posture.', + description: 'The legal and release lane stays more trustworthy when package validation evidence remains visible alongside download guidance.', bullets: [ 'Show validation summaries where public audiences assess readiness.', 'Preserve the link between build proof, release notes, and distribution guidance.', @@ -873,7 +873,7 @@ export const termsBoundaryCards = [ description: 'Terms should match the actual product topology: public pages, protected dashboard access, and native desktop delivery.', bullets: [ 'Browser access covers public information, account, entitlement, and release coordination.', - 'Protected downloads remain tied to account and plan posture.', + 'Protected downloads remain tied to account and plan status.', 'Native runtime use remains subject to release, notice, and distribution rules.', ], }, @@ -881,7 +881,7 @@ export const termsBoundaryCards = [ title: 'Simulator boundary', description: 'Terms should not pretend the current website has replaced the native simulator lane.', bullets: [ - 'Keep the desktop-first simulator posture explicit.', + 'Keep the desktop-first simulator model explicit.', 'Treat any later full-browser simulator work as a separate branch until reopened.', 'Avoid vague “all features available on the web” language while that is untrue.', ], @@ -890,9 +890,9 @@ export const termsBoundaryCards = [ title: 'Operational obligations', description: 'Commercial and rollout terms should stay aligned with the same legal and package-proof duties visible elsewhere on the site.', bullets: [ - 'Keep notices and corresponding-source posture reachable from access and download surfaces.', + 'Keep notices and corresponding-source status reachable from access and download surfaces.', 'Preserve release-note and support references for operator-grade deployment.', - 'Bind the commercial lane to the actual shipped release posture, not a speculative future branch.', + 'Bind the commercial lane to the actual shipped release status, not a speculative future branch.', ], }, ] as const @@ -900,7 +900,7 @@ export const termsBoundaryCards = [ export const digitalDeliveryCards = [ { title: 'Release selection before install', - description: 'Digital delivery begins in the browser shell so the operator can review platform, entitlement, and release posture before opening the desktop runtime.', + description: 'Digital delivery begins in the browser shell so the operator can review platform, entitlement, and release status before opening the desktop runtime.', bullets: [ 'Choose the platform from the public download surface.', 'Carry that selection into the protected dashboard.', @@ -922,7 +922,7 @@ export const digitalDeliveryCards = [ bullets: [ 'Use the browser dashboard for account, billing, and rollout governance.', 'Use the desktop app for simulator execution, diagnostics, and higher-dimensional training.', - 'Return to notices, pricing, and support pages when release/compliance posture changes.', + 'Return to notices, pricing, and support pages when release/compliance status changes.', ], }, ] as const @@ -934,12 +934,12 @@ export const resourceCollections = [ 'Feature registry-backed descriptions only', 'Dedicated browser guide for the public web-version-versus-downloadable boundary', 'Dedicated getting-started route for the first real browser-to-desktop operator journey', - 'Dedicated launch-status route for the canonical preview-versus-launch authority surface', + 'Dedicated launch-status route for the canonical early-access and public-launch status surface', 'Dedicated help-center route for product-safe onboarding and troubleshooting', 'Public feature atlas for the real browser-versus-desktop product split', 'Roadmap-honest separation between shipped and retained capability', 'Release notes that surface what actually landed', - 'Desktop-first simulator posture with browser-shell boundaries kept explicit', + 'Desktop-first simulator model with browser-shell boundaries kept explicit', 'Practical software-workflow manual for classic-cube, recognition, replay, and higher-dimensional use', 'Public manual now surfaces the live speech, provider, and continuity adjunct families too', ], @@ -958,16 +958,16 @@ export const resourceCollections = [ items: [ 'Classic-cube recognition and correction workflows', 'Step-by-step desktop workflow guidance for practice, review, and higher-dimensional sessions', - 'Replay, coaching, analytics, and package validation posture', + 'Replay, coaching, analytics, and package validation status', 'Higher-dimensional puzzle-family references and browser-host boundaries', '120-cell and 5D dedicated-family runtime ownership overview', - 'Speech capture, narration, and model-custody adjunct posture', + 'Speech capture, narration, and model-custody adjunct status', ], }, { title: 'Operator adjuncts', items: [ - 'Provider-neutral routing, BYOK/profile custody, and custom-endpoint posture', + 'Provider-neutral routing, BYOK/profile custody, and custom-endpoint status', 'Usage or cost dashboards, export history, receipts, settlement, and exception handoff', 'Continuity, memory, notes, and provenance-aware replay or publication state', 'Operator-safe reference surfaces around the simulator instead of generic AI-platform claims', @@ -976,17 +976,17 @@ export const resourceCollections = [ { title: 'Deployment readiness', items: [ - 'Shared auth and browser-to-desktop pairing posture', + 'Shared auth and browser-to-desktop pairing status', 'Package validation proof and release-manifest interpretation', 'Pricing, checkout, notices, and corresponding-source coordination', - 'Launch-readiness distinction between preview, protected, and public lanes', + 'Launch-readiness distinction between early-access, protected, and public lanes', ], }, { title: 'Recovery and escalation', items: [ - 'Auth fallback posture and mixed-mode recovery guidance', - 'Release-authority fallback without raw package-delivery overclaim', + 'Auth recovery and mixed-mode guidance', + 'Release-authority recovery without raw package-delivery overclaim', 'Direct contact route for operator, rollout, pricing, and legal follow-through questions', 'Account, package, runtime, and compliance issue separation', 'Operator-safe next steps when browser authority is degraded', @@ -996,10 +996,10 @@ export const resourceCollections = [ export const browserPurposeCards = [ { - title: 'Use the browser for access, release, and rollout posture', + title: 'Use the browser for access, release, and rollout status', description: 'The browser lane owns the work that should stay inspectable outside the simulator.', bullets: [ - 'Open public pages for product research, pricing, release notes, legal notices, and launch-readiness posture.', + 'Open public pages for product research, pricing, release notes, legal notices, and launch-readiness status.', 'Use the protected browser dashboard for sign-in, entitlement, billing, protected downloads, and desktop-link pairing.', 'Keep rollout, purchase, and legal-follow-through work on the web so the simulator is not forced to become a storefront or auth shell.', ], @@ -1047,7 +1047,7 @@ export const browserLimitCards = [ title: 'When browser-only use is still worthwhile', description: 'The website is not superfluous just because it is narrower.', bullets: [ - 'Use it for product evaluation, account access, protected release posture, billing, notices, help, and launch-readiness review.', + 'Use it for product evaluation, account access, protected release status, billing, notices, help, and launch-readiness review.', 'Use it when a team needs product-safe explanation, public references, or rollout coordination without opening the simulator.', 'Use it as the bounded bridge into the desktop runtime rather than as a lesser substitute for the simulator itself.', ], @@ -1057,20 +1057,20 @@ export const browserLimitCards = [ export const browserWorkflowTracks = [ { title: '1. Start on the web before you install anything', - description: 'The first job is understanding release posture and choosing the right operator path.', + description: 'The first job is understanding release status and choosing the right operator path.', steps: [ - 'Review launch status, pricing, and download posture on the public site.', + 'Review launch status, pricing, and download guidance on the public site.', 'Open docs, help, or resources if the team still needs rollout-safe explanation of the product topology.', - 'Choose the correct platform and plan posture before you cross into the protected browser shell.', + 'Choose the correct platform and plan status before you cross into the protected browser shell.', ], }, { title: '2. Use the protected browser shell for account-aware follow-through', description: 'The browser becomes stronger after sign-in, but still stays bounded to account and release work.', steps: [ - 'Sign in, review account and entitlement posture, and generate a desktop-link token when needed.', + 'Sign in, review account and entitlement status, and generate a desktop-link token when needed.', 'Use protected downloads and notices instead of expecting anonymous public pages to expose raw delivery authority.', - 'Keep the browser focused on release, billing, pairing, and rollout posture rather than simulator execution.', + 'Keep the browser focused on release, billing, pairing, and rollout status rather than simulator execution.', ], }, { @@ -1116,7 +1116,7 @@ export const puzzleCatalogCards = [ title: 'Magic120Cell packaged runtime', description: 'HyperTwist already owns a real dedicated higher-dimensional family lane in the downloadable.', bullets: [ - 'The desktop runtime owns live `Magic120Cell` session surfaces, scene surfaces, symmetry/focus posture, and persisted selector continuity.', + 'The desktop runtime owns live `Magic120Cell` session surfaces, scene surfaces, symmetry/focus settings, and persisted selector continuity.', 'Operators can inspect session, interactive-scene, persistence-boundary, and state-semantics ownership directly in native diagnostics.', 'This lane is described on the public site, but it is only executed in the downloadable runtime.', ], @@ -1134,8 +1134,8 @@ export const puzzleCatalogCards = [ title: 'MagicTile embedded-browser lane', description: 'HyperTwist also carries a bounded non-Euclidean lane, but it is still intentionally hosted inside the desktop product.', bullets: [ - 'The current live `MagicTile` posture runs through the embedded browser host inside Unreal rather than through the public website.', - 'State bridge, scramble normalization, and timer continuity are already first-party owned around that host posture.', + 'The current live `MagicTile` lane runs through the embedded browser host inside Unreal rather than through the public website.', + 'State bridge, scramble normalization, and timer continuity are already first-party owned around that host.', 'Native renderer widening remains an explicit gate, so the public product story stays honest about where this lane currently lives.', ], }, @@ -1155,20 +1155,20 @@ export const audienceFitCards = [ description: 'This is the current core audience for the desktop runtime.', bullets: [ 'Recognition, replay, coaching, diagnostics, and continuity are already designed to support repeated deliberate practice.', - 'The browser lane stays useful around that work for release posture, account access, and support-safe coordination.', + 'The browser lane stays useful around that work for release status, account access, and support-safe coordination.', ], }, { title: 'Hypercubers and topology-focused learners', description: 'HyperTwist is already unusual in that it treats higher-dimensional work as a real shipping lane.', bullets: [ - 'Dedicated `Magic120Cell`, `MagicCube5D`, and bounded `MagicTile` posture are public, truthful, and source-backed today.', + 'Dedicated `Magic120Cell`, `MagicCube5D`, and bounded `MagicTile` lanes are public, truthful, and source-backed today.', 'The downloadable remains essential here because the higher-dimensional runtime ownership is not a browser claim.', ], }, { title: 'Studios, educators, and rollout owners', - description: 'The website matters most for teams that need distribution, launch, and support posture before training sessions begin.', + description: 'The website matters most for teams that need distribution, launch, and support status before training sessions begin.', bullets: [ 'Pricing, notices, support, launch status, docs, help, and browser-to-desktop handoff are deliberate operator surfaces.', 'This is the strongest reason the browser lane is still worth keeping even though the downloadable remains the main product.', @@ -1198,7 +1198,7 @@ export const helpCenterCards = [ description: 'The current input story is strong, but it is bounded and should be taught honestly.', bullets: [ 'Keyboard, mouse, touch, camera, immersive settings, selector continuity, and dedicated-family view ownership are already real.', - 'The current desktop-hosted OpenXR/controller widening boundary remains explicit No-Go until Windows packaged controller proof exists on the shipping lane; bounded runtime owners plus first-party controller settings/rebinding already exist underneath that gate.', + 'Broader headset/controller rollout waits for Windows packaged controller proof on the shipping lane; bounded runtime owners plus first-party controller settings/rebinding already exist underneath that gate.', ], }, { @@ -1217,7 +1217,7 @@ export const contactChannelCards = [ description: 'Use this when a real user session is blocked by account, entitlement, or rollout issues.', bullets: [ `Contact ${brandConfig.contact.email} for access, release enablement, desktop-link pairing trouble, or protected browser-lane follow-through.`, - 'Include the exact route, plan posture, requested platform, and whether the failure is public, protected, or native.', + 'Include the exact route, plan status, requested platform, and whether the failure is public, protected, or native.', ], }, { @@ -1225,14 +1225,14 @@ export const contactChannelCards = [ description: 'Use this when the downloadable itself behaves unexpectedly.', bullets: [ 'Name the affected lane: classic cube, recognition, replay/coaching, `Magic120Cell`, `MagicCube5D`, or `MagicTile`.', - 'Include build/channel context, control posture, and whether the issue is a real shipped regression or a still-explicit unfinished XR/controller expectation.', + 'Include build/channel context, control state, and whether the issue is a real shipped regression or a still-explicit unfinished headset/controller expectation.', ], }, { title: 'Studio rollout and commercial contact', description: 'Use this when the question is deployment, pricing, or broader rollout readiness rather than one operator session.', bullets: [ - 'Bundle plan, platform, launch posture, notices, and release expectations together so commercial follow-through stays attached to real package and legal truth.', + 'Bundle plan, platform, launch status, notices, and release expectations together so commercial follow-through stays attached to real package and legal truth.', 'Use this lane for production-oriented training programs, deployment review, and release-safe distribution planning.', ], }, @@ -1242,7 +1242,7 @@ export const publicManualRouteAtlasCards = [ { title: 'Home', route: '/', - description: 'Start here when you need the shortest truthful overview of the product, the browser-versus-desktop split, and the current release posture.', + description: 'Start here when you need the shortest truthful overview of the product, the browser-versus-desktop split, and the current release status.', bullets: [ 'Summarizes what HyperTwist already ships today.', 'Shows live public launch-readiness and packaged-proof context.', @@ -1264,7 +1264,7 @@ export const publicManualRouteAtlasCards = [ route: '/features', description: 'Open this page when you need capability truth instead of pitch language.', bullets: [ - 'Separates implemented now, retained, and frozen or gated branches.', + 'Separates implemented now, retained, and future validation branches.', 'Maps public website, protected dashboard, embedded browser shell, native runtime, and optional browser-client scope.', 'Surfaces higher-dimensional, control-roster, and release-maturity truth in one place.', ], @@ -1312,7 +1312,7 @@ export const publicManualRouteAtlasCards = [ { title: 'Launch status', route: '/launch-status', - description: 'Use this route when rollout truth, blockers, or preview-versus-public posture need one canonical authority page.', + description: 'Use this route when rollout truth, blockers, or early-access-versus-public status need one canonical authority page.', bullets: [ 'Shows the current launch-readiness checklist and hardening tracks.', 'Keeps packaged desktop proof and release references attached to rollout status.', @@ -1335,7 +1335,7 @@ export const publicManualRouteAtlasCards = [ description: 'Open this route when an operator needs help choosing the correct recovery or escalation lane.', bullets: [ 'Separates launch, access, rollout, package, runtime, and compliance questions.', - 'Keeps current release posture and packaged proof visible beside the help lanes.', + 'Keeps current release status and packaged proof visible beside the help lanes.', 'Mirrors the same browser-versus-desktop split so support does not soften product truth.', ], }, @@ -1346,25 +1346,25 @@ export const publicManualRouteAtlasCards = [ bullets: [ 'Provides the direct operator contact lane alongside what information to include for faster diagnosis.', 'Keeps runtime, rollout, account, and legal/commercial contacts separated instead of flattening them together.', - 'Links back to support topics, download posture, and public/protected route ownership as needed.', + 'Links back to support topics, download guidance, and public/protected route ownership as needed.', ], }, { title: 'Pricing', route: '/pricing', - description: 'Use this route when plan comparison or billing posture matters but the product topology still needs to stay honest.', + description: 'Use this route when plan comparison or billing status matters but the product topology still needs to stay honest.', bullets: [ 'Keeps plan language aligned with the desktop-first delivery model.', - 'Shows launch posture, package proof, and current auth-method lineup before checkout.', + 'Shows launch status, package proof, and current auth-method lineup before checkout.', 'Explains the path from browser entitlement into the protected release lane and native runtime.', ], }, { title: 'Download', route: '/download', - description: 'Open this route when you need platform targets, release posture, and the desktop handoff explained without exposing raw entitlement URLs.', + description: 'Open this route when you need platform targets, release status, and the desktop handoff explained without exposing raw entitlement URLs.', bullets: [ - 'Shows supported targets, package proof, and release-manifest posture.', + 'Shows supported targets, package proof, and release-manifest status.', 'Explains protected delivery, desktop-link pairing, and first native launch follow-through.', 'Keeps notices, distribution doctrine, and release references attached to install decisions.', ], @@ -1384,7 +1384,7 @@ export const publicManualRouteAtlasCards = [ route: '/open-source-notices', description: 'Open this route when legal-distribution and corresponding-source follow-through matter for downloadable builds.', bullets: [ - 'Lists key public notices and the current corresponding-source posture.', + 'Lists key public notices and the current corresponding-source status.', 'Keeps the legal lane tied to current release proof instead of abstract compliance prose.', 'Connects notices work back to download, release notes, and launch-readiness context.', ], @@ -1402,7 +1402,7 @@ export const publicManualRouteAtlasCards = [ { title: 'Terms', route: '/terms', - description: 'Open this route when you need the access model, protected-download boundary, and desktop delivery posture expressed as product terms.', + description: 'Open this route when you need the access model, protected-download boundary, and desktop delivery model expressed as product terms.', bullets: [ 'Keeps access, simulator, and redistribution obligations separated clearly.', 'Explains why the current browser shell does not equal simulator parity.', @@ -1412,10 +1412,10 @@ export const publicManualRouteAtlasCards = [ { title: 'Shipping & payment', route: '/shipping-payment', - description: 'Use this route when you need the digital-delivery model and payment posture explained operationally rather than cosmetically.', + description: 'Use this route when you need the digital-delivery model and payment status explained operationally rather than cosmetically.', bullets: [ 'Clarifies that HyperTwist is digitally delivered through browser account and desktop-release surfaces.', - 'Explains the handoff from checkout posture into protected entitlement and native runtime delivery.', + 'Explains the handoff from checkout into protected entitlement and native runtime delivery.', 'Keeps payment language attached to package proof, notices, and desktop-first truth.', ], }, @@ -1448,8 +1448,8 @@ export const releasePacketCards = [ category: 'Release integrity and package evidence', notes: [ 'Revalidated the exact-source browser surface and refreshed the packaged higher-dimensional proof so public release pages stay attached to current native evidence.', - 'Reran owned source and browser validation without widening product scope and kept the live preview lane green.', - 'Preserved the rule that native package proof, browser release posture, and legal-distribution follow-through move together.', + 'Reran owned source and browser validation without widening product scope and kept the live early-access lane green.', + 'Preserved the rule that native package proof, browser release status, and legal-distribution follow-through move together.', ], }, { @@ -1468,7 +1468,7 @@ export const releasePacketCards = [ category: 'Public routes, protected routes, and browser shell startup', notes: [ 'Added dedicated public launch-status and getting-started routes plus stronger protected launch authority so rollout truth stopped depending on scattered callouts.', - 'Improved browser auth behavior, startup loading posture, and public/protected route continuity without implying browser simulator parity.', + 'Improved browser auth behavior, startup loading state, and public/protected route continuity without implying browser simulator parity.', 'Turned the first real desktop-session path into a clearer public manual route instead of burying it across unrelated pages.', ], }, @@ -1488,7 +1488,7 @@ export const releasePacketCards = [ category: 'Phase 10 package integrity plus bounded browser/runtime expansion', notes: [ 'Closed package and integration hardening while keeping the embedded browser shell, release notes, and packaged-proof story aligned.', - 'Hardened MagicTile behavior proof without reopening native renderer widening and preserved the browser-host decision as the current honest shipping posture.', + 'Hardened MagicTile behavior proof without reopening native renderer widening and preserved the browser-host decision as the current honest shipping model.', 'Expanded the public site into a bounded operator/distribution surface around the downloadable rather than a replacement for it.', ], }, @@ -1503,7 +1503,7 @@ export const changelogEntries = [ { date: 'June 30, 2026', title: 'Downloadable operator manual now mirrors the richer public manual routes', - details: 'The same-origin offline operator manual is no longer the thinner sibling of the live website. It now mirrors the richer public/manual lane with browser-auth posture, protected release handoff, concrete desktop workflow tracks, the shipped control roster, higher-dimensional family guidance, operator adjunct families, recovery guidance, and a public/protected route atlas so rollout teams can carry one substantial offline reference without inventing a second product story.', + details: 'The same-origin offline operator manual is no longer the thinner sibling of the live website. It now mirrors the richer public/manual lane with browser-auth status, protected release handoff, concrete desktop workflow tracks, the shipped control roster, higher-dimensional family guidance, operator adjunct families, recovery guidance, and a public/protected route atlas so rollout teams can carry one substantial offline reference without inventing a second product story.', }, { date: 'June 30, 2026', @@ -1512,18 +1512,18 @@ export const changelogEntries = [ }, { date: 'June 30, 2026', - title: 'Native control-settings diagnostics now distinguish missing versus partial higher-dimensional ownership', - details: 'The desktop training-panel and coach-dashboard settings diagnostics no longer flatten every degraded 120-cell, 5D, or selector lane into one vague partial label. The current operator-facing formatter now keeps missing versus partial versus ready ownership explicit while still preserving the ready-side profile, selector, and continuity facts that actually exist.', + title: 'Native control-settings diagnostics now distinguish absent versus partial higher-dimensional ownership', + details: 'The desktop training-panel and coach-dashboard settings diagnostics no longer flatten every degraded 120-cell, 5D, or selector lane into one vague partial label. The current operator-facing formatter now keeps absent versus partial versus ready ownership explicit while still preserving the ready-side profile, selector, and continuity facts that actually exist.', }, { date: 'June 30, 2026', - title: 'Login and registration now preview the real desktop workflows too', - details: 'The public auth entry pages now keep a compact desktop-workflow preview beside the existing access and topology guidance, so operators can see the concrete classic-cube and recognition workflows they are signing in for before they ever cross into the protected browser shell.', + title: 'Login and registration now explain the real desktop workflows too', + details: 'The public auth entry pages now keep a compact desktop-workflow overview beside the existing access and topology guidance, so operators can see the concrete classic-cube and recognition workflows they are signing in for before they ever cross into the protected browser shell.', }, { date: 'June 30, 2026', title: 'Protected browser routes now teach the concrete desktop workflows too', - details: 'The signed-in dashboard, browser-access, download, and account routes now share a first-party protected workflow manual for classic-cube practice, recognition and correction, replay/coaching review, and higher-dimensional session use. Protected browser access now explains not only release and entitlement posture, but also what the installed software is actually used for once the browser handoff is complete.', + details: 'The signed-in dashboard, browser-access, download, and account routes now share a first-party protected workflow manual for classic-cube practice, recognition and correction, replay/coaching review, and higher-dimensional session use. Protected browser access now explains not only release and entitlement status, but also what the installed software is actually used for once the browser handoff is complete.', }, { date: 'June 30, 2026', @@ -1542,13 +1542,13 @@ export const changelogEntries = [ }, { date: 'June 29, 2026', - title: 'Protected launch surfaces now name the concrete live preview blockers too', - details: 'The signed-in dashboard and protected `/app/launch-status` lane now mirror the same concrete live blocker details already shown on the public launch surface. Instead of only generic missing-label prose, signed-in operators now see whether Windows release publication, operator/studio checkout, webhook secret, billing plan maps, shared-auth runtime readiness, or live runtime warnings are the actual remaining preview blockers.', + title: 'Protected launch surfaces now name the concrete live access blockers too', + details: 'The signed-in dashboard and protected `/app/launch-status` lane now mirror the same concrete live blocker details already shown on the public launch surface. Instead of only generic setup prose, signed-in operators now see whether Windows release publication, operator/studio checkout, webhook secret, billing plan maps, shared-auth runtime readiness, or live runtime warnings are the actual remaining access blockers.', }, { date: 'June 29, 2026', - title: 'Responsive route proof and live preview-readiness were revalidated again', - details: 'The owned web-surface umbrella was rerun with responsive Playwright coverage, keeping all major public and protected routes clean on mobile and tablet while the same-origin preview-readiness command also passed again against `https://hypertwist.app`. The current launch truth remains disciplined: the site is live and healthy in preview posture, while Windows download, Paddle checkout, webhook-secret, and loopback SuperTokens-core warnings still remain explicit instead of being blurred into a false public-launch claim.', + title: 'Responsive route proof and live early-access readiness were revalidated again', + details: 'The owned web-surface umbrella was rerun with responsive Playwright coverage, keeping all major public and protected routes clean on mobile and tablet while the same-origin readiness command also passed again against `https://hypertwist.app`. The current launch truth remains disciplined: the site is live and healthy in account-gated early access, while Windows download, Paddle checkout, webhook-secret, and loopback SuperTokens-core warnings still remain explicit instead of being blurred into a false public-launch claim.', }, { date: 'June 29, 2026', @@ -1588,27 +1588,27 @@ export const changelogEntries = [ { date: 'June 27, 2026', title: 'Launch status now has its own canonical public authority route', - details: 'HyperTwist now exposes a dedicated public `/launch-status` surface for the live launch-readiness checklist, rollout tracks, packaged desktop proof, release references, and the exact preview-versus-launch blockers, so launch truth no longer has to be reconstructed from pricing plus scattered callouts.', + details: 'HyperTwist now exposes a dedicated public `/launch-status` surface for the live launch-readiness checklist, rollout tracks, packaged desktop proof, release references, and exact early-access blockers, so launch truth no longer has to be reconstructed from pricing plus scattered callouts.', }, { date: 'June 27, 2026', title: 'A dedicated getting-started route now anchors the public onboarding story', - details: 'HyperTwist now has a crawlable public getting-started page that turns the current first-session path into one canonical manual surface: release-target choice, protected dashboard pairing, first native classic-cube verification, higher-dimensional verification, and the current XR/controller No-Go boundary all live together instead of staying spread across separate pages only.', + details: 'HyperTwist now has a crawlable public getting-started page that turns the current first-session path into one canonical manual surface: release-target choice, protected dashboard pairing, first native classic-cube verification, higher-dimensional verification, and the current headset/controller validation boundary all live together instead of staying spread across separate pages only.', }, { date: 'June 27, 2026', title: 'Public and protected manuals now show the first real desktop-session path more directly', - details: 'Homepage, docs, download, and the protected dashboard now share a tighter operator quickstart explaining the real end-to-end journey: choose the release target, pair the installed runtime through the desktop-link token, verify the first classic-cube session, open the higher-dimensional families, and read the current XR/controller No-Go boundary honestly.', + details: 'Homepage, docs, download, and the protected dashboard now share a tighter operator quickstart explaining the real end-to-end journey: choose the release target, pair the installed runtime through the desktop-link token, verify the first classic-cube session, open the higher-dimensional families, and read the current headset/controller validation boundary honestly.', }, { date: 'June 27, 2026', title: 'Protected dashboard and account routes now surface signed-in auth authority more explicitly', - details: 'The protected dashboard and account lanes now carry a fuller auth/session-authority surface instead of reducing signed-in browser identity to a thin auth-stack label. Operators can now see the signed-in method, current provider lineup, shared auth readiness, runtime origins, fallback posture, and deployment diagnostics directly inside the protected shell.', + details: 'The protected dashboard and account lanes now carry a fuller auth/session-authority surface instead of reducing signed-in browser identity to a thin auth-stack label. Operators can now see the signed-in method, current provider lineup, shared auth readiness, runtime origins, recovery state, and deployment diagnostics directly inside the protected shell.', }, { date: 'June 27, 2026', title: 'Shared browser auth now exposes real provider parity and public-manual account guidance', - details: 'HyperTwist no longer leaves ORCID as a UI-only placeholder: the auth server now owns a bounded custom ORCID provider, same-origin bundle rendering emits matching ORCID env flags, auth-health reports ORCID readiness, login and register both recover cleanly around provider redirects, and the public docs route now shows the real browser-account method lineup instead of hiding it inside the form pages alone.', + details: 'HyperTwist now gives ORCID a real shared-auth path: the auth server owns a bounded custom ORCID provider, same-origin bundle rendering emits matching ORCID env flags, auth-health reports ORCID readiness, login and register both recover cleanly around provider redirects, and the public docs route now shows the real browser-account method lineup instead of hiding it inside the form pages alone.', }, { date: 'June 27, 2026', @@ -1618,7 +1618,7 @@ export const changelogEntries = [ { date: 'June 27, 2026', title: 'Website startup now boots with centered first-paint shell and early shared-auth init', - details: 'The website entrypoint now initializes the shared SuperTokens posture before React root creation, and the public root document now ships a centered HyperTwist first-paint shell inside #root so public and protected routes no longer begin from a blank page while the first bundle loads.', + details: 'The website entrypoint now initializes the shared SuperTokens runtime before React root creation, and the public root document now ships a centered HyperTwist first-paint shell inside #root so public and protected routes no longer begin from a blank page while the first bundle loads.', }, { date: 'June 27, 2026', @@ -1633,7 +1633,7 @@ export const changelogEntries = [ { date: 'June 25, 2026', title: 'Public commerce pages now use the shared release-manifest view', - details: 'Pricing and Download now consume the same public release-manifest helper used across the rest of the site, removing duplicated manifest-resolution logic while keeping platform proof, fallback posture, and operator handoff behavior unchanged.', + details: 'Pricing and Download now consume the same public release-manifest helper used across the rest of the site, removing duplicated manifest-resolution logic while keeping platform proof, recovery behavior, and operator handoff behavior unchanged.', }, { date: 'June 24, 2026', @@ -1683,11 +1683,11 @@ export const changelogEntries = [ { date: 'June 24, 2026', title: 'Public and auth copy now reads as fully HyperTwist-owned', - details: 'Remaining public pricing, resources, capability, and auth-shell copy no longer references sibling-product shells or a generic broader product family. The live web surface now describes its structure and commerce posture in fully HyperTwist-native terms.', + details: 'Remaining public pricing, resources, capability, and auth-shell copy no longer references sibling-product shells or a generic broader product family. The live web surface now describes its structure and commerce model in fully HyperTwist-native terms.', }, { date: 'June 24, 2026', - title: 'About and Support now surface live launch posture plus packaged desktop proof', + title: 'About and Support now surface live launch status plus packaged desktop proof', details: 'The public About and Support pages no longer talk about maturity only in abstract terms. They now expose the same current launch-readiness callout and Windows packaged-proof section already used by the other public manual surfaces, so narrative, rollout, and help pages stay anchored to current native release evidence.', }, { @@ -1702,8 +1702,8 @@ export const changelogEntries = [ }, { date: 'June 24, 2026', - title: 'Auth and release fallback posture now reads as an operator workflow, not scattered warnings', - details: 'Login, protected-route loading, dashboard auth health, public/protected release-authority fallback surfaces, and the public docs/support manual now share a bounded recovery-guidance shape that preserves what still works, what stays intentionally withheld, and the next best move while live authority is degraded.', + title: 'Auth and release recovery now reads as an operator workflow, not scattered warnings', + details: 'Login, protected-route loading, dashboard auth health, public/protected release-authority recovery surfaces, and the public docs/support manual now share a bounded recovery-guidance shape that preserves what still works, what stays intentionally withheld, and the next best move while live authority is degraded.', }, { date: 'June 24, 2026', @@ -1717,8 +1717,8 @@ export const changelogEntries = [ }, { date: 'June 24, 2026', - title: 'XR host No-Go truth now renders end to end across native and public surfaces', - details: 'The native training and coach-dashboard control diagnostics now render the fixed desktop-hosted No-Go decision for OpenXR/controller widening directly in their operator-facing detail lines, the public/manual copy mirrors that same boundary language, and a later same-day hardening follow-up moved the same decision id plus reopen requirements into stable inspect-surface fields, with Browser-XrBoundaryStructured-PostBuild-Verify re-exporting all 20 HyperTwist.Browser tests green from the maintained Windows validation lane.', + title: 'Headset/controller host truth now renders end to end across native and public surfaces', + details: 'The native training and coach-dashboard control diagnostics now render the fixed desktop-hosted validation boundary for OpenXR/controller widening directly in their operator-facing detail lines, the public/manual copy mirrors that same boundary language, and a later same-day hardening follow-up moved the same decision id plus reopen requirements into stable inspect-surface fields, with Browser-XrBoundaryStructured-PostBuild-Verify re-exporting all 20 HyperTwist.Browser tests green from the maintained Windows validation lane.', }, { date: 'June 24, 2026', @@ -1738,7 +1738,7 @@ export const changelogEntries = [ { date: 'June 22, 2026', title: 'Public HyperTwist website, auth shell, and distribution surfaces landed', - details: 'A dedicated hypertwist.app app now exists for public pages, browser account access, download posture, public notices, and Paddle-ready pricing.', + details: 'A dedicated hypertwist.app app now exists for public pages, browser account access, download guidance, public notices, and Paddle-ready pricing.', }, { date: 'June 19, 2026', @@ -1747,8 +1747,8 @@ export const changelogEntries = [ }, { date: 'June 19, 2026', - title: 'MagicTile native behavior proof and renderer gate frozen', - details: 'The native behavior proof seam landed and the renderer-port decision remained explicit No-Go without new browser-host failure evidence.', + title: 'MagicTile native behavior proof and renderer decision held', + details: 'The native behavior proof seam landed and the renderer-port decision remained closed without new browser-host failure evidence.', }, { date: 'June 18, 2026', @@ -1769,13 +1769,13 @@ export const releaseRolloutChecklist = [ title: 'Confirm package proof before broad rollout', bullets: [ 'Pair the release note with the current packaged-validation summary so teams know whether a native change is merely implemented or also freshly package-proven.', - 'Use the protected download center when actual entitlement or package delivery posture matters.', + 'Use the protected download center when actual entitlement or package delivery status matters.', ], }, { title: 'Keep distribution and legal follow-through attached', bullets: [ - 'Review notices and corresponding-source posture before redistributing any build that contains covered code or newly widened package surfaces.', + 'Review notices and corresponding-source status before redistributing any build that contains covered code or newly widened package surfaces.', 'Keep public docs, release notes, and download guidance aligned so browser, package, and legal truths do not drift apart.', ], }, @@ -1813,11 +1813,11 @@ export const browserDesktopDecisionFaqs = [ }, { question: 'If the desktop app is primary, why keep the web version?', - answer: 'Because the browser shell owns the parts that should stay outside the simulator: public positioning, account access, billing, release posture, download gating, notices, support-safe rollout guidance, and browser-to-desktop pairing. It is intentionally inferior for the core simulator job: it does not own package-validated training behavior, low-latency native input, higher-dimensional packaged execution, or device/runtime integration authority. That narrower boundary is a strength, not a weakness, because it keeps the native runtime easier to trust, easier to operate, and easier to ship honestly.', + answer: 'Because the browser shell owns the parts that should stay outside the simulator: public positioning, account access, billing, release status, protected download access, notices, support-safe rollout guidance, and browser-to-desktop pairing. It is intentionally inferior for the core simulator job: it does not own package-validated training behavior, low-latency native input, higher-dimensional packaged execution, or device/runtime integration authority. That narrower boundary is a strength, not a weakness, because it keeps the native runtime easier to trust, easier to operate, and easier to ship honestly.', }, { question: 'Is VR/controller support already fully finished?', - answer: 'Not yet. HyperTwist already has real classic keyboard and mouse or touch ownership, viewer camera and immersive settings ownership, higher-dimensional selector and view ownership, EnhancedInput posture, motion-controller groundwork, a bounded OpenXR runtime owner, and first-party controller settings/rebinding ownership. But the broader host decision remains desktop-hosted No-Go on native OpenXR/controller widening until Windows packaged controller validation with controller truth exists on the shipping lane, so the software still should not market a finished headset/runtime branch.', + answer: 'Not yet. HyperTwist already has real classic keyboard and mouse or touch ownership, viewer camera and immersive settings ownership, higher-dimensional selector and view ownership, EnhancedInput setup, motion-controller groundwork, a bounded OpenXR runtime owner, and first-party controller settings/rebinding ownership. But the broader native OpenXR/controller lane still needs Windows packaged controller validation with controller truth before HyperTwist should market a finished headset/runtime branch.', }, ] @@ -1828,12 +1828,12 @@ export const supportFaqs = [ }, ...browserDesktopDecisionFaqs, { - question: 'Can I already customize controls and higher-dimensional view posture?', - answer: 'Partly. The current desktop runtime already owns the classic keyboard profile, viewer camera settings, bounded camera-export continuity, immersive-presence settings, session-local immersive recall, and higher-dimensional projection, focus, stereo, symmetry, and visibility defaults. The native operator surfaces now also expose which Magic120Cell or MagicCube5D session surface, interactive scene, persistence boundary, and state-semantics contract currently owns that settings lane, and they can recall selector posture from the latest persisted generated-mode launch request. The bounded XR desktop lane now also owns first-party controller settings, layout presets, and rebinding truth for the exact shipped XR input ids. What remains outside the current desktop-hosted No-Go lane is Windows packaged controller proof and broader launch-tier XR completion.', + question: 'Can I already customize controls and higher-dimensional view settings?', + answer: 'Partly. The current desktop runtime already owns the classic keyboard profile, viewer camera settings, bounded camera-export continuity, immersive-presence settings, session-local immersive recall, and higher-dimensional projection, focus, stereo, symmetry, and visibility defaults. The native operator surfaces now also expose which Magic120Cell or MagicCube5D session surface, interactive scene, persistence boundary, and state-semantics contract currently owns that settings lane, and they can recall selector state from the latest persisted generated-mode launch request. The bounded XR desktop lane now also owns first-party controller settings, layout presets, and rebinding truth for the exact shipped XR input ids. What remains outside the current shipping lane is Windows packaged controller proof and broader launch-tier XR completion.', }, { question: 'Do higher-dimensional selector choices persist between sessions?', - answer: 'They can now persist in a bounded way. When the desktop runtime has a structurally valid generated-mode launch request on hand, the native operator and training surfaces can recall that selector posture. That is useful real continuity, but it is still narrower than a full global preferences or controller-rebinding system.', + answer: 'They can now persist in a bounded way. When the desktop runtime has a structurally valid generated-mode launch request on hand, the native operator and training surfaces can recall that selector state. That is useful real continuity, but it is still narrower than a full global preferences or controller-rebinding system.', }, { question: 'Can I download a build immediately after sign-in?', @@ -1841,11 +1841,11 @@ export const supportFaqs = [ }, { question: 'Does HyperTwist already include voice or speech support?', - answer: 'Yes, in a bounded adjunct form. The live product already owns microphone capture, permission/readiness workflows, native capture-route control, transcript session envelopes, downloadable speech-model custody, Python transcription-service orchestration, local narration, and advanced voice-model review posture. Those are real operator-facing support surfaces around the simulator, not a claim that the website itself becomes the training runtime.', + answer: 'Yes, in a bounded adjunct form. The live product already owns microphone capture, permission/readiness workflows, native capture-route control, transcript session envelopes, downloadable speech-model custody, Python transcription-service orchestration, local narration, and advanced voice-model review state. Those are real operator-facing support surfaces around the simulator, not a claim that the website itself becomes the training runtime.', }, { question: 'Are provider routing and continuity features already real?', - answer: 'Yes, again in a bounded operator-grade form. HyperTwist already has provider-neutral speech or vision contracts, BYOK/profile custody, custom-endpoint routing, workflow-policy posture, usage/cost and settlement shells, plus continuity, memory, knowledge, notes, and provenance-aware replay or publication state families. These are adjunct governance and workflow surfaces around the simulator, not a claim that every external service is mandatory for core local training.', + answer: 'Yes, again in a bounded operator-grade form. HyperTwist already has provider-neutral speech or vision contracts, BYOK/profile custody, custom-endpoint routing, workflow-policy controls, usage/cost and settlement shells, plus continuity, memory, knowledge, notes, and provenance-aware replay or publication state families. These are adjunct governance and workflow surfaces around the simulator, not a claim that every external service is mandatory for core local training.', }, { question: 'Why is there an open-source notices page on pricing and download surfaces?', @@ -1875,15 +1875,15 @@ export const desktopFirstLaunchCards = [ description: 'Identity should pass through the bounded desktop-link handoff instead of through password reuse inside the runtime.', bullets: [ 'Open the protected dashboard and generate a desktop-link token.', - 'Use that token during first launch so the installed runtime inherits the correct account and entitlement posture.', + 'Use that token during first launch so the installed runtime inherits the correct account and entitlement status.', 'Return to the dashboard if the account, plan, or release lane changes later.', ], }, { title: 'Verify the current training lanes', - description: 'First launch should confirm the real simulator posture HyperTwist already claims publicly.', + description: 'First launch should confirm the real simulator state HyperTwist already claims publicly.', bullets: [ - 'Open the classic-cube training lane to confirm timing, replay, and coaching posture.', + 'Open the classic-cube training lane to confirm timing, replay, and coaching state.', 'Open the dedicated Magic120Cell or MagicCube5D training maps to confirm the higher-dimensional packaged lane.', 'Treat any unfinished XR/controller/preferences behavior as a later native packet, not as a first-launch surprise.', ], @@ -1905,7 +1905,7 @@ export const firstSessionVerificationCards = [ description: 'Treat the first session as a release-verified operator flow, not as a detached post-download guess.', bullets: [ 'Confirm the platform, channel, version/build id, and current packaged-validation summary on the public or protected download surface before deeper troubleshooting begins.', - 'Review release notes, notices, and corresponding-source posture before wider rollout or redistribution so the exact build story stays attached to the runtime you installed.', + 'Review release notes, notices, and corresponding-source status before wider rollout or redistribution so the exact build story stays attached to the runtime you installed.', 'Keep the protected release lane as the delivery authority instead of relying on stale browser tabs, screenshots, or remembered package assumptions.', ], }, @@ -1914,17 +1914,17 @@ export const firstSessionVerificationCards = [ description: 'The installed runtime should match the current public control truth before broader device expectations enter the session.', bullets: [ 'Confirm the shipped classic profile `classic-wca-keyboard/v1` together with pointer, orbit, zoom, hint, and hold-to-talk behavior so the first native session starts from the intended control baseline.', - 'Read camera-export continuity, immersive recall, and higher-dimensional selector posture as current bounded settings truth rather than as a finished global rebinding suite.', - 'Keep the desktop-hosted `No-Go` on native OpenXR/controller widening explicit instead of treating project groundwork as proof of finished VR or controller support.', + 'Read camera-export continuity, immersive recall, and higher-dimensional selector state as current bounded settings truth rather than as a finished global rebinding suite.', + 'Keep the packaged controller-validation boundary explicit instead of treating project groundwork as proof of finished VR or controller support.', ], }, { title: 'Verify the classic training lane', description: 'Classic-cube execution is the fastest way to confirm that the delivered desktop runtime matches current product truth.', bullets: [ - 'Launch the classic-cube lane and confirm timer, scramble, HUD, replay, coaching, and diagnostics posture before escalating a runtime issue outward.', + 'Launch the classic-cube lane and confirm timer, scramble, HUD, replay, coaching, and diagnostics state before escalating a runtime issue outward.', 'Treat recognition, reconstruction, and solve-guidance behavior as native runtime authority instead of expecting the public browser shell to reproduce those flows directly.', - 'Return to the browser shell only when account, release, entitlement, or support posture becomes the next actual job.', + 'Return to the browser shell only when account, release, entitlement, or support status becomes the next actual job.', ], }, { @@ -1932,7 +1932,7 @@ export const firstSessionVerificationCards = [ description: 'The serious 120-cell and 5D families should be confirmed intentionally, not inferred from broad capability claims.', bullets: [ 'Launch the dedicated `Magic120Cell` or `MagicCube5D` packaged training map from the desktop runtime instead of assuming browser parity.', - 'Confirm the current selector, projection, focus, symmetry or stereo, and visibility posture you intend to use before treating the session as higher-dimensional-ready.', + 'Confirm the current selector, projection, focus, symmetry or stereo, and visibility settings you intend to use before treating the session as higher-dimensional-ready.', 'Use native diagnostics when session, interactive-scene, persistence-boundary, or state-semantics ownership needs confirmation for a higher-dimensional issue report.', ], }, @@ -1941,10 +1941,10 @@ export const firstSessionVerificationCards = [ export const issueReportingChecklistCards = [ { title: 'Account, pairing, or entitlement issue report', - description: 'Support can move faster when account-facing failures stay attached to the exact browser surface and auth posture that produced them.', + description: 'Support can move faster when account-facing failures stay attached to the exact browser surface and auth state that produced them.', bullets: [ 'Include whether the failure happened on a public route or a protected route, and name the exact path such as `/login`, `/app`, or `/app/downloads`.', - 'State the current sign-in method and whether the UI showed normal, mixed, or fallback auth posture when the failure occurred.', + 'State the current sign-in method and whether the UI showed normal, mixed, or recovery-mode auth state when the failure occurred.', 'Call out whether the problem is sign-in, plan/entitlement visibility, desktop-link pairing, or protected release access rather than flattening them together.', ], }, @@ -1959,18 +1959,18 @@ export const issueReportingChecklistCards = [ }, { title: 'Runtime or training issue report', - description: 'Simulator bugs are easier to classify when the report keeps the actual runtime family and current control posture visible.', + description: 'Simulator bugs are easier to classify when the report keeps the actual runtime family and current control state visible.', bullets: [ 'State whether the issue affects classic-cube training, recognition, replay/coaching, `Magic120Cell`, `MagicCube5D`, or the `MagicTile` browser-host lane.', - 'Include the current control profile or settings lane when relevant, especially if the issue involves camera continuity, selector recall, or higher-dimensional view posture.', + 'Include the current control profile or settings lane when relevant, especially if the issue involves camera continuity, selector recall, or higher-dimensional view settings.', 'Separate a real shipped regression from the current explicit unfinished XR/controller/preferences widening so expected non-claims do not get filed as product breakage.', ], }, { title: 'Rollout, pricing, or compliance issue report', - description: 'Commercial and legal follow-through stay easier to resolve when they are reported as rollout posture issues rather than simulator defects.', + description: 'Commercial and legal follow-through stay easier to resolve when they are reported as rollout status issues rather than simulator defects.', bullets: [ - 'Include the route, checkout/source target, and whether the problem is public launch posture, billing/provisioning configuration, or legal-distribution follow-through.', + 'Include the route, checkout/source target, and whether the problem is public launch status, billing/provisioning configuration, or legal-distribution follow-through.', 'Keep pricing, notices, corresponding-source, and release-reference issues distinct from simulator bugs even when they were discovered during the same operator session.', 'Attach the current launch-status or release-note context when it materially explains why the public or protected shell could not complete the expected next move.', ], @@ -1980,7 +1980,7 @@ export const issueReportingChecklistCards = [ export const desktopReleaseSignals = [ { title: 'Package validation truth stays visible', - description: 'The public lane reflects the existing Phase 10B and 10C package-validation posture instead of pretending distribution is detached from real packaged proof.', + description: 'The public lane reflects the existing Phase 10B and 10C package-validation proof instead of pretending distribution is detached from real packaged evidence.', }, { title: 'Release access remains entitlement-aware', @@ -1997,8 +1997,8 @@ export const supportEscalationCards = [ title: 'Account and entitlement issues', description: 'Use the browser/operator lane first when the problem is access rather than simulator execution.', bullets: [ - 'Missing plan access, absent download buttons, or failed desktop-link pairing belong to the protected dashboard lane.', - 'Support should confirm auth, billing, and entitlement posture before troubleshooting simulator behavior.', + 'Absent plan access, unavailable download buttons, or failed desktop-link pairing belong to the protected dashboard lane.', + 'Support should confirm auth, billing, and entitlement status before troubleshooting simulator behavior.', 'Do not treat account-state issues as proof that the packaged runtime itself is broken.', ], }, @@ -2022,10 +2022,10 @@ export const supportEscalationCards = [ }, { title: 'Rollout and compliance issues', - description: 'When the question is about public launch safety, support should keep package, pricing, and legal posture tied together.', + description: 'When the question is about public launch safety, support should keep package, pricing, and legal status tied together.', bullets: [ 'Route pricing, notices, and corresponding-source questions through the public/support lane instead of improvising local answers.', - 'Treat public distribution pages as part of the shipped release posture.', + 'Treat public distribution pages as part of the shipped release status.', 'Keep release, payment, and legal guidance synchronized before broader operator rollout.', ], }, @@ -2034,7 +2034,7 @@ export const supportEscalationCards = [ export const companyNarrative = { mission: 'HyperTwist closes the gap between physical cubing practice, deep replay analysis, operator-grade coaching, and serious higher-dimensional puzzle study.', posture: - 'The product is intentionally honest about what already ships, what is retained and planned, and what remains optional or spec-only. That honesty is part of the platform quality bar.', + 'The product is intentionally honest about what already ships, what is planned, and what remains a future branch. That honesty is part of the platform quality bar.', distribution: 'The website exists to support public positioning, authenticated operator access, pricing, notices, and desktop distribution without pretending the browser itself already replaces the real desktop runtime.', contactEmail: brandConfig.contact.email, diff --git a/website/src/styles/global.css b/website/src/styles/global.css index ba392a8..77e6b64 100644 --- a/website/src/styles/global.css +++ b/website/src/styles/global.css @@ -17,6 +17,24 @@ --font-body: "IBM Plex Sans", system-ui, sans-serif; } +@property --glow-angle { + syntax: ''; + inherits: false; + initial-value: 0deg; +} + +@property --glow-x { + syntax: ''; + inherits: false; + initial-value: 50%; +} + +@property --glow-y { + syntax: ''; + inherits: false; + initial-value: 0%; +} + html[data-theme="light"] { --ht-bg: #f4f8ff; --ht-bg-2: #dbeaff; @@ -108,6 +126,14 @@ img { box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.04), 0 22px 60px rgba(0, 0, 0, 0.22); + transition: transform 220ms ease, opacity 220ms ease, border-color 220ms ease, box-shadow 220ms ease; + will-change: transform; +} + +.site-header--hidden { + transform: translateY(calc(-100% - 1.25rem)); + opacity: 0; + pointer-events: none; } .brand-mark { @@ -117,7 +143,13 @@ img { min-width: 0; } -.brand-mark__image, +.brand-mark__image { + width: clamp(6.5rem, 9vw, 9.72rem); + height: clamp(6.5rem, 9vw, 9.72rem); + object-fit: contain; + filter: drop-shadow(0 0 34px rgba(84, 203, 255, 0.3)); +} + .app-sidebar__brand-image { width: 5.4rem; height: 5.4rem; @@ -215,16 +247,25 @@ img { letter-spacing: 0.01em; cursor: pointer; transition: transform 160ms ease, background 160ms ease, border-color 160ms ease, color 160ms ease, box-shadow 160ms ease; + text-align: center; + white-space: nowrap; } .button:hover { transform: translateY(-1px); } +.button.pui-btn { + font-family: var(--font-body); +} + .button--primary { background: linear-gradient(120deg, var(--ht-amber), #ffc788); color: #09111d; - box-shadow: 0 14px 34px rgba(247, 178, 103, 0.24); + border-color: rgba(247, 178, 103, 0.72); + box-shadow: + 0 14px 34px rgba(247, 178, 103, 0.24), + 0 0 0 1px rgba(255, 255, 255, 0.08) inset; } .button--ghost { @@ -233,6 +274,14 @@ img { color: var(--ht-text); } +.button--secondary { + color: var(--ht-text); +} + +.theme-toggle { + min-width: 6.2rem; +} + .button--full { width: 100%; } @@ -463,10 +512,66 @@ img { } .card--pricing { + position: relative; + isolation: isolate; display: grid; gap: 1rem; } +.card--pricing::before { + content: ''; + position: absolute; + inset: -1px; + border-radius: inherit; + padding: 1px; + background: linear-gradient( + var(--glow-angle, 0deg), + rgba(84, 203, 255, 0), + rgba(84, 203, 255, 0.82), + rgba(247, 178, 103, 0.88), + rgba(84, 203, 255, 0) + ); + -webkit-mask: + linear-gradient(#fff 0 0) content-box, + linear-gradient(#fff 0 0); + -webkit-mask-composite: xor; + mask: + linear-gradient(#fff 0 0) content-box, + linear-gradient(#fff 0 0); + mask-composite: exclude; + pointer-events: none; + animation: glow-border-rotate 5.5s linear infinite; +} + +.card--pricing::after { + content: ''; + position: absolute; + inset: -2px; + z-index: -1; + border-radius: inherit; + background: radial-gradient( + ellipse at var(--glow-x, 50%) var(--glow-y, 0%), + rgba(247, 178, 103, 0.2) 0%, + rgba(84, 203, 255, 0.1) 34%, + transparent 70% + ); + pointer-events: none; + animation: glow-radial-sweep 5.5s ease-in-out infinite; +} + +@keyframes glow-border-rotate { + 0% { --glow-angle: 0deg; } + 100% { --glow-angle: 360deg; } +} + +@keyframes glow-radial-sweep { + 0% { --glow-x: 50%; --glow-y: 0%; opacity: 0.74; } + 25% { --glow-x: 100%; --glow-y: 50%; opacity: 1; } + 50% { --glow-x: 50%; --glow-y: 100%; opacity: 0.74; } + 75% { --glow-x: 0%; --glow-y: 50%; opacity: 1; } + 100% { --glow-x: 50%; --glow-y: 0%; opacity: 0.74; } +} + .top-gap { margin-top: 1rem; } @@ -774,6 +879,45 @@ img { color: var(--ht-text); } +.input-with-action { + position: relative; +} + +.input-with-action .input { + padding-right: 3rem; +} + +.input-action { + position: absolute; + top: 50%; + right: 0.65rem; + display: inline-grid; + width: 2rem; + height: 2rem; + place-items: center; + border: 1px solid transparent; + border-radius: 999px; + background: transparent; + color: var(--ht-muted); + cursor: pointer; + transition: color 160ms ease, background 160ms ease, border-color 160ms ease; + transform: translateY(-50%); +} + +.input-action:hover, +.input-action:focus-visible { + border-color: var(--ht-border); + background: var(--ht-cyan-soft); + color: var(--ht-text); + outline: none; +} + +.input-help { + margin: -0.25rem 0 0.35rem; + color: var(--ht-muted); + font-size: 0.85rem; +} + .input:focus { outline: 2px solid rgba(84, 203, 255, 0.24); outline-offset: 1px; @@ -1012,6 +1156,24 @@ code { } @media (max-width: 720px) { + .app-shell, + .app-main-shell { + min-width: 0; + max-width: 100vw; + overflow-x: clip; + } + + .app-sidebar { + width: calc(100% - 1rem); + max-width: calc(100vw - 1rem); + margin: 0.5rem; + box-sizing: border-box; + } + + .app-main-shell { + padding: 0 0.5rem 0.5rem; + } + .site-header, .page-main, .site-footer { @@ -1035,8 +1197,8 @@ code { } .brand-mark__image { - width: 4.4rem; - height: 4.4rem; + width: 6.2rem; + height: 6.2rem; } .button-row > * { diff --git a/website/tests/e2e/responsive-protected-app-routes.spec.ts b/website/tests/e2e/responsive-protected-app-routes.spec.ts index b71a94d..71e4e9e 100644 --- a/website/tests/e2e/responsive-protected-app-routes.spec.ts +++ b/website/tests/e2e/responsive-protected-app-routes.spec.ts @@ -22,7 +22,7 @@ const responsiveProtectedRoutes: readonly ProtectedRouteExpectation[] = [ }, { path: '/app/browser-access', - marker: 'Current browser posture', + marker: 'Current browser role', }, { path: '/app/account', diff --git a/website/tests/e2e/responsive-public-pages.spec.ts b/website/tests/e2e/responsive-public-pages.spec.ts index c64fcf3..a2173ec 100644 --- a/website/tests/e2e/responsive-public-pages.spec.ts +++ b/website/tests/e2e/responsive-public-pages.spec.ts @@ -16,7 +16,7 @@ const responsivePublicRoutes: readonly PublicRouteExpectation[] = [ }, { path: '/features', - heading: 'Feature truth without the roadmap archaeology.', + heading: 'Feature truth without the guesswork.', }, { path: '/about', @@ -44,7 +44,7 @@ const responsivePublicRoutes: readonly PublicRouteExpectation[] = [ }, { path: '/launch-status', - heading: 'See exactly what still separates preview from public launch.', + heading: 'See how public pages, account access, and desktop delivery work together.', }, { path: '/support', @@ -65,7 +65,7 @@ const responsivePublicRoutes: readonly PublicRouteExpectation[] = [ }, { path: '/privacy', - heading: 'Privacy posture', + heading: 'Privacy model', }, { path: '/terms',