/* Stephanie & Ryan — the RSVP page opens out of an envelope.
 *
 * On a phone or tablet, finding your name opens your invitation the way
 * the printed one opens: an envelope folds away, the photograph is
 * behind it with "you're invited" arriving out of a blur, and the RSVP
 * itself is a scroll further down.
 *
 * Phones and tablets only for now — the desktop page is unchanged.
 *
 * The fold is js/envelope.js; envelope.css carries the shadows it casts.
 */

@import url('envelope.css');

/* Hidden until the script decides to play it, and hidden altogether on
   desktop. Nothing here may leave the page covered on its own. */
.rsvp-open,
.rsvp-open-rough,
.rsvp-open-scroll,
.rsvp-env {
  display: none;
}

@media screen and (max-width: 991px) {

  /* ---- The photograph the envelope opens onto --------------------- */

  .rsvp-opening .rsvp-open {
    display: block;
    position: relative;
    width: 100%;
    /* One screenful, and the screen is the one the reader can see.

       vh is the height with the browser's bars hidden, which makes the
       panel taller than what's showing and pushes everything in it
       down. svh is the height with them showing, and is right wherever
       it is understood — but Safari's newer bars float over the page
       instead of making room beside it, and svh there can come back as
       the whole screen. So the last word goes to js/rsvp/rsvp.js, which
       sets --rsvp-panel to what the browser says it is showing. The
       invitation page had exactly this, and this is the same fix. */
    height: 100vh;
    height: 100svh;
    height: var(--rsvp-panel, 100svh);
    background-color: var(--rsvp-sage, #929b81);
    background-image: url('../images/email-img.webp?v=822b5608');
    background-position: 50% 0;
    background-repeat: no-repeat;
    background-size: cover;
    /* The lettering runs off the right edge on a phone (below), and
       what leaves the picture has to be cut off by it — otherwise the
       page can be dragged sideways to look at nothing. */
    overflow: hidden;
  }

  /* Right of the picture and centred down it, as on the invitation
     page. A percentage height so it scales with the phone rather than
     overwhelming a small one. */
  .rsvp-open-art {
    position: absolute;
    top: 50%;
    right: 4%;
    height: 60%;
    width: auto;
    transform: translateY(-50%);
  }

  /* The torn green edge the photograph gives way to, as on the
     invitation page: the same artwork, the same 60px strip pulled up
     over the bottom of the picture. The page behind is already this
     green, so the tear reads as the paper itself. */
  .rsvp-opening .rsvp-open-rough {
    display: block;
    position: relative;
    z-index: 2;
    width: 100%;
    height: 60px;
    margin-top: -43px;
    background-image: url('../images/green-background.svg?v=df34d2e6');
    background-position: 50% 0;
    background-repeat: no-repeat;
    background-size: 120%;
  }

  /* The card sits just under the torn edge rather than floating in the
     middle of what's left of the screen. .rsvp-main is a flex container
     that centres the card vertically, which is right when the card is
     the whole page and wrong when a photograph is above it: the space
     above the card came out three times the space at its sides. Anchored
     to the top, the gap is the padding, and the padding matches the
     sides. */
  .rsvp-opening .rsvp-main {
    align-items: flex-start;
    padding-top: 16px;
    /* Up into the torn strip. Only its top edge is ragged; the rest is
       solid green continuing the page, so the card can sit in it and
       what you see is the gap between the tear itself and the border —
       near enough the 12px at the card's sides.

       Above the strip, or the strip's green would paint over the card's
       top border. The card has no fill of its own, so the tear still
       shows through it. */
    position: relative;
    z-index: 3;
    margin-top: -40px;
  }

  /* ---- The envelope ----------------------------------------------- */

  .rsvp-opening .rsvp-env {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 60;
    /* The flaps fold in 3D; without this they'd merely squash. */
    perspective: 1400px;
    perspective-origin: 50% 50%;
  }

  .rsvp-env-flap {
    position: absolute;
    left: 0;
    right: 0;
    background-repeat: no-repeat;
    background-size: cover;
    /* Past 90 degrees a flap is edge-on and then facing away; hiding the
       back is what makes it read as opening rather than flipping over to
       show a mirrored copy of itself. */
    backface-visibility: hidden;
    -webkit-backface-visibility: hidden;
    will-change: transform;
  }

  .rsvp-env-flap--top {
    top: 0;
    height: 60%;
    background-image: url('../images/envelop-top.webp?v=3fb80b51');
    background-position: 50% 0;
    transform-origin: 50% 0;
  }

  .rsvp-env-flap--bottom {
    bottom: 0;
    /* Overlapping the top flap, so the join is covered from both sides
       and the pair reads as one closed envelope. */
    height: 60%;
    z-index: -1;
    background-image: url('../images/envelop-bottom.webp?v=4a25956c');
    background-position: 50% 100%;
    transform-origin: 50% 100%;
  }

  /* ---- The lettering arriving ------------------------------------- */

  .sr-invite-armed .rsvp-open-art {
    opacity: 0;
  }

  .sr-invite-ready .rsvp-open-art {
    animation: rsvp-open-arrive 1.9s cubic-bezier(0.25, 0.5, 0.25, 1) both;
  }

  /* ---- The arrow that says there's more ---------------------------

     A picture that fills the screen gives no sign anything is under it.
     A chevron at the foot of it does, quietly: cream on the photograph,
     drifting down and back like something being beckoned.

     It fades out as the page moves, driven by the scroll itself rather
     than by a listener — by the time it's a few finger-widths down, its
     work is done and it shouldn't be sitting over the picture. Where
     scroll-driven animation isn't supported it simply stays, which is
     no worse than not having it. */

  .rsvp-opening .rsvp-open-scroll {
    display: block;
    position: absolute;
    /* Above the torn edge, which rides 43px up over the foot of the
       picture: at 34px the arrow was bouncing down behind it. Clear of
       it in both senses — higher up, and in front. */
    z-index: 3;
    left: 50%;
    bottom: 64px;
    width: 22px;
    height: 22px;
    margin-left: -11px;
    opacity: 0.92;
  }

  .rsvp-open-scroll::after {
    content: '';
    position: absolute;
    inset: 0 0 auto 50%;
    width: 15px;
    height: 15px;
    margin-left: -7.5px;
    border-right: 1.5px solid var(--rsvp-ivory, #ebeae0);
    border-bottom: 1.5px solid var(--rsvp-ivory, #ebeae0);
    transform: rotate(45deg);
    /* The foot of the picture is water, and cream on a bright wave is
       nearly nothing. A shadow the width of the stroke is enough to
       hold it without turning it into a graphic. */
    filter: drop-shadow(0 1px 4px rgba(47, 50, 42, 0.45));
  }

  @media (prefers-reduced-motion: no-preference) {
    .rsvp-opening .rsvp-open-scroll {
      animation: rsvp-open-beckon 2.4s ease-in-out infinite;
    }

    @supports (animation-timeline: scroll()) {
      .rsvp-opening .rsvp-open-scroll::after {
        animation: rsvp-open-scroll-away linear both;
        animation-timeline: scroll(root block);
        animation-range: 0 140px;
      }
    }
  }
}

/* Off the right edge, as on the invitation page: the words are written
   down the page, so what leaves the screen is the width of the hand
   that wrote them and not anything to be read. The invitation bleeds
   more of it the narrower the screen gets, and these are its figures —
   a negative margin from its 4% inset on a large phone, and the whole
   distance from the edge on a small one, which is where it stops being
   positioned that way. */
@media screen and (max-width: 767px) {
  .rsvp-open-art {
    margin-right: -112px;
  }
}

@media screen and (max-width: 479px) {
  .rsvp-opening .rsvp-open-rough {
    margin-top: -40px;
  }

  .rsvp-open-art {
    right: -50px;
    margin-right: 0;
  }
}

@keyframes rsvp-open-beckon {
  0%, 100% { transform: translateY(0); opacity: 0.92; }
  50%      { transform: translateY(9px); opacity: 0.55; }
}

@keyframes rsvp-open-scroll-away {
  from { opacity: 1; }
  to   { opacity: 0; }
}

@keyframes rsvp-open-arrive {
  from { opacity: 0; filter: blur(9px); scale: 1.03; }
  60%  { opacity: 1; }
  to   { opacity: 1; filter: blur(0); scale: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .sr-invite-ready .rsvp-open-art,
  .sr-invite-armed .rsvp-open-art {
    animation: none;
    opacity: 1;
  }
}

/* =====================================================================
   The scene moves as you scroll
   =====================================================================

   The same gestures the invitation page makes, on the page a guest
   actually arrives at: the photograph slides behind the words, the words
   leave a little faster than the page does, and the card comes up into
   place rather than simply being there.

   All of it hangs off one number. Scroll drives --rsvp-park from 0 to 1
   across the height of the photograph, and each piece multiplies it by
   its own distance, so the three move together without being
   choreographed. Where scroll-driven animation isn't supported nothing
   moves, which is the design as it stands today.
   ------------------------------------------------------------------ */

@property --rsvp-park {
  syntax: '<number>';
  initial-value: 0;
  inherits: true;
}

@keyframes rsvp-park {
  from { --rsvp-park: 0; }
  to   { --rsvp-park: 1; }
}

/* Everything in the card, arriving. Each piece is timed against its own
   position rather than against the page, so they settle one after
   another simply because that is the order they cross the screen in —
   the logo, then the heading, then each line, then the fields, then the
   buttons. Nothing is choreographed and nothing needs to be renumbered
   when a question is added.

   Each is done with by the time it has properly arrived, which is well
   before anyone reaches it: a field that moves while it is being filled
   in is worse than a field that never moved. */
@keyframes rsvp-rise {
  from { translate: 0 var(--rsvp-rise, 18px); opacity: 0.001; }
  to   { translate: 0 0; opacity: 1; }
}

@media screen and (max-width: 991px) {
  @media (prefers-reduced-motion: no-preference) {
    @supports (animation-timeline: scroll()) {
      .rsvp-opening .rsvp-open {
        animation: rsvp-park linear both;
        animation-timeline: scroll(root block);
        /* The height of the photograph, so the movement lasts exactly as
           long as there is photograph to watch. */
        animation-range: 0 100vh;
        animation-range: 0 100svh;
      }

      /* The photograph. A tenth of room at each end, a tenth of travel,
         and one size throughout — see the invitation page's stylesheet
         for why the room and the travel have to be the same number, and
         what the room costs. */
      .rsvp-opening .rsvp-open::before {
        content: '';
        position: absolute;
        left: 0;
        right: 0;
        /* Hung from the top with the slack below it, as the design hangs
           it and as the invitation page does — see that page's
           stylesheet for what centring it cost. */
        top: 0;
        bottom: -20%;
        z-index: 0;
        background: inherit;
        background-size: cover;
        background-position: 50% 0;
        translate: 0 calc(var(--rsvp-park, 0) * -0.1 * var(--rsvp-panel, 100svh));
      }

      /* The lettering, leaving faster than the page — which is what
         reads as depth. translate only: the centring is a transform and
         the arrival animates scale, and all three compose. */
      .rsvp-opening .rsvp-open-art {
        translate: 0 calc(var(--rsvp-park, 0) * -140px);
      }
    }

    @supports (animation-timeline: view()) {
      /* The contents, not the box: the logo, the heading, each line of
         text, each question with its fields, and the row of buttons.

         The list is long because it reaches past the containers. A step
         holds a form, the form holds the groups of questions — each
         marked .rsvp-group — and every one of those is only a box around
         the things that should be moving, so each is skipped in favour
         of what is inside it. Classes rather than ids for the skipping,
         so that one plain selector here doesn't quietly outweigh the
         rules below it. A
         thing is animated once, by exactly one of these selectors:
         animating a box and its contents both would move them twice as
         far as either was asked to go. */
      .rsvp-opening .rsvp-shell > *:not(.rsvp-step),
      .rsvp-opening .rsvp-step > *:not(form):not(.rsvp-group),
      .rsvp-opening .rsvp-step form > *:not(.rsvp-group),
      .rsvp-opening .rsvp-group > * {
        animation: rsvp-rise cubic-bezier(0.4, 0, 0.2, 1) both;
        animation-timeline: view();
        animation-range: cover 0% cover 220px;
      }

      /* The last thing on the page can't be timed against its own
         journey up the screen, because that journey is cut short: there
         is no scrolling left underneath it, so it would arrive a little
         faded and a little low and stay that way. The row of buttons at
         the foot of every step is timed against the end of the page
         instead, and lands exactly as the scrolling runs out. */
      .rsvp-opening .rsvp-step form > .rsvp-actions,
      .rsvp-opening .rsvp-step > .rsvp-actions,
      .rsvp-opening .rsvp-group > .rsvp-actions {
        animation-timeline: scroll(root block);
        /* Finished a little before the very bottom: the last pixel of
           scrolling is one nobody reliably reaches, and a row of buttons
           should be solid by the time it is under the thumb. */
        animation-range: calc(100% - 260px) calc(100% - 40px);
      }

      /* Bigger things travel further, the same reading the home page
         uses: nearer things move more. */
      .rsvp-opening .rsvp-invite-logo { --rsvp-rise: 26px; }
      .rsvp-opening .rsvp-display     { --rsvp-rise: 24px; }
      .rsvp-opening .rsvp-greeting,
      .rsvp-opening .rsvp-section-title { --rsvp-rise: 22px; }
      .rsvp-opening .rsvp-actions     { --rsvp-rise: 14px; }
    }
  }
}
