/*
  Same sizing idea as the wedding page: the card is a fixed-shape artboard (100 x 176 units
  in portrait, 160 x 100 in landscape) and one unit (--u) is worked out from the screen so
  it always fits, centred, with padding (--p) around it. Nothing ever needs to scroll.
*/

:root {
  --hot: #ff2d87;
  --magenta: #d6006f;
  --bubblegum: #ff7ab8;
  --blush: #ffd1e6;
  --cream: #fff7fb;
  --peach: #ffb38a;
  --sun: #ffd23f;
  --grape: #8b3dff;
  --ink: #4a0f2e;

  --p: clamp(14px, 4.5vmin, 44px);
  --w: 100;
  --h: 176;
  --u: min(
    calc((100vw - 2 * var(--p)) / var(--w)),
    calc((100vh - 2 * var(--p) - 1px) / var(--h))
  );
}

@media (min-aspect-ratio: 1/1) {
  :root {
    --w: 160;
    --h: 100;
  }
}

@supports (height: 100svh) {
  :root {
    --u: min(
      calc((100vw - 2 * var(--p)) / var(--w)),
      calc((100svh - 2 * var(--p) - 1px) / var(--h))
    );
  }
}

* {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
  background: var(--hot);
}

body {
  margin: 0;
  overflow: hidden;
  color: var(--ink);
  font-family: "Caveat", "Segoe Print", "Bradley Hand", cursive;
  background:
    radial-gradient(60% 45% at 15% 12%, #ff8fc4 0, transparent 70%),
    radial-gradient(55% 45% at 88% 20%, var(--peach) 0, transparent 70%),
    radial-gradient(70% 55% at 80% 92%, #b5179e 0, transparent 70%),
    radial-gradient(60% 50% at 8% 88%, #ff5fa2 0, transparent 70%),
    linear-gradient(160deg, #ff4f9a, var(--magenta));
  -webkit-tap-highlight-color: transparent;
  user-select: none;
  -webkit-user-select: none;
}

/* ---------- pop-art backdrop ---------- */

.sunburst {
  position: fixed;
  left: 50%;
  top: 50%;
  width: 220vmax;
  height: 220vmax;
  margin: -110vmax 0 0 -110vmax;
  background: repeating-conic-gradient(rgba(255, 255, 255, 0.16) 0 9deg, transparent 9deg 18deg);
  -webkit-mask: radial-gradient(closest-side, #000 20%, transparent 78%);
  mask: radial-gradient(closest-side, #000 20%, transparent 78%);
}

.dots {
  position: fixed;
  inset: 0;
  background-image: radial-gradient(rgba(255, 255, 255, 0.5) 22%, transparent 24%);
  background-size: 18px 18px;
  -webkit-mask: linear-gradient(135deg, #000, transparent 38%, transparent 62%, #000);
  mask: linear-gradient(135deg, #000, transparent 38%, transparent 62%, #000);
  opacity: 0.55;
}

.balloons {
  position: fixed;
  inset: 0;
  overflow: hidden;
}
.balloon {
  position: absolute;
  bottom: 0;
  left: var(--x);
  width: var(--size);
  translate: -50% 110%;
  cursor: pointer;
  color: var(--c);
  filter: drop-shadow(0 6px 10px rgba(74, 15, 46, 0.25));
}
.balloon svg {
  display: block;
  width: 100%;
  height: auto;
  overflow: visible;
}
.balloon.popped svg {
  animation: pop 0.22s ease-out forwards;
}

.confetti {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 5;
}

/* ---------- stage ---------- */

.stage {
  position: relative;
  z-index: 2;
  height: 100vh;
  height: 100svh;
  display: grid;
  place-items: center;
  padding: var(--p);
  perspective: calc(var(--u) * 300);
}
.stage > * {
  grid-area: 1 / 1;
}

/* ---------- the card ---------- */

.card {
  width: calc(var(--u) * var(--w));
  height: calc(var(--u) * var(--h));
  padding: calc(var(--u) * 3);
  border: calc(var(--u) * 1) solid var(--ink);
  border-radius: calc(var(--u) * 7);
  background: var(--hot);
  box-shadow: calc(var(--u) * 1.8) calc(var(--u) * 1.8) 0 var(--ink);
  rotate: -1.2deg;
}

.card-inner {
  position: relative;
  height: 100%;
  padding: calc(var(--u) * 5) calc(var(--u) * 6) calc(var(--u) * 5);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-between;
  gap: calc(var(--u) * 2);
  overflow: hidden;
  border: calc(var(--u) * 0.6) solid var(--ink);
  border-radius: calc(var(--u) * 4.5);
  background:
    radial-gradient(var(--blush) 20%, transparent 22%) 0 0 / calc(var(--u) * 5) calc(var(--u) * 5),
    var(--cream);
  text-align: center;
}

.hero,
.words {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100%;
}

/* sticker lettering: white outline, then a hard plum shadow stepping down and right */
.hb {
  margin: 0;
  font-family: "Shrikhand", "Cooper Black", Georgia, serif;
  font-weight: 400;
  font-size: calc(var(--u) * 15.5 * var(--fit-head, 1));
  line-height: 0.92;
  color: var(--hot);
  rotate: -5deg;
  -webkit-text-stroke: 0.09em #fff;
  paint-order: stroke fill;
  text-shadow:
    0.035em 0.035em 0 var(--ink),
    0.07em 0.07em 0 var(--ink),
    0.105em 0.105em 0 var(--ink),
    0.14em 0.14em 0 var(--ink);
}
.hb-line {
  display: block;
  white-space: nowrap;
}
.hb-line:nth-child(2) {
  color: var(--grape);
  margin-left: 0.5em;
}
.hb-line i {
  display: inline-block;
  font-style: normal;
}

.ribbon {
  position: relative;
  margin: calc(var(--u) * 3.4) 0 0;
  padding: 0 calc(var(--u) * 7);
  rotate: 2.5deg;
  background: var(--sun);
  border: calc(var(--u) * 0.6) solid var(--ink);
  box-shadow: calc(var(--u) * 0.9) calc(var(--u) * 0.9) 0 var(--ink);
  clip-path: polygon(0 0, 100% 0, calc(100% - var(--u) * 3.2) 50%, 100% 100%, 0 100%, calc(var(--u) * 3.2) 50%);
}
.ribbon span {
  display: block;
  font-family: "Shrikhand", "Cooper Black", Georgia, serif;
  font-size: calc(var(--u) * 10.5);
  line-height: 1.5;
  color: var(--ink);
}

.cake {
  width: calc(var(--u) * 46);
  height: auto;
  margin-top: calc(var(--u) * 2.5);
  overflow: visible;
}

.spark {
  position: absolute;
  width: calc(var(--u) * var(--s));
  height: calc(var(--u) * var(--s));
  fill: var(--c);
  stroke: var(--ink);
  stroke-width: 1.4;
  stroke-linejoin: round;
}
.s1 { --s: 9; --c: var(--sun); left: 0; top: calc(var(--u) * -1); }
.s2 { --s: 6; --c: var(--bubblegum); right: calc(var(--u) * 1); top: calc(var(--u) * 12); }
.s3 { --s: 7; --c: var(--grape); left: calc(var(--u) * 3); bottom: calc(var(--u) * 6); }

.words {
  padding: calc(var(--u) * 3.6) calc(var(--u) * 4) calc(var(--u) * 3.2);
  border: calc(var(--u) * 0.5) dashed var(--bubblegum);
  border-radius: calc(var(--u) * 3.5);
  background: #fff;
  rotate: 0.8deg;
}

.message {
  margin: 0;
  font-size: calc(var(--u) * 7.6 * var(--fit, 1));
  font-weight: 500;
  line-height: 1.12;
  color: var(--ink);
  text-wrap: pretty;
}
.signoff {
  margin: calc(var(--u) * 2.6) 0 0;
  font-size: calc(var(--u) * 8.4 * var(--fit, 1));
  font-weight: 700;
  line-height: 1.05;
  color: var(--magenta);
  text-wrap: balance;
}

/* ---------- landscape: lettering and cake on the left, the words on the right ---------- */

@media (min-aspect-ratio: 1/1) {
  .card-inner {
    flex-direction: row;
    justify-content: center;
    gap: calc(var(--u) * 5);
    padding: calc(var(--u) * 5) calc(var(--u) * 7);
  }
  .hero {
    width: calc(var(--u) * 68);
    flex: none;
  }
  .words {
    flex: 1;
    min-width: 0;
  }
  .hb {
    font-size: calc(var(--u) * 12.5 * var(--fit-head, 1));
  }
  .ribbon span {
    font-size: calc(var(--u) * 8);
  }
  .cake {
    width: calc(var(--u) * 30);
  }
  .words {
    align-self: center;
  }
  .message {
    font-size: calc(var(--u) * 7 * var(--fit, 1));
  }
  .signoff {
    font-size: calc(var(--u) * 7.8 * var(--fit, 1));
  }
  .s2 { top: calc(var(--u) * 6); }
}

/* ---------- the envelope (only shown when scripting is on) ---------- */

.envelope {
  --ew: calc(var(--u) * 80);
  --eh: calc(var(--u) * 54);
  position: relative;
  z-index: 3;
  width: var(--ew);
  height: var(--eh);
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: inherit;
  cursor: pointer;
  rotate: -3deg;
  filter: drop-shadow(calc(var(--u) * 1.6) calc(var(--u) * 2.2) 0 rgba(74, 15, 46, 0.85));
  transform-style: preserve-3d;
}
.envelope[hidden] {
  display: none;
}
.envelope > span {
  position: absolute;
  display: block;
}
.env-back,
.env-front {
  inset: 0;
  border: calc(var(--u) * 0.8) solid var(--ink);
  border-radius: calc(var(--u) * 3.5);
}
.env-back {
  background: #ffb3d4;
}
.env-peek {
  left: 7%;
  right: 7%;
  top: 8%;
  bottom: 12%;
  border: calc(var(--u) * 0.6) solid var(--ink);
  border-radius: calc(var(--u) * 2);
  background:
    radial-gradient(var(--blush) 20%, transparent 22%) 0 0 / calc(var(--u) * 5) calc(var(--u) * 5),
    var(--cream);
}
.env-front {
  background:
    linear-gradient(to top right, #ff9cc8 49.4%, var(--ink) 49.5% 50.5%, transparent 50.6%) left / 50.2% 100% no-repeat,
    linear-gradient(to top left, #ff9cc8 49.4%, var(--ink) 49.5% 50.5%, transparent 50.6%) right / 50.2% 100% no-repeat;
  clip-path: polygon(0 0, 50% 52%, 100% 0, 100% 100%, 0 100%);
  overflow: hidden;
}
.env-front::after {
  content: "";
  position: absolute;
  inset: 52% 0 0;
  background: #ff86bb;
  clip-path: polygon(0 100%, 50% 0, 100% 100%);
}
.env-to {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 9%;
  z-index: 1;
  font-size: calc(var(--u) * 9);
  font-weight: 700;
  color: var(--ink);
}
.env-flap {
  left: calc(var(--u) * 0.7);
  right: calc(var(--u) * 0.7);
  top: calc(var(--u) * 0.5);
  height: 58%;
  background: var(--hot);
  clip-path: polygon(0 0, 100% 0, 50% 100%);
  transform-origin: 50% 0;
  filter: drop-shadow(0 calc(var(--u) * 0.8) 0 var(--ink));
}
.env-seal {
  left: 50%;
  top: 50%;
  width: calc(var(--u) * 17);
  height: calc(var(--u) * 17);
  margin: calc(var(--u) * -6) 0 0 calc(var(--u) * -8.5);
  display: grid !important;
  place-items: center;
  border: calc(var(--u) * 0.8) solid var(--ink);
  border-radius: 50%;
  background: var(--sun);
  box-shadow: calc(var(--u) * 0.7) calc(var(--u) * 0.7) 0 var(--ink);
}
.env-seal svg {
  width: 62%;
  fill: var(--hot);
  stroke: var(--ink);
  stroke-width: 2.2;
  stroke-linejoin: round;
}
.env-hint {
  left: 0;
  right: 0;
  top: calc(100% + var(--u) * 7);
  font-family: "Shrikhand", "Cooper Black", Georgia, serif;
  font-size: calc(var(--u) * 7.5);
  color: #fff;
  text-shadow: 0.06em 0.06em 0 var(--ink), 0.12em 0.12em 0 var(--ink);
  rotate: 3deg;
}

/* sealed: card waits out of sight. opened: envelope drops away, card springs out */
.sealed .card {
  opacity: 0;
  pointer-events: none;
  transform: translateY(calc(var(--u) * 14)) scale(0.35) rotate(-8deg);
}
.opening .env-flap {
  transform: rotateX(178deg);
  transition: transform 0.55s cubic-bezier(0.5, 0, 0.3, 1);
}
.opening .env-seal {
  animation: seal-off 0.5s ease-in forwards;
}
.opening .env-hint {
  opacity: 0;
  transition: opacity 0.2s;
}
.opened .envelope {
  animation: env-away 0.7s cubic-bezier(0.5, 0, 0.8, 0.4) forwards;
  pointer-events: none;
}
.opened .card {
  animation: card-out 0.95s cubic-bezier(0.2, 1.3, 0.35, 1) both;
}

/* ---------- motion ---------- */

@media (prefers-reduced-motion: no-preference) {
  .sunburst {
    animation: spin 70s linear infinite;
  }
  .balloon {
    animation: rise var(--d) linear var(--delay) infinite;
  }
  .balloon svg {
    animation: sway calc(var(--d) / 4) ease-in-out infinite alternate;
  }
  .sealed:not(.opening) .envelope {
    animation: bob 2.4s ease-in-out infinite;
  }
  .sealed:not(.opening) .env-hint {
    animation: pulse 1.2s ease-in-out infinite alternate;
  }
  .sealed:not(.opening) .env-seal {
    animation: throb 1.2s ease-in-out infinite alternate;
  }
  .opened .hb-line i {
    animation:
      letter-in 0.7s cubic-bezier(0.2, 1.6, 0.4, 1) calc(0.45s + var(--i) * 55ms) both,
      jelly 2.6s ease-in-out calc(1.6s + var(--i) * 120ms) infinite;
  }
  .opened .ribbon {
    animation: stamp 0.6s cubic-bezier(0.2, 1.7, 0.4, 1) 1.15s both;
  }
  .opened .cake {
    animation: stamp 0.7s cubic-bezier(0.2, 1.5, 0.4, 1) 1.35s both;
  }
  .opened .words {
    animation: fade-up 0.8s ease-out 1.5s both;
  }
  .opened .signoff {
    animation: fade-up 0.8s ease-out 2.2s both;
  }
  .flames use {
    transform-box: fill-box;
    transform-origin: 50% 100%;
    animation: flicker 0.5s ease-in-out infinite alternate;
  }
  .flames g:nth-child(2) use { animation-duration: 0.42s; }
  .flames g:nth-child(3) use { animation-duration: 0.58s; }
  .spark {
    animation: twinkle 2.4s ease-in-out infinite;
  }
  .s2 { animation-delay: 0.8s; }
  .s3 { animation-delay: 1.5s; }
}

@keyframes spin { to { rotate: 360deg; } }
@keyframes rise {
  from { translate: -50% 110%; }
  to { translate: -50% calc(-100vh - 110%); }
}
@keyframes sway {
  from { transform: translateX(-14px) rotate(-6deg); }
  to { transform: translateX(14px) rotate(6deg); }
}
@keyframes pop {
  to { transform: scale(1.7); opacity: 0; }
}
@keyframes bob {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(calc(var(--u) * -2.5)); }
}
@keyframes pulse {
  from { opacity: 0.65; scale: 0.96; }
  to { opacity: 1; scale: 1.04; }
}
@keyframes throb {
  from { scale: 1; }
  to { scale: 1.12; }
}
@keyframes seal-off {
  to { transform: translateY(calc(var(--u) * 30)) rotate(200deg) scale(0.4); opacity: 0; }
}
@keyframes env-away {
  to { transform: translateY(calc(var(--u) * 120)) rotate(14deg); opacity: 0; }
}
@keyframes card-out {
  from { opacity: 0; transform: translateY(calc(var(--u) * 14)) scale(0.35) rotate(-8deg); }
  to { opacity: 1; transform: none; }
}
@keyframes letter-in {
  from { opacity: 0; transform: translateY(0.6em) scale(0.3) rotate(-25deg); }
  to { opacity: 1; transform: none; }
}
@keyframes jelly {
  0%, 100% { transform: none; }
  50% { transform: translateY(-0.06em) rotate(2.5deg); }
}
@keyframes stamp {
  from { opacity: 0; scale: 1.9; }
  to { opacity: 1; scale: 1; }
}
@keyframes fade-up {
  from { opacity: 0; transform: translateY(calc(var(--u) * 4)); }
  to { opacity: 1; transform: none; }
}
@keyframes flicker {
  from { transform: scale(0.9, 1.05) rotate(-4deg); }
  to { transform: scale(1.08, 0.92) rotate(4deg); }
}
@keyframes twinkle {
  0%, 100% { scale: 0.75; rotate: 0deg; }
  50% { scale: 1.15; rotate: 25deg; }
}
