/* ============================================================
   The envelope on the landing page.

   Drawn from the back -- the side with the flaps, the side that opens. Five
   sheets of paper stacked in this order, nearest last:

     base            the envelope body
     letter          the card inside; slides up out of the pocket
     side flaps      two triangles folded in from the left and right
     bottom flap     folded up over the sides, closing the pocket
     top flap        folded down over everything; this is what lifts
     seal            pressed where the top flap's point lands

   Every colour is derived from the page's own tokens (a touch of --ink mixed
   into --bg), so the paper sits in the same palette as the site and follows it
   if the palette ever changes. Nothing here is an image.

   The whole opening is driven by three classes on <body>, added by envelope.js
   in sequence:  .is-opening (seal lifts, flap swings)  ->  .is-out (the card
   rises out)  ->  .is-veiled (the page's hero fades in over the top).
   ============================================================ */

.gate-body {
  margin: 0;
  min-height: 100svh;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-body);
  overflow-x: hidden;
  overflow-y: auto;
}

.gate {
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: clamp(26px, 4vh, 44px);
  padding: 24px 20px 40px;
  box-sizing: border-box;
}

/* ---------------- paper ---------------- */

/* Cream stationery, drawn flat: the site is ink on cream with hairline rules
   and small diamonds, so the envelope is the same -- one warm paper tone, folds
   marked by hairlines, one soft shadow on the page and nothing glossy. */
:root {
  --paper:       #F1ECE1;   /* the envelope */
  --paper-light: #F6F2E9;   /* the flaps nearest the viewer */
  --paper-inner: #E7E0D2;   /* the inside: seen through the pocket, and the turned flap */
  --paper-fold:  #DBD3C4;   /* hairline along every fold */
}

/* ---------------- the envelope ---------------- */

.env-wrap {
  /* the width has to live here: the pieces inside are absolutely positioned,
     so without an explicit size the envelope collapses to nothing */
  width: min(460px, 84vw);
  /* the open flap stands above the envelope and the card rises out of it, so
     the envelope sits low enough for both to stay on screen */
  margin-top: clamp(48px, 12vh, 120px);
  /* above the form: on opening it glides down through the space the form is
     fading out of, and should pass over that text, not under it */
  position: relative;
  z-index: 2;
}

.env {
  position: relative;
  width: 100%;
  aspect-ratio: 1.45;
  /* the flap swings in depth; everything else stays flat so paint order
     follows z-index */
  perspective: 1200px;
  perspective-origin: 50% 0;
  animation: env-settle 1.1s cubic-bezier(0.22, 1, 0.36, 1) both;
  /* the one shadow: the envelope resting on the page */
  filter: drop-shadow(0 14px 22px color-mix(in oklab, var(--ink) 13%, transparent));
}

@media (prefers-reduced-motion: no-preference) {
  .env-wrap { animation: env-float 7s ease-in-out 1.2s infinite; }
}
@keyframes env-float {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-7px); }
}
@keyframes env-settle {
  from { opacity: 0; transform: translateY(22px) scale(0.97); }
  to   { opacity: 1; transform: none; }
}

.env > * { position: absolute; inset: 0; }

.env-base {
  z-index: 1;
  background: var(--paper-inner);
  border-radius: 4px;
}

/* The flaps. One SVG for the pocket (both sides and the bottom), one for the
   top flap so it can hinge on its own. The viewBox is 145x100 and the envelope
   is 1.45:1, so preserveAspectRatio="none" is a plain fit; the strokes are the
   folds, held at 1px by non-scaling-stroke whatever the size. */
.env-pocket, .env-top svg {
  display: block;
  width: 100%; height: 100%;
  overflow: visible;
}
.env-pocket { z-index: 3; }
.p-side, .p-bottom, .p-top {
  stroke: var(--paper-fold);
  stroke-width: 1;
  stroke-linejoin: round;
}
.p-side   { fill: var(--paper); }
.p-bottom { fill: var(--paper-light); }   /* nearest the viewer, lightest */
.p-top    { fill: var(--paper); transition: fill 0.3s ease 0.55s; }

/* Top flap. Its point lands just below centre, under the seal. Hinged along
   the top edge; opening swings it up and over the back of the envelope, and
   its fill turns to the inside of the paper as it does. */
.env-top {
  z-index: 5;
  transform-origin: 50% 0;
  transform: rotateX(0deg);
  transition:
    transform 1s cubic-bezier(0.55, 0.05, 0.25, 1) 0.12s,
    z-index 0s linear 0.6s;
}

