/**
 * Super Speedy AJAX Prices - display modes (reveal / spinner).
 *
 * Applied CSS-first so the cached price is dimmed in the very first painted
 * frame, with NO dependency on JavaScript running. The JS reveals the real
 * price when it arrives; a pure-CSS fallback (ssap-auto-reveal) reveals the
 * cached price after the timeout so a no-JS visitor is never left looking at a
 * dimmed price.
 *
 * The price text is ALWAYS present in the HTML and only ever dimmed with
 * opacity - never display:none or visibility:hidden - so it stays visible to
 * search engines and assistive technology. Do not set --ssap-dim to 0.
 *
 * Mode + spinner-style classes are emitted onto each .ajax-price wrapper by
 * replace_price_with_placeholder(), so every rule below is self-contained and
 * does not depend on any body/ancestor class.
 */

:root {
  --ssap-dim: 0.15;          /* overridden inline from ssap_dim_opacity */
  --ssap-reveal-delay: 3s;   /* matches REVEAL_TIMEOUT_MS in ssap-pricing.js */
  /* --ssap-spin-color falls back to currentColor when the setting is blank */
}

/* --- Pending placeholder --- */
/* reveal = dimmed (price still readable, softly). spinner = fully hidden so the
   spinner stands alone (the price is still in the HTML for search engines, just
   visually replaced). The 0s-duration animation flips opacity to 1 once the
   reveal delay elapses and holds it (forwards): the no-JS / slow-AJAX safety net. */
.ajax-price.ssap-mode-reveal .ajax-price-placeholder {
  opacity: var(--ssap-dim, 0.15);
  animation: ssap-auto-reveal 0s linear var(--ssap-reveal-delay) forwards;
}
.ajax-price.ssap-mode-spinner .ajax-price-placeholder {
  opacity: 0;
  animation: ssap-auto-reveal 0s linear var(--ssap-reveal-delay) forwards;
}

/* Real price arrived (JS added ajax-price-loaded on success) OR cached price
   force-revealed (JS added ssap-revealed on failure): fade to full opacity over
   the configured reveal speed (--ssap-fade; 0ms = instant) and cancel the
   fallback animation. */
.ajax-price.ajax-price-loaded .ajax-price-placeholder,
.ajax-price.ssap-revealed .ajax-price-placeholder {
  opacity: 1;
  animation: none;
  transition: opacity var(--ssap-fade, 180ms) ease-in;
}

@keyframes ssap-auto-reveal { to { opacity: 1; } }

/* --- Spinner mode --- */
.ajax-price.ssap-mode-spinner {
  position: relative;
  display: inline-block;
}

/* Shared spinner geometry. The per-style rules below add the visual + the
   spin animation. Keeping the animation OUT of this base rule matters: a
   later `animation:` declaration replaces rather than merges, so each style
   owns its full animation list (spin + the timeout auto-hide). */
.ajax-price.ssap-mode-spinner::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  box-sizing: border-box;
  color: var(--ssap-spin-color, currentColor);
  pointer-events: none;
}

/* Hide the spinner once the price is in (JS) or on failure/no-JS fallback. */
.ajax-price.ajax-price-loaded::before,
.ajax-price.ssap-revealed::before {
  display: none !important;
}

@keyframes ssap-spin { to { transform: rotate(360deg); } }
/* No-JS / slow-AJAX: fade the spinner out at the reveal delay so it does not
   spin forever if JS never runs. */
@keyframes ssap-spin-timeout { to { opacity: 0; visibility: hidden; } }

/* ring (default) - single rotating border arc */
.ajax-price.ssap-spin-ring::before {
  width: 1em; height: 1em;
  margin: -0.5em 0 0 -0.5em;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  animation: ssap-spin .7s linear infinite,
             ssap-spin-timeout 0s linear var(--ssap-reveal-delay) forwards;
}

/* dual-ring - two opposing arcs */
.ajax-price.ssap-spin-dual::before {
  width: 1em; height: 1em;
  margin: -0.5em 0 0 -0.5em;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-left-color: transparent;
  border-radius: 50%;
  animation: ssap-spin .7s linear infinite,
             ssap-spin-timeout 0s linear var(--ssap-reveal-delay) forwards;
}

/* pulse - single expanding, fading circle */
.ajax-price.ssap-spin-pulse::before {
  width: 1em; height: 1em;
  margin: -0.5em 0 0 -0.5em;
  background: currentColor;
  border-radius: 50%;
  opacity: 0.7;
  animation: ssap-pulse 1s ease-in-out infinite,
             ssap-spin-timeout 0s linear var(--ssap-reveal-delay) forwards;
}
@keyframes ssap-pulse {
  0%   { transform: scale(0.4); opacity: 0.7; }
  50%  { transform: scale(1);   opacity: 0.2; }
  100% { transform: scale(0.4); opacity: 0.7; }
}

