/* Gravin Wood motion.
   The whole file is inert under prefers-reduced-motion: the tokens collapse to
   0ms/0px in tokens.css, and the two behaviours that a duration cannot flatten
   are guarded explicitly at the bottom. */

/* -----------------------------------------------------------------------------
 * Scroll reveal
 *
 * gravin-reveal-ready is set by JS, so the hidden state only ever exists on a
 * page that has something running to un-hide it.
 * -------------------------------------------------------------------------- */

.gravin-reveal-ready [data-gravin-reveal] {
  opacity: 0;
  transform: translateY(var(--gravin-rise));
  transition: opacity 620ms var(--gravin-ease), transform 620ms var(--gravin-ease);
}

.gravin-reveal-ready [data-gravin-reveal].gravin-revealed {
  opacity: 1;
  transform: none;
}

/* Children of a revealed group arrive in sequence rather than together. */
.gravin-reveal-ready [data-gravin-reveal] > * {
  transition: opacity 520ms var(--gravin-ease), transform 520ms var(--gravin-ease);
}

.gravin-reveal-ready [data-gravin-reveal-stagger] > * {
  opacity: 0;
  transform: translateY(calc(var(--gravin-rise) * 0.7));
}

.gravin-reveal-ready [data-gravin-reveal-stagger].gravin-revealed > * {
  opacity: 1;
  transform: none;
}

.gravin-reveal-ready [data-gravin-reveal-stagger].gravin-revealed > *:nth-child(2) { transition-delay: 70ms; }
.gravin-reveal-ready [data-gravin-reveal-stagger].gravin-revealed > *:nth-child(3) { transition-delay: 140ms; }
.gravin-reveal-ready [data-gravin-reveal-stagger].gravin-revealed > *:nth-child(4) { transition-delay: 210ms; }
.gravin-reveal-ready [data-gravin-reveal-stagger].gravin-revealed > *:nth-child(5) { transition-delay: 280ms; }
.gravin-reveal-ready [data-gravin-reveal-stagger].gravin-revealed > *:nth-child(6) { transition-delay: 350ms; }
.gravin-reveal-ready [data-gravin-reveal-stagger].gravin-revealed > *:nth-child(7) { transition-delay: 420ms; }

/* -----------------------------------------------------------------------------
 * Home tiles
 * -------------------------------------------------------------------------- */

.gravin-home-tile img {
  transition: transform 720ms var(--gravin-ease), opacity 130ms linear;
}

/* The caption is the image block's own figcaption now, not a class of ours. */
.gravin-home-tile figcaption {
  transition: background-color var(--gravin-dur) var(--gravin-ease);
}

.gravin-home-tile__name {
  display: inline-block;
  transition: transform var(--gravin-dur) var(--gravin-ease);
}

.gravin-frame-swapping {
  opacity: 0;
}

@media (prefers-reduced-motion: no-preference) and (hover: hover) {
  .gravin-home-tile:hover img,
  .gravin-home-tile:focus-visible img {
    transform: scale(1.04);
  }

  .gravin-home-tile:hover .gravin-home-tile__name,
  .gravin-home-tile:focus-visible .gravin-home-tile__name {
    transform: translateX(4px);
  }

  [dir="rtl"] .gravin-home-tile:hover .gravin-home-tile__name {
    transform: translateX(-4px);
  }
}

.gravin-home-tile:hover figcaption,
.gravin-home-tile:focus-visible figcaption {
  background: rgba(var(--gravin-charcoal-deep-rgb), .96);
}

/* The catalogue tile is text, not a photograph — its rule extends instead. */
.gravin-home-tile--catalogue .gravin-home-tile__link {
  transition: border-color var(--gravin-dur) var(--gravin-ease), color var(--gravin-dur) var(--gravin-ease);
}

.gravin-home-tile--catalogue:hover .gravin-home-tile__link {
  border-bottom-color: var(--gravin-text);
}

/* Category strip and the craft link: the rule draws in from the start edge
   rather than appearing. */
.gravin-home-categories a,
.gravin-home-craft__link,
.gravin-wood-cta__secondary,
.gravin-cart-empty__secondary {
  position: relative;
}

.gravin-home-categories a::after {
  position: absolute;
  inset: auto var(--gravin-s-5) 18px;
  height: 1px;
  background: var(--gravin-rule);
  content: "";
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--gravin-dur) var(--gravin-ease);
}

[dir="rtl"] .gravin-home-categories a::after {
  transform-origin: right center;
}

.gravin-home-categories a:hover::after,
.gravin-home-categories a:focus-visible::after {
  transform: scaleX(1);
}

