/* ============================================
   The Feeling — Experience Transition
   ============================================
   - Loading overlay
   - Website dissolve
   - Desk environment
   - Envelope with wax seal
   - Paper pull interaction (paper becomes final frame)
   ============================================ */

/* ============================================
   Base Overlay
   ============================================ */

.experience {
  position: fixed;
  inset: 0;
  z-index: 500;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.4s ease, visibility 0.4s ease;
  font-family: 'Cormorant Garamond', Georgia, 'Times New Roman', serif;
  -webkit-tap-highlight-color: transparent;
}

.experience--active {
  opacity: 1;
  visibility: visible;
  pointer-events: all;
}

.experience:focus {
  outline: none;
}

.experience__stage {
  position: absolute;
  inset: 0;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.8s ease, visibility 0.8s ease;
}

.experience__stage--active {
  opacity: 1;
  visibility: visible;
}


/* ============================================
   Loading Screen
   ============================================ */

.experience__loading {
  position: fixed;
  inset: 0;
  z-index: 600;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--color-bg, #FAF8F5);
  opacity: 0;
  transition: opacity 0.6s ease;
  pointer-events: none;
}

.experience__loading--visible {
  opacity: 1;
}

.experience__loading-text {
  font-family: 'Cormorant Garamond', Georgia, 'Times New Roman', serif;
  font-size: clamp(1.125rem, 2.5vw, 1.5rem);
  color: var(--color-text-secondary, #6B6258);
  letter-spacing: 0.02em;
  font-style: italic;
  animation: loading-pulse 1.5s ease-in-out infinite;
  text-align: center;
  padding: 0 2rem;
}

@keyframes loading-pulse {
  0%, 100% { opacity: 0.6; }
  50% { opacity: 1; }
}


/* ============================================
   Website Dissolve
   ============================================ */

.experience__dissolve {
  position: fixed;
  inset: 0;
  z-index: 550;
  background: var(--color-bg, #FAF8F5);
  opacity: 0;
  pointer-events: none;
  transition: opacity 1.5s ease;
}

.experience__dissolve--active {
  opacity: 0;
}

.experience__dissolve--visible {
  opacity: 1;
}


/* ============================================
   Desk Scene
   ============================================ */

.experience__desk {
  position: fixed;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

/* Wooden desk surface — warm walnut, lit by the same upper-left window.
   The grain is long low-frequency streaks (like real figure), plus barely-
   there plank seams. It should read as one photographed surface, never
   as a pattern. */
.desk__surface {
  position: absolute;
  inset: -10%;
  --wood-grain: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='320' height='320'><filter id='w'><feTurbulence type='fractalNoise' baseFrequency='0.006 0.11' numOctaves='4' seed='4' stitchTiles='stitch'/><feColorMatrix type='matrix' values='0 0 0 0 0.35  0 0 0 0 0.24  0 0 0 0 0.11  0 0 0 0.32 0'/></filter><rect width='320' height='320' filter='url(%23w)'/></svg>");
  background:
    var(--wood-grain) repeat,
    /* a few quiet plank seams — the desk is boards, not a sheet */
    repeating-linear-gradient(
      180deg,
      transparent 0,
      transparent 17.6%,
      rgba(56, 32, 14, 0.09) 17.8%,
      rgba(56, 32, 14, 0.09) 18.2%,
      transparent 18.4%
    ),
    /* warm walnut, falling off toward the lower-right */
    linear-gradient(
      160deg,
      #9C7442 0%,
      #8D6334 30%,
      #7C552C 60%,
      #6C4722 100%
    );
  transform: scale(1.1);
}

/* Warm light overlay — natural window light: a soft parallelogram of
   sun falling from the upper-left, and the key pool where the envelope
   sits in the brightest part of the scene. */
.desk__light {
  position: absolute;
  inset: 0;
  background:
    /* the window — a diagonal band of late-morning light across the desk */
    linear-gradient(
      112deg,
      transparent 30%,
      rgba(255, 226, 176, 0.09) 44%,
      rgba(255, 214, 156, 0.04) 58%,
      transparent 72%
    ),
    /* the key pool where the envelope rests — the brightest part */
    radial-gradient(
      ellipse 72% 62% at 38% 30%,
      rgba(255, 226, 176, 0.16) 0%,
      rgba(255, 208, 148, 0.06) 42%,
      transparent 72%
    ),
    /* warm bounce from the far corner */
    radial-gradient(
      ellipse 60% 46% at 62% 68%,
      rgba(255, 190, 120, 0.05) 0%,
      transparent 62%
    );
  pointer-events: none;
}

/* Vignette — warm lens falloff, never pure black */
.desk__vignette {
  position: absolute;
  inset: 0;
  box-shadow:
    inset 0 0 130px rgba(46, 28, 10, 0.42),
    inset 0 0 280px rgba(46, 28, 10, 0.2);
  pointer-events: none;
}

/* Film grain — a whisper of sensor noise over the entire scene so it
   reads as one photograph, not as UI layered on a gradient.
   NB: z-index 500 is INTENTIONALLY above .paper--final (z400) so the
   fullscreen letter keeps the same photographic grain. The desk stage
   is position: fixed, which scopes the blend inside the stage. */
.desk__grain {
  position: absolute;
  inset: 0;
  z-index: 500;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='200' height='200'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix type='matrix' values='0 0 0 0 0.5 0 0 0 0 0.5 0 0 0 0 0.5 0 0 0 0.06 0'/></filter><rect width='200' height='200' filter='url(%23n)'/></svg>");
  mix-blend-mode: overlay;
  opacity: 0.45;
  pointer-events: none;
}

/* Dust particles */
.desk__particle {
  position: absolute;
  width: 2px;
  height: 2px;
  background: rgba(255, 220, 180, 0.6);
  border-radius: 50%;
  pointer-events: none;
  will-change: transform, opacity;
  animation: dust-float linear infinite;
}

@keyframes dust-float {
  0% {
    transform: translateY(0) translateX(0);
    opacity: 0;
  }
  10% {
    opacity: 0.6;
  }
  90% {
    opacity: 0.4;
  }
  100% {
    transform: translateY(-120px) translateX(20px);
    opacity: 0;
  }
}


/* ============================================
   Envelope
   ============================================ */

.envelope {
  position: relative;
  /* Landscape invitation proportions (~1.6 : 1) — a wide flat-card
     announcement envelope resting on the desk */
  width: min(440px, 80vw);
  aspect-ratio: 1.6;
  z-index: 10;
  /* Shared handmade-cotton grain — warm tan fibres, nearly invisible
     at reading distance; only light grazing the surface reveals it */
  --cotton-grain: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='g'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix type='matrix' values='0 0 0 0 0.55  0 0 0 0 0.42  0 0 0 0 0.28  0 0 0 0.1 0'/></filter><rect width='160' height='160' filter='url(%23g)'/></svg>");
  /* ONE continuous sheet of cotton — every surface of the envelope
     shares this same FLAT warm ivory. No panel is ever a different
     colour; folds are defined by shadow and light alone. */
  --cotton-paper: #F6EEDC;
  /* Hand-placed: a barely-perceptible tilt, as if set down by hand */
  transform: rotate(-0.55deg);
  animation: envelope-breathe 6s ease-in-out infinite;
  will-change: transform;
}

@keyframes envelope-breathe {
  0%, 100% {
    transform: translateY(0) rotate(-0.55deg) scale(1);
  }
  50% {
    transform: translateY(-3px) rotate(-0.62deg) scale(1.002);
  }
}

/* Natural ground shadow — tight warm contact, then a soft cast falling
   to the lower-right, matching the key light from the upper-left */
.envelope__shadow {
  position: absolute;
  inset: -8px;
  border-radius: 6px;
  background: transparent;
  box-shadow:
    0 3px 8px rgba(50, 32, 14, 0.2),
    10px 18px 34px rgba(50, 32, 14, 0.16),
    26px 46px 88px rgba(50, 32, 14, 0.12);
  pointer-events: none;
}

/* Envelope interior — the same cotton sheet fallen into shadow.
   Completely hidden while the envelope is sealed; the dark pocket only
   appears after the flap lifts. */
.envelope__interior {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 66%;
  z-index: 1;
  background:
    var(--cotton-grain) repeat,
    /* the cavity walls fall into shadow toward the mouth */
    linear-gradient(
      90deg,
      rgba(108, 82, 48, 0.16) 0%,
      transparent 24%,
      transparent 76%,
      rgba(108, 82, 48, 0.16) 100%
    ),
    /* a deep warm pocket — the shared cotton, fallen out of the light */
    linear-gradient(
      180deg,
      #DED0AF 0%,
      #C8B487 46%,
      #A68C5D 100%
    );
  pointer-events: none;
}

/* Mouth shadow — the letter recedes into the cavity toward the flap line */
.envelope__mouth {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 48%;
  z-index: 3;
  background: linear-gradient(
    180deg,
    rgba(70, 50, 25, 0) 0%,
    rgba(70, 50, 25, 0) 42%,
    rgba(70, 50, 25, 0.28) 100%
  );
  pointer-events: none;
}

/* Contact shadow — the letter casts a soft shadow onto the envelope's
   front panel just below the mouth. Crisp and close at rest; the JS
   stretches + softens it as the letter lifts, so the paper visually
   separates from the envelope. Painted ABOVE the body (z5) so it is
   never occluded by the paper or the front panel. */
.envelope__paper-shadow {
  position: absolute;
  left: 50%;
  top: 46%;
  width: 82%;
  height: 40px;
  z-index: 5;
  transform: translateX(-50%) scaleY(0.7);
  background: radial-gradient(
    50% 100% at 50% 0%,
    rgba(84, 56, 24, 0.28),
    rgba(84, 56, 24, 0.08) 55%,
    transparent 80%
  );
  filter: blur(3px);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.6s ease;
}

.paper--visible ~ .envelope__paper-shadow {
  opacity: 1;
}

/* Front panel — starts at the mouth line so it masks the letter below it.
   Lighting defines the material: no outlines, only a soft crease where
   the panel folds up to meet the flap, a top-left sheen and a warm
   ambient bounce rising from below. */
.envelope__body {
  position: absolute;
  top: 48%;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 4;
  background:
    var(--cotton-grain) repeat,
    /* key light — the same upper-left source, entering from ABOVE this
       panel so its wash continues the flap's light instead of
       restarting a fresh hotspot at the seam */
    radial-gradient(
      150% 130% at 24% -18%,
      rgba(255, 252, 244, 0.45),
      rgba(255, 250, 240, 0.12) 42%,
      transparent 66%
    ),
    /* warm fill — light bouncing back up off the desk */
    radial-gradient(
      140% 100% at 60% 116%,
      rgba(206, 168, 112, 0.18),
      transparent 62%
    ),
    /* one continuous sheet — the shared cotton ivory */
    var(--cotton-paper);
  border-radius: 4px;
  overflow: hidden;
  box-shadow:
    /* crisp rim light along the top-left cut edge */
    inset 1px 1px 0 rgba(255, 255, 255, 0.65),
    /* a soft contact shadow where the folded flap lies over this panel —
       never a seam, only light pressing down */
    inset 0 10px 18px -12px rgba(120, 92, 55, 0.16),
    /* thick cardstock — a compressed bottom edge catching warm shadow */
    inset 0 -3px 0 rgba(138, 108, 72, 0.18),
    inset 0 -6px 10px -6px rgba(120, 92, 55, 0.1);
}

/* The envelope front is deliberately clean — no printed branding.
   Only the cotton stock, the light and the folds define it. */


/* ============================================
   Envelope Flap
   ============================================ */

.envelope__flap {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 48%;
  z-index: 5;
  transform-origin: top center;
  transform: rotateX(0deg);
  transition: transform 1.2s cubic-bezier(0.4, 0, 0.2, 1);
  will-change: transform;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
}

.envelope__flap--open {
  transform: rotateX(180deg);
  /* Once the flap is up it is invisible; never block grabbing the letter */
  pointer-events: none;
}

/* The folded-edge shadow — a separate element from the clipped shape,
   so no browser (Safari included) ever drops the clip-path. The shadow
   falls down-right, matching the key light, and is what makes the
   triangle read as a raised fold lying on the face. */
.envelope__flap-edge {
  position: absolute;
  inset: 0;
  filter: drop-shadow(3px 5px 5px rgba(120, 92, 55, 0.2));
  pointer-events: none;
}

.envelope__flap-shape {
  position: absolute;
  inset: 0;
  /* A classic triangular invitation flap — one clean triangle from the
     top edge, both sides tapering evenly to a single point in the
     centre, exactly like a luxury handmade envelope. */
  clip-path: polygon(0% 0%, 100% 0%, 50% 100%);
  background:
    var(--cotton-grain) repeat,
    /* the raised flap faces the window — a touch brighter than the flat
       face beneath, so the triangle clearly reads as a separate fold */
    radial-gradient(
      120% 90% at 22% 0%,
      rgba(255, 252, 244, 0.64),
      rgba(255, 250, 240, 0.2) 42%,
      transparent 66%
    ),
    /* one continuous sheet — the shared cotton ivory */
    var(--cotton-paper);
}

/* Side gussets — the two inner folds flanking the flap. Each wedge is a
   point at the envelope's top corner and widens only toward the mouth,
   so the letter is framed as it settles into the pocket — never pinched. */
.envelope__sides {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 48%;
  z-index: 4;
  pointer-events: none;
}

.envelope__sides::before,
.envelope__sides::after {
  content: '';
  position: absolute;
  top: 0;
  height: 100%;
  width: 46%;
}

/* Left gusset — the inner fold wall, slightly in shadow like a real
   open pocket; light still grazes the outer edge */
.envelope__sides::before {
  left: 0;
  clip-path: polygon(0 0, 0 100%, 100% 100%);
  background:
    var(--cotton-grain) repeat,
    /* the fold wall — light grazing the outer edge, shadow pooling
       where the sheet turns inward */
    linear-gradient(
      135deg,
      rgba(255, 251, 242, 0.1) 0%,
      transparent 38%,
      rgba(100, 76, 44, 0.18) 100%
    ),
    /* one continuous sheet — the shared cotton ivory */
    var(--cotton-paper);
}

/* Right gusset — mirrored */
.envelope__sides::after {
  right: 0;
  clip-path: polygon(100% 0, 100% 100%, 0 100%);
  background:
    var(--cotton-grain) repeat,
    /* mirrored fold wall — same light, same sheet */
    linear-gradient(
      225deg,
      rgba(255, 251, 242, 0.1) 0%,
      transparent 38%,
      rgba(100, 76, 44, 0.18) 100%
    ),
    /* one continuous sheet — the shared cotton ivory */
    var(--cotton-paper);
}

/* Upper face — the front panel continues up behind the triangular flap,
   so the SEALED envelope reads as one continuous sheet of cotton (the
   corner wedges beside the triangle are face, never open cavity). It
   fades away as the flap lifts, revealing the gussets and letter. */
.envelope__mouth-panel {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 48%;
  z-index: 4;
  background:
    var(--cotton-grain) repeat,
    /* the exact same light as the front panel below — the face is one
       continuous tone, so the raised flap reads purely by contrast */
    radial-gradient(
      150% 130% at 24% -18%,
      rgba(255, 252, 244, 0.45),
      rgba(255, 250, 240, 0.12) 42%,
      transparent 66%
    ),
    /* warm fill — light bouncing back up off the desk */
    radial-gradient(
      140% 100% at 60% 116%,
      rgba(206, 168, 112, 0.18),
      transparent 62%
    ),
    /* one continuous sheet — the shared cotton ivory */
    var(--cotton-paper);
  pointer-events: none;
  transition: opacity 0.8s ease;
}

/* Once the flap lifts, the mouth is genuinely open — the upper face
   withdraws and the cavity (gussets, letter, shadow) shows. */
.envelope__flap--open ~ .envelope__mouth-panel {
  opacity: 0;
}

/* The top fold crease — a soft band of shadow, not a line */
.envelope__flap-fold {
  position: absolute;
  top: 0;
  left: 1%;
  right: 1%;
  height: 12px;
  /* A pressed fold — soft shadow above, a hairline of light catching
     the raised ridge below. Never a drawn line. */
  background:
    linear-gradient(
      180deg,
      transparent 46%,
      rgba(255, 253, 246, 0.55) 54%,
      transparent 62%
    ),
    linear-gradient(
      180deg,
      transparent,
      rgba(130, 100, 62, 0.2) 42%,
      rgba(130, 100, 62, 0.1) 60%,
      transparent
    );
  z-index: 6;
  pointer-events: none;
}


/* ============================================
   Wax Seal
   ============================================ */

.envelope__seal {
  position: absolute;
  bottom: 0;
  left: 50%;
  /* The seal locks the envelope shut: its centre rests exactly on the
     flap's tip, so it physically bridges the triangle point and the
     front panel beneath — the only thing holding the flap closed. */
  transform: translateX(-50%) translateY(50%) rotate(-2deg);
  width: min(52px, 13vw);
  height: min(52px, 13vw);
  z-index: 15;
  cursor: pointer;
  will-change: transform;
}

/* Wax seal visual — hand-poured: an organic edge, a warm glossy body
   and a single drip where the wax cooled against the flap. */
.envelope__seal-inner {
  width: 100%;
  height: 100%;
  border-radius: 47% 53% 52% 48% / 52% 47% 53% 48%;
  background:
    radial-gradient(
      62% 56% at 32% 28%,
      #DE5E50 0%,
      #C44538 32%,
      #A53026 62%,
      #851F16 100%
    );
  box-shadow:
    /* a hair of warm wax pressed out at the base — a slight overflow
       around the seal's organic edge */
    0 0 0 1.5px rgba(216, 132, 108, 0.2),
    /* the wax presses into the cotton — a soft indentation where the
       paper buckles beneath the seal */
    0 0 0 5px rgba(96, 62, 30, 0.07),
    0 0 0 13px rgba(96, 62, 30, 0.035),
    0 4px 12px rgba(40, 12, 8, 0.38),
    0 1px 3px rgba(40, 12, 8, 0.3),
    inset 0 2px 4px rgba(255, 205, 175, 0.35),
    inset 0 -4px 8px rgba(120, 24, 14, 0.5);
  position: relative;
  overflow: visible;
  transition: box-shadow 0.3s ease;
}

/* The drip — a small bead of wax that ran down the flap */
.envelope__seal-drip {
  position: absolute;
  bottom: -18%;
  left: 26%;
  width: 32%;
  height: 20%;
  border-radius: 50%;
  background:
    radial-gradient(
      70% 70% at 40% 30%,
      #C94A40 0%,
      #A8322B 55%,
      #8B241E 100%
    );
  box-shadow:
    0 2px 5px rgba(40, 12, 8, 0.3),
    inset 0 1px 2px rgba(255, 200, 170, 0.25);
  pointer-events: none;
}

/* Keyboard focus ring for the seal */
.envelope__seal:focus-visible {
  outline: 2px solid rgba(196, 168, 130, 0.9);
  outline-offset: 3px;
  border-radius: 50%;
}

.envelope__seal-inner::before {
  content: '';
  position: absolute;
  top: 10%;
  left: 16%;
  width: 22%;
  height: 14%;
  background: radial-gradient(
    ellipse at center,
    rgba(255, 238, 210, 0.5) 0%,
    rgba(255, 238, 210, 0.15) 55%,
    transparent 75%
  );
  border-radius: 50%;
  pointer-events: none;
}

.envelope__seal-inner::after {
  content: '';
  position: absolute;
  top: 15%;
  left: 15%;
  right: 15%;
  bottom: 15%;
  border-radius: 50%;
  background:
    radial-gradient(
      circle at 50% 50%,
      transparent 40%,
      rgba(0, 0, 0, 0.08) 60%,
      transparent 72%
    );
  pointer-events: none;
}

/* Seal hover effect — the wax catches the light */
.envelope__seal:hover .envelope__seal-inner {
  box-shadow:
    0 0 0 1.5px rgba(216, 132, 108, 0.2),
    0 0 0 5px rgba(96, 62, 30, 0.07),
    0 0 0 13px rgba(96, 62, 30, 0.035),
    0 5px 18px rgba(40, 12, 8, 0.4),
    inset 0 2px 6px rgba(255, 200, 170, 0.35),
    inset 0 -3px 6px rgba(0, 0, 0, 0.3);
}

/* Seal cracked state */
.envelope__seal--cracked .envelope__seal-inner {
  box-shadow:
    0 2px 6px rgba(0, 0, 0, 0.2),
    inset 0 -1px 2px rgba(0, 0, 0, 0.1);
  opacity: 0.7;
}

.envelope__seal--cracked::before,
.envelope__seal--cracked::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 40%;
  height: 1.5px;
  background: rgba(0, 0, 0, 0.15);
  pointer-events: none;
}

.envelope__seal--cracked::before {
  transform: translate(-50%, -50%) rotate(-30deg);
}

.envelope__seal--cracked::after {
  transform: translate(-50%, -50%) rotate(40deg);
  width: 30%;
}


/* ============================================
   Paper (inside envelope — becomes final frame)
   ============================================ */

.paper {
  position: absolute;
  left: 50%;
  top: 39%;
  width: 84%;
  height: 88%;
  z-index: 2;
  /* The premium cotton material — shared by the envelope-phase letter
     body and the long reading sheets (.paper__page-sheet), so every
     surface of the paper is the same sheet of stationery. */
  --paper-material:
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='g'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix type='matrix' values='0 0 0 0 0.55  0 0 0 0 0.42  0 0 0 0 0.28  0 0 0 0.1 0'/></filter><rect width='160' height='160' filter='url(%23g)'/></svg>") repeat,
    radial-gradient(140% 110% at 22% 0%, rgba(255, 251, 240, 0.38), transparent 55%),
    radial-gradient(120% 90% at 50% 108%, rgba(214, 178, 120, 0.2), transparent 60%),
    linear-gradient(118deg, #FDF9EF 0%, #F8F1E2 36%, #F4EBD8 66%, #EFE3CC 100%);
  /* Landscape card — its top edge pokes ~5% above the envelope mouth,
     tucked deep inside so only a sliver of letter shows at rest */
  transform: translate(-50%, -50%) translateY(24px);
  transform-origin: center bottom;
  opacity: 0;
  pointer-events: none;
  will-change: transform, opacity;
  transition: opacity 0.7s ease, transform 0.9s cubic-bezier(0.25, 0.8, 0.3, 1.06);
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
}

.paper:focus-visible {
  outline: none;
}

.paper--draggable:focus-visible {
  box-shadow: 0 0 0 2px rgba(196, 168, 130, 0.5), 0 0 24px rgba(196, 168, 130, 0.25);
  border-radius: 3px;
}

.paper--visible {
  opacity: 1;
  transform: translate(-50%, -50%);
  pointer-events: none;
}

.paper--draggable {
  pointer-events: all;
  cursor: grab;
}

.paper--dragging {
  cursor: grabbing;
  transition: none;
}

/* As the letter lifts it catches a little more of the warm light */
.paper--dragging .paper__body {
  box-shadow:
    0 2px 5px rgba(70, 45, 20, 0.16),
    0 12px 32px rgba(70, 45, 20, 0.14),
    inset 0 1px 0 rgba(255, 255, 255, 0.9),
    inset 0 -1px 0 rgba(180, 150, 105, 0.2),
    inset 0 0 30px rgba(255, 242, 214, 0.2);
}

/* The cardstock edge thickens a touch while the letter is in hand */
.paper--dragging .paper__edge {
  transform: translate(1px, 3.4px);
}

/* Cardstock thickness — a darker sheet offset just behind the face */
.paper__edge {
  position: absolute;
  inset: 0;
  z-index: 0;
  border-radius: 6px;
  background: linear-gradient(
    160deg,
    #E7DAC0 0%,
    #DCCCA9 45%,
    #CDB98F 100%
  );
  transform: translate(1px, 2.5px);
  transition: transform 0.3s ease;
  pointer-events: none;
}

/* Premium cotton paper — quiet, expensive material.
   Almost smooth at reading distance: a microscopic warm grain where
   light catches the fibres, and lighting that carries the material
   quality (top-left sheen, warm ivory falloff, gentle ambient bounce). */
.paper__body {
  position: absolute;
  inset: 0;
  z-index: 1;
  border-radius: 6px;
  border: 1px solid rgba(206, 186, 152, 0.3);
  /* Precision-cut edge — microscopic imperfections only */
  --paper-edge-mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='120' height='170'><filter id='w'><feTurbulence type='fractalNoise' baseFrequency='0.06' numOctaves='2' seed='7' stitchTiles='stitch'/><feDisplacementMap in='SourceGraphic' scale='0.35'/></filter><rect width='120' height='170' fill='white' filter='url(%23w)'/></svg>");
  background: var(--paper-material);
  box-shadow:
    0 2px 5px rgba(70, 45, 20, 0.15),
    0 10px 26px rgba(70, 45, 20, 0.1),
    inset 0 1px 0 rgba(255, 255, 255, 0.9),
    inset 0 -1px 0 rgba(180, 150, 105, 0.15),
    inset 1px 0 0 rgba(255, 255, 255, 0.45),
    inset -1px 0 0 rgba(180, 150, 105, 0.1);
  -webkit-mask-image: var(--paper-edge-mask);
  mask-image: var(--paper-edge-mask);
  -webkit-mask-size: 100% 100%;
  mask-size: 100% 100%;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
}


/* Paper content — greeting and hint */
.paper__content {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 1.1rem 1.4rem;
  opacity: 0;
  transition: opacity 1s ease;
  background: transparent;
}

.paper__content--visible {
  opacity: 1;
}

/* Ornamental rule — the printable area opens with intention */
.paper__rule {
  width: clamp(3.5rem, 28%, 6rem);
  color: #C4A882;
  opacity: 0.6;
  margin-bottom: 0.7rem;
}

.paper__rule-svg {
  display: block;
  width: 100%;
  height: auto;
}

.paper__title {
  font-family: 'Cormorant Garamond', Georgia, 'Times New Roman', serif;
  font-size: clamp(0.875rem, 2.4vw, 1.15rem);
  font-style: italic;
  font-weight: 500;
  color: #2C2C2C;
  text-align: center;
  letter-spacing: 0.03em;
  line-height: 1.35;
  transition: opacity 0.8s ease, filter 0.8s ease, transform 0.8s ease;
}

.paper__title-main {
  display: block;
}

.paper__title-sub {
  display: block;
  font-family: 'Inter', -apple-system, sans-serif;
  font-style: normal;
  font-weight: 400;
  font-size: 0.5rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: #9C9288;
  margin-top: 0.4rem;
}

/* The tutorial title gently lifts and dissolves before the real title is written */
.paper__title--leaving {
  opacity: 0;
  filter: blur(6px);
  transform: translateY(-6px) scale(0.985);
  pointer-events: none;
}

/* ==========================================
   The ink-writing reveal
   ========================================== */

.paper__reveal {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.6s ease, visibility 0.6s ease;
  pointer-events: none;
}

.paper__reveal--active {
  opacity: 1;
  visibility: visible;
}

.paper__reveal-svg {
  width: min(84vw, 460px);
  height: auto;
  overflow: visible;
}

/* Each line is "written" with a stroke that draws along the glyphs,
   then the ink fill soaks in behind it — an organic pen effect. */
.paper__reveal-line {
  font-family: 'Cormorant Garamond', Georgia, 'Times New Roman', serif;
  font-style: italic;
  font-weight: 500;
  fill: transparent;
  stroke: #33281C;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
}

/* Font sizes are in SVG user units (the viewBox scales with the page) */
.paper__reveal-line--1 {
  font-size: 46px;
}

.paper__reveal-line--2 {
  font-size: 58px;
}

.paper__reveal--active .paper__reveal-line--1 {
  animation:
    ink-draw 1.3s cubic-bezier(0.4, 0, 0.2, 1) forwards,
    ink-fill 0.9s ease 0.85s forwards;
}

.paper__reveal--active .paper__reveal-line--2 {
  animation:
    ink-draw 1.3s cubic-bezier(0.4, 0, 0.2, 1) 0.35s forwards,
    ink-fill 0.9s ease 1.2s forwards;
}

@keyframes ink-draw {
  from { stroke-dashoffset: 1; }
  to   { stroke-dashoffset: 0; }
}

@keyframes ink-fill {
  from { fill: transparent; }
  to   { fill: #33281C; }
}

/* Hint text at bottom */
.paper__hint {
  position: absolute;
  bottom: 2rem;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-family: 'Inter', -apple-system, sans-serif;
  font-size: clamp(0.75rem, 1.5vw, 0.875rem);
  font-weight: 400;
  color: #9C9288;
  letter-spacing: 0.06em;
  opacity: 0;
  transition: opacity 1.2s ease;
}

.paper__hint--visible {
  opacity: 1;
}

.paper__hint-arrow {
  display: inline-block;
  animation: hint-pulse 2s ease-in-out infinite;
}

@keyframes hint-pulse {
  0%, 100% {
    transform: translateX(0);
    opacity: 0.5;
  }
  50% {
    transform: translateX(-4px);
    opacity: 1;
  }
}

/* Paper at final state — a physical sheet resting inside the viewport.
   The JS drives the FLIP transition inline; this class sets the same
   fluid sheet sizing so the resting state is consistent everywhere.
   (Milestone 4.2 — never edge-to-edge: 12–20px gutters on phones,
   generous centred margins on desktop.) */
.paper--final {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  margin: auto;
  /* The reading sheet rests in the viewport like a page in a book — a
     generous, fluid margin from every screen edge (the sheet is an
     object, never a fullscreen background). On phones that is ~20-24px
     per side, growing steadily to generous desktop margins. */
  width: min(calc(100vw - 2 * clamp(20px, 6vw, 64px)), 1080px);
  height: min(calc(100vh - 2 * clamp(12px, 3.5vh, 76px)), 1280px);
  height: min(calc(100dvh - 2 * clamp(12px, 3.5vh, 76px)), 1280px);
  transform: none;
  transform-origin: top left;
  z-index: 400;
  pointer-events: none;
}

.paper--final .paper__body {
  /* The letter becomes the page — still a physical sheet resting in the
     viewport: rounded corners, the precision-cut edge and a soft resting
     shadow carry over from the envelope phase, plus a gentle lit-paper
     vignette so it reads as paper under light, never a flat fill. */
  /* The same stack the reading sheets carry — the cardstock rim first,
     so the cover-phase paper and the sheets hand off seamlessly. */
  box-shadow:
    1px 2.5px 0 0 rgba(214, 196, 162, 0.5),
    0 2px 5px rgba(70, 45, 20, 0.18),
    0 16px 40px rgba(70, 45, 20, 0.16),
    inset 0 1px 0 rgba(255, 255, 255, 0.9),
    inset 0 -1px 0 rgba(180, 150, 105, 0.15),
    inset 0 0 120px rgba(180, 150, 105, 0.06);
}

.paper--final .paper__edge {
  /* the cardstock thickness stays — the sheet has a real edge at rest */
}

.paper--final .paper__content {
  padding: clamp(2.5rem, 8vw, 5rem) clamp(1.5rem, 5vw, 3.5rem);
}

.paper--final .paper__title {
  font-size: clamp(1.5rem, 4.5vw, 3.25rem);
}

.paper--final .paper__title-sub {
  font-size: clamp(0.6rem, 1.3vw, 0.85rem);
}

/* While reading, the long sheet IS the paper — it carries the material,
   the rounded corners, the resting shadow and the cardstock edge, and
   the whole object scrolls together as one physical sheet (never a
   fixed frame with words sliding behind it). The envelope-phase body
   and its frame hand over the moment the first sheet appears, so
   nothing is doubled and nothing stays still while the paper moves. */
.paper--started .paper__body {
  background: none;
  border: none;
  border-radius: 0;
  box-shadow: none;
}

.paper--started .paper__edge {
  display: none;
}

/* The reading sheet rests on the desk — a soft ambient shadow behind the
   whole paper window gives the book-like depth of a sheet lying under
   warm light. It bleeds past the sheet onto the wood; on phones it
   simply fades before the screen edge. The class only appears once
   reading starts (never during the drag or FLIP), so its box-shadow
   transition cannot affect the expansion. */
.paper--started.paper--final {
  box-shadow:
    0 26px 70px rgba(70, 45, 20, 0.32),
    0 10px 26px rgba(70, 45, 20, 0.2);
  transition:
    opacity 0.7s ease,
    transform 0.9s cubic-bezier(0.25, 0.8, 0.3, 1.06),
    box-shadow 0.6s ease;
}


/* ============================================
   State transitions
   ============================================ */

html.is-experiencing,
html.is-experiencing body {
  overflow: hidden;
  height: 100%;
  overscroll-behavior: none;
  touch-action: none;
}

/* Prevent iOS text selection / callouts during the experience */
html.is-experiencing body {
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}


/* ============================================
   Reduced motion
   ============================================ */

@media (prefers-reduced-motion: reduce) {
  .envelope {
    animation: none;
  }

  .desk__particle {
    display: none;
  }

  .envelope__flap {
    transition-duration: 0.5s;
  }

  .envelope__mouth-panel {
    transition-duration: 0.2s;
  }

  .experience__loading-text {
    animation: none;
  }

  .paper__hint-arrow {
    animation: none;
  }

  /* Match the 15% timing scale used in JS (anim()) */
  .experience__dissolve {
    transition-duration: 0.25s;
  }

  .experience__stage {
    transition-duration: 0.2s;
  }

  .paper__hint {
    transition-delay: 0s;
    transition-duration: 0.3s;
  }

  .paper {
    transition: opacity 0.15s ease, transform 0.15s ease;
  }

  .paper__content {
    transition-duration: 0.3s;
  }

  .paper__reveal--active .paper__reveal-line {
    animation: none;
    stroke-dashoffset: 0;
    fill: #33281C;
  }
}


/* ============================================
   Mobile adjustments
   ============================================ */

@media (max-width: 480px) {
  .envelope {
    width: 86vw;
  }

  .paper__title {
    font-size: clamp(0.875rem, 3.4vw, 1.15rem);
  }

  .paper__title-sub {
    font-size: 0.5rem;
    letter-spacing: 0.18em;
  }

  .paper--final .paper__title {
    font-size: clamp(1.375rem, 6vw, 2.25rem);
  }

  .paper--final .paper__title-sub {
    font-size: 0.6rem;
  }

  .paper__hint {
    bottom: calc(1.25rem + env(safe-area-inset-bottom, 0px));
  }
}
