diff --git a/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.Client/Pages/Receiver/EnvelopeExpired.razor b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.Client/Pages/Receiver/EnvelopeExpired.razor
new file mode 100644
index 00000000..f6544983
--- /dev/null
+++ b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.Client/Pages/Receiver/EnvelopeExpired.razor
@@ -0,0 +1,24 @@
+@page "/envelope-expired"
+@layout EnvelopeGenerator.ReceiverUI.Web.Client.Layout.ReceiverLayout
+@rendermode InteractiveAuto
+@inject LocalizationService Loc
+
+@*
+ Counterpart of Views/Envelope/EnvelopeExpired.cshtml.
+*@
+
+@Loc["Expired"]
+
+
+
+
+ @Loc["DocumentSharingPeriodExpired"]
+
+
+
+@code {
+ protected override async Task OnInitializedAsync() => await Loc.EnsureLoadedAsync();
+}
diff --git a/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.Client/Pages/Receiver/EnvelopeKeyRedirect.razor b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.Client/Pages/Receiver/EnvelopeKeyRedirect.razor
new file mode 100644
index 00000000..5251d291
--- /dev/null
+++ b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.Client/Pages/Receiver/EnvelopeKeyRedirect.razor
@@ -0,0 +1,20 @@
+@page "/envelopekey/{*Path}"
+@layout EnvelopeGenerator.ReceiverUI.Web.Client.Layout.ReceiverLayout
+@rendermode InteractiveAuto
+@inject NavigationManager Nav
+
+@*
+ Counterpart of EnvelopeKeyRedirController:
+ /EnvelopeKey/{*path} ? /envelope/{path}
+ Preserves backwards compatibility with links generated by older e-mails.
+*@
+
+@code {
+ [Parameter] public string? Path { get; set; }
+
+ protected override void OnInitialized()
+ {
+ var target = "/envelope/" + (Path ?? string.Empty).TrimStart('/');
+ Nav.NavigateTo(target, replace: true);
+ }
+}
diff --git a/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.Client/Pages/Receiver/EnvelopeLockedView.razor b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.Client/Pages/Receiver/EnvelopeLockedView.razor
new file mode 100644
index 00000000..fb3a1bd0
--- /dev/null
+++ b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.Client/Pages/Receiver/EnvelopeLockedView.razor
@@ -0,0 +1,229 @@
+@implements IDisposable
+@inject ReceiverApiClient Api
+@inject ReceiverAuthState State
+@inject LocalizationService Loc
+
+@*
+ Counterpart of EnvelopeGenerator.Web/Views/Envelope/EnvelopeLocked.cshtml.
+
+ Renders one of three input modes based on the current auth state:
+
+ • Status == requires_access_code
+ ? AccessCode input (+ optional "2FA per SMS" toggle)
+
+ • Status == requires_tfa, TfaType == "sms"
+ ? SMS code input + countdown until TfaExpiration
+
+ • Status == requires_tfa, TfaType == "authenticator"
+ ? Authenticator code input + "set up authenticator" link
+
+ On submit, the matching ReceiverApiClient method is invoked. The fresh
+ response replaces ReceiverAuthState.Current; the parent EnvelopePage
+ re-renders and either shows the document or navigates to a terminal page.
+*@
+
+
+
+ @* — Welcome banner (custom company image is added in Phase 6) — *@
+
+
+
+
+ @Loc[$"LockedTitle{CodeKey}"]
+
+
+ @* — "Set up authenticator" hint, shown only on the authenticator step — *@
+ @if (IsAuthenticator)
+ {
+
+
+ @Loc["AuthenticatorSetup_Prefix"]
+
+ @Loc["AuthenticatorSetup_Link"]
+
+ @Loc["AuthenticatorSetup_Suffix"]
+
+
+ }
+
+
+ @Loc[$"LockedBody{CodeKey}"]
+
+
+
+
+ @if (!string.IsNullOrEmpty(State.Current?.ErrorMessage))
+ {
+
+ @State.Current.ErrorMessage
+
+ }
+
+
+
+ @Loc[$"LockedFooterTitle{CodeKey}"]
+
+ @Loc.Format($"LockedFooterBody{CodeKey}",
+ State.Current?.SenderEmail ?? string.Empty,
+ $"Envelope - {State.Current?.Title}",
+ string.Empty)
+
+
+
+
+
+@code {
+ [Parameter] public string EnvelopeKey { get; set; } = string.Empty;
+
+ private string Code { get; set; } = string.Empty;
+ private bool PreferSms { get; set; }
+ private bool _submitting;
+ private System.Threading.Timer? _smsTimer;
+ private string? _smsRemaining;
+
+ // — Mode helpers ????????????????????????????????????????????????
+ private bool IsAccessCodeStep => State.Current?.Status == ReceiverAuthStatus.RequiresAccessCode;
+ private bool IsTfa => State.Current?.Status == ReceiverAuthStatus.RequiresTfa;
+ private bool IsSms => IsTfa && State.Current?.TfaType == "sms";
+ private bool IsAuthenticator => IsTfa && State.Current?.TfaType == "authenticator";
+
+ ///
+
+ @Loc["EnvelopeNotFoundTitle"]
+
+
+ @Loc["EnvelopeNotFoundBody"]
+
+
+
+@code {
+ protected override async Task OnInitializedAsync() => await Loc.EnsureLoadedAsync();
+}
diff --git a/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.Client/Pages/Receiver/EnvelopePage.razor b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.Client/Pages/Receiver/EnvelopePage.razor
new file mode 100644
index 00000000..e2eccd7f
--- /dev/null
+++ b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.Client/Pages/Receiver/EnvelopePage.razor
@@ -0,0 +1,110 @@
+@page "/envelope/{Key}"
+@layout EnvelopeGenerator.ReceiverUI.Web.Client.Layout.ReceiverLayout
+@rendermode InteractiveAuto
+@inject ReceiverApiClient Api
+@inject ReceiverAuthState State
+@inject LocalizationService Loc
+@inject NavigationManager Nav
+
+@*
+ Counterpart of EnvelopeGenerator.Web/Controllers/EnvelopeController.Main.
+
+ Behavior:
+ 1. Calls GET /api/receiverauth/{key}/status.
+ 2. Routes to a sub-view based on the response Status:
+ - requires_access_code / requires_tfa ? EnvelopeLockedView (Phase 3)
+ - show_document ? ShowEnvelopeView (Phase 4)
+ - already_signed ? /envelope-signed
+ - rejected ? /envelope-rejected
+ - not_found ? /envelope-not-found
+ - expired ? /envelope-expired
+ - error ? inline error banner
+
+ Sub-views are simple placeholders here; they are filled with real UI
+ in later phases. The routing skeleton just needs to compile and
+ transition correctly.
+*@
+
+
+
@Loc["UnexpectedErrorTitle"]
+
+}
+else
+{
+ switch (Auth.Status)
+ {
+ case ReceiverAuthStatus.RequiresAccessCode:
+ case ReceiverAuthStatus.RequiresTfa:
+
+
@(Auth.ErrorMessage ?? Loc["UnexpectedErrorTitle"])
+
+ break;
+ }
+}
+
+@code {
+ [Parameter] public string Key { get; set; } = string.Empty;
+
+ private bool _loading = true;
+ private ReceiverAuthResponse? Auth => State.Current;
+
+ protected override async Task OnInitializedAsync()
+ {
+ await Loc.EnsureLoadedAsync();
+ State.Changed += OnStateChanged;
+ }
+
+ protected override async Task OnParametersSetAsync()
+ {
+ // Re-fetch status if the route key changed or no response loaded yet.
+ if (State.EnvelopeKey != Key || State.Current is null)
+ {
+ _loading = true;
+ var res = await Api.GetStatusAsync(Key);
+ State.Set(Key, res);
+ RedirectIfTerminal(res);
+ _loading = false;
+ }
+ else
+ {
+ _loading = false;
+ }
+ }
+
+ private void RedirectIfTerminal(ReceiverAuthResponse? res)
+ {
+ if (res is null) return;
+ var target = res.Status switch
+ {
+ ReceiverAuthStatus.AlreadySigned => "/envelope-signed",
+ ReceiverAuthStatus.Rejected => "/envelope-rejected",
+ ReceiverAuthStatus.NotFound => "/envelope-not-found",
+ ReceiverAuthStatus.Expired => "/envelope-expired",
+ _ => null
+ };
+ if (target is not null)
+ Nav.NavigateTo(target, replace: true);
+ }
+
+ private void OnStateChanged() => InvokeAsync(StateHasChanged);
+
+ public void Dispose() => State.Changed -= OnStateChanged;
+}
diff --git a/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.Client/Pages/Receiver/EnvelopeRejected.razor b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.Client/Pages/Receiver/EnvelopeRejected.razor
new file mode 100644
index 00000000..256498b3
--- /dev/null
+++ b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.Client/Pages/Receiver/EnvelopeRejected.razor
@@ -0,0 +1,39 @@
+@page "/envelope-rejected"
+@layout EnvelopeGenerator.ReceiverUI.Web.Client.Layout.ReceiverLayout
+@rendermode InteractiveAuto
+@inject ReceiverAuthState State
+@inject LocalizationService Loc
+
+@*
+ Counterpart of Views/Envelope/EnvelopeRejected.cshtml.
+ Reads envelope title / sender info from the cached auth response,
+ which is populated by EnvelopePage before navigation occurs.
+*@
+
+
+
+
+ @Loc["RejectionInfo1"]
+
+
+
+ @(Loc["RejectionInfo2"])
+
+ @if (State.Current is not null)
+ {
+
+ @State.Current.Title
+ @if (!string.IsNullOrEmpty(State.Current.SenderEmail))
+ {
+ — @State.Current.SenderEmail
+ }
+
+ }
+
+
+
+@code {
+ protected override async Task OnInitializedAsync() => await Loc.EnsureLoadedAsync();
+}
diff --git a/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.Client/Pages/Receiver/EnvelopeSigned.razor b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.Client/Pages/Receiver/EnvelopeSigned.razor
new file mode 100644
index 00000000..676fb83f
--- /dev/null
+++ b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.Client/Pages/Receiver/EnvelopeSigned.razor
@@ -0,0 +1,31 @@
+@page "/envelope-signed"
+@layout EnvelopeGenerator.ReceiverUI.Web.Client.Layout.ReceiverLayout
+@rendermode InteractiveAuto
+@inject LocalizationService Loc
+
+@*
+ Counterpart of Views/Envelope/EnvelopeSigned.cshtml.
+ Full styling (icon + section card) is migrated in Phase 6.
+*@
+
+
+
+
+ @Loc["DocumentSuccessfullySigned"]
+
+
+ @Loc["DocumentSignedConfirmationMessage"]
+
+
+
+@code {
+ protected override async Task OnInitializedAsync() => await Loc.EnsureLoadedAsync();
+}
diff --git a/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.Client/Pages/Receiver/Error404.razor b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.Client/Pages/Receiver/Error404.razor
new file mode 100644
index 00000000..745a5473
--- /dev/null
+++ b/receiverUI/EnvelopeGenerator.ReceiverUI.Web/EnvelopeGenerator.ReceiverUI.Web.Client/Pages/Receiver/Error404.razor
@@ -0,0 +1,88 @@
+@page "/error404"
+@layout EnvelopeGenerator.ReceiverUI.Web.Client.Layout.ReceiverLayout
+@rendermode InteractiveAuto
+@inject LocalizationService Loc
+@inject NavigationManager Nav
+@inject IJSRuntime JS
+
+@*
+ Counterpart of HomeController.Error404 ? Views/Shared/_Error.cshtml.
+
+ The legacy view fully replaces the document with a black-space themed
+ layout. In Blazor we keep the receiver layout intact (so the user can
+ still reach the language switcher) and only scope error-space.css to
+ this page via