/* ============================================================
   Tactizen - NFT card presence
   ------------------------------------------------------------
   Rarity you can feel. Until now a Q5 Legendary and a Q1 Common
   were the same green-bordered box with a different badge. Tier
   now drives the card's edge, its aura and how much foil catches
   the light, so rarity reads from across the grid.

   The ramp reuses the .tier-1..5 badge colours already in the
   inventory, so badge, border and foil are one system rather
   than three opinions:

     Q1 Common     slate    matte, no foil
     Q2 Uncommon   emerald  faint single-hue sheen
     Q3 Rare       blue     brighter sheen
     Q4 Epic       purple   duotone foil, violet into magenta
     Q5 Legendary  amber    full spectrum, and a slow idle shimmer

   static/js/nft_card.js sets five custom properties from the
   pointer; everything below is CSS.

     --tz-holo-x / --tz-holo-y    pointer position, 0-1
     --tz-holo-rx / --tz-holo-ry  tilt, in degrees
     --tz-holo-on                 0 at rest, 1 while pointed at
   ============================================================ */

.tz-holo {
  --tz-holo-x: 0.5;
  --tz-holo-y: 0.5;
  --tz-holo-rx: 0deg;
  --tz-holo-ry: 0deg;
  --tz-holo-on: 0;

  /* Tier defaults; the ramp below overrides per data-tier. */
  --tz-tier: var(--tz-slate-400);
  --tz-tier-rgb: var(--tz-slate-400-rgb);
  --tz-tier-foil: 0;
  --tz-tier-aura: 0.18;

  transform:
    perspective(900px)
    rotateX(var(--tz-holo-rx))
    rotateY(var(--tz-holo-ry))
    translateY(calc(var(--tz-holo-on) * -6px));
  transition:
    transform 0.45s var(--tz-ease-out),
    box-shadow 0.3s var(--tz-ease),
    border-color 0.3s var(--tz-ease);
}

/* While the pointer is on the card, track it almost instantly.
   The 0.45s ease above is for the settle back to flat on leave. */
.tz-holo.is-tilting {
  transition:
    transform 0.08s linear,
    box-shadow 0.3s var(--tz-ease),
    border-color 0.3s var(--tz-ease);
}

/* ---------- the tier ramp ---------- */
.tz-holo[data-tier="1"] {
  --tz-tier: var(--tz-slate-400);
  --tz-tier-rgb: var(--tz-slate-400-rgb);
  --tz-tier-foil: 0;
  --tz-tier-aura: 0.16;
}
.tz-holo[data-tier="2"] {
  --tz-tier: var(--tz-emerald-400);
  --tz-tier-rgb: var(--tz-emerald-400-rgb);
  --tz-tier-foil: 0.20;
  --tz-tier-aura: 0.24;
}
.tz-holo[data-tier="3"] {
  --tz-tier: var(--tz-blue-400);
  --tz-tier-rgb: var(--tz-blue-400-rgb);
  --tz-tier-foil: 0.38;
  --tz-tier-aura: 0.34;
}
.tz-holo[data-tier="4"] {
  --tz-tier: var(--tz-purple-400);
  --tz-tier-rgb: var(--tz-purple-400-rgb);
  --tz-tier-foil: 0.58;
  --tz-tier-aura: 0.46;
}
.tz-holo[data-tier="5"] {
  --tz-tier: var(--tz-amber-400);
  --tz-tier-rgb: var(--tz-amber-400-rgb);
  --tz-tier-foil: 0.85;
  --tz-tier-aura: 0.60;
}

/* ---------- the art, and the light on it ---------- */
.tz-holo-art {
  position: relative;
  isolation: isolate;          /* keep the blend modes off the page */
  border-radius: var(--tz-radius-lg);
}

.tz-holo-art::before,
.tz-holo-art::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  transition: opacity 0.35s var(--tz-ease);
  z-index: 2;
}

/* Glare - a soft highlight sitting under the pointer. */
.tz-holo-art::before {
  background: radial-gradient(
    circle at calc(var(--tz-holo-x) * 100%) calc(var(--tz-holo-y) * 100%),
    rgba(var(--tz-white-rgb), 0.5) 0%,
    rgba(var(--tz-white-rgb), 0.12) 32%,
    transparent 62%
  );
  mix-blend-mode: soft-light;
  opacity: var(--tz-holo-on);
}

