/*
  Holographic teacher cards.

  .holo-card
    __mover             pops the card out to the middle of the screen
      __tilt            follows the light and carries the spin
        __face __front
          __paper       full-card background art, washed out so text stays readable
          __sheen       foil over the card body (reverse holo only)
          __etch        etched line texture over the card body
          __layout      header, art window, event details
            __art       the holo window: __bg, __foil, __shimmer, __etch, __glitter, __figure
          __glare       soft surface highlight over everything
        __face __back   the cover, seen while the card spins

  holo-card.js drives these unitless custom properties on .holo-card:
    --mx, --my          light position, -1 (left/top) to 1 (right/bottom)
    --hyp               distance of the light from the centre, 0 to 1
    --on                effect strength, 0 (resting) to 1 (interacting)
    --pop               0 (in place) to 1 (popped out)
    --turn              full turns around the vertical axis (-0.5 is cover-side up)
    --tx, --ty, --zoom  where the popped-out card sits, in px and scale
    --res               how much larger than its slot the card is laid out (see __mover)

  Per card, set --theme and --theme-deep, and data-foil="reverse | holo | cosmos | rainbow".
  --figure-scale (default 1) shrinks or grows a portrait so heads match across cards, and
  --figure-head (default 0.075) says how far down its image the top of the head sits.
*/

.holo-card {
  --mx: 0;
  --my: 0;
  --hyp: 0;
  --on: 0;
  --pop: 0;
  --turn: 0;
  --tx: 0;
  --ty: 0;
  --zoom: 1;
  --res: 1;

  --theme: hsl(217 84% 49%);
  --theme-deep: hsl(218 88% 38%);
  --ink: hsl(222 38% 20%);
  /* Latin and numerals in Poppins, Traditional Chinese in Noto Sans TC. Both are web fonts the
     page has to load (see index.html); the system fonts after them are the fallback. Set
     --card-font on the page to use a different typeface. */
  --font: var(--card-font, "Poppins", "Noto Sans TC", system-ui, "PingFang TC", "Microsoft JhengHei", sans-serif);
  --tilt: 13deg;
  --radius: 4.4% / 3.15%;
  --shadow: 222 45% 16%;

  --c1: hsl(348 100% 70%);
  --c2: hsl(38 100% 66%);
  --c3: hsl(92 85% 64%);
  --c4: hsl(174 90% 58%);
  --c5: hsl(218 100% 70%);
  --c6: hsl(284 100% 72%);

  --lx: calc(50% + var(--mx) * 50%);
  --ly: calc(50% + var(--my) * 50%);

  position: relative;
  /* the popped-out card sits above its neighbours */
  z-index: calc(max(var(--pop), 0) * 100);
  aspect-ratio: 5 / 7;
  cursor: pointer;
  /* vertical swipes still scroll the page; horizontal drags move the light */
  touch-action: pan-y;
  -webkit-tap-highlight-color: transparent;
  user-select: none;
}

/* cover-side up until first clicked; set here too so the front never flashes before the script runs */
.holo-card[data-face-down] {
  --turn: -0.5;
}

/* nothing to draw on a front nobody can see yet */
.holo-card[data-face-down] .holo-card__front {
  visibility: hidden;
}

/* a popped-out card takes every drag for the light, including vertical ones */
.holo-card[aria-pressed="true"] {
  touch-action: none;
}

.holo-card:focus-visible {
  outline: none;
}

.holo-card:focus-visible .holo-card__tilt {
  outline: 1cqw solid hsl(215 100% 78%);
  outline-offset: 1.2cqw;
}

/*
  While popped out, the card is laid out at its enlarged size (--res) and scaled
  back down, so the browser draws it sharp instead of stretching a small picture.
  Everything inside is sized in cqw against this box, so it scales as one piece.
*/
.holo-card__mover {
  position: absolute;
  top: 50%;
  left: 50%;
  width: calc(100% * var(--res));
  height: calc(100% * var(--res));
  container-type: inline-size;
  perspective: calc(900px * var(--res));
  transform:
    translate3d(calc(-50% + var(--pop) * var(--tx) * 1px), calc(-50% + var(--pop) * var(--ty) * 1px), 0)
    scale(calc((1 + var(--pop) * (var(--zoom) - 1)) / var(--res)));
}

.holo-card__tilt {
  position: absolute;
  inset: 0;
  border-radius: var(--radius);
  transform-style: preserve-3d;
  /* the spin comes last so the tilt reads the same on either side */
  transform:
    rotateY(calc(var(--mx) * var(--tilt) * -1))
    rotateX(calc(var(--my) * var(--tilt)))
    scale(calc(1 + var(--on) * 0.03))
    rotateY(calc(var(--turn) * 360deg));
  box-shadow:
    calc(var(--mx) * -4.4cqw) calc(4.4cqw + var(--my) * -3.8cqw) 9.4cqw -4.4cqw hsl(var(--shadow) / 0.55),
    0 0.6cqw 1.9cqw -0.6cqw hsl(var(--shadow) / 0.35);
}

.holo-card__face {
  position: absolute;
  inset: 0;
  overflow: hidden;
  border-radius: var(--radius);
  isolation: isolate;
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
}

.holo-card__face > * {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

/* thin printed edge */
.holo-card__face::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  box-shadow: inset 0 0 0 0.3cqw hsl(0 0% 100% / 0.55);
  pointer-events: none;
}

/* ---------- front ---------- */

.holo-card__front {
  background: #fff;
}

