/* ============================================================
   EVANIA — MOTION LAYER
   ============================================================
   One place for every piece of motion on the storefront.

   Rules this file holds itself to:
   - transform / opacity / clip-path only. Anything touching
     width, height, margin or top/left forces layout on every
     frame and drops frames on a phone.
   - UI motion (hover, menus, buttons) stays under 300ms.
     Editorial reveals may run longer — they're read, not used.
   - ease-out on entrances, never ease-in. ease-in delays the
     exact moment the eye is waiting for, so 200ms of ease-in
     feels slower than 200ms of ease-out.
   - Hover motion is gated to real pointers. Touch fires a
     synthetic hover on tap, which leaves effects stuck on.
   - prefers-reduced-motion gets a gentler version, not nothing:
     opacity is kept, travel and parallax are dropped.
   ============================================================ */

:root {
  /* The browser's built-in easings are too weak to read as
     deliberate. These are the strong equivalents. */
  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
  --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);
  --ease-drawer: cubic-bezier(0.32, 0.72, 0, 1);

  --dur-press: 140ms;
  --dur-hover: 240ms;
  --dur-menu: 220ms;
  --dur-reveal: 700ms;
  --dur-sweep: 1100ms;

  --stagger-step: 70ms;
}

/* ============================================================
   1. SCROLL REVEAL
   Editorial surfaces only. Transitions rather than keyframes so
   an element caught mid-reveal retargets instead of restarting.
   ============================================================ */

.motion-ready [data-reveal] {
  opacity: 0;
  transition:
    opacity var(--dur-reveal) var(--ease-out),
    transform var(--dur-reveal) var(--ease-out),
    clip-path var(--dur-reveal) var(--ease-in-out);
  /* Delay is driven by --stagger-index, set by js/motion.js on
     each child of a [data-reveal-group]. */
  transition-delay: calc(var(--stagger-index, 0) * var(--stagger-step));
  will-change: transform, opacity;
}

.motion-ready [data-reveal="rise"]   { transform: translate3d(0, 28px, 0); }
.motion-ready [data-reveal="fall"]   { transform: translate3d(0, -20px, 0); }
.motion-ready [data-reveal="left"]   { transform: translate3d(-32px, 0, 0); }
.motion-ready [data-reveal="right"]  { transform: translate3d(32px, 0, 0); }
.motion-ready [data-reveal="scale"]  { transform: scale(0.94); }

/* Wipes the element into view from below. clip-path is the one
   non-transform property that's still cheap here — it composites
   without forcing layout. */
.motion-ready [data-reveal="wipe"] {
  clip-path: inset(0 0 100% 0);
  transform: translate3d(0, 12px, 0);
}

.motion-ready [data-reveal].is-revealed {
  opacity: 1;
  transform: none;
  clip-path: inset(0 0 0 0);
  /* Released once the reveal is done — leaving will-change on
     permanently keeps a compositor layer alive for no reason. */
  will-change: auto;
}

/* ============================================================
   2. HEADING LINE REVEAL
   Each line rides up from behind a mask. js/motion.js wraps the
   heading's lines in .line > .line-inner.
   ============================================================ */

.line {
  display: block;
  overflow: hidden;
}

.motion-ready .line-inner {
  display: block;
  transform: translate3d(0, 110%, 0);
  transition: transform 900ms var(--ease-out);
  transition-delay: calc(var(--line-index, 0) * 90ms);
}

.is-revealed .line-inner { transform: none; }

/* ============================================================
   3. GOLD SWEEP — the signature
   A slow band of light travelling across a surface, echoing the
   way light runs over polished metal. Used sparingly: once on
   headings as they reveal, and on product imagery on hover.
   Pure transform, so it costs nothing to run.
   ============================================================ */

.gold-sweep {
  position: relative;
  /* Contains the sweep without clipping descenders the way
     overflow:hidden on the text itself would. */
  isolation: isolate;
}

.gold-sweep::after {
  content: "";
  position: absolute;
  inset: -20% -60%;
  z-index: 1;
  pointer-events: none;
  background: linear-gradient(
    100deg,
    transparent 42%,
    rgba(232, 200, 74, 0.00) 46%,
    rgba(232, 200, 74, 0.42) 50%,
    rgba(255, 245, 200, 0.55) 52%,
    rgba(232, 200, 74, 0.00) 58%,
    transparent 62%
  );
  transform: translate3d(-60%, 0, 0);
  opacity: 0;
  mix-blend-mode: screen;
}

.gold-sweep.is-revealed::after,
.gold-sweep.sweep-now::after {
  animation: goldSweep var(--dur-sweep) var(--ease-in-out) forwards;
  animation-delay: calc(var(--stagger-index, 0) * var(--stagger-step) + 260ms);
}

