/* ==========================================================================
   THE LIT ENVELOPE

   Dark botanical paper filling the screen, a bronze wax seal holding it
   shut, and foliage that is only embossed until the seal is pressed - at
   which point it lights in gold, drawn on from the seal outwards, light
   floods out along the folds, and everything goes to light.

   Nothing here is a video or an image.

   Two ideas do most of the work:

   1. An emboss has no colour of its own. Every stem and leaf is drawn in
      the paper's own colour and raised by a filter - a dark shadow pushed
      away from the light, a pale one pulled towards it. That is why it
      reads as paper pushed up rather than as ink laid down.

   2. The gold is that same line-work again with its dash offset animated
      from one to zero, which is what makes it look drawn rather than
      switched on. Every path carries pathLength="1", so a single rule
      dashes all of them regardless of how long they really are.
   ========================================================================== */

:root {
  /* ---- the paper: a warm dark grey-brown, never black and never green -- */
  --paper-lit:    #433e33;
  --paper:        #383129;
  --paper-deep:   #302c23;
  --paper-dark:   #36342b;

  /* the relief is the paper, so it is drawn in the paper's own colour */
  --paper-relief: #3a352c;

  /* ---- the light ---- */
  --gold:     #dccb82;
  --gold-hot: #fff3bd;
  --beam:     #e6d379;

  --ink:      #cfc7b4;
  --ink-soft: #8d8674;

  /* ---- geometry ----
     The reference fills the phone edge to edge. A card floating in the
     middle of a page reads as a picture of an envelope; this reads as the
     envelope. */
  --env-w: 100vw;
  --env-h: 100svh;

  /* where the flap's point lands, and therefore where the wax sits */
  --v: 59%;

  --ease-soft: cubic-bezier(0.4, 0, 0.2, 1);
}

* { box-sizing: border-box; }

html { overflow-x: clip; scroll-behavior: smooth; }

body {
  margin: 0;
  min-height: 100svh;
  font-family: "Inter", system-ui, -apple-system, sans-serif;
  color: var(--ink);
  overflow-x: clip;
  background: #14130f;
  -webkit-font-smoothing: antialiased;
}

/* ==========================================================================
   THE STAGE
   ========================================================================== */
.stage {
  position: relative;
  z-index: 1;
  min-height: 100svh;
  display: grid;
  place-items: center;
  padding: 0;
  transition: opacity 0.9s var(--ease-soft);
}

.envelope-wrap { perspective: 1600px; }

.envelope {
  position: relative;
  width: var(--env-w);
  height: var(--env-h);
  overflow: hidden;
  transition: transform 1.4s var(--ease-soft);
}

body.is-lighting .envelope,
body.is-opened .envelope { transform: scale(1.006); }

/* ==========================================================================
   THE PAPER AND ITS FOLDS
   The folds carry no artwork of their own. What separates them is only the
   light each one catches - which is all that separates them on a real
   envelope either.
   ========================================================================== */
.paper {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(150% 90% at 46% 16%, var(--paper-lit) 0%, rgba(76, 72, 62, 0) 74%),
    linear-gradient(174deg, var(--paper) 0%, var(--paper-deep) 62%, var(--paper-dark) 100%);
}

/* the tooth of a heavy uncoated sheet */
.paper::after {
  content: "";
  position: absolute;
  inset: 0;
  opacity: 0.26;
  background-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='180'%20height='180'%3E%3Cfilter%20id='n'%3E%3CfeTurbulence%20type='fractalNoise'%20baseFrequency='0.9'%20numOctaves='4'%20stitchTiles='stitch'/%3E%3CfeColorMatrix%20type='saturate'%20values='0'/%3E%3C/filter%3E%3Crect%20width='180'%20height='180'%20filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 180px 180px;
  mix-blend-mode: overlay;
}

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

/* the flap, coming down from the top to a point */
.fold-flap {
  clip-path: polygon(0 0, 100% 0, 50% var(--v));
  background:
    linear-gradient(172deg,
      rgba(186, 175, 145, 0.07) 0%,
      rgba(0, 0, 0, 0.06) 26%,
      rgba(0, 0, 0, 0.19) 46%,
      rgba(0, 0, 0, 0.29) 68%,
      rgba(0, 0, 0, 0.44) 100%);
  /* the crease itself, so the V reads as an edge and not only as shading */
  filter:
    drop-shadow(0 1px 0 rgba(214, 206, 176, 0.13))
    drop-shadow(0 3px 6px rgba(0, 0, 0, 0.55));
}