.holo-card__paper {
  object-fit: cover;
  opacity: 0.42;
}

.holo-card__layout {
  display: flex;
  flex-direction: column;
  padding: 4.6cqw 5cqw 4.6cqw;
  border-radius: inherit;
  /* the coloured card border */
  box-shadow: inset 0 0 0 2.4cqw var(--theme);
  color: var(--ink);
  font-family: var(--font);
  line-height: 1.35;
}

.holo-card__layout :where(p, ul) {
  margin: 0;
  padding: 0;
  list-style: none;
}

.holo-card__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.6cqw 1.2cqw 1.6cqw;
}

.holo-card__name {
  font-size: 7.4cqw;
  font-weight: 900;
  letter-spacing: 0.04em;
  line-height: 1.2;
}

.holo-card__badge {
  padding: 0.7cqw 2.6cqw;
  border-radius: 99cqw;
  background: var(--theme);
  color: #fff;
  font-size: 3.2cqw;
  font-weight: 700;
  letter-spacing: 0.12em;
  /* letter-spacing trails the last character; this re-centres the label */
  text-indent: 0.12em;
}

/* an emblem in the badge's place */
.holo-card__emblem {
  /* block, so it adds no line spacing and the header stays as tall as on the other cards */
  display: block;
  width: auto;
  height: 8.4cqw;
  margin-right: 0.6cqw;
}

.holo-card__art {
  position: relative;
  flex: none;
  height: 60cqw;
  overflow: hidden;
  border-radius: 1.6cqw;
  isolation: isolate;
  box-shadow:
    0 0 0 0.7cqw #fff,
    0 0 0 0.9cqw hsl(var(--shadow) / 0.16),
    0 1cqw 2.4cqw hsl(var(--shadow) / 0.3);
  /* the window is the top half of the card, so the light is re-aimed for it */
  --ly: calc((50% + var(--my) * 50%) * 2.3 - 26%);
}

