/* =====================================================================
   Ronelle Perfume — Global storefront infrastructure (Phase 6.5)
   ---------------------------------------------------------------------
   Reusable UX layer consumed by window.RUI (rui-global.js): toasts,
   loading, skeletons, scroll UI, image fade, error states. Token-driven;
   `rui-`-prefixed so the global prefers-reduced-motion rule in
   components.css ([class*=" rui-"]) already calms every animation here.
   Served directly (no Tailwind build). Page layouts are NOT redesigned.
   ===================================================================== */

/* ============================ TOASTS ============================ */
.rui-toaster {
  position: fixed;
  inset-block-start: calc(env(safe-area-inset-top, 0px) + 1rem);
  inset-inline-end: 1rem;
  z-index: var(--rui-z-toast, 1070);
  display: flex;
  flex-direction: column;
  gap: var(--rui-space-xs);
  width: min(360px, calc(100vw - 2rem));
  pointer-events: none;
}
.rui-toast {
  pointer-events: auto;
  display: flex;
  align-items: flex-start;
  gap: var(--rui-space-sm);
  padding: var(--rui-space-sm) var(--rui-space-md);
  border-radius: var(--rui-radius-md);
  background: var(--rui-bg, #fff);
  color: var(--rui-text);
  border: 1px solid var(--rui-border);
  border-inline-start: 3px solid var(--rui-accent);
  box-shadow: var(--rui-shadow-md, 0 10px 30px rgba(0, 0, 0, 0.12));
  font-size: 0.86rem;
  line-height: 1.5;
  opacity: 0;
  transform: translateX(12px);
  transition: opacity var(--rui-duration-base) var(--rui-ease-standard),
              transform var(--rui-duration-base) var(--rui-ease-soft);
}
[dir="rtl"] .rui-toast { transform: translateX(-12px); }
.rui-toast.is-in { opacity: 1; transform: translateX(0); }
.rui-toast.is-out { opacity: 0; transform: translateY(-8px); }

.rui-toast__icon { flex-shrink: 0; display: inline-flex; color: var(--rui-accent); margin-block-start: 1px; }
.rui-toast__msg { flex: 1 1 auto; min-width: 0; }
.rui-toast__close {
  flex-shrink: 0;
  border: none;
  background: transparent;
  color: var(--rui-text-subtle);
  cursor: pointer;
  padding: 0;
  line-height: 0;
  transition: color var(--rui-duration-fast) var(--rui-ease-standard);
}
.rui-toast__close:hover { color: var(--rui-text); }

.rui-toast--success { border-inline-start-color: #16a34a; }
.rui-toast--success .rui-toast__icon { color: #16a34a; }
.rui-toast--error   { border-inline-start-color: #dc2626; }
.rui-toast--error   .rui-toast__icon { color: #dc2626; }
.rui-toast--warning { border-inline-start-color: #d97706; }
.rui-toast--warning .rui-toast__icon { color: #d97706; }
.rui-toast--info    { border-inline-start-color: var(--rui-accent); }

@media (max-width: 480px) {
  .rui-toaster { inset-inline: 0.75rem; width: auto; }
}

/* ===================== BACK TO TOP + SCROLL PROGRESS ===================== */
.rui-scrollprog {
  position: fixed;
  inset-block-start: 0;
  inset-inline: 0;
  height: 3px;
  z-index: calc(var(--rui-z-header, 1020) + 5);
  background: transparent;
  pointer-events: none;
}
.rui-scrollprog__bar {
  height: 100%;
  width: 100%;
  transform: scaleX(0);
  transform-origin: inline-start;
  background: linear-gradient(90deg, var(--rui-accent), var(--rui-accent-hover, var(--rui-accent)));
  transition: transform 80ms linear;
}
[dir="rtl"] .rui-scrollprog__bar { transform-origin: right; }

.rui-totop {
  position: fixed;
  inset-block-end: calc(env(safe-area-inset-bottom, 0px) + 1.25rem);
  inset-inline-end: 1.25rem;
  z-index: var(--rui-z-sticky, 1010);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: var(--rui-radius-pill);
  border: 1px solid var(--rui-border);
  background: var(--rui-bg, #fff);
  color: var(--rui-text);
  box-shadow: var(--rui-shadow-md, 0 10px 30px rgba(0, 0, 0, 0.12));
  cursor: pointer;
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px);
  transition: opacity var(--rui-duration-base) var(--rui-ease-standard),
              transform var(--rui-duration-base) var(--rui-ease-soft),
              visibility var(--rui-duration-base) var(--rui-ease-standard);
}
.rui-totop.is-visible { opacity: 1; visibility: visible; transform: translateY(0); }
.rui-totop:hover { color: var(--rui-accent-strong, var(--rui-accent)); border-color: var(--rui-border-strong); }
.rui-totop:focus-visible { outline: 2px solid var(--rui-accent); outline-offset: 2px; }

/* ============================ LOADING ============================ */
.rui-loading-overlay {
  position: absolute;
  inset: 0;
  z-index: var(--rui-z-overlay, 1030);
  display: flex;
  align-items: center;
  justify-content: center;
  background: color-mix(in srgb, var(--rui-bg, #fff) 70%, transparent);
  backdrop-filter: blur(2px);
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--rui-duration-base) var(--rui-ease-standard),
              visibility var(--rui-duration-base) var(--rui-ease-standard);
}
.rui-loading-overlay.is-active { opacity: 1; visibility: visible; }
.rui-loading-overlay--fixed { position: fixed; }

/* ====================== SKELETON COMPOSITIONS ====================== */
/* Built on the existing `.rui-skeleton` shimmer primitive. */
.rui-skel-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  gap: var(--rui-space-lg);
}
.rui-skel-card { display: flex; flex-direction: column; gap: var(--rui-space-sm); }
.rui-skel-card__media { aspect-ratio: 3 / 4; border-radius: var(--rui-radius-lg); }
.rui-skel-cart-item {
  display: grid;
  grid-template-columns: 72px 1fr;
  gap: var(--rui-space-sm);
  padding-block: var(--rui-space-md);
  border-block-end: 1px solid var(--rui-border);
}
.rui-skel-cart-item__img { width: 72px; height: 90px; border-radius: var(--rui-radius-md); }
.rui-skel-cart-item__lines { display: flex; flex-direction: column; gap: var(--rui-space-xs); }
.rui-skel-review { display: flex; flex-direction: column; gap: var(--rui-space-xs); padding-block: var(--rui-space-md); }

/* ====================== IMAGE SYSTEM ====================== */
/* JS only adds .rui-img-fade to images that are NOT yet loaded, so cached
   images never flash and a JS failure leaves images fully visible. */
.rui-img-fade { opacity: 0; transition: opacity var(--rui-duration-base) var(--rui-ease-standard); }
.rui-img-fade.is-loaded { opacity: 1; }
.rui-img-broken {
  opacity: 1 !important;
  object-fit: contain !important;
  background: var(--rui-surface-sunken, #f4f4f6);
  padding: 12%;
}

/* ====================== ERROR STATE (extends .rui-empty) ====================== */
.rui-empty--error .rui-empty__icon { color: #dc2626; opacity: 1; }
.rui-empty__actions { display: flex; gap: var(--rui-space-sm); justify-content: center; flex-wrap: wrap; margin-block-start: var(--rui-space-sm); }
