Skip to content

Components Registry

Components Registry

Flat reference for every component, hook, module, and Edge Function across the Surfc codebase. Use this page when you need to answer “what is X and where does it live” without grepping. Categories below are organisational only — within a category, rows are loosely ordered from foundational to leaf.

Convention. If a component is named in surfc/CLAUDE.md or surfc-web/CLAUDE.md, it must have a row here. When you add a new entity to either CLAUDE.md, add the row in the same PR.

Sibling docs. Hooks have their own page with Returns and Used by columns — see React Hooks Registry. The encryption story is in End-to-End Encryption Architecture.


PWA — Root & layout

ComponentRepoPathPurpose
Appsurfcsrc/App.jsxRoot component. Wires state hooks, owns the declarative react-router-dom route tree, renders shell layout and overlays. Partial refactor in progress (SUR-303).
AppGatessurfcsrc/components/AppGates.jsxSequential gate ladder: encryption check → passkey enrolment → unlock → migration → device-add/transfer. Renders the appropriate gate screen or children when all gates clear.
ShellNavigationsurfcsrc/components/ShellNavigation.jsxExports ShellTabRow (desktop/tablet top nav) and ShellBottomNav (mobile bottom nav). ShellBottomNav hides on immersive screens (/, /capture, /note).
UnsyncedChangesModalsurfcsrc/components/UnsyncedChangesModal.jsxStyled modal for sign-out with unsynced changes; replaces window.confirm. Mounted outside <Routes> so gate screens can render it too.

PWA — Auth & account

ComponentRepoPathPurpose
AuthScreensurfcsrc/AuthScreen.jsxSigned-out login shell — one landing for every entry point (SUR-711 retired the ?intent=signup signup framing). Still consumes ?open_email=1 (UpgradeAuthGate deep-link) to pre-open the email sheet. Fires unified auth_landing_viewed { intent: 'signin' } event; the app_signup_started anchor was removed.
AuthControlssurfcsrc/components/AuthControls.jsxShared OAuth + email-OTP primitives extracted from AuthScreen (SUR-370). Optional host overrides (sheetTitle, secondaryLabel, onCtaClick) let UpgradeAuthGate compose it.
UpgradeRoutesurfcsrc/pages/UpgradeRoute.jsx/upgrade entry point. Sends signed-in users to Stripe Checkout; sends signed-out users to UpgradeAuthGate. Reads ?interval and ?ref from the URL.
UpgradeAuthGatesurfcsrc/pages/UpgradeAuthGate.jsxIntermediate page for signed-out /upgrade visitors. Inline <AuthControls /> composition (SUR-357). Persists upgrade intent to sessionStorage.
UpgradeSuccessRoutesurfcsrc/pages/UpgradeSuccessRoute.jsx/upgrade/success post-Stripe redirect. Calls refreshEntitlements() so the UI flips to Pro without a sign-in cycle (SUR-345).
SettingsBridgesurfcsrc/pages/SettingsBridge.jsx/settings redirect shim. Navigates to /profile and programmatically opens the Settings modal. Catches /.well-known/change-password redirects too.
PolicyPagesurfcsrc/pages/PolicyPage.jsxRenders Termly-hosted policy documents inside the SPA shell via useTermlyEmbed. Reached at /policies/:kind (privacy, terms).
ProfileScreensurfcsrc/components/ProfileScreen.jsxUser profile + tier display. Member-since date, tier badge, account name/email. Links to help.surfc.app and policy pages.
DeleteAccountModalsurfcsrc/components/DeleteAccountModal.jsxPermanent account deletion confirmation. Pre-deletes notes/books/ideas client-side, then calls the delete-account Edge Function.

PWA — Screens & views