/* the two side folds, each catching the light differently */
.fold-left {
  clip-path: polygon(0 0, 50% var(--v), 50% 100%, 0 100%);
  background:
    linear-gradient(104deg, rgba(178, 168, 140, 0.07) 0%, rgba(178, 168, 140, 0) 44%),
    linear-gradient(0deg, rgba(0, 0, 0, 0.19), rgba(0, 0, 0, 0.19));
}

.fold-right {
  clip-path: polygon(100% 0, 100% 100%, 50% 100%, 50% var(--v));
  background: linear-gradient(256deg, rgba(0, 0, 0, 0.36) 0%, rgba(0, 0, 0, 0) 46%);
}

/* the bottom fold laps over both of them */
.fold-bottom {
  clip-path: polygon(0 100%, 50% 61%, 100% 100%);
  background:
    linear-gradient(0deg, rgba(0, 0, 0, 0.24) 0%, rgba(0, 0, 0, 0) 48%),
    linear-gradient(180deg, rgba(184, 176, 148, 0.12) 0%, rgba(184, 176, 148, 0) 12%);
  filter: drop-shadow(0 -1px 0 rgba(214, 206, 176, 0.1));
}

/* ==========================================================================
   THE BOTANICALS
   ========================================================================== */
.flora {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  overflow: visible;
}

.flora path { stroke-linecap: round; stroke-linejoin: round; }

/* ---- the relief ---- */
.fl-relief {
  fill: var(--paper-relief);
  stroke: var(--paper-relief);
  stroke-width: 1.1;
  filter:
    drop-shadow(1px 1.4px 1.4px rgba(0, 0, 0, 0.82))
    drop-shadow(-0.7px -1px 1px rgba(242, 236, 214, 0.40))
    drop-shadow(0 0 0.7px rgba(0, 0, 0, 0.36));
}

/* the stems are thinner than the leaves they carry */
.fl-stem { fill: none; stroke-width: 1.3; }

/* the crease running down each leaf, pressed in rather than raised */
.fl-crease {
  fill: none;
  stroke: rgba(0, 0, 0, 0.16);
  stroke-width: 0.6;
  filter: drop-shadow(0 -0.8px 0 rgba(228, 222, 196, 0.14));
}

/* ---- the creases where the paper is folded ---- */
.creases {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  overflow: visible;
}

.creases path { fill: none; }

/* the shade under the fold, wide and soft */
.cr-dark {
  transform: translate(0, 2.6px);
  stroke: rgba(0, 0, 0, 0.62);
  stroke-width: 7;
  filter: blur(3px);
}

/* and the lit edge of the paper turning over, narrow and sharp */
.cr-lite {
  transform: translate(0, -0.5px);
  stroke: rgba(232, 224, 198, 0.5);
  stroke-width: 1.6;
}

/* ---- the gold ---- */
.flora-lit {
  opacity: 0;
  transition: opacity 0.25s ease;
}

body.is-lighting .flora-lit,
body.is-opened .flora-lit,
body.is-flashing .flora-lit { opacity: 1; }

.fl-gold path {
  fill: none;
  stroke: var(--gold);
  stroke-width: 1.15;
}