/* Foil - a single-hue sheen by default, swapped for the higher
   tiers below. Masked to the pointer so the light has a source. */
.tz-holo-art::after {
  background-image: linear-gradient(
    115deg,
    transparent 20%,
    rgba(var(--tz-tier-rgb), 0.75) 42%,
    rgba(var(--tz-white-rgb), 0.85) 50%,
    rgba(var(--tz-tier-rgb), 0.75) 58%,
    transparent 80%
  );
  background-size: 260% 260%;
  background-position:
    calc(var(--tz-holo-x) * 100%)
    calc(var(--tz-holo-y) * 100%);
  mix-blend-mode: color-dodge;
  opacity: calc(var(--tz-tier-foil) * var(--tz-holo-on));
  -webkit-mask-image: radial-gradient(
    circle at calc(var(--tz-holo-x) * 100%) calc(var(--tz-holo-y) * 100%),
    #000 0%, rgba(0, 0, 0, 0.55) 40%, transparent 78%
  );
  mask-image: radial-gradient(
    circle at calc(var(--tz-holo-x) * 100%) calc(var(--tz-holo-y) * 100%),
    #000 0%, rgba(0, 0, 0, 0.55) 40%, transparent 78%
  );
}

/* Q4 - duotone. Violet running into magenta. */
.tz-holo[data-tier="4"] .tz-holo-art::after {
  background-image: repeating-linear-gradient(
    112deg,
    rgba(168, 85, 247, 0.7) 0%,
    rgba(236, 72, 153, 0.7) 14%,
    rgba(129, 140, 248, 0.7) 28%,
    rgba(168, 85, 247, 0.7) 42%
  );
}

/* Q5 - the full spectrum, and the only tier that moves at rest. */
.tz-holo[data-tier="5"] .tz-holo-art::after {
  background-image: repeating-linear-gradient(
    108deg,
    rgba(255, 122, 182, 0.7) 0%,
    rgba(255, 214, 112, 0.7) 11%,
    rgba(126, 255, 199, 0.7) 22%,
    rgba(112, 194, 255, 0.7) 33%,
    rgba(198, 132, 255, 0.7) 44%,
    rgba(255, 122, 182, 0.7) 55%
  );
}

.tz-holo[data-tier="5"] .tz-holo-art {
  animation: tz-holo-idle 7s var(--tz-ease-in-out) infinite;
}

@keyframes tz-holo-idle {
  0%, 100% { filter: saturate(1)    brightness(1);    }
  50%      { filter: saturate(1.14) brightness(1.06); }
}

/* ---------- tier aura on the inventory card ---------- */
/* .nft-card's own "transition: all" is declared in the inventory
   page's inline <style>, which loads after this file and matches at
   the same specificity - so restate the transition here, where the
   extra class wins, or the tilt would lag 0.3s behind the pointer. */
.nft-card.tz-holo {
  border-color: rgba(var(--tz-tier-rgb), calc(0.25 + var(--tz-tier-aura) * 0.35));
  transition:
    transform 0.45s var(--tz-ease-out),
    box-shadow 0.3s var(--tz-ease),
    border-color 0.3s var(--tz-ease);
}

.nft-card.tz-holo.is-tilting {
  transition:
    transform 0.08s linear,
    box-shadow 0.3s var(--tz-ease),
    border-color 0.3s var(--tz-ease);
}

.nft-card.tz-holo:hover {
  border-color: rgba(var(--tz-tier-rgb), 0.85);
  box-shadow:
    0 14px 34px rgba(var(--tz-black-rgb), 0.55),
    0 0 26px rgba(var(--tz-tier-rgb), var(--tz-tier-aura));
  /* Override the old flat lift; .tz-holo's transform does the work. */
  transform:
    perspective(900px)
    rotateX(var(--tz-holo-rx))
    rotateY(var(--tz-holo-ry))
    translateY(-6px);
}

/* Equipped / listed / selected still win on colour, because
   "this one is in a slot" outranks "this one is rare". */