ComponentRepoPathPurpose
HomeScreensurfcsrc/components/HomeScreen.jsxDashboard landing. Note/idea/source counts, week summary, recently surfaced note, quick-jump stats. Composes HomeHero.
HomeHerosurfcsrc/components/HomeHero.jsxHero section shared between AuthScreen and HomeScreen. Brand tagline + signup/signin framing.
CaptureScreensurfcsrc/components/CaptureScreen.jsxCamera viewfinder for note capture. Hosts CameraViewfinder; mobile-first immersive layout.
IndexScreensurfcsrc/components/IndexScreen.jsxYour Commonplace — the Idea Tree (default) + flat note list, view-mode-driven by URL (?view=tree|flat, ?slide=). Note cards, filtering, long-press surface. Mounted at /commonplace (renamed from /index, SUR-493).
CustomIdeasScreensurfcsrc/components/CustomIdeasScreen.jsxUser’s custom-created ideas — add / edit / delete / description flows. Reached from Settings → “Manage your custom ideas” (SUR-493); browsing also lives on the Tree’s Ideas You Bring slide.
IdeaDetailsurfcsrc/components/IdeaDetail.jsxSingle-idea detail. Shows notes tagged to the idea.
Librarysurfcsrc/components/Library.jsxBook / source management. List, add, edit, delete. Drives note filtering by source.
RelatedNotesScreensurfcsrc/components/RelatedNotesScreen.jsxNotes related to the current context (same source, same idea). Driven by route params.
SourcesScreensurfcsrc/components/SourcesScreen.jsxAggregated view of all sources/books, grouped by author with note counts.
HelpCenterScreensurfcsrc/components/HelpCenterScreen.jsxIn-app help index at /help. Searchable list of articles from src/help/manifest.js. Fires help_index_opened.
HelpArticlesurfcsrc/components/HelpArticle.jsxIn-app article renderer at /help/:slug. Passes markdown body to HelpArticleBody. Fires help_article_viewed.
HelpArticleBodysurfcsrc/components/HelpArticleBody.jsxMarkdown renderer (react-markdown + remark-gfm + remark-directive + callout plugin). Rewrites VitePress paths to SPA /help/:slug.
HelpCalloutsurfcsrc/components/HelpCallout.jsxCallout / admonition component (Note, Tip, Warning, Danger). Used by HelpArticleBody.

PWA — Note & idea forms

ComponentRepoPathPurpose
NoteFormsurfcsrc/components/NoteForm.jsxNote creation/edit form. Image capture, text input, idea tagging via AddIdeaSheet, transcription, save. Central capture UX.
NoteEditFormsurfcsrc/components/NoteEditForm.jsxDedicated edit form for existing notes. Text/tags/image updates; triggers rediscovery and re-encryption.
NoteActionOverlaysurfcsrc/components/NoteActionOverlay.jsxLong-press note action flow (action sheet → full-edit or source-edit). Exposed via forwardRef; App.jsx calls ref.current.open(note).
NoteActionSheetsurfcsrc/components/NoteActionSheet.jsxBottom sheet for note actions (delete, tag, view image). Rendered by NoteActionOverlay.
NoteCardsurfcsrc/components/NoteCard.jsxIndividual note card in grid/list view. Preview text, image thumbnail, tags, source badge. Long-press to NoteActionOverlay.
NoteDetailOverlaysurfcsrc/components/NoteDetailOverlay.jsxFull-screen note detail. Read-only preview of text, tags, image, source with lightbox integration.
PiiReviewSheetsurfcsrc/components/PiiReviewSheet.jsxBottom sheet for PII detection review before managed-AI submission. Shows matches; allows redact/edit/send-anyway.
AddIdeaSheetsurfcsrc/components/AddIdeaSheet.jsxBottom sheet for searching/adding ideas during note capture. Renders canon + custom ideas with live search and “Create” CTA.
AddIdeaBannersurfcsrc/components/AddIdeaBanner.jsxPost-creation banner prompting description entry for newly created custom ideas. Dismissal local-state only.
IdeaEditFormsurfcsrc/components/IdeaEditForm.jsxForm for editing existing custom idea (name, description). Soft validation; updates via saveCustomIdea.
IdeaActionOverlaysurfcsrc/components/IdeaActionOverlay.jsxLong-press idea action flow (action sheet → edit). Exposed via forwardRef; fires onActiveChange so IdeasSidebar syncs.
IdeaActionSheetsurfcsrc/components/IdeaActionSheet.jsxBottom sheet for idea actions (edit, delete, view notes).

PWA — Sidebar & navigation primitives

