.envelope-intro{display:none}
@media(prefers-reduced-motion:no-preference){
 .envelope-enabled .envelope-intro{display:block;height:145svh;position:relative;background:var(--paper)}
 /* Large-viewport height: the stage does not resize (and recentre) when the mobile address bar collapses mid-scroll. */
 .envelope-stage{position:fixed;inset:0;z-index:50;height:100vh;height:100lvh;display:grid;place-items:center;overflow:hidden;background:radial-gradient(ellipse at 50% 55%,#fffdf4 0%,#fff6e5 65%,#f8e8ce 100%);perspective:1600px;contain:layout paint}
 /* The caption hangs from the envelope's top edge (its bottom sits --cap-gap above it), so the two stay together on every viewport. */
 .opening-caption{position:absolute;top:calc(var(--env-cy) - var(--env-w)/3.2 - var(--cap-gap));transform:translateY(-100%);left:20px;right:20px;text-align:center;pointer-events:none}
 /* Only transform and opacity are animated, and only these elements are promoted while the envelope is opening. */
 .envelope-opening .envelope-back,.envelope-opening .envelope-pocket,.envelope-opening .envelope-flap,.envelope-opening .envelope-seal,.envelope-opening .opening-caption,.envelope-opening .page-sleeve{will-change:transform,opacity}
 .envelope-opening .opening-frame,.envelope-opening .page-frame,.envelope-opening .page-card{will-change:opacity}
 .opening-caption .eyebrow{font-size:.8rem;color:var(--rose)}
 .opening-instruction{font-family:var(--serif);font-size:clamp(1.6rem,3vw,2.2rem);margin-top:9px;color:var(--emerald)}
 /* Centred on the small viewport (--env-cy = 50svh), not on the 100lvh stage, so it is centred in what is actually visible and never moves when the address bar collapses. */
 .envelope-object{position:absolute;top:var(--env-cy);left:50%;width:var(--env-w);aspect-ratio:1.6;transform:translate(-50%,-50%);perspective:1400px;isolation:isolate}
 .envelope-back{position:absolute;inset:0;border-radius:5px;background:#70132f;box-shadow:0 30px 60px #5012242b,0 3px 8px #50122430}
 .envelope-pocket{position:absolute;inset:0;z-index:4;filter:drop-shadow(0 -1px 0 #ffffff20)}
 .pocket-left,.pocket-right,.pocket-front{position:absolute;inset:0;border-radius:4px}
 .pocket-left{background:linear-gradient(130deg,#a62b55,#902047);clip-path:polygon(0 0,56% 57%,0 100%)}
 .pocket-right{background:linear-gradient(230deg,#ad315b,#8f1e43);clip-path:polygon(100% 0,44% 57%,100% 100%)}
 .pocket-front{background:linear-gradient(180deg,#bd4269,#98234b);clip-path:polygon(0 100%,0 98%,50% 43%,100% 98%,100% 100%)}
 .envelope-flap{position:absolute;inset:0 0 36%;z-index:5;transform-origin:50% 0;will-change:transform}
 .flap-face{position:absolute;inset:0;background:linear-gradient(180deg,#ae365d,#882044);clip-path:polygon(0 0,100% 0,50% 94%);filter:drop-shadow(0 3px 3px #49122566)}
 .envelope-seal{position:absolute;z-index:6;top:45%;left:50%;width:65px;height:65px;display:flex;align-items:center;justify-content:center;border-radius:50%;background:linear-gradient(135deg,#f2d797,#c89440);color:#6b1b31;border:4px double #a46c28;box-shadow:0 4px 10px #5012244d;font-family:var(--serif);font-size:1.5rem;letter-spacing:-.08em;transform:translate(-50%,-30%)}
 .envelope-seal span{font-style:italic;font-size:1.1rem;margin:0 1px}
 @media(max-width:700px){.envelope-seal{width:48px;height:48px;font-size:1.15rem;border-width:3px}.envelope-seal span{font-size:.9rem}.opening-caption .eyebrow{font-size:.75rem}}
 @media(max-height:540px) and (min-width:701px){.opening-instruction{font-size:1.4rem}}
}
.site-letter{background:var(--paper)}
.envelope-enabled{overflow-anchor:none}
.envelope-intro.is-complete .envelope-stage{display:none}
/* The sleeve carries the composited transform (set inline per frame); the page inside keeps its natural height and is
   clipped with clip-path, so growing it costs no layout. The empty .page-frame carries the outline and shadow, fading out. */
.page-sleeve{display:none}
.envelope-opening .page-sleeve{display:block;position:absolute;top:0;left:50%;width:100%;z-index:2;transform-origin:50% 0;transform:translateX(-50%) scale(.4);pointer-events:none}
.envelope-opening .page-frame{position:absolute;top:0;left:0;width:100%;height:0;outline:6px solid var(--paper);box-shadow:0 8px 28px rgb(41 19 33 / .2);pointer-events:none}
.envelope-opening .site-letter.is-extracting{position:relative;width:100%;max-width:none;overflow:hidden;pointer-events:none}
/* Name card shown on the rising page. Authored at viewport size (the sleeve's scale shrinks it with the page) and faded with opacity only. */
.page-card{display:none}
.envelope-opening .page-card{display:block;position:absolute;top:0;left:0;width:100%;height:0;box-sizing:border-box;overflow:hidden;padding:min(5vw,6vh) 6vw 0;background:linear-gradient(180deg,#fffaf0,#fff6e5);color:#9e2350;font-family:var(--serif);text-align:center;pointer-events:none}
.envelope-opening .page-card::before{content:'';position:absolute;inset:min(3vw,26px);border:1px solid #c89440;outline:1px solid #b58b38;outline-offset:-5px;pointer-events:none}
.page-card .card-names{margin:0;font-size:clamp(2.2rem,11vw,9rem);font-weight:500;line-height:1.1;letter-spacing:.01em;white-space:nowrap}
.page-card i{font-style:italic;font-weight:400;color:#c89440}
.page-card .card-names i{font-size:.82em;margin:0 .12em}
.page-card .card-mark{display:inline-flex;align-items:center;gap:.6em;margin-top:min(2.5vw,3vh);font-size:clamp(.8rem,3.4vw,2.6rem);letter-spacing:.14em;color:#b58b38}
.page-card .card-mark::before,.page-card .card-mark::after{content:'';width:3em;height:1px;background:linear-gradient(90deg,#c8944000,#b58b38)}
.page-card .card-mark::after{background:linear-gradient(90deg,#b58b38,#c8944000)}
.envelope-opening .site-letter.is-extracting .site-header{position:relative}
@media print{.envelope-intro{display:none!important}.site-slot{height:auto!important}}

/* Letterpress-style ornamental frame. Every measure derives from --u (corner/200, the symbols' unit). Each rule is one continuous element along its whole edge
   (the outer rule is one rect round the frame) and the ornaments sit on top with cream fills, so nothing has to meet end-to-end. */
/* --env-w is the envelope width: capped so that, centred at --env-cy, it leaves room above for the crest (80u), the caption and --cap-gap.
   --env-w/3.2 is half its height (aspect 1.6). */
.envelope-stage{--corner:clamp(100px,13.5vw,184px);--u:calc(var(--corner)/200);--env-cy:50svh;--cap-gap:24px;--env-w:min(74vw,620px,(100svh - var(--u)*160 - 204px)*1.6)}
/* Flush with the screen: the pattern is the border. Sized to the small viewport (not the 100lvh stage) so the bottom rule and corners stay on screen above Safari's toolbar; the stage itself keeps its stable height. */
.opening-frame{position:absolute;top:0;left:0;right:0;height:100vh;height:100svh;pointer-events:none}
.opening-frame svg{position:absolute;display:block}
.frame-definitions{width:0;height:0;overflow:hidden}
/* Explicit sizes: an absolutely positioned svg is a replaced element, so left+right would be ignored in favour of its intrinsic (viewBox) width. */
.frame-rule,.frame-beads{z-index:1}
.rule-top,.rule-bottom{left:0;width:100%;height:calc(var(--u)*30)}
.rule-left,.rule-right{top:0;height:100%;width:calc(var(--u)*30)}
.beads-top,.beads-bottom{width:50%;height:calc(var(--u)*30)}
/* Side chains are one continuous element per edge, symmetric about the edge's midpoint (nothing covers a join there any more). */
.beads-left,.beads-right{top:0;height:100%;width:calc(var(--u)*30)}
.rule-top,.beads-top{top:0}.rule-bottom,.beads-bottom{bottom:0}.rule-left,.beads-left{left:0}.rule-right,.beads-right{right:0}
.rule-bottom{transform:scaleY(-1)}.rule-right,.beads-right{transform:scaleX(-1)}
/* Top/bottom bead halves: 'start' is anchored at the first corner of the edge, 'end' is its mirror image anchored at the other; they overlap under the crest. */
.beads-top.beads-start,.beads-bottom.beads-start{left:0}.beads-top.beads-end,.beads-bottom.beads-end{left:50%}
.beads-top.beads-end{transform:scaleX(-1)}.beads-bottom.beads-start{transform:scaleY(-1)}.beads-bottom.beads-end{transform:scale(-1,-1)}
.ornate-corner{width:var(--corner);height:var(--corner);z-index:2}
.corner-tl{top:0;left:0}.corner-tr{top:0;right:0;transform:scale(-1,1)}.corner-bl{bottom:0;left:0;transform:scale(1,-1)}.corner-br{bottom:0;right:0;transform:scale(-1,-1)}
.frame-centrepiece{left:50%;width:calc(var(--u)*300);height:calc(var(--u)*80);z-index:3;transform:translateX(-50%)}
.centre-top{top:0}.centre-bottom{bottom:0;transform:translateX(-50%) scaleY(-1)}
/* Outer rule above corners and crests (their cream fills start at its inner edge). Its stroke is centred on the screen edge, so the visible half starts at the very edge. */
.frame-outer{inset:0;width:100%;height:100%;z-index:4;overflow:hidden}
.frame-outer rect{stroke-width:calc(var(--u)*3.6)}
@media(max-width:700px){
  /* 28px from each screen edge to the envelope: the rail is ~14px deep (crimson line at 28.6u), leaving >=14px of clear cream beside it on a 320px phone. */
  .envelope-stage{--corner:92px;--cap-gap:28px;--env-w:min(100vw - 56px,(100svh - var(--u)*160 - 190px)*1.6)}
  /* At --u≈.46 the drawn strokes would fall to ~0.4px; keep them at their drawn CSS-px widths (hairlines .6–.9px, outer rule 1.8px) regardless of scale. */
  .frame-definitions path,.frame-definitions circle,.frame-definitions rect{vector-effect:non-scaling-stroke}
  .frame-outer rect{stroke-width:3.6px}
}
/* Short landscape: the envelope sits a little below centre so the caption fits between it and the crest. */
@media(max-height:540px) and (min-width:701px){.envelope-stage{--corner:92px;--env-cy:58svh;--cap-gap:20px;--env-w:min(420px,(116svh - var(--u)*160 - 166px)*1.6)}}
/* The live page stays visually identical when it leaves its envelope. */
.envelope-enabled.motion-ready .hero-photo,.envelope-enabled.motion-ready h1,.envelope-enabled.motion-ready .invitation-inner>.eyebrow,.envelope-enabled.motion-ready .hero-quote,.envelope-enabled.motion-ready .date-block,.envelope-enabled.motion-ready .invitation .button{animation:none!important}
.envelope-opening .hero-photo{transform:none!important}
.envelope-opening .hero-photo img{transform:scale(1.025)!important}