@keyframes goldSweep {
  0%   { transform: translate3d(-60%, 0, 0); opacity: 0; }
  18%  { opacity: 1; }
  82%  { opacity: 1; }
  100% { transform: translate3d(60%, 0, 0); opacity: 0; }
}

/* ============================================================
   4. PRODUCT CARDS
   Seen constantly while browsing, so this is deliberately in the
   "near-imperceptible" tier — a small lift and a slow image
   push-in, nothing that demands attention.
   ============================================================ */

.product-card {
  transition:
    transform var(--dur-hover) var(--ease-out),
    box-shadow var(--dur-hover) var(--ease-out);
}

.product-card .product-card-image {
  overflow: hidden;
  position: relative;
}

.product-card .product-card-image img {
  transition: transform 900ms var(--ease-out);
  will-change: transform;
}

@media (hover: hover) and (pointer: fine) {
  .product-card:hover {
    transform: translate3d(0, -6px, 0);
  }

  .product-card:hover .product-card-image img {
    transform: scale(1.06);
  }

  /* Light running across the piece as the pointer arrives. */
  .product-card .product-card-image::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 2;
    pointer-events: none;
    background: linear-gradient(
      100deg,
      transparent 40%,
      rgba(255, 245, 210, 0.28) 50%,
      transparent 60%
    );
    transform: translate3d(-100%, 0, 0);
    opacity: 0;
  }

  .product-card:hover .product-card-image::after {
    animation: cardSweep 900ms var(--ease-in-out) forwards;
  }
}

@keyframes cardSweep {
  0%   { transform: translate3d(-100%, 0, 0); opacity: 0; }
  15%  { opacity: 1; }
  85%  { opacity: 1; }
  100% { transform: translate3d(100%, 0, 0); opacity: 0; }
}

/* Card action buttons ride up rather than appearing. */
.product-card .product-card-actions {
  transition:
    opacity var(--dur-hover) var(--ease-out),
    transform var(--dur-hover) var(--ease-out);
}

@media (hover: hover) and (pointer: fine) {
  .product-card .product-card-actions {
    opacity: 0;
    transform: translate3d(0, 8px, 0);
  }
  .product-card:hover .product-card-actions,
  .product-card:focus-within .product-card-actions {
    opacity: 1;
    transform: none;
  }
}

/* ============================================================
   5. BUTTONS
   Press feedback only — fired constantly, so it has to be fast
   enough to feel like the button reacted, not animated.
   ============================================================ */

.btn {
  transition:
    transform var(--dur-press) var(--ease-out),
    background-color var(--dur-hover) ease,
    border-color var(--dur-hover) ease,
    color var(--dur-hover) ease;
}

.btn:active { transform: scale(0.975); }

@media (hover: hover) and (pointer: fine) {
  .btn-primary:hover { transform: translate3d(0, -2px, 0); }
}

/* ============================================================
   6. MEGA MENU
   Was an instant class toggle. Anchored to its trigger, so it
   grows from the top edge rather than from its centre.
   ============================================================ */

.mega-menu {
  transform-origin: top center;
  transform: translate3d(0, -8px, 0) scaleY(0.98);
  opacity: 0;
  pointer-events: none;
  transition:
    opacity var(--dur-menu) var(--ease-out),
    transform var(--dur-menu) var(--ease-out);
}

.mega-menu.active {
  opacity: 1;
  transform: none;
  pointer-events: auto;
}

/* Menu contents trail the panel very slightly, so it reads as one
   surface arriving rather than a list of items appearing. */
.mega-menu .mega-menu-col a {
  opacity: 0;
  transform: translate3d(0, 6px, 0);
  transition:
    opacity var(--dur-menu) var(--ease-out),
    transform var(--dur-menu) var(--ease-out);
}

.mega-menu.active .mega-menu-col a { opacity: 1; transform: none; }
.mega-menu.active .mega-menu-col a:nth-child(2) { transition-delay: 30ms; }
.mega-menu.active .mega-menu-col a:nth-child(3) { transition-delay: 60ms; }
.mega-menu.active .mega-menu-col a:nth-child(4) { transition-delay: 90ms; }
.mega-menu.active .mega-menu-col a:nth-child(5) { transition-delay: 120ms; }
.mega-menu.active .mega-menu-col a:nth-child(6) { transition-delay: 150ms; }

/* ============================================================
   6b. SEARCH PANEL
   Grows from the trigger — same transform-origin discipline as
   the mega menu — rather than sliding in from an unrelated edge.
   ============================================================ */