/* The seal: the site's monogram in wax. */
.env-seal {
  z-index: 6;
  inset: auto;
  left: 50%;
  top: 58%;
  width: clamp(58px, 16%, 76px);
  aspect-ratio: 1;
  transform: translate(-50%, -50%);
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--accent);
  box-shadow:
    0 1px 2px color-mix(in oklab, var(--ink) 25%, transparent),
    inset 0 0 0 2px var(--accent),
    inset 0 0 0 3px color-mix(in oklab, var(--paper) 70%, transparent);
  transition: opacity 0.3s ease, transform 0.45s cubic-bezier(0.5, -0.3, 0.7, 1.3);
}
/* the nav's monogram, pressed rather than printed */
.env-seal .monogram {
  font-family: var(--font-script);
  font-size: clamp(13px, 2.8vw, 16px);
  line-height: 1;
  white-space: nowrap;
  color: var(--bg);
  padding-bottom: 3px;
}
.env-seal .monogram .zfix { font-family: 'Pinyon Script', cursive; font-size: 1.12em; margin-left: -0.2em; }

/* ---------------- the letter ---------------- */

.env-letter {
  z-index: 2;
  inset: 5% 4% 3%;
  background: var(--bg);
  border: 1px solid var(--rule);
  border-radius: 3px;
  text-align: center;
  box-sizing: border-box;
  box-shadow: 0 1px 2px color-mix(in oklab, var(--ink) 10%, transparent);
  transform: translateY(0) scale(1);
  transition:
    transform 1.05s cubic-bezier(0.22, 1, 0.36, 1),
    box-shadow 1.05s ease,
    z-index 0s linear 0.45s;
}
/* The face is the hero lockup at PAGE size, laid out under the same width
   limit the hero has (the viewport less its padding), so line breaks match
   the real hero too. It is then scaled down to fit the card. --k is set by
   envelope.js from the measured sizes. */
.letter-face {
  position: absolute;
  left: 50%; top: 50%;
  width: max-content;
  max-width: calc(100vw - 48px);
  transform: translate(-50%, -50%) scale(var(--k, 0.5));
  transform-origin: center;
}

/* ---------------- the prompt ---------------- */

.gate-panel {
  width: min(460px, 100%);
  text-align: center;
  /* backwards, not both: a fill that outlives the animation pins opacity at 1,
     and the fade-out on opening then snaps instead of playing */
  animation: env-settle 1.1s cubic-bezier(0.22, 1, 0.36, 1) 0.18s backwards;
  transition: opacity 0.4s ease, transform 0.5s ease;
}
.gate-panel .eyebrow { margin: 0; }
/* the hero's lockup again, at a size that suits a form rather than a page */
.gate-names { font-size: clamp(40px, 7.5vw, 62px); margin: 2px 0 0; line-height: 1.12; }
.gate-meta { font-size: 12.5px; letter-spacing: 0.24em; gap: 14px; margin: 4px 0 30px; }

.gate-field { display: grid; gap: 8px; text-align: left; margin-bottom: 22px; }
.gate-field label {
  font-family: var(--font-serif);
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
.gate-field input {
  font-family: var(--font-body);
  font-size: 18px;
  color: var(--ink);
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--rule);
  padding: 9px 2px;
  outline: none;
  width: 100%;
  box-sizing: border-box;
  transition: border-color 0.2s ease;
}
.gate-field input:focus { border-bottom-color: var(--accent); }
.gate-submit { width: 100%; }
/* checking the list takes a moment; a half-faded slab reads as broken rather
   than busy, so the button only softens */
.gate-submit[disabled] { opacity: 0.78; cursor: progress; }

.gate-msg {
  font-size: 14px;
  color: var(--ink-soft);
  margin: 18px 0 0;
  min-height: 2.6em;
  line-height: 1.5;
}
.gate-msg.is-error { color: var(--ink); }
.gate-help {
  font-size: 14px;
  line-height: 1.6;
  color: var(--ink-soft);
  margin: 4px 0 0;
  padding-top: 14px;
  border-top: 1px solid var(--rule);
}
.gate-help a { color: var(--ink); }

/* A wrong name nudges rather than scolds. The shake is added alongside the
   entrance animation, not in place of it: swapping env-settle out and back in
   restarts it, and the envelope would blink out and fade in again from
   nothing after every miss. It moves `translate`, so the two never contend
   for the same property. */
@keyframes gate-shake {
  0%, 100% { translate: 0; }
  20% { translate: -7px; }
  40% { translate: 6px; }
  60% { translate: -4px; }
  80% { translate: 2px; }
}
.is-wrong .env {
  animation:
    env-settle 1.1s cubic-bezier(0.22, 1, 0.36, 1) both,
    gate-shake 0.42s ease;
}

/* ---------------- opening ---------------- */

