/* Regalo (screen28): message crossfade, final photo, gift box, regalos photos. */

/* screen28: single closing photo, same polaroid look as .carousel-photo
   (white border + shadow) but sized as one big hero image instead of a
   fanned set - no width/height/object-fit so its own aspect ratio decides
   the box, same reasoning as .carousel-photo. */
.final-photo {
  border: 6px solid #ffffff;
  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.3);
  border-radius: 4px;
  max-width: 60vw;
  /* Was 55vh, briefly dropped to 40vh to fix an overflow on desktop (the
     message + default 2.5rem gap were pushing the photo's top edge above
     the visible viewport) - #screen28 .message got its own smaller
     font-size instead, freeing up enough room to bring this back up
     without reintroducing that overflow. */
  max-height: 48vh;
  cursor: pointer;
  transition: opacity 0.6s ease;
}

.final-photo--hidden {
  opacity: 0;
  cursor: default;
  pointer-events: none;
}

@media (max-width: 600px) {
  .final-photo {
    max-width: 80vw;
    max-height: 32vh;
  }
}

/* screen28's gift box: flat, single face only, no 3D/isometric angle - that
   was tried twice (real 3D-CSS faces, then a skewed-rectangle isometric
   version) and explicitly rejected as too fragile to align by hand. See
   docs/superpowers/specs/2026-09-21-screen28-gift-box-design.md. Starts
   translated below the screen's own bottom edge; .gift-box--visible (added
   by script.js) is what actually slides it up. */
/* .gift-box itself is now just a positioning shell (size + slide-up
   transform) with no visuals of its own - the cream background/shadow
   moved onto .gift-box__shake below. Keeping them on .gift-box meant only
   the ribbon (inside .gift-box__shake) actually jittered on shake, while
   the box's own background sat there motionless underneath it (confirmed
   from a recording - looked like the ribbon was shaking loose from a
   static box). Now the whole visible box shakes as one piece. */
.gift-box {
  position: absolute;
  left: 50%;
  bottom: 6vh;
  width: 44vw;
  max-width: 220px;
  height: 30vw;
  max-height: 150px;
  transform: translate(-50%, 160%);
  transition: transform 0.9s ease;
}

.gift-box--visible {
  transform: translate(-50%, 0);
}

/* Carries the box's actual visuals (background/shadow/radius) as well as
   the shake jitter (see .shake-jitter below) - kept separate from .gift-box
   itself so the shake's transform doesn't fight/override .gift-box's own
   slide-up transform: translate(-50%, ...). inset:0 keeps it the exact
   same size as .gift-box, so .gift-box__ribbon's own percentages still
   resolve the same way through this extra layer. */
.gift-box__shake {
  position: absolute;
  inset: 0;
  background: #f2ede4;
  border-radius: 4px;
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.3);
}

.gift-box__ribbon {
  position: absolute;
  top: 0;
  left: 50%;
  width: 16%;
  height: 100%;
  background: #b3352b;
  transform: translateX(-50%);
}

/* Lid is split into two separately-transitioning wrappers on purpose - see
   the design doc's "position vs. spin" note. Combining a translate and a
   rotate into one hand-written transform value means the rotation also
   rotates the translation offset, not just the lid's own orientation; that
   bug ate most of a whole brainstorming session on this feature. Keeping
   position (.gift-lid-position, left/top) and spin (.gift-lid-spin,
   rotate) on two different elements avoids it entirely.

   left/top and transition-duration are NOT fixed here on purpose - the
   lid's journey has multiple beats at different speeds (fly in, pause,
   anticipate, drop - see the screen28NextBtn click handler in script.js),
   so script.js sets `transition` inline before every position change
   instead of relying on one fixed value here. The 1s below is just a
   sensible fallback, not load-bearing. left/top are also always set
   inline, computed from .gift-box's own real on-screen position each
   time - a guessed static landing spot (originally top: 42%) had no
   actual relationship to the box's real (bottom-anchored) position, and
   landed nowhere near it on a real phone. */
.gift-lid-position {
  position: absolute;
  transition: left 1s ease, top 1s ease;
}

.gift-lid-spin {
  transform: rotate(180deg);
  transition: transform 1s ease;
}

.gift-lid-spin--upright {
  transform: rotate(0deg);
}

.gift-lid {
  position: relative;
  width: 48vw;
  max-width: 236px;
  height: 8vw;
  max-height: 34px;
  background: #ede6d8;
  border-radius: 4px;
  box-shadow: 0 3px 6px rgba(0, 0, 0, 0.3);
}

.gift-lid__ribbon {
  position: absolute;
  top: 0;
  left: 50%;
  width: 15%;
  height: 100%;
  background: #b3352b;
  transform: translateX(-50%);
}

