/* ==========================================================================
   Motion system.
   Rules: transform + opacity only, GPU-composited, never animate layout.
   Everything here is neutralised by prefers-reduced-motion in base.css.
   ========================================================================== */

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

@keyframes t-rise {
  from { opacity: 0; transform: translate3d(0, 26px, 0); }
  to   { opacity: 1; transform: none; }
}

@keyframes t-word {
  from { transform: translate3d(0, 110%, 0) rotate(3deg); }
  to   { transform: none; }
}

@keyframes t-marquee {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}

@keyframes t-pop {
  0%   { transform: scale(1); }
  40%  { transform: scale(1.35); }
  100% { transform: scale(1); }
}

@keyframes t-shimmer {
  from { background-position: -140% 0; }
  to   { background-position: 240% 0; }
}

/* ---------- Scroll reveal ----------
   .reveal starts hidden; IntersectionObserver adds .is-in.
   Grid children stagger via --i set in JS. */

.reveal {
  opacity: 0;
  transform: translate3d(0, 26px, 0);
  transition:
    opacity var(--t-speed) var(--t-ease-out),
    transform var(--t-speed) var(--t-ease-out);
  transition-delay: calc(var(--i, 0) * 55ms);
  will-change: opacity, transform;
}
.reveal.is-in { opacity: 1; transform: none; will-change: auto; }

/* No-JS fallback: never hide content permanently. */
.no-js .reveal { opacity: 1; transform: none; }

/* ---------- Word-by-word heading reveal ---------- */

/* The mask lives on each word, not on the heading: a heading that wraps to
   several lines would have its lower lines clipped by a container overflow. */

/* Display headings run at line-height 1.08, which is tighter than the glyphs
   of a serif with descenders. The per-word mask clips to that box, so it needs
   a little more room or letters like "p" and "g" are cut in half. */
.reveal-head { line-height: 1.16; }

.reveal-head .rw {
  display: inline-block;
  overflow: hidden;
  vertical-align: bottom;
  padding-bottom: 0.2em;
}
.reveal-head .rw > span {
  display: inline-block;
  transform: translate3d(0, 110%, 0);
  transition: transform 640ms var(--t-ease-out);
  transition-delay: calc(var(--i) * 60ms);
}
.reveal-head.is-in .rw > span { transform: none; }
.no-js .reveal-head .rw > span { transform: none; }

/* ---------- Marquee strip ---------- */

.marquee {
  overflow: hidden;
  background: var(--t-ink);
  color: #fff;
  padding-block: 12px;
  font-size: 11px;
  letter-spacing: .22em;
  text-transform: uppercase;
}
.marquee-track {
  display: flex;
  align-items: center;
  gap: 18px;
  width: max-content;
  animation: t-marquee 28s linear infinite;
}
.marquee:hover .marquee-track { animation-play-state: paused; }
.marquee i { opacity: .45; font-style: normal; }

/* ---------- Link underline sweep ---------- */

.link-sweep,
.primary-nav .menu > li > a,
.section-link {
  position: relative;
}
.link-sweep::after,
.primary-nav .menu > li > a::after,
.section-link::after {
  content: "";
  position: absolute;
  left: 0; bottom: -2px;
  width: 100%; height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: right;
  transition: transform var(--t-speed) var(--t-ease-out);
}
.link-sweep:hover::after,
.primary-nav .menu > li > a:hover::after,
.primary-nav .menu > li.current-menu-item > a::after,
.section-link:hover::after {
  transform: scaleX(1);
  transform-origin: left;
}

/* ---------- Product card hover ----------
   The image swap is two stacked <img>s cross-fading with a slow zoom.
   Actions slide in from the right, CTA bar rises from the bottom. */

.product-card { position: relative; }

/* Clips the rising CTA so it is invisible until the card is hovered. */
.card-top {
  position: relative;
  overflow: hidden;
  border-radius: var(--t-radius);
}

.card-media {
  position: relative;
  display: block;
  overflow: hidden;
  background: #efe8e0;
  aspect-ratio: 3 / 4;
  border-radius: var(--t-radius);
}

.card-media-inner { position: absolute; inset: 0; }

.card-media img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition:
    opacity var(--t-speed) var(--t-ease),
    transform 900ms var(--t-ease-out);
}

.card-media .img-hover { opacity: 0; transform: scale(1.06); }

.product-card:hover .card-media .img-primary,
.product-card:focus-within .card-media .img-primary {
  opacity: 0;
  transform: scale(1.06);
}
.product-card:hover .card-media .img-hover,
.product-card:focus-within .card-media .img-hover {
  opacity: 1;
  transform: scale(1);
}

/* Single-image cards still get a subtle zoom so hover always feels alive. */
.product-card:hover .card-media:not(.has-swap) .img-primary {
  opacity: 1;
  transform: scale(1.05);
}

