/* ═══════════════════════════════════════════════════════════════════════
   YVOREN — Hover Transition system

   A native recreation of the interaction model behind the shadcn registry
   item `@componentry/hover-transition`, which could not be installed here:
   that component is a React client component built on Tailwind utilities and
   `@/lib/utils`, and this storefront is static HTML/CSS/JS with no bundler,
   no React and no Tailwind. Rather than convert the site, the same behaviour
   is rebuilt in the storefront's own idiom.

   What is carried over from the original component
     • a second "hover state" surface revealed by an animated clip-path,
       with the same directional inset geometry (top / right / bottom / left)
     • the same default easing, cubic-bezier(0.22, 1, 0.36, 1)
     • a soft scale on the resting surface while the hover surface arrives
     • a pointer-tracked glare that follows the cursor across the surface
     • focus parity — keyboard focus triggers the identical state
     • prefers-reduced-motion collapses the animation to a plain state change

   What is deliberately NOT carried over
     • the 3D tilt. YVOREN is an editorial fashion storefront; tilting product
       photography reads as a gadget effect and fights the flat, printed feel
       the rest of the site is built on. Nova uses the tilt instead, so the
       two sites stay distinct.
     • the eight-effect / nine-direction matrix. Only the wipe geometry is
       kept, because one consistent motion is what makes a storefront feel
       considered rather than demoed.

   Loaded AFTER styles.css and yvoren-ui.css, so it can lean on their tokens.

   Usage
     <article class="product-card nk-ht nk-ht--from-bottom"> … </article>

   Layering contract
     `.nk-ht` creates a stacking context and paints its two effect layers at
     z-index -1. Inside a stacking context the element's own background paints
     first, then negative-z-index children, then content — so the layers sit
     above the card background and below every child, and NO child markup or
     z-index needs to change. That is what keeps this safe to bolt onto
     existing components, including the ones rendered by shopify.js.
   ═══════════════════════════════════════════════════════════════════════ */

/* ── Tokens ──
   Overridable per component, so one system serves cards, tiles and CTAs
   without any of them needing their own copy of the machinery. */
.nk-ht {
  --ht-dur: 520ms;          /* slow. editorial, not snappy — Nova is snappy */
  --ht-dur-fast: 320ms;
  --ht-ease: var(--ease, cubic-bezier(0.22, 1, 0.36, 1));

  --ht-lift: -3px;          /* elevation. deliberately small               */
  --ht-scale: 1.006;        /* soft scale. barely perceptible by design    */
  --ht-media-scale: 1.028;
  --ht-shift: 3px;          /* content movement                            */

  --ht-wash: rgba(200, 16, 46, 0.10);   /* rosewood, the single accent     */
  --ht-wash-2: rgba(241, 236, 227, 0.03);
  --ht-glare: rgba(241, 236, 227, 0.07); /* bone-tinted, never white glow  */
  --ht-border: var(--line-strong);
  --ht-rail: var(--yvoren-accent);

  --ht-shadow: 0 18px 40px -18px rgba(0, 0, 0, 0.78);

  /* Pointer position, written by yvoren-hover.js. Centre until tracked. */
  --ht-gx: 50%;
  --ht-gy: 50%;

  /* Resting clip for the reveal layer. Set by the direction modifiers;
     bottom-up is the default because it reads as the surface "rising". */
  --ht-hidden: inset(100% 0 0 0);

  position: relative;
  isolation: isolate;
  transition:
    transform var(--ht-dur) var(--ht-ease),
    border-color var(--ht-dur-fast) var(--ht-ease),
    box-shadow var(--ht-dur) var(--ht-ease),
    background-color var(--ht-dur-fast) var(--ht-ease);
}

/* Directional geometry — mirrors hiddenInset() in the original component. */
.nk-ht--from-bottom { --ht-hidden: inset(100% 0 0 0); }
.nk-ht--from-top    { --ht-hidden: inset(0 0 100% 0); }
.nk-ht--from-left   { --ht-hidden: inset(0 100% 0 0); }
.nk-ht--from-right  { --ht-hidden: inset(0 0 0 100%); }

/* ── Layer 1: the reveal surface ──
   The "hover component" of the original, reduced to a tonal wash. A full
   content swap would be wrong here: these cards carry prices, sizes and
   stock state, and swapping them out on hover would hide information the
   customer is reaching for. */
.nk-ht::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  border-radius: inherit;
  background:
    linear-gradient(180deg, var(--ht-wash-2), transparent 60%),
    linear-gradient(0deg, var(--ht-wash), transparent 78%);
  clip-path: var(--ht-hidden);
  transition: clip-path var(--ht-dur) var(--ht-ease);
}

