/* ─────────────────────────────────────────────────────────────────
 * Neo-Brutalist canonical animations & utilities for the vanilla SPA.
 *
 * The React micro-apps (aml-dossier-app, etc.) bring their own keyframes
 * via tailwind.config.js. The vanilla SPA loads Tailwind from CDN, which
 * doesn't process a config — so the same keyframes live here as plain CSS
 * utility classes. Keep names identical to the React side so docs and
 * mental model stay in sync.
 *
 * See CLAUDE.md → "Visual Style — Neo-Brutalist canonical pattern"
 * ───────────────────────────────────────────────────────────────── */

@keyframes nb-row-in {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes nb-enter {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes nb-pop-in {
  0%   { opacity: 0; transform: scale(0.6); }
  70%  { opacity: 1; transform: scale(1.08); }
  100% { opacity: 1; transform: scale(1); }
}
@keyframes nb-scale-in {
  from { opacity: 0; transform: scale(0.96); }
  to   { opacity: 1; transform: scale(1); }
}

.animate-row-in   { animation: nb-row-in   0.35s cubic-bezier(0.22, 1, 0.36, 1) both; }
.animate-enter    { animation: nb-enter    0.35s cubic-bezier(0.25, 0.1, 0.25, 1) both; }
.animate-pop-in   { animation: nb-pop-in   0.5s  cubic-bezier(0.34, 1.56, 0.64, 1) both; }
.animate-scale-in { animation: nb-scale-in 0.25s cubic-bezier(0.22, 1, 0.36, 1) both; }

/* Focus ring matching React side. The vanilla app has no `--ring` token,
 * so we use foreground ink with a translucent halo. */
.nb-focus-ring:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px #ffffff, 0 0 0 4px #0d0d0d;
  border-radius: inherit;
}

/* ─────────────────────────────────────────────────────────────────
 * SweetAlert2 popup styled to neo-brutalist canon. Used by the
 * "Riepilogo Notturno" modal and any other vanilla SPA Swal.fire
 * call that opts in via customClass.popup = 'nb-summary-popup'.
 * ───────────────────────────────────────────────────────────────── */
.nb-summary-popup.swal2-popup {
  border: 2px solid #0d0d0d;
  border-radius: 12px;
  box-shadow: 6px 6px 0 #0d0d0d;
  padding: 1.25rem;
}

.nb-summary-popup .swal2-actions {
  gap: 0.5rem;
  margin-top: 1rem;
  flex-wrap: wrap;
  justify-content: center;
}

.nb-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.25rem;
  padding: 0.55rem 1rem;
  font-size: 0.8125rem;
  font-weight: 900;
  border: 2px solid #0d0d0d;
  border-radius: 8px;
  cursor: pointer;
  transition: transform 120ms ease, box-shadow 120ms ease, background-color 120ms ease;
  line-height: 1;
}
.nb-btn:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px #ffffff, 0 0 0 4px #0d0d0d;
}
.nb-btn-primary {
  background: #0d0d0d;
  color: #ffffff;
  box-shadow: 3px 3px 0 #0d0d0d;
}
.nb-btn-primary:hover {
  transform: translate(-2px, -2px);
  box-shadow: 5px 5px 0 #0d0d0d;
}
.nb-btn-primary:active {
  transform: translate(0, 0);
  box-shadow: 1px 1px 0 #0d0d0d;
}
.nb-btn-secondary {
  background: #ffffff;
  color: #0d0d0d;
  box-shadow: 3px 3px 0 #0d0d0d;
}
.nb-btn-secondary:hover {
  background: #fef9c3;
  transform: translate(-2px, -2px);
  box-shadow: 5px 5px 0 #0d0d0d;
}
.nb-btn-secondary:active {
  transform: translate(0, 0);
  box-shadow: 1px 1px 0 #0d0d0d;
}
.nb-btn-danger {
  background: #ffffff;
  color: #b91c1c;
  box-shadow: 3px 3px 0 #b91c1c;
  border-color: #b91c1c;
}
.nb-btn-danger:hover {
  background: #fee2e2;
  transform: translate(-2px, -2px);
  box-shadow: 5px 5px 0 #b91c1c;
}
.nb-btn-danger:active {
  transform: translate(0, 0);
  box-shadow: 1px 1px 0 #b91c1c;
}
.nb-btn-ghost {
  background: transparent;
  color: #0d0d0d;
  border-color: transparent;
  box-shadow: none;
  font-weight: 700;
  text-decoration: underline;
  text-underline-offset: 3px;
}
.nb-btn-ghost:hover {
  background: #f5f0e8;
  border-color: #0d0d0d;
}

