diff --git a/src/app/(admin)/admin/settings/page.tsx b/src/app/(admin)/admin/settings/page.tsx
index 947b5dc..79207a9 100644
--- a/src/app/(admin)/admin/settings/page.tsx
+++ b/src/app/(admin)/admin/settings/page.tsx
@@ -49,8 +49,9 @@ export default async function AdminSettingsPage() {
{readiness ? (
) : null}
diff --git a/src/app/app/access/page.tsx b/src/app/app/access/page.tsx
index 0021ad9..b36a6a8 100644
--- a/src/app/app/access/page.tsx
+++ b/src/app/app/access/page.tsx
@@ -2,7 +2,18 @@ import Link from "next/link";
import { Card } from "@/components/ui/card";
-function resolveCopy(status: string | undefined, reason: string | undefined) {
+type AccessCopy = {
+ eyebrow: string;
+ title: string;
+ body: string;
+ reason?: string;
+ actionHref: string;
+ actionLabel: string;
+ /** Overrides the default "what this means" bullets (which describe suspension). */
+ points?: string[];
+};
+
+function resolveCopy(status: string | undefined, reason: string | undefined): AccessCopy {
if (status === "superadmin-setup") {
return {
eyebrow: "Platform owner setup required",
@@ -22,8 +33,18 @@ function resolveCopy(status: string | undefined, reason: string | undefined) {
body:
"Superadmin access is private and requires both an allowlisted email address and a persisted platform role.",
reason: "Use the normal admin or buyer workspace for this account.",
- actionHref: "/",
- actionLabel: "Return to homepage",
+ // Send tenant operators back to their own workspace, not the marketing
+ // homepage — this page is reached by an ordinary admin who simply hit a
+ // /superadmin URL.
+ actionHref: "/admin",
+ actionLabel: "Go to your dashboard",
+ // The default bullets describe a SUSPENDED company, which is wrong here:
+ // nothing is blocked for this user, they just aren't a platform owner.
+ points: [
+ "Your company workspace is unaffected — admin, portal, and payment actions all still work.",
+ "The platform owner dashboard is reserved for EstateOS staff.",
+ "If you reached this by mistake, continue in your own admin dashboard.",
+ ],
};
}
@@ -80,9 +101,15 @@ export default async function AppAccessPage({
What this means
- - Admin dashboards, portal access, and payment actions are currently blocked.
- - Super admins can still inspect the company safely from the platform command center.
- - Once the company is reactivated, normal access resumes automatically.
+ {(
+ copy.points ?? [
+ "Admin dashboards, portal access, and payment actions are currently blocked.",
+ "Super admins can still inspect the company safely from the platform command center.",
+ "Once the company is reactivated, normal access resumes automatically.",
+ ]
+ ).map((point) => (
+ - {point}
+ ))}
diff --git a/src/components/shared/logo.tsx b/src/components/shared/logo.tsx
index d6560e2..cef1da5 100644
--- a/src/components/shared/logo.tsx
+++ b/src/components/shared/logo.tsx
@@ -35,8 +35,13 @@ export function Logo({
monogram
)}
-
-
+ {/* min-w-0 lets this flex child shrink inside narrow shells (e.g. the
+ dashboard sidebar). A hard min-width here caused long company names
+ such as "Blueprint Urban Residences LTD" to overflow and get clipped
+ by the parent's overflow-hidden. The name wraps instead of truncating
+ so the full company name always stays readable. */}
+
+
{name}
{showTagline && tagline ? (
diff --git a/src/components/shared/tenant-readiness-checklist.tsx b/src/components/shared/tenant-readiness-checklist.tsx
index 3967cc8..bff506c 100644
--- a/src/components/shared/tenant-readiness-checklist.tsx
+++ b/src/components/shared/tenant-readiness-checklist.tsx
@@ -16,18 +16,35 @@ const statusClasses = {
missing: "border-rose-200 bg-rose-50 text-rose-800",
} as const;
+/**
+ * Readiness items owned by EstateOS itself (platform Paystack keys, R2 storage,
+ * superadmin-only checks). A tenant admin can neither see nor action these — and
+ * their action links point at /superadmin/*, which tenants cannot open — so they
+ * are hidden from the tenant audience and shown only to superadmins.
+ */
+const PLATFORM_OWNERS = new Set(["Platform", "Superadmin"]);
+
+export function isTenantVisibleReadinessItem(item: TenantReadinessItem) {
+ return !PLATFORM_OWNERS.has(item.owner) && !item.actionLink.startsWith("/superadmin");
+}
+
export function TenantReadinessChecklist({
title = "Go-live readiness",
description = "Resolve these items before onboarding real buyers and payments.",
items,
+ audience = "superadmin",
}: {
title?: string;
description?: string;
items: TenantReadinessItem[];
+ /** "tenant" hides platform/superadmin-owned items. Defaults to the full list. */
+ audience?: "tenant" | "superadmin";
}) {
- const missing = items.filter((item) => item.status === "missing").length;
- const warnings = items.filter((item) => item.status === "warning").length;
- const complete = items.filter((item) => item.status === "complete").length;
+ const visibleItems =
+ audience === "tenant" ? items.filter(isTenantVisibleReadinessItem) : items;
+ const missing = visibleItems.filter((item) => item.status === "missing").length;
+ const warnings = visibleItems.filter((item) => item.status === "warning").length;
+ const complete = visibleItems.filter((item) => item.status === "complete").length;
return (
@@ -43,7 +60,7 @@ export function TenantReadinessChecklist({
- {items.map((item) => (
+ {visibleItems.map((item) => (
diff --git a/src/modules/portal/payments-layout.test.ts b/src/modules/portal/payments-layout.test.ts
index e3331f6..6b1638d 100644
--- a/src/modules/portal/payments-layout.test.ts
+++ b/src/modules/portal/payments-layout.test.ts
@@ -81,7 +81,10 @@ test("payment summary cards wrap long values instead of clipping", () => {
assert.match(logoSource, /showTagline = true/);
assert.match(logoSource, /showTagline && tagline/);
assert.match(dashboardShellSource, /showTagline=\{false\}/);
- assert.match(logoSource, /overflow-visible/);
+ // The name wrapper uses break-words (not a hard min-width) so long company
+ // names wrap instead of overflowing the sidebar card.
+ assert.match(logoSource, /break-words/);
+ assert.doesNotMatch(logoSource, /sm:min-w-\[11rem\]/);
assert.doesNotMatch(logoSource, /tenant-logo-tagline[^\n]+whitespace-nowrap/);
assert.match(globalsSource, /--duration-fast: 120ms/);
assert.match(globalsSource, /--tenant-motion-duration: 160ms/);