/* =============================================================================
 * Opener, Enchanted Forest
 * Loaded conditionally when payload.envelope is true. Two styles live in this
 * one file, picked by payload.envelope_style and rendered as mutually exclusive
 * markup in template.hbs, so only one of .style-classic / .style-seal is ever
 * in the DOM at once:
 *   .style-classic  the original drawn envelope (flap, vine SVGs, wax glyph,
 *                    "Tap to open"), every rule below is copied unchanged
 *                    from the pre-port envelope.css, only re-scoped under
 *                    .style-classic so it can share a file with .style-seal
 *                    without its class names (.envelope, .envelope-seal, ...)
 *                    colliding with the seal markup's identical class names.
 *   .style-seal      the photographic wax-seal still, ported from Obsidian
 *                    Vow (OPENER-FIX-NOTES.md, 2026-09-05) and re-tokened to
 *                    Enchanted Forest's own fonts, gold and dark tokens. No
 *                    Italiana, Jost, wine-red or gunmetal anywhere below.
 *
 * JS contract (site.js, unchanged): #envelope-reveal, click anywhere adds
 * .opening, sessionStorage remembers, node removed after 1500ms.
 * body.envelope-active, scroll lock while the opener is up, and (style-seal
 * only) the signal the founders bar hold-back below keys off.
 * ============================================================================= */

body.envelope-active {
  overflow: hidden;
}

/* Shared between both styles: identical keyframes in the pre-port classic
   file and in the OV seal file, so defined once instead of twice. */
@keyframes reveal-fade {
  0%   { opacity: 1; }
  100% { opacity: 0; pointer-events: none; }
}
@keyframes cta-fade-in {
  to { opacity: 1; }
}

/* =============================================================================
   CLASSIC, the drawn envelope. Every declaration below is unchanged from the
   pre-port file; only the selectors gained a ".style-classic" scope so this
   file can hold both styles without their shared class names colliding.
   ============================================================================= */

.envelope-reveal.style-classic {
  position: fixed;
  inset: 0;
  z-index: 9999;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--pitch);
  background: radial-gradient(ellipse at center, var(--moss-deep) 0%, var(--pitch) 70%);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

/* ── Envelope container ──────────────────────────────────── */
.style-classic .envelope {
  position: relative;
  width: 380px;
  max-width: 90vw;
  aspect-ratio: 5 / 3.5;
  perspective: 800px;
}

/* ── Envelope body ───────────────────────────────────────── */
.style-classic .envelope-body {
  position: absolute;
  inset: 0;
  background: var(--moss-deep);
  border-radius: 4px;
  box-shadow:
    0 4px 30px rgba(0, 0, 0, 0.5),
    inset 0 0 0 1px var(--rule);
  overflow: hidden;
}

/* Vine accent border */
.style-classic .envelope-body::before {
  content: '';
  position: absolute;
  inset: 8px;
  border: 1px solid var(--rule);
  border-radius: 2px;
  pointer-events: none;
}

/* Corner vine accents */
.style-classic .envelope-body::after {
  content: '';
  position: absolute;
  inset: 0;
  background:
    radial-gradient(ellipse at 0 0, rgba(209, 178, 140, 0.08) 0%, transparent 40%),
    radial-gradient(ellipse at 100% 100%, rgba(209, 178, 140, 0.08) 0%, transparent 40%);
  pointer-events: none;
}

/* ── Envelope flap (triangle) ────────────────────────────── */
.style-classic .envelope-flap {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 55%;
  transform-origin: top center;
  transform: rotateX(0deg);
  z-index: 3;
  transition: transform 0.5s cubic-bezier(0.4, 0, 0.2, 1);
}

.style-classic .envelope-flap-face {
  position: absolute;
  inset: 0;
  background: var(--moss-mid);
  clip-path: polygon(0 0, 100% 0, 50% 100%);
  border-radius: 4px 4px 0 0;
}

