diff --git a/public/configuration/housekeeping-texts-en.example b/public/configuration/housekeeping-texts-en.example
index b432660..3e16a74 100644
--- a/public/configuration/housekeeping-texts-en.example
+++ b/public/configuration/housekeeping-texts-en.example
@@ -16,6 +16,14 @@
"housekeeping.action.pending": "Action pending…",
"housekeeping.action.success": "Action completed",
"housekeeping.action.error": "Action failed",
+ "housekeeping.action.reset_password.done": "Password reset — new password shown below.",
+ "housekeeping.password.title": "%username% (#%id%) · new password",
+ "housekeeping.password.value_label": "Generated password",
+ "housekeeping.password.copy": "Copy",
+ "housekeeping.password.copied": "Copied",
+ "housekeeping.password.copy_failed": "Copy failed",
+ "housekeeping.password.dismiss": "Dismiss",
+ "housekeeping.password.hint": "Share with the user out-of-band. This is shown once — close this card when you're done; the password is never displayed again.",
"housekeeping.error.invalid_input": "Invalid input — check the user id and the value you provided.",
"housekeeping.error.user_not_found": "User not found.",
"housekeeping.error.user_offline": "User is offline — this action only works on online users.",
diff --git a/public/configuration/housekeeping-texts-it.example b/public/configuration/housekeeping-texts-it.example
index 80ea048..8f5903f 100644
--- a/public/configuration/housekeeping-texts-it.example
+++ b/public/configuration/housekeeping-texts-it.example
@@ -16,6 +16,14 @@
"housekeeping.action.pending": "Azione in corso…",
"housekeeping.action.success": "Azione completata",
"housekeeping.action.error": "Azione fallita",
+ "housekeeping.action.reset_password.done": "Password resettata — la nuova password è mostrata sotto.",
+ "housekeeping.password.title": "%username% (#%id%) · nuova password",
+ "housekeeping.password.value_label": "Password generata",
+ "housekeeping.password.copy": "Copia",
+ "housekeeping.password.copied": "Copiata",
+ "housekeeping.password.copy_failed": "Copia fallita",
+ "housekeeping.password.dismiss": "Chiudi",
+ "housekeeping.password.hint": "Condividila con l'utente fuori dal client. La password viene mostrata una sola volta — chiudi questa card quando hai finito, non sarà più visibile.",
"housekeeping.error.invalid_input": "Input non valido — controlla l'id utente e il valore inserito.",
"housekeeping.error.user_not_found": "Utente non trovato.",
"housekeeping.error.user_offline": "Utente offline — questa azione funziona solo sugli utenti online.",
diff --git a/src/components/housekeeping/HousekeepingPasswordReveal.tsx b/src/components/housekeeping/HousekeepingPasswordReveal.tsx
new file mode 100644
index 0000000..b88f476
--- /dev/null
+++ b/src/components/housekeeping/HousekeepingPasswordReveal.tsx
@@ -0,0 +1,149 @@
+import { FC, useEffect, useState } from 'react';
+import { FaCheck, FaCopy, FaKey, FaTimes } from 'react-icons/fa';
+import { LocalizeText } from '../../api';
+import { useHousekeepingStore } from '../../hooks';
+
+const COPY_CONFIRM_MS = 1600;
+
+/**
+ * Password-reveal card — surfaces the plaintext password the emulator
+ * returned from `HousekeepingResetUserPasswordEvent` so the operator
+ * can read it once and copy it out-of-band to the user.
+ *
+ * Sensitive data, so:
+ * - Renders OUTSIDE the auto-dismissing status banner (which truncates
+ * long content and disappears after 4s).
+ * - Stays put until the operator explicitly dismisses — they have to
+ * acknowledge they've copied/communicated the secret.
+ * - The plaintext lives in `useHousekeepingStore.passwordReveal` and
+ * never flows through the generic success-toast / banner pipeline
+ * (`useHousekeepingActions.resetUserPassword` intercepts it before
+ * `wrap`'s default path).
+ * - The clipboard write uses the modern `navigator.clipboard.writeText`
+ * when available, with a `document.execCommand('copy')` fallback for
+ * non-secure-context legacy paths so the button still works inside an
+ * `http://` deployment.
+ */
+export const HousekeepingPasswordReveal: FC = () =>
+{
+ const { passwordReveal, clearPasswordReveal } = useHousekeepingStore();
+ const [ copyState, setCopyState ] = useState<'idle' | 'ok' | 'fail'>('idle');
+
+ // Reset the "copied!" visual whenever a new reveal lands so the
+ // operator doesn't see a stale checkmark from a previous reset.
+ useEffect(() =>
+ {
+ setCopyState('idle');
+ }, [ passwordReveal?.password ]);
+
+ // Auto-revert the copy-confirmation icon back to the copy icon
+ // a short while after a successful copy. The plaintext itself
+ // stays revealed until the operator explicitly dismisses.
+ useEffect(() =>
+ {
+ if(copyState === 'idle') return;
+
+ const handle = window.setTimeout(() => setCopyState('idle'), COPY_CONFIRM_MS);
+
+ return () => window.clearTimeout(handle);
+ }, [ copyState ]);
+
+ if(!passwordReveal) return null;
+
+ const copyPassword = async () =>
+ {
+ const text = passwordReveal.password;
+
+ if(!text) return;
+
+ // Modern path — requires a secure context (https / wss / localhost).
+ if(typeof navigator !== 'undefined' && navigator.clipboard && window.isSecureContext)
+ {
+ try
+ {
+ await navigator.clipboard.writeText(text);
+ setCopyState('ok');
+ return;
+ }
+ catch
+ {
+ // Fall through to the legacy path below — some browsers
+ // still gate the modern API behind extra permissions even
+ // in secure contexts.
+ }
+ }
+
+ // Legacy fallback: stage a textarea, select, exec copy. Works
+ // on plain-http deployments where `navigator.clipboard` is
+ // refused. The textarea is positioned off-screen so the user
+ // doesn't see a flash.
+ try
+ {
+ const textarea = document.createElement('textarea');
+ textarea.value = text;
+ textarea.setAttribute('readonly', '');
+ textarea.style.position = 'absolute';
+ textarea.style.left = '-9999px';
+ textarea.style.top = '0';
+ document.body.appendChild(textarea);
+ textarea.select();
+ textarea.setSelectionRange(0, text.length);
+ const ok = document.execCommand('copy');
+ document.body.removeChild(textarea);
+ setCopyState(ok ? 'ok' : 'fail');
+ }
+ catch
+ {
+ setCopyState('fail');
+ }
+ };
+
+ const copyIcon = copyState === 'ok' ?
{ LocalizeText('housekeeping.password.hint') }
+