/* ── Layer 2: the pointer glare ──
   Kept behind the content (z-index -1) rather than over it with a blend
   mode. Over the content it would wash across the price and size pills;
   behind it, it reads as the material catching light. */
.nk-ht::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  border-radius: inherit;
  background: radial-gradient(
    circle 220px at var(--ht-gx) var(--ht-gy),
    var(--ht-glare),
    transparent 72%
  );
  opacity: 0;
  transition: opacity var(--ht-dur-fast) var(--ht-ease);
}

/* `--solo` is for components whose ::after is already spoken for by
   yvoren-ui.css (the category tile's scrim). They keep the reveal, lose the
   glare — the effect still reads, and nothing existing breaks. */
.nk-ht--solo::after { content: none; }

/* ── Moving parts ──
   Opt-in hooks so a component chooses what travels. Nothing moves unless it
   is marked, which is what keeps this from turning into a jitter of parts. */
.nk-ht__shift {
  transition: transform var(--ht-dur) var(--ht-ease);
}

.nk-ht__icon {
  display: inline-block;
  transition:
    transform var(--ht-dur) var(--ht-ease),
    color var(--ht-dur-fast) var(--ht-ease);
}

/* A rail that draws in from the leading edge. This is already YVOREN's
   language — .directory-row uses one — so reusing it keeps the new system
   reading as part of the original design rather than bolted on.

   Positioned absolutely rather than as a flex/grid child on purpose: these
   containers are flex columns with a gap, so an in-flow rail would add its
   own height plus a gap to every card and shift the resting layout. Absolute
   keeps the resting design byte-for-byte identical to before. */
.nk-ht__rail {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 1px;
  pointer-events: none;
  background: var(--ht-rail);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--ht-dur) var(--ht-ease);
}

.nk-ht__rail--top {
  bottom: auto;
  top: 0;
}

/* ═══════════════════════════════════════════════════════════════════════
   ACTIVE STATE

   Pointer hover is gated behind a fine-pointer query so touch devices never
   latch into a stuck hover — the storefront already uses this guard for the
   product image crossfade, so the behaviour stays consistent.

   Focus is NOT gated: a keyboard user gets the identical state, which is the
   focus parity the original component provides via its onFocus handler.
   ═══════════════════════════════════════════════════════════════════════ */

@media (hover: hover) and (pointer: fine) {
  .nk-ht:hover {
    transform: translate3d(0, var(--ht-lift), 0) scale(var(--ht-scale));
    border-color: var(--ht-border);
    box-shadow: var(--ht-shadow);
  }
  .nk-ht:hover::before { clip-path: inset(0); }
  .nk-ht:hover::after { opacity: 1; }
  .nk-ht:hover .nk-ht__shift { transform: translate3d(0, calc(var(--ht-shift) * -1), 0); }
  .nk-ht:hover .nk-ht__icon { transform: translate3d(var(--ht-shift), 0, 0); }
  .nk-ht:hover .nk-ht__rail { transform: scaleX(1); }
}

.nk-ht:focus-visible,
.nk-ht:focus-within {
  transform: translate3d(0, var(--ht-lift), 0) scale(var(--ht-scale));
  border-color: var(--ht-border);
  box-shadow: var(--ht-shadow);
}
.nk-ht:focus-visible::before,
.nk-ht:focus-within::before { clip-path: inset(0); }
.nk-ht:focus-visible .nk-ht__rail,
.nk-ht:focus-within .nk-ht__rail { transform: scaleX(1); }
.nk-ht:focus-visible .nk-ht__icon,
.nk-ht:focus-within .nk-ht__icon { transform: translate3d(var(--ht-shift), 0, 0); }

/* The card itself is not a tab stop — its links and buttons are. Suppress
   the ring on the container so :focus-within does not double-outline, while
   the real control keeps the site's own focus treatment. */
.nk-ht:focus { outline: none; }

/* ═══════════════════════════════════════════════════════════════════════
   COMPONENT BINDINGS

   Each surface opts into a subset. Not everything gets everything — that is
   the difference between a hover system and a hover pile.
   ═══════════════════════════════════════════════════════════════════════ */

/* ── Product card (shop, mens, index rails; markup from shopify.js) ──
   No border and no background in the resting state by design, so this one
   takes elevation + media scale + the rail, and skips the border shift.
   The existing front/back image crossfade is untouched. */
.product-card.nk-ht {
  --ht-lift: -4px;
  --ht-shadow: 0 22px 46px -22px rgba(0, 0, 0, 0.72);
  border-radius: var(--radius-md);
}

.product-card.nk-ht .product-card__media {
  transition: transform var(--ht-dur) var(--ht-ease);
}