/* Inner side of flap (visible when opening) */
.style-classic .envelope-flap-inner {
  position: absolute;
  inset: 0;
  background: var(--moss-deep);
  clip-path: polygon(0 0, 100% 0, 50% 100%);
  transform: rotateX(180deg);
  backface-visibility: hidden;
}

/* ── Wax seal ────────────────────────────────────────────── */
.style-classic .envelope-seal {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 4;
  width: 64px;
  height: 64px;
  border-radius: 50%;
  background: var(--gold);
  box-shadow:
    0 2px 8px rgba(0, 0, 0, 0.4),
    inset 0 1px 2px rgba(255, 255, 255, 0.2),
    inset 0 -1px 2px rgba(0, 0, 0, 0.2);
  display: flex;
  align-items: center;
  justify-content: center;
  animation: seal-shimmer 2.5s ease-in-out infinite;
}

.style-classic .envelope-seal-text {
  font-family: var(--ff-display);
  font-size: 18px;
  color: var(--moss-deep);
  letter-spacing: 2px;
  font-style: italic;
}

@keyframes seal-shimmer {
  0%, 100% { box-shadow: 0 2px 8px rgba(0, 0, 0, 0.4), inset 0 1px 2px rgba(255, 255, 255, 0.2); }
  50% { box-shadow: 0 2px 12px rgba(209, 178, 140, 0.4), inset 0 1px 4px rgba(255, 255, 255, 0.35); }
}

/* ── Invitation card ─────────────────────────────────────── */
.style-classic .envelope-card {
  position: absolute;
  left: 8%;
  right: 8%;
  bottom: 10%;
  top: 15%;
  background: var(--bone);
  border-radius: 2px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 24px 16px;
  z-index: 1;
  transform: translateY(0);
  opacity: 1;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.2);
}

.style-classic .envelope-card-names {
  font-family: var(--ff-display);
  font-size: 28px;
  color: var(--moss-deep);
  line-height: 1.2;
  margin-bottom: 8px;
}

.style-classic .envelope-card-amp {
  font-family: var(--ff-editorial);
  font-size: 22px;
  color: var(--gold-deep);
  display: block;
  margin: 2px 0;
}

.style-classic .envelope-card-date {
  font-family: var(--ff-body);
  font-weight: var(--fw-body);
  font-size: 12px;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--moss-deep);
  margin-top: 4px;
}

.style-classic .envelope-card-cta {
  font-family: var(--ff-body);
  font-weight: var(--fw-body);
  font-size: 10px;
  letter-spacing: 3px;
  text-transform: uppercase;
  color: #0C100E;
  font-weight: 600;
  margin-top: 16px;
  opacity: 0;
  animation: cta-fade-in 1s ease 1s forwards;
}

/* Gold vine SVG decorations on envelope */
.style-classic .envelope-vine {
  position: absolute;
  pointer-events: none;
  z-index: 2;
  opacity: 0.15;
}
.style-classic .envelope-vine--left {
  left: 6px;
  top: 20%;
  bottom: 20%;
  width: 20px;
}
.style-classic .envelope-vine--right {
  right: 6px;
  top: 20%;
  bottom: 20%;
  width: 20px;
  transform: scaleX(-1);
}

/* ── Opening animation ───────────────────────────────────── */
.envelope-reveal.style-classic.opening .envelope-seal {
  animation: seal-crack 0.3s cubic-bezier(0.4, 0, 0.2, 1) forwards;
}

@keyframes seal-crack {
  0% { transform: translate(-50%, -50%) scale(1); opacity: 1; }
  100% { transform: translate(-50%, -50%) scale(1.3); opacity: 0; }
}

.envelope-reveal.style-classic.opening .envelope-flap {
  animation: flap-open 0.5s cubic-bezier(0.4, 0, 0.2, 1) 0.2s forwards;
}

@keyframes flap-open {
  0% { transform: rotateX(0deg); }
  100% { transform: rotateX(-180deg); }
}

