@font-face{font-family:Cormorant;src:url('assets/cormorant.woff2') format('woff2');font-display:swap}@font-face{font-family:Cormorant;src:url('assets/cormorant-italic.woff2') format('woff2');font-display:swap;font-style:italic}@font-face{font-family:DM;src:url('assets/dm-sans.woff2') format('woff2');font-display:swap}@font-face{font-family:Caveat;src:url('assets/caveat.woff2') format('woff2');font-display:swap}
:root{--paper:#f7efdf;--ink:#542233;--rose:#a66272;--gold:#ae8652;--muted:#805663;--display:Cormorant,Georgia,serif;--body:DM,sans-serif}*{box-sizing:border-box}html{scroll-behavior:smooth;scrollbar-color:var(--rose) var(--paper)}body{margin:0;background:var(--paper);color:var(--ink);font-family:var(--body);font-size:16px}::selection{background:#d6a7ae;color:#331520}a{color:inherit}button{font:inherit;cursor:pointer}button:focus-visible,a:focus-visible{outline:2px solid var(--rose);outline-offset:7px}button:disabled{cursor:wait}h1,h2,p{margin:0}h1,h2{font-family:var(--display);font-weight:400}em{font-weight:400}.masthead{position:absolute;z-index:20;inset:0 0 auto;height:105px;padding:0 5.7%;display:flex;align-items:center;justify-content:space-between}.monogram{text-decoration:none;font-family:var(--display);font-size:28px}.monogram span{font-style:italic;font-size:20px;color:var(--rose);margin:0 3px}.date{font-size:14px;letter-spacing:.13em}.sound{display:flex;gap:9px;align-items:center;border:0;background:transparent;color:var(--ink);font-size:13px}.sound svg{width:19px;height:19px;stroke:currentColor;stroke-width:1.3;fill:none}.opening{min-height:100svh;position:relative;padding:145px 8% 115px;display:grid;grid-template-columns:1.12fr 1fr;align-items:center;overflow:hidden}.opening-copy{z-index:2}.dedication{font-family:Caveat,cursive;font-size:25px;margin-bottom:26px;color:var(--muted)}h1{font-size:clamp(64px,6.7vw,96px);line-height:.98;letter-spacing:-.035em}h1 em{color:var(--rose)}.opening-note{font-size:16px;line-height:1.8;margin-top:28px;color:var(--muted)}.open-letter{border:1px solid #b88f96;color:var(--ink);background:transparent;padding:18px 22px;display:flex;gap:32px;align-items:center;font-size:14px;margin-top:32px;transition:background .3s,color .3s}.open-letter:hover{background:var(--ink);color:var(--paper)}.open-letter svg{width:22px;height:22px;stroke:currentColor;stroke-width:1.3;fill:none}.signed{font-family:Caveat,cursive;font-size:25px;margin-top:25px}.opening-art{position:relative;align-self:stretch;min-height:480px}.opening-art img{position:absolute;width:135%;height:145%;top:-25%;left:-13%;object-fit:contain;mix-blend-mode:multiply}.art-caption{position:absolute;bottom:3%;left:5%;width:100%;text-align:center;font-family:Caveat,cursive;font-size:22px;transform:rotate(-5deg);color:var(--muted)}.opening-bottom{position:absolute;bottom:32px;left:5.7%;right:5.7%;display:flex;justify-content:space-between;font-size:12px;color:var(--muted);border-top:1px solid #d8c5b9;padding-top:20px}.opening-bottom a{text-decoration:none}.opening-bottom a span{margin-left:14px}.birthday{min-height:100vh;background:var(--ink);color:var(--paper);display:flex;align-items:center;justify-content:center;flex-direction:column;text-align:center;padding:80px 20px;gap:32px}.birthday h2{font-size:clamp(48px,7vw,96px);line-height:1.05}.birthday h2 em{color:#dcb2b8}.reading-progress{position:fixed;left:0;top:0;right:0;z-index:100;height:2px}.reading-progress span{display:block;width:0;height:100%;background:var(--rose)}@media(max-width:700px){.masthead{height:80px;padding:0 6%}.date{font-size:12px}.opening{padding:120px 8% 100px;display:flex;flex-direction:column;align-items:stretch}.opening-art{height:370px;min-height:0;margin-top:10px}.opening-art img{height:160%;top:-35%;width:100%;left:0}.art-caption{bottom:0;left:0}h1{font-size:64px}.opening-bottom>span{display:none}.opening-bottom{justify-content:center}.dedication{font-size:22px}.opening-note{margin-top:22px}}
/* A letter in rose, ink and ivory. */
body{overflow-x:clip}.sound{position:fixed;right:5.7%;top:38px;z-index:50;padding:8px 12px;background:var(--paper);border-radius:30px;box-shadow:0 3px 15px #54223308}.masthead{pointer-events:none}.masthead>*{pointer-events:auto}.masthead .date{position:absolute;left:50%;transform:translateX(-50%)}.opening-art img{mask-image:linear-gradient(to bottom,transparent,black 15%,black 80%,transparent)}.opening-bottom svg{width:17px;height:17px;stroke:currentColor;fill:none;stroke-width:1;vertical-align:middle;margin-left:12px}.opening-copy{transition:opacity .6s,transform .9s cubic-bezier(.16,1,.3,1)}.opening.opened .opening-copy{transform:translateY(-15px)}.script-note{font:28px Caveat,cursive}.scroll-scene{position:relative}.sticky{position:sticky;top:0;height:100svh;overflow:hidden}.birthday{display:block;height:190svh;padding:0;min-height:0}.birthday-inner{display:grid;place-items:center;padding:70px 24px}.birthday-content{position:relative;z-index:1}.birthday-date{font:clamp(300px,44vw,640px)/1 var(--display);position:absolute;opacity:.045;color:#ecc6b3;left:50%;top:50%;transform:translate(-50%,-50%);pointer-events:none}.birthday .script-note{color:#e3bdbd;margin-bottom:32px}.birthday h2{font-size:clamp(52px,6.8vw,96px)}.birthday-name{font:42px Caveat,cursive;margin-top:32px;color:#e2b1b9}.birthday-small{font-size:16px;line-height:1.9;color:#e6d0c7;margin-top:28px}.scene-foot{position:absolute;bottom:34px;left:0;right:0;text-align:center;font-size:13px;color:#d4b7b0}.reveal{transition:opacity .25s;will-change:opacity,transform}.story{height:220svh;background:#f0e3d2}.story-inner{padding:10vh 10%;display:grid;grid-template-columns:1fr 1fr;gap:11%;align-items:center}.story-title{align-self:center}.story h2,.moments h2,.letter-aside h2,.wish h2{font-size:clamp(48px,5.3vw,78px);line-height:1.03;letter-spacing:-.025em}.story h2 em,.moments h2 em,.letter-aside h2 em{color:var(--rose)}.story-title>p{margin-top:26px;font-size:16px;color:var(--muted);line-height:1.8}.story-thread{width:235px;height:200px;margin-top:20px;fill:none;stroke:var(--rose);stroke-width:1;opacity:.7}.story-beats{display:flex;flex-direction:column;gap:40px;padding-left:30px;border-left:1px solid #c8a6a5}.story-beat{position:relative;transition:opacity .3s,transform .3s}.beat-mark{position:absolute;width:7px;height:7px;background:var(--rose);border-radius:50%;left:-34px;top:8px}.beat-intro{font-family:Caveat;font-size:22px;color:var(--muted);margin-bottom:10px}.story h3{font:36px/1.04 var(--display);margin:0 0 12px}.story-beat>p:last-child{font-size:14px;color:var(--muted)}.story h3 em{color:#8c3e53}.moments{padding:115px 8% 130px;overflow:hidden}.moments-heading{text-align:center}.moments-heading>p{font-size:16px;color:var(--muted);margin-top:24px}.photo-spread{display:flex;justify-content:center;align-items:center;gap:45px;margin:80px auto 0;max-width:1020px;min-height:560px}.memory{width:320px;margin:0;padding:14px 14px 28px;background:#fffbf1;box-shadow:0 14px 38px #54223319;flex-shrink:0;will-change:transform}.photo-window{height:380px;overflow:hidden}.memory img{width:100%;height:100%;object-fit:cover;object-position:50% 61%}.memory-one{transform:rotate(-7deg) translateY(-15px)}.memory-two{transform:rotate(7deg) translateY(30px)}.memory figcaption{font:24px/1.15 Caveat;text-align:center;margin-top:20px}.between-photos{width:150px;flex-shrink:0;text-align:center;align-self:center}.between-photos span{font:26px Caveat;display:block;transform:rotate(-8deg)}.between-photos svg{width:130px;height:80px;stroke:var(--rose);fill:none;stroke-width:1.4;margin-top:15px}.letter-scene{height:440svh;background:#efe1d0}.letter-inner{display:grid;grid-template-columns:.75fr 1.65fr;gap:5%;padding:8vh 6%;align-items:center}.letter-aside{position:relative;max-width:350px}.letter-aside h2{font-size:clamp(40px,4.4vw,65px);position:relative;z-index:1}.letter-aside>img{display:block;width:92%;margin-top:25px;max-height:38vh;object-fit:contain;mix-blend-mode:multiply;mask-image:linear-gradient(transparent,black 10%,black 90%,transparent)}.letter-aside .script-note{font-size:23px;transform:rotate(-5deg);text-align:center;margin-top:10px}.letter-paper{background:#fffaf0;position:relative;box-shadow:0 18px 60px #54223310;padding:30px 26px 20px;transform:rotate(-1deg);max-width:900px;width:100%;isolation:isolate}.letter-to{font:30px Caveat;display:block;margin-left:5%;color:var(--muted)}.writing-stage{position:relative;aspect-ratio:840/600;width:100%}.writing-stage>svg{width:100%;height:100%;overflow:visible;display:none}.writing-stage.ready>svg{display:block}.writing-hand{position:absolute;width:48%;height:auto;max-width:none;pointer-events:none;z-index:5;opacity:0;filter:drop-shadow(3px 8px 5px #4a291426);transform-origin:15.15% 19.7%;will-change:left,top,transform}.letter-fallback{font:clamp(20px,2.2vw,32px)/1.4 Caveat;padding:35px 5%;color:var(--ink)}.writing-stage.ready .letter-fallback{display:none}.letter-bottom{display:flex;align-items:center;justify-content:space-between;gap:15px;border-top:1px solid #e4d5c8;padding:16px 3% 0;position:relative;z-index:6}.writing-hint{font-size:12px;color:var(--muted)}.text-button{font-size:12px;background:none;color:var(--ink);border:0;border-bottom:1px solid #bc9098;padding:4px 0}.text-button:hover{color:var(--rose)}.wish{position:relative;min-height:110svh;padding:100px 24px 95px;text-align:center;background:var(--ink);color:var(--paper);overflow:hidden}.wish .script-note{color:#ddb9bc}.wish h2{margin-top:22px}.wish h2 em{color:#dfb7bd}.wish-instruction{font-size:14px;color:#ddc6bf;margin:26px auto 0;line-height:1.6}.candle{display:flex;flex-direction:column;align-items:center;width:210px;padding:0;border:0;background:transparent;color:#f2ded1;margin:25px auto 30px}.candle-image{display:block;width:160px;height:240px;background-image:url('assets/candle.webp');background-size:200% 100%;background-position:left center;background-repeat:no-repeat;transition:filter .5s}.candle:hover .candle-image{filter:brightness(1.1)}.candle-label{font-size:13px;letter-spacing:.04em;border-bottom:1px solid #b88e91;padding:6px 0}.candle.blown .candle-image{background-position:right center}.candle.blown .candle-label{visibility:hidden}.wish.granted .wish-intro{display:none}.wish.granted .candle{position:absolute;right:6%;bottom:100px;opacity:.65;transform:scale(.7);transform-origin:bottom right}.last-letter{margin:30px auto 90px;position:relative;z-index:2;animation:letter-in 1.3s ease both}.last-letter>p:not(.script-note){margin:30px 0;font-size:18px;line-height:1.9;color:#ead9cc}.signature-wrap{display:flex;flex-direction:column;align-items:center;margin-top:35px}.signature-wrap>span{font:24px Caveat;color:#e1c1ba}.signature-wrap svg{width:235px;height:96px;overflow:visible}.wish footer{position:absolute;bottom:30px;left:6%;right:6%;border-top:1px solid #94616d;display:flex;justify-content:space-between;padding-top:20px;font-size:12px;color:#dfc5be}.wish footer a{text-underline-offset:5px}.confetti{position:absolute;inset:0;pointer-events:none}.confetti i{position:absolute;top:-20px;width:5px;height:9px;background:#dcb18d;border-radius:1px;animation:confetti-fall 5s cubic-bezier(.22,.61,.36,1) both}.confetti i:nth-child(3n){background:#d3a0aa}.confetti i:nth-child(2n){width:3px;height:6px;background:#f0dbb5}@keyframes confetti-fall{to{transform:translate3d(var(--drift),110vh,0) rotate(560deg);opacity:0}}@keyframes letter-in{from{opacity:0;transform:translateY(25px)}to{opacity:1;transform:translateY(0)}}
@media(min-width:1500px){.opening{padding-left:max(8%,calc((100vw - 1250px)/2));padding-right:max(8%,calc((100vw - 1250px)/2))}.letter-inner{max-width:1650px;margin:auto}}
@media(max-height:740px) and (min-width:900px){.opening{padding-top:125px;padding-bottom:90px}.opening-art{min-height:380px}.dedication{margin-bottom:20px}.opening-note{margin-top:20px}.open-letter{margin-top:23px}.story-beats{gap:25px}.story h3{font-size:31px}.story-inner{padding-top:5vh;padding-bottom:5vh}.letter-inner{padding:5vh 7%}.letter-paper{max-width:720px;padding-top:22px}.writing-stage{max-height:65vh}.letter-to{font-size:25px}.letter-aside>img{max-height:32vh}.birthday-small{margin-top:18px}.birthday-name{margin-top:20px}}
@media(max-width:900px){.story-inner{gap:6%;padding:8vh 7%}.story h3{font-size:30px}.photo-spread{gap:24px}.memory{width:280px}.between-photos{width:100px}.between-photos svg{width:90px}.letter-inner{grid-template-columns:.55fr 1.45fr;gap:3%;padding:7vh 4%}.letter-aside h2{font-size:40px}.letter-paper{padding:23px 12px 20px}.writing-hint{max-width:130px;line-height:1.5}.letter-aside .script-note{font-size:20px}}
@media(max-width:700px){.sound{top:24px;right:4%;font-size:12px;padding:5px 9px}.sound svg{width:16px}.masthead .date{left:48%;font-size:12px;letter-spacing:.05em}.opening{min-height:100svh}.opening-art{margin-top:0;height:360px}.opening-copy{padding-top:6px}.opening-art img{top:-36%;height:170%}.opening h1{font-size:68px}.opening-note{font-size:15px}.opening-bottom{font-size:12px;bottom:26px}.opening-bottom a{display:flex;align-items:center}.birthday{height:150svh}.birthday-inner{padding:90px 7%}.birthday h2{font-size:52px}.birthday .script-note{font-size:26px}.birthday-small{font-size:15px}.scene-foot{font-size:12px;padding:0 25px}.story{height:210svh}.story-inner{display:flex;flex-direction:column;justify-content:center;align-items:stretch;padding:65px 9%;gap:30px}.story-title h2{font-size:44px}.story-title h2 br{display:none}.story-title>p{margin-top:15px;font-size:14px}.story-thread{display:none}.story-beats{gap:26px;padding-left:25px}.beat-mark{left:-29px}.beat-intro{font-size:20px;margin-bottom:5px}.story h3{font-size:28px;margin-bottom:8px}.story h3 br{display:none}.story-beat>p:last-child{font-size:13px}.moments{padding:80px 6% 90px}.moments h2{font-size:48px}.moments-heading>p{font-size:14px;line-height:1.6;padding:0 15px}.photo-spread{margin-top:50px;display:block;position:relative;min-height:0}.memory{width:75%;max-width:330px;margin:0 auto 60px;padding:11px 11px 24px}.photo-window{height:330px}.memory figcaption{font-size:23px}.between-photos{display:none}.letter-scene{height:390svh}.letter-inner{display:flex;flex-direction:column;justify-content:center;gap:22px;padding:60px 5% 28px}.letter-aside{max-width:none;align-self:stretch}.letter-aside h2{font-size:38px;text-align:center}.letter-aside h2 br{display:none}.letter-aside>img,.letter-aside .script-note{display:none}.letter-paper{padding:24px 8px 18px;transform:rotate(-.6deg)}.letter-to{font-size:26px;margin-left:4%}.writing-stage{aspect-ratio:840/680}.writing-stage>svg{height:100%}.letter-bottom{padding-top:10px;gap:8px}.writing-hint{font-size:11px;max-width:140px}.text-button{font-size:11px}.writing-hand{width:46%}.letter-fallback{font-size:22px}.wish{padding:85px 20px 110px;min-height:100svh}.wish h2{font-size:49px}.wish-instruction{font-size:13px;max-width:270px}.wish footer{font-size:11px;gap:20px;text-align:left;line-height:1.6}.wish footer>a{white-space:nowrap}.last-letter{margin:30px 0 110px}.last-letter>p:not(.script-note){font-size:16px}.wish.granted .candle{right:5px;bottom:65px;transform:scale(.4)}.signature-wrap svg{width:210px}.candle-image{height:220px;width:147px}}
@media(prefers-reduced-motion:reduce){html{scroll-behavior:auto}*,*:before,*:after{animation:none!important;transition:none!important}.scroll-scene{height:auto!important}.sticky{position:relative;height:auto;min-height:95svh}.birthday-inner{min-height:100svh}.story-inner{padding-top:80px;padding-bottom:80px}.writing-hand{display:none}.letter-inner{padding-top:80px;padding-bottom:80px}.confetti{display:none}}
.opening-art img,.letter-aside>img{mask-image:linear-gradient(to bottom,transparent,black 15%,black 80%,transparent),linear-gradient(to right,transparent,black 12%,black 87%,transparent);mask-composite:intersect;-webkit-mask-composite:source-in}
.writing-hand{mask-image:linear-gradient(to bottom,black 75%,transparent 100%)}
.candle-image{height:280px;width:140px}
@media(max-width:700px){.letter-scene{height:auto}.letter-inner{position:relative;height:auto;min-height:100svh;padding:80px 5%}.letter-aside h2{font-size:38px}.writing-stage{aspect-ratio:auto}.writing-stage.ready>svg{display:none}.writing-stage.ready .letter-fallback{display:block;font-size:23px;line-height:1.4;padding:28px 5%}.writing-hand{display:none}.letter-paper{padding-bottom:20px}.writing-hint{font-size:12px}.letter-bottom .text-button{display:none}.candle-image{width:135px;height:270px}}

/* Entrance: a sealed keepsake opening into their watercolor world. */
body.booting{overflow:hidden}.loader{position:fixed;inset:0;z-index:1000;display:grid;place-items:center;background:var(--ink);color:var(--paper);overflow:hidden;transition:clip-path 1.1s cubic-bezier(.76,0,.24,1),visibility 1.1s;clip-path:inset(0)}.loader.is-gone{clip-path:inset(0 0 100% 0);visibility:hidden}.loader-wash{position:absolute;inset:-20%;background:url('assets/portrait.webp') center/cover;opacity:.1;filter:blur(24px) saturate(.65);transform:scale(1.08);animation:loader-breathe 5s ease-in-out infinite alternate}.loader-wash:after{content:"";position:absolute;inset:0;background:linear-gradient(180deg,#542233cc,#542233f5)}.loader-inner{position:relative;width:min(620px,86vw);text-align:center}.loader-mark{display:flex;align-items:center;justify-content:center;gap:18px;font:32px var(--display);margin-bottom:32px}.loader-mark i{width:46px;height:1px;background:#c8929e;position:relative}.loader-mark i:after{content:"";position:absolute;width:5px;height:5px;border:1px solid #c8929e;transform:rotate(45deg);top:-3px;left:20px;background:var(--ink)}.loader-script{font:25px Caveat,cursive;color:#ddbac0}.loader h1{font-size:clamp(54px,7vw,88px);margin-top:14px;color:var(--paper)}.loader-rule{height:1px;background:#81505d;margin:35px auto 18px;max-width:390px;overflow:hidden}.loader-rule span{display:block;width:100%;height:100%;background:#e1bd9b;transform:scaleX(0);transform-origin:left;transition:transform 1.8s cubic-bezier(.16,1,.3,1)}.loader.is-ready .loader-rule span{transform:scaleX(1)}.loader-status{font-size:12px;letter-spacing:.12em;text-transform:uppercase;color:#d5b8b6;min-height:18px}.enter-story{margin:32px auto 0;border:1px solid #a7737e;background:transparent;color:var(--paper);padding:17px 22px;min-width:215px;display:flex;align-items:center;justify-content:space-between;gap:28px;opacity:.35;transition:opacity .3s,background .3s,color .3s,transform .3s}.enter-story:not(:disabled){opacity:1}.enter-story:not(:disabled):hover{background:var(--paper);color:var(--ink);transform:translateY(-2px)}.enter-story svg{width:21px;height:21px;fill:none;stroke:currentColor;stroke-width:1.4}.masthead{position:fixed;transition:opacity .5s}.booting .masthead,.booting .reading-progress{opacity:0}

.opening{display:block;grid-template-columns:none;height:360svh;min-height:0;padding:0;background:var(--paper);overflow:clip}.opening-stage{width:100%;padding:0;display:grid;place-items:center;isolation:isolate}.opening-stage:before,.opening-stage:after{content:"";position:absolute;inset:0;pointer-events:none;z-index:5}.opening-stage:before{background:linear-gradient(90deg,var(--paper) 0%,transparent 25%,transparent 75%,var(--paper) 100%);opacity:.52}.opening-stage:after{inset:auto 0 0;height:25%;background:linear-gradient(transparent,var(--paper));opacity:.75}.portal-glow{position:absolute;width:min(78vw,1030px);height:min(88vh,800px);border-radius:52% 52% 10px 10px/36% 36% 10px 10px;background:#c98b9842;filter:blur(48px);transform:scale(.86);will-change:transform,opacity}.portal{position:absolute;width:min(55vw,710px);height:min(76vh,720px);top:11vh;overflow:hidden;border-radius:48% 48% 4px 4px/30% 30% 4px 4px;box-shadow:0 26px 80px #54223329;transform-origin:50% 48%;will-change:transform,clip-path,filter;clip-path:inset(0 round 48% 48% 4px 4px/30% 30% 4px 4px);background:#ead5c8}.portal:before{content:"";position:absolute;inset:16px;border:1px solid #fff8eb99;border-radius:48% 48% 2px 2px/30% 30% 2px 2px;z-index:4;pointer-events:none}.portal-backdrop{position:absolute;inset:-15%;background:url('assets/portrait.webp') center/cover;filter:blur(20px) saturate(.65);opacity:.48;transform:scale(1.1);will-change:transform}.portal-portrait{position:absolute;inset:-7% -5%;width:110%;height:114%;object-fit:cover;object-position:center 48%;mix-blend-mode:multiply;mask-image:linear-gradient(transparent 1%,black 18%,black 87%,transparent);will-change:transform,filter}.portal-veil{position:absolute;inset:0;background:linear-gradient(180deg,#fff8ee28 0%,transparent 55%,#f7efdfb5 100%);z-index:3}.opening-copy{position:absolute;z-index:6;max-width:780px;text-align:center;pointer-events:none;will-change:transform,opacity,filter}.opening-copy .dedication{margin:0 0 22px}.opening-copy h1{font-size:clamp(58px,7vw,96px);text-shadow:0 2px 30px #f7efdf}.opening-copy-first{top:12vh}.opening-copy-second{opacity:0;top:24vh}.opening-copy-second .signed{font-size:27px}.portal-caption{position:absolute;z-index:7;bottom:7vh;display:flex;align-items:center;gap:12px;font-size:12px;letter-spacing:.08em;text-transform:uppercase;color:var(--muted);will-change:opacity,transform}.portal-caption svg{width:18px;fill:none;stroke:currentColor;stroke-width:1.2;animation:scroll-bob 1.8s ease-in-out infinite}.opening .opening-bottom{z-index:7}.opening .opening-bottom span:last-child{margin-left:auto}.birthday{margin-top:0}.reading-progress span{transition:background .3s}

@keyframes loader-breathe{to{transform:scale(1.15);filter:blur(18px) saturate(.8)}}@keyframes scroll-bob{50%{transform:translateY(6px)}}

@media(max-width:700px){.loader-script{font-size:21px}.loader h1{font-size:54px}.opening{height:280svh}.opening-stage{min-height:100svh}.portal{width:84vw;height:64vh;top:18vh}.portal-glow{width:96vw;height:70vh}.opening-copy{width:90%;padding:0 10px}.opening-copy-first{top:12vh}.opening-copy-second{top:22vh}.opening-copy h1{font-size:54px}.opening-copy .dedication{font-size:21px}.portal-caption{bottom:8vh}.opening .opening-bottom{display:none}}

@media(prefers-reduced-motion:reduce){.loader-wash,.portal-caption svg{animation:none}.loader{transition:opacity .3s}.loader.is-gone{clip-path:none;opacity:0}.opening{height:auto}.opening-stage{position:relative;height:100svh}.opening-copy-first{display:none}.opening-copy-second{opacity:1}.portal{transform:none!important}.portal-caption{display:none}}

/* --- Layer: doorway opening. The arch is a frame you pass through into light,
   never a portrait blown up until it is unreadable. --- */
.opening{height:250svh}
.opening-stage:before{opacity:.4}

/* Title sits above the doorway rather than on top of it, so the headline reads
   at full contrast and their faces stay uncropped. */
.portal{top:35vh;height:min(53vh,480px);--frame:1}
.portal:before{opacity:var(--frame)}
.portal-portrait{object-position:center 40%;mask-image:linear-gradient(transparent 1%,#000 13%,#000 88%,transparent)}
.portal-backdrop{opacity:.34}
.portal-glow{top:27vh}

/* Kept as a faint lift under the type for the moment the arch drifts up into it. */
.portal-scrim{position:absolute;z-index:5;width:min(64vw,840px);height:min(40vh,360px);top:4vh;
  background:radial-gradient(ellipse at 50% 42%,#f7efdfd6 0%,#f7efdf9e 45%,#f7efdf00 74%);
  pointer-events:none;will-change:opacity,transform}

/* The light you step into. Scales out of the arch and floods the screen. */
.portal-flood{position:absolute;inset:0;z-index:5;opacity:0;pointer-events:none;will-change:opacity,transform;
  background:radial-gradient(ellipse at 50% 46%,#fffaf0 0%,#f9f1e2 34%,#f2e3d2 68%,#eddbc9 100%)}

.opening-copy h1{text-shadow:0 1px 26px #f7efdf,0 1px 3px #f7efdf}
.opening-copy-first{top:7vh}
.opening-copy-second{top:26vh}


/* The date label was landing on top of section headings further down the page. */
.masthead .date{transition:opacity .45s}
body.past-opening .masthead .date{opacity:0}
.moments{padding-top:155px}

/* Birthday chapter: lines arrive one at a time instead of sitting there pre-rendered. */
.birthday-content .reveal{will-change:opacity,transform}
.birthday-date{will-change:transform,opacity}

@media(max-height:820px) and (min-width:900px){
  .opening-copy-first{top:5vh}
  .opening-copy h1{font-size:clamp(50px,5.4vw,72px)}
  .portal{top:32vh;height:min(52vh,430px)}
  .portal-glow{top:25vh}
}
@media(max-width:700px){
  .opening{height:215svh}
  .portal{top:38vh;height:48vh}
  .portal-glow{top:30vh}
  .portal-scrim{width:94vw;height:30vh;top:5vh}
  .moments{padding-top:110px}
}
@media(prefers-reduced-motion:reduce){
  .opening{height:auto}
  .portal-flood,.portal-scrim{display:none}
  .portal{--frame:1}
}

/* Clear the fixed masthead and the footer rule. */
.opening-copy-first{top:11vh}
.opening-copy h1{font-size:clamp(52px,5.6vw,80px)}
.portal-caption{bottom:11vh}
@media(max-height:820px) and (min-width:900px){.opening-copy-first{top:9vh}.opening-copy h1{font-size:clamp(46px,4.9vw,66px)}}
@media(max-width:700px){.opening-copy-first{top:12vh}.opening-copy h1{font-size:46px}.portal-caption{bottom:9vh}}

/* The blown-out candle was stranded half-out of the corner. Settle it under the
   closing letter instead, dimmed, as a spent object rather than a stray sprite. */
.wish.granted .candle{position:static;margin:0 auto 4px;opacity:.5;transform:scale(.72);
  transform-origin:center bottom;transition:opacity .9s ease .4s}
.wish.granted{display:flex;flex-direction:column;justify-content:center}
.wish.granted .last-letter{margin-bottom:60px}
@media(max-width:700px){.wish.granted .candle{transform:scale(.58);margin-bottom:0}}

/* The monogram inherits ink and vanishes against the burgundy chapters, and the
   date collides with section headings. Retire the whole masthead after the
   opening — the sound toggle is fixed separately and stays. */
.masthead{transition:opacity .5s}
body.past-opening .masthead{opacity:0;pointer-events:none}

/* ============================================================
   Cinema model. The page no longer scrolls in the ordinary sense:
   every chapter is a full-viewport scene stacked in one fixed stage,
   and scrolling cross-dissolves one scene into the next. An empty
   track below supplies the scroll distance.
   ============================================================ */
.stage{position:fixed;inset:0;overflow:hidden;z-index:1}
#track{position:relative;z-index:0;pointer-events:none}

.stage > section{
  position:absolute;inset:0;width:100%;height:100svh;min-height:0;
  overflow:hidden;opacity:0;pointer-events:none;
  transform-origin:50% 50%;will-change:opacity,transform,filter;
  display:grid;place-items:center;margin:0}
.stage > section.is-live{pointer-events:auto}

/* The old sticky wrappers become plain full-bleed scene contents. */
.stage > section > .sticky{position:static;height:100%;width:100%;overflow:visible}

/* Scenes that were laid out as ordinary flow now need to fill a scene box. */
.moments{padding:0 8%;display:grid;place-items:center;align-content:center}
.moments .photo-spread{margin-top:46px;min-height:0}
.wish{position:absolute;min-height:0;padding:0 24px;display:grid;place-items:center;align-content:center}
.wish footer{bottom:26px}

/* Chapters no longer own their scroll length in CSS; the track does. */
.opening,.birthday,.story,.letter-scene{height:100svh}

.stage > section > .scene-foot,.stage > section .scene-foot{z-index:8}

@media(prefers-reduced-motion:reduce){
  /* Fall back to an ordinary, complete, still document. */
  .stage{position:static;overflow:visible}
  #track{display:none}
  .stage > section{position:relative;opacity:1!important;pointer-events:auto;
    transform:none!important;filter:none!important;height:auto;min-height:100svh}
  .opening,.birthday,.story,.letter-scene{height:auto}
  .moments,.wish{position:relative;padding:90px 8%}
}
.stage{background:var(--paper)}

/* The stage owns the ground colour now, so chapters paint only their content. */
.stage > section{background:transparent!important}

/* Fit each scene inside one viewport: the photo spread and the closing
   signature were both running past the bottom edge of the stage. */
.moments .photo-window{height:min(42vh,360px)}
.moments .memory{width:min(27vw,300px)}
.moments-heading h2{font-size:clamp(34px,4vw,56px)}
.wish .last-letter{margin:18px auto 34px}
.wish .last-letter>p:not(.script-note){margin:20px 0;font-size:17px}
.wish .signature-wrap{margin-top:22px}
.wish .signature-wrap svg{height:82px}
.wish h2{font-size:clamp(38px,4.6vw,64px)}

/* --- The wedding day. Deep ground so the gold in the photographs glows. --- */
.the-day{color:var(--paper)}
.day-inner{display:grid;grid-template-columns:.85fr 1.15fr;gap:5%;
  padding:7vh 7%;align-items:center}
.day-copy .script-note{color:#e0b4ab;margin-bottom:14px}
.day-copy h2{font-size:clamp(46px,5.4vw,80px);line-height:1.02;letter-spacing:-.025em}
.day-copy h2 em{color:#e8bda4}
.day-copy .day-unity{font-size:clamp(38px,4.3vw,64px);max-width:12ch;margin-inline:auto;text-wrap:balance}
.day-spread{display:flex;justify-content:center;align-items:center}
.the-day .memory{background:#fffbf1;padding:11px 11px 13px;margin:0;
  box-shadow:0 20px 55px #14070c66;flex-shrink:0;will-change:transform,opacity}
.the-day .photo-window{height:min(48vh,410px)}
.day-one{width:min(25vw,300px);z-index:1}
.day-two{width:min(22vw,262px);z-index:2}
.the-day .memory img{object-position:50% 42%}

@media(max-width:900px){
  .day-inner{grid-template-columns:1fr;gap:26px;padding:6vh 7%;justify-items:center;text-align:center}
  .day-copy h2{font-size:44px}
  .the-day .photo-window{height:min(36vh,300px)}
  .day-one{width:min(46vw,230px)}
  .day-two{width:min(40vw,200px)}
}
@media(max-width:700px){.day-copy .day-unity{font-size:34px;max-width:15ch}}
@media(prefers-reduced-motion:reduce){
  .the-day .memory{opacity:1!important}
  .day-inner{padding:80px 7%}
}

/* ============================================================
   The present. It is the way in: the lid lifts, the bow comes
   undone, light spills out of the box and becomes the page.
   ============================================================ */
.gift{position:relative;display:block;margin:30px auto 0;width:220px;padding:0;
  background:none;border:0;color:var(--paper);
  transition:transform .4s cubic-bezier(.34,1.56,.64,1),opacity .4s;opacity:.4}
.gift:not(:disabled){opacity:1;cursor:pointer}
.gift:not(:disabled):hover{transform:translateY(-5px)}
.gift:not(:disabled):active{transform:translateY(-1px) scale(.98)}

.gift-art{display:block;width:100%;height:auto;overflow:visible}
.gift-body rect{fill:#e9d3b4}
.gift-lid rect{fill:#f6e7cf}
.gift-art .gift-ribbon-v{fill:#a8566b}
.gift-bow path{fill:#b9607a}
.gift-bow circle{fill:#c9738c}
.gift-body,.gift-lid,.gift-bow{transform-origin:110px 120px}
.gift-lid{transform-origin:110px 88px}
.gift-bow{transform-origin:110px 60px}

/* A soft breath while it waits, so it reads as something to touch. */
.gift:not(:disabled) .gift-art{animation:gift-breathe 2.8s ease-in-out infinite}
@keyframes gift-breathe{0%,100%{transform:rotate(-1.2deg) scale(1)}50%{transform:rotate(1.2deg) scale(1.025)}}

.gift-glow{position:absolute;left:50%;top:56%;width:190px;height:190px;margin:-95px 0 0 -95px;
  border-radius:50%;pointer-events:none;opacity:0;
  background:radial-gradient(circle,#fff6e4 0%,#f6dcb4cc 34%,#e0a98e00 70%)}
.gift-hint{display:block;margin-top:20px;font-size:12px;letter-spacing:.16em;
  text-transform:uppercase;color:#d8bab7;transition:opacity .3s}

/* --- Opening --- */
.loader.is-opening .gift{pointer-events:none}
.loader.is-opening .gift-art{animation:none}
.loader.is-opening .gift-hint{opacity:0}
.loader.is-opening .gift-bow{animation:bow-off .55s cubic-bezier(.4,0,.7,.2) forwards}
.loader.is-opening .gift-lid{animation:lid-off 1.15s cubic-bezier(.3,-.4,.5,1) .18s forwards}
.loader.is-opening .gift-body{animation:box-open 1.2s cubic-bezier(.4,0,.3,1) .3s forwards}
.loader.is-opening .gift-glow{animation:gift-light 1.25s cubic-bezier(.4,0,.4,1) .34s forwards}
.loader.is-opening .loader-inner>:not(.gift){animation:loader-copy-off .5s ease forwards}

@keyframes bow-off{to{transform:translateY(-26px) rotate(-22deg) scale(.5);opacity:0}}
@keyframes lid-off{
  30%{transform:translateY(-34px) rotate(-5deg)}
  to{transform:translateY(-190px) rotate(-17deg) scale(.86);opacity:0}}
@keyframes box-open{
  22%{transform:scaleY(.94) scaleX(1.04)}
  to{transform:translateY(46px) scaleY(.5) scaleX(1.12);opacity:0}}
@keyframes gift-light{
  0%{opacity:0;transform:scale(.25)}
  38%{opacity:1}
  to{opacity:0;transform:scale(7.5)}}
@keyframes loader-copy-off{to{opacity:0;transform:translateY(-14px)}}

@media(max-width:700px){
  .gift{width:170px;margin-top:22px}
  .gift-glow{width:150px;height:150px;margin:-75px 0 0 -75px}
  .gift-hint{margin-top:16px;font-size:11px}
}
@media(prefers-reduced-motion:reduce){
  .gift:not(:disabled) .gift-art,.loader.is-opening *{animation:none!important}
  .gift{transition:none}
}

/* ============================================================
   Phones. Every chapter is a scene that must fit inside one
   100svh box, so nothing here may rely on the page growing.
   ============================================================ */
@media(max-width:700px){
  .stage > section{padding:0}
  /* Centre each scene vertically without overriding its own layout. */
  .letter-inner{display:flex;flex-direction:column;justify-content:center;height:100%}
  .day-inner{align-content:center}
  .story-inner{height:100%}

  /* Opening */
  .opening-stage{padding:0 5vw}
  .portal{width:80vw;height:44svh;top:auto;position:absolute;top:38svh}
  .portal-glow{width:94vw;height:44svh;top:33svh}
  .portal-scrim{width:92vw;height:26svh;top:6svh}
  .opening-copy{width:92vw;padding:0}
  .opening-copy-first{top:9svh}
  .opening-copy-second{top:30svh}
  .opening-copy h1{font-size:40px;line-height:1.04}
  .opening-copy .dedication{font-size:19px;margin-bottom:14px}
  .opening-copy-second .signed{font-size:21px;margin-top:16px}
  .portal-caption{bottom:5svh;font-size:10px}
  .opening .opening-bottom{display:none}

  /* Birthday */
  .birthday-inner{padding:0 7vw}
  .birthday h2{font-size:38px;line-height:1.08}
  .birthday .script-note{font-size:21px;margin-bottom:20px}
  .birthday-small{font-size:14px;line-height:1.75;margin-top:22px}
  .birthday-date{font-size:58vw}

  /* Their story: three beats plus a heading has to clear a short phone. */
  .story-inner{display:flex;flex-direction:column;justify-content:center;
    align-items:stretch;padding:0 8vw;gap:20px}
  .story-title h2{font-size:32px}
  .story-title h2 br,.story h3 br{display:none}
  .story-title>p{margin-top:10px;font-size:13px;line-height:1.6}
  .story-thread{display:none}
  .story-beats{gap:17px;padding-left:19px}
  .beat-mark{left:-23px;width:5px;height:5px;top:7px}
  .beat-intro{font-size:17px;margin-bottom:2px}
  .story h3{font-size:21px;line-height:1.14;margin-bottom:4px}
  .story-beat>p:last-child{font-size:12px}

  /* The wedding */
  .day-inner{grid-template-columns:1fr;gap:20px;padding:0 7vw;
    justify-items:center;text-align:center}
  .day-copy h2{font-size:38px}
  .day-copy .script-note{font-size:20px;margin-bottom:8px}
  .the-day .photo-window{height:32svh}
  .day-one{width:42vw}
  .day-two{width:37vw}

  /* Everyday photographs, side by side rather than stacked */
  .moments{padding:0 5vw}
  .photo-spread{display:flex;margin-top:26px;gap:0;min-height:0}
  .moments-heading h2{font-size:30px}
  .moments-heading>p{font-size:13px;margin-top:12px;padding:0}
  .moments .memory{width:40vw;max-width:none;margin:0;padding:8px 8px 14px}
  .moments .photo-window{height:31svh}
  .memory figcaption{font-size:15px;margin-top:10px;line-height:1.2}
  .memory-one{transform:rotate(-6deg)}
  .memory-two{transform:rotate(6deg)}
  .between-photos{display:none}

  /* The letter keeps the handwriting; the aside and portrait step aside. */
  .letter-inner{padding:0 4vw}
  .letter-aside{display:none}
  .letter-paper{max-width:none;padding:13px 7px 8px;transform:rotate(-.5deg)}
  .letter-to{font-size:19px;margin-left:3%}
  .writing-stage{aspect-ratio:auto;max-height:none}
  .writing-stage.ready .letter-fallback{font-size:17px;line-height:1.5;padding:14px 5%}
  .letter-paper{width:100%}
  .letter-bottom{display:none}
  .writing-hand{width:44%}
  .letter-bottom{padding:9px 2% 0}
  .writing-hint{font-size:10px}
  .text-button{font-size:10px}

  /* The wish */
  .wish{padding:0 6vw}
  .wish h2{font-size:34px}
  .wish .script-note{font-size:20px}
  .wish-instruction{font-size:12px;margin-top:16px;max-width:250px}
  .candle{width:150px;margin:14px auto 16px}
  .candle-image{width:104px;height:158px}
  .wish .last-letter{margin:10px auto 26px}
  .wish .last-letter>p:not(.script-note){font-size:14px;line-height:1.75;margin:14px 0}
  .wish .signature-wrap{margin-top:16px}
  .wish .signature-wrap svg{width:170px;height:62px}
  .wish footer{bottom:14px;font-size:10px;left:5vw;right:5vw;padding-top:12px}
}

/* Short phones (SE and similar) need one more notch down. */
@media(max-width:700px) and (max-height:700px){
  .opening-copy h1{font-size:34px}
  .birthday h2{font-size:32px}
  .story-title h2{font-size:27px}
  .story h3{font-size:18px}
  .story-beats{gap:12px}
  .day-copy h2,.wish h2{font-size:31px}
  .moments-heading h2{font-size:25px}
  .the-day .photo-window,.moments .photo-window{height:27svh}
  .candle-image{width:88px;height:134px}
  .wish .last-letter>p:not(.script-note){font-size:13px}
}

/* ============================================================
   Texture. A single grain plate over the whole stage, plus a
   little more tooth on the surfaces that should read as paper.
   ============================================================ */
.grain{position:fixed;inset:0;z-index:45;pointer-events:none;
  background:url('assets/grain.webp') repeat;background-size:320px 320px;
  mix-blend-mode:soft-light;opacity:.42}
.booting .grain{opacity:0}

.letter-paper,.memory,.the-day .memory{position:relative}
.letter-paper:after,.memory:after{content:"";position:absolute;inset:0;pointer-events:none;
  background:url('assets/grain.webp') repeat;background-size:210px 210px;
  mix-blend-mode:soft-light;opacity:.75;z-index:7}
.memory:after{z-index:3}
.letter-paper{box-shadow:0 18px 60px #54223318,inset 0 0 70px #e8d3b52e}

/* ============================================================
   The letter. The seal breaks, the flap falls open, the page
   rises out of it and the light it carries becomes the site.
   ============================================================ */
.gift{width:250px}

.env-letter{transform-origin:110px 76px}
.env-flap{transform-origin:110px 45px}
.env-seal{transform-origin:110px 103px}
.gift-art{overflow:visible}

/* Closed: the page sits down inside the envelope, behind the pocket. */
.env-letter{transform:translateY(25px)}

.gift:not(:disabled) .gift-art{animation:gift-breathe 3.4s ease-in-out infinite}
@keyframes gift-breathe{0%,100%{transform:rotate(-1deg) scale(1)}50%{transform:rotate(1deg) scale(1.02)}}

.loader.is-opening .env-seal{animation:seal-break .45s cubic-bezier(.4,0,.8,.3) forwards}
.loader.is-opening .env-flap{animation:flap-open .8s cubic-bezier(.45,-.25,.35,1) .16s forwards}
.loader.is-opening .env-letter{animation:page-rise 1s cubic-bezier(.3,0,.3,1) .46s forwards}
.loader.is-opening .env-back,.loader.is-opening .env-pocket{animation:env-settle 1s ease .5s forwards}
.loader.is-opening .gift-glow{animation:gift-light 1.2s cubic-bezier(.4,0,.4,1) .52s forwards}

@keyframes seal-break{to{transform:scale(.4) rotate(-26deg);opacity:0}}
@keyframes flap-open{60%{transform:scaleY(-1.06)}to{transform:scaleY(-1)}}
@keyframes page-rise{to{transform:translateY(-58px) scale(1.06)}}
@keyframes env-settle{to{opacity:0;transform:translateY(16px)}}
@keyframes gift-light{0%{opacity:0;transform:scale(.3)}40%{opacity:1}to{opacity:0;transform:scale(7)}}

.gift-glow{top:46%}

@media(max-width:700px){.gift{width:190px}}
@media(prefers-reduced-motion:reduce){.loader.is-opening .gift-art *{animation:none!important}}

/* ============================================================
   The letter scene: keep the writing hand clear of the footer rule.
   ============================================================ */
.writing-hint{display:none}
.letter-bottom{background:#fffaf0;z-index:8}
.letter-paper{padding-bottom:14px}
.writing-hand{-webkit-mask-image:linear-gradient(to bottom,#000 58%,#0000 90%);
  mask-image:linear-gradient(to bottom,#000 58%,#0000 90%)}

/* ============================================================
   The candle, alight. The flame is part of the photograph, so a
   warm pulse sits over it to stop it reading as a still.
   ============================================================ */
.candle-image{position:relative;width:70px;height:250px;
  background-size:200% 100%;background-position:left center}
.candle-image:before{content:"";position:absolute;left:50%;top:13.5%;
  width:74px;height:74px;margin:-37px 0 0 -37px;border-radius:50%;pointer-events:none;
  background:radial-gradient(circle,#ffdcaa9e 0%,#ffa55742 40%,#ff8a3300 74%);
  animation:flame-breathe 2.2s ease-in-out infinite}
.candle:not(.blown) .candle-image{animation:flame-live 3.1s ease-in-out infinite}
@keyframes flame-breathe{
  0%,100%{transform:scale(1);opacity:.85}
  28%{transform:scale(1.14) translateY(-2px);opacity:1}
  55%{transform:scale(.94) translateX(1px);opacity:.72}
  78%{transform:scale(1.08);opacity:.95}}
@keyframes flame-live{
  0%,100%{filter:brightness(1)}
  30%{filter:brightness(1.07)}
  62%{filter:brightness(.97)}}
.candle.blown .candle-image{background-position:right center}
.candle.blown .candle-image:before{opacity:0;animation:none;transition:opacity .5s}

/* Once the wish is made the candle has done its work; their photograph takes over. */
.wish.granted .candle{opacity:0;height:0;margin:0;padding:0;overflow:hidden;
  transition:opacity .6s ease,height .6s ease .2s}
.wish-portrait{width:min(190px,42vw);margin:0 auto 22px;padding:9px 9px 11px;
  background:#fffbf1;box-shadow:0 16px 44px #14070c66;transform:rotate(-2.5deg)}
.wish-portrait img{display:block;width:100%;aspect-ratio:3/3.6;object-fit:cover;object-position:50% 38%}
@media(max-width:700px){
  .candle-image{width:58px;height:206px}
  .candle-image:before{width:70px;height:70px;margin:-35px 0 0 -35px}
  .wish-portrait{width:40vw;margin-bottom:14px;padding:7px 7px 9px}
}

/* ============================================================
   The writing hand. It was sized at nearly half the page, so at
   the last line it reached well past the footer rule. The page
   now carries blank paper below the text for the hand to rest on.
   ============================================================ */
@media(min-width:701px){
  .writing-stage{aspect-ratio:840/780;max-height:none}
  .writing-hand{width:34%}
  .letter-inner{padding:5vh 6%}
  .letter-paper{padding:22px 24px 14px}
}
@media(min-width:701px) and (max-height:820px){
  .letter-inner{padding:3vh 6%}
  .letter-paper{padding:16px 20px 12px}
  .letter-to{font-size:25px}
}

/* ============================================================
   The letter, composed. The heading, the portrait and the page
   were three loose objects at three different heights; they now
   read as one column beside the page.
   ============================================================ */
@media(min-width:701px){
  .letter-inner{grid-template-columns:.62fr 1.38fr;gap:4.5%;align-items:center}
  .letter-aside{max-width:290px;display:flex;flex-direction:column;align-items:flex-start}
  .letter-aside h2{font-size:clamp(34px,3.4vw,50px);line-height:1.05;margin-bottom:20px}
  .letter-aside>img{width:100%;max-height:30vh;margin:0}
}

/* ============================================================
   Phones now get the written letter too, on a portrait page with
   the lines re-broken to suit. JS sets the board's aspect ratio.
   ============================================================ */
@media(max-width:700px){
  .writing-stage{max-height:none}
  .writing-stage.ready>svg{display:block}
  .writing-stage.ready .letter-fallback{display:none}
  .letter-paper{width:100%;padding:14px 10px 8px}
  .letter-inner{padding:0 3vw}
  .letter-to{font-size:20px;margin-left:4%}
  .letter-bottom{display:flex;padding:8px 3% 0;background:#fffaf0}
  .writing-hint{display:none}
  .text-button{font-size:11px;margin-left:auto}
  .writing-hand{filter:drop-shadow(2px 5px 4px #4a291426)}
}

@media(max-width:700px){
  /* These two were switched off when phones showed the typeset letter instead. */
  .writing-hand{display:block;width:42%}
  .letter-bottom .text-button{display:inline-block}
}
/* Reduced motion still gets the finished letter, with no hand. */
@media(prefers-reduced-motion:reduce){.writing-hand{display:none!important}}

/* ============================================================
   Phone typography. The chapters were sized down far enough that
   they read as sparse on a tall screen; this gives them presence
   without breaking the one-scene-per-viewport rule.
   ============================================================ */
@media(max-width:700px){
  .opening-copy h1{font-size:44px}
  .opening-copy .dedication{font-size:20px}
  .birthday h2{font-size:42px}
  .birthday .script-note{font-size:23px}
  .birthday-small{font-size:15px;line-height:1.8}
  .birthday-date{font-size:64vw;opacity:.055}
  .story-title h2{font-size:34px}
  .story h3{font-size:22px}
  .beat-intro{font-size:18px}
  .day-copy h2{font-size:42px}
  .day-copy .script-note{font-size:22px}
  .moments-heading h2{font-size:33px}
  .moments-heading>p{font-size:14px}
  .memory figcaption{font-size:16px}
  .wish h2{font-size:35px}
  .wish .script-note{font-size:21px}
  .wish-instruction{font-size:13px}
  .wish .last-letter>p:not(.script-note){font-size:15px}
}
@media(max-width:700px) and (max-height:700px){
  .opening-copy h1{font-size:36px}
  .birthday h2{font-size:34px}
  .day-copy h2,.wish h2{font-size:33px}
  .moments-heading h2{font-size:27px}
  .story-title h2{font-size:28px}
  .story h3{font-size:19px}
}
@media(max-width:700px){
  .wish-portrait{width:37vw;margin-bottom:12px}
  .wish .last-letter{margin:6px auto 22px}
  .wish .last-letter>p:not(.script-note){margin:12px 0}
}

/* ============================================================
   Phone hero. The dedication was running into the masthead, and
   the headline, the arch and the caption sat as three islands
   with dead bands between them while the doorway itself was left
   small and adrift. Close the gaps and let the arch carry the
   screen: near full width, in the portrait's own proportion.
   ============================================================ */
@media(max-width:700px){
  .opening-stage{padding:0}
  .opening-copy{width:88vw;padding:0}
  .opening-copy-first{top:max(92px,12svh)}
  .opening-copy h1{font-size:clamp(34px,10.6vw,42px);line-height:1.06}
  .opening-copy .dedication{font-size:clamp(17px,4.9vw,20px);margin-bottom:10px}

  .portal{width:88vw;height:57svh;top:auto;bottom:13svh;
    border-radius:46% 46% 5px 5px/26% 26% 5px 5px;
    clip-path:inset(0 round 46% 46% 5px 5px/26% 26% 5px 5px)}
  .portal:before{inset:11px;border-radius:46% 46% 3px 3px/26% 26% 3px 3px}
  .portal-portrait{object-position:center 42%;
    mask-image:linear-gradient(transparent 1%,#000 11%,#000 90%,transparent)}
  .portal-glow{width:104vw;height:60svh;top:auto;bottom:10svh}
  .portal-scrim{width:96vw;height:24svh;top:5svh}

  .opening-copy-second{top:auto;bottom:46svh}
  .opening-copy-second .signed{font-size:20px;margin-top:14px}
  .portal-caption{bottom:4.5svh;font-size:10px;letter-spacing:.12em}
}
@media(max-width:700px) and (max-height:700px){
  .opening-copy-first{top:max(88px,10svh)}
  .opening-copy h1{font-size:32px}
  .opening-copy .dedication{font-size:16px;margin-bottom:7px}
  .portal{height:56svh;bottom:10svh}
  .portal-glow{height:59svh;bottom:7svh}
  .opening-copy-second{bottom:44svh}
}

@media(max-width:700px){
  /* The watercolour carries a wide cream margin of its own, which left the two
     of them small inside a tall arch. Crop into it so they fill the doorway. */
  .portal-portrait{inset:-17% -15%;width:130%;height:134%;object-position:center 44%}
}

/* ============================================================
   Rajavel's own words. Set quietly - they carry themselves and
   do not need display type.
   ============================================================ */
.day-lines{margin-top:26px;display:flex;flex-direction:column;gap:11px}
.day-lines p{font-size:16px;line-height:1.65;color:#eccfc4;max-width:30ch}
.day-lines p:last-child{color:#f0dcc9}

.birthday-her{font-size:17px;line-height:1.75;color:#f0d9cf;margin-top:26px;max-width:34ch;
  margin-left:auto;margin-right:auto}
.birthday-her+.birthday-her{margin-top:14px}
.birthday-small{margin-top:26px;color:#dcb9b3;font-size:15px}

@media(max-width:700px){
  .day-lines{margin-top:18px;gap:8px;align-items:center;text-align:center}
  .day-lines p{font-size:14px;line-height:1.55;max-width:28ch}
  .birthday-her{font-size:15px;line-height:1.7;margin-top:20px;max-width:30ch}
  .birthday-her+.birthday-her{margin-top:11px}
  .birthday-small{margin-top:20px;font-size:13.5px}
}
@media(max-width:700px) and (max-height:700px){
  .day-lines p{font-size:13px}
  .birthday-her{font-size:13.5px;margin-top:15px}
  .birthday-small{margin-top:15px;font-size:12.5px}
}

/* ============================================================
   Sound: icon only. The label stays in the DOM for screen readers
   and because the script rewrites it to reflect the state.
   ============================================================ */
.sound{width:40px;height:40px;padding:0;gap:0;justify-content:center;border-radius:50%}
.sound span{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;
  clip-path:inset(50%);white-space:nowrap;border:0}
.sound svg{width:19px;height:19px}
@media(max-width:700px){.sound{width:36px;height:36px}.sound svg{width:17px;height:17px}}

/* ============================================================
   His three lines all open with "With". Centred, those openings
   scattered and the first line orphaned its last word; ranged
   left they stack, which is the whole shape of the sentence.
   ============================================================ */


@media(max-width:700px) and (max-height:700px){
  .day-lines p{font-size:13px;max-width:30ch}
}

/* His last word to her, immediately before the signature. */
.closing-line{font-family:var(--display);font-size:clamp(21px,2.3vw,28px);line-height:1.4;
  font-style:italic;color:#f2dcd0;margin:26px auto 0;max-width:30ch}
@media(max-width:700px){
  .closing-line{font-size:19px;line-height:1.42;margin-top:18px;max-width:26ch}
  .closing-line br{display:none}
}
@media(max-width:700px) and (max-height:700px){.closing-line{font-size:17px;margin-top:13px}}

/* Short phones: his closing line earns its room from the portrait above it. */
@media(max-width:700px) and (max-height:700px){
  .wish-portrait{width:29vw;margin-bottom:8px;padding:6px 6px 8px}
  .wish h2{font-size:29px}
  .wish .signature-wrap{margin-top:12px}
  .wish .signature-wrap svg{width:150px;height:54px}
  .wish .last-letter{margin-bottom:16px}
}

/* ============================================================
   His three lines, centred. Centred text only reads well if each
   line breaks evenly, so the measure is narrow enough that every
   line wraps deliberately and text-wrap:balance splits the long
   one down the middle rather than stranding a word.
   ============================================================ */
.day-lines{align-items:center;text-align:center;gap:16px;margin-top:30px}
.day-lines p{max-width:26ch;text-wrap:balance;font-size:17px;line-height:1.7;
  margin-left:auto;margin-right:auto;letter-spacing:.004em}

@media(max-width:700px){
  .day-lines{gap:14px;margin-top:22px}
  .day-lines p{max-width:24ch;font-size:15.5px;line-height:1.72}
}
@media(max-width:700px) and (max-height:700px){
  .day-lines{gap:11px;margin-top:16px}
  .day-lines p{font-size:14px;line-height:1.65;max-width:25ch}
}

/* ============================================================
   The opening animation. Replaces the hand-built envelope; the
   glow still blooms out of it and becomes the page.
   ============================================================ */
.gift{width:min(300px,62vw)}
.gift-lottie{width:100%;aspect-ratio:1/1;display:block;pointer-events:none}
.gift-lottie svg{display:block;width:100%!important;height:100%!important}
.gift:not(:disabled) .gift-lottie{animation:gift-breathe 3.6s ease-in-out infinite}
@keyframes gift-breathe{0%,100%{transform:scale(1)}50%{transform:scale(1.025)}}
.loader.is-opening .gift-lottie{animation:none}
.loader.is-opening .gift-glow{animation:gift-light 1.5s cubic-bezier(.4,0,.4,1) .55s forwards}
.gift-glow{top:50%;width:230px;height:230px;margin:-115px 0 0 -115px}
@media(max-width:700px){
  .gift{width:min(230px,64vw)}
  .gift-glow{width:180px;height:180px;margin:-90px 0 0 -90px}
}

/* On laptops the wedding heading was ranged left while the three lines under it
   were centred - two alignments in one column. Centre the whole column. */
@media(min-width:701px){
  .day-copy{text-align:center}
  .day-lines{align-items:center}
  .day-inner{align-items:center}
}

/* The closing line was breaking at a hard <br> and then again at the measure,
   stranding "journey," alone. Let it break where it wants, balanced. */
.closing-line{max-width:34ch;text-wrap:balance}
@media(max-width:700px){.closing-line{max-width:27ch}}

/* The watercolour beside the letter was small enough to read as a stamp. */
@media(min-width:701px){
  .letter-aside{width:100%;max-width:460px;align-self:stretch;justify-content:center}
  .letter-aside>img{width:100%;height:min(58vh,560px);max-height:none;margin-top:4px;object-fit:contain;object-position:center;transform:scale(1.28);transform-origin:center}
  .letter-aside h2{margin-bottom:16px}
}

/* Very wide screens: the doorway and the letter were sized for a laptop and
   left adrift in the extra space. */
@media(min-width:1600px){
  .portal{width:min(46vw,880px);height:min(56vh,600px)}
  .portal-glow{width:min(64vw,1180px);height:min(64vh,700px)}
  .opening-copy h1{font-size:88px}
  .opening-copy{max-width:900px}
  .letter-inner{max-width:1480px}
  .day-inner,.story-inner{max-width:1500px;margin-inline:auto}
  .moments .photo-spread{max-width:1150px}
}

/* .last-letter > p:not(.script-note) sets margin:30px 0, which outranked this
   line's margin:auto and left it ranged against its box instead of centred. */
.last-letter > p.closing-line{margin:26px auto 0;max-width:36ch}
@media(max-width:700px){.last-letter > p.closing-line{margin:18px auto 0;max-width:27ch}}

/* .wish .last-letter > p:not(.script-note) (0,3,1) outranked every rule above,
   so his closing line was rendering at body size with its auto margins zeroed.
   Match that specificity so it gets the display face and centres. */
.wish .last-letter > p.closing-line{
  margin:26px auto 0;max-width:36ch;
  font-family:var(--display);font-style:italic;
  font-size:clamp(21px,2.3vw,28px);line-height:1.45;color:#f2dcd0}
@media(max-width:700px){
  .wish .last-letter > p.closing-line{margin:18px auto 0;max-width:26ch;font-size:19px;line-height:1.45}
}
@media(max-width:700px) and (max-height:700px){
  .wish .last-letter > p.closing-line{font-size:17px;margin-top:13px}
}

/* ============================================================
   The half hour before midnight.
   ============================================================ */
body.prelude-open{overflow:hidden}
body.prelude-open .loader,body.prelude-open .stage,
body.prelude-open .masthead,body.prelude-open .sound,
body.prelude-open .reading-progress{opacity:0!important;pointer-events:none!important}

.prelude{position:fixed;inset:0;z-index:2000;background:var(--ink);color:var(--paper);
  display:grid;place-items:center;transition:opacity .9s ease}
.prelude.is-gone{opacity:0;pointer-events:none}
.prelude:before{content:"";position:absolute;inset:0;pointer-events:none;
  background:radial-gradient(ellipse at 50% 42%,#7a3a4c55,transparent 62%)}
.prelude-inner{position:relative;width:min(560px,86vw);text-align:center}

.prelude-kicker{font:13px/1 var(--body);letter-spacing:.22em;text-transform:uppercase;
  color:#d8aeb0;margin-bottom:22px}
.prelude-stage{display:grid;place-items:center;min-height:min(58vh,520px)}
.prelude-card{margin:0;padding:12px 12px 14px;background:#fffbf1;
  box-shadow:0 26px 70px #10060a80;transform:rotate(-1.4deg) scale(.97);opacity:0;
  transition:opacity .55s ease,transform .75s cubic-bezier(.16,1,.3,1)}
.prelude-card.is-in{opacity:1;transform:rotate(-1.4deg) scale(1)}
.prelude-card img{display:block;width:100%;max-height:min(54vh,480px);object-fit:cover}
.prelude-caption{font:24px/1.45 Caveat,cursive;color:#f0d6ce;margin-top:20px;min-height:34px}

.prelude-dots{display:flex;gap:9px;justify-content:center;margin-top:20px}
.prelude-dots i{width:6px;height:6px;border-radius:50%;background:#7c4a58;transition:background .5s}
.prelude-dots i.on{background:#e2b6b6}

.prelude-bar{position:absolute;left:0;right:0;bottom:0;height:2px;background:#ffffff14}
.prelude-bar span{display:block;height:100%;width:0;background:linear-gradient(90deg,#c9738c,#e5c08f);
  transition:width .6s linear}

/* Before it begins: no photograph, just the wait. */
.prelude.is-waiting .prelude-stage,.prelude.is-waiting .prelude-dots{visibility:hidden}
.prelude.is-waiting .prelude-caption{font:clamp(40px,9vw,64px)/1 var(--display);
  color:var(--paper);margin-top:0;letter-spacing:.02em}
.prelude.is-waiting .prelude-inner:after{content:"For Nivethidha";display:block;
  font:22px Caveat,cursive;color:#d8aeb0;margin-top:20px}

@media(max-width:700px){
  .prelude-inner{width:88vw}
  .prelude-kicker{font-size:11px;margin-bottom:16px}
  .prelude-card img{max-height:52vh}
  .prelude-caption{font-size:21px;margin-top:16px}
}
@media(prefers-reduced-motion:reduce){.prelude-card{transition:none}}

/* .prelude sets display:grid, which overrides the hidden attribute's default
   display:none - so it painted an empty panel over the site whether or not the
   script ran. hidden must win. */
.prelude[hidden]{display:none!important}
