/* ── Toast notifications ── */

.toast-stack {
  position: fixed;
  bottom: 24px;
  right: 20px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  z-index: 500;
  pointer-events: none;
  max-width: min(420px, calc(100vw - 40px));
}

.toast {
  background: var(--header-bg);
  color: var(--header-text);
  padding: 9px 16px;
  border-radius: 20px;
  font-size: 0.82rem;
  font-weight: 600;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.22);
  animation: toast-life 3s ease forwards;
  white-space: nowrap;
}

@keyframes toast-life {
  0%   { opacity: 0; transform: translateX(10px); }
  12%  { opacity: 1; transform: translateX(0); }
  75%  { opacity: 1; }
  100% { opacity: 0; }
}

.toast.error {
  background: var(--danger);
  animation: toast-in 0.25s ease forwards;
  pointer-events: auto;
  white-space: normal;
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 10px 14px;
  border-radius: 12px;
}

/* Long-running status (e.g. bulk upload). Opts out of the auto-dismiss
   animation — the caller updates the text in place and removes the toast
   explicitly when the underlying operation finishes. */
.toast.sticky {
  animation: toast-in 0.25s ease forwards;
}

@keyframes toast-in {
  0%   { opacity: 0; transform: translateX(10px); }
  100% { opacity: 1; transform: translateX(0); }
}

.toast-details {
  margin: 2px 0 0;
  padding: 0 0 0 16px;
  font-weight: 400;
  font-size: 0.78rem;
  opacity: 0.92;
}

.toast-details li {
  margin: 1px 0;
}

.toast-dismiss {
  align-self: flex-end;
  background: none;
  border: none;
  color: rgba(255, 255, 255, 0.7);
  cursor: pointer;
  font-size: 0.78rem;
  padding: 10px 12px;
  min-width: 44px;
  min-height: 44px;
  margin-top: 2px;
}

.toast-dismiss:hover {
  color: #fff;
}

/* ── Password-change recovery notice ──
   App-wide and modal, because the code it carries is the account's only
   remaining recovery material and the rotation that issued it may have
   completed with no page of its own on screen (a crash-interrupted change
   finishes on a later worker startup). Above the toasts, below the fatal
   states banner: this must be dismissed deliberately, but it is not an
   error. */

.pw-recovery-notice {
  position: fixed;
  inset: 0;
  z-index: 1500;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  background: rgba(0, 0, 0, 0.55);
}

.pw-recovery-notice-inner {
  background: var(--header-bg);
  border: 1px solid var(--accent);
  border-radius: 12px;
  padding: 1.25rem;
  max-width: min(480px, 100%);
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.pw-recovery-notice-inner h2 {
  margin: 0;
  font-size: 1.05rem;
}

.pw-recovery-notice-inner .recovery-code {
  display: block;
  font-size: 1.1rem;
  letter-spacing: 0.05em;
  word-break: break-all;
  padding: 0.6rem 0.75rem;
  border-radius: 8px;
  background: var(--accent-soft);
  color: var(--text);
}