.envelope-reveal.style-classic.opening .envelope-card {
  animation: card-slide 0.6s cubic-bezier(0.4, 0, 0.2, 1) 0.5s forwards,
             card-expand 0.5s cubic-bezier(0.4, 0, 0.2, 1) 0.9s forwards;
}

@keyframes card-slide {
  0% { transform: translateY(0); }
  100% { transform: translateY(-80%); }
}

@keyframes card-expand {
  0% { transform: translateY(-80%) scale(1); }
  100% { transform: translateY(-80%) scale(3); opacity: 0; }
}

.envelope-reveal.style-classic.opening {
  animation: reveal-fade 0.5s cubic-bezier(0.4, 0, 0.2, 1) 1.1s forwards;
}

/* ── Accessibility ───────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  .envelope-reveal.style-classic.opening .envelope-seal,
  .envelope-reveal.style-classic.opening .envelope-flap,
  .envelope-reveal.style-classic.opening .envelope-card,
  .envelope-reveal.style-classic.opening {
    animation-duration: 0.01s !important;
    animation-delay: 0s !important;
  }
}

/* =============================================================================
   SEAL, photographic wax-seal still, ported from Obsidian Vow's envelope.css
   (OPENER-FIX-NOTES.md, 2026-09-05). Geometry math is identical to OV's; only
   the wax fraction constants and every color/font token are Enchanted Forest's
   own. assets/opener-seal.jpg is 1600x1600; the wax (rim + shadow) measured at
   rows 0.3725-0.5825 of the frame (outputs/images/wedding-opener/NOTES.md,
   enchanted-forest v3), vs. OV's own still at 0.385-0.571, different enough
   (21.0% of the frame tall here, vs 18.6% on OV) that the fraction is a
   variable, not a hardcoded 0.385/0.571 copy-paste.
   ============================================================================= */

.envelope-reveal.style-seal {
  position: fixed;
  inset: 0;
  z-index: 9999;
  display: flex;
  align-items: stretch;
  justify-content: center;
  background: var(--pitch);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  overflow: hidden;

  /* ── Geometry (see OPENER-FIX-NOTES.md §2.1 for the derivation) ──
     --seal-frac-top / --seal-frac-h are THIS theme's measured wax box, read
     off assets/opener-seal.jpg. Everything else is the same formula OV uses. */
  --seal-frac-top: 0.3725;
  --seal-frac-h: 0.2100;
  --seal-anchor: 0.52;   /* shared aesthetic choice across all three ported themes, not measured */

  /* Revision 2, 2026-09-10: realm-font sizing for the monogram and names line.
     --seal-mono-fs replaces the old flat 22px monogram size (see PORT-NOTES.md
     "Revision 2" for the display-serif rationale); --seal-group-h below now
     reads it back instead of a hardcoded 22px so the group-height estimate
     stays correct at the new, larger size. --seal-mono-ls / --seal-names-ls
     are display-serif letter-spacing, deliberately tighter than the
     sans-serif --tr-ultra (0.52em) tracking the monogram and names line used
     before, with a matching padding-left so the trailing tracked space after
     the last glyph doesn't read as off-centre. */
  --seal-mono-fs: clamp(32px, calc(var(--seal-vh) * 0.05), 48px);
  --seal-mono-ls: 0.08em;
  --seal-names-ls: 0.28em;

  --seal-vh: 100vh;
  --seal-date-h: 20px;
  --seal-names-top: clamp(24px, calc(var(--seal-vh) * 0.06), 64px);
  --seal-gap: clamp(28px, calc(var(--seal-vh) * 0.05), 48px);
  --seal-line-gap: clamp(12px, calc(var(--seal-vh) * 0.024), 22px);
  --seal-pad-below: clamp(16px, calc(var(--seal-vh) * 0.03), 28px);
  --seal-pad: 24px;
  --seal-cta-h: 49px;
  --seal-group-h: calc(var(--seal-mono-fs) + 2 * var(--seal-line-gap) + 1px + var(--seal-date-h) + var(--seal-pad-below) + var(--seal-cta-h));
  --seal-min: calc(var(--seal-names-top) + 28px);
  --seal-S: min(max(100vw, var(--seal-vh)), calc((var(--seal-vh) - var(--seal-min) - var(--seal-gap) - var(--seal-group-h) - var(--seal-pad)) / var(--seal-frac-h)));
  --seal-h: calc(var(--seal-S) * var(--seal-frac-h));
  --seal-edge: clamp(0px, calc((100vw - var(--seal-S)) * 4), 120px);
  --seal-natural: calc(var(--seal-vh) * var(--seal-anchor) - var(--seal-S) * (var(--seal-anchor) - var(--seal-frac-top)));
  --seal-max: calc(var(--seal-vh) - var(--seal-h) - var(--seal-gap) - var(--seal-group-h) - var(--seal-pad));
  --seal-top: clamp(var(--seal-min), var(--seal-natural), var(--seal-max));
  --seal-group-top: calc(var(--seal-top) + var(--seal-h) + var(--seal-gap));
}
@supports (height: 100svh) {
  .envelope-reveal.style-seal { --seal-vh: 100svh; }
}
@media (max-width: 600px) {
  .envelope-reveal.style-seal { --seal-date-h: 40px; }
}