/* -----------------------------------------------------------------------------
 * Timber tiles — the grain reveal
 *
 * The field lifts and saturates on hover. When the grain photographs exist they
 * become the field's background-image and this same rule reveals them.
 * -------------------------------------------------------------------------- */

.gravin-wood-timber::before {
  background-position: center;
  background-size: cover;
  transition: transform 820ms var(--gravin-ease), filter 420ms var(--gravin-ease);
}

.gravin-wood-timber h3 {
  transition: transform var(--gravin-dur) var(--gravin-ease);
}

@media (prefers-reduced-motion: no-preference) and (hover: hover) {
  .gravin-wood-timber:hover .gravin-wood-timber::before {
    transform: scale(1.06);
    filter: saturate(1.15) brightness(1.06);
  }

  .gravin-wood-timber:hover h3 {
    transform: translateY(-4px);
  }
}

/* -----------------------------------------------------------------------------
 * Rewards
 *
 * A stroke drawn once across the thing that just worked, the way a line is
 * drawn on a workshop drawing. Never a bounce, never a colour flash.
 * -------------------------------------------------------------------------- */

.gravin-marked {
  position: relative;
  overflow: hidden;
}

.gravin-marked::after {
  position: absolute;
  z-index: 2;
  inset: 0;
  background: linear-gradient(
    100deg,
    transparent 0%,
    rgba(var(--gravin-copper-rgb), .14) 42%,
    rgba(var(--gravin-offwhite-rgb), .5) 50%,
    rgba(var(--gravin-copper-rgb), .14) 58%,
    transparent 100%
  );
  content: "";
  pointer-events: none;
  transform: translateX(-100%);
  animation: gravin-stroke 760ms var(--gravin-ease) both;
}

@keyframes gravin-stroke {
  to { transform: translateX(100%); }
}

/* The basket count is the one number that means "it worked". It steps up in
   weight and colour, then settles. */
.gravin-site-header__basket-count {
  display: inline-block;
  transition: color var(--gravin-dur) var(--gravin-ease);
}

.gravin-count-ticked {
  animation: gravin-count-tick 700ms var(--gravin-ease) both;
  color: var(--gravin-accent);
}

@keyframes gravin-count-tick {
  0%   { transform: translateY(0) scale(1); }
  28%  { transform: translateY(-3px) scale(1.28); }
  60%  { transform: translateY(0) scale(1); }
  100% { transform: none; }
}

/* A variation chosen settles into place rather than snapping. */
.gravin-variation-option {
  transition: background-color var(--gravin-dur-fast) var(--gravin-ease),
              color var(--gravin-dur-fast) var(--gravin-ease),
              border-color var(--gravin-dur-fast) var(--gravin-ease);
}

/* Add to cart: the fill sweeps from the start edge on hover, and the label
   holds still while it does. */
.gravin-product-purchase .single_add_to_cart_button,
.gravin-button {
  position: relative;
  overflow: hidden;
  transition: background-color var(--gravin-dur) var(--gravin-ease),
              color var(--gravin-dur) var(--gravin-ease),
              border-color var(--gravin-dur) var(--gravin-ease);
}

.gravin-button:hover,
.gravin-product-purchase .single_add_to_cart_button:not(.disabled):not(:disabled):hover {
  background: var(--gravin-strong);
  color: var(--gravin-inverse);
}

/* The commission submit, while it is being sent. */
.gravin-button--sending {
  color: transparent !important;
}

.gravin-button--sending::after {
  position: absolute;
  inset-block-start: 50%;
  inset-inline-start: 50%;
  width: 16px;
  height: 16px;
  margin: -8px 0 0 -8px;
  border: 1px solid rgba(var(--gravin-offwhite-rgb), .3);
  border-block-start-color: var(--gravin-on-action);
  border-radius: 50%;
  content: "";
  animation: gravin-spin 700ms linear infinite;
}

@keyframes gravin-spin {
  to { transform: rotate(360deg); }
}

/* -----------------------------------------------------------------------------
 * The explicit reduced-motion floor
 *
 * Durations already collapse via tokens. These are the effects that a 0ms
 * duration would not silence, so they are removed outright.
 * -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  .gravin-reveal-ready [data-gravin-reveal],
  .gravin-reveal-ready [data-gravin-reveal-stagger] > * {
    opacity: 1;
    transform: none;
  }

  .gravin-marked::after,
  .gravin-count-ticked,
  .gravin-button--sending::after {
    animation: none;
  }

  .gravin-marked::after {
    display: none;
  }

  .gravin-button--sending {
    color: inherit !important;
    opacity: 0.6;
  }

  .gravin-home-tile img,
  .gravin-wood-timber::before {
    transition: none;
  }
}
