/* One magnolia stationery suite, from the opening portal to the reply. */
:root{--paper:#f7f2e8;--light:#fffaf2;--line:#c8b58f;--gold:#ae8d55;--ink:#57452f;--action:#785c32;--shadow:0 18px 50px #67513618}
body{background:var(--paper)}
.welcome::before{background:linear-gradient(90deg,transparent,#fffaf02b 30%,#fffaf02b 70%,transparent)}
.welcome-frame{display:none}
.welcome-content{padding:25px 12px}
.welcome h1{font-size:clamp(78px,8vw,108px);line-height:.98;color:#785c32;text-shadow:none}

/* The header carries no bar of its own. It was a band of solid cream with a hairline under it,
   sitting across the top of a garden, and it read as a strip laid over the design rather than part
   of it. What is left is the one control that has to stay reachable, lifted off the page: ivory
   that lets the garden through, a hairline of champagne to hold its edge, and a shadow soft enough
   to read as paper resting on paper rather than a button. The blur is what keeps the icon legible
   when a magnolia happens to pass behind it. */
.masthead{background:none;border-bottom:0}
.sound-toggle{
  pointer-events:auto;
  /* Lighter than the paper rather than tinted against it, so the lift comes from the disc being
     nearer the light than the page is. Over the garden the blur does the work; over flat
     stationery the paper and the disc are only a few percent apart, so the hairline and the
     shadow are what actually hold the edge - at the first pass they were too faint and both
     controls disappeared for most of the scroll. */
  background:#fffdf8e0;
  -webkit-backdrop-filter:blur(10px) saturate(1.08);
  backdrop-filter:blur(10px) saturate(1.08);
  border:1px solid #c3ae7f7d;
  box-shadow:0 3px 11px #6b53302b,0 1px 2px #6b53301f,inset 0 1px 0 #fffffacc;
  border-radius:999px;
  transition:background .15s ease,box-shadow .15s ease,border-color .15s ease,color .15s ease;
}
.sound-toggle:hover{background:#fffefb;border-color:#b99f6aa8;box-shadow:0 6px 18px #6b533036,0 1px 2px #6b53301f,inset 0 1px 0 #fffffacc}
.sound-toggle:hover{color:var(--action)}
/* The ring now leaves the disc instead of pulsing inside it, so the beat reads as a halo around
   the control rather than as something rattling within it. */
.sound-toggle::after{width:44px;height:44px;border-color:var(--gold)}
@keyframes sound-pulse{0%{opacity:.32;scale:.86}70%,100%{opacity:0;scale:1.5}}
.section{isolation:isolate;max-width:none;padding:110px max(9%,24px)}
/* The paper's flowers run down both edges at their own proportions, however long the section. They used
   to be one sheet stretched to the section's box, which on a phone - where a section is several screens
   tall - pulled every flower long. Each edge is now its own strip, a sixth of the width, repeated down
   the page; the strip is followed by its own mirror image, so the vine meets itself at every join rather
   than breaking off. The plain paper between them is cut from the same sheet. */
.section::before{content:'';position:absolute;inset:0;z-index:-1;pointer-events:none;background:url('assets/magnolia-suite/paper-flora-left.webp') left top/18.55% auto repeat-y,url('assets/magnolia-suite/paper-flora-right.webp') right top/18.55% auto repeat-y,url('assets/magnolia-suite/paper-plain.webp') center/cover;opacity:.76}
.section:not(.invitation)::after{width:100px;left:calc(50% - 50px);background:var(--line)}
.section>h2{max-width:780px}
.section>p:not(.disclosure){max-width:580px}
.invitation{padding-top:90px}
.photo-invitation{max-width:1050px;margin-inline:auto;padding-bottom:30px}

/* ---------- The couple at the head of the letter ----------
   A graphite pencil portrait of the two of them, from their photograph under the bell arch with the
   arch and the garden left out, that draws itself when the letter comes into view (couple-drawing.js).
   It stands where the house crest stood: the letter is from the two of them, so they head it. The
   pencil is the invitation's gold, pale champagne in the light strokes and the letter's dark ink in
   the darkest, so it sits on the ivory paper like the lettering. The figure is the drawing's own shape, 834 by
   1200, sized by its height and as large as the letter allows, because the detail is in their faces. */
.couple-drawing{--tall:clamp(400px,42vw,580px);position:relative;margin:-14px auto 22px;width:min(100%,calc(var(--tall) * 834 / 1200));aspect-ratio:834/1200;cursor:pointer;-webkit-tap-highlight-color:transparent}
.couple-drawing canvas{position:absolute;inset:0;width:100%;height:100%}
/* The pencil that draws them: ivory lacquer, a gold ferrule, and a lead the colour of the drawing. It
   is held as a right hand holds it, its point at the end of the stroke, leaning a little with the
   hand's movement. Between strokes it lifts - its shadow draws away and it grows a touch nearer - and
   when the drawing is done it is lifted away. */
.couple-pencil{position:absolute;left:0;top:0;width:34%;height:0;pointer-events:none;opacity:0;--lift:0;--tilt:0deg;
  filter:drop-shadow(calc(2px + 6px * var(--lift)) calc(3px + 9px * var(--lift)) calc(1.5px + 3px * var(--lift)) #4b371c52);
  transition:opacity .45s;will-change:transform}
.couple-pencil svg{position:absolute;left:0;top:0;width:100%;height:auto;overflow:visible;transform-origin:0 50%;
  transform:translateY(-50%) rotate(calc(-50deg + var(--tilt))) scale(calc(1 + .05 * var(--lift)))}
.couple-drawing.is-drawing .couple-pencil{opacity:1}
.couple-drawing:not(.is-drawing) .couple-pencil{transition:opacity .6s,transform .7s cubic-bezier(.2,.7,.2,1)}
@media(max-width:700px){.couple-drawing{--tall:clamp(320px,110vw,440px);margin:-6px auto 16px}}

/* ---------- The prints ----------
   The photographs are cards in the suite: printed on handmade cotton paper with a torn deckle edge,
   made of the same materials as everything around them. The paper is the letter's own stock. Each
   picture sits inside a plate mark, the pressed rectangle an etching leaves in the sheet, which is the
   engraved-plate idea the house mark is drawn on. */
.print-paper{
  position:relative;display:block;padding:var(--pad);clip-path:url(#deckle);
  background:linear-gradient(#fffbf3e6,#fffbf3e6),url('assets/magnolia-suite/paper.webp') 50% 50%/320% auto;
}
/* The plate mark: pressed in, so its upper and left walls are in shade and its lower and right walls
   catch the light. It sits a finger's width outside the image, as it does on a real print. */
.print-paper::before{
  content:'';position:absolute;inset:calc(var(--pad) * .55);pointer-events:none;
  box-shadow:inset 1px 1px 0 #b79c6b59,inset -1px -1px 0 #fffffae6,1px 1px 0 #fffffab3,-1px -1px 0 #c9b28a33;
}
.print-photo{position:relative;display:block;aspect-ratio:4/5;overflow:hidden;isolation:isolate;background:#3a2d1f}
.print-photo img{
  position:absolute;left:0;top:-5%;width:100%;height:110%;object-fit:cover;object-position:50% 22%;
}
.invitation-letter{position:relative;background:linear-gradient(#fffaf2cf,#fffaf2cf),url('assets/magnolia-suite/paper-flora-left.webp') left top/18.55% auto repeat-y,url('assets/magnolia-suite/paper-flora-right.webp') right top/18.55% auto repeat-y,url('assets/magnolia-suite/paper-plain.webp') center/cover;padding:52px 60px;outline-offset:-14px}

/* ---------- The gallery: a stack of prints ----------
   The prints - deckled cotton paper, the pressed plate mark - piled on the table. Each has a pair of
   soft shadows rather than a box-shadow, because the deckle is a clip and a clip takes any shadow on the
   same element with it: a broad one lifts the sheet off the page and a tight one puts it down on it.
   The top one lies nearly square to the guest; the two beneath it
   are turned further, each its own way, so their edges show and the pile reads as a pile. Turning one
   over throws it aside the way a hand would and the next settles up into its place; leafing back
   brings it in again on the same path and at the same pace, so the two read as one motion. Tall prints take
   most of the table's width and wide ones all of it, so both feel the same size in the hand. */
.print-stack{--table:min(520px,88vw);--tall:70%;--fly:.9s;--glide:cubic-bezier(.25,.8,.25,1);margin:46px auto 8px;width:var(--table)}
.stack-table{display:grid;place-items:center;padding:18px 0 26px;touch-action:pan-y;user-select:none;-webkit-user-select:none;cursor:grab;outline-offset:6px;border-radius:6px}
.stack-table:focus-visible{outline:2px solid var(--action)}
.stack-table:active{cursor:grabbing}
.stack-print{--pad:clamp(9px,1.6vw,15px);grid-area:1/1;position:relative;z-index:calc(20 - var(--depth,0));width:var(--tall);margin:0;opacity:0;
  rotate:var(--tilt);translate:calc(var(--depth,0) * 3px) calc(var(--depth,0) * 4px);
  transition:rotate var(--fly) var(--glide),translate var(--fly) var(--glide),scale var(--fly) var(--glide),opacity .3s ease}
.stack-print.is-wide{width:100%}
.stack-print::before,.stack-print::after{content:'';position:absolute;z-index:-1;pointer-events:none;background:#4b371c;border-radius:8px}
.stack-print::before{inset:8% 5% 0;translate:0 18px;filter:blur(20px);opacity:.2}
.stack-print::after{inset:1.5% 1%;translate:0 2px;filter:blur(3px);opacity:.14}
.stack-print .print-photo{aspect-ratio:auto}
.stack-print .print-photo img{position:static;display:block;width:100%;height:auto;pointer-events:none;-webkit-user-drag:none}
.stack-print:not([data-depth]):first-child,.stack-print[data-depth="0"],.stack-print[data-depth="1"],.stack-print[data-depth="2"]{opacity:1}
.stack-print:not([data-depth]):first-child,.stack-print[data-depth="0"]{rotate:calc(var(--tilt) * .3)}
.stack-print[data-depth="1"],.stack-print[data-depth="2"]{scale:.975}
.stack-print:nth-child(1){--tilt:-3deg}.stack-print:nth-child(2){--tilt:2.6deg}.stack-print:nth-child(3){--tilt:-1.8deg}
.stack-print:nth-child(4){--tilt:3.6deg}.stack-print:nth-child(5){--tilt:-2.6deg}.stack-print:nth-child(6){--tilt:1.6deg}
.stack-print:nth-child(7){--tilt:-4deg}.stack-print:nth-child(8){--tilt:3deg}.stack-print:nth-child(9){--tilt:-2deg}
.stack-print:nth-child(10){--tilt:4deg}.stack-print:nth-child(11){--tilt:-3.4deg}.stack-print:nth-child(12){--tilt:2deg}
.stack-print:nth-child(13){--tilt:-1.2deg}.stack-print:nth-child(14){--tilt:3.2deg}.stack-print:nth-child(15){--tilt:-2.4deg}
/* Set aside: carried off past the table's edge on the side it was pushed, turning as it goes. */
.stack-print.is-thrown{z-index:30;opacity:0;translate:calc(var(--throw,-1) * 118%) -6%;rotate:calc(var(--throw,-1) * 18deg);
  transition:translate var(--fly) var(--glide),rotate var(--fly) var(--glide),opacity .35s ease .25s}
.stack-print.is-still,.stack-print.is-dragging{transition:none}
.stack-controls{display:flex;align-items:center;justify-content:center;gap:22px;margin-top:4px}
.stack-turn{display:grid;place-items:center;width:46px;height:46px;border:1px solid #cbb68e;border-radius:50%;color:var(--action);background:#fffaf2b3;transition:background .2s,border-color .2s}
.stack-turn:hover{background:#f3e8d2;border-color:var(--gold)}
.stack-turn svg{width:18px;height:18px;fill:none;stroke:currentColor;stroke-width:1.4;stroke-linecap:round;stroke-linejoin:round}
.stack-count{min-width:70px;margin:0;font:17px Figures,Italiana,serif;letter-spacing:.12em;color:var(--muted);font-variant-numeric:tabular-nums}
.stack-count b{font-weight:400;color:var(--action)}
.stack-count span{color:var(--gold);margin:0 2px}
@media(max-width:700px){.print-stack{--tall:80%;margin-top:34px}}
blockquote{padding:30px 12px 0;font-size:32px;color:var(--action)}
/* The couple's line opens the invitation, so its space falls below it, toward the letter. */
.invitation>blockquote{margin:0 auto 56px;padding-top:0}
@media(max-width:700px){.invitation>blockquote{margin-bottom:38px}}
.scratch-card{height:280px;max-width:440px;background:var(--light) url('assets/magnolia-suite/paper.webp') center/100% 100%;border-radius:4px}
.date-reveal{margin:10px;height:calc(100% - 20px)}
.scratch-label span{font-family:Calligraphy,cursive;font-size:60px}
.scratch-label p{font-size:13px}
.calendar-actions{margin-top:30px}
.button{border-radius:2px;font-size:13px;min-height:52px}
.countdown{max-width:560px;padding-block:20px;border-block:1px solid #c8b58f88}
.countdown b{font-size:56px}
.countdown>div+div{border-left:0}
.countdown span{font-size:12px}
.timeline{max-width:720px;margin-top:55px}
.timeline li{padding-bottom:42px}
.timeline h3{font-size:31px}
.timeline p{font-size:14px}
.timeline-mark{background:var(--paper);border:1px solid var(--gold);width:11px;height:11px;left:202px}
.architecture{max-width:1000px;margin-top:45px}
.venue address{font-size:25px}
.reply-card{background:linear-gradient(#fffaf2d9,#fffaf2d9),url('assets/magnolia-suite/paper-flora-left.webp') left top/18.55% auto repeat-y,url('assets/magnolia-suite/paper-flora-right.webp') right top/18.55% auto repeat-y,url('assets/magnolia-suite/paper-plain.webp') center/cover;max-width:600px;padding:48px 58px;outline-offset:-14px}
.reply-card h3{font-size:49px}
.reply-card label,.reply-card legend{font-size:13px}
.closing{position:relative;isolation:isolate;padding:90px 24px 65px;background:url('assets/magnolia-suite/garden.webp') center 68%/cover}
.closing::before{content:'';position:absolute;inset:0;background:#fffaf2b8;z-index:-1}
.closing>p:not(.closing-names){font-size:13px}
@media(min-width:1000px){.date-section,.agenda,.venue,.response{padding-inline:18%}.response::before{opacity:.85}}
@media(max-width:700px){
 .welcome{background-position:center;min-height:100svh;padding:140px 26px 100px}
 .welcome-content{padding:0}
 .welcome h1{font-size:clamp(65px,18vw,88px)}
 .welcome-wording{font-size:18px;margin-bottom:25px}

 .section{padding:78px 26px}
 .section::before{opacity:.48}
 .section>h2{font-size:44px}
 .photo-invitation{padding-bottom:25px}
 .invitation-letter{padding:38px 26px;background:linear-gradient(#fffaf2e6,#fffaf2e6),url('assets/magnolia-suite/paper-flora-left.webp') left top/18.55% auto repeat-y,url('assets/magnolia-suite/paper-flora-right.webp') right top/18.55% auto repeat-y,url('assets/magnolia-suite/paper-plain.webp') center/cover}
 .invitation-letter h2{font-size:40px}
 .invitation-letter .couple-names{font-size:32px}
 blockquote{font-size:26px;padding:8px 0 0}
 .scratch-card{height:260px;margin-top:32px}
 .countdown b{font-size:39px}.countdown span{font-size:11px}
 .timeline{margin-top:38px;padding-left:7px}
 .timeline li{padding-bottom:32px;padding-left:28px}
 .timeline-mark{left:-1px}
 .timeline h3{font-size:27px}.timeline p{font-size:14px}
 .architecture{margin-top:32px}
 .reply-card{padding:38px 30px;background:linear-gradient(#fffaf2e8,#fffaf2e8),url('assets/magnolia-suite/paper-flora-left.webp') left top/18.55% auto repeat-y,url('assets/magnolia-suite/paper-flora-right.webp') right top/18.55% auto repeat-y,url('assets/magnolia-suite/paper-plain.webp') center/cover}
 .reply-card h3{font-size:44px}
 .closing{padding-block:112px 50px}
 .closing::before{background-image:linear-gradient(#fffaf2bd,#fffaf2bd),url('assets/magnolia-suite/portrait.webp');-webkit-mask-image:linear-gradient(to bottom,transparent,#000 170px);mask-image:linear-gradient(to bottom,transparent,#000 170px)}
 .closing-names{font-size:38px}
}

/* ---------- Typography: Pinyon Script carries the names, Julius Sans One the figures ---------- */
@font-face{font-family:Script;src:url('assets/fonts/pinyon-script.ttf') format('truetype');font-display:swap}
@font-face{font-family:Figures;src:url('assets/fonts/julius-sans-one.ttf') format('truetype');font-display:swap}
/* The script is reserved for the two names; everything else keeps the established faces. */
.welcome h1,.invitation-letter .couple-names{font-family:Script,cursive}
.welcome h1{font-size:clamp(72px,7.6vw,104px);line-height:1.02}
.welcome h1 .amp{font-family:Italiana,serif;font-size:.26em;line-height:1.15;color:var(--gold)}
.date-reveal b,.date-reveal time>span,.countdown b{font-family:Figures,serif}

.countdown b{font-size:60px}

/* ---------- The crest, at one size in the masthead and another above each section ---------- */
.flourish{width:92px;height:auto;aspect-ratio:112/120;margin-bottom:24px;overflow:visible}
.invitation-letter .flourish{margin-bottom:20px}
/* Dash properties inherit through the <use> shadow tree, so the crest draws itself in. */

/* ---------- The arrival dissolves into the stationery instead of cutting ---------- */
/* The arrival needs air: the names, the crest and the date each get their own breathing room. */
.welcome{padding-bottom:120px}
.welcome-wording{margin-bottom:40px;letter-spacing:.04em;text-wrap:balance}
.welcome h1{line-height:1.14}
.welcome h1 .amp{margin:.1em 0}

.scroll-cue{margin-top:44px}
.welcome::after{content:'';position:absolute;left:0;right:0;bottom:-1px;height:min(34vh,235px);z-index:-1;pointer-events:none;background:linear-gradient(to bottom,#f7f2e800,#f8f3ea9e 46%,var(--paper))}
.invitation::before{-webkit-mask-image:linear-gradient(to bottom,transparent,#000 240px);mask-image:linear-gradient(to bottom,transparent,#000 240px)}

/* ---------- Scroll choreography ---------- */
.scroll-progress{position:absolute;left:0;top:0;width:100%;height:2px;transform-origin:left center;scale:0 1;pointer-events:none;background:linear-gradient(90deg,#dcc9a0,var(--gold));box-shadow:0 1px 3px #6b533024}
/* Every duration here is a whole number of beats of the score (0.6s at 100bpm): opacity resolves in
   one beat, movement in a beat and a half, and no cascade of staggered children runs longer than a
   single beat. Reveals therefore land on the pulse of whatever is playing underneath them without
   needing to be driven from script. Nothing is still arriving once you have scrolled past it —
   anything slower reads as broken rather than graceful. */
.motion-ready [data-reveal]{opacity:0;transition:opacity .6s cubic-bezier(.16,1,.3,1) var(--d,0s),translate .9s cubic-bezier(.16,1,.3,1) var(--d,0s),scale .9s cubic-bezier(.16,1,.3,1) var(--d,0s),transform .9s cubic-bezier(.16,1,.3,1) var(--d,0s),filter .6s ease-out var(--d,0s)}
/* --dir is +1 when an element will return from below and -1 when it will return from above, so a
   reveal always travels with the scroll instead of fighting it on the way back up. */
.motion-ready [data-reveal=up]{translate:0 calc(22px * var(--dir,1));filter:blur(3px)}
.motion-ready [data-reveal=scale]{scale:.962}
/* Cards tilt up out of the page — the one place a real 3D transform earns its keep. */
.motion-ready [data-reveal=lift]{transform:perspective(1100px) rotateX(calc(11deg * var(--dir,1))) translateY(calc(34px * var(--dir,1)));transform-origin:50% calc(50% + 50% * var(--dir,1))}
.motion-ready [data-reveal].shown{opacity:1;translate:none;scale:none;transform:none;filter:none}

/* ---------- The programme lights up the act you are reading ---------- */
.timeline h3{transition:color .6s ease}
.timeline li>time{transition:opacity .6s ease,color .6s ease}
.timeline li>div{padding:12px 18px;margin:-12px -18px;border-radius:3px;transition:opacity .6s ease,background .6s ease,translate .6s cubic-bezier(.16,1,.3,1)}
.motion-ready .timeline li:not(.is-active)>div,.motion-ready .timeline li:not(.is-active)>time{opacity:.62}
.timeline li.is-active>div{background:#fffaf2a8;translate:7px 0}
.timeline li.is-active h3{color:var(--action)}
.timeline li.is-active>time{color:var(--gold)}
.timeline-mark{transition:scale .6s cubic-bezier(.16,1,.3,1),background .6s ease,box-shadow .6s ease}
.timeline li.is-active .timeline-mark{scale:1.5;background:var(--action);border-color:var(--action);box-shadow:0 0 0 6px #ac8b511f}
.timeline li::after{content:'';position:absolute;left:207px;top:14px;bottom:0;width:1px;background:var(--gold);transform-origin:top center;scale:1 0;transition:scale .9s cubic-bezier(.4,0,.2,1)}
.timeline li:last-child::after{display:none}
.timeline li.is-active::after,.timeline li.is-passed::after{scale:1 1}

/* ---------- The letter: pressed stationery, names as the centrepiece ---------- */
.invitation-letter{max-width:628px;padding:70px 62px 86px;box-shadow:0 30px 80px #5b45241f,0 1px 0 #fffdf9 inset}
.invitation-letter::before{content:'';position:absolute;inset:22px;border:1px solid #c8b58f59;pointer-events:none}
.letter-label{text-transform:uppercase;letter-spacing:.28em;font-size:10px;color:var(--muted)}
/* The card carries one script voice — the names. The sentiment line steps back into Italiana. */
.invitation-letter h2{font:400 clamp(27px,3.5vw,35px)/1.4 Italiana,serif;letter-spacing:.06em;color:#6b563a;margin:22px 0 10px}
.invitation-letter>p:not(.letter-label):not(.couple-names):not(.signature):not(.letter-place):not(.letter-greeting){font-size:13px;color:#6b563a}
.invitation-letter .couple-names{font:400 clamp(48px,6.6vw,68px)/1.24 Script,cursive;margin:38px 0 34px;color:var(--action)}
.couple-names span{display:block;font-family:Italiana,serif;font-size:.3em;line-height:1;margin:.2em 0 .16em;color:var(--gold)}
.letter-place{position:relative;font:14px/1.6 Italiana,serif;letter-spacing:.12em;text-transform:uppercase;color:var(--action);padding:22px 0;margin:26px auto 20px;max-width:340px}
.letter-place span{margin-inline:6px;color:var(--gold)}
.letter-place::before,.letter-place::after{content:'';position:absolute;left:50%;translate:-50% 0;width:180px;height:1px;background:linear-gradient(90deg,transparent,var(--line) 22%,var(--gold) 50%,var(--line) 78%,transparent)}
.letter-place::before{top:0}
.letter-place::after{bottom:0}
.invitation-letter .signature{font:24px/1.55 Italiana,serif;color:var(--action);text-wrap:balance}
/* On a guest's own link the letter opens with their name, in the signature's voice. */
.invitation-letter .letter-greeting{font:24px/1.55 Italiana,serif;color:var(--action);margin-bottom:14px;text-wrap:balance}
.letter-seal{width:78px;height:78px;margin:30px auto -66px;rotate:-8deg;filter:drop-shadow(0 8px 14px #4b371c33)}
blockquote{color:var(--gold)}
.memory-gallery figure{transition:translate .6s cubic-bezier(.16,1,.3,1)}
.memory-gallery figure::before{transition:translate .6s cubic-bezier(.16,1,.3,1),opacity .6s ease}
/* Only where there is a real pointer. A phone treats a tap as a hover that sticks until the next tap
   somewhere else, which left a photograph lifted out of the row after the guest merely touched it. */
@media(hover:hover){.memory-gallery figure:hover{translate:0 -8px}.memory-gallery figure:hover::before{translate:0 26px;opacity:.26}}

/* ---------- The foil card: a lace-edged cameo, die-cut, rather than a gold slab ----------
   Cut to the #cameo outline in the document, the same one the language panels use. Its width sets its
   height at the cameo's own 0.84 : 1. A clip takes borders and shadows with it, so the plate carries
   the card: its ::before is the die-cut edge, its ::after the paper one pixel inside, and its
   drop-shadow follows the scallops. The shadow sits on the plate and not the card because the scroll
   reveal clears the card's own filter, and because the plate never repaints while the foil does.
   The card's rounded corner is only there so the focus ring is an oval around the cameo. */
.scratch-card{width:min(100%,360px);max-width:none;height:auto;aspect-ratio:.84;overflow:visible;border-radius:50%;background:none;box-shadow:none}
.scratch-card:focus-within{outline:2px solid var(--action);outline-offset:5px}
.scratch-plate{position:absolute;inset:0;z-index:-1;pointer-events:none;filter:drop-shadow(0 22px 28px #5b452424)}
.scratch-plate::before,.scratch-plate::after{content:'';position:absolute;inset:0;clip-path:url(#cameo)}
.scratch-plate::before{background:#cfbc95}
.scratch-plate::after{inset:1px;background:var(--light) url('assets/magnolia-suite/paper.webp') center/100% 100%}
/* The revealed face is a plain oval nine pixels inside the scallops, with its rule seven more
   inside that - exactly where the foil's two pressed rules lie - so the card reads as one object
   before and after scratching rather than a decorated lid over a blank card. */
.date-reveal{position:absolute;inset:calc(3.05% + 9px) calc(3.63% + 9px);margin:0;height:auto;border-color:#d8c6a2;border-radius:50%;padding:11% 10% 12%;background:radial-gradient(ellipse at 50% 38%,#fffdf8,#fdf9f0 62%,#f7f1e3)}
.date-reveal::before{content:'';position:absolute;inset:7px;border:1px solid #cbb68e6b;border-radius:50%;pointer-events:none}
.reveal-crest{width:58px;height:auto;aspect-ratio:112/120;color:var(--gold);margin-bottom:6px;opacity:.9}
.date-reveal>span{color:var(--gold);letter-spacing:.36em;font-size:10px}
.date-reveal time{font-family:Figures,serif}
.date-reveal b{font-size:78px;line-height:.98;color:var(--action)}
.date-reveal time>span{font-size:17px;letter-spacing:.14em;text-transform:uppercase;margin-top:6px;color:var(--action)}
.date-reveal p{font-size:9px;letter-spacing:.17em;text-transform:uppercase;color:var(--muted);margin-top:12px}
.send-actions{display:grid;gap:10px;margin:16px 0 12px}
/* The Sinhala label runs to two lines on a phone; balanced, it never leaves one word on the second. */
.reply-card>.button{text-wrap:balance}
#people-hint{display:block;margin:-14px 0 22px;font-size:11px;color:var(--muted)}
.reply-general{margin-top:34px}
#prepared>.button.secondary{width:100%}
.scratch-sheen{position:absolute;inset:0;opacity:0;pointer-events:none;clip-path:url(#cameo);background:linear-gradient(105deg,transparent 38%,#fff6dc8c 47%,#fffefa9e 50%,#fff6dc8c 53%,transparent 62%);background-size:280% 100%;transition:opacity .3s}
.motion-ready .scratch-sheen{opacity:1;animation:foil-sheen 4.8s cubic-bezier(.55,0,.3,1) infinite}
@keyframes foil-sheen{0%,22%{background-position:130% 0}62%,100%{background-position:-40% 0}}
/* The oval narrows towards its foot, so the words sit higher than they did on the flat-bottomed card
   and are held to the width the oval has there. */
/* The words are struck into the foil by invitation.js, round the foot of the oval, so they scratch
   away with it. The label stays in the markup only as the source of the words in each language. */
.scratch-label{visibility:hidden}
.scratch-card.scratching .scratch-sheen,.scratch-card.revealed .scratch-sheen{opacity:0}
.motion-ready .scratch-card.revealed .date-reveal{animation:date-bloom 1.8s cubic-bezier(.16,1,.3,1)}
@keyframes date-bloom{0%{scale:.94;box-shadow:0 0 0 0 #d9bc7a00 inset}35%{box-shadow:0 0 70px 10px #e6c88d5c inset}100%{scale:1;box-shadow:0 0 0 0 #d9bc7a00 inset}}

/* ---------- The closing: the garden returns gradually, not on a hard edge ---------- */
/* The imagery moves onto the pseudo-element so it can be masked; masking .closing itself would
   fade the rings and the names with it. */
.closing{background:var(--paper);padding-top:132px}
.closing::before{background-image:linear-gradient(#fffaf2bd,#fffaf2bd),url('assets/magnolia-suite/garden.webp');background-size:cover,cover;background-position:center,center 68%;-webkit-mask-image:linear-gradient(to bottom,transparent,#000 240px);mask-image:linear-gradient(to bottom,transparent,#000 240px)}

/* ---------- The closing: two linked bands, names quiet beneath ---------- */
/* The closing carries the couple's own mark rather than a pair of rings, and it draws itself there
   exactly as it does on the first screen -- against the scroll that reaches it instead of the
   clock, which is all --fig changes. It is a clone of the hero node, so its weights, colours and
   geometry come along with it and only its size and its trigger are set here. */
.closing-crest{
  --fig:0s;
  display:block;width:min(158px,42vw);height:auto;aspect-ratio:1;margin:0 auto 26px;overflow:visible;
  color:var(--gold);fill:none;stroke:currentColor;stroke-linecap:round;stroke-linejoin:round;
}
.closing-names{font-size:19px;letter-spacing:.2em;text-transform:uppercase;font-family:Italiana,serif;color:var(--action)}

/* ---------- Ambient drift ---------- */
.petal-drift{position:fixed;inset:0;width:100%;height:100%;z-index:1;pointer-events:none;opacity:0;transition:opacity 1.8s ease}
.petal-drift.lit{opacity:1}

@media(max-width:700px){
 /* The script's swashes run past the advance width, so phones need their own setting. */
 .welcome h1{font-size:clamp(42px,15.5vw,72px)}

 .invitation-letter{padding:44px 26px 62px}
 .invitation-letter .couple-names{font-size:clamp(38px,11vw,50px);margin:22px 0 20px}
 .letter-place{font-size:12px;padding:17px 0;margin:20px auto 16px}
 .letter-place::before,.letter-place::after{width:140px}
 .invitation-letter .signature,.invitation-letter .letter-greeting{font-size:21px}
 .letter-seal{width:64px;height:64px;margin:24px auto -52px}
 .date-reveal b{font-size:68px}
 .date-reveal time>span{font-size:15px}
 .reveal-crest{width:50px;margin-bottom:4px}
 .countdown b{font-size:44px}
}

@media(max-width:700px){
 .flourish{width:78px;margin-bottom:18px}

 .welcome{padding-bottom:95px}
 .welcome::after{height:min(26vh,170px)}
 .invitation::before{-webkit-mask-image:linear-gradient(to bottom,transparent,#000 150px);mask-image:linear-gradient(to bottom,transparent,#000 150px)}
 .invitation-letter::before{inset:13px}
 .timeline li::after{left:4px}
 .timeline li>div{padding:9px 12px;margin:-9px -12px}
 .timeline li.is-active>div{translate:4px 0}
}

/* ---------- The arrival: the medallion draws itself, then the names are written ----------
   One figure in three movements, cut from the same grid as everything else: the score is 100bpm,
   so a beat is 0.6s and a bar 2.4s, and every delay below is a whole number of half-beats. The
   figure runs 6s - two and a half bars - and it is cued to start 3.6s into the door sequence, so
   the first line is already surfacing while the camera is still moving through the arch. Six
   seconds later the invitation has finished introducing itself at exactly four bars from the
   press, which is where the recording's own phrase ends.

   `--arrive` carries that lead. The doors set it to what is left of their own run; every path that
   skips the entrance sets it to zero and the figure simply plays from the top. Nothing here is
   driven from script beyond that one number and the class that starts it.

   Everything that begins hidden is scoped to .motion-ready, which is only ever added when the
   guest has not asked for less motion and the engine has the properties this is written in. A
   browser that never gets the class is shown the finished arrival rather than an empty screen. */
/* --arrive is the arrival's lead, handed over by the door sequence. --fig is the base offset every
   step of the figure hangs off, so one set of rules can drive the hero (which plays against that
   lead) and the closing (which plays against the scroll that reaches it, from zero). */
:root{--arrive:0s;--fig:var(--arrive)}

.welcome-crest{
  --fig:var(--arrive);
  /* The base rule gives every svg a 22px box; the medallion needs its own, and an explicit
     auto height so the square aspect can take effect at all. */
  display:block;width:min(214px,29vw,23svh);height:auto;aspect-ratio:1;margin:0 auto clamp(12px,2.6svh,22px);overflow:visible;
  color:var(--gold);fill:none;stroke:currentColor;stroke-linecap:round;stroke-linejoin:round;
}
/* Four weights, and they are what separates a plate from an icon. The frame is twice the inner
   rule; the laurel sits between them; the veins are the finest line on the page. Give these one
   shared value again and the mark collapses back into clipart however well it is drawn. */
/* Measured at the size it actually ships, not at the size it is drawn. The viewBox is 200 units
   wide and the mark renders at 214px on a laptop and 176px on a phone, so a 0.6-unit rule lands
   under two thirds of a device pixel and antialiases away to nothing on the phone. These are the
   weights that keep the 2:1 frame-to-rule ratio legible at the smaller of the two. */
.wc-ring{stroke-width:1.6}
.wc-rule{stroke-width:.8}
/* The sepals live inside scaled groups, so each is drawn finer by its own scale. */
.wc-leaf{stroke-width:1.05}
.wc-petal{stroke-width:1.15}
.wc-vein{stroke-width:.62}
.wc-tip{fill:currentColor;stroke:none}
/* The only filled mass in the mark, and a shade deeper than the linework, so the initials read as
   the subject and the frame reads as the setting. Not scoped to .welcome-crest: the closing's mark
   is a clone of that node under a different class, and scoping these left its initials falling back
   to the browser's default face. */
.wc-letter{font-family:Script,cursive;fill:#6d5228;stroke:none}
.wc-swash{fill:#6d5228;stroke:none}
.wc-amp{font-family:Italiana,serif;fill:var(--gold)}
.wc-leaf,.wc-petal,.wc-flare,.wc-tip{transform-box:fill-box;transform-origin:50% 100%}
.wc-flare,.wc-tip{transform-origin:50% 50%}
.wc-flare{stroke-width:2.4;opacity:0}
/* The nib is the one part that is decoration rather than drawing, and the one part that can fail
   to know where it belongs: without a motion path it would sit at the corner of the viewBox. It
   is therefore invisible by default and only lit inside the @supports that can place it. */
.wc-nib{fill:#a97f36;stroke:none;opacity:0;transform-box:fill-box;transform-origin:50% 50%;
  /* Cream on cream is invisible here: on this paper the readable light is a warm amber point
     with a pale halo, not a white one. */
  filter:drop-shadow(0 0 2.5px #fff6dc) drop-shadow(0 0 6px #e8cd93)}

.motion-ready .welcome-wording,
.motion-ready .welcome h1 .amp,
.motion-ready .scroll-cue{opacity:0}
/* Every "not drawn yet" state below is scoped to the two medallions that actually draw themselves.
   Written bare, as .motion-ready .wc-petal, they also reached the small crests, which are <use>
   copies of the #crest symbol and carry the same class names on their parts. Chrome does not match
   document selectors inside a <use> copy; Safari does. On an iPhone every section's crest lost its
   magnolia -- the petals, sepals and veins sat at their hidden starting state, waiting for an
   animation only the medallions are ever given. */
.motion-ready :is(.welcome-crest,.closing-crest) .wc-ring{stroke-dasharray:428;stroke-dashoffset:428}
.motion-ready :is(.welcome-crest,.closing-crest) .wc-rule{stroke-dasharray:340;stroke-dashoffset:340}
.motion-ready :is(.welcome-crest,.closing-crest) .wc-vein{stroke-dasharray:18;stroke-dashoffset:18}
.motion-ready :is(.welcome-crest,.closing-crest) .wc-tip{scale:0}
.motion-ready :is(.welcome-crest,.closing-crest) .wc-leaf{scale:0}
.motion-ready :is(.welcome-crest,.closing-crest) .wc-petal{scale:.15;opacity:0}
/* The ink front rests at the END of its travel, not the start. Without this the mask rect sits
   entirely left of the glyphs whenever .motion-ready is absent -- which is exactly the reduced
   motion case -- and the initials render invisible inside an otherwise complete medallion. */
.wc-ink{translate:var(--ink-to) 0}
.motion-ready .wc-ink{translate:var(--ink-from) 0}
/* The names are inscribed, not wiped. A soft-edged mask crossing the letters in a straight band never
   looked like writing, and the bloom of light that rode it was a sliding blob sitting on top of the
   lettering. Both are gone. Each name is the font's outline, traced by a champagne hairline in
   writing order, with the ink coming up behind the nib.

   Every letter is its own pair of small SVGs, one for the ink and one for the pen, each boxed to that
   letter's own ink, and that is a performance decision. A pen stroke is drawn by moving
   stroke-dashoffset, which is a paint property: no browser can hand it to the compositor, so every
   frame it changes the browser repaints whatever SVG it lives in. With each name in one SVG that
   meant re-rasterising forty-one glyph paths on every frame the pen moved, which is what made the
   writing stutter. Boxed per letter, a frame repaints only the letters the nib is actually on, and
   the ink fades are opacity on whole SVG elements, which the compositor runs without repainting.

   The pen no longer uses vector-effect:non-scaling-stroke. It holds a hairline at one width, but it
   makes the browser rebuild the stroke in screen space on every paint, which on curves this dense is
   expensive. The script sets --pen to one CSS pixel in the font's own units instead, and updates it
   when the type size changes with the viewport.

   Positioning is by baseline, not by box: --top is where each name's box sits relative to the
   baseline the live text used, and every letter is offset from it in the font's own units, so the
   outlines land exactly where the words used to. */
.welcome h1 .given{display:block;position:relative;height:1.14em}
/* height:auto beats the base svg rule's fixed 22px; each letter's aspect comes from its viewBox. */
.welcome h1 .letter{position:absolute;height:auto;overflow:visible}
/* stroke:none on the ink: the base svg rule would otherwise hand every letter an inherited hairline,
   which is invisible at this scale and still has to be painted. */
.letter.ink path{fill:#6d5228;stroke:none}
.letter.pen path{fill:none;stroke:var(--gold);stroke-width:var(--pen,24);stroke-linecap:round;stroke-linejoin:round}
/* The dash is what hides a pen line until its letter begins, and it only works with a dasharray to
   offset: without one stroke-dashoffset does nothing, and the full outline of both names sat on
   screen from page load, right across the medallion while it was meant to be drawing alone. Resting
   at a full offset means a trace that never gets its animation stays hidden and the ink alone
   carries the name. stroke-opacity rather than opacity: opacity on an SVG child can make the browser
   paint that path into a buffer of its own and composite it back, on every frame it repaints. */
.name-trace{opacity:0}
.motion-ready .name-trace.traceable{opacity:1;stroke-opacity:.95;stroke-dasharray:var(--len);stroke-dashoffset:var(--len)}

.motion-ready .arrived .welcome-crest .wc-ring,
.motion-ready .closing-crest.shown .wc-ring{animation:wc-draw 3.6s cubic-bezier(.45,.05,.2,1) var(--fig) both}
.motion-ready .arrived .welcome-crest .wc-rule,
.motion-ready .closing-crest.shown .wc-rule{animation:wc-draw 2.7s cubic-bezier(.4,0,.25,1) calc(var(--fig) + 1.2s) both}
.motion-ready .arrived .welcome-crest .wc-tip,
.motion-ready .closing-crest.shown .wc-tip{animation:wc-unfold .6s cubic-bezier(.2,.85,.3,1) calc(var(--fig) + 3.6s) both}
.motion-ready .arrived .welcome-crest .wc-ink,
.motion-ready .closing-crest.shown .wc-ink{animation:wc-ink 1.2s cubic-bezier(.5,.02,.4,1) calc(var(--fig) + 2.4s + var(--d,0s)) both}
/* The ampersand and the D follow the N a beat apart; the swash closes the lockup under them. */
#wc-ink-amp .wc-ink,#wc-ink-amp-close .wc-ink{--d:.6s}
#wc-ink-d .wc-ink,#wc-ink-d-close .wc-ink{--d:1.2s}
#wc-ink-swash .wc-ink,#wc-ink-swash-close .wc-ink{--d:2.1s}
/* The sepals open a breath before the petals they hold. */
.motion-ready .arrived .welcome-crest .wc-leaf,
.motion-ready .closing-crest.shown .wc-leaf{animation:wc-unfold .9s cubic-bezier(.2,.85,.3,1) calc(var(--fig) + 4.2s + var(--d,0s)) both}
.motion-ready .arrived .welcome-crest .wc-petal,
.motion-ready .closing-crest.shown .wc-petal{animation:wc-open 1.2s cubic-bezier(.22,1,.3,1) calc(var(--fig) + 4.5s + var(--d,0s)) both}
.motion-ready .arrived .welcome-crest .wc-vein,
.motion-ready .closing-crest.shown .wc-vein{animation:wc-draw .9s cubic-bezier(.4,0,.25,1) calc(var(--fig) + 5.4s + var(--d,0s)) both}
.motion-ready .arrived .welcome-crest .wc-flare,
.motion-ready .closing-crest.shown .wc-flare{animation:wc-flare 1.2s cubic-bezier(.2,.6,.3,1) calc(var(--fig) + 6s) both}
.motion-ready .arrived .welcome-crest{animation:wc-settle 1.8s cubic-bezier(.16,1,.3,1) calc(var(--fig) + 6.6s) both}
.motion-ready .arrived .welcome-wording{animation:wc-rise 1.2s cubic-bezier(.16,1,.3,1) calc(var(--fig) + 7.5s) both}
/* A bar each, three beats apart, and the light travels with the hand that writes them. */
/* A bar each, three beats apart. The pen finishes a name at 78% of its travel and lifts over the
   remaining 22%; the ink is already coming up behind it by then. */
/* linear, deliberately. An eased trace accelerates and brakes inside every letter, which makes the
   word pulse along letter by letter instead of flowing -- the single thing that made this read as
   appearing rather than being written. A nib moves at one speed, and each letter's travel is longer
   than the step between letters, so the next is under way before the last is finished and the line
   never stops. */
.motion-ready .arrived .welcome h1 .name-trace.traceable{animation:name-trace .75s linear calc(var(--fig) + 8.4s + var(--d,0s) + var(--i) * var(--step)) both}
/* The ink follows the nib rather than arriving all at once: each letter starts filling as the pen
   is a little over halfway through drawing it. */
.motion-ready .arrived .welcome h1 .letter.ink{animation:name-ink .5s ease-out calc(var(--fig) + 8.82s + var(--d,0s) + var(--i) * var(--step)) both}
/* The pen lifts off the whole name at once, and only once the ink is under it. Fading each stroke
   on its own schedule left the first letters with nothing holding them between the pen leaving and
   the fill arriving -- they blinked out and came back. */
.motion-ready .arrived .welcome h1 .letter.pen{animation:name-lift .6s ease calc(var(--fig) + 10.8s + var(--d,0s)) both}
.motion-ready .arrived .welcome h1 .given:last-child{--d:1.8s}
.motion-ready .arrived .welcome h1 .amp{animation:wc-rise .9s ease-out calc(var(--fig) + 10.2s) both}
.motion-ready .arrived .scroll-cue{animation:wc-rise .9s cubic-bezier(.16,1,.3,1) calc(var(--fig) + 12.3s) both}

@keyframes wc-rise{from{opacity:0;translate:0 14px;filter:blur(4px)}to{opacity:1;translate:none;filter:none}}
@keyframes wc-draw{to{stroke-dashoffset:0}}
@keyframes wc-unfold{from{scale:0}to{scale:1}}
@keyframes wc-open{from{scale:.15;opacity:0}to{scale:1;opacity:1}}
@keyframes wc-ink{to{translate:var(--ink-to) 0}}
@keyframes wc-flare{0%{opacity:0;scale:1}28%{opacity:.55}100%{opacity:0;scale:1.17}}
/* One letter's worth of pen. The stroke holds a moment after the letter closes and then lifts, so
   the word is never a row of outlines waiting together for the ink -- each one is handed over as
   the next begins. */
/* No opacity ramp: the stroke is there from the first frame and the dash alone reveals it. Fading
   each letter up as it began was a second "appearing" on top of the drawing. */
@keyframes name-trace{
  from{stroke-dashoffset:var(--len)}
  to{stroke-dashoffset:0}
}
@keyframes name-lift{from{opacity:1}to{opacity:0}}
@keyframes name-ink{from{opacity:0}to{opacity:1}}
/* --crest-lift is measured, not guessed: it is the distance from the mark's resting centre to the
   centre of the whole arrival, so the mark opens optically centred on the screen whatever the names
   below it happen to measure at this viewport. The fallback only matters if the script never ran. */
@keyframes wc-settle{from{translate:0 var(--crest-lift,-96px);scale:1.5}to{translate:none;scale:1}}

/* A point of light riding the ring as it closes. Same duration, delay and easing as the stroke it
   sits on, so the two cannot drift apart. */
@supports (offset-path:path("M0 0")){
  .motion-ready .arrived .welcome-crest .wc-nib,
  .motion-ready .closing-crest.shown .wc-nib{
    offset-path:path("M120.4 28.87A74 74 0 1 1 79.6 28.87");offset-rotate:0deg;
    animation:wc-nib 1.5s cubic-bezier(.45,.05,.2,1) calc(var(--fig) + .6s) both;
  }
  @keyframes wc-nib{0%{offset-distance:0%;opacity:0}12%{opacity:1}82%{opacity:1}100%{offset-distance:100%;opacity:0}}
}

/* ---------- The cue: a light that rises up the line, so the line says which way to go ----------
   It used to breathe in place, which reads as decoration. A mark that travels upward once a bar
   and then rests is an instruction. The track is a full gradient in its own right, so with motion
   turned off the cue is still a drawn line rather than an empty gap.

   The mark is ink, not light. A white highlight is the obvious choice and the wrong one here: on
   cream paper under a bright garden it vanishes. A soft bar of the same gold the line is drawn in
   reads at a glance and still counts as a whisper. It is sized and moved in percentages of itself,
   so one pair of keyframes serves the line at any height, and the track clips it at both ends. */
.scroll-cue{gap:14px;margin-top:clamp(24px,4.6svh,46px)}
.scroll-cue span{
  position:relative;width:2px;height:62px;border-radius:1px;transform-origin:center;
  background:linear-gradient(to bottom,#bda06600,#bda066 18%,#bda066 76%,#bda06600);
  animation:none;
}
/* The falling mark is ink with a lamp behind it. The ink is what reads on cream paper -- a white
   highlight disappears here, which the drawing nib taught first -- and the pale halo around it is
   what makes it read as lit rather than merely dark. The halo needs the track not to clip it, so
   the glow lives on a second layer that overflows while the mark itself stays inside. */
.scroll-cue span::after{
  content:'';position:absolute;left:50%;top:0;width:4px;height:60%;border-radius:2px;
  background:linear-gradient(to top,#6b4f2400,#5d431c 52%,#6b4f240d);
  box-shadow:0 0 12px 5px #fff3d2,0 0 22px 9px #f2ddaf99;
  opacity:0;translate:-50% -100%;
}
.motion-ready .scroll-cue span{animation:cue-track 4.8s cubic-bezier(.42,0,.45,1) infinite}
.motion-ready .scroll-cue span::after{animation:cue-fall 4.8s cubic-bezier(.42,0,.45,1) infinite}
@keyframes cue-track{0%,100%{opacity:.72}34%{opacity:1}}
@keyframes cue-fall{0%{opacity:0;translate:-50% 150%}9%{opacity:1}48%{opacity:1}60%,100%{opacity:0;translate:-50% -70%}}

/* The arrival is a whole screen of composition, so its rhythm answers to the height of the screen
   as well as its width: on a short laptop window the cue is otherwise the one thing pushed under
   the fold, and the cue is the one thing that has to be visible. */
.welcome{padding-block:clamp(78px,11svh,118px)}
.welcome-wording{margin-bottom:clamp(20px,3.4svh,38px)}
.welcome h1{font-size:clamp(58px,min(7.6vw,12.2svh),100px)}

@media(max-width:700px){
 .welcome{padding-block:clamp(86px,13svh,132px) clamp(58px,9svh,92px)}
 .welcome h1{font-size:clamp(40px,min(15.5vw,10.6svh),72px)}
 .welcome-crest{width:min(176px,47vw,24svh);margin:0 auto clamp(10px,2svh,16px)}
 .welcome-wording{margin-bottom:clamp(14px,2.6svh,24px)}
 .scroll-cue span{height:52px}
}

/* ---------- The closing is the end of the page, not a panel stuck on it ----------
   The stationery has to run out before the garden begins. The reply card's paper texture used to
   stop dead at the section's edge, and because it is a few percent lighter than the paper beneath
   it that edge read as a rule drawn across the full width. Both sides now fade over roughly a
   third of a screen, and the small centred rule that closes every other section is dropped here --
   nothing follows this one, so there is nothing to divide it from. */
.response::before{-webkit-mask-image:linear-gradient(to bottom,#000 calc(100% - 320px),transparent);mask-image:linear-gradient(to bottom,#000 calc(100% - 320px),transparent)}
.response::after{display:none}
.closing{padding-top:150px}
.closing::before{-webkit-mask-image:linear-gradient(to bottom,transparent,#000 340px);mask-image:linear-gradient(to bottom,transparent,#000 340px)}
@media(max-width:700px){
 .response::before{-webkit-mask-image:linear-gradient(to bottom,#000 calc(100% - 200px),transparent);mask-image:linear-gradient(to bottom,#000 calc(100% - 200px),transparent)}
 .closing{padding-top:124px}
 .closing::before{-webkit-mask-image:linear-gradient(to bottom,transparent,#000 220px);mask-image:linear-gradient(to bottom,transparent,#000 220px)}
 .closing-crest{width:min(132px,38vw);margin-bottom:20px}
}

/* ---------- The closing's actions ----------
   The foot of the invitation offers three things: back to the beginning, the doors again, and the other
   language. They were three underlined links stacked one above another, which read as leftovers rather
   than as part of the stationery. The first two are now a pair, each a small drawn icon in a paper
   roundel with its label beneath, held apart by the programme's diamond. The language is a control of its
   own below them: a paper pill holding both languages, each named in its own script, with the one being
   read filled in gold, so it says what the invitation is in now as well as what it could be. */
.closing-actions{display:flex;align-items:flex-start;justify-content:center;gap:clamp(16px,5vw,40px);margin:38px auto 0}
.closing .closing-action{display:flex;flex-direction:column;align-items:center;gap:11px;width:136px;min-height:44px;margin:0;padding:4px;
  font:400 10px/1.65 Manrope,sans-serif;letter-spacing:.2em;text-transform:uppercase;text-align:center;text-decoration:none;
  color:var(--ink);background:none;border:0;border-radius:0;cursor:pointer;transition:color .3s ease}
.closing-icon{display:grid;place-items:center;width:44px;height:44px;border-radius:50%;border:1px solid var(--line);
  background:#fffaf2d9;color:var(--gold);box-shadow:0 8px 20px #6751361a,inset 0 1px 0 #fffdf9;
  transition:translate .6s cubic-bezier(.16,1,.3,1),scale .15s ease,border-color .3s ease,box-shadow .6s cubic-bezier(.16,1,.3,1),background .3s ease}
.closing-icon svg{width:17px;height:17px;stroke-width:1.3;stroke-linecap:round;stroke-linejoin:round;transition:rotate .6s cubic-bezier(.16,1,.3,1),translate .6s cubic-bezier(.16,1,.3,1)}
.closing-action:focus-visible{outline:none}
.closing-action:focus-visible .closing-icon{outline:2px solid var(--action);outline-offset:4px}
@media(hover:hover){
  .closing-action:hover{color:var(--action)}
  .closing-action:hover .closing-icon{translate:0 -3px;border-color:var(--gold);background:#fffdf8;box-shadow:0 14px 28px #67513626,inset 0 1px 0 #fffdf9}
  .closing-action[href]:hover .closing-icon svg{translate:0 -1px}
  .closing-action.intro-replay:hover .closing-icon svg{rotate:-40deg}
}
.closing-action:active .closing-icon{scale:.94}
/* The diamond sits level with the middle of the two roundels. */
.closing-sep{flex:none;width:7px;height:7px;margin-top:23px;border:1px solid var(--gold);background:var(--paper);rotate:45deg}

.language-toggle{position:relative;display:grid;grid-template-columns:1fr 1fr;width:min(100%,236px);margin:30px auto 0;padding:4px;
  border:1px solid var(--line);border-radius:999px;background:#fffaf2d9;box-shadow:0 10px 26px #6751361a,inset 0 1px 0 #fffdf9}
/* The gold fill is one piece that slides to the language being read, rather than two states that swap.
   It is exactly one column wide: half the padding box less the padding, which translate:100% then moves
   by exactly one column. */
.language-toggle::before{content:'';position:absolute;top:4px;bottom:4px;left:4px;width:calc(50% - 4px);border-radius:999px;
  background:var(--action);box-shadow:0 4px 12px #58452c30;transition:translate .6s cubic-bezier(.16,1,.3,1)}
.language-toggle[data-current=si]::before{translate:100% 0}
.language-toggle button{position:relative;z-index:1;min-height:44px;padding:0 12px;border:0;border-radius:999px;background:none;color:var(--ink);cursor:pointer;transition:color .3s ease}
.language-toggle button[lang=en]{font:400 10px/1 Manrope,sans-serif;letter-spacing:.22em;text-transform:uppercase}
.language-toggle button[lang=si]{font:400 15px/1 SinhalaSerif,serif;letter-spacing:0}
.language-toggle button[aria-pressed=true]{color:var(--light);cursor:default}
.language-toggle button:focus-visible{outline:2px solid var(--action);outline-offset:3px}
@media(hover:hover){.language-toggle button[aria-pressed=false]:hover{color:var(--action)}}