/* ── The seal still: centred square, seal top pinned at --seal-top, breathes slowly ── */
.style-seal .envelope-still {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
}

/* Placeholder, 2026-09-11 (PRELOAD-NOTES.md "Placeholder" section): a small,
   unblurred copy of this theme's own opener-seal.jpg, baked in as a data URI on
   a dedicated ::before layer so it paints with the container itself, no network
   round trip. Positioned with `left`/`top` using the EXACT same --seal-S /
   --seal-top / --seal-frac-top formula the sharp <img> below uses (a plain
   position property, not `background-position`), so the placeholder sits in
   precisely the box the photo will land in and the sharp image, once loaded,
   covers it edge-to-edge with no shift.
   NOTE: an earlier draft set this same image/geometry as a `background-image`
   directly on `.envelope-still` using `background-position: calc(50% - S/2) ...`.
   That produced a hard vertical seam covering only the left ~50% of the box on
   every theme and viewport (confirmed with a plain, unblurred test gradient
   image: identical seam, so it was not photo content). Root cause isolated to
   Chromium's `background-position` percentage-resolution path specifically,
   not `left`/`top`: replacing `calc(50% - 406px)`-style background-position
   with the equivalent plain `left: calc(50% - S/2)` on this ::before element
   (the same pattern the <img> two rules down already uses successfully)
   eliminated the seam completely in a controlled test (isolate_gradient*.html /
   diagnose_seam.py, session scratchpad). `background-size: 100% 100%` here is
   a normal same-box percentage (fills its own already-correctly-sized box),
   an unrelated, unaffected code path.
   `filter: blur()` is scoped to this pseudo-element only, not `.envelope-still`
   itself, so it never touches the real <img> (a sibling-in-paint-order, not a
   descendant of ::before): the browser's own smooth (non-pixelated) upscaling
   plus this light blur is what reads as "soft", while the baked image itself
   stays unblurred so the seal's own colour and shape survive recognisably. */