ComponentRepoPathPurpose
IdeasSidebarsurfcsrc/components/IdeasSidebar.jsxPersistent idea browser for desktop/tablet. Toggles on mobile. Syncs selected idea state with the main view.
RecentlySurfacedsurfcsrc/components/RecentlySurfaced.jsxMini widget showing recently reviewed notes on HomeScreen.
CameraViewfindersurfcsrc/components/CameraViewfinder.jsxCamera stream viewfinder canvas for CaptureScreen. Handles permission, stream setup, frame capture.
ContextualHelpLinksurfcsrc/components/ContextualHelpLink.jsxInline ? icon linking to in-app help article or help.surfc.app fallback.
AvatarButtonsurfcsrc/components/AvatarButton.jsxUser avatar + initials button in nav chrome. Opens menu or navigates to profile.
BottomSheetsurfcsrc/components/BottomSheet.jsxReusable accessible bottom-sheet primitive used throughout for modals/pickers/action flows.

PWA — Settings & device management

ComponentRepoPathPurpose
SettingsModalsurfcsrc/components/SettingsModal.jsxApp-settings modal (custom ideas, import/export, data/cache management). Drives useSettings.
LinkedDevicesModalsurfcsrc/components/LinkedDevicesModal.jsx(SUR-233) Device manager UI for the key lifecycle. Lists active prf-v1 blobs with device label, enrolment date, “This device” badge. Inline removal with last-device guard.

PWA — Encryption & crypto components

ComponentRepoPathPurpose
PasskeyEnrollmentScreensurfcsrc/components/PasskeyEnrollmentScreen.jsxGuides initial passkey registration. Calls registerEncryptionPasskey(); uploads wrapped blob to Supabase. Rendered by the gate ladder.
UnlockScreensurfcsrc/components/UnlockScreen.jsxAsks the user to unlock their Master Key via passkey assertion. Calls getEncryptionPrfOutput(); derives wrapping key; unwraps MK.
EncryptionMigrationModalsurfcsrc/components/EncryptionMigrationModal.jsxOne-time migration from legacy PRF-derived key to Master Key architecture. Re-encrypts the corpus when legacy notes are detected.

PWA — Crypto module (stateless pure functions)

See End-to-End Encryption Architecture for the full narrative; this table is the address book.

ComponentRepoPathPurpose
keyManagersurfcsrc/crypto/keyManager.jsMaster Key lifecycle: generate, wrap/unwrap (PRF and PIN), re-wrap for multi-device. Holds module-level non-extractable CryptoKey. Never extracted.
noteEncryptionsurfcsrc/crypto/noteEncryption.jsStateless AES-GCM-256 encrypt/decrypt for note text. Two formats: enc:v1 (no AAD, legacy) and enc:v2 (AAD = noteId, current).
passkeyEnrollmentsurfcsrc/crypto/passkeyEnrollment.jsAll navigator.credentials calls. Registers platform passkey with WebAuthn PRF extension. Returns PRF output as raw ArrayBuffer.
deviceTransfersurfcsrc/crypto/deviceTransfer.jsPIN-based MK transfer between devices. Working device wraps with 6-digit PIN (PBKDF2 600k); new device redeems. 60 s TTL enforced server-side.

PWA — Hooks

See React Hooks Registry for the full table with Returns and Used by columns. The hook files are:

HookRepoPath
useAuthsurfcsrc/hooks/useAuth.js
useKeyManagementsurfcsrc/hooks/useKeyManagement.js
useUpgradeResumptionsurfcsrc/hooks/useUpgradeResumption.js
useUIsurfcsrc/hooks/useUI.js
useToastsurfcsrc/hooks/useToast.js
useMediaQuerysurfcsrc/hooks/useMediaQuery.js
useFocusRestoresurfcsrc/hooks/useFocusRestore.js
useNoteActionssurfcsrc/hooks/useNoteActions.js
useNoteFormsurfcsrc/hooks/useNoteForm.js
useSettingssurfcsrc/hooks/useSettings.js
useAnalyticssurfcsrc/hooks/useAnalytics.js
useEntitlementssurfcsrc/hooks/useEntitlements.js
useUserProfilesurfcsrc/hooks/useUserProfile.js
useCameraStreamsurfcsrc/hooks/useCameraStream.js
useLongPresssurfcsrc/hooks/useLongPress.js
useTurnstilesurfcsrc/hooks/useTurnstile.js
useTermlyEmbedsurfcsrc/hooks/useTermlyEmbed.js

PWA — Dexie & storage

ComponentRepoPathPurpose
dbsurfcsrc/db.jsDexie IndexedDB schema and all local CRUD (saveBook, saveNote, saveCustomIdea, deleteNote, etc.), version migrations, outbox queue, export/import. Single source of truth offline.