/* Beat 1: the seal lifts away and the flap swings up and over. */
.is-opening .env-seal {
  opacity: 0;
  transform: translate(-50%, -120%) rotate(-12deg) scale(0.8);
}
.is-opening .env-top {
  transform: rotateX(-180deg);
  z-index: 0;
}
.is-opening .p-top { fill: var(--paper-inner); }
/* animation: none covers a guest quick enough to submit before the panel has
   finished settling in */
.is-opening .gate-panel {
  animation: none;
  opacity: 0;
  transform: translateY(14px);
  pointer-events: none;
}
/* The envelope glides to the middle of the screen as the form fades from
   under it, so the card has room to rise its full height on any screen.
   envelope.js measures --sink. It rides on `translate`, a separate property
   from the idle float's `transform`, so the float can carry on underneath
   instead of being cut off mid-bob, which jolted the envelope by up to 7px. */
.is-opening .env-wrap {
  translate: 0 var(--sink, 0px);
  transition: translate 0.95s cubic-bezier(0.22, 1, 0.36, 1);
}

/* Beat 2: the card slides up out of the pocket. It stays behind the flaps the
   whole way -- they are what it is sliding out from under -- and only once it
   has cleared the top edge does it come forward (beat 3). The keyframes run
   the two together: straight up first, then forward and down a little, like
   a hand drawing it out and holding it up. */
.is-out .env-letter {
  animation: letter-out 1.6s cubic-bezier(0.4, 0, 0.2, 1) both;
  transition: none;
}
@keyframes letter-out {
  0%   { transform: translateY(0)      scale(1);    z-index: 2; box-shadow: 0 1px 2px color-mix(in oklab, var(--ink) 10%, transparent); }
  55%  { transform: translateY(-104%) scale(1);    z-index: 2; box-shadow: 0 1px 2px color-mix(in oklab, var(--ink) 10%, transparent); }
  56%  { z-index: 7; }
  100% { transform: translateY(-34%)  scale(1.08); z-index: 7; box-shadow: 0 24px 40px -18px color-mix(in oklab, var(--ink) 30%, transparent); }
}

/* Beat 3: the lockup lands. envelope.js hides the card's face, shows this
   hero's lockup already transformed to sit exactly over it, then releases the
   transform so it travels to the hero's true position while the envelope
   fades away. index.html then paints its hero in that same place. */
.gate-veil {
  position: fixed;
  inset: 0;
  z-index: 20;
  /* no width: 100vw -- that counts a desktop scrollbar's gutter, and the
     hero it stands in for is centred in the space beside it */
  pointer-events: none;
  overflow: hidden;
}
.gate-veil .hero-inner { opacity: 0; }
.is-landing .gate-veil .hero-inner {
  opacity: 1;
  transition: transform 0.95s cubic-bezier(0.4, 0, 0.2, 1);
}
.is-landing .letter-face { visibility: hidden; }
.is-landing .env-letter {
  transition: opacity 0.5s ease 0.15s;
  opacity: 0;
}
.is-landing .env-base, .is-landing .env-pocket, .is-landing .env-top, .is-landing .env-seal {
  transition: opacity 0.6s ease 0.1s;
  opacity: 0;
}
/* the hero's collage, kept only for its height */
.veil-spacer { visibility: hidden; }
.veil-spacer image-slot { display: block; }

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

@media (prefers-reduced-motion: reduce) {
  .env, .gate-panel { animation: none; }
  .env-top, .env-letter, .env-seal, .gate-panel, .gate-veil .hero-inner, .env-wrap { transition-duration: 0.01ms; transition-delay: 0s; }
  .is-out .env-letter { animation-duration: 0.01ms; }
  .is-wrong .env { animation: none; }
}

/* ---------------- narrow ---------------- */

@media (max-width: 560px) {
  .gate { gap: 30px; }
  .env-wrap { width: min(86vw, 340px); margin-top: clamp(50px, 12vh, 110px); }
  .gate-names { font-size: clamp(38px, 12vw, 50px); }
  .gate-meta { font-size: 11px; letter-spacing: 0.18em; gap: 10px; }
}

/* Short viewports: the envelope and the form together can outgrow the screen,
   so let the page scroll rather than clip the button. */
@media (max-height: 680px) {
  .gate-body { overflow-y: auto; }
  .gate { min-height: auto; padding-top: 36px; padding-bottom: 36px; }
  .env-wrap { width: min(400px, 78vw); margin-top: 40px; }
}
/* A phone on its side. At its highest the card stands about its own height
   above the envelope, so the envelope and the card together need nearly twice
   the envelope's height; at the usual size that's more than this screen has. */
@media (max-height: 480px) {
  .env-wrap { width: min(280px, 70vw); }
}