.search-panel {
  position: absolute;
  top: 100%;
  right: var(--space-6);
  width: min(420px, calc(100vw - var(--space-8)));
  margin-top: var(--space-2);
  background: var(--color-secondary-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  padding: var(--space-2);
  transform-origin: top right;
  transform: scale(0.96) translate3d(0, -4px, 0);
  opacity: 0;
  pointer-events: none;
  transition:
    opacity var(--dur-menu) var(--ease-out),
    transform var(--dur-menu) var(--ease-out);
}

.search-panel.active {
  opacity: 1;
  transform: none;
  pointer-events: auto;
}

.search-panel-form {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
}

.search-panel-form svg { color: rgba(248, 244, 234, 0.4); flex-shrink: 0; }

.search-panel-form input {
  flex: 1;
  background: none;
  border: none;
  outline: none;
  color: var(--color-cream);
  font-family: var(--font-body);
  font-size: var(--text-base);
}

.search-panel-form input::placeholder { color: rgba(248, 244, 234, 0.32); }

@media (max-width: 767px) {
  .search-panel { right: var(--space-4); left: var(--space-4); width: auto; }
}

/* ============================================================
   7. NAV LINK UNDERLINE
   scaleX from the side the pointer is on would need JS; centre-out
   is honest and costs nothing.
   ============================================================ */

.nav-links a {
  position: relative;
}

.nav-links a::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -4px;
  height: 1px;
  background: var(--color-gold);
  transform: scaleX(0);
  transform-origin: center;
  transition: transform var(--dur-hover) var(--ease-out);
}

@media (hover: hover) and (pointer: fine) {
  .nav-links a:hover::after { transform: scaleX(1); }
}

.nav-links a[aria-current="page"]::after { transform: scaleX(1); }

/* ============================================================
   8. CART FEEDBACK
   Removal has to be legible — an item vanishing with no motion
   reads as a bug, and people are watching their money here.
   ============================================================ */

.cart-item {
  transition:
    opacity var(--dur-menu) var(--ease-out),
    transform var(--dur-menu) var(--ease-out);
}

.cart-item.is-removing {
  opacity: 0;
  transform: translate3d(-24px, 0, 0);
}

/* Quantity changes pulse the figure so the eye catches which
   number moved. */
.cart-item-total.is-updated,
.cart-summary-row.is-updated span:last-child {
  animation: figurePulse 420ms var(--ease-out);
}

@keyframes figurePulse {
  0%   { transform: scale(1); color: inherit; }
  35%  { transform: scale(1.08); color: var(--color-gold); }
  100% { transform: scale(1); color: inherit; }
}

.cart-count.is-bumped { animation: countBump 380ms var(--ease-out); }

@keyframes countBump {
  0%   { transform: scale(1); }
  40%  { transform: scale(1.32); }
  100% { transform: scale(1); }
}

/* ============================================================
   9. SHOP GRID
   Re-filtering replaces the grid wholesale. Without motion the
   swap reads as a flash; this gives it a beat.
   ============================================================ */

.product-grid.is-filtering {
  opacity: 0.35;
  transform: translate3d(0, 6px, 0);
  transition:
    opacity 160ms var(--ease-out),
    transform 160ms var(--ease-out);
}

.product-grid {
  transition:
    opacity var(--dur-hover) var(--ease-out),
    transform var(--dur-hover) var(--ease-out);
}

/* ============================================================
   10. PAGE TRANSITIONS
   Cross-document View Transitions. Progressive enhancement:
   browsers without support simply navigate as before.
   ============================================================ */

/* Cross-document view transitions are switched off.

   They were the cause of the header jitter between pages. The nav is
   position: sticky with a backdrop-filter, which is the worst possible
   candidate for a snapshot: the browser captures it into its own layer with
   the blur resolved against the old page's backdrop, then swaps it over the
   new one. That produced a visible rectangle around the bar for a frame and
   left the nav appearing to settle after the body had already drawn.

   The rules below are kept so this is one line to re-enable once the nav is
   not both sticky and blurred, but a smooth navigation matters more than the
   transition did. */
@view-transition {
  navigation: none;
}

::view-transition-old(root) {
  animation: vtOut 180ms var(--ease-out) forwards;
}

::view-transition-new(root) {
  animation: vtIn 320ms var(--ease-out) backwards;
  animation-delay: 90ms;
}

@keyframes vtOut {
  to { opacity: 0; transform: translate3d(0, -8px, 0); }
}

@keyframes vtIn {
  from { opacity: 0; transform: translate3d(0, 12px, 0); }
}

/* The chrome persists across navigation instead of cross-fading with the
   page body. Each named element needs its own unique name — the spec
   rejects two simultaneously-visible elements sharing one. */
.nav { view-transition-name: site-nav; }
.announcement-bar { view-transition-name: site-announcement; }

::view-transition-old(site-nav),
::view-transition-new(site-nav),
::view-transition-old(site-announcement),
::view-transition-new(site-announcement) {
  animation: none;
  mix-blend-mode: normal;
}