.style-seal .envelope-still::before {
  content: '';
  position: absolute;
  z-index: 0;
  width: var(--seal-S);
  height: var(--seal-S);
  left: calc(50% - var(--seal-S) / 2);
  top: calc(var(--seal-top) - var(--seal-S) * var(--seal-frac-top));
  background-image: url("data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAoHCAkIBgoJCAkMCwoMDxoRDw4ODx8WGBMaJSEnJiQhJCMpLjsyKSw4LCMkM0Y0OD0/QkNCKDFITUhATTtBQj//2wBDAQsMDA8NDx4RER4/KiQqPz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz//wAARCAAoACgDASIAAhEBAxEB/8QAGgABAAMBAQEAAAAAAAAAAAAAAAMEBQIGB//EACgQAAEEAAUDAwUAAAAAAAAAAAEAAgMREiExQVEEEyIFYXEUQoGR0f/EABcBAAMBAAAAAAAAAAAAAAAAAAABAgP/xAAaEQEBAQADAQAAAAAAAAAAAAAAAQIREjED/9oADAMBAAIRAxEAPwD5LFZdkFfhBa4Fwwg6BUmSiMUwW732VmGWSfBE6nYjQJFV+eEtIjXg6t0T2lryYzxlaqde8Et7dktbndfpRta6N9TMa7VoZqOLXcsXZjDS2rFgnyP8WcklVbbGbKwWbsIpAT5FjbJ+47ItohXjGetDlacJZCwNecYkBugMuFlXhOtqxD1AiFtFOvxPCnU5OPbzeselt9CMbHYXiHB9L2ySH83pW92vJOt8Xdc6R1EYnVvsK2VU9U4kFxLnA6k5BQuneQ4YiMWoByPypx8+ni9b7eupZb8awjf3+UULnFxtxsotUcObREQZaIiAIiID/9k=");
  background-size: 100% 100%;
  background-repeat: no-repeat;
  filter: blur(6px);
  transform: scale(1.04); /* offsets the blur filter's own edge fade, so no thin dim ring shows at this box's own edge */
}
.style-seal .envelope-still img {
  position: absolute;
  width: var(--seal-S);
  height: var(--seal-S);
  max-width: none;
  max-height: none;
  left: calc(50% - var(--seal-S) / 2);
  top: calc(var(--seal-top) - var(--seal-S) * var(--seal-frac-top));
  object-fit: cover;
  -webkit-mask-image: linear-gradient(to right, transparent, #000 var(--seal-edge), #000 calc(100% - var(--seal-edge)), transparent);
  mask-image: linear-gradient(to right, transparent, #000 var(--seal-edge), #000 calc(100% - var(--seal-edge)), transparent);
  transform-origin: 50% calc((var(--seal-frac-top) + var(--seal-frac-h) / 2) * 100%);
  animation: seal-breathe 9s ease-in-out infinite alternate;
  will-change: transform;
}
@keyframes seal-breathe {
  from { transform: scale(1); }
  to   { transform: scale(1.02); }
}

/* Heavy radial vignette + bottom fade, matching the mock. */
.style-seal .envelope-vignette {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background:
    radial-gradient(60% 70% at 50% 50%, rgba(12,16,14,0) 30%, rgba(12,16,14,0.92) 100%),
    linear-gradient(0deg, rgba(12,16,14,0.9) 0%, rgba(12,16,14,0) 42%);
}

/* ── Type column: names line pinned at the top, the group padded down from the seal ── */
.style-seal .envelope {
  position: relative;
  z-index: 2;
  width: 100%;
  max-width: 100vw;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  text-align: center;
  padding: var(--seal-group-top) 24px 0;
  pointer-events: none;
}

.style-seal .envelope-card-names {
  position: absolute;
  top: var(--seal-names-top);
  left: 24px;
  right: 24px;
  font-family: var(--ff-display);
  font-weight: 300;
  font-size: 11px;
  letter-spacing: var(--seal-names-ls);
  text-transform: uppercase;
  color: var(--bone);
  padding-left: var(--seal-names-ls);
}
.style-seal .envelope-card-amp { display: inline; }

.style-seal .envelope-seal {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--seal-line-gap);
  margin-top: 0;
  padding-top: 0;
  padding-bottom: var(--seal-pad-below);
}
.style-seal .envelope-seal-text {
  /* The hero of the screen: IvyPresto Display, larger than the pre-revision
     22px flat size and tracked for a display serif rather than the ultra-wide
     sans-serif eyebrow spacing this shared with the names line before. */
  font-family: var(--ff-display);
  font-size: var(--seal-mono-fs);
  letter-spacing: var(--seal-mono-ls);
  padding-left: var(--seal-mono-ls);
  color: var(--bone);
  line-height: 1;
}
.style-seal .envelope-seal-rule {
  width: 32px;
  height: 1px;
  background: var(--gold);
}
.style-seal .envelope-card-date {
  font-family: var(--ff-display);
  font-weight: 300;
  font-size: 11px;
  letter-spacing: var(--tr-wide);
  text-transform: uppercase;
  color: var(--parchment);
  padding-left: var(--tr-wide);
  line-height: 1.8;
}

/* Outlined "break the seal": 1px, tracked caps, no fill, the whole overlay is the
   click target; this is the affordance, not the only hit area. */
.style-seal .envelope-card-cta {
  font-family: var(--ff-display);
  font-weight: 300;
  font-size: 11px;
  letter-spacing: 0.44em;
  padding: 14px 30px 14px calc(30px + 0.44em);
  text-transform: uppercase;
  color: var(--parchment);
  border: 1px solid var(--rule-bright);
  opacity: 0;
  animation: cta-fade-in 1s ease 0.9s forwards;
  transition: color 0.4s, border-color 0.4s;
}
.envelope-reveal.style-seal:hover .envelope-card-cta { color: var(--bone); border-color: var(--gold); }

/* ── Founders banner hold (demo only; the bar and its dismiss logic live in
   template.hbs). While the seal opener is up, the fixed bottom bar is held
   off-screen and invisible; when site.js removes body.envelope-active (1500ms
   after the click) the bar's own .tb-fb-visible rule takes over and it slides
   in on its own transition. Scoped to .style-seal only: the classic envelope
   never held the bar back before this port and keeps not doing so, since
   changing that would not be byte-identical to today's classic rendering. ── */
body.envelope-active:has(.envelope-reveal.style-seal) #tb-founders-banner {
  visibility: hidden;
  opacity: 0;
  transform: translateY(100%);
  transition: none;
}

