diff --git a/ghostkey-web/src/App.tsx b/ghostkey-web/src/App.tsx index bab01bc..541e03c 100644 --- a/ghostkey-web/src/App.tsx +++ b/ghostkey-web/src/App.tsx @@ -359,13 +359,13 @@ export default function App() { Skip to content - {/* Wait for the first /health probe before showing the network - banner. `network` defaults to "testnet", so rendering early - flashed an "Alpha: testnet, don't use real money" warning on - every reload of a mainnet vault before flipping to the live - banner. A wrong-network safety warning, even for a moment, - is worse than a brief absence. */} - {health !== "unknown" && } + {/* Only show the network banner once /health has SUCCEEDED. + `network` defaults to "testnet", so rendering before the + probe (or after a failed one) told a mainnet owner + "Alpha: testnet, don't use real-money keys" — false and + alarming at the exact moment the server was already down. + When the probe fails, ServerOfflineBanner below covers it. */} + {health === "ok" && } {demoMode && } {health === "offline" && } {/* diff --git a/ghostkey-web/src/SignInPortal.tsx b/ghostkey-web/src/SignInPortal.tsx index 4866ad2..2679221 100644 --- a/ghostkey-web/src/SignInPortal.tsx +++ b/ghostkey-web/src/SignInPortal.tsx @@ -81,6 +81,10 @@ type Phase = export function SignInPortal({ onNavigate }: Props) { const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); + // Mistyped passwords are the #1 sign-in failure, and the field hides + // every character. A show toggle costs nothing and rescues most of + // them (Bitcoin UX principle: password UX is money UX). + const [showPassword, setShowPassword] = useState(false); const [phase, setPhase] = useState({ kind: "idle" }); const [error, setError] = useState(null); @@ -351,17 +355,27 @@ export function SignInPortal({ onNavigate }: Props) { - { - setPassword(e.target.value); - reset(); - }} - autoComplete="current-password" - className="input" - disabled={phase.kind === "looking" || phase.kind === "unsealing"} - /> +
+ { + setPassword(e.target.value); + reset(); + }} + autoComplete="current-password" + className="input pr-16" + disabled={phase.kind === "looking" || phase.kind === "unsealing"} + /> + +
{phase.kind === "unsealing" ? (