Harden HyperTwist website access and public copy

This commit is contained in:
axiomlogicnexus 2026-07-03 03:32:15 +00:00
parent 85b851184e
commit a08e58fbcb
40 changed files with 1341 additions and 851 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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",

View file

@ -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",

View file

@ -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 () => ({

View file

@ -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()

View file

@ -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(<MarketingLaunchStatusBanner />)
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()
})
})

View file

@ -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()
})

View file

@ -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(<BrowserAccessPage />, '/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(<ProtectedLaunchStatusPage />, '/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(<NoticesPage />, '/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(<AccountPage />, '/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',

View file

@ -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')

View file

@ -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',

View file

@ -267,8 +267,8 @@ describe('public marketing pages', () => {
renderWithProviders(<DownloadPage />)
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(<DownloadPage />)
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(<HomeLanding />, ['/'])
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(<FeaturesPage />, ['/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(<HelpCenterPage />, ['/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(<ContactPage />, ['/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(<LaunchStatusPage />, ['/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(<LaunchStatusPage />, ['/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 () => {

View file

@ -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')

View file

@ -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<Props, State> {
<p>{this.state.error?.message || 'An unexpected error occurred loading this view.'}</p>
</div>
<div className="button-row">
<button type="button" className="button button--primary" onClick={this.handleRetry}>
<HyperTwistButton type="button" onClick={this.handleRetry}>
Retry this view
</button>
<button
</HyperTwistButton>
<HyperTwistButton
type="button"
className="button button--ghost"
tone="ghost"
onClick={() => window.location.assign('/')}
>
Return to homepage
</button>
</HyperTwistButton>
</div>
</div>
</div>

View file

@ -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() {
</p>
<ul className="list top-gap">
<li><Link to="/app/launch-status">Protected launch status</Link></li>
<li><Link to="/download">Public download posture</Link></li>
<li><Link to="/download">Public download guidance</Link></li>
<li><Link to="/open-source-notices">Public notices</Link></li>
<li><Link to={buildSupportPath('operator-access')}>Operator access support</Link></li>
</ul>
</div>
<button type="button" className="button button--ghost button--full" onClick={toggleColorMode}>
<HyperTwistButton type="button" tone="ghost" className="button--full" onClick={toggleColorMode}>
Switch to {colorMode === 'dark' ? 'light' : 'dark'} mode
</button>
<button type="button" className="button button--ghost button--full" onClick={() => void logout()}>
</HyperTwistButton>
<HyperTwistButton type="button" tone="ghost" className="button--full" onClick={() => void logout()}>
Log out
</button>
</HyperTwistButton>
</div>
</aside>

View file

@ -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 = (
<section className="product-reality-strip" aria-label="Current HyperTwist product reality">
@ -13,18 +16,18 @@ export const publicProductRealityStrip = (
</article>
<article className="product-reality-strip__item">
<p className="eyebrow">Web purpose</p>
<strong>Access and rollout</strong>
<p>The browser owns docs, account, pricing, notices, release posture, and desktop pairing.</p>
<strong>Access and guidance</strong>
<p>The browser owns docs, accounts, pricing, notices, protected downloads, and desktop pairing.</p>
</article>
<article className="product-reality-strip__item">
<p className="eyebrow">Ready today</p>
<strong>Keyboard and mouse</strong>
<p>Desktop control surfaces are usable for development and operator review without a headset.</p>
<p>Desktop controls support serious keyboard, mouse, touch, camera, replay, and training work without a headset.</p>
</article>
<article className="product-reality-strip__item">
<p className="eyebrow">Still gated</p>
<strong>Launch config and XR proof</strong>
<p>Public download, Paddle, live auth, and headset/controller observation remain explicit gates.</p>
<p className="eyebrow">Account delivery</p>
<strong>Account-gated delivery</strong>
<p>Public pages explain the product; signed-in dashboard routes handle release access and pairing.</p>
</article>
</section>
)
@ -41,22 +44,58 @@ export const compactProductRealityStrip = (
</article>
<article className="product-reality-strip__item">
<p className="eyebrow">Web purpose</p>
<strong>Access and rollout</strong>
<p>The browser owns docs, account, pricing, notices, release posture, and desktop pairing.</p>
<strong>Access and guidance</strong>
<p>The browser owns docs, accounts, pricing, notices, protected downloads, and desktop pairing.</p>
</article>
<article className="product-reality-strip__item">
<p className="eyebrow">Ready today</p>
<strong>Keyboard and mouse</strong>
<p>Desktop control surfaces are usable for development and operator review without a headset.</p>
<p>Desktop controls support serious keyboard, mouse, touch, camera, replay, and training work without a headset.</p>
</article>
<article className="product-reality-strip__item">
<p className="eyebrow">Still gated</p>
<strong>Launch config and XR proof</strong>
<p>Public download, Paddle, live auth, and headset/controller observation remain explicit gates.</p>
<p className="eyebrow">Account delivery</p>
<strong>Account-gated delivery</strong>
<p>Public pages explain the product; signed-in dashboard routes handle release access and pairing.</p>
</article>
</section>
)
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 (
<div className="site-shell">
<header className="site-header">
<header className={`site-header${isHeaderHidden ? ' site-header--hidden' : ''}`}>
<Link to="/" className="brand-mark">
<img
src="/branding/hypertwist-3d-symbol.png"
@ -111,12 +151,22 @@ export function MarketingShell({
))}
</nav>
<div className="site-header__actions">
<Link className="button button--ghost" to={isAuthenticated ? '/app' : '/login'}>
<HyperTwistButton
tone="ghost"
type="button"
aria-label={`Switch to ${colorMode === 'dark' ? 'light' : 'dark'} mode`}
onClick={toggleColorMode}
className="theme-toggle"
>
{colorMode === 'dark' ? <Sun size={17} /> : <Moon size={17} />}
<span>{colorMode === 'dark' ? 'Light' : 'Dark'}</span>
</HyperTwistButton>
<HyperTwistButtonLink tone="ghost" to={isAuthenticated ? '/app' : '/login'}>
{isAuthenticated ? 'Open dashboard' : 'Log in'}
</Link>
<Link className="button button--primary" to="/download">
</HyperTwistButtonLink>
<HyperTwistButtonLink to={isAuthenticated ? '/app/downloads?platform=windows' : '/register?next=%2Fapp%2Fdownloads%3Fplatform%3Dwindows'}>
Get desktop app
</Link>
</HyperTwistButtonLink>
</div>
</header>
@ -139,12 +189,12 @@ export function MarketingShell({
Contact: <a href={brandConfig.contact.emailHref}>{brandConfig.contact.email}</a>
</p>
<div className="button-row top-gap">
<Link className="button button--primary" to="/download">
<HyperTwistButtonLink to={isAuthenticated ? '/app/downloads?platform=windows' : '/register?next=%2Fapp%2Fdownloads%3Fplatform%3Dwindows'}>
Get desktop app
</Link>
<Link className="button button--ghost" to={isAuthenticated ? '/app' : '/login'}>
</HyperTwistButtonLink>
<HyperTwistButtonLink tone="ghost" to={isAuthenticated ? '/app' : '/login'}>
{isAuthenticated ? 'Account dashboard' : 'Account access'}
</Link>
</HyperTwistButtonLink>
</div>
</div>
<div className="site-footer__grid">

View file

@ -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() {
<GeneralPageLoader
title="Loading operator access..."
eyebrow="Browser account access"
description="Checking your saved browser session, protected release posture, and browser-to-desktop continuity before the operator shell opens."
description="Checking your saved browser session, protected release status, and browser-to-desktop continuity before the operator shell opens."
fullscreen
showBrand
>
<div className="button-row general-page-loader-actions">
<Link className="button button--ghost" to={loginRedirectTarget}>
<HyperTwistButtonLink tone="ghost" to={loginRedirectTarget}>
Open sign-in
</Link>
<Link className="button button--ghost" to={buildSupportPath('operator-access')}>
</HyperTwistButtonLink>
<HyperTwistButtonLink tone="ghost" to={buildSupportPath('operator-access')}>
Open support
</Link>
</HyperTwistButtonLink>
</div>
</GeneralPageLoader>
)

View file

@ -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 (
<div>

View file

@ -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<LinkProps, 'to'> & {
to: LinkProps['to']
tone?: HyperTwistButtonTone
size?: ButtonSize
full?: boolean
children: ReactNode
}) {
return (
<PerformativeButton
as={Link}
to={to}
size={size}
variant={resolvePerformativeVariant(tone)}
sparkle={tone === 'primary'}
block={full}
className={buildClassName({ tone, full, className })}
{...props}
>
{children}
</PerformativeButton>
)
}
export function HyperTwistButton({
tone = 'primary',
size = 'md',
full,
className,
children,
...props
}: ButtonHTMLAttributes<HTMLButtonElement> & {
tone?: HyperTwistButtonTone
size?: ButtonSize
full?: boolean
children: ReactNode
}) {
return (
<PerformativeButton
as="button"
size={size}
variant={resolvePerformativeVariant(tone)}
sparkle={tone === 'primary'}
block={full}
className={buildClassName({ tone, full, className })}
{...props}
>
{children}
</PerformativeButton>
)
}
export function HyperTwistButtonAnchor({
href,
tone = 'primary',
size = 'md',
full,
className,
children,
...props
}: AnchorHTMLAttributes<HTMLAnchorElement> & {
href: string
tone?: HyperTwistButtonTone
size?: ButtonSize
full?: boolean
children: ReactNode
}) {
return (
<PerformativeButton
as="a"
href={href}
size={size}
variant={resolvePerformativeVariant(tone)}
sparkle={tone === 'primary'}
block={full}
className={buildClassName({ tone, full, className })}
{...props}
>
{children}
</PerformativeButton>
)
}

View file

@ -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({
<div className="button-row top-gap">
{actions.map((action) => (
isExternalHref(action.to) ? (
<a
<HyperTwistButtonAnchor
key={action.label}
className="button button--ghost"
href={action.to}
target="_blank"
rel="noreferrer"
tone="ghost"
>
{action.label}
</a>
</HyperTwistButtonAnchor>
) : (
<Link key={action.label} className="button button--ghost" to={action.to}>
<HyperTwistButtonLink key={action.label} tone="ghost" to={action.to}>
{action.label}
</Link>
</HyperTwistButtonLink>
)
))}
</div>

View file

@ -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() {
<article className="callout site-status-banner">
<div className="status-row">
<p className={`status-pill${ready ? ' status-pill--success' : ''}`}>
{ready ? 'Launch-ready posture' : 'Preview posture'}
{ready ? 'Public launch ready' : 'Early access'}
</p>
<strong>Public site status</strong>
</div>
<p>{buildMarketingLaunchStatusSummary(ready, liveBlockerDetails, missingLabels)}</p>
<div className="status-row">
<Link className="inline-link" to="/launch-status">
View launch posture
View access status
</Link>
<Link className="inline-link" to={buildProtectedDownloadPath('windows')}>
Open protected release lane
Open signed-in downloads
</Link>
</div>
</article>
@ -97,33 +89,30 @@ export function PublicLaunchStatus({
}: {
title?: string
}) {
const { authHealthQuery, checklist, launchStatus, liveBlockerDetails, missingLabels, ready } = usePublicLaunchStatus()
const { authHealthQuery, launchStatus, liveBlockerDetails, ready } = usePublicLaunchStatus()
return (
<article className="callout">
<p className={`status-pill${ready ? ' status-pill--success' : ''}`}>
{ready ? 'Launch-ready posture' : 'Preview posture'}
{ready ? 'Public launch ready' : 'Account-gated early access'}
</p>
<h3>{title}</h3>
<p>
{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.'}
</p>
<ul className="list">
{checklist.map((item) => (
<li key={item.id}>
{item.label}: {item.configured
? (item.id === 'public-auth-runtime' ? 'production-ready' : 'configured')
: (item.id === 'public-auth-runtime' ? 'local-or-mixed' : 'missing')}
</li>
))}
<li>Operator checkout target: {launchStatus.targets.operatorCheckoutTarget || 'support fallback active'}</li>
<li>Studio checkout target: {launchStatus.targets.studioCheckoutTarget || 'support fallback active'}</li>
<li>Desktop app access: routed through account creation or sign-in before package delivery.</li>
<li>Browser version: available as the public/protected account, docs, release, pricing, and pairing shell, not as simulator parity.</li>
<li>Subscription access: managed on the website/dashboard and handed to the downloadable through desktop-link pairing.</li>
<li>Download authority: protected dashboard first; anonymous public pages explain targets without exposing raw package delivery.</li>
<li>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'}.</li>
<li>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'}.</li>
</ul>
{liveBlockerDetails.length > 0 ? (
{ready && liveBlockerDetails.length > 0 ? (
<div className="callout top-gap">
<p>{ready ? 'Live runtime notes' : 'Current preview blockers from the live auth runtime'}</p>
<p>Current runtime notes</p>
<ul className="list">
{liveBlockerDetails.map((item) => (
<li key={item}>{item}</li>
@ -132,21 +121,21 @@ export function PublicLaunchStatus({
</div>
) : null}
{authHealthQuery.isLoading ? (
<p>Checking live launch-readiness posture from the deployed auth server.</p>
<p>Checking current account and release access status.</p>
) : null}
{authHealthQuery.isError ? (
<p className="form-error">
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.
</p>
) : null}
{!ready ? (
<div className="button-row top-gap">
<Link className="button button--ghost" to={buildProtectedDownloadPath('windows')}>
Open protected release lane
</Link>
<Link className="button button--ghost" to="/app/notices">
<HyperTwistButtonLink tone="ghost" to={buildProtectedDownloadPath('windows')}>
Open signed-in downloads
</HyperTwistButtonLink>
<HyperTwistButtonLink tone="ghost" to="/app/notices">
Open protected notices
</Link>
</HyperTwistButtonLink>
</div>
) : null}
</article>

View file

@ -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({
<Panel title={title} kicker={kicker}>
<ul className="list">
<li>Signed-in method: {formatAuthMethodLabel(user?.authMethod)}</li>
<li>Auth stack: {superTokensConfigured ? 'SuperTokens-backed' : 'Local fallback mode'}</li>
<li>Auth stack: {superTokensConfigured ? 'SuperTokens-backed' : 'Local recovery mode'}</li>
{healthQuery.data ? (
<>
<li>Shared auth configured: {healthQuery.data.supertokens.configured ? 'yes' : 'no'}</li>
@ -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'}
</li>
<li>
Fallback posture: {healthQuery.data.fallback.active
Recovery mode: {healthQuery.data.fallback.active
? `active${healthQuery.data.fallback.reason ? ` (${healthQuery.data.fallback.reason})` : ''}`
: 'inactive'}
</li>
@ -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 ? (
<OperationalStatusCallout
badge="Dashboard fallback posture"
badge="Dashboard recovery mode"
title="Shared auth core is not fully ready right now."
summary={`Dashboard fallback posture remains available${healthQuery.data.fallback.reason ? ` (${healthQuery.data.fallback.reason})` : ''}.`}
summary={`Dashboard recovery mode remains available${healthQuery.data.fallback.reason ? ` (${healthQuery.data.fallback.reason})` : ''}.`}
sections={[
{
title: 'What still works',
@ -320,43 +321,43 @@ function ReleaseAuthorityLinks({
return (
<div className="button-row top-gap">
<a className="button button--ghost" href={downloadablePublicManualHref} download>
<HyperTwistButtonAnchor tone="ghost" href={downloadablePublicManualHref} download>
Download operator manual (.md)
</a>
</HyperTwistButtonAnchor>
{releaseManifest.public_docs_url ? (
<a className="button button--ghost" href={releaseManifest.public_docs_url} target="_blank" rel="noreferrer">
<HyperTwistButtonAnchor tone="ghost" href={releaseManifest.public_docs_url} target="_blank" rel="noreferrer">
Public docs
</a>
</HyperTwistButtonAnchor>
) : null}
{releaseManifest.release_notes_url ? (
<a className="button button--ghost" href={releaseManifest.release_notes_url} target="_blank" rel="noreferrer">
<HyperTwistButtonAnchor tone="ghost" href={releaseManifest.release_notes_url} target="_blank" rel="noreferrer">
Release notes
</a>
</HyperTwistButtonAnchor>
) : null}
{releaseManifest.corresponding_source_url ? (
<a className="button button--ghost" href={releaseManifest.corresponding_source_url} target="_blank" rel="noreferrer">
<HyperTwistButtonAnchor tone="ghost" href={releaseManifest.corresponding_source_url} target="_blank" rel="noreferrer">
Corresponding source
</a>
</HyperTwistButtonAnchor>
) : null}
{releaseManifest.open_source_repo_url ? (
<a className="button button--ghost" href={releaseManifest.open_source_repo_url} target="_blank" rel="noreferrer">
<HyperTwistButtonAnchor tone="ghost" href={releaseManifest.open_source_repo_url} target="_blank" rel="noreferrer">
Repository/notices
</a>
</HyperTwistButtonAnchor>
) : null}
{includeProtectedLaunchStatusLink ? (
<Link className="button button--ghost" to="/app/launch-status">
<HyperTwistButtonLink tone="ghost" to="/app/launch-status">
Protected launch status
</Link>
</HyperTwistButtonLink>
) : null}
{includeProtectedNoticesLink ? (
<Link className="button button--ghost" to="/app/notices">
<HyperTwistButtonLink tone="ghost" to="/app/notices">
Protected notices
</Link>
</HyperTwistButtonLink>
) : null}
{includePublicNoticesLink ? (
<Link className="button button--ghost" to="/open-source-notices">
<HyperTwistButtonLink tone="ghost" to="/open-source-notices">
Public notices
</Link>
</HyperTwistButtonLink>
) : null}
</div>
)
@ -482,22 +483,22 @@ function ProtectedLaunchReadinessPanel({
<Panel title={title} kicker={kicker}>
{description ? <p>{description}</p> : null}
<p className={`status-pill${launchStatus.ready ? ' status-pill--success' : ''}`}>
{launchStatus.ready ? 'Launch-ready posture' : 'Preview posture'}
{launchStatus.ready ? 'Launch-ready status' : 'Early-access status'}
</p>
<ul className="list">
{launchStatus.checklist.map((item) => (
<li key={item.id}>
{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')}
</li>
))}
<li>Operator checkout target: {launchStatus.targets.operatorCheckoutTarget || 'support fallback active'}</li>
<li>Studio checkout target: {launchStatus.targets.studioCheckoutTarget || 'support fallback active'}</li>
<li>Operator checkout target: {launchStatus.targets.operatorCheckoutTarget || 'support follow-up active'}</li>
<li>Studio checkout target: {launchStatus.targets.studioCheckoutTarget || 'support follow-up active'}</li>
</ul>
{liveBlockerDetails.length > 0 ? (
<div className="callout top-gap">
<p>{launchStatus.ready ? 'Live runtime notes' : 'Current preview blockers from the live auth runtime'}</p>
<p>{launchStatus.ready ? 'Live runtime notes' : 'Current early-access blockers from the live auth runtime'}</p>
<ul className="list">
{liveBlockerDetails.map((item) => (
<li key={item}>{item}</li>
@ -510,11 +511,11 @@ function ProtectedLaunchReadinessPanel({
) : null}
{releaseManifestQuery.isError ? (
<ProtectedReleaseAuthorityNotice
badge="Dashboard release fallback"
badge="Dashboard release recovery"
title="Live release-manifest lookup failed."
summary="Download readiness is currently using local fallback metadata rather than current runtime release authority."
summary="Download readiness is currently using local recovery metadata rather than current runtime release authority."
stillWorks={[
'Protected launch-readiness interpretation, packaged proof, and account posture remain visible.',
'Protected launch-readiness interpretation, packaged proof, and account status remain visible.',
'The protected browser shell can still separate auth, package, runtime, and rollout work while release authority recovers.',
]}
actionTo="/app/downloads"
@ -531,9 +532,9 @@ function ProtectedLaunchReadinessPanel({
{actions.length > 0 ? (
<div className="button-row top-gap">
{actions.map((action) => (
<Link key={`${title}-${action.label}`} className="button button--ghost" to={action.to}>
<HyperTwistButtonLink key={`${title}-${action.label}`} tone="ghost" to={action.to}>
{action.label}
</Link>
</HyperTwistButtonLink>
))}
</div>
) : 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({
</ul>
<div className="button-row top-gap">
{topic.actions.map((action) => (
<Link key={`${topic.topicKey}-${action.label}`} className="button button--ghost" to={action.to}>
<HyperTwistButtonLink key={`${topic.topicKey}-${action.label}`} tone="ghost" to={action.to}>
{action.label}
</Link>
</HyperTwistButtonLink>
))}
</div>
</article>
@ -1018,15 +1019,15 @@ function OperatorDesktopQuickstartPanel({
))}
</div>
<div className="button-row top-gap">
<Link className="button button--ghost" to="/app/downloads">
<HyperTwistButtonLink tone="ghost" to="/app/downloads">
Open downloads
</Link>
<Link className="button button--ghost" to="/app/browser-access">
</HyperTwistButtonLink>
<HyperTwistButtonLink tone="ghost" to="/app/browser-access">
Open browser access
</Link>
<Link className="button button--ghost" to="/docs">
</HyperTwistButtonLink>
<HyperTwistButtonLink tone="ghost" to="/docs">
Open public manual
</Link>
</HyperTwistButtonLink>
</div>
</Panel>
)
@ -1062,15 +1063,15 @@ function ProtectedSoftwareWorkflowPanel({
))}
</div>
<div className="button-row top-gap">
<Link className="button button--ghost" to="/app/downloads">
<HyperTwistButtonLink tone="ghost" to="/app/downloads">
Open downloads
</Link>
<Link className="button button--ghost" to="/app/browser-access">
</HyperTwistButtonLink>
<HyperTwistButtonLink tone="ghost" to="/app/browser-access">
Open browser access
</Link>
<Link className="button button--ghost" to="/docs">
</HyperTwistButtonLink>
<HyperTwistButtonLink tone="ghost" to="/docs">
Open public manual
</Link>
</HyperTwistButtonLink>
</div>
</Panel>
)
@ -1107,12 +1108,12 @@ function SupportEscalationChecklist({
))}
</div>
<div className="button-row top-gap">
<Link className="button button--ghost" to={buildSupportPath('operator-access')}>
<HyperTwistButtonLink tone="ghost" to={buildSupportPath('operator-access')}>
Open support
</Link>
<Link className="button button--ghost" to={secondaryLink.to}>
</HyperTwistButtonLink>
<HyperTwistButtonLink tone="ghost" to={secondaryLink.to}>
{secondaryLink.label}
</Link>
</HyperTwistButtonLink>
</div>
</Panel>
)
@ -1142,9 +1143,9 @@ function ProtectedOperatorQuickRoutesPanel({
</ul>
<div className="button-row top-gap">
{topic.actions.map((action) => (
<Link key={`${topic.topicKey}-${action.label}`} className="button button--ghost" to={action.to}>
<HyperTwistButtonLink key={`${topic.topicKey}-${action.label}`} tone="ghost" to={action.to}>
{action.label}
</Link>
</HyperTwistButtonLink>
))}
</div>
</article>
@ -1243,9 +1244,9 @@ function ProtectedBrowserDesktopRealityPanel({
))}
</ul>
<div className="button-row top-gap">
<Link className="button button--ghost" to={action.to}>
<HyperTwistButtonLink tone="ghost" to={action.to}>
{action.label}
</Link>
</HyperTwistButtonLink>
</div>
</article>
)
@ -1295,7 +1296,7 @@ export function DashboardOverviewPage() {
<>
<SiteMetadata
title="HyperTwist dashboard"
description="Open the protected HyperTwist dashboard for account state, auth health, billing posture, release readiness, and desktop-link pairing."
description="Open the protected HyperTwist dashboard for account state, auth health, billing status, release readiness, and desktop-link pairing."
canonicalPath="/app"
robots="noindex,nofollow"
/>
@ -1308,7 +1309,7 @@ export function DashboardOverviewPage() {
<p>Desktop downloads: {user?.canDownload ? 'enabled' : 'not yet entitled'}</p>
{!superTokensConfigured || user?.billing?.source === 'local-fallback' ? (
<p className="form-error">
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.
</p>
) : null}
{releaseManifestQuery.data?.manifest && releaseAuthoritySyncItems.length > 0 ? (
@ -1336,14 +1337,13 @@ export function DashboardOverviewPage() {
<Panel title="Desktop-link pairing" kicker="Browser to desktop handoff">
<p>Generate a short-lived token so the local desktop runtime can verify your browser session without exposing account credentials.</p>
<button
className="button button--primary"
<HyperTwistButton
type="button"
onClick={() => desktopLinkMutation.mutate()}
disabled={desktopLinkMutation.isPending}
>
{desktopLinkMutation.isPending ? 'Generating token...' : 'Generate desktop-link token'}
</button>
</HyperTwistButton>
{desktopLinkMutation.isError ? (
<p className="form-error">Could not generate a token. Ensure the auth server is reachable and your session is valid.</p>
) : null}
@ -1365,7 +1365,7 @@ export function DashboardOverviewPage() {
<ProtectedSoftwareWorkflowPanel
title="Software workflows after access is resolved"
kicker="Protected simulator-use manual"
description="The protected dashboard should also say what the installed software is actually for once access, pairing, and release posture are already settled."
description="The protected dashboard should also say what the installed software is actually for once access, pairing, and release status are already settled."
limit={4}
/>
@ -1407,7 +1407,7 @@ export function DashboardOverviewPage() {
<ProtectedBrowserDesktopRealityPanel
title="Protected browser-versus-desktop reality"
kicker="Signed-in product boundary"
description="Sign-in should not blur the same truth the public manual now states plainly: the browser lane handles account, release, and pairing work, the desktop runtime remains simulator authority, and unfinished XR/controller widening still stays behind an explicit boundary."
description="Sign-in should not blur the same truth the public manual now states plainly: the browser lane handles account, release, and pairing work, the desktop runtime remains simulator authority, and headset/controller widening still requires packaged validation."
/>
<PackagedValidationPanel
@ -1432,7 +1432,7 @@ export function DashboardOverviewPage() {
<Panel title="Current product-surface map" kicker="Operator orientation">
<p>
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.
</p>
<div className="top-gap">
<ProductSurfaceMatrix rows={productSurfaceMatrixRows} />
@ -1472,7 +1472,7 @@ export function ProtectedLaunchStatusPage() {
<>
<SiteMetadata
title="HyperTwist protected launch status"
description="Review the signed-in HyperTwist launch-readiness posture, release action, package proof, and rollout references."
description="Review the signed-in HyperTwist launch-readiness status, release action, package proof, and rollout references."
canonicalPath="/app/launch-status"
robots="noindex,nofollow"
/>
@ -1524,7 +1524,7 @@ export function ProtectedLaunchStatusPage() {
<ProtectedReleaseReferencesPanel
title="Launch references and notices"
kicker="Distribution follow-through"
description="Rollout posture is only trustworthy when docs, release notes, corresponding source, public notices, and protected notices remain reachable from the same signed-in launch surface."
description="Rollout status is only trustworthy when docs, release notes, corresponding source, public notices, and protected notices remain reachable from the same signed-in launch surface."
releaseManifest={releaseManifest}
/>
@ -1572,19 +1572,19 @@ export function DownloadCenterPage() {
<div className="panel-grid">
{releaseManifestQuery.isLoading ? (
<Panel title="Release manifest status" kicker="Runtime authority">
<p>Loading the current server-backed release manifest. Local fallback metadata remains visible until the live manifest arrives.</p>
<p>Loading the current server-backed release manifest. Local recovery metadata remains visible until the live manifest arrives.</p>
</Panel>
) : null}
{releaseManifestQuery.isError ? (
<Panel title="Release manifest status" kicker="Runtime authority">
<ProtectedReleaseAuthorityNotice
badge="Protected release fallback"
badge="Protected release recovery"
title="The live release manifest could not be loaded from the auth server right now."
summary="This panel is showing bounded fallback site metadata instead of current runtime release authority, and direct package delivery remains intentionally withheld until the auth server returns."
summary="This panel is showing bounded recovery metadata instead of current runtime release authority, and direct package delivery remains intentionally withheld until the auth server returns."
stillWorks={[
'Requested platform targeting, packaged proof, and protected rollout guidance remain visible.',
'Signed-in entitlement posture can still be reviewed without pretending the missing manifest is live authority.',
'Signed-in entitlement status can still be reviewed without pretending the unavailable manifest is live authority.',
]}
actionTo="/app"
actionLabel="Open dashboard"
@ -1609,7 +1609,7 @@ export function DownloadCenterPage() {
) : null}
{releaseAuthorityUnavailable && viewerCanDownload ? (
<div className="callout top-gap">
<p className="status-pill status-pill--info">Fallback release posture</p>
<p className="status-pill status-pill--info">Release recovery mode</p>
<p>
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}
<ReleaseValidationSummary platform={target} />
{target.download_url && viewerCanDownload ? (
<a className="button button--primary button--full" href={target.download_url}>
<HyperTwistButtonAnchor className="button--full" href={target.download_url}>
Download {target.platform}
</a>
</HyperTwistButtonAnchor>
) : (
<div className="button button--ghost button--full is-disabled" aria-disabled="true">
{getProtectedDownloadActionLabel({
@ -1748,23 +1748,23 @@ export function BrowserAccessPage() {
<>
<SiteMetadata
title="HyperTwist browser access"
description="Review the HyperTwist browser-access boundary, embedded browser posture, and the still-frozen optional full-browser branch."
description="Review the HyperTwist browser-access boundary, embedded browser role, and the still-future optional full-browser branch."
canonicalPath="/app/browser-access"
robots="noindex,nofollow"
/>
<div className="panel-grid">
<Panel title="Current browser posture" kicker="Shipping lane">
<Panel title="Current browser role" kicker="Shipping lane">
<ul className="list">
<li>The embedded browser/CEF shell is live and owned as part of the current shipping posture.</li>
<li>The embedded browser/CEF shell is live and owned as part of the current shipping model.</li>
<li>Browser runtime status, runtime-ready typing, and native operator diagnostics are already surfaced in the desktop runtime.</li>
<li>The public browser dashboard is for operator/account/release access, not a claim of full simulator parity.</li>
</ul>
{healthQuery.isLoading ? <p>Checking current browser-shell auth posture...</p> : null}
{healthQuery.isLoading ? <p>Checking current browser-shell auth state...</p> : null}
{healthQuery.isError ? (
<OperationalStatusCallout
badge="Browser access fallback"
title="Runtime auth-health could not be loaded."
summary="The page is still using the bounded dashboard posture rather than claiming browser-simulator parity."
summary="The page is still using the bounded dashboard role rather than claiming browser-simulator parity."
sections={[
{
title: 'What still works',
@ -1802,12 +1802,12 @@ export function BrowserAccessPage() {
))}
</ul>
<div className="button-row top-gap">
<Link className="button button--ghost" to="/app">
<HyperTwistButtonLink tone="ghost" to="/app">
Open dashboard
</Link>
<Link className="button button--ghost" to="/app/downloads">
</HyperTwistButtonLink>
<HyperTwistButtonLink tone="ghost" to="/app/downloads">
Open downloads
</Link>
</HyperTwistButtonLink>
</div>
</Panel>
<ProtectedSoftwareWorkflowPanel
@ -1835,9 +1835,9 @@ export function BrowserAccessPage() {
<Panel title="Release authority around the browser shell" kicker="Distribution context">
{releaseManifestQuery.isError ? (
<ProtectedReleaseAuthorityNotice
badge="Browser-access release fallback"
badge="Browser-access release recovery"
title="Live release-manifest lookup failed."
summary="Browser-shell release context is currently using fallback metadata instead of current auth-server authority."
summary="Browser-shell release context is currently using recovery metadata instead of current auth-server authority."
stillWorks={[
'Browser-to-desktop handoff guidance, packaged proof, and support references remain available.',
'This route can still show the bounded browser-shell role without claiming live release authority.',
@ -1873,7 +1873,7 @@ export function BrowserAccessPage() {
<Panel title="Optional branches remain bounded" kicker="Not widened here">
<ul className="list">
<li>The optional full-browser client remains spec-only.</li>
<li>MagicTile native renderer widening remains explicit No-Go until a real browser-host gap is proven.</li>
<li>MagicTile native renderer widening remains closed unless a real browser-host gap is proven.</li>
<li>This dashboard intentionally stays above those boundaries instead of silently crossing them.</li>
</ul>
<ul className="list top-gap">
@ -1905,7 +1905,7 @@ export function AccountPage() {
<>
<SiteMetadata
title="HyperTwist account"
description="Inspect your protected HyperTwist account profile, plan, billing posture, and auth stack mode."
description="Inspect your protected HyperTwist account profile, plan, billing status, and auth stack mode."
canonicalPath="/app/account"
robots="noindex,nofollow"
/>
@ -1942,14 +1942,14 @@ export function AccountPage() {
healthQuery={healthQuery}
/>
<Panel title="Entitlement and release access" kicker="Protected release lane">
{releaseManifestQuery.isLoading ? <p>Refreshing release-access posture from the live manifest...</p> : null}
{releaseManifestQuery.isLoading ? <p>Refreshing release-access status from the live manifest...</p> : null}
{releaseManifestQuery.isError ? (
<ProtectedReleaseAuthorityNotice
badge="Account release fallback"
badge="Account release recovery"
title="Live release-manifest lookup failed."
summary="This account view is using bounded fallback metadata until auth-server release authority returns."
summary="This account view is using bounded recovery metadata until auth-server release authority returns."
stillWorks={[
'Signed-in profile, entitlement posture, and packaged proof remain visible.',
'Signed-in profile, entitlement status, and packaged proof remain visible.',
'Protected follow-through links still keep account, download, notices, and support separated.',
]}
actionTo="/app"
@ -1994,11 +1994,11 @@ export function AccountPage() {
<ProtectedBrowserDesktopRealityPanel
title="Protected browser-versus-desktop reality"
kicker="Signed-in product boundary"
description="Account posture should not make the browser shell sound like simulator ownership. This signed-in account route keeps the same explicit browser-versus-desktop split visible while plan, entitlement, and release-access state are being reviewed."
description="Account status should not make the browser shell sound like simulator ownership. This signed-in account route keeps the same explicit browser-versus-desktop split visible while plan, entitlement, and release-access state are being reviewed."
/>
<ControlRosterManualPanel
title="Current simulator control ownership"
kicker="Signed-in runtime posture"
kicker="Signed-in runtime state"
description="Your account and entitlement state matter here, but the real simulator still lives on the desktop side. This roster keeps the current control/settings truth visible after sign-in instead of dropping back to a thinner account-only shell."
/>
<Panel title="Account follow-through" kicker="Next actions">
@ -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.
</p>
<div className="button-row top-gap">
<Link className="button button--ghost" to="/app">
<HyperTwistButtonLink tone="ghost" to="/app">
Open dashboard
</Link>
<Link className="button button--ghost" to="/app/downloads">
</HyperTwistButtonLink>
<HyperTwistButtonLink tone="ghost" to="/app/downloads">
Open downloads
</Link>
<Link className="button button--ghost" to="/app/notices">
</HyperTwistButtonLink>
<HyperTwistButtonLink tone="ghost" to="/app/notices">
Review notices
</Link>
<Link className="button button--ghost" to={buildSupportPath('operator-access')}>
</HyperTwistButtonLink>
<HyperTwistButtonLink tone="ghost" to={buildSupportPath('operator-access')}>
Get help
</Link>
</HyperTwistButtonLink>
</div>
<ReleaseAuthorityLinks
releaseManifest={releaseManifest}
@ -2029,7 +2029,7 @@ export function AccountPage() {
<ProtectedSoftwareWorkflowPanel
title="Desktop workflows available to this account"
kicker="Protected simulator-use manual"
description="Account, plan, and entitlement posture exist to unlock real native workflows. This panel keeps those practical simulator uses visible after sign-in."
description="Account, plan, and entitlement status exist to unlock real native workflows. This panel keeps those practical simulator uses visible after sign-in."
limit={4}
/>
@ -2053,23 +2053,23 @@ export function NoticesPage() {
<>
<SiteMetadata
title="HyperTwist notices"
description="Review the protected HyperTwist distribution notices posture and corresponding-source requirements for downloadable builds."
description="Review the protected HyperTwist distribution notices and corresponding-source requirements for downloadable builds."
canonicalPath="/app/notices"
robots="noindex,nofollow"
/>
<div className="panel-grid">
<Panel title="Distribution notices" kicker="Legal posture">
<Panel title="Distribution notices" kicker="Legal follow-through">
<p>
Pricing, checkout, and download surfaces must expose open-source notices and corresponding-source guidance whenever shipped builds contain MPL-covered material.
</p>
{releaseManifestQuery.isLoading ? <p>Refreshing notices posture from the live release manifest...</p> : null}
{releaseManifestQuery.isLoading ? <p>Refreshing notices status from the live release manifest...</p> : null}
{releaseManifestQuery.isError ? (
<ProtectedReleaseAuthorityNotice
badge="Notices fallback"
badge="Notices recovery"
title="Live release-manifest lookup failed."
summary="This page is using bounded fallback notice metadata until auth-server release authority returns."
summary="This page is using bounded recovery notice metadata until auth-server release authority returns."
stillWorks={[
'Protected notice references, corresponding-source posture, and packaged proof remain visible.',
'Protected notice references, corresponding-source status, and packaged proof remain visible.',
'Operators can still keep distribution work separate from runtime and entitlement work while authority recovers.',
]}
actionTo="/app/downloads"
@ -2079,8 +2079,8 @@ export function NoticesPage() {
<ul className="list top-gap">
<li>Configured release targets: {configuredPlatforms.length}/{releaseManifest.platforms.length}</li>
<li>Viewer download access: {releaseManifest.viewer.canDownload ? 'enabled' : 'not yet enabled'}</li>
<li>Public repository/notices URL: {releaseManifest.open_source_repo_url || 'configure the public repository/notices URL before launch'}</li>
<li>Corresponding-source URL: {releaseManifest.corresponding_source_url || 'configure the corresponding-source URL before public launch'}</li>
<li>Public repository/notices URL: {releaseManifest.open_source_repo_url || 'add the public repository/notices URL before wider launch'}</li>
<li>Corresponding-source URL: {releaseManifest.corresponding_source_url || 'add the corresponding-source URL before wider launch'}</li>
</ul>
</Panel>
<ProtectedReleaseActionPanel
@ -2092,14 +2092,14 @@ export function NoticesPage() {
<Panel title="Operator obligations" kicker="Keep aligned">
<ul className="list">
<li>Keep pricing, download, and notices surfaces aligned whenever a public downloadable build is offered.</li>
<li>Keep release notes and package proof reachable so public audiences can see what build posture is actually being distributed.</li>
<li>Keep release notes and package proof reachable so public audiences can see what build state is actually being distributed.</li>
<li>Do not present browser access as simulator parity just because distribution/legal pages are live.</li>
</ul>
{releaseManifest.platforms.length > 0 ? (
<ul className="list top-gap">
{releaseManifest.platforms.map((platform) => (
<li key={platform.platform_key}>
{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}` : ''}
</li>
))}
</ul>
@ -2108,7 +2108,7 @@ export function NoticesPage() {
<PackagedValidationPanel
title={protectedPackagedDesktopProofTitle}
kicker="Distribution evidence"
description="This protected notices lane now keeps the downloadable release story tied to the current Windows desktop package proof instead of only naming validation abstractly. That makes notices, corresponding source, and package posture easier to read together."
description="This protected notices lane now keeps the downloadable release story tied to the current Windows desktop package proof instead of only naming validation abstractly. That makes notices, corresponding source, and package status easier to read together."
emptyMessage="The current protected notices route could not find a Windows release target, so packaged desktop evidence is unavailable here right now."
releaseManifest={releaseManifest}
/>

View file

@ -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() {
<article className="card card--compact">
<h3>What the desktop runtime is for once you are signed in</h3>
<p>
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.
</p>
</article>
{desktopWorkflowTracks.slice(0, 2).map((track) => (
@ -198,7 +201,7 @@ function AuthBrowserDesktopRealityPanel() {
<h2>Browser account access does not replace the simulator.</h2>
<p>
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.
</p>
<div className="card-grid top-gap">
{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 (
<OperationalStatusCallout
badge={authRuntimeValidation.ready ? 'Auth launch warning' : 'Auth fallback posture'}
badge={authRuntimeValidation.ready ? 'Auth launch notice' : 'Auth recovery mode'}
title={
authRuntimeValidation.ready
? 'Shared browser auth is present, but launch posture is still mixed.'
: 'Shared browser auth is not fully in production posture yet.'
? 'Account access is available while launch configuration is being finalized.'
: 'Account access can continue through the available browser-auth lane.'
}
summary={
authRuntimeValidation.ready
? 'Browser sign-in can still continue, but launch-facing auth warnings should be cleared before this surface is treated as fully production-ready.'
: 'Local fallback mode may activate until the required auth env vars are configured.'
? 'You can still sign in, create an account, and continue into protected dashboard routes. Operator diagnostics keep the deeper auth warnings visible after sign-in.'
: 'If shared auth is temporarily unavailable, HyperTwist keeps account routing recoverable so you can still review product access and support paths.'
}
sections={[
{
title: 'What still works',
items: [
'Login, registration, and safe next-step routing remain available.',
'The protected dashboard can still recover bounded account, release, and desktop-pairing posture after sign-in.',
'The protected dashboard can still recover bounded account, release, and desktop-pairing status after sign-in.',
],
},
{
@ -264,14 +267,14 @@ function AuthRuntimeNotice() {
title: 'Recommended recovery order',
items: [
authRuntimeValidation.ready
? 'Clear the remaining mixed-mode warnings before public launch so browser auth, protected release access, and account state share one production authority.'
: 'Configure the missing auth runtime values first, then re-check non-loopback HTTPS origins before public launch.',
? 'Continue into the dashboard for account-aware status, downloads, and desktop-link pairing.'
: 'Use account creation for orientation now; contact support if you need production release access immediately.',
],
},
]}
actions={[
{ label: 'Open support', to: buildSupportPath('operator-access') },
{ label: 'Review download posture', to: '/download' },
{ label: 'Review download access', to: '/download' },
]}
/>
)
@ -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() {
<AuthNextStepNotice nextPath={nextPath} />
<form className="auth-form" onSubmit={handleSubmit}>
<label className="input-label" htmlFor="login-email">Email</label>
<input id="login-email" className="input" value={email} onChange={(event) => setEmail(event.target.value)} />
<input
id="login-email"
className="input"
type="email"
autoComplete="email"
required
value={email}
onChange={(event) => setEmail(event.target.value)}
/>
<label className="input-label" htmlFor="login-password">Password</label>
<input id="login-password" className="input" type="password" value={password} onChange={(event) => setPassword(event.target.value)} />
<div className="input-with-action">
<input
id="login-password"
className="input"
type={showPassword ? 'text' : 'password'}
autoComplete="current-password"
required
value={password}
onChange={(event) => setPassword(event.target.value)}
/>
<button
type="button"
className="input-action"
aria-label={showPassword ? 'Hide password' : 'Show password'}
onClick={() => setShowPassword((current) => !current)}
>
{showPassword ? <EyeOff size={17} /> : <Eye size={17} />}
</button>
</div>
{error ? <p className="form-error">{error}</p> : null}
<button className="button button--primary button--full" disabled={isSubmitting} type="submit">
<HyperTwistButton full disabled={isSubmitting} type="submit">
{isSubmitting ? 'Signing in...' : 'Log in'}
</button>
</HyperTwistButton>
</form>
<div className="provider-row">
{isGoogleOAuthEnabled() ? (
<button className="button button--ghost button--full" disabled={oauthLoading !== null} type="button" onClick={() => void handleOAuth('google')}>
<HyperTwistButton full tone="ghost" disabled={oauthLoading !== null} type="button" onClick={() => void handleOAuth('google')}>
{oauthLoading === 'google' ? 'Redirecting to Google...' : 'Continue with Google'}
</button>
</HyperTwistButton>
) : null}
{isGitHubOAuthEnabled() ? (
<button className="button button--ghost button--full" disabled={oauthLoading !== null} type="button" onClick={() => void handleOAuth('github')}>
<HyperTwistButton full tone="ghost" disabled={oauthLoading !== null} type="button" onClick={() => void handleOAuth('github')}>
{oauthLoading === 'github' ? 'Redirecting to GitHub...' : 'Continue with GitHub'}
</button>
</HyperTwistButton>
) : null}
{isOrcidOAuthEnabled() ? (
<button className="button button--ghost button--full" disabled={oauthLoading !== null} type="button" onClick={() => void handleOAuth('orcid')}>
<HyperTwistButton full tone="ghost" disabled={oauthLoading !== null} type="button" onClick={() => void handleOAuth('orcid')}>
{oauthLoading === 'orcid' ? 'Redirecting to ORCID...' : 'Continue with ORCID'}
</button>
</HyperTwistButton>
) : null}
</div>
<AuthBrowserDesktopRealityPanel />
@ -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() {
<>
<SiteMetadata
title="Create a HyperTwist account"
description="Create a HyperTwist account to unlock the browser dashboard, release posture, and desktop-link pairing for the desktop simulator lane."
description="Create a HyperTwist account to unlock the browser dashboard, release status, and desktop-link pairing for the desktop simulator lane."
canonicalPath="/register"
robots="noindex,nofollow"
/>
<AuthShell
title="Create a HyperTwist account"
subtitle="This unlocks the browser dashboard, release posture, and desktop-link pairing for the simulator lane."
subtitle="Create an account to reach the protected dashboard, desktop download center, release notes, entitlement state, and browser-to-desktop pairing."
footer={<p>Already have access? <Link to={`/login?next=${encodeURIComponent(nextPath)}`}>Log in</Link>.</p>}
>
<AuthRuntimeNotice />
<AuthNextStepNotice nextPath={nextPath} />
<form className="auth-form" onSubmit={handleSubmit}>
<label className="input-label" htmlFor="register-name">Name</label>
<input id="register-name" className="input" value={name} onChange={(event) => setName(event.target.value)} />
<input
id="register-name"
className="input"
type="text"
autoComplete="name"
value={name}
onChange={(event) => setName(event.target.value)}
/>
<label className="input-label" htmlFor="register-email">Email</label>
<input id="register-email" className="input" value={email} onChange={(event) => setEmail(event.target.value)} />
<input
id="register-email"
className="input"
type="email"
autoComplete="email"
required
value={email}
onChange={(event) => setEmail(event.target.value)}
/>
<label className="input-label" htmlFor="register-password">Password</label>
<input id="register-password" className="input" type="password" value={password} onChange={(event) => setPassword(event.target.value)} />
<div className="input-with-action">
<input
id="register-password"
className="input"
type={showPassword ? 'text' : 'password'}
autoComplete="new-password"
required
minLength={8}
placeholder={PASSWORD_POLICY_PLACEHOLDER}
value={password}
onChange={(event) => setPassword(event.target.value)}
/>
<button
type="button"
className="input-action"
aria-label={showPassword ? 'Hide password' : 'Show password'}
onClick={() => setShowPassword((current) => !current)}
>
{showPassword ? <EyeOff size={17} /> : <Eye size={17} />}
</button>
</div>
<p className="input-help">{PASSWORD_POLICY_HINT}</p>
{error ? <p className="form-error">{error}</p> : null}
<button className="button button--primary button--full" disabled={isSubmitting} type="submit">
<HyperTwistButton full disabled={isSubmitting} type="submit">
{isSubmitting ? 'Creating account...' : 'Create account'}
</button>
</HyperTwistButton>
</form>
<div className="provider-row">
{isGoogleOAuthEnabled() ? (
<button className="button button--ghost button--full" disabled={oauthLoading !== null} type="button" onClick={() => void handleOAuth('google')}>
<HyperTwistButton full tone="ghost" disabled={oauthLoading !== null} type="button" onClick={() => void handleOAuth('google')}>
{oauthLoading === 'google' ? 'Redirecting to Google...' : 'Continue with Google'}
</button>
</HyperTwistButton>
) : null}
{isGitHubOAuthEnabled() ? (
<button className="button button--ghost button--full" disabled={oauthLoading !== null} type="button" onClick={() => void handleOAuth('github')}>
<HyperTwistButton full tone="ghost" disabled={oauthLoading !== null} type="button" onClick={() => void handleOAuth('github')}>
{oauthLoading === 'github' ? 'Redirecting to GitHub...' : 'Continue with GitHub'}
</button>
</HyperTwistButton>
) : null}
{isOrcidOAuthEnabled() ? (
<button className="button button--ghost button--full" disabled={oauthLoading !== null} type="button" onClick={() => void handleOAuth('orcid')}>
<HyperTwistButton full tone="ghost" disabled={oauthLoading !== null} type="button" onClick={() => void handleOAuth('orcid')}>
{oauthLoading === 'orcid' ? 'Redirecting to ORCID...' : 'Continue with ORCID'}
</button>
</HyperTwistButton>
) : null}
</div>
<AuthBrowserDesktopRealityPanel />

View file

@ -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<string, SupportTopicGuide> = {
'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<string, SupportTopicGuide> = {
'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<string, SupportTopicGuide> = {
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({
))}
</ul>
<div className="button-row top-gap">
<Link className="button button--ghost" to={card.action.to}>
<HyperTwistButtonLink tone="ghost" to={card.action.to}>
{card.action.label}
</Link>
</HyperTwistButtonLink>
</div>
</article>
))}
@ -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({
))}
</ul>
<div className="button-row top-gap">
<Link className="button button--ghost" to={card.action.to}>
<HyperTwistButtonLink tone="ghost" to={card.action.to}>
{card.action.label}
</Link>
</HyperTwistButtonLink>
</div>
</article>
))}
@ -366,15 +367,15 @@ export function OperatorDesktopQuickstartSection({
))}
</div>
<div className="button-row top-gap">
<Link className="button button--ghost" to="/download">
<HyperTwistButtonLink tone="ghost" to="/download">
Open download center
</Link>
<Link className="button button--ghost" to="/app">
</HyperTwistButtonLink>
<HyperTwistButtonLink tone="ghost" to="/app">
Open operator dashboard
</Link>
<Link className="button button--ghost" to="/docs">
</HyperTwistButtonLink>
<HyperTwistButtonLink tone="ghost" to="/docs">
Open public manual
</Link>
</HyperTwistButtonLink>
</div>
</Section>
)
@ -398,18 +399,18 @@ export function DownloadableOperatorManualSection({
<ul className="list top-gap">
<li>Use it for desktop-side onboarding, rollout review, and operator support when the browser shell is not the best reading surface.</li>
<li>It stays aligned with the current public route atlas instead of inventing a separate product story.</li>
<li>It keeps the current desktop-hosted XR/controller `No-Go` boundary explicit instead of flattening it into generic VR support language.</li>
<li>It keeps the current headset/controller validation boundary explicit instead of flattening it into generic VR support language.</li>
</ul>
<div className="button-row top-gap">
<a className="button button--primary" href={downloadablePublicManualHref} download>
<HyperTwistButtonAnchor href={downloadablePublicManualHref} download>
Download offline operator manual
</a>
<Link className="button button--ghost" to="/docs">
</HyperTwistButtonAnchor>
<HyperTwistButtonLink tone="ghost" to="/docs">
Open public manual
</Link>
<Link className="button button--ghost" to="/getting-started">
</HyperTwistButtonLink>
<HyperTwistButtonLink tone="ghost" to="/getting-started">
Open getting started
</Link>
</HyperTwistButtonLink>
</div>
</article>
</Section>
@ -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({
</ul>
<div className="button-row top-gap">
{topic.actions.map((action) => (
<Link key={`${topic.topicKey}-${action.label}`} className="button button--ghost" to={action.to}>
<HyperTwistButtonLink key={`${topic.topicKey}-${action.label}`} tone="ghost" to={action.to}>
{action.label}
</Link>
</HyperTwistButtonLink>
))}
</div>
</article>
@ -714,9 +715,9 @@ export function PublicManualRouteAtlasSection({
))}
</ul>
<div className="button-row top-gap">
<Link className="button button--ghost" to={card.route}>
<HyperTwistButtonLink tone="ghost" to={card.route}>
Open {card.title}
</Link>
</HyperTwistButtonLink>
</div>
</article>
))}
@ -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 ? (
<div className="button-row top-gap">
{actions.map((action) => (
<Link key={`${action.to}-${action.label}`} className="button button--ghost" to={action.to}>
<HyperTwistButtonLink key={`${action.to}-${action.label}`} tone="ghost" to={action.to}>
{action.label}
</Link>
</HyperTwistButtonLink>
))}
</div>
) : 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 (
<a className={className} href={to} target="_blank" rel="noreferrer">
<HyperTwistButtonAnchor className={className} tone="ghost" href={to} target="_blank" rel="noreferrer">
{label}
</a>
</HyperTwistButtonAnchor>
)
}
return (
<Link className={className} to={to}>
<HyperTwistButtonLink className={className} tone="ghost" to={to}>
{label}
</Link>
</HyperTwistButtonLink>
)
}
@ -1093,15 +1094,15 @@ export function PublicReleaseDecisionGuideSection({
export function PlanActionLink({ href, label }: { href: string; label: string }) {
if (isExternalHref(href)) {
return (
<a className="button button--primary button--full" href={href} target="_blank" rel="noreferrer">
<HyperTwistButtonAnchor full href={href} target="_blank" rel="noreferrer">
{label}
</a>
</HyperTwistButtonAnchor>
)
}
return (
<Link className="button button--primary button--full" to={href}>
<HyperTwistButtonLink full to={href}>
{label}
</Link>
</HyperTwistButtonLink>
)
}

View file

@ -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() {
<>
<SiteMetadata
title="HyperTwist pricing"
description="View HyperTwist browser-access, operator, and studio pricing with Paddle-ready checkout posture and launch-honest download/legal guidance."
description="View HyperTwist browser-access, operator, and studio pricing with Paddle-ready checkout, account-gated downloads, and launch-honest legal guidance."
canonicalPath="/pricing"
/>
<MarketingShell
@ -111,7 +112,7 @@ export function PricingPage() {
cards={browserLimitCards}
/>
<Section title="Launch posture">
<Section title="Launch access status">
<PublicLaunchStatus />
</Section>
@ -156,7 +157,7 @@ export function PricingPage() {
<BulletCardSection
title="Current input and runtime control truth"
description="The pricing page should also be explicit about the present control quality bar so buyers can see what is real today and what still remains gated."
description="The pricing page should also be explicit about the present control quality bar so buyers can see what is real today and what remains in later device validation."
cards={[...inputAndDevicePostureCards, ...runtimeControlGuideCards]}
/>
@ -171,14 +172,14 @@ export function PricingPage() {
<Section
title="Why plans live in the browser while training stays native"
description="Commercial access, entitlement, and launch-readiness posture belong to the browser shell so the simulator can stay focused on training quality."
description="Commercial access, entitlement, and launch-readiness status belong to the browser shell so the simulator can stay focused on training quality."
>
<DeliverySurfaceResponsibilitiesGrid limit={3} />
</Section>
<BulletCardSection
title="Commercial distribution doctrine"
description="Commercial pages should stay as explicit about release and legal posture as the rest of the public site."
description="Commercial pages should stay as explicit about release and legal follow-through as the rest of the public site."
cards={distributionDoctrineCards}
/>
@ -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.
</p>
<div className="button-row top-gap">
<Link className="button button--ghost" to="/browser">
<HyperTwistButtonLink to="/browser" tone="ghost">
Open browser guide
</Link>
<Link className="button button--ghost" to="/help">
</HyperTwistButtonLink>
<HyperTwistButtonLink to="/help" tone="ghost">
Open help center
</Link>
<Link className="button button--primary" to="/contact">
</HyperTwistButtonLink>
<HyperTwistButtonLink to="/contact">
Contact HyperTwist
</Link>
</HyperTwistButtonLink>
</div>
</article>
</Section>
@ -224,7 +225,7 @@ function ReleaseManifestStatusSections({
{isLoading ? (
<Section title="Release manifest status">
<article className="callout">
<p>Loading the current server-backed release manifest. Static preview metadata remains visible until the live manifest arrives.</p>
<p>Loading the current server-backed release manifest. Static target guidance remains visible until live release authority arrives.</p>
</article>
</Section>
) : null}
@ -232,9 +233,9 @@ function ReleaseManifestStatusSections({
{isError ? (
<Section title="Release manifest status">
<OperationalStatusCallout
badge="Public release fallback"
badge="Release service recovery"
title="The live release manifest could not be loaded from the auth server right now."
summary="This page is showing bounded fallback site metadata instead of current runtime release authority, and direct package delivery stays intentionally withheld until that authority returns."
summary="This page is showing bounded static target guidance instead of current runtime release authority, and direct package delivery stays intentionally withheld until that authority returns."
sections={[
{
title: 'What still works',
@ -254,12 +255,12 @@ function ReleaseManifestStatusSections({
title: 'Recommended recovery order',
items: [
'Use the protected dashboard once the auth server recovers if you need actual package delivery.',
'Open operator support if release-authority fallback persists during rollout or purchase work.',
'Open operator support if release-authority recovery persists during rollout or purchase work.',
],
},
]}
actions={[
{ label: 'Open protected downloads', to: buildProtectedDownloadPath('windows') },
{ label: 'Open protected download center', to: buildProtectedDownloadPath('windows') },
{ label: 'Open support', to: buildSupportPath('operator-access') },
]}
/>
@ -291,12 +292,12 @@ function AvailableTargetsSection({ platforms }: { platforms: readonly ReleaseMan
) : null}
<ReleaseValidationSummary platform={platform} />
{platform.configured ? (
<Link className="button button--primary button--full" to={buildProtectedDownloadPath(platform.platform_key)}>
<HyperTwistButtonLink className="button--full" to={buildProtectedDownloadPath(platform.platform_key)}>
Sign in for {platform.platform} access
</Link>
</HyperTwistButtonLink>
) : (
<div className="button button--ghost button--full is-disabled" aria-disabled="true">
Release URL not configured yet
Release access opens after account approval
</div>
)}
</article>
@ -320,7 +321,7 @@ export function DownloadPage() {
<MarketingShell
eyebrow="Desktop distribution"
title="Download the desktop build and pair it with your browser account."
lede="The website provides account, release, and legal surfaces. The actual simulator ships through the desktop lane, with package validation and release discipline carried over from the HyperTwist roadmap."
lede="The website provides account, release, and legal surfaces. The actual simulator ships through the desktop lane, with package validation and release discipline carried into every protected download."
>
<ReleaseManifestStatusSections
isLoading={releaseManifestQuery.isLoading}
@ -362,23 +363,23 @@ export function DownloadPage() {
<SimulatorManualSection
title="What the installed runtime already owns"
description="Download posture is stronger when the page also explains the real software lane operators receive after the package handoff."
description="The download page is stronger when it also explains the real software lane operators receive after the package handoff."
/>
<HigherDimensionalRuntimeGuideSection
title="Higher-dimensional family guide"
description="This keeps the download lane concrete about which serious family runtimes are already real and what host posture each one currently uses."
description="This keeps the download lane concrete about which serious family runtimes are already real and what host model each one currently uses."
/>
<BulletCardSection
title="Current input and runtime control truth"
description="The download lane should also teach the real control boundary before the first session starts, including what is strong now and what still remains gated."
description="The download lane should also teach the real control boundary before the first session starts, including what is strong now and what remains in later device validation."
cards={[...inputAndDevicePostureCards, ...runtimeControlGuideCards]}
/>
<BrowserDesktopRealitySection />
<SurfaceChoiceGuideSection description="Download posture is clearer when the current best surface is explicit: public for target and release context, protected for entitlement, and desktop for the real training runtime." />
<SurfaceChoiceGuideSection description="Download guidance is clearer when the current best surface is explicit: public for target and release context, protected for entitlement, and desktop for the real training runtime." />
<PublicReleaseDecisionGuideSection
releaseManifest={releaseManifest}
@ -386,7 +387,7 @@ export function DownloadPage() {
/>
<BrowserAuthMethodsSection
description="Download posture is clearer when the current shared-auth sign-in lineup is visible before operators cross into the protected entitlement and package-delivery lane."
description="Download guidance is clearer when the current shared-auth sign-in lineup is visible before operators cross into the protected entitlement and package-delivery lane."
/>
<BulletCardSection
@ -407,7 +408,7 @@ export function DownloadPage() {
<OperatorDesktopQuickstartSection title="First desktop session after install" />
<Section title="Release posture">
<Section title="Release access state">
<PublicLaunchStatus title="Desktop release access stays launch-honest" />
</Section>
@ -434,7 +435,7 @@ export function DownloadPage() {
<BulletCardSection
title="Distribution doctrine"
description="Download posture should stay tied to package proof, notices, and the desktop-first simulator boundary."
description="Download guidance should stay tied to package proof, notices, and the desktop-first simulator boundary."
cards={distributionDoctrineCards}
/>
@ -451,20 +452,20 @@ export function DownloadPage() {
<ReleaseAuthorityBundleSection
releaseManifest={releaseManifest}
description="Download posture is more trustworthy when docs, release notes, corresponding source, notices repository, and operator escalation remain visible as one coherent release bundle."
description="Download guidance is more trustworthy when docs, release notes, corresponding source, notices repository, and operator escalation remain visible as one coherent release bundle."
/>
<Section title="Why this page does not expose raw download URLs">
<article className="callout">
<p>
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.
</p>
<Link className="button button--ghost" to={buildProtectedDownloadPath('windows')}>
<HyperTwistButtonLink to={buildProtectedDownloadPath('windows')} tone="ghost">
Open protected download lane
</Link>
</HyperTwistButtonLink>
</article>
</Section>
@ -472,11 +473,11 @@ export function DownloadPage() {
<article className="callout">
<p>
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.
</p>
<Link className="button button--ghost" to={buildLoginPath('/app')}>
<HyperTwistButtonLink to={buildLoginPath('/app')} tone="ghost">
Open protected dashboard
</Link>
</HyperTwistButtonLink>
</article>
</Section>
</MarketingShell>
@ -632,15 +633,15 @@ export function OpenSourceNoticesPage() {
<Section title="Questions about notices or redistribution?">
<article className="callout">
<p>
Contact <a href={brandConfig.contact.emailHref}>{brandConfig.contact.email}</a> when the next question is redistribution, corresponding-source follow-through, or release-surface notice posture rather than simulator behavior.
Contact <a href={brandConfig.contact.emailHref}>{brandConfig.contact.email}</a> when the next question is redistribution, corresponding-source follow-through, or release-surface notices rather than simulator behavior.
</p>
<div className="button-row top-gap">
<Link className="button button--ghost" to="/support?topic=launch-readiness">
<HyperTwistButtonLink to="/support?topic=launch-readiness" tone="ghost">
Open launch support
</Link>
<Link className="button button--primary" to="/contact">
</HyperTwistButtonLink>
<HyperTwistButtonLink to="/contact">
Open contact route
</Link>
</HyperTwistButtonLink>
</div>
</article>
</Section>
@ -656,12 +657,12 @@ export function PrivacyPage() {
<>
<SiteMetadata
title="HyperTwist privacy"
description="Understand the HyperTwist privacy posture for browser account access, desktop-link issuance, and the desktop-first simulator boundary."
description="Understand the HyperTwist privacy model for browser account access, desktop-link issuance, and the desktop-first simulator boundary."
canonicalPath="/privacy"
/>
<MarketingShell
eyebrow="Privacy"
title="Privacy posture"
title="Privacy model"
lede="HyperTwist keeps the browser shell narrow and the simulator desktop-first. Privacy descriptions must reflect that separation clearly."
>
<Section title="Core points">
@ -693,11 +694,11 @@ export function PrivacyPage() {
</div>
</Section>
<SurfaceChoiceGuideSection description="Privacy posture is clearer when the next working surface is explicit too: public for policy context, protected for identity and account work, and desktop for simulator execution." />
<SurfaceChoiceGuideSection description="Privacy guidance is clearer when the next working surface is explicit too: public for policy context, protected for identity and account work, and desktop for simulator execution." />
<PublicReleaseDecisionGuideSection
releaseManifest={releaseManifest}
description="Privacy posture is stronger when it also says whether the next honest move is protected desktop access, pricing/provisioning, browser/account continuity, or notices/source follow-through."
description="Privacy guidance is stronger when it also says whether the next honest move is protected desktop access, pricing/provisioning, browser/account continuity, or notices/source follow-through."
/>
<Section
@ -724,7 +725,7 @@ export function PrivacyPage() {
<ReleaseAuthorityBundleSection
releaseManifest={releaseManifest}
description="Privacy posture remains more actionable when docs, release notes, corresponding source, notices repository, and operator support stay reachable from the same public boundary page."
description="Privacy guidance remains more actionable when docs, release notes, corresponding source, notices repository, and operator support stay reachable from the same public boundary page."
/>
<Section
@ -752,12 +753,12 @@ export function PrivacyPage() {
For browser-account, billing, release-access, or policy questions, contact <a href={brandConfig.contact.emailHref}>{brandConfig.contact.email}</a> and include whether the concern is public, protected, or native-runtime context.
</p>
<div className="button-row top-gap">
<Link className="button button--ghost" to="/help">
<HyperTwistButtonLink to="/help" tone="ghost">
Open help center
</Link>
<Link className="button button--primary" to="/contact">
</HyperTwistButtonLink>
<HyperTwistButtonLink to="/contact">
Open contact route
</Link>
</HyperTwistButtonLink>
</div>
</article>
</Section>
@ -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."
>
<Section title="Service posture">
<Section title="Service model">
<article className="card">
<ul className="list">
<li>Browser access covers public pages, account, release, download, and operator/dashboard surfaces.</li>
@ -826,7 +827,7 @@ export function TermsPage() {
<Section
title="Current surface authority map"
description="This is the quickest way to see which live surface owns access, execution, and future-gated branches today."
description="This is the quickest way to see which live surface owns access, execution, and future validation branches today."
>
<ProductSurfaceMatrix rows={productSurfaceMatrixRows} />
</Section>
@ -868,12 +869,12 @@ export function TermsPage() {
Terms questions that affect billing, protected release access, or redistribution should go to <a href={brandConfig.contact.emailHref}>{brandConfig.contact.email}</a> with the exact public or protected route and the current build or release context.
</p>
<div className="button-row top-gap">
<Link className="button button--ghost" to="/support?topic=studio-rollout">
<HyperTwistButtonLink to="/support?topic=studio-rollout" tone="ghost">
Open rollout support
</Link>
<Link className="button button--primary" to="/contact">
</HyperTwistButtonLink>
<HyperTwistButtonLink to="/contact">
Open contact route
</Link>
</HyperTwistButtonLink>
</div>
</article>
</Section>
@ -889,7 +890,7 @@ export function ShippingPaymentPage() {
<>
<SiteMetadata
title="HyperTwist shipping and payment"
description="HyperTwist is delivered digitally through account access, release pages, and desktop downloads with Paddle-ready billing posture."
description="HyperTwist is delivered digitally through account access, release pages, and desktop downloads with Paddle-ready billing."
canonicalPath="/shipping-payment"
/>
<MarketingShell
@ -910,7 +911,7 @@ export function ShippingPaymentPage() {
<Section
title="Digital delivery workflow"
description="A professional digital-delivery lane does more than expose a buy button. It keeps release posture, entitlement, and the desktop handoff coherent."
description="A professional digital-delivery lane does more than expose a buy button. It keeps release status, entitlement, and the desktop handoff coherent."
>
<div className="card-grid">
{digitalDeliveryCards.map((card) => (
@ -946,11 +947,11 @@ export function ShippingPaymentPage() {
</div>
</Section>
<SurfaceChoiceGuideSection description="Shipping and payment posture stays practical when the next live surface is explicit instead of implied." />
<SurfaceChoiceGuideSection description="Shipping and payment guidance stays practical when the next live surface is explicit instead of implied." />
<PublicReleaseDecisionGuideSection
releaseManifest={releaseManifest}
description="Shipping and payment posture is clearer when it also says whether the next honest move is protected desktop access, pricing/provisioning, browser/account continuity, or notices/source follow-through."
description="Shipping and payment guidance is clearer when it also says whether the next honest move is protected desktop access, pricing/provisioning, browser/account continuity, or notices/source follow-through."
/>
<BrowserAuthMethodsSection
@ -959,12 +960,12 @@ export function ShippingPaymentPage() {
<BrowserDesktopRealitySection
title="Why checkout and entitlement stay on the web while training stays native"
description="The commercial/browser shell owns access, billing, and release posture so the packaged simulator can remain focused on execution quality instead of becoming a confused storefront."
description="The commercial/browser shell owns access, billing, and release status so the packaged simulator can remain focused on execution quality instead of becoming a confused storefront."
/>
<Section
title="Browser and desktop responsibilities"
description="Shipping and payment surfaces should explain why checkout, entitlement, and release posture stay on the web while simulator execution stays native."
description="Shipping and payment surfaces should explain why checkout, entitlement, and release status stay on the web while simulator execution stays native."
>
<DeliverySurfaceResponsibilitiesGrid />
</Section>
@ -986,7 +987,7 @@ export function ShippingPaymentPage() {
<ReleaseAuthorityBundleSection
releaseManifest={releaseManifest}
description="Shipping and payment posture should carry the same docs, release, source, notices, and support bundle as the rest of the public desktop-distribution lane."
description="Shipping and payment guidance should carry the same docs, release, source, notices, and support bundle as the rest of the public desktop-distribution lane."
/>
<Section
@ -1047,29 +1048,29 @@ export function ShippingPaymentPage() {
<PublicManualRouteAtlasSection
title="Which public route should you open next?"
description="The shipping/payment lane now also keeps the strongest adjacent manual routes visible so checkout, launch posture, release notes, notices, and simulator onboarding remain one coherent product story."
description="The shipping/payment lane now also keeps the strongest adjacent manual routes visible so checkout, launch status, release notes, notices, and simulator onboarding remain one coherent product story."
limit={6}
/>
<DownloadableOperatorManualSection
description="The delivery lane also keeps the offline operator manual attached so first-session setup, rollout posture, higher-dimensional runtime guidance, and browser-versus-desktop truth can accompany the purchase and download path."
description="The delivery lane also keeps the offline operator manual attached so first-session setup, rollout guidance, higher-dimensional runtime guidance, and browser-versus-desktop truth can accompany the purchase and download path."
/>
<Section title="Need billing, rollout, or plan help?">
<article className="callout">
<p>
Write to <a href={brandConfig.contact.emailHref}>{brandConfig.contact.email}</a> for operator provisioning, studio rollout, payment posture, or release-surface billing questions.
Write to <a href={brandConfig.contact.emailHref}>{brandConfig.contact.email}</a> for operator provisioning, studio rollout, payment, or release-surface billing questions.
</p>
<div className="button-row top-gap">
<Link className="button button--ghost" to="/pricing">
<HyperTwistButtonLink to="/pricing" tone="ghost">
Reopen pricing
</Link>
<Link className="button button--ghost" to="/help">
</HyperTwistButtonLink>
<HyperTwistButtonLink to="/help" tone="ghost">
Open help center
</Link>
<Link className="button button--primary" to="/contact">
</HyperTwistButtonLink>
<HyperTwistButtonLink to="/contact">
Open contact route
</Link>
</HyperTwistButtonLink>
</div>
</article>
</Section>

View file

@ -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() {
<>
<SiteMetadata
title="HyperTwist features"
description="Explore the HyperTwist feature atlas: desktop runtime ownership, browser account and release surfaces, higher-dimensional capability, and explicit roadmap boundaries."
description="Explore the HyperTwist feature atlas: desktop runtime ownership, browser account and release surfaces, higher-dimensional capability, and clear product boundaries."
canonicalPath="/features"
/>
<MarketingShell
eyebrow="Capability atlas"
title="Feature truth without the roadmap archaeology."
lede="This page condenses the real HyperTwist product surface into one public map: what ships now, what stays desktop-first, what the browser shell owns, and which branches remain intentionally gated."
title="Feature truth without the guesswork."
lede="This page condenses the real HyperTwist product surface into one public map: what ships now, what stays desktop-first, what the browser shell owns, and which branches remain deliberately future-facing."
>
<BulletCardSection
title="How to read the product truth"
description="The public website now mirrors the same discipline used in the internal feature registry so advanced readers do not have to guess which surfaces are live, retained, or still gated."
description="The public website now mirrors the same discipline used in the internal feature registry so advanced readers do not have to guess which surfaces are live, retained, or reserved for later validation."
cards={featureRegistryTierCards}
/>
@ -64,7 +64,7 @@ export function FeaturesPage() {
<Section
title="Current surface authority map"
description="This is the clean public answer to the architecture question: public website, protected dashboard, embedded browser shell, native runtime, and the frozen browser-client branch each have different ownership."
description="This is the clean public answer to the architecture question: public website, protected dashboard, embedded browser shell, native runtime, and future browser-client branch each have different ownership."
>
<ProductSurfaceMatrix rows={productSurfaceMatrixRows} />
</Section>
@ -79,12 +79,12 @@ export function FeaturesPage() {
<BrowserDesktopRealitySection />
<HigherDimensionalRuntimeGuideSection
title="Higher-dimensional families and runtime posture"
title="Higher-dimensional families and runtime host"
description="These are the current public-safe explanations of the serious hypercubing lanes and the runtime host each one actually uses."
/>
<InputAndDevicePostureSection
title="Current control and XR posture"
title="Current control and device state"
description="The public product surface stays stronger when it is explicit about what input quality exists now and what still belongs to a later native completion packet."
/>
@ -95,7 +95,7 @@ export function FeaturesPage() {
<RuntimeControlGuideSection
title="Runtime control guide"
description="The feature atlas is more useful when it also teaches the current practical desktop control posture instead of stopping at capability labels and roster summaries."
description="The feature atlas is more useful when it also teaches practical desktop controls instead of stopping at capability labels and roster summaries."
/>
<FaqCardSection
@ -106,7 +106,7 @@ export function FeaturesPage() {
<Section
title="Release and distribution maturity"
description="Production readiness in HyperTwist is not just code quality. It also includes package proof, launch posture, account access, and legal/distribution discipline."
description="Production readiness in HyperTwist is not just code quality. It also includes package proof, launch status, account access, and legal/distribution discipline."
>
<div className="card-grid">
{releaseStoryCards.map((card) => (
@ -134,10 +134,10 @@ export function FeaturesPage() {
</Section>
<Section
title="Current public rollout posture"
description="Capability and launch posture are related but not identical. This section keeps the current public release lane honest."
title="Current public rollout state"
description="Capability and launch status are related but not identical. This section keeps the current public release lane honest."
>
<PublicLaunchStatus title="Public feature and launch posture" />
<PublicLaunchStatus title="Public feature and access status" />
</Section>
<PublicPackagedDesktopProofSection
@ -165,15 +165,15 @@ export function FeaturesPage() {
))}
</div>
<div className="button-row top-gap">
<Link className="button button--ghost" to="/docs">
<HyperTwistButtonLink to="/docs" tone="ghost">
Open public manual
</Link>
<Link className="button button--ghost" to="/resources">
</HyperTwistButtonLink>
<HyperTwistButtonLink to="/resources" tone="ghost">
Open resources
</Link>
<Link className="button button--primary" to="/download">
</HyperTwistButtonLink>
<HyperTwistButtonLink to="/download">
Open download center
</Link>
</HyperTwistButtonLink>
</div>
</Section>
</MarketingShell>

View file

@ -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() {
<MarketingShell
eyebrow="Web version and protected browser shell"
title="The browser version exists to support the downloadable, not replace it."
lede="HyperTwist keeps a real browser experience because account access, pricing, release posture, notices, pairing, and operator support should stay outside the simulator. That does make the browser version narrower and less powerful for training work, and this page says exactly how."
lede="HyperTwist keeps a real browser experience because account access, pricing, release status, notices, pairing, and operator support should stay outside the simulator. That does make the browser version narrower and less powerful for training work, and this page says exactly how."
>
<Section
title="Start with the right expectation"
@ -57,7 +58,7 @@ export function BrowserExperiencePage() {
<article className="feature-band__card">
<Globe size={22} />
<h3>The browser is the public and protected operator shell</h3>
<p>Use it for docs, pricing, release posture, account access, notices, and browser-to-desktop pairing.</p>
<p>Use it for docs, pricing, release status, account access, notices, and browser-to-desktop pairing.</p>
</article>
<article className="feature-band__card">
<MonitorSmartphone size={22} />
@ -67,19 +68,19 @@ export function BrowserExperiencePage() {
<article className="feature-band__card">
<Headset size={22} />
<h3>The current XR boundary is still explicit</h3>
<p>The browser does not hide the fact that finished OpenXR/controller completion still remains a separate native packet.</p>
<p>The browser does not hide the fact that full headset/controller validation remains a separate native device packet.</p>
</article>
</div>
<div className="button-row top-gap">
<Link className="button button--primary" to="/download">
<HyperTwistButtonLink to="/download">
Open desktop download
</Link>
<Link className="button button--ghost" to="/app">
</HyperTwistButtonLink>
<HyperTwistButtonLink to="/app" tone="ghost">
Open protected dashboard
</Link>
<Link className="button button--ghost" to="/help">
</HyperTwistButtonLink>
<HyperTwistButtonLink to="/help" tone="ghost">
Open help center
</Link>
</HyperTwistButtonLink>
</div>
</Section>
@ -111,7 +112,7 @@ export function BrowserExperiencePage() {
/>
<BrowserAuthMethodsSection
description="The browser lane is easier to understand when the real sign-in posture is visible next to the release, support, and download decisions it controls."
description="The browser lane is easier to understand when real sign-in options are visible next to the release, support, and download decisions it controls."
/>
<Section
@ -187,8 +188,8 @@ export function HelpCenterPage() {
/>
<InputAndDevicePostureSection
title="Current controls and device posture"
description="The help center should say plainly what is real today and what still remains outside the current native XR/controller completion lane."
title="Current controls and device state"
description="The help center should say plainly what is real today and what still remains in the later native headset/controller validation lane."
/>
<HigherDimensionalRuntimeGuideSection
@ -283,18 +284,18 @@ export function ContactPage() {
<article className="callout">
<p>
Email <a href={brandConfig.contact.emailHref}>{brandConfig.contact.email}</a> 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.
</p>
<p>
The clearer the surface ownership is up front, the faster HyperTwist can separate account, package, runtime, and rollout questions.
</p>
<div className="button-row top-gap">
<a className="button button--primary" href={brandConfig.contact.emailHref}>
<HyperTwistButtonAnchor href={brandConfig.contact.emailHref}>
Email HyperTwist
</a>
<Link className="button button--ghost" to="/support">
</HyperTwistButtonAnchor>
<HyperTwistButtonLink to="/support" tone="ghost">
Open support routes
</Link>
</HyperTwistButtonLink>
</div>
</article>
</Section>
@ -324,12 +325,12 @@ export function ContactPage() {
<Section
title="Launch and release context"
description="Contact and support are safer when they stay anchored to current package proof and public launch posture."
description="Contact and support are safer when they stay anchored to current package proof and public launch status."
>
<div className="feature-band">
<article className="feature-band__card">
<ShieldCheck size={22} />
<h3>Release posture stays visible</h3>
<h3>Release status stays visible</h3>
<p>Use current launch status and packaged proof before reporting a rollout or release concern.</p>
</article>
<article className="feature-band__card">

View file

@ -21,31 +21,31 @@ export function LaunchStatusPage() {
return (
<>
<SiteMetadata
title="HyperTwist launch status"
description="Check the canonical HyperTwist public launch-readiness posture: checkout, download, notices, corresponding source, public auth runtime, and release authority."
title="HyperTwist access status"
description="Check how HyperTwist public pages, account access, protected downloads, notices, and desktop delivery fit together."
canonicalPath="/launch-status"
/>
<MarketingShell
eyebrow="Launch authority"
title="See exactly what still separates preview from public launch."
lede="This is the canonical public authority surface for rollout truth: release targets, checkout posture, notices, corresponding source, and public auth-runtime readiness stay visible here in one place instead of being reconstructed from scattered callouts."
eyebrow="Access status"
title="See how public pages, account access, and desktop delivery work together."
lede="This is the canonical public status surface for HyperTwist access: release targets, checkout/account flow, notices, corresponding source, and protected desktop handoff stay visible in one place instead of being reconstructed from scattered callouts."
>
<Section
title="Current public launch status"
description="Use this page when rollout language, pricing, download, and legal/distribution follow-through need one authoritative browser-owned checklist."
title="Current public access status"
description="Use this page when rollout language, pricing, download, and legal/distribution follow-through need one authoritative browser-owned status surface."
>
<PublicLaunchStatus title="Current launch-readiness checklist" />
<PublicLaunchStatus title="Current account and release access" />
</Section>
<StepOnlyCardSection
title="What must be true before public launch"
title="What must be true before wider public launch"
description="These are the bounded rollout checks that keep external launch language tied to real release authority instead of aspiration."
cards={releaseRolloutChecklist}
/>
<StepOnlyCardSection
title="Launch hardening tracks"
description="These are the practical work tracks for turning a truthful preview lane into a production-grade public release lane."
description="These are the practical work tracks for turning account-gated early access into a production-grade public release lane."
cards={deploymentReadinessTracks}
/>
@ -58,15 +58,15 @@ export function LaunchStatusPage() {
/>
<SupportTopicDirectorySection
title="Launch support and escalation lanes"
description="Launch posture only helps when the next human lane is explicit too, so these support routes stay attached to the same authority surface."
title="Access support and escalation lanes"
description="Access status only helps when the next human lane is explicit too, so these support routes stay attached to the same authority surface."
topics={supportTopicDirectory}
selectedTopicKey="launch-readiness"
/>
<PublicReleaseDecisionGuideSection
releaseManifest={releaseManifest}
title="Choose the next launch move"
title="Choose the next access move"
description="This page should not stop at checklist language. It should also say whether the next honest move is protected desktop access, pricing/provisioning, browser/account follow-through, or notices/source review."
/>
@ -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."
/>
<SurfaceChoiceGuideSection description="This keeps launch posture grounded in the real product topology too: public for launch truth, protected for account-aware release work, and native for the simulator itself." />
<SurfaceChoiceGuideSection description="This keeps access status grounded in the real product topology too: public for product truth, protected for account-aware release work, and native for the simulator itself." />
<BrowserDesktopRealitySection
title="Why launch authority stays in the browser shell"
description="Launch-readiness posture belongs to the distribution shell because checkout, notices, release references, and account access are browser-owned even while the actual training runtime remains native."
title="Why access authority stays in the browser shell"
description="Launch-readiness belongs to the distribution shell because checkout, notices, release references, and account access are browser-owned even while the actual training runtime remains native."
/>
</MarketingShell>
</>

View file

@ -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.
</p>
<div className="button-row">
<Link className="button button--primary" to="/download">
<HyperTwistButtonLink to="/download">
Download desktop app
</Link>
<Link className="button button--ghost" to="/browser">
</HyperTwistButtonLink>
<HyperTwistButtonLink to="/browser" tone="ghost">
Why keep the web version?
</Link>
<Link className="button button--ghost" to="/help">
</HyperTwistButtonLink>
<HyperTwistButtonLink to="/help" tone="ghost">
Open help center
</Link>
<Link className="button button--ghost" to="/app">
</HyperTwistButtonLink>
<HyperTwistButtonLink to="/app" tone="ghost">
Open operator dashboard
</Link>
</HyperTwistButtonLink>
</div>
</div>
<div className="hero-visual-card">
@ -105,7 +106,7 @@ function HomeHeroPanel() {
<ul className="list top-gap">
<li>Use the web for pricing, docs, release notes, notices, and protected downloads.</li>
<li>Use the downloadable for real cube-state workflows, higher-dimensional maps, and diagnostics.</li>
<li>Read XR/controller widening honestly as a separate native completion packet, not as a finished browser or desktop claim today.</li>
<li>Read headset and controller support as a native device-validation track, not as a browser feature claim.</li>
</ul>
</div>
</div>
@ -160,8 +161,8 @@ function HomeCapabilityPillarsSection() {
function HomeRoadmapHonestySection() {
return (
<Section
title="Roadmap-honest posture"
description="Important boundaries stay visible instead of being blurred into vague marketing claims."
title="Current product boundaries"
description="Important limits stay visible in plain product language instead of being blurred into vague claims."
>
<div className="split-grid">
{roadmapHonestyCards.map((item) => (
@ -184,7 +185,7 @@ function HomeDeliverySurfacesSection() {
<article className="feature-band__card">
<MonitorCog size={22} />
<h3>Browser account and operator shell</h3>
<p>Authenticated browser access for release posture, desktop pairing, notices, and operator state.</p>
<p>Authenticated browser access for release status, desktop pairing, notices, and operator state.</p>
<Link to="/app" className="inline-link">
Open dashboard <ArrowRight size={15} />
</Link>
@ -192,7 +193,7 @@ function HomeDeliverySurfacesSection() {
<article className="feature-band__card">
<Download size={22} />
<h3>Desktop download and package lane</h3>
<p>Public download posture for the native Unreal build, with legal linkage already wired in.</p>
<p>Public download guidance for the native Unreal build, with legal linkage already wired in.</p>
<Link to="/download" className="inline-link">
Open download center <ArrowRight size={15} />
</Link>
@ -299,7 +300,7 @@ function ResourcesDirectRoutesSection() {
<Link to="/features" className="feature-band__card feature-band__card--link">
<Boxes size={22} />
<h3>Feature atlas</h3>
<p>One public page for current capability, surface boundaries, and release posture.</p>
<p>One public page for current capability, surface boundaries, and release status.</p>
</Link>
<Link to="/help" className="feature-band__card feature-band__card--link">
<MonitorCog size={22} />
@ -314,7 +315,7 @@ function ResourcesDirectRoutesSection() {
<Link to="/launch-status" className="feature-band__card feature-band__card--link">
<Landmark size={22} />
<h3>Launch status</h3>
<p>The canonical public checklist for preview-versus-launch posture, release authority, and rollout blockers.</p>
<p>The canonical public checklist for early access, release authority, and rollout follow-through.</p>
</Link>
<Link to="/docs" className="feature-band__card feature-band__card--link">
<BookOpenText size={22} />
@ -334,7 +335,7 @@ function ResourcesDirectRoutesSection() {
<Link to="/changelog" className="feature-band__card feature-band__card--link">
<Sparkles size={22} />
<h3>Release notes</h3>
<p>Recent public-facing packets and posture updates.</p>
<p>Recent public-facing release packets and product updates.</p>
</Link>
</div>
</Section>
@ -398,15 +399,15 @@ export function HomeLanding() {
<MarketingShell
eyebrow="Desktop-first simulator. Browser-first access and rollout."
title="From first solves to 120-cell, HyperTwist keeps the real simulator in the downloadable."
lede="The website is a real product surface for account access, pricing, release posture, legal follow-through, and operator help. The downloadable is the much more powerful runtime for recognition, replay, coaching, higher-dimensional execution, and package-validated training."
lede="The website is a real product surface for account access, pricing, release status, legal follow-through, and operator help. The downloadable is the much more powerful runtime for recognition, replay, coaching, higher-dimensional execution, and package-validated training."
>
<HomeHeroPanel />
<Section
title="Current public site status"
description="The homepage now exposes the same bounded preview-versus-launch truth that governs the release and pricing lanes."
description="The homepage explains the current account-gated access model that governs release, download, and pricing paths."
>
<PublicLaunchStatus title="Public website and release posture" />
<PublicLaunchStatus title="Public website and release access" />
</Section>
<BulletCardSection
@ -461,7 +462,7 @@ export function HomeLanding() {
<PublicReleaseDecisionGuideSection
releaseManifest={releaseManifest}
description="The homepage should not stop at posture and proof. It should also say whether the next honest move is protected desktop access, pricing, browser/account continuity, or notices/source follow-through."
description="The homepage should not stop at proof. It should also say whether the next useful move is protected desktop access, pricing, browser/account continuity, or notices/source follow-through."
/>
<ReleaseAuthorityBundleSection
@ -483,11 +484,11 @@ export function HomeLanding() {
<OperatorDesktopQuickstartSection title="What the first serious session should look like" />
<SurfaceChoiceGuideSection description="This is the shortest practical answer to the browser-versus-desktop question: stay public for release-safe context, move protected for account-aware release work, and move native for the actual simulator." />
<SurfaceChoiceGuideSection description="This is the shortest practical answer to the browser-versus-desktop question: stay public for release context, move protected for account-aware access, and move native for the actual simulator." />
<Section
title="Current surface authority map"
description="HyperTwist really has five distinct surfaces today. This shared map keeps the public site, embedded browser shell, protected dashboard, desktop runtime, and frozen browser-client branch from being blurred together."
description="HyperTwist really has five distinct surfaces today. This shared map keeps the public site, embedded browser shell, protected dashboard, desktop runtime, and future browser-client branch from being blurred together."
>
<ProductSurfaceMatrix rows={productSurfaceMatrixRows} />
</Section>
@ -529,7 +530,7 @@ export function AboutPage() {
</Section>
<BrowserDesktopDecisionFaqSection
description="The about page should also answer the recurring boundary questions directly: what the browser can do, what it should not claim, and why keeping both surfaces is the more trustworthy product posture."
description="The about page should also answer the recurring boundary questions directly: what the browser can do, what it should not claim, and why keeping both surfaces is the more trustworthy product choice."
/>
<Section title="What makes the product different">
@ -541,8 +542,8 @@ export function AboutPage() {
</article>
<article className="card">
<BookOpenText size={22} />
<h3>It stays roadmap-honest</h3>
<p>Shipped, retained, and spec-only surfaces remain clearly separated so public copy matches actual authority.</p>
<h3>It stays product-honest</h3>
<p>Shipped, retained, and future-facing surfaces remain clearly separated so public copy matches actual capability.</p>
</article>
<article className="card">
<MonitorCog size={22} />
@ -597,8 +598,8 @@ export function AboutPage() {
/>
<InputAndDevicePostureSection
title="Current desktop control and XR truth"
description="The product can be ambitious without overclaiming. This page now makes the current input, controller, and XR posture explicit."
title="Current desktop control and headset truth"
description="The product can be ambitious without overclaiming. This page makes the current input, controller, and headset boundary explicit."
/>
<ControlProfileRosterSection
@ -608,7 +609,7 @@ export function AboutPage() {
<Section
title="Release and deployment maturity"
description="Production seriousness comes from clean separation between identity, package proof, legal posture, and runtime execution."
description="Production seriousness comes from clean separation between identity, package proof, legal follow-through, and runtime execution."
>
<div className="card-grid">
{deploymentReadinessTracks.map((track) => (
@ -625,10 +626,10 @@ export function AboutPage() {
</Section>
<Section
title="Current public rollout posture"
description="Narrative claims stay more credible when this page also shows the live public launch posture and the current packaged desktop proof."
title="Current public rollout state"
description="Narrative claims stay more credible when this page also shows live public access status and current packaged desktop proof."
>
<PublicLaunchStatus title="About-page launch and release posture" />
<PublicLaunchStatus title="About-page launch and release access" />
</Section>
<PublicPackagedDesktopProofSection
@ -708,7 +709,7 @@ export function ResourcesPage() {
<SimulatorManualSection
title="Simulator use today"
description="This summary is deliberately practical: what you actually do in the desktop runtime once browser identity and release posture are already resolved."
description="This summary is deliberately practical: what you actually do in the desktop runtime once browser identity and release access are already resolved."
/>
<BulletCardSection
@ -725,12 +726,12 @@ export function ResourcesPage() {
<HigherDimensionalRuntimeGuideSection
title="Higher-dimensional runtime guide"
description="These public-safe cards explain which higher-dimensional family lanes are already real and what runtime posture each one actually uses."
description="These public-safe cards explain which higher-dimensional family lanes are already real and what runtime host each one uses."
/>
<InputAndDevicePostureSection
title="Current control and device posture"
description="This keeps public resources honest about what input/runtime ownership is already strong and what remains outside the current desktop-hosted No-Go XR/controller branch."
title="Current control and device state"
description="This keeps public resources honest about what input/runtime ownership is already strong and what remains in the later packaged headset/controller validation track."
/>
<ControlProfileRosterSection
@ -770,7 +771,7 @@ function GettingStartedPageContent({
<>
<OperatorDesktopQuickstartSection
title="The first serious HyperTwist session"
description="This quickstart stays faithful to the current product topology: browser first for identity and release posture, desktop first for the actual simulator."
description="This quickstart stays faithful to the current product topology: browser first for identity and release access, desktop first for the actual simulator."
/>
<StepCardSection
@ -827,7 +828,7 @@ function GettingStartedPageContent({
<HigherDimensionalRuntimeGuideSection
title="Higher-dimensional family guide"
description="The onboarding route is stronger when it also teaches which higher-dimensional lanes already exist and what host/runtime posture each one actually uses."
description="The onboarding route is stronger when it also teaches which higher-dimensional lanes already exist and what host/runtime model each one uses."
/>
<InputAndDevicePostureSection
@ -842,7 +843,7 @@ function GettingStartedPageContent({
<RuntimeControlGuideSection
title="Runtime control guide"
description="This onboarding route should also show the practical desktop control posture so operators do not have to leave the canonical first-session page just to find the real input and diagnostics guidance."
description="This onboarding route should also show practical desktop controls so operators do not have to leave the canonical first-session page just to find the real input and diagnostics guidance."
/>
<SurfaceChoiceGuideSection description="Onboarding is smoother when the right next surface is explicit too: public for orientation, protected for entitled access, and desktop for simulator execution." />
@ -905,13 +906,13 @@ export function DocsPage() {
<>
<SiteMetadata
title="HyperTwist documentation"
description="Open the HyperTwist public documentation lane for feature-registry-backed product truth, roadmap honesty, and distribution guidance."
description="Open the HyperTwist public documentation lane for feature-backed product truth, honest capability boundaries, and distribution guidance."
canonicalPath="/docs"
/>
<MarketingShell
eyebrow="Documentation posture"
eyebrow="Documentation"
title="HyperTwist documentation stays capability-accurate."
lede="The public docs surface now functions as a real product manual: current feature truth, browser-versus-downloadable boundaries, first-session guidance, control truth, higher-dimensional runtime posture, and release-safe distribution guidance."
lede="The public docs surface now functions as a real product manual: current feature truth, browser-versus-downloadable boundaries, first-session guidance, control truth, higher-dimensional runtime state, and release-safe distribution guidance."
>
<PrincipleCardSection title="Public documentation lanes" cards={publicDocumentationPrinciples} />
@ -961,7 +962,7 @@ export function DocsPage() {
<StepCardSection
title="Operator manual"
description="This is the public-facing manual for how HyperTwist is actually used today: browser first for identity and release posture, desktop first for the simulator."
description="This is the public-facing manual for how HyperTwist is actually used today: browser first for identity and release access, desktop first for the simulator."
cards={operatorManualTracks}
/>
@ -985,7 +986,7 @@ export function DocsPage() {
<StepCardSection
title="Recovery and degraded-state manual"
description="This manual section explains how to move through auth or release-authority degradation without confusing fallback continuity for live production authority."
description="This manual section explains how to move through auth or release-service interruptions without confusing recovery guidance for live production authority."
cards={degradedStateRecoveryTracks}
/>
@ -1030,7 +1031,7 @@ export function DocsPage() {
<StepOnlyCardSection
title="Deployment readiness manual"
description="This is the public-safe checklist for moving from preview posture to operator-grade rollout."
description="This is the public-safe checklist for moving from account-gated early access to operator-grade rollout."
cards={deploymentReadinessTracks}
/>
@ -1061,9 +1062,9 @@ export function DocsPage() {
{releaseManifest.public_docs_url ? (
<Section title="External docs portal">
<a className="button button--primary" href={releaseManifest.public_docs_url} target="_blank" rel="noreferrer">
<HyperTwistButtonAnchor href={releaseManifest.public_docs_url} target="_blank" rel="noreferrer">
Open public docs portal
</a>
</HyperTwistButtonAnchor>
</Section>
) : null}
</MarketingShell>
@ -1109,10 +1110,10 @@ export function SupportPage() {
) : null}
<Section
title="Current release and package posture"
title="Current release and package state"
description="Support gets easier when current launch-readiness truth and current packaged desktop proof remain visible beside the help lanes themselves."
>
<PublicLaunchStatus title="Current support-facing launch posture" />
<PublicLaunchStatus title="Current support-facing launch access" />
</Section>
<PublicPackagedDesktopProofSection
@ -1145,12 +1146,12 @@ export function SupportPage() {
release enablement, pricing configuration, or deployment help.
</p>
<div className="button-row top-gap">
<Link className="button button--ghost" to="/help">
<HyperTwistButtonLink to="/help" tone="ghost">
Open help center
</Link>
<Link className="button button--primary" to="/contact">
</HyperTwistButtonLink>
<HyperTwistButtonLink to="/contact">
Open contact route
</Link>
</HyperTwistButtonLink>
</div>
</article>
</Section>
@ -1172,7 +1173,7 @@ export function SupportPage() {
<Section
title="Browser and desktop responsibilities"
description="This keeps support conversations anchored to the real live surfaces so operators know whether they need public guidance, protected account posture, or native runtime follow-through."
description="This keeps support conversations anchored to the real live surfaces so operators know whether they need public guidance, protected account access, or native runtime follow-through."
>
<DeliverySurfaceResponsibilitiesGrid limit={3} />
</Section>
@ -1210,7 +1211,7 @@ export function SupportPage() {
<StepCardSection
title="Recovery and degraded-state guidance"
description="This keeps support answers aligned with the now-explicit auth and release fallback posture in the product itself."
description="This keeps support answers aligned with the now-explicit auth and release recovery model in the product itself."
cards={degradedStateRecoveryTracks}
/>
@ -1288,7 +1289,7 @@ export function ChangelogPage() {
<MarketingShell
eyebrow="Release notes"
title="Release notes you can actually use for rollout."
lede="This page now combines grouped release packets with the chronological feed so operators can understand what changed in the browser shell, what changed in the downloadable, and what changed in the release or legal lane without reading raw roadmap archaeology."
lede="This page combines grouped release packets with the chronological feed so operators can understand what changed in the browser shell, what changed in the downloadable, and what changed in release or legal follow-through without digging through internal planning notes."
>
<Section
title="Recent release packets"
@ -1353,7 +1354,7 @@ export function ChangelogPage() {
<Section
title="Release rollout checklist"
description="Use the public release notes as an operator tool, not just a chronology. This keeps each change tied to package proof, entitlement posture, and distribution follow-through."
description="Use the public release notes as an operator tool, not just a chronology. This keeps each change tied to package proof, entitlement status, and distribution follow-through."
>
<div className="card-grid">
{releaseRolloutChecklist.map((card) => (
@ -1384,9 +1385,9 @@ export function ChangelogPage() {
{releaseManifest.release_notes_url ? (
<Section title="External release notes">
<a className="button button--ghost" href={releaseManifest.release_notes_url} target="_blank" rel="noreferrer">
<HyperTwistButtonAnchor href={releaseManifest.release_notes_url} target="_blank" rel="noreferrer" tone="ghost">
Open release feed
</a>
</HyperTwistButtonAnchor>
</Section>
) : null}
</MarketingShell>

View file

@ -94,25 +94,25 @@ export function buildLiveLaunchBlockerDetails(
const details = new Set<string>()
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) => {

View file

@ -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

View file

@ -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,

View file

@ -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

View file

@ -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)
: []

View file

@ -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.'

File diff suppressed because it is too large Load diff

View file

@ -17,6 +17,24 @@
--font-body: "IBM Plex Sans", system-ui, sans-serif;
}
@property --glow-angle {
syntax: '<angle>';
inherits: false;
initial-value: 0deg;
}
@property --glow-x {
syntax: '<percentage>';
inherits: false;
initial-value: 50%;
}
@property --glow-y {
syntax: '<percentage>';
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 > * {

View file

@ -22,7 +22,7 @@ const responsiveProtectedRoutes: readonly ProtectedRouteExpectation[] = [
},
{
path: '/app/browser-access',
marker: 'Current browser posture',
marker: 'Current browser role',
},
{
path: '/app/account',

View file

@ -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',