PWA — Cloud & API

ComponentRepoPathPurpose
supabasesurfcsrc/supabase.jsSupabase client and all cloud operations: auth (Google + email-OTP), CRUD, image storage, sync fetch, cross-domain auth-cookie mirror. Wraps supabase-js.
apisurfcsrc/api.jsAnthropic API calls (legacy BYOK path — sunset SUR-91). Direct calls to Claude for transcription/discovery; managed path goes through anthropic-proxy.

PWA — Utilities & helpers

ComponentRepoPathPurpose
constantssurfcsrc/constants.jsThe Idea Canon (Adler 102 ideas). Imported by anthropic-proxy/prompts.ts via Deno cross-tree import — must remain Vite/build-tool neutral.
createCustomIdeasurfcsrc/lib/createCustomIdea.jsShared deduped custom-idea creation: collision-checks via findCanonicalIdeaName, writes Dexie + Supabase. Used by ProfileScreen and AddIdeaSheet.
deviceLabelsurfcsrc/utils/deviceLabel.jsPure UA parser: getDeviceLabel(userAgent, hasTouch)"Platform · Browser". Captured at passkey-enrolment time.
utmParamssurfcsrc/lib/utmParams.jsPure readUtmParams(search). Parses query string; returns { utm_source, utm_medium, utm_campaign, utm_term, utm_content, gclid, fbclid }. Used by AuthScreen + UpgradeAuthGate.
upgradeIntentsurfcsrc/lib/upgradeIntent.jsHelpers for upgrade-flow intent persistence (sessionStorage). Written by UpgradeAuthGate; read by useUpgradeResumption.
freshSignupsurfcsrc/lib/freshSignup.jsDetects fresh signup via browser local state. Drives onboarding gate show/hide.
platformsurfcsrc/lib/platform.jsPlatform detection helpers. isStandaloneOrTwa() checks for PWA/TWA contexts. Used by AuthScreen to alter login framing.
webVitalsToPostHogsurfcsrc/lib/webVitalsToPostHog.jsBridges the web-vitals library to PostHog. Records LCP/FID/CLS metrics as events.

PWA — Ingest & data processing

ComponentRepoPathPurpose
ingestsurfcsrc/ingest/index.jsMain export. Orchestrates photoAdapter and manualAdapter; normalises raw input into note shape.
photoAdaptersurfcsrc/ingest/photoAdapter.jsConverts photo + transcription (managed/BYOK) into note objects. Handles source metadata.
manualAdaptersurfcsrc/ingest/manualAdapter.jsConverts manual text input into note objects. Minimal processing; used for keyboard-entry notes.

PWA — Safety & guardrails

ComponentRepoPathPurpose
safetysurfcsrc/safety/index.jsClient-side safety orchestrator. Runs checkStructuredPii before managed-AI calls. Warn-not-block via the PiiReviewSheet. Stub seams for SUR-246.
piiRegexsurfcsrc/safety/piiRegex.jsStructured-PII regex detection: credit cards (Luhn), IBANs (mod-97), phone numbers (E.164/US/GB), emails, UK NINs, US SSNs. Stateless.

PWA — Help system

