3D card with cursor glow effect

html
<div id="card-wrapper">
  <div class="card"></div>
</div>

<style>
  #card-wrapper {
    perspective: 800px;
  }

  .card {
    --background: linear-gradient(
      192deg,
      rgba(255, 255, 255, 0.4) 0%,
      rgba(235, 238, 241, 0.8) 100%
    );
    overflow: hidden;
    display: flex;
    width: 268px;
    height: 368px;
    padding: 16px;
    flex-direction: column;
    justify-content: space-between;
    align-items: flex-start;
    border-radius: 16px;
    background: var(--background);
    background-blend-mode: overlay, normal;
    box-shadow:
      0px 1px 0px 0px rgba(10, 37, 64, 0.12),
      -1px 0px 0px 0px #fff inset,
      0px 60px 60px -40px rgba(50, 72, 93, 0.25),
      0px 1px 0px 0px #fff inset;
    transition: all 0.2s ease;
  }

  body {
    font-family: sans-serif;
    color: #353a44;
    background: linear-gradient(to right, #12c2e9, #c471ed, #f64f59);
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100vh;
  }
</style>

<script>
  const clamp = (min, num, max) => {
    return Math.min(Math.max(num, min), max)
  }

  const mapRange = (x, inMin, inMax, outMin, outMax) => {
    return ((x - inMin) * (outMax - outMin)) / (inMax - inMin) + outMin
  }

  // makes the card 3D angle follow cursor when hovered
  document.addEventListener("DOMContentLoaded", () => {
    const body = document.body
    const card = document.querySelector(".card")

    document.body.addEventListener("mousemove", (event) => {
      const rect = card.getBoundingClientRect()
      const offsetX = event.clientX - rect.left
      const offsetY = event.clientY - rect.top
      const centerX = rect.width / 2
      const centerY = rect.height / 2

      const rotateX = clamp(-20, ((offsetY - centerY) / centerY) * 8, 20)
      const rotateY = clamp(-20, -((offsetX - centerX) / centerX) * 12, 20)

      const xMin = rect.left
      const xMax = rect.left + rect.width
      const yMin = rect.top
      const yMax = rect.top + rect.height

      const borderX = mapRange(event.clientX, xMin, xMax, -1, 1)
      const borderY = mapRange(event.clientY, yMin, yMax, -1, 2)

      card.style.transform = `rotateX(${rotateX}deg) rotateY(${rotateY}deg)`

      card.style.boxShadow = `0px 1px 0px 0px rgba(10, 37, 64, 0.12), ${borderX}px 0px 0px 0px #fff, 0px ${borderY}px 0px 0px #fff, 0px 60px 60px -40px rgba(50, 72, 93, 0.25), 0px 1px 0px 0px #fff inset`
    })

    document.body.addEventListener("mouseleave", () => {
      card.style.transform = `none`
      card.style.boxShadow = `0px 1px 0px 0px rgba(10, 37, 64, 0.12),
			-1px 0px 0px 0px #fff inset,
			0px 60px 60px -40px rgba(50, 72, 93, 0.25),
			0px 1px 0px 0px #fff inset`
    })
  })

  // makes the glare move around inside the card
  document.addEventListener("DOMContentLoaded", () => {
    const container = document.querySelector(".card")

    document.body.addEventListener("mousemove", (event) => {
      const { left, top, width, height } = container.getBoundingClientRect()
      const x = event.clientX - left
      const y = event.clientY - top

      const gradientX = clamp(0, (x / width) * 100, 100)
      const gradientY = clamp(0, (y / height) * 100, 100)

      container.style.background = `radial-gradient(circle at ${gradientX}% ${gradientY}%, rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0.0) 75%), var(--background)`
    })

    container.addEventListener("mouseleave", () => {
      container.style.background = `rgba(255, 255, 255, 0.2)`
    })
  })
</script>