/* ============================================================
   The sealed envelope — the first thing a guest sees.

   Everything is built from the couple's own photograph: the seal
   is cut out of it, and the envelope beneath was cleared so the
   seal can break away. The pieces share one box sized like the
   photo, so every clip and position below is a percentage of the
   photograph itself. Nothing is drawn on top to press — a tap
   anywhere around the seal opens it.
   ============================================================ */

html.is-locked,
html.is-locked body { overflow: hidden; }

.lock {
  position: fixed;
  inset: 0;
  z-index: 100;
  overflow: hidden;
  background: var(--white);
  touch-action: manipulation;
}

.lock[hidden] { display: none; }

/* The scene breathes very slowly, like light moving across a table. */
.lock__scene {
  position: absolute;
  inset: 0;
  animation: scene-in 1.8s var(--ease-out) both, scene-drift 16s ease-in-out 1.8s infinite alternate;
}

@keyframes scene-in {
  from { opacity: 0; transform: scale(1.07); filter: blur(6px); }
  to   { opacity: 1; transform: scale(1); filter: blur(0); }
}

@keyframes scene-drift {
  from { transform: scale(1); }
  to   { transform: scale(1.025); }
}

/* The photograph's box, scaled to cover the screen with the seal held at
   its centre (the seal sits at 49.465% × 57.489% of the photo). */
.env {
  --W: max(102vw, 95vh);
  position: absolute;
  width: var(--W);
  height: calc(var(--W) * 1.24955);
  left: calc(50% - var(--W) * 0.49465);
  top: calc(50% - var(--W) * 1.24955 * 0.57489);
  perspective: 2400px;
  perspective-origin: 50% 57%;
}

@supports (height: 100dvh) {
  .env { --W: max(102vw, 95dvh); }
}

.env__inside,
.env__body,
.env__flap,
.env__card,
.env__seal,
.env__dust { position: absolute; }

.env__inside,
.env__body,
.env__flap { inset: 0; }

.env__body,
.env__flap {
  background: url("../assets/lock/envelope.jpg") center / 100% 100% no-repeat;
}

/* Front of the envelope: everything below the flap's V. */
.env__body {
  z-index: 3;
  clip-path: polygon(0 29.9%, 49.465% 60.77%, 100% 31%, 100% 100%, 0 100%);
}

/* Inside the envelope, seen once the flap lifts: the same paper, deeper. */
.env__inside {
  z-index: 1;
  /* Reaches a little below the V, under the front, so the two cut edges
     never leave a hairline of the page showing between them. */
  clip-path: polygon(0 0, 100% 0, 100% 33%, 49.465% 63%, 0 32%);
  background: url("../assets/lock/envelope.jpg") center / 100% 100% no-repeat;
  filter: brightness(0.5) saturate(0.9);
}

/* The flap, hinged along the photo's top edge. */
.env__flap {
  z-index: 4;
  clip-path: polygon(0 0, 100% 0, 100% 31%, 49.465% 60.77%, 0 29.9%);
  transform-origin: 50% 0;
  backface-visibility: visible;
}

/* ---- The card inside --------------------------------------------------- */

.env__card {
  z-index: 2;
  left: 31%;
  width: 38%;
  top: 46%;
  height: 33%;
  display: grid;
  place-items: center;
  background: var(--white);
  box-shadow: 0 -18px 40px -20px rgb(0 0 0 / 0.45);
}

.env__card-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.6em;
  width: calc(100% - 1.6em);
  height: calc(100% - 1.6em);
  font-size: calc(var(--W) * 0.017);
  border: 1px solid var(--wine-40);
  outline: 1px solid var(--blush-60);
  outline-offset: -0.45em;
  text-align: center;
}

.env__card-names {
  font-family: var(--font-script);
  font-size: 3.4em;
  line-height: 1.1;
  color: var(--wine);
}

.env__card-names span { color: var(--blush); font-size: 0.6em; }

.env__card .bloom { --s: 1.8em; }

.env__card-date {
  font-size: 0.9em;
  font-weight: 600;
  letter-spacing: 0.4em;
  text-indent: 0.4em;
  color: var(--wine);
}

/* ---- The seal ---------------------------------------------------------- */

.env__seal {
  z-index: 5;
  left: 33.601%;
  top: 44.864%;
  width: 31.729%;
  height: 25.25%;
  animation: seal-breathe 3.8s ease-in-out 2s infinite;
}

@keyframes seal-breathe {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.018); }
}

.seal__face,
.seal__sheen {
  position: absolute;
  inset: 0;
  background: url("../assets/lock/seal.png") center / 100% 100% no-repeat;
}

/* A warm blush halo that blooms behind the seal as it lifts. */
.seal__glow {
  position: absolute;
  inset: -30%;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgb(255 160 122 / 0.55), rgb(255 160 122 / 0.18) 55%, transparent 72%);
  opacity: 0;
  transform: scale(0.6);
}

/* Light catching the gold now and then — the seal's own shape is the mask,
   so it glints on the wax and nowhere else. */
.seal__sheen {
  background: linear-gradient(115deg, transparent 38%, rgb(255 255 255 / 0.42) 50%, transparent 62%) 150% 0 / 260% 100% no-repeat;
  -webkit-mask: url("../assets/lock/seal.png") center / 100% 100% no-repeat;
  mask: url("../assets/lock/seal.png") center / 100% 100% no-repeat;
  mix-blend-mode: soft-light;
  animation: sheen 5.2s ease-in-out 2.4s infinite;
}