.nft-card.tz-holo.equipped { border-color: rgba(var(--tz-amber-400-rgb), 0.7); }
.nft-card.tz-holo.listed   { border-color: rgba(var(--tz-blue-400-rgb), 0.7); }
.nft-card.tz-holo.selected { border-color: rgba(var(--tz-red-600-rgb), 0.7); }

/* ---------- equipped slots ---------- */
/* A slot shows one small NFT and its markup is a bare <img>, which
   has no pseudo-elements to hang foil on. Rarity still has to read
   there, so a slotted card gets the tier ring and aura and the same
   tilt - and no wrapper element, so no slot layout moves. */
img.tz-holo {
  box-shadow:
    0 0 0 1px rgba(var(--tz-tier-rgb), 0.5),
    0 0 18px rgba(var(--tz-tier-rgb), var(--tz-tier-aura));
  transition:
    transform 0.45s var(--tz-ease-out),
    box-shadow 0.3s var(--tz-ease);
}

img.tz-holo:hover {
  box-shadow:
    0 0 0 1px rgba(var(--tz-tier-rgb), 0.85),
    0 0 26px rgba(var(--tz-tier-rgb), calc(var(--tz-tier-aura) + 0.15));
}

/* ---------- inspect ---------- */
.tz-holo-zoom {
  position: absolute;
  top: 0.5rem;
  right: 0.5rem;
  z-index: 3;
  width: 30px;
  height: 30px;
  display: grid;
  place-items: center;
  padding: 0;
  border: 1px solid rgba(var(--tz-white-rgb), 0.25);
  border-radius: var(--tz-radius-pill);
  background: rgba(var(--tz-surface-base-rgb), 0.72);
  color: var(--tz-white);
  font-size: 0.75rem;
  cursor: pointer;
  opacity: 0;
  transform: scale(0.85);
  transition: opacity 0.2s var(--tz-ease), transform 0.2s var(--tz-ease-out);
}

.tz-holo:hover .tz-holo-zoom,
.tz-holo-zoom:focus-visible {
  opacity: 1;
  transform: scale(1);
}

.tz-holo-zoom:hover {
  background: rgba(var(--tz-tier-rgb), 0.9);
  border-color: rgba(var(--tz-white-rgb), 0.5);
}

/* ---------- full-size inspect overlay ---------- */
.tz-holo-lightbox {
  position: fixed;
  inset: 0;
  z-index: 10000;
  display: grid;
  place-items: center;
  padding: 2rem 1rem;
  background: rgba(var(--tz-black-rgb), 0.82);
  backdrop-filter: blur(6px);
  animation: tz-holo-fade 0.22s var(--tz-ease-out);
}

.tz-holo-lightbox .tz-holo-art {
  border-radius: var(--tz-radius-xl);
  box-shadow:
    0 30px 80px rgba(var(--tz-black-rgb), 0.7),
    0 0 60px rgba(var(--tz-tier-rgb), var(--tz-tier-aura));
}

.tz-holo-lightbox img {
  display: block;
  max-width: min(86vw, 460px);
  max-height: 78vh;
  border-radius: var(--tz-radius-xl);
}

.tz-holo-lightbox-caption {
  margin-top: 1rem;
  text-align: center;
  font-family: var(--tz-font-display);
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--tz-white);
}

.tz-holo-lightbox-caption small {
  display: block;
  margin-top: 0.35rem;
  font-family: var(--tz-font-ui);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--tz-tier);
}

@keyframes tz-holo-fade {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* ---------- quality floor ---------- */
@media (prefers-reduced-motion: reduce) {
  .tz-holo,
  .tz-holo.is-tilting {
    transform: none;
    transition: box-shadow 0.3s var(--tz-ease), border-color 0.3s var(--tz-ease);
  }
  .nft-card.tz-holo:hover { transform: none; }
  .tz-holo[data-tier="5"] .tz-holo-art { animation: none; }
  .tz-holo-lightbox { animation: none; }
  /* Tier still reads: the aura stays, and the foil sits still. */
  .tz-holo-art::after { opacity: calc(var(--tz-tier-foil) * 0.25); }
}

/* Coarse pointers get no tilt - there is nothing to track - but
   they keep the tier colour, the aura and the inspect button. */
@media (hover: none) {
  .tz-holo { transform: none; }
  .tz-holo-zoom { opacity: 1; transform: scale(1); }
}