/* ─────────────────────────────────────────────────────────────────
 * Text loader — caricamento testuale shimmer stile OpenAI.
 * Una frase centrata che cambia ogni 2.5s con crossfade, mentre una
 * banda di luce scorre sul glifo (background-clip: text). Sostituisce
 * gli skeleton grid. Markup: vedi window.SkeletonLoader in index.html
 * e il componente React TextLoader (stesse classi `prisma-tl-*`).
 * ───────────────────────────────────────────────────────────────── */
@keyframes prisma-loader-shimmer {
  0%   { background-position: 140% 0; }
  100% { background-position: -40% 0; }
}
@keyframes prisma-loader-cycle {
  0%        { opacity: 0; transform: translate(-50%, calc(-50% + 5px)); }
  3%        { opacity: 1; transform: translate(-50%, -50%); }
  17%       { opacity: 1; transform: translate(-50%, -50%); }
  20%, 100% { opacity: 0; transform: translate(-50%, calc(-50% - 5px)); }
}
.prisma-loader {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: 60vh;
}
.prisma-loader-text {
  position: relative;
  height: 1.6em;
}
.prisma-loader-text > span {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  white-space: nowrap;
  font-size: 15px;
  font-weight: 800;
  letter-spacing: 0.01em;
  opacity: 0;
  background: linear-gradient(100deg,
    #b4b9c1 0%, #b4b9c1 38%, #14161a 50%, #b4b9c1 62%, #b4b9c1 100%);
  background-size: 220% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
  animation:
    prisma-loader-cycle 12.5s linear infinite,
    prisma-loader-shimmer 2.4s linear infinite;
  animation-delay: calc(var(--i) * -2.5s), 0s;
}
@media (prefers-reduced-motion: reduce) {
  .prisma-loader-text > span {
    animation: prisma-loader-cycle 12.5s linear infinite;
    animation-delay: calc(var(--i) * -2.5s);
    background: none;
    -webkit-text-fill-color: #5b6068;
    color: #5b6068;
  }
}

/* Overlay a tutto schermo — mostrato dal router ad ogni cambio pagina.
 * Copre sidebar + header + contenuto; il .prisma-loader interno centra
 * il testo shimmer nel viewport. */
.prisma-loader-overlay {
  position: fixed;
  inset: 0;
  z-index: 9998;
  background: #ffffff;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 1;
  transition: opacity 0.3s ease;
}
.prisma-loader-overlay.is-hiding {
  opacity: 0;
}

/* --- Optlyx Scanner launcher modal (softened internal style) --- */
.scanner-overlay { position: fixed; inset: 0; background: rgba(0,0,0,.45); display: flex; align-items: center; justify-content: center; z-index: 10000; }
.scanner-modal { background: #fff; border-radius: 18px; padding: 26px; width: min(420px, 92vw); position: relative; box-shadow: 0 16px 48px rgba(0,0,0,.22); font-family: Inter, system-ui, sans-serif; }
.scanner-modal h2 { margin: 0 0 4px; font-size: 19px; font-weight: 700; }
.scanner-close { position: absolute; top: 12px; right: 14px; border: 0; background: transparent; font-size: 24px; line-height: 1; cursor: pointer; color: #888; }
.scanner-label { display: block; margin: 14px 0 6px; font-size: 13px; color: #666; }
.scanner-select { width: 100%; padding: 10px 12px; border: 1px solid #e7e5e0; border-radius: 10px; margin-bottom: 14px; font-size: 14px; }
.scanner-btn-primary { width: 100%; background: #0d0d0d; color: #fff; border: 0; border-radius: 11px; padding: 12px; font-weight: 600; font-size: 15px; cursor: pointer; }
.scanner-btn-primary:disabled { opacity: .5; cursor: default; }
.scanner-result { margin-top: 18px; text-align: center; }
.scanner-result .muted { color: #888; font-size: 12px; }
.scanner-qr { display: flex; justify-content: center; margin-bottom: 12px; }
.scanner-pin { font-size: 18px; margin-bottom: 8px; }
.scanner-pin strong { letter-spacing: 3px; }
.scanner-link a { color: #0d0d0d; font-weight: 600; }