/* ── Opening: the seal scales up and dissolves into the hero ── */
.envelope-reveal.style-seal.opening .envelope-still img {
  animation: seal-break 1.2s cubic-bezier(0.4, 0, 0.2, 1) forwards;
}
@keyframes seal-break {
  0%   { transform: scale(1.02); filter: brightness(1); }
  100% { transform: scale(1.32); filter: brightness(1.6) blur(6px); }
}
.envelope-reveal.style-seal.opening .envelope {
  animation: type-dissolve 0.6s ease forwards;
}
@keyframes type-dissolve {
  to { opacity: 0; transform: translateY(-12px); }
}
.envelope-reveal.style-seal.opening {
  animation: reveal-fade 0.7s cubic-bezier(0.4, 0, 0.2, 1) 0.6s forwards;
}

@media (max-width: 480px) {
  .envelope-reveal.style-seal { --seal-cta-h: 45px; }
  .style-seal .envelope-card-names { font-size: 10px; letter-spacing: 0.22em; padding-left: 0.22em; }
  /* No fixed font-size override here any more: --seal-mono-fs's own clamp()
     already floors the monogram at 32px, larger than the pre-revision 20px
     mobile override, so this breakpoint doesn't need to shrink it further. */
  .style-seal .envelope-card-date { font-size: 10px; letter-spacing: 0.32em; padding-left: 0.32em; }
  .style-seal .envelope-card-cta { font-size: 10px; letter-spacing: 0.36em; padding: 13px 22px 13px calc(22px + 0.36em); }
}

/* ── Accessibility ── */
@media (prefers-reduced-motion: reduce) {
  .style-seal .envelope-still img { animation: none; }
  .style-seal .envelope-card-cta { animation: none; opacity: 1; }
  .envelope-reveal.style-seal.opening .envelope-still img,
  .envelope-reveal.style-seal.opening .envelope,
  .envelope-reveal.style-seal.opening {
    animation-duration: 0.01s !important;
    animation-delay: 0s !important;
  }
}