/* one filter over the whole group, rather than a blurred copy of every path */
.fl-gold {
  filter:
    drop-shadow(0 0 1.5px rgba(220, 203, 130, 0.6))
    drop-shadow(0 0 6px rgba(204, 180, 96, 0.32));

  /* the band of light that washes down over the plate */
  -webkit-mask-image: linear-gradient(180deg,
    #000 0%, #000 46%, rgba(0, 0, 0, 0.45) 51%, rgba(0, 0, 0, 0) 57%);
          mask-image: linear-gradient(180deg,
    #000 0%, #000 46%, rgba(0, 0, 0, 0.45) 51%, rgba(0, 0, 0, 0) 57%);
  -webkit-mask-size: 100% 200%;
          mask-size: 100% 200%;
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
  -webkit-mask-position: 0% 100%;
          mask-position: 0% 100%;
}

body.is-lighting .fl-gold,
body.is-opened .fl-gold,
body.is-flashing .fl-gold {
  animation: goldWash 0.85s cubic-bezier(0.32, 0.08, 0.36, 1) forwards;
}

@keyframes goldWash {
  from { -webkit-mask-position: 0% 100%; mask-position: 0% 100%; }
  to   { -webkit-mask-position: 0% 0%;   mask-position: 0% 0%; }
}

/* once it is all in, the gold breathes rather than sitting flat */
body.is-opened .fl-gold {
  animation:
    goldWash 0.85s cubic-bezier(0.32, 0.08, 0.36, 1) forwards,
    goldBreathe 2.8s ease-in-out 1s infinite;
}

@keyframes goldBreathe {
  0%, 100% {
    filter: drop-shadow(0 0 1.5px rgba(220, 203, 130, .6))
            drop-shadow(0 0 6px rgba(204, 180, 96, .32));
  }
  50% {
    filter: drop-shadow(0 0 3px rgba(236, 222, 160, .8))
            drop-shadow(0 0 11px rgba(220, 196, 110, .5));
  }
}

/* ==========================================================================
   THE SEAMS
   Light does not come from nowhere. It comes out from behind the folds:
   along the two diagonals of the flap, and straight down under the wax.
   ========================================================================== */
.seam {
  position: absolute;
  pointer-events: none;
  opacity: 0;
  mix-blend-mode: screen;
  transition: opacity 0.7s ease;
}

.seam-left,
.seam-right {
  top: 0;
  width: 50%;
  height: var(--v);
  background: linear-gradient(180deg,
    rgba(230, 211, 121, 0.42) 0%,
    rgba(240, 219, 116, 1) 54%,
    #f6ecbe 100%);
  filter: blur(3px);
}

/* Each beam is a wedge lying along one diagonal of the V, wide where the
   fold meets the top edge and closing to nothing at the seal. */
.seam-left {
  left: 0;
  /* closed: a hairline lying on the crease */
  clip-path: polygon(0 0, 100% 100%, 96% 100%, 0 5%);
  transition: clip-path 0.85s cubic-bezier(0.3, 0, 0.2, 1),
              opacity 0.45s ease, filter 0.9s ease, transform 1.1s var(--ease-soft);
}

body.is-lighting .seam-left,
body.is-opened .seam-left,
body.is-flashing .seam-left {
  clip-path: polygon(0 0, 100% 100%, 66% 100%, 0 38%);
  transition-delay: 1.05s, 1.05s, 0s, 0s;
}
.seam-right {
  right: 0;
  clip-path: polygon(100% 0, 0 100%, 4% 100%, 100% 5%);
  transition: clip-path 0.85s cubic-bezier(0.3, 0, 0.2, 1),
              opacity 0.45s ease, filter 0.9s ease, transform 1.1s var(--ease-soft);
}

body.is-lighting .seam-right,
body.is-opened .seam-right,
body.is-flashing .seam-right {
  clip-path: polygon(100% 0, 0 100%, 34% 100%, 100% 38%);
  transition-delay: 1.05s, 1.05s, 0s, 0s;
}

/* and the light that spills straight down from under the wax */
.seam-down {
  left: 50%;
  top: var(--v);
  width: 48%;
  height: 42%;
  transform: translateX(-50%);
  background: linear-gradient(180deg,
    #f6ecbe 0%,
    rgba(240, 219, 116, 0.85) 26%,
    rgba(230, 211, 121, 0.18) 78%,
    rgba(230, 211, 121, 0) 100%);
  clip-path: polygon(34% 0, 66% 0, 100% 100%, 0 100%);
  filter: blur(5px);
}

/* held back until the gold has had time to travel */
body.is-lighting .seam { opacity: 1; transition-delay: 1.05s; }
body.is-opened .seam,
body.is-flashing .seam { opacity: 1; }

body.is-opened .seam { animation: beamPulse 2.4s ease-in-out infinite; }

@keyframes beamPulse {
  0%, 100% { opacity: 0.82; }
  50%      { opacity: 1; }
}

/* ==========================================================================
   THE WAX
   Bronze while it is holding the envelope shut. Pressed, the light behind
   it comes through and it goes pale with a gold rim.
   ========================================================================== */
.seal {
  position: absolute;
  left: 50%;
  top: var(--v);
  z-index: 6;
  width: clamp(126px, 35.6vw, 224px);
  aspect-ratio: 1;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  transform: translate(-50%, -50%);
  -webkit-tap-highlight-color: transparent;
  filter: drop-shadow(0 9px 15px rgba(0, 0, 0, 0.62));
  transition: transform 0.24s var(--ease-soft), filter 0.7s ease;
}

/* a tap target rather larger than the wax it draws */
.seal::before { content: ""; position: absolute; inset: -18px; }

.seal svg { display: block; width: 100%; height: 100%; overflow: visible; }

.seal:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 10px;
  border-radius: 50%;
}

.seal:hover { transform: translate(-50%, -50%) scale(1.02); }

body.is-pressing .seal {
  transform: translate(-50%, -50%) scale(0.955);
  filter: drop-shadow(0 3px 7px rgba(0, 0, 0, 0.65));
}

.wax-blob circle,
.wax-well,
.wax-shade,
.wax-inner,
.wax-ring,
.wax-ring2,
.wax-rimlight,
.wax-die path { transition: all 1.15s var(--ease-soft) 0.75s; }

body.is-lighting .seal,
body.is-opened .seal,
body.is-flashing .seal {
  pointer-events: none;
  transition: transform 0.24s var(--ease-soft), filter 0.9s ease 0.85s;
  filter:
    drop-shadow(0 0 10px rgba(255, 233, 150, 0.85))
    drop-shadow(0 0 32px rgba(255, 214, 92, 0.55))
    drop-shadow(0 10px 16px rgba(0, 0, 0, 0.5));
}

/* the wax goes pale as the light behind it comes through */
body.is-lighting .wax-blob circle,
body.is-opened .wax-blob circle,
body.is-flashing .wax-blob circle { fill: #d9bd8b; }

body.is-lighting .wax-well,
body.is-opened .wax-well,
body.is-flashing .wax-well { fill: #efe6cf; }

body.is-lighting .wax-die path,
body.is-opened .wax-die path,
body.is-flashing .wax-die path { stroke: #8a6a2c; }

body.is-lighting .wax-ring,
body.is-opened .wax-ring,
body.is-flashing .wax-ring { stroke: #c9a35a; }

body.is-lighting .wax-shade,
body.is-opened .wax-shade,
body.is-flashing .wax-shade { opacity: 0.28; }

/* the rim keeps its bronze when the middle goes pale, as theirs does */
body.is-lighting .wax-rimlight,
body.is-opened .wax-rimlight,
body.is-flashing .wax-rimlight { stroke: url(#rim-light); opacity: .92; }

body.is-lighting .wax-inner,
body.is-opened .wax-inner,
body.is-flashing .wax-inner { opacity: .45; }

/* ==========================================================================
   THE LAST OF IT
   The flap goes to light, the beams go to their brightest, and the foot of
   the envelope stays dark - which is what keeps the V readable while
   everything above it is blowing out.
   ========================================================================== */
.fold-flap { transition: background 1.1s ease, filter 1.1s ease; }

body.is-flashing .fold-flap,
body.is-completed .fold-flap {
  z-index: 7;
  background:
    linear-gradient(0deg,
      #fffef8 0%, #fffdf0 46%, #fffbe4 78%, #fff8d4 100%);
  filter: none;
}

/* the beams reach full strength and widen */
body.is-flashing .seam,
body.is-completed .seam {
  opacity: 1;
  filter: blur(7px);
}

body.is-flashing .seam-left,
body.is-flashing .seam-right,
body.is-completed .seam-left,
body.is-completed .seam-right {
  background: linear-gradient(180deg,
    rgba(226, 200, 74, 0.75) 0%,
    #ecd76f 52%,
    #f8f0c8 100%);
}

/* only a core of light at the wax itself, not a wash over the whole page */
.flash {
  position: absolute;
  inset: 0;
  z-index: 9;
  pointer-events: none;
  opacity: 0;
  background: radial-gradient(closest-side at 50% var(--v),
    #fffdf4 0%, rgba(255, 250, 220, 0.9) 12%, rgba(255, 236, 140, 0.35) 24%,
    rgba(255, 232, 115, 0) 40%);
  transition: opacity 1.1s ease;
}

body.is-flashing .flash,
body.is-completed .flash { opacity: 1; }

/* the seal is the first thing the light takes, not the last */
body.is-flashing .seal,
body.is-completed .seal {
  opacity: 0;
  transform: translate(-50%, -50%) scale(1.16);
  transition: opacity 0.8s ease 0.1s, transform 1.1s var(--ease-soft);
}

/* and the gold on the lit flap has nothing left to glow against */
body.is-flashing .flora-lit,
body.is-completed .flora-lit { opacity: 0.3; transition: opacity 1.1s ease; }

/* ---- the hint ---- */
.hint {
  position: absolute;
  left: 0;
  right: 0;
  bottom: calc(clamp(14px, 4vw, 30px) + env(safe-area-inset-bottom));
  z-index: 8;
  margin: 0;
  text-align: center;
  font-size: 0.62rem;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--ink-soft);
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.7);
  transition: opacity 0.5s ease;
}

body.is-closed .hint { animation: hintBreathe 2.8s ease-in-out infinite; }
body:not(.is-closed) .hint { opacity: 0; }

@keyframes hintBreathe {
  0%, 100% { opacity: 0.55; transform: translateY(0); }
  50%      { opacity: 0.95; transform: translateY(-3px); }
}

/* ==========================================================================
   WHAT IT OPENS INTO
   ========================================================================== */
.invitation {
  position: relative;
  z-index: 1;
  min-height: 100svh;
  opacity: 0;
  visibility: hidden;
  transform: translateY(24px);
  transition:
    opacity 1.2s var(--ease-soft),
    transform 1.2s var(--ease-soft),
    visibility 1.2s;
  padding: clamp(40px, 10vw, 90px) clamp(18px, 6vw, 40px) clamp(60px, 14vw, 120px);
  background: radial-gradient(120% 80% at 50% 0%, #221f16 0%, #14130e 70%);
}

body.is-completed .invitation {
  opacity: 1;
  visibility: visible;
  transform: none;
}

body.is-completed .stage {
  opacity: 0;
  pointer-events: none;
  position: absolute;
  inset: 0;
}

.inv-hero { text-align: center; max-width: 40ch; margin: 0 auto; }

.inv-kicker {
  margin: 0;
  font-size: 0.64rem;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: #a08d5c;
}

.inv-names {
  margin: 0.3em 0 0.2em;
  font-family: "Cormorant Garamond", serif;
  font-weight: 300;
  font-size: clamp(2.6rem, 12vw, 5rem);
  line-height: 1.05;
  color: #f2e6c6;
}

.inv-names span { font-style: italic; color: var(--gold); }

.inv-date {
  margin: 0;
  font-family: "Cormorant Garamond", serif;
  font-size: clamp(1rem, 4vw, 1.3rem);
  letter-spacing: 0.24em;
  color: #9d9482;
}

.inv-body { max-width: 720px; margin: clamp(34px, 8vw, 64px) auto 0; }

.inv-lede {
  margin: 0 auto;
  max-width: 44ch;
  text-align: center;
  font-size: clamp(0.95rem, 3.6vw, 1.05rem);
  line-height: 1.95;
  color: #b3ab97;
}

.inv-grid {
  margin-top: clamp(30px, 7vw, 52px);
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr));
  gap: 14px;
}

.inv-card {
  padding: 26px 24px;
  border-radius: 18px;
  text-align: center;
  background: rgba(255, 246, 220, 0.045);
  border: 1px solid rgba(244, 222, 146, 0.2);
}

.inv-label {
  margin: 0;
  font-size: 0.58rem;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  color: var(--gold);
}

.inv-card h2 {
  margin: 8px 0 6px;
  font-family: "Cormorant Garamond", serif;
  font-weight: 400;
  font-size: clamp(1.3rem, 5vw, 1.7rem);
  color: #f2e6c6;
}

.inv-card p { margin: 0; font-size: 0.9rem; color: #9d9482; }

.inv-close {
  margin: clamp(34px, 8vw, 60px) 0 0;
  text-align: center;
  font-family: "Cormorant Garamond", serif;
  font-style: italic;
  font-size: clamp(1.05rem, 4.4vw, 1.35rem);
  color: #a08d5c;
}

/* ==========================================================================
   A PHONE HELD SIDEWAYS
   ========================================================================== */
@media (orientation: landscape) and (max-height: 560px) {
  :root { --v: 52%; }
  .seal { width: clamp(96px, 18vw, 150px); }
}

@media (prefers-reduced-motion: reduce) {
  .fl-gold path { animation: none !important; stroke-dashoffset: 0 !important; }
  body.is-opened .fl-gold,
  body.is-opened .seam { animation: none !important; }
  body.is-closed .hint { animation: none; opacity: 0.8; }

  .envelope, .seal, .flash, .invitation, .stage, .flora-lit, .seam {
    transition-duration: 0.01ms !important;
  }
}