ComponentRepoPathPurpose
manifestsurfcsrc/help/manifest.jsReads docs/getting-started/*.md at Vite build time via import.meta.glob. Exports articles, indexArticle, getArticle(slug), isForwardReference(slug).
calloutPluginsurfcsrc/help/calloutPlugin.jsRemark plugin transforming :::note/:::tip/:::warning/:::danger into HelpCallout AST nodes.
normaliseContainerssurfcsrc/help/normaliseContainers.jsNormalises container element wrappers from remark-directive before the callout plugin processes them.

Edge Functions (Supabase / Deno)

ComponentRepoPathPurpose
anthropic-proxysurfcsupabase/functions/anthropic-proxy/Proxies managed Anthropic calls (transcribe, discover). Runs guardrails (Prompt Shields, harm moderation, spotlighting). Records ai_usage_daily. Enforces per-user quotas. Fail-open on Azure outage.
anthropic-proxy/guardrail.tssurfcsupabase/functions/anthropic-proxy/guardrail.tsAzure AI Content Safety integration. shield() (Prompt Shields + Spotlighting) and moderate() (harm classifiers, threshold ≥5). Fail-open on Azure outage.
anthropic-proxy/prompts.tssurfcsupabase/functions/anthropic-proxy/prompts.tsSingle source of truth for managed-AI system prompts. TRANSCRIBE_SYSTEM, TRANSCRIBE_SYSTEM_ASCII_NOTE, buildDiscoverSystem(customIdeas). Imports GREAT_IDEAS from src/constants.js.
delete-accountsurfcsupabase/functions/delete-account/Permanently deletes the authenticated user’s account. Service-role Supabase client to nuke ai_usage_daily rows and the auth.users record.
approve-waitlistsurfcsupabase/functions/approve-waitlist/Legacy admin-UI approval path. Upserts waitlist_requests with approval status. Retirement tracked SUR-369.
waitlist-signupsurfcsupabase/functions/waitlist-signup/Sunset SUR-367. Historically posted to from the marketing site; clients now hit /auth/v1/signup directly. Kept for reference / rollback.
me-entitlementssurfcsupabase/functions/me-entitlements/Exposes the resolved Entitlements shape (SSoT from _shared/entitlements.ts) for the authenticated user. Called by useEntitlements.
image-uploadsurfcsupabase/functions/image-upload/Note-image uploads. Increments user_profiles.image_storage_bytes_used atomically via adjust_image_storage_bytes RPC. Respects tier storage limits.
create-checkout-sessionsurfcsupabase/functions/create-checkout-session/Creates a Stripe Checkout session for Pro tier upgrade. Upserts stripe_customer_id; sets subscription_data.metadata.user_id for webhook fallback.
create-billing-portal-sessionsurfcsupabase/functions/create-billing-portal-session/Creates a Stripe Customer Portal session for subscription management.
stripe-webhooksurfcsupabase/functions/stripe-webhook/Handles Stripe webhook events (subscription.created/updated/deleted, invoice.paid). Updates user_profiles tier. Idempotent via stripe_webhook_events ledger. Self-heal fallback on customer-id mismatch.

Edge Functions — shared

ComponentRepoPathPurpose
entitlementssurfcsupabase/functions/_shared/entitlements.tsSingle source of truth for Entitlements shape and tier defaults (FREE_DEFAULTS, PRO_DEFAULTS). getResolvedEntitlements(row) resolver.

Marketing — surfc-web components

ComponentRepoPathPurpose
BaseLayoutsurfc-websrc/layouts/BaseLayout.astroShared head (meta, fonts, Termly, PostHog init) and body chrome. Props: title, description, ogImage, path, noindex, nofollow, bodyClass, bodyData.
BlogPostLayoutsurfc-websrc/layouts/BlogPostLayout.astroTemplate for /blog/[slug].astro posts. Extends BaseLayout; renders TOC, article body, publication metadata, reading time.
Navsurfc-websrc/components/Nav.astroTop navigation. Links to /, /pricing, /blog, sign-in/sign-up CTAs. data-cta values for analytics. UTM-preserving via preserveUtm.ts.
Herosurfc-websrc/components/Hero.astroLanding hero. Brand tagline + sign-up / sign-in CTAs. Shared HomeHero styles.
PulledQuotesurfc-websrc/components/PulledQuote.astroTypographic pull-quote section drawn from the Syntopicon philosophy.
WhatSurfcIssurfc-websrc/components/WhatSurfcIs.astroFeature/benefit overview (“Offline-first”, “End-to-end encrypted”, “AI-assisted tagging”).
CapturePassagessurfc-websrc/components/CapturePassages.astroFeature showcase with mockup (“Photograph passages and handwritten notes”).
TagIdeassurfc-websrc/components/TagIdeas.astroFeature showcase (“Tag to 102 canonical ideas or your own”).
SupportingCardssurfc-websrc/components/SupportingCards.astroThree-column feature cards (Fast / Secure / Personal).
Testimonialssurfc-websrc/components/Testimonials.astroUser testimonial carousel/grid.
CapturePhoneMockupsurfc-websrc/components/CapturePhoneMockup.astroiPhone mockup used in feature sections.
Faqsurfc-websrc/components/Faq.astroFrequently asked questions accordion.
PricingFaqsurfc-websrc/components/PricingFaq.astroPricing-specific FAQ.
PricingTierssurfc-websrc/components/PricingTiers.astroFree and Pro tier cards. Price strings duplicated with surfc/src/pages/UpgradeAuthGate.jsx (PRICE_COPY); cross-repo grep before editing.
ClosingCtasurfc-websrc/components/ClosingCta.astroFinal call-to-action section + sign-up CTA.
Footersurfc-websrc/components/Footer.astroSite footer. Links to policies, blog, social, copyright.
AuthorCardsurfc-websrc/components/AuthorCard.astroBlog post author byline card (avatar, name, bio).
TableOfContentssurfc-websrc/components/TableOfContents.astroSticky TOC for blog posts. rehype-autolink-headings integration.

Marketing — surfc-web content & config

ComponentRepoPathPurpose
content.config.tssurfc-websrc/content.config.tsAstro content-collection schema for blog posts (Zod). Fields: title, description, pubDate, author, tags, heroImage, draft.
Blog indexsurfc-websrc/pages/blog/index.astroPaginated blog listing with metadata.
Blog [slug]surfc-websrc/pages/blog/[slug].astroIndividual post renderer. Passes body to BlogPostLayout; integrates MDX.
RSS feedsurfc-websrc/pages/blog/rss.xml.jsRSS feed for all published blog posts.
remark-reading-timesurfc-websrc/plugins/remark-reading-time.mjsRemark plugin injecting estimated reading time into frontmatter (SUR-256).
Landingsurfc-websrc/pages/index.astro/ route. Composes Nav, Hero, PulledQuote, WhatSurfcIs, CapturePassages, TagIdeas, SupportingCards, Testimonials, Faq, ClosingCta, Footer.
Pricingsurfc-websrc/pages/pricing.astro/pricing route. PricingHero, PricingTiers, PricingFaq. UTM preservation, Stripe Checkout integration.
Waitlist redirectsurfc-websrc/pages/waitlist.astro/waitlist sunset page. Friendly “we’ve opened up” + 3 s meta http-equiv="refresh" to app.surfc.app. noindex.
Privacy policysurfc-websrc/pages/policies/privacy.astro/policies/privacy. Termly embed.
Terms policysurfc-websrc/pages/policies/terms.astro/policies/terms. Termly embed.

Marketing — surfc-web utilities

ComponentRepoPathPurpose
authsurfc-websrc/lib/auth.tsReads cross-domain access token from the sb-surfc-access cookie (set by surfc/src/supabase.js). Returns JWT for Stripe calls.
appUrlsurfc-websrc/lib/appUrl.tsShared signupUrl() helper. Returns ${appUrl}/signin for deep-linking past the auth redirect (SUR-711 dropped the ?intent=signup param).
checkoutsurfc-websrc/lib/checkout.tsStripe Checkout integration. Calls create-checkout-session Edge Function.
preserveUtmsurfc-websrc/scripts/preserveUtm.tsForwards UTM params from the marketing page onto every <a data-cta> cross-domain href. Re-attaches on astro:page-load. Inverse of surfc/src/lib/utmParams.js.
astro.configsurfc-webastro.config.mjsAstro config. MDX + rehype-slug + rehype-autolink-headings + remarkReadingTime. trailingSlash: 'always'. Static output (no adapter).
.nvmrcsurfc-web.nvmrcPins Node 22; matches engines.node and the Cloudflare Pages runtime (SUR-254).

Recently sunset

These components have been removed from the codebase but are listed here for historical reference — older PRs, plan docs, and CLAUDE.md snippets may still reference them.

ComponentRepoRemoved byNotes
WaitlistFormsurfc-webSUR-365 (2026-05-10)Deleted along with tests/waitlist.spec.ts and tests/fixtures/cors-server.mjs. Marketing CTAs now compose signupUrl() from src/lib/appUrl.ts, deep-linking to app.surfc.app/signin (SUR-711 dropped the ?intent=signup param). src/pages/waitlist.astro replaced with a noindex sunset page (3 s meta refresh to app.surfc.app).
LandingPagesurfcSUR-215 (2026-04-23)Marketing surface now lives entirely in surfc-web/.
WaitlistScreensurfcSUR-215 (2026-04-23)Pre-open-signup waitlist gate (PendingApprovalScreen) was removed alongside in SUR-364 (2026-05-10) when Surfc flipped to direct signup.
HowItWorksPagesurfcSUR-215 (2026-04-23)Replaced by the marketing landing page in surfc-web/.

Evidence gathered from source files only, per AGENTS.md.