@keyframes sheen {
  0%       { background-position: 150% 0; }
  38%, 100% { background-position: -50% 0; }
}

/* Tiny roses the seal releases as it lifts — the same engraved bloom used
   across the invitation, in wine and blush. */
.env__dust {
  z-index: 6;
  left: 49.465%;
  top: 57.489%;
  width: 0;
  height: 0;
}

.petal-rose {
  position: absolute;
  width: var(--d);
  height: var(--d);
  margin: calc(var(--d) / -2);
  background-color: var(--c);
  -webkit-mask: url("../assets/flora/rose-head.svg") center / contain no-repeat;
  mask: url("../assets/flora/rose-head.svg") center / contain no-repeat;
  opacity: 0;
}

/* ---- The invisible touch area around the seal -------------------------- */

.lock__hit {
  position: absolute;
  left: 50%;
  top: 50%;
  z-index: 10;
  width: min(78vw, 70vh, 520px);
  aspect-ratio: 1;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  transform: translate(-50%, -50%);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.lock__hit:focus { outline: none; }
.lock__hit:focus-visible { box-shadow: 0 0 0 2px rgb(255 160 122 / 0.5); }

/* ============================================================
   The opening — each stage is a class lock.js adds in turn.
   ============================================================ */

.lock.is-opening .lock__scene { animation: none; }
.lock.is-opening .env__seal { animation: seal-press 260ms var(--ease-soft) both; }
.lock.is-opening .seal__sheen { animation: sheen-flash 700ms ease-out both; }

@keyframes seal-press {
  0%   { transform: scale(1); }
  60%  { transform: scale(0.93); }
  100% { transform: scale(0.95); }
}

@keyframes sheen-flash {
  0%   { background-position: 150% 0; opacity: 1; }
  100% { background-position: -50% 0; opacity: 0; }
}

/* 1 · The seal lifts away whole — rising towards the guest in a warm glow,
   turning a breath, then drifting up and fading like a kiss let go. */
.lock.is-lifted .env__seal { animation: seal-lift 1.6s cubic-bezier(0.45, 0, 0.2, 1) both; }
.lock.is-lifted .seal__glow { animation: glow-bloom 1.6s ease-out both; }

@keyframes seal-lift {
  0%   { transform: translateY(0) scale(0.95) rotate(0deg); opacity: 1; filter: drop-shadow(0 0 0 rgb(0 0 0 / 0)); }
  30%  { transform: translateY(-3%) scale(1.1) rotate(-3deg); opacity: 1; filter: drop-shadow(0 24px 30px rgb(0 0 0 / 0.45)); }
  60%  { transform: translateY(-22%) scale(1.16) rotate(4deg); opacity: 0.9; }
  100% { transform: translateY(-70%) scale(1.22) rotate(8deg); opacity: 0; filter: drop-shadow(0 40px 40px rgb(0 0 0 / 0)); }
}

@keyframes glow-bloom {
  0%   { opacity: 0; transform: scale(0.6); }
  35%  { opacity: 1; transform: scale(1); }
  100% { opacity: 0; transform: scale(1.5); }
}

.lock.is-lifted .petal-rose { animation: rose-float var(--t) cubic-bezier(0.2, 0.6, 0.3, 1) var(--delay) both; }

@keyframes rose-float {
  0%   { opacity: 0; transform: translate(0, 0) rotate(0deg) scale(0.4); }
  18%  { opacity: 1; }
  100% { opacity: 0; transform: translate(var(--x), var(--y)) rotate(var(--r)) scale(1); }
}

/* 2 · The flap lifts on its fold and swings up out of view. */
.lock.is-flap .env__flap { animation: flap-open 1.5s cubic-bezier(0.55, 0.05, 0.25, 1) both; }

@keyframes flap-open {
  0%   { transform: rotateX(0deg); filter: brightness(1); }
  48%  { filter: brightness(0.82); }
  52%  { filter: brightness(0.5); }
  100% { transform: rotateX(178deg); filter: brightness(0.62); }
}

/* 3 · The card rises out of the envelope. */
.env__card { transition: transform 1.3s var(--ease-out); }
.lock.is-rise .env__card { transform: translateY(-62%); }

/* 4 · The envelope sinks away, leaving the card on the paper. */
.env__body,
.env__inside,
.env__flap { transition: opacity 900ms ease, transform 1.1s var(--ease-soft); }
.lock.is-lift .env__body,
.lock.is-lift .env__inside { opacity: 0; transform: translateY(14%); }
.lock.is-lift .env__flap { opacity: 0; }

/* 5 · The card comes forward and opens into the whole invitation. */
.lock.is-cover .env__card {
  z-index: 8;
  transform: translate(var(--dx), var(--dy)) scale(var(--s));
  box-shadow: none;
  transition: transform 1.25s cubic-bezier(0.7, 0, 0.2, 1), box-shadow 600ms ease;
}

.lock.is-cover .env__card-inner { opacity: 0; transition: opacity 700ms ease 250ms; }

.lock.is-done { opacity: 0; transition: opacity 700ms ease; pointer-events: none; }

@media (prefers-reduced-motion: reduce) {
  .lock__scene,
  .env__seal,
  .seal__sheen { animation: none !important; }
}