/* --- Text mode: show the loading text, keep the real price in the DOM --- */
/* The price stays in the HTML (present for search engines); it is only visually
   replaced by the loading text (::before content: attr(data-loading)) until it
   loads. :not() guards so the loaded/revealed state always wins over order. */
.ajax-price.ssap-mode-text {
  position: relative;
  display: inline-block;
}
.ajax-price.ssap-mode-text:not(.ajax-price-loaded):not(.ssap-revealed) .ajax-price-placeholder {
  opacity: 0;
  animation: ssap-auto-reveal 0s linear var(--ssap-reveal-delay) forwards;
}
.ajax-price.ssap-mode-text:not(.ajax-price-loaded):not(.ssap-revealed)::before {
  content: attr(data-loading);
  position: absolute;
  left: 0;
  top: 50%;
  transform: translateY(-50%);
  white-space: nowrap;
  color: currentColor;
  opacity: 0.6;
  font-style: italic;
  animation: ssap-spin-timeout 0s linear var(--ssap-reveal-delay) forwards;
}

/* Respect reduced-motion: no spin, just the dimmed price with the CSS
   auto-reveal fallback still in force. */
@media (prefers-reduced-motion: reduce) {
  .ajax-price.ssap-mode-spinner::before { display: none !important; }
}

/* ==========================================================================
   Pending STOCK — the stock line and the whole add-to-cart region.
   ==========================================================================

   Same CSS-first idea as prices, with two differences that matter and must not
   be "tidied" into the price rules above:

   1. THE PENDING REGION IS NOT CLICKABLE. A dimmed price is harmless. A dimmed
      Add to Cart that somebody clicks before the real state lands puts a
      sold-out item in their basket. So pending gets pointer-events: none, and
      the PHP side sets aria-disabled.

   2. THE NO-JS RESTORE MUST GIVE THE BUTTON BACK. If JS never runs, the
      auto-reveal animation has to restore pointer-events as well as opacity,
      or a JS failure leaves every visitor on the site with a permanently dead
      button. That is the single most damaging thing this file could get wrong.

   Which elements are pending is decided server-side per product (stock level
   vs the threshold, out-of-stock, settled days) and baked into the cached HTML
   as .ssap-stock-pending — identical for every visitor, so it is cache-safe. */

.ssap-stock-pending {
  animation: ssap-stock-restore 0s linear var(--ssap-reveal-delay) forwards;
}

.ssap-stock-pending.ssap-mode-reveal { opacity: var(--ssap-dim, 0.15); pointer-events: none; }
.ssap-stock-pending.ssap-mode-spinner,
.ssap-stock-pending.ssap-mode-text    { opacity: 0.25; pointer-events: none; }

/* Resolved (JS) or force-revealed (failure / no-JS): full opacity AND usable
   again. Both properties, always together. */
.ssap-stock-pending.ajax-stock-loaded,
.ssap-stock-pending.ssap-revealed,
.ajax-stock-loaded,
.ssap-revealed {
  opacity: 1;
  pointer-events: auto;
  animation: none;
  transition: opacity var(--ssap-fade, 180ms) ease-in;
}

@keyframes ssap-stock-restore {
  to { opacity: 1; pointer-events: auto; }
}

/* Spinner over the region. The region is a block, so centre on it rather than
   using the inline geometry the price spinner uses. */
.ssap-stock-pending.ssap-mode-spinner { position: relative; display: block; }
.ssap-stock-pending.ssap-mode-spinner::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 1.5em;
  height: 1.5em;
  margin: -0.75em 0 0 -0.75em;
  box-sizing: border-box;
  color: var(--ssap-spin-color, currentColor);
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  pointer-events: none;
  animation: ssap-spin .7s linear infinite,
             ssap-spin-timeout 0s linear var(--ssap-reveal-delay) forwards;
}
.ssap-stock-pending.ssap-spin-dual::before  { border-right-color: transparent; border-left-color: transparent; border-top-color: currentColor; }
.ssap-stock-pending.ssap-spin-pulse::before { border: 0; background: currentColor; opacity: 0.7; animation: ssap-pulse 1s ease-in-out infinite, ssap-spin-timeout 0s linear var(--ssap-reveal-delay) forwards; }

.ajax-stock-loaded::before,
.ssap-revealed::before { display: none !important; }

@media (prefers-reduced-motion: reduce) {
  .ssap-stock-pending.ssap-mode-spinner::before { display: none !important; }
}
