/* ==========================================================================
   LUMEN · foil — holographic sheen + thickness for the detail viewer image
   --------------------------------------------------------------------------
   The frame (`.viewer__frame`) carries the 3D pose; three absolutely-placed
   layers inside it paint the material:
     .foil__shine  the rainbow, masked to a patch around the pointer
     .foil__glare  the specular highlight (a soft elliptical hotspot)
     .foil__rim    a 1px light-catching edge, strongest on the tilt side
   The 体积感 comes from a stack of shadows offset opposite the tilt plus the
   rim, so the sheet reads as a solid slab instead of a flat image.
   ========================================================================== */

.foil,
.is-foil {
  --foil-rx: 0deg;
  --foil-ry: 0deg;
  --foil-x: 50%;
  --foil-y: 50%;
  --foil-i: 0;
  --foil-shine: 0.55;
  --foil-depth: 0.45;
  --foil-strength: 0.55;
}

/* ---- the sheet itself -------------------------------------------------- */
.viewer__frame.is-foil {
  perspective: 1100px;
  transform-style: preserve-3d;
  /* a real card has an edge: a dark seat + a soft ambient shadow */
  filter: drop-shadow(0 26px 44px rgba(0, 0, 0, 0.55));
  transition: filter 320ms var(--ease-out);
  isolation: isolate;
}

/* The 3D pose lives on the media, not the frame: the frame's transform is
   owned by the zoom/pan code, and rotating that would fight the pinch zoom. */
.viewer__frame.is-foil .viewer__media {
  transform: rotateX(var(--foil-rx)) rotateY(var(--foil-ry))
    translateZ(calc(var(--foil-depth) * 14px)) scale(1.012);
  transform-style: preserve-3d;
  transition: transform 220ms cubic-bezier(0.22, 0.61, 0.36, 1),
    box-shadow 260ms var(--ease-out);
  /* Thickness. A flat image casts one soft shadow; a solid sheet casts a
     stack: a tight contact shadow at the bottom edge (the seat), a wide
     ambient pool, and a bright lip along the top edge. All three scale with
     --foil-depth so the 体积感 slider has something to move. */
  box-shadow:
    /* contact seat, offset opposite the light */
    calc(var(--foil-depth) * 4px) calc(var(--foil-depth) * 14px)
      calc(6px + var(--foil-depth) * 18px) rgba(0, 0, 0, 0.78),
    /* wide ambient pool */
    calc(var(--foil-depth) * -8px) calc(var(--foil-depth) * 26px)
      calc(30px + var(--foil-depth) * 70px) rgba(0, 0, 0, 0.55),
    /* bright lip on the lit side */
    calc(var(--foil-depth) * -2px) calc(var(--foil-depth) * -3px)
      calc(6px + var(--foil-depth) * 12px) rgba(255, 255, 255, 0.1),
    /* inner bevel: the sheet has an edge, not a decal */
    inset 0 1px 0 rgba(255, 255, 255, calc(0.12 + var(--foil-depth) * 0.3)),
    inset 0 calc(var(--foil-depth) * -3px) calc(var(--foil-depth) * 10px)
      rgba(0, 0, 0, calc(var(--foil-depth) * 0.35));
}

/* while the pointer moves, the pose must not lag behind the pointer */
.viewer__frame.is-foil.is-live .viewer__media {
  transition-duration: 60ms;
}

/* ---- layers ------------------------------------------------------------ */
.foil__shine,
.foil__glare,
.foil__rim {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  /* The media is lifted by --foil-depth * 14px, so the layers have to sit
     further forward than that or the photo paints over its own sheen. */
  transform: translateZ(calc(var(--foil-depth) * 14px + 2px));
  transform-style: preserve-3d;
}

.foil__shine {
  /* the slider scales the sheet: intensity 0 must be genuinely invisible */
  opacity: calc(var(--foil-i) * var(--foil-strength, 0.55) * 1.45);
  /* screen, not overlay: overlay barely lifts a dark wallpaper and the foil has
     to read as light bouncing off the sheet, not as a colour cast */
  mix-blend-mode: screen;
  background-repeat: repeat;
  background-size: 105% 105%;
  background-position: var(--foil-x) var(--foil-y);
  /* a narrow band, not a wash: a true foil only lights up where the sheet
     catches the light, so the mask stays tight around the pointer */
  -webkit-mask-image: radial-gradient(
    ellipse 52% 64% at var(--foil-x) var(--foil-y),
    #000 0%,
    rgba(0, 0, 0, 0.62) 42%,
    transparent 78%
  );
  mask-image: radial-gradient(
    ellipse 52% 64% at var(--foil-x) var(--foil-y),
    #000 0%,
    rgba(0, 0, 0, 0.62) 42%,
    transparent 78%
  );
  transition: opacity 200ms linear;
}