/* Actions rail */
.card-actions {
  position: absolute;
  top: 12px; right: 12px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  z-index: 2;
}
.card-act {
  display: grid;
  place-items: center;
  width: 38px; height: 38px;
  border: 0;
  border-radius: 999px;
  background: rgba(255,255,255,.94);
  color: var(--t-ink);
  cursor: pointer;
  opacity: 0;
  transform: translate3d(14px, 0, 0);
  transition:
    opacity var(--t-speed) var(--t-ease-out),
    transform var(--t-speed) var(--t-ease-out),
    background var(--t-fast) var(--t-ease),
    color var(--t-fast) var(--t-ease);
  transition-delay: calc(var(--n, 0) * 60ms);
}
.card-act:nth-child(2) { --n: 1; }
.card-act svg { width: 17px; height: 17px; fill: none; stroke: currentColor; stroke-width: 1.5; }
.card-act span { display: none; }

.product-card:hover .card-act,
.product-card:focus-within .card-act {
  opacity: 1;
  transform: none;
}
.card-act:hover { background: var(--t-accent); color: #fff; }

.wish-btn[aria-pressed="true"] { background: var(--t-accent); color: #fff; }
.wish-btn[aria-pressed="true"] svg { fill: currentColor; }
.wish-btn.just-added svg { animation: t-pop 420ms var(--t-ease-out); }

/* Rising CTA */
.card-cta {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  display: block;
  padding: 14px;
  border: 0;
  background: var(--t-ink);
  color: #fff;
  font: 500 11px/1 var(--font-body);
  letter-spacing: .14em;
  text-transform: uppercase;
  text-align: center;
  cursor: pointer;
  transform: translate3d(0, 100%, 0);
  transition: transform var(--t-speed) var(--t-ease-out), background var(--t-fast) var(--t-ease);
  z-index: 2;
}
.product-card:hover .card-cta,
.product-card:focus-within .card-cta { transform: none; }
.card-cta:hover { background: var(--t-accent); }
.card-cta.is-disabled { background: var(--t-ink-35); cursor: not-allowed; }

/* On touch screens hover never fires — pin the affordances open. */
@media (hover: none) {
  .card-act { opacity: 1; transform: none; }
  /* No hover on touch, so the CTA sits in normal flow and the wrapper
     must stop clipping it. A <button> still shrink-wraps at display:block,
     unlike the <a> variant, so the width is set explicitly. */
  .card-top { overflow: visible; }
  .card-cta {
    position: static;
    transform: none;
    margin-top: 10px;
    width: 100%;
  }
}

/* ---------- Badges ---------- */

.card-badges {
  position: absolute;
  top: 12px; left: 12px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
  z-index: 2;
}
.badge {
  padding: 5px 9px;
  border-radius: var(--t-radius);
  font: 600 10px/1 var(--font-body);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: #fff;
  background: var(--t-ink);
  animation: t-rise 420ms var(--t-ease-out) both;
}
.badge--sale { background: var(--t-accent); }
.badge--new  { background: var(--t-ok); }
.badge--low  { background: var(--t-warn); }
.badge--sold { background: var(--t-ink-35); }

/* ---------- Swatches ---------- */

.card-swatches { display: flex; align-items: center; gap: 6px; margin-top: 8px; }
.swatch {
  width: 14px; height: 14px;
  border-radius: 50%;
  background: var(--sw);
  box-shadow: inset 0 0 0 1px var(--t-ink-12);
  transition: transform var(--t-fast) var(--t-ease);
}
.swatch:hover { transform: scale(1.25); }
.swatch-more { font-size: 11px; color: var(--t-ink-60); }

/* ---------- Magnetic button (JS sets --mx/--my) ---------- */

.magnetic { transform: translate3d(var(--mx, 0), var(--my, 0), 0); transition: transform 240ms var(--t-ease-out); }

/* ---------- Skeleton shimmer ---------- */

.is-skeleton {
  background: linear-gradient(90deg, #efe8e0 25%, #f8f4ef 50%, #efe8e0 75%);
  background-size: 200% 100%;
  animation: t-shimmer 1.2s linear infinite;
  color: transparent !important;
}

/* ---------- Scroll progress ---------- */

.progress-bar {
  position: fixed;
  top: 0; left: 0; right: 0;
  height: 2px;
  z-index: 300;
  pointer-events: none;
}
.progress-bar i {
  display: block;
  height: 100%;
  width: 100%;
  background: var(--t-accent);
  transform: scaleX(var(--p, 0));
  transform-origin: left;
}

/* ---------- Toast ---------- */

.toast-stack {
  position: fixed;
  left: 50%; bottom: 24px;
  z-index: 400;
  display: grid;
  gap: 8px;
  transform: translateX(-50%);
  pointer-events: none;
}
.toast {
  padding: 12px 20px;
  border-radius: var(--t-radius);
  background: var(--t-ink);
  color: #fff;
  font-size: 13px;
  box-shadow: var(--t-shadow-lift);
  animation: t-rise 320ms var(--t-ease-out) both;
}
.toast--error { background: #a02020; }