.holo-card__art > * {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.holo-card__bg {
  object-fit: cover;
}

/* head and shoulders: the portrait is taller than the window and cropped at the chest */
.holo-card__art > .holo-card__figure {
  /* --figure-scale evens out head sizes between portraits; the top of the head stays put */
  inset: calc(9.5% - var(--figure-head, 0.075) * 180% * var(--figure-scale, 1)) auto auto 50%;
  width: auto;
  height: calc(180% * var(--figure-scale, 1));
  /* centred in the window; it is printed on the card, so it never shifts against its background */
  transform: translateX(-50%);
  filter: drop-shadow(0 0.4em 0.9em hsl(var(--shadow) / 0.28));
}

.holo-card__strip {
  margin: 2.6cqw 3cqw 0;
  padding: 0.7cqw 0;
  border-radius: 99cqw;
  background: linear-gradient(90deg, transparent, var(--theme) 18%, var(--theme) 82%, transparent);
  color: #fff;
  font-size: 3.2cqw;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-align: center;
}

.holo-card__details {
  display: flex;
  flex: 1;
  flex-direction: column;
  justify-content: space-evenly;
  padding: 0 1.2cqw;
}

.holo-card__event {
  display: flex;
  align-items: center;
  gap: 2.4cqw;
  padding-bottom: 2cqw;
  border-bottom: 0.3cqw solid hsl(var(--shadow) / 0.14);
  color: var(--theme-deep);
  font-variant-numeric: tabular-nums;
}

.holo-card__event svg {
  flex: none;
  width: 8cqw;
  height: 8cqw;
}

/* a logo in place of the calendar icon and date */
.holo-card__mark {
  width: auto;
  height: 10cqw;
}

.holo-card__date {
  font-size: 9.8cqw;
  font-weight: 700;
  letter-spacing: 0.01em;
  line-height: 1;
}

.holo-card__date small {
  margin-left: 0.6cqw;
  font-size: 4.6cqw;
  font-weight: 700;
}

.holo-card__time {
  margin-left: auto;
  color: var(--ink);
  font-size: 4.8cqw;
  font-weight: 600;
  letter-spacing: 0.02em;
}

.holo-card__points {
  display: grid;
  gap: 1.7cqw;
  font-size: 4.1cqw;
  font-weight: 700;
  letter-spacing: 0.03em;
}

.holo-card__points li {
  display: flex;
  align-items: center;
  gap: 2.2cqw;
}

.holo-card__points svg {
  flex: none;
  box-sizing: border-box;
  width: 5cqw;
  height: 5cqw;
  padding: 0.9cqw;
  border-radius: 50%;
  background: var(--theme);
  color: #fff;
}

.holo-card__flavor {
  padding-top: 2.2cqw;
  border-top: 0.3cqw solid hsl(var(--shadow) / 0.14);
  color: var(--theme-deep);
  font-size: 3.5cqw;
  font-weight: 700;
  letter-spacing: 0.2em;
  text-align: center;
}

/* ---------- back cover ---------- */

.holo-card__back {
  transform: rotateY(180deg);
  /* this face is mirrored on screen, so the light is too */
  --lx: calc(50% - var(--mx) * 50%);
}

.holo-card__cover {
  --star: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 48 48'%3E%3Cpath fill='%23fff' d='M12 3c.6 4 2.9 6.3 7 7-4.1.7-6.4 3-7 7-.6-4-2.9-6.3-7-7 4.1-.7 6.4-3 7-7zM36 29c.4 2.7 1.9 4.2 4.6 4.6-2.7.4-4.2 1.9-4.6 4.6-.4-2.7-1.9-4.2-4.6-4.6 2.7-.4 4.2-1.9 4.6-4.6z'/%3E%3C/svg%3E");
  display: grid;
  place-content: center;
  justify-items: center;
  gap: 5cqw;
  background:
    radial-gradient(90% 60% at 50% 46%, hsl(0 0% 100% / 0.22), transparent 70%),
    linear-gradient(155deg, hsl(222 92% 44%) 0%, hsl(214 88% 50%) 42%, hsl(178 74% 44%) 80%, hsl(146 72% 62%) 100%);
  box-shadow:
    inset 0 0 0 2.4cqw #fff,
    inset 0 0 0 2.9cqw hsl(var(--shadow) / 0.18),
    inset 0 0 0 5.4cqw hsl(0 0% 100% / 0.14);
  border-radius: inherit;
  color: #fff;
  font-family: var(--font);
}

.holo-card__cover::before {
  content: "";
  position: absolute;
  inset: 6cqw;
  background: var(--star) 0 0 / 16cqw 16cqw;
  opacity: 0.2;
}

/* the logo image, turned solid white */
.holo-card__logo {
  position: relative;
  width: 62cqw;
  height: auto;
  filter: brightness(0) invert(1) drop-shadow(0 1cqw 2cqw hsl(var(--shadow) / 0.35));
}

.holo-card__cover p {
  position: relative;
  margin: 0;
  padding: 1cqw 4.4cqw;
  border-radius: 99cqw;
  background: hsl(0 0% 100% / 0.2);
  font-size: 4.2cqw;
  font-weight: 700;
  letter-spacing: 0.24em;
  text-indent: 0.24em;
}

/* ---------- glare ---------- */

.holo-card__glare {
  background-image: radial-gradient(
    farthest-corner circle at var(--lx) var(--ly),
    hsl(0 0% 100% / 0.9) 0%,
    hsl(0 0% 100% / 0.4) 18%,
    hsl(0 0% 100% / 0) 45%,
    hsl(var(--shadow) / 0.45) 120%
  );
  mix-blend-mode: overlay;
  opacity: calc(var(--on) * 0.7);
}

/* ---------- foils ----------

  data-foil picks one:
    reverse   Reverse Holo: the card body shines, the portrait window stays flat
    holo      Holofoil Rare: rainbow foil and bars of light in the portrait window
    cosmos    Galaxy / Cosmos Holofoil: rainbow foil with orbs and stars in the portrait window
    rainbow   Rainbow Rare: card body and portrait background recoloured in pastel rainbow,
              with faceted stamped foil across the body

  The artwork here is light pastel, so the foils tint and deepen it (burn, multiply,
  hard-light) instead of brightening it; brightening a pastel only turns it white.
*/

/* strongest where the light falls; restated wherever the light position is re-aimed */
.holo-card,
.holo-card__art,
.holo-card__back {
  --spot: radial-gradient(farthest-corner circle at var(--lx) var(--ly), #000 8%, transparent 78%);
}

.holo-card__sheen,
.holo-card__foil,
.holo-card__shimmer {
  opacity: 0;
}

.holo-card__glitter {
  display: none;
}

/* ---------- reverse holo ---------- */

/* a band of rainbow light that slides diagonally across the card body, on a silvery falloff */
.holo-card[data-foil="reverse"] .holo-card__sheen {
  background-image:
    radial-gradient(
      farthest-corner circle at var(--lx) var(--ly),
      hsl(220 30% 100% / 0) 15%,
      hsl(220 26% 70% / 0.16) 70%,
      hsl(222 30% 50% / 0.3) 125%
    ),
    linear-gradient(
      -45deg,
      transparent 27%,
      hsl(218 100% 80%), hsl(174 85% 72%), hsl(92 80% 76%), hsl(45 100% 76%), hsl(348 100% 82%), hsl(284 100% 84%),
      transparent 73%
    );
  background-size: 100% 100%, 240% 240%;
  background-position: center, calc(50% + var(--mx) * 46%) calc(50% + var(--my) * 46%);
  mix-blend-mode: multiply;
  opacity: calc(var(--on) * 0.9);
}

/* ---------- holofoil rare ---------- */

/* slanted rainbow foil with fine vertical scanlines */
.holo-card[data-foil="holo"] .holo-card__foil {
  background-image:
    repeating-linear-gradient(90deg, hsl(0 0% 100%) 0 0.3cqw, hsl(0 0% 80%) 0.3cqw 0.6cqw),
    linear-gradient(
      110deg,
      var(--c6), var(--c5), var(--c4), var(--c2), var(--c1),
      var(--c6), var(--c5), var(--c4), var(--c2), var(--c1),
      var(--c6), var(--c5), var(--c4), var(--c2), var(--c1)
    );
  background-blend-mode: multiply;
  background-size: 100% 100%, 400% 400%;
  background-position: center, calc(50% - var(--mx) * 34%) calc(50% - var(--my) * 45%);
  mix-blend-mode: color-burn;
  opacity: calc(var(--on) * (0.5 + var(--hyp) * 0.3));
}

/* two sets of vertical light bars that drift past each other as the card tilts */
.holo-card[data-foil="holo"] .holo-card__shimmer {
  --bars-a: repeating-linear-gradient(
    90deg,
    transparent 0 6%, #000 9%, transparent 10.5%, #000 12%, transparent 15%, transparent 42%
  );
  --bars-b: repeating-linear-gradient(
    90deg,
    transparent 0 6%, #000 9%, transparent 10.5%, #000 12%, transparent 15%, transparent 30%
  );
  background-image: linear-gradient(
    110deg,
    var(--c3), var(--c4), var(--c5), var(--c6), var(--c1), var(--c2),
    var(--c3), var(--c4), var(--c5), var(--c6), var(--c1), var(--c2), var(--c3)
  );
  background-size: 300% 300%;
  background-position: calc(50% + var(--mx) * 40%) calc(50% + var(--my) * 40%);
  -webkit-mask-image: var(--bars-a), var(--bars-b);
  mask-image: var(--bars-a), var(--bars-b);
  -webkit-mask-size: 200% 100%;
  mask-size: 200% 100%;
  -webkit-mask-position:
    calc(50% - var(--mx) * 55% + var(--my) * 18%) center,
    calc(50% + var(--mx) * 32% - var(--my) * 28%) center;
  mask-position:
    calc(50% - var(--mx) * 55% + var(--my) * 18%) center,
    calc(50% + var(--mx) * 32% - var(--my) * 28%) center;
  mix-blend-mode: hard-light;
  opacity: calc(var(--on) * (0.45 + var(--hyp) * 0.3));
}

/* ---------- galaxy / cosmos holofoil ---------- */

.holo-card[data-foil="cosmos"] .holo-card__foil {
  --band: 4%;
  background-image:
    radial-gradient(
      farthest-corner circle at var(--lx) var(--ly),
      hsl(180 100% 94% / 0.75) 5%,
      hsl(200 40% 78% / 0.35) 45%,
      hsl(240 45% 40% / 0.5) 130%
    ),
    repeating-linear-gradient(
      82deg,
      var(--c2) calc(var(--band) * 1), var(--c3) calc(var(--band) * 2), var(--c4) calc(var(--band) * 3),
      var(--c5) calc(var(--band) * 4), var(--c6) calc(var(--band) * 5), var(--c1) calc(var(--band) * 6),
      var(--c1) calc(var(--band) * 7), var(--c6) calc(var(--band) * 8), var(--c5) calc(var(--band) * 9),
      var(--c4) calc(var(--band) * 10), var(--c3) calc(var(--band) * 11), var(--c2) calc(var(--band) * 12)
    );
  background-size: 100% 100%, 300% 500%;
  background-position: center, calc(50% + var(--mx) * 40%) calc(50% + var(--my) * 40%);
  mix-blend-mode: color-burn;
  opacity: calc(var(--on) * (0.5 + var(--hyp) * 0.3));
}

/* orbs, rings and stars cut out of a pale rainbow; the two layers slide at different speeds */
.holo-card[data-foil="cosmos"] .holo-card__shimmer {
  --orbs: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 300 300' fill='%23fff'%3E%3CradialGradient id='o'%3E%3Cstop offset='0' stop-color='%23fff'/%3E%3Cstop offset='.55' stop-color='%23fff' stop-opacity='.55'/%3E%3Cstop offset='1' stop-color='%23fff' stop-opacity='0'/%3E%3C/radialGradient%3E%3Ccircle cx='45.3' cy='195.3' r='12.5' fill='url(%23o)'/%3E%3Ccircle cx='160.8' cy='109.7' r='8.2' fill='url(%23o)'/%3E%3Ccircle cx='152.2' cy='11.2' r='8.0' fill='url(%23o)'/%3E%3Ccircle cx='21.0' cy='27.2' r='14.4' fill='url(%23o)'/%3E%3Ccircle cx='248.1' cy='37.1' r='14.2' fill='url(%23o)'/%3E%3Ccircle cx='188.2' cy='284.3' r='10.8' fill='url(%23o)'/%3E%3Ccircle cx='119.0' cy='-7.1' r='16.8' fill='url(%23o)'/%3E%3Ccircle cx='119.0' cy='292.9' r='16.8' fill='url(%23o)'/%3E%3Ccircle cx='257.5' cy='86.9' r='7.8' fill='url(%23o)'/%3E%3Ccircle cx='35.3' cy='92.5' r='9.5' fill='url(%23o)'/%3E%3Ccircle cx='54.2' cy='174.5' r='20.9' fill='url(%23o)'/%3E%3Ccircle cx='111.7' cy='164.3' r='17.9' fill='url(%23o)'/%3E%3Ccircle cx='17.9' cy='61.8' r='8.1' fill='url(%23o)'/%3E%3Ccircle cx='128.3' cy='94.2' r='18.6' fill='url(%23o)'/%3E%3Ccircle cx='136.0' cy='89.9' r='17.0' fill='url(%23o)'/%3E%3Ccircle cx='209.7' cy='73.2' r='20.5' fill='url(%23o)'/%3E%3Ccircle cx='157.6' cy='262.5' r='16.8' fill='url(%23o)'/%3E%3Ccircle cx='-5.9' cy='35.4' r='12.3' fill='none' stroke='%23fff' stroke-width='1.6' opacity='0.48'/%3E%3Ccircle cx='294.1' cy='35.4' r='12.3' fill='none' stroke='%23fff' stroke-width='1.6' opacity='0.48'/%3E%3Ccircle cx='45.6' cy='146.7' r='9.2' fill='none' stroke='%23fff' stroke-width='1.6' opacity='0.69'/%3E%3Ccircle cx='229.4' cy='171.9' r='5.4' fill='none' stroke='%23fff' stroke-width='1.6' opacity='0.65'/%3E%3Ccircle cx='208.6' cy='178.3' r='13.8' fill='none' stroke='%23fff' stroke-width='1.6' opacity='0.49'/%3E%3Ccircle cx='252.0' cy='283.4' r='10.8' fill='none' stroke='%23fff' stroke-width='1.6' opacity='0.56'/%3E%3Ccircle cx='18.2' cy='210.4' r='9.7' fill='none' stroke='%23fff' stroke-width='1.6' opacity='0.65'/%3E%3Ccircle cx='246.6' cy='85.4' r='11.5' fill='none' stroke='%23fff' stroke-width='1.6' opacity='0.8'/%3E%3Ccircle cx='6.8' cy='138.5' r='8.9' fill='none' stroke='%23fff' stroke-width='1.6' opacity='0.65'/%3E%3Ccircle cx='306.8' cy='138.5' r='8.9' fill='none' stroke='%23fff' stroke-width='1.6' opacity='0.65'/%3E%3Ccircle cx='17.7' cy='230.5' r='6.7' fill='none' stroke='%23fff' stroke-width='1.6' opacity='0.4'/%3E%3C/svg%3E");
  --stars: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 300 300' fill='%23fff'%3E%3Ccircle cx='25.1' cy='177.6' r='1.1' opacity='0.94'/%3E%3Ccircle cx='107.4' cy='217.8' r='1.4' opacity='0.66'/%3E%3Ccircle cx='66.3' cy='136.5' r='1.1' opacity='0.69'/%3E%3Ccircle cx='294.4' cy='149.5' r='0.7' opacity='0.51'/%3E%3Ccircle cx='220.3' cy='107.7' r='0.7' opacity='0.73'/%3E%3Ccircle cx='10.6' cy='110.7' r='0.7' opacity='0.56'/%3E%3Ccircle cx='291.2' cy='108.8' r='0.9' opacity='0.79'/%3E%3Ccircle cx='84.4' cy='292.4' r='1.1' opacity='0.98'/%3E%3Ccircle cx='142.2' cy='215.4' r='1.8' opacity='0.5'/%3E%3Ccircle cx='202.7' cy='49.1' r='1.8' opacity='0.89'/%3E%3Ccircle cx='202.0' cy='156.0' r='0.9' opacity='0.74'/%3E%3Ccircle cx='29.6' cy='11.7' r='1.8' opacity='0.51'/%3E%3Ccircle cx='84.2' cy='177.0' r='1.1' opacity='0.97'/%3E%3Ccircle cx='86.5' cy='91.4' r='0.7' opacity='0.65'/%3E%3Ccircle cx='77.5' cy='32.1' r='1.4' opacity='0.75'/%3E%3Ccircle cx='248.6' cy='71.4' r='0.7' opacity='0.84'/%3E%3Ccircle cx='223.6' cy='30.1' r='1.8' opacity='0.53'/%3E%3Ccircle cx='292.5' cy='16.8' r='1.4' opacity='0.54'/%3E%3Ccircle cx='48.8' cy='67.7' r='1.4' opacity='0.67'/%3E%3Ccircle cx='241.5' cy='284.6' r='0.7' opacity='0.99'/%3E%3Ccircle cx='133.5' cy='27.8' r='1.8' opacity='0.97'/%3E%3Ccircle cx='113.1' cy='58.0' r='0.7' opacity='0.99'/%3E%3Ccircle cx='164.5' cy='226.5' r='0.7' opacity='0.6'/%3E%3Ccircle cx='64.8' cy='31.1' r='1.4' opacity='0.97'/%3E%3Ccircle cx='207.2' cy='167.4' r='1.8' opacity='0.81'/%3E%3Ccircle cx='126.5' cy='270.3' r='0.9' opacity='0.59'/%3E%3Ccircle cx='197.0' cy='124.3' r='1.4' opacity='0.87'/%3E%3Ccircle cx='206.3' cy='123.8' r='0.9' opacity='0.94'/%3E%3Ccircle cx='269.3' cy='223.7' r='2.4' opacity='0.98'/%3E%3Ccircle cx='122.9' cy='231.5' r='1.8' opacity='0.61'/%3E%3Ccircle cx='15.5' cy='85.5' r='1.8' opacity='0.79'/%3E%3Ccircle cx='99.8' cy='167.8' r='0.7' opacity='0.8'/%3E%3Ccircle cx='285.5' cy='23.6' r='1.4' opacity='0.59'/%3E%3Ccircle cx='34.1' cy='266.1' r='1.8' opacity='0.83'/%3E%3Ccircle cx='296.5' cy='81.6' r='1.4' opacity='0.89'/%3E%3Ccircle cx='235.7' cy='42.6' r='1.1' opacity='0.66'/%3E%3Ccircle cx='204.3' cy='51.9' r='1.4' opacity='0.56'/%3E%3Ccircle cx='286.4' cy='126.0' r='1.4' opacity='0.86'/%3E%3Ccircle cx='206.7' cy='161.7' r='1.1' opacity='0.71'/%3E%3Ccircle cx='159.7' cy='79.6' r='1.8' opacity='0.55'/%3E%3Ccircle cx='18.7' cy='267.0' r='0.7' opacity='0.57'/%3E%3Ccircle cx='202.0' cy='181.5' r='1.4' opacity='0.88'/%3E%3Ccircle cx='122.2' cy='241.4' r='1.1' opacity='0.82'/%3E%3Ccircle cx='102.4' cy='116.3' r='1.1' opacity='0.98'/%3E%3Ccircle cx='200.4' cy='226.8' r='1.4' opacity='0.94'/%3E%3Ccircle cx='207.3' cy='115.2' r='1.1' opacity='0.75'/%3E%3Ccircle cx='43.9' cy='111.3' r='1.1' opacity='0.99'/%3E%3Ccircle cx='36.3' cy='169.8' r='1.8' opacity='0.7'/%3E%3Ccircle cx='11.1' cy='234.8' r='1.4' opacity='0.45'/%3E%3Ccircle cx='294.8' cy='190.3' r='0.7' opacity='0.59'/%3E%3Ccircle cx='23.9' cy='60.1' r='0.7' opacity='0.67'/%3E%3Ccircle cx='251.2' cy='27.1' r='1.8' opacity='0.53'/%3E%3Ccircle cx='183.3' cy='108.3' r='2.4' opacity='0.73'/%3E%3Ccircle cx='208.9' cy='181.5' r='0.7' opacity='0.79'/%3E%3Ccircle cx='273.5' cy='54.8' r='0.7' opacity='0.99'/%3E%3Ccircle cx='204.9' cy='279.7' r='0.7' opacity='0.52'/%3E%3Ccircle cx='212.7' cy='170.9' r='1.1' opacity='0.71'/%3E%3Ccircle cx='180.9' cy='177.4' r='0.7' opacity='0.9'/%3E%3Ccircle cx='105.2' cy='48.0' r='1.1' opacity='0.47'/%3E%3Ccircle cx='128.0' cy='95.0' r='0.9' opacity='0.56'/%3E%3Ccircle cx='176.1' cy='281.6' r='1.8' opacity='0.57'/%3E%3Ccircle cx='195.4' cy='223.4' r='2.4' opacity='0.65'/%3E%3Ccircle cx='265.9' cy='294.4' r='2.4' opacity='0.62'/%3E%3Ccircle cx='114.0' cy='232.2' r='2.4' opacity='0.52'/%3E%3Ccircle cx='105.1' cy='63.1' r='0.7' opacity='0.72'/%3E%3Ccircle cx='63.2' cy='122.0' r='2.4' opacity='0.74'/%3E%3Ccircle cx='220.8' cy='141.8' r='0.7' opacity='0.47'/%3E%3Ccircle cx='124.3' cy='73.8' r='0.9' opacity='0.77'/%3E%3Ccircle cx='88.9' cy='245.5' r='1.1' opacity='0.47'/%3E%3Ccircle cx='172.7' cy='290.3' r='1.4' opacity='0.9'/%3E%3Ccircle cx='189.4' cy='244.1' r='1.8' opacity='0.94'/%3E%3Ccircle cx='294.4' cy='198.3' r='0.9' opacity='0.96'/%3E%3Ccircle cx='136.9' cy='0.9' r='1.4' opacity='0.99'/%3E%3Ccircle cx='136.9' cy='300.9' r='1.4' opacity='0.99'/%3E%3Ccircle cx='17.1' cy='10.2' r='2.4' opacity='0.66'/%3E%3Ccircle cx='282.9' cy='201.5' r='1.4' opacity='0.64'/%3E%3Ccircle cx='215.8' cy='43.1' r='2.4' opacity='0.93'/%3E%3Ccircle cx='243.5' cy='139.3' r='0.7' opacity='0.86'/%3E%3Ccircle cx='127.0' cy='205.9' r='0.7' opacity='0.96'/%3E%3Ccircle cx='35.2' cy='5.3' r='2.4' opacity='0.89'/%3E%3Ccircle cx='159.5' cy='59.2' r='1.8' opacity='0.78'/%3E%3Ccircle cx='93.7' cy='211.1' r='1.1' opacity='0.88'/%3E%3Ccircle cx='163.8' cy='237.2' r='1.4' opacity='0.72'/%3E%3Ccircle cx='221.7' cy='66.1' r='1.1' opacity='0.64'/%3E%3Ccircle cx='270.3' cy='45.9' r='2.4' opacity='0.76'/%3E%3Ccircle cx='41.9' cy='278.0' r='2.4' opacity='0.88'/%3E%3Ccircle cx='290.9' cy='33.2' r='2.4' opacity='0.96'/%3E%3Ccircle cx='24.4' cy='238.6' r='1.8' opacity='0.49'/%3E%3Ccircle cx='280.9' cy='10.6' r='2.4' opacity='0.71'/%3E%3Ccircle cx='171.9' cy='297.7' r='1.1' opacity='0.6'/%3E%3Ccircle cx='276.0' cy='276.2' r='2.4' opacity='0.45'/%3E%3Ccircle cx='21.3' cy='246.1' r='2.4' opacity='0.85'/%3E%3Ccircle cx='146.6' cy='220.9' r='0.9' opacity='0.91'/%3E%3Ccircle cx='278.0' cy='180.0' r='0.9' opacity='0.59'/%3E%3Ccircle cx='170.8' cy='171.6' r='1.4' opacity='0.87'/%3E%3Ccircle cx='41.8' cy='239.1' r='0.7' opacity='0.8'/%3E%3Ccircle cx='282.2' cy='167.3' r='1.1' opacity='0.81'/%3E%3Ccircle cx='149.0' cy='136.9' r='1.4' opacity='0.45'/%3E%3Ccircle cx='183.6' cy='249.7' r='1.1' opacity='0.82'/%3E%3Ccircle cx='252.4' cy='34.5' r='0.9' opacity='0.62'/%3E%3Ccircle cx='175.0' cy='292.7' r='0.9' opacity='0.53'/%3E%3Ccircle cx='225.7' cy='59.0' r='1.8' opacity='0.91'/%3E%3Ccircle cx='161.0' cy='178.0' r='0.9' opacity='0.74'/%3E%3Ccircle cx='79.9' cy='180.0' r='0.9' opacity='0.91'/%3E%3Ccircle cx='285.5' cy='274.6' r='1.8' opacity='0.84'/%3E%3Ccircle cx='129.1' cy='19.3' r='0.9' opacity='0.51'/%3E%3Ccircle cx='295.1' cy='230.5' r='2.4' opacity='0.73'/%3E%3Ccircle cx='44.3' cy='189.3' r='0.7' opacity='0.84'/%3E%3Ccircle cx='47.9' cy='165.1' r='1.4' opacity='0.7'/%3E%3Ccircle cx='169.1' cy='292.0' r='0.9' opacity='0.63'/%3E%3Ccircle cx='220.9' cy='45.8' r='0.7' opacity='0.88'/%3E%3Ccircle cx='9.4' cy='10.7' r='1.8' opacity='0.66'/%3E%3Ccircle cx='267.0' cy='104.8' r='0.7' opacity='0.54'/%3E%3Ccircle cx='233.8' cy='101.3' r='0.9' opacity='0.71'/%3E%3Ccircle cx='273.2' cy='236.9' r='0.7' opacity='0.89'/%3E%3Ccircle cx='199.9' cy='112.9' r='0.7' opacity='0.67'/%3E%3Ccircle cx='169.6' cy='194.7' r='2.4' opacity='0.46'/%3E%3Ccircle cx='257.5' cy='233.4' r='0.7' opacity='0.46'/%3E%3Ccircle cx='255.4' cy='200.5' r='2.4' opacity='0.53'/%3E%3Ccircle cx='289.1' cy='284.1' r='2.4' opacity='0.79'/%3E%3Ccircle cx='209.9' cy='122.8' r='2.4' opacity='0.97'/%3E%3Cpath d='M82.4 158.4q0.7 3.9 4.6 4.6q-3.9 0.7-4.6 4.6q-0.7-3.9-4.6-4.6q3.9-0.7 4.6-4.6z'/%3E%3Cpath d='M243.5 163.9q1.1 5.9 7.0 7.0q-5.9 1.1-7.0 7.0q-1.1-5.9-7.0-7.0q5.9-1.1 7.0-7.0z'/%3E%3Cpath d='M153.6 195.3q1.2 6.0 7.2 7.2q-6.0 1.2-7.2 7.2q-1.2-6.0-7.2-7.2q6.0-1.2 7.2-7.2z'/%3E%3Cpath d='M80.6 212.6q0.8 4.1 4.9 4.9q-4.1 0.8-4.9 4.9q-0.8-4.1-4.9-4.9q4.1-0.8 4.9-4.9z'/%3E%3Cpath d='M244.9 259.9q1.2 6.4 7.6 7.6q-6.4 1.2-7.6 7.6q-1.2-6.4-7.6-7.6q6.4-1.2 7.6-7.6z'/%3E%3Cpath d='M164.6 255.9q1.3 6.6 7.9 7.9q-6.6 1.3-7.9 7.9q-1.3-6.6-7.9-7.9q6.6-1.3 7.9-7.9z'/%3E%3Cpath d='M214.8 10.0q1.0 5.4 6.4 6.4q-5.4 1.0-6.4 6.4q-1.0-5.4-6.4-6.4q5.4-1.0 6.4-6.4z'/%3E%3Cpath d='M227.1 17.6q1.0 5.1 6.1 6.1q-5.1 1.0-6.1 6.1q-1.0-5.1-6.1-6.1q5.1-1.0 6.1-6.1z'/%3E%3Cpath d='M5.7 178.4q0.8 4.1 4.9 4.9q-4.1 0.8-4.9 4.9q-0.8-4.1-4.9-4.9q4.1-0.8 4.9-4.9z'/%3E%3Cpath d='M109.6 260.0q1.4 7.1 8.5 8.5q-7.1 1.4-8.5 8.5q-1.4-7.1-8.5-8.5q7.1-1.4 8.5-8.5z'/%3E%3C/svg%3E");
  background-image: linear-gradient(
    -38deg,
    hsl(0 0% 100%), hsl(190 100% 84%), hsl(0 0% 100%), hsl(320 100% 88%),
    hsl(0 0% 100%), hsl(55 100% 82%), hsl(0 0% 100%), hsl(265 100% 88%), hsl(0 0% 100%)
  );
  background-size: 300% 300%;
  background-position: calc(50% - var(--mx) * 50%) calc(50% - var(--my) * 50%);
  -webkit-mask-image: var(--spot), var(--orbs), var(--stars);
  mask-image: var(--spot), var(--orbs), var(--stars);
  -webkit-mask-size: 100% 100%, 62cqw 62cqw, 47cqw 47cqw;
  mask-size: 100% 100%, 62cqw 62cqw, 47cqw 47cqw;
  -webkit-mask-position:
    center,
    calc(var(--mx) * 5cqw) calc(var(--my) * 5cqw),
    calc(11cqw + var(--mx) * -9cqw) calc(7cqw + var(--my) * -9cqw);
  mask-position:
    center,
    calc(var(--mx) * 5cqw) calc(var(--my) * 5cqw),
    calc(11cqw + var(--mx) * -9cqw) calc(7cqw + var(--my) * -9cqw);
  -webkit-mask-composite: source-in, source-over;
  mask-composite: intersect, add;
  opacity: var(--on);
}

/* ---------- rainbow rare ----------

  Unlike the other foils this one is always on: the card is rainbow even at rest, and
  the light only slides the colours. The figure sits above all of it, in its own colours.
*/

.holo-card[data-foil="rainbow"] {
  --r1: hsl(0 90% 68%);
  --r2: hsl(35 95% 65%);
  --r3: hsl(55 95% 65%);
  --r4: hsl(110 70% 62%);
  --r5: hsl(185 80% 60%);
  --r6: hsl(220 90% 68%);
  --r7: hsl(285 80% 70%);
  --rainbow: linear-gradient(
    -30deg,
    var(--r1), var(--r2), var(--r3), var(--r4), var(--r5), var(--r6), var(--r7),
    var(--r1), var(--r2), var(--r3), var(--r4), var(--r5), var(--r6), var(--r7),
    var(--r1), var(--r2), var(--r3), var(--r4), var(--r5), var(--r6), var(--r7), var(--r1)
  );
  /* the border, badge and icons drift through the spectrum as the card tilts */
  --hue: calc(265 + var(--mx) * 80 + var(--my) * 50);
  --theme: hsl(var(--hue) 58% 62%);
  --theme-deep: hsl(var(--hue) 50% 42%);
}

/* The card body, under the text. It is laid on fairly strong: the foil above it can only shine
   against a mid-tone, and on near-white stock there would be nothing left to brighten. */
.holo-card[data-foil="rainbow"] .holo-card__sheen {
  background-image: var(--rainbow);
  background-size: 400% 400%;
  background-position: calc(50% + var(--mx) * 22%) calc(50% + var(--my) * 22%);
  mix-blend-mode: multiply;
  opacity: 0.8;
}

/* No relief pattern over the body: the rainbow stock is left smooth, with only the sheen moving
   across it. (The portrait window keeps the plain contour-line texture.) */
.holo-card[data-foil="rainbow"] .holo-card__front > .holo-card__etch {
  display: none;
}

/* the portrait window's background: the rainbow's hue on the artwork's own light and shade... */
.holo-card[data-foil="rainbow"] .holo-card__foil {
  background-image: var(--rainbow);
  background-size: 400% 400%;
  background-position: calc(50% + var(--mx) * 22%) calc(50% + var(--my) * 22%);
  mix-blend-mode: color;
  opacity: 0.9;
}

/* ...plus a wash so its whites pick up colour too */
.holo-card[data-foil="rainbow"] .holo-card__shimmer {
  background-image: var(--rainbow);
  background-size: 400% 400%;
  background-position: calc(50% + var(--mx) * 22%) calc(50% + var(--my) * 22%);
  mix-blend-mode: multiply;
  opacity: 0.4;
}

/* a light dusting of glitter behind the figure, only where the light falls */
.holo-card[data-foil="rainbow"] .holo-card__glitter {
  display: block;
  background: url("glitter.png") calc(var(--mx) * 4cqw) calc(var(--my) * 4cqw) / 110cqw 110cqw;
  -webkit-mask-image: var(--spot);
  mask-image: var(--spot);
  /* glitter.png is bright specks on black; black adds nothing, so only the specks show */
  mix-blend-mode: screen;
  opacity: calc(var(--on) * 0.75);
}

.holo-card[data-foil="rainbow"] .holo-card__cover {
  background:
    radial-gradient(90% 60% at 50% 46%, hsl(0 0% 100% / 0.25), transparent 70%),
    linear-gradient(
      155deg,
      hsl(285 70% 56%), hsl(222 86% 56%), hsl(186 76% 44%), hsl(120 55% 50%), hsl(44 92% 54%), hsl(2 82% 62%)
    );
}

/* ---------- etched texture ----------

  Fine contour lines pressed into the foil, like the etching on textured cards. They
  come from etch.webp (dark lines on white) and show as rainbow glints near the light.
  One layer sits under the text on the card body and one in the portrait window
  behind the figure.

  The texture is a plain image rather than a live SVG filter on purpose: a filter
  is redrawn at every size the card passes through while it pops out, which is slow
  and can exhaust memory.
*/

.holo-card__etch {
  --pattern: url("etch.webp");
  --pattern-size: 120cqw 120cqw;
  background-image:
    var(--pattern),
    linear-gradient(
      125deg,
      var(--c1), var(--c2), var(--c3), var(--c4), var(--c5), var(--c6),
      var(--c1), var(--c2), var(--c3), var(--c4), var(--c5), var(--c6), var(--c1)
    );
  /* white stays white; the dark lines take on the rainbow */
  background-blend-mode: screen;
  background-size: var(--pattern-size), 300% 300%;
  background-position: 0 0, calc(50% + var(--mx) * 45%) calc(50% + var(--my) * 45%);
  -webkit-mask-image: var(--spot);
  mask-image: var(--spot);
  mix-blend-mode: multiply;
  opacity: calc(var(--on) * 0.45);
}

/* shifted so the lines carry on from the card body into the window */
.holo-card__art > .holo-card__etch {
  background-position: -5cqw -15cqw, calc(50% + var(--mx) * 45%) calc(50% + var(--my) * 45%);
}

/* a reverse holo keeps its portrait window flat */
.holo-card[data-foil="reverse"] .holo-card__art > .holo-card__etch {
  display: none;
}

@media (prefers-reduced-motion: reduce) {
  .holo-card {
    --tilt: 0deg;
  }
}