@media (hover: hover) and (pointer: fine) {
  .product-card.nk-ht:hover .product-card__media {
    transform: scale(var(--ht-media-scale));
  }
}

/* ── Highlight / feature cards (index) ──
   These are flat jet-lift panels. They gain a border that materialises on
   hover, the reveal wash, and the diamond glyph drifting up. */
.highlight-item.nk-ht {
  border: 1px solid transparent;
  border-radius: var(--radius-md);
}

.highlight-item.nk-ht .highlight-item__icon {
  display: inline-block;
  color: var(--olive-lift);
  transition:
    transform var(--ht-dur) var(--ht-ease),
    color var(--ht-dur-fast) var(--ht-ease);
}

@media (hover: hover) and (pointer: fine) {
  .highlight-item.nk-ht:hover .highlight-item__icon {
    transform: translate3d(0, -4px, 0) rotate(45deg);
    color: var(--yvoren-accent-hover);
  }
}

.highlight-item.nk-ht:focus-within .highlight-item__icon {
  transform: translate3d(0, -4px, 0) rotate(45deg);
  color: var(--yvoren-accent-hover);
}

/* Not bound: .category-tile and .editorial-panel. Both are styled in
   yvoren-ui.css but neither is rendered by any current page or template, so a
   binding here would be dead CSS from the day it was written. If either
   returns, adding `nk-ht nk-ht--from-bottom` to its markup is enough — and
   .category-tile additionally needs `nk-ht--solo`, because its ::after is
   already the image scrim. */

/* ── Document CTA (about, care, shipping, returns, privacy, terms, cookies) ──
   A real call to action, so it gets the most pronounced reveal of the set. */
.doc-cta.nk-ht {
  --ht-wash: rgba(200, 16, 46, 0.16);
  --ht-lift: -2px;
}

/* ── Set card (magic-bento) ── */
.set-card.nk-ht {
  --ht-lift: -4px;
}

/* On the bone variant the dark-surface values invert: a rosewood wash over
   warm off-white needs less weight, and the shadow has to be softer or it
   reads as dirt on a light card. */
.set-card--bone.nk-ht {
  --ht-wash: rgba(200, 16, 46, 0.12);
  --ht-wash-2: rgba(8, 8, 9, 0.03);
  --ht-glare: rgba(255, 255, 255, 0.34);
  --ht-border: rgba(8, 8, 9, 0.30);
  --ht-shadow: 0 18px 40px -20px rgba(8, 8, 9, 0.38);
}

/* ── Directory rows (index) ──
   Already had a hover (background + padding shift + olive rail) before this
   system existed. It is NOT converted to .nk-ht — its ::before is the rail.
   Instead the arrow is brought in line with the rest of the system so the
   page reads as one vocabulary. */
.directory-row__arrow {
  display: inline-block;
  transition: transform 320ms var(--ease);
}

@media (hover: hover) and (pointer: fine) {
  .directory-row:hover .directory-row__arrow {
    transform: translate3d(5px, 0, 0);
  }
}

.directory-row:focus-within .directory-row__arrow {
  transform: translate3d(5px, 0, 0);
}

/* ═══════════════════════════════════════════════════════════════════════
   REDUCED MOTION

   Everything that moves is cancelled. The state change itself is kept —
   removing the hover feedback entirely would cost affordance, which is a
   usability regression, not an accessibility win. The reveal layer snaps to
   its shown state instead of wiping to it.
   ═══════════════════════════════════════════════════════════════════════ */

@media (prefers-reduced-motion: reduce) {
  .nk-ht,
  .nk-ht::before,
  .nk-ht::after,
  .nk-ht__shift,
  .nk-ht__icon,
  .nk-ht__rail,
  .product-card.nk-ht .product-card__media,
  .highlight-item.nk-ht .highlight-item__icon,
  .directory-row__arrow {
    transition-duration: 1ms !important;
  }

  .nk-ht:hover,
  .nk-ht:focus-visible,
  .nk-ht:focus-within {
    transform: none;
  }

  .nk-ht:hover .nk-ht__shift,
  .nk-ht:focus-within .nk-ht__shift,
  .nk-ht:hover .nk-ht__icon,
  .nk-ht:focus-within .nk-ht__icon,
  .nk-ht:hover .highlight-item__icon,
  .nk-ht:focus-within .highlight-item__icon,
  .directory-row:hover .directory-row__arrow,
  .directory-row:focus-within .directory-row__arrow {
    transform: none;
  }

  .product-card.nk-ht:hover .product-card__media {
    transform: none;
  }

  /* No pointer glare when motion is reduced — it is pure decoration and it
     tracks the cursor, which is exactly the kind of movement to drop. */
  .nk-ht::after { content: none; }
}