/* A flat bow-tie sitting where the ribbon crosses the lid's top edge,
   matching a reference photo of a real bow-tie ribbon (two wing loops +
   a knot + two outward-sweeping tails) rather than the rounder "pull-bow"
   pom-pom tried first (that one read as a flower once built). All solid
   color (no gradients), sized in vw/max-width like the rest of this
   box/lid. Every piece below is sized/positioned as a percentage of
   .gift-lid__bow's own box, tuned by eye against a 90x76px reference
   version - see docs/superpowers/specs/2026-09-21-screen28-gift-box-design.md. */
.gift-lid__bow {
  position: absolute;
  top: 0;
  left: 50%;
  width: 18vw;
  max-width: 86px;
  height: 15vw;
  max-height: 72px;
  transform: translate(-50%, -66%);
}

.gift-lid__bow-wing {
  position: absolute;
  width: 51%;
  height: 79%;
  background: #b3352b;
}

/* Asymmetric border-radius pinches one corner to a point (the corner
   touching the knot) while the other three stay rounded - a teardrop/loop
   silhouette instead of a plain circle, which is what made the earlier
   pom-pom version read as a flower. transform-origin sits at that same
   pinched corner so rotating the wing outward doesn't shift its anchor
   point away from the knot. */
.gift-lid__bow-wing--left {
  top: 0;
  left: 0;
  border-radius: 50% 50% 50% 6%;
  transform-origin: 100% 100%;
  transform: rotate(-18deg);
}

.gift-lid__bow-wing--right {
  top: 0;
  right: 0;
  border-radius: 50% 50% 6% 50%;
  transform-origin: 0% 100%;
  transform: rotate(18deg);
}

.gift-lid__bow-knot {
  position: absolute;
  top: 68%;
  left: 50%;
  width: 22%;
  height: 26%;
  background: #922b22;
  border-radius: 3px;
  transform: translate(-50%, -50%);
  z-index: 2;
}

/* Same pinch-corner trick as the wings, but rotated closer to horizontal
   and anchored so the sharp corner sits at the knot - sweeps outward and
   slightly down to a rounded tip, instead of hanging straight down. */
.gift-lid__bow-tail {
  position: absolute;
  top: 66%;
  width: 69%;
  height: 32%;
  background: #b3352b;
}

.gift-lid__bow-tail--left {
  right: 59%;
  border-radius: 50% 0 0 40%;
  transform-origin: 100% 30%;
  transform: rotate(22deg);
}

.gift-lid__bow-tail--right {
  left: 59%;
  border-radius: 0 50% 40% 0;
  transform-origin: 0% 30%;
  transform: rotate(-22deg);
}

/* Reuses the existing wrong-shake keyframes (see the quiz's own
   .quiz-option.wrong above) for the gift's little jitter after the photo
   lands inside and again on every tap. Applied to .gift-box__shake and
   #screen28LidPosition together (see shakeGift() in script.js) so the box
   and lid visibly move as one rigid object despite being positioned two
   different ways (transform vs. left/top). */
.shake-jitter {
  animation: wrong-shake 0.5s ease;
}

/* Added once the tap-to-open phase starts (script.js), so the box/lid
   only look tappable once tapping them actually does something. */
.gift-box--tappable,
.gift-lid-position--tappable {
  cursor: pointer;
}

/* The 10th-tap finale's scattered regalos/ photos - built lazily by
   finishGiftReveal() in script.js, not present in the markup at page
   load. Just a positioning canvas the same size as #screen28; each photo
   inside handles its own placement via left/top (see script.js for why
   left/top rather than a translate offset - same reasoning as the lid). */
/* screen28's own confetti canvas, placed before .gift-box in the markup so
   it paints BEHIND the box - the burst starts just inside the box's top
   edge, so the flowers look like they shoot up out of the opening instead
   of over the top of it (the shared full-screen canvas partyPoppers() uses
   always sits on top of everything). Absolute, not in the flex flow. */
.gift-confetti {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

.regalos-photos {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

/* Same polaroid look as .carousel-photo elsewhere in this file (white
   border, drop shadow), starting tiny/invisible at the gift box's own
   position and flying out to a random scattered spot - see
   finishGiftReveal() in script.js. pointer-events: auto (the container
   above turns it off) since each photo re-opens the shared lightbox on
   tap, same as every other photo in this site. */
.regalos-photo {
  position: absolute;
  border: 6px solid #ffffff;
  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.3);
  border-radius: 4px;
  /* width is set inline per photo from REGALOS_LAYOUT (script.js) to match
     the mockup; height follows each photo's own aspect ratio. */
  height: auto;
  cursor: pointer;
  pointer-events: auto;
  opacity: 0;
}
