/* ── 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);
}

/* ── The report composer ──────────────────────────────────────────────────
   The dialog a Report control opens, from a People row, a comment, a followed
   activity or an announced plan (specs/social.allium, ReportComposer). A
   dialog rather than a page because the thing being reported has to stay on
   the screen behind it: a report is quoted evidence.

   Above the header (z-index 100) for the reason the waypoint menu gives: it
   calls itself a modal dialog, and a dialog with a live header above it is
   not one (docs/invariants/accessibility.md A11Y-22, A11Y-23). */
.report-backdrop {
  position: fixed;
  inset: 0;
  z-index: 200;
  background: rgba(0, 0, 0, 0.45);
}

.report-dialog {
  position: fixed;
  z-index: 201;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: min(560px, calc(100vw - 32px));
  max-height: calc(100vh - 48px);
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  padding: 1.1rem;
  border-radius: 12px;
  border: 1px solid var(--border);
  background: var(--surface);
  box-shadow: var(--shadow-md);
}

.report-title {
  margin: 0;
  font-size: 1.05rem;
}

.report-about {
  margin: 0;
  color: var(--text-muted);
  font-size: 0.85rem;
}

.report-field-label {
  margin: 0;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--text-muted);
}

.report-reason,
.report-note {
  width: 100%;
  padding: 8px 10px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--surface-alt);
  color: var(--text);
  font-family: inherit;
  font-size: 0.9rem;
}

.report-note {
  min-height: 4.5rem;
  resize: vertical;
}

/* The disclosure, above the preview: what is about to be sent, to whom, and
   by whom. Deliberately not muted — it is the one paragraph on this dialog a
   person must not skim past (TheReporterReadsWhatIsSent). */
.report-disclosure {
  margin: 0;
  padding: 0.6rem 0.75rem;
  border-radius: 8px;
  background: var(--accent-soft);
  color: var(--text);
  font-size: 0.85rem;
  line-height: 1.45;
}

/* The email itself, not a summary of it. Wrapped rather than scrolled
   sideways, so a long quoted comment reads. */
.report-preview {
  margin: 0;
  max-height: 14rem;
  overflow-y: auto;
  padding: 0.6rem 0.75rem;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--surface-alt);
  color: var(--text);
  font-size: 0.78rem;
  line-height: 1.4;
  white-space: pre-wrap;
  word-break: break-word;
}

.report-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: 0.5rem;
}

.report-blocked {
  margin: 0;
  color: var(--text-muted);
  font-size: 0.8rem;
}

.social-btn.report-send {
  background: var(--text);
  color: var(--surface);
  text-decoration: none;
}

.social-btn.report-close,
.social-btn.report-copy {
  background: var(--surface-alt);
  color: var(--text-muted);
}

.social-btn.report-close:hover,
.social-btn.report-copy:hover {
  background: var(--border);
}