/* ============================================================
   11. REDUCED MOTION
   Keep the fade so reveals still resolve; drop every translation,
   scale, parallax and sweep.
   ============================================================ */

@media (prefers-reduced-motion: reduce) {
  .motion-ready [data-reveal] {
    transform: none !important;
    clip-path: none !important;
    transition: opacity 240ms ease;
    transition-delay: 0ms;
  }

  .motion-ready .line-inner { transform: none !important; transition: none; }

  .gold-sweep::after { display: none; }

  .product-card,
  .product-card .product-card-image img,
  .product-card .product-card-actions,
  .btn,
  .mega-menu,
  .mega-menu .mega-menu-col a,
  .search-panel,
  .nav-links a::after,
  .cart-item,
  .product-grid {
    transition-duration: 120ms;
  }

  .search-panel { transform: none !important; }

  .product-card:hover,
  .product-card:hover .product-card-image img,
  .btn-primary:hover,
  .btn:active {
    transform: none;
  }

  .product-card .product-card-image::after { animation: none; }

  .cart-item-total.is-updated,
  .cart-summary-row.is-updated span:last-child,
  .cart-count.is-bumped {
    animation: none;
  }

  ::view-transition-old(root),
  ::view-transition-new(root) { animation: none; }
}

/* ============================================================
   12. PRESS FEEDBACK
   Before this, the whole theme had exactly one :active rule
   (.btn), so nav links, icon buttons, category cards, product
   cards, pagination and every WooCommerce button gave no
   response at all until the click had already resolved.

   Two rules, from Apple's "Response" principle:
     - feedback happens on pointer-DOWN, not on release, and
     - it is near-instant going in, then springs back out.
   Hence the very short transition-duration on :active (the
   press must not feel animated) against the spring easing on
   the way back (the release should).

   Scale is inversely proportional to element size: a small
   icon can take 0.94 and still look deliberate, whereas the
   same value on a full product card reads as the card being
   yanked. Large surfaces get 0.99.
   ============================================================ */

.btn,
.btn-icon,
.nav-links a,
.mega-menu-col a,
.footer-col a,
.category-card,
.product-card,
.announcement-close,
.mobile-menu-toggle,
.woocommerce button.button,
.woocommerce input.button,
.woocommerce a.button,
.single_add_to_cart_button,
.add_to_cart_button,
.woocommerce-pagination .page-numbers a {
  /* Removes the grey flash mobile Safari/Chrome paint over tapped elements,
     which otherwise fires alongside our own press state and reads as a
     double response. */
  -webkit-tap-highlight-color: transparent;
}

/* Small controls — icons, links, pagination chips. */
.btn-icon:active,
.announcement-close:active,
.mobile-menu-toggle:active,
.woocommerce-pagination .page-numbers a:active {
  transform: scale(0.94);
  transition-duration: 70ms;
}

/* Buttons. Overrides the older flat 0.975 with a spring release. */
.btn,
.woocommerce button.button,
.woocommerce input.button,
.woocommerce a.button,
.single_add_to_cart_button,
.add_to_cart_button {
  transition:
    transform var(--ease-spring-snappy-duration) var(--ease-spring-snappy),
    background-color var(--dur-hover) ease,
    border-color var(--dur-hover) ease,
    color var(--dur-hover) ease;
}

.btn:active,
.woocommerce button.button:active,
.woocommerce input.button:active,
.woocommerce a.button:active,
.single_add_to_cart_button:active,
.add_to_cart_button:active {
  transform: scale(0.965);
  transition-duration: 70ms;
}

/* Text links — scale would look wrong, so press dims instead. */
.nav-links a:active,
.mega-menu-col a:active,
.footer-col a:active {
  opacity: 0.55;
  transition-duration: 60ms;
}

/* Large surfaces — a much smaller displacement, plus the shadow dropping
   back toward its resting step so the card reads as being pushed INTO the
   page rather than shrinking on the spot. */
.category-card:active,
.product-card:active {
  transform: scale(0.99);
  box-shadow: var(--shadow-sm);
  transition-duration: 90ms;
}

@media (prefers-reduced-motion: reduce) {
  /* Feedback still has to exist — reduced motion means a gentler,
     non-vestibular equivalent, not silence. Drop the movement, keep a
     brightness change so the press is still confirmed. */
  .btn:active,
  .btn-icon:active,
  .category-card:active,
  .product-card:active,
  .announcement-close:active,
  .mobile-menu-toggle:active,
  .woocommerce button.button:active,
  .woocommerce input.button:active,
  .woocommerce a.button:active,
  .single_add_to_cart_button:active,
  .add_to_cart_button:active,
  .woocommerce-pagination .page-numbers a:active {
    transform: none;
    filter: brightness(0.93);
  }
}