/* five materials — the rainbow band layouts differ, not just the hue */
.viewer__frame[data-foil-preset="aurora"] .foil__shine {
  background-image: linear-gradient(
    118deg,
    transparent 10%,
    rgba(120, 255, 240, 0.62) 26%,
    rgba(120, 190, 255, 0.58) 38%,
    rgba(190, 140, 255, 0.56) 50%,
    transparent 68%
  );
  filter: saturate(1.4) brightness(1.04);
}
.viewer__frame[data-foil-preset="rainbow"] .foil__shine {
  background-image: repeating-linear-gradient(
    112deg,
    rgba(255, 90, 140, 0.56) 0%,
    rgba(255, 200, 90, 0.5) 5%,
    rgba(120, 255, 170, 0.5) 10%,
    rgba(110, 190, 255, 0.56) 15%,
    rgba(190, 130, 255, 0.56) 20%,
    rgba(255, 90, 140, 0.56) 25%
  );
  filter: saturate(1.5) brightness(1.04);
}
.viewer__frame[data-foil-preset="metal"] .foil__shine {
  background-image: linear-gradient(
    104deg,
    transparent 20%,
    rgba(255, 255, 255, 0.5) 32%,
    rgba(190, 210, 230, 0.34) 40%,
    rgba(255, 255, 255, 0.55) 47%,
    transparent 62%
  );
  filter: saturate(0.35) brightness(1.25) contrast(1.2);
}
.viewer__frame[data-foil-preset="stardust"] .foil__shine {
  background-image: radial-gradient(
      18% 26% at 28% 32%,
      rgba(255, 255, 255, 0.6),
      transparent 70%
    ),
    radial-gradient(14% 20% at 68% 62%, rgba(180, 220, 255, 0.55), transparent 72%),
    radial-gradient(10% 14% at 46% 78%, rgba(255, 210, 240, 0.5), transparent 74%),
    linear-gradient(
      120deg,
      transparent 18%,
      rgba(200, 230, 255, 0.34) 40%,
      transparent 66%
    );
  background-size: 140% 140%, 150% 150%, 160% 160%, 240% 240%;
  filter: saturate(1.35) brightness(1.08);
}
.viewer__frame[data-foil-preset="silk"] .foil__shine {
  background-image: linear-gradient(
    96deg,
    transparent 8%,
    rgba(255, 236, 200, 0.4) 22%,
    rgba(255, 250, 240, 0.62) 34%,
    rgba(255, 226, 190, 0.36) 44%,
    transparent 60%
  );
  filter: saturate(0.9) brightness(1.12) contrast(1.06);
}

.foil__glare {
  opacity: calc(0.22 + var(--foil-shine) * 0.55);
  mix-blend-mode: soft-light;
  background: radial-gradient(
    46% 40% at var(--foil-x) var(--foil-y),
    rgba(255, 255, 255, 0.95),
    rgba(255, 255, 255, 0.25) 40%,
    transparent 68%
  );
}

/* the light-catching edge — this is most of the 体积感 */
.foil__rim {
  opacity: calc(0.3 + var(--foil-shine) * 0.5);
  mix-blend-mode: screen;
  background: linear-gradient(
    calc(90deg + var(--foil-ry) * 6),
    rgba(255, 255, 255, 0) 0%,
    rgba(255, 255, 255, 0.5) 18%,
    rgba(255, 255, 255, 0.08) 42%,
    rgba(255, 255, 255, 0) 62%,
    rgba(255, 255, 255, 0.34) 88%,
    rgba(255, 255, 255, 0) 100%
  );
  -webkit-mask-image: linear-gradient(#000 0 0), linear-gradient(#000 0 0);
  mask-image: linear-gradient(#000 0 0), linear-gradient(#000 0 0);
  -webkit-mask-clip: content-box, border-box;
  mask-clip: content-box, border-box;
  -webkit-mask-composite: xor;
  mask-composite: exclude;
  padding: 1.5px;
  box-sizing: border-box;
}

/* ---- reduced motion: a still sheet with a centred sheen ---------------- */
@media (prefers-reduced-motion: reduce) {
  .viewer__frame.is-foil .viewer__media {
    transform: translateZ(calc(var(--foil-depth) * 8px));
    transition: none;
  }
  .foil__shine,
  .foil__glare {
    opacity: calc(0.35 + var(--foil-strength) * 0.3);
  }
}
html[data-motion="off"] .viewer__frame.is-foil .viewer__media {
  transform: none;
  transition: none;
}
html[data-motion="off"] .foil__shine {
  background-position: 50% 50%;
  opacity: calc(0.3 + var(--foil-strength) * 0.25);
}
