/* Letter theme — shared by letter_login.html (locked envelope) and letter.html (the gift).
   Image URLs come in as --img-* variables from the templates (static_v keeps them cache-busted). */
:root{
  --gold:#e9c98f; --gold-dim:rgba(233,201,143,.55); --ink:#3e1119; --ink-2:#6d1426;
  --ease-out:cubic-bezier(.22,1,.36,1);
  --arabic:"Tajawal",sans-serif;
  --script:"Petit Formal Script",var(--arabic);   /* Arabic titles fall through to Tajawal; it runs wide, so titles are sized smaller */
  --serif:"Caveat",var(--arabic);
}
*{box-sizing:border-box;margin:0;padding:0}
html{background:#430c11;font-synthesis:none}  /* Caveat has no italic: never fake-slant it */
body{min-height:100vh;min-height:100svh;color:var(--gold);font-family:var(--serif);overflow-x:hidden;-webkit-tap-highlight-color:transparent}
/* (100vh first: browsers without svh keep a full-height page) */
/* fixed layer instead of background-attachment:fixed (iOS ignores it) */
.bg{position:fixed;inset:0;z-index:0;pointer-events:none;background:#430c11 var(--img-linen) center/cover no-repeat}
.bg::after{content:"";position:absolute;inset:0;
  background:radial-gradient(ellipse at 50% 42%,rgba(255,120,120,.06),transparent 45%,rgba(8,0,2,.5) 100%)}
/* waiting for the design images + fonts (see _letter_head.html): only the plain background and a gold ring */
.scene,.player{transition:opacity .6s}
html.wait .scene,html.wait .player{opacity:0;pointer-events:none}
html.wait body::after{content:"";position:fixed;left:50%;top:50%;z-index:5;width:34px;height:34px;margin:-17px 0 0 -17px;border-radius:50%;
  border:2px solid rgba(233,201,143,.2);border-top-color:var(--gold);animation:spin .9s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}
.scene{position:relative;z-index:1;min-height:100vh;min-height:100svh;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:24px 16px}
/* scenes that aren't showing stay laid out, just parked off-flow and invisible — so switching to the letter
   (5000 chars) or the memories page costs no layout at the tap (display:none meant a full relayout then).
   fixed + overflow:hidden keeps their height out of the page's scroll. */
.scene:not(.on){position:fixed;left:0;right:0;top:0;height:100%;overflow:hidden;visibility:hidden;pointer-events:none}

/* ---------- 1 · envelope ---------- */
.kicker{font-family:var(--script);font-size:clamp(33px,9.4vw,45px);line-height:1.3;color:var(--gold);text-align:center;
  text-shadow:0 2px 12px rgba(0,0,0,.45);margin-bottom:6px;transition:opacity .5s}
.sub{font-size:21px;letter-spacing:.12em;text-transform:uppercase;opacity:.7;margin-bottom:30px;text-align:center;transition:opacity .5s}
.env-wrap{width:min(92vw,560px);perspective:1400px;transition:transform 1s var(--ease-out),opacity .8s}
.env{position:relative;width:100%;aspect-ratio:735/490;transform-style:preserve-3d}
.env.shake{animation:shake .5s cubic-bezier(.36,.07,.19,.97)}
@keyframes shake{10%,90%{transform:translateX(-2px)}20%,80%{transform:translateX(4px)}30%,50%,70%{transform:translateX(-7px)}40%,60%{transform:translateX(7px)}}
.env-shadow{position:absolute;inset:4% 2% -3%;border-radius:8px;box-shadow:0 24px 44px rgba(0,0,0,.55),0 6px 14px rgba(0,0,0,.4);z-index:0}
.env-inside{position:absolute;inset:0;border-radius:6px;z-index:1;background:linear-gradient(#1e0309,#3a0810 55%,#4a0c16)}
/* box = envelope-wide (never wider: on phones extra width makes the browser zoom the page out),
   5× tall (4 envelopes of room above for the slide-out), ends 3px above the bottom edge */
.env-letter-clip{position:absolute;left:0;right:0;top:-400%;bottom:3px;overflow:hidden;z-index:2;visibility:hidden;pointer-events:none}
.env.open .env-letter-clip{visibility:visible}
.env-letter{position:absolute;left:8%;width:84%;top:81.4%;aspect-ratio:700/1000;will-change:transform;
  background:var(--img-lace-full) center/100% 100% no-repeat;filter:drop-shadow(0 -4px 10px rgba(0,0,0,.35))}
.env-pocket{position:absolute;inset:0;z-index:3;border-radius:6px;
  background:var(--img-envelope) center/100% 100% no-repeat;
  clip-path:polygon(0 6.02%,50.16% 63.9%,100% 6.16%,100% 100%,0 100%)}
.env-flap{position:absolute;inset:0;z-index:5;transform-origin:50% 0;transform-style:preserve-3d;
  transition:transform .9s cubic-bezier(.55,.05,.3,1)}
.env-flap .face{position:absolute;inset:0;backface-visibility:hidden;-webkit-backface-visibility:hidden;
  clip-path:polygon(0 0,100% 0,100% 6.16%,50.16% 63.9%,0 6.02%)}
.env-flap .front{background:var(--img-envelope) center/100% 100% no-repeat;border-radius:6px 6px 0 0}
.env-flap .back{transform:rotateX(180deg);background:linear-gradient(#5a1220,#3c0912)}
.seal{position:absolute;left:38.37%;top:35.1%;width:23.67%;aspect-ratio:174/176;z-index:2;
  background:var(--img-seal) center/contain no-repeat;border:0;cursor:pointer;
  backface-visibility:hidden;-webkit-backface-visibility:hidden;transform:translateZ(1px);
  filter:drop-shadow(0 4px 5px rgba(0,0,0,.55));transition:transform .15s}
.seal::after{content:"";position:absolute;inset:-6%;border-radius:50%;border:2px solid rgba(233,201,143,.55);opacity:0;animation:pulse 2.2s ease-out infinite}
@keyframes pulse{0%{opacity:.9;transform:scale(.92)}75%,100%{opacity:0;transform:scale(1.3)}}
.env.locked .seal::after{animation:none}
.seal.pressed{transform:translateZ(1px) scale(.93)}
.seal.wiggle{animation:wiggle .45s}
@keyframes wiggle{25%{transform:translateZ(1px) rotate(-9deg)}60%{transform:translateZ(1px) rotate(7deg)}}
.env.open .seal::after{display:none}
.env.open .env-flap{transform:rotateX(180deg)}
.env.flap-behind .env-flap{z-index:0}

/* the strip under the envelope: the password on the login page, the hint on the gift page.
   Same height on both so the envelope doesn't jump when the page changes after the password. */
.below{min-height:128px;width:min(84vw,330px);display:flex;flex-direction:column;align-items:center}
.lock{margin-top:34px;width:100%;text-align:center}
.pw-row{position:relative;width:100%}
.pw-row input{width:100%;background:transparent;border:0;border-bottom:1px solid var(--gold-dim);border-radius:0;
  color:var(--gold);font:500 26px var(--serif);letter-spacing:.14em;text-align:center;padding:8px 44px;outline:none;
  transition:border-color .3s}
.pw-row input::placeholder{color:var(--gold);opacity:.35;letter-spacing:.12em}
.pw-row input:focus{border-bottom-color:var(--gold)}
.pw-row button{position:absolute;right:0;bottom:6px;width:36px;height:36px;border-radius:50%;border:1px solid var(--gold-dim);
  background:transparent;color:var(--gold);font-size:18px;cursor:pointer;transition:background .2s,opacity .2s}
.pw-row button:hover,.pw-row button:focus-visible{background:rgba(233,201,143,.12)}
.lock.sending .pw-row button{opacity:.4;pointer-events:none}
.pw-err{min-height:24px;margin-top:10px;font-size:21px;color:#f3b3b3}
.hint{margin-top:34px;font-size:23px;letter-spacing:.06em;opacity:.85;animation:breathe 2.2s ease-in-out infinite}
@keyframes breathe{50%{opacity:.45}}

/* ---------- 2 · lace letter ---------- */
#s2{justify-content:flex-start;padding-top:max(28px,env(safe-area-inset-top))}
.paper{position:relative;width:min(94vw,460px);display:flex;flex-direction:column;
}
/* a plain shadow under the paper — a drop-shadow filter on the lace sheet was heavy for cheap phones (it's scaled
   while it opens, and a 5000-char letter is ~7 screens tall, which can come out blank on iOS) */
.paper::before{content:"";position:absolute;inset:4% 10% 5%;z-index:-1;border-radius:12px;
  box-shadow:0 12px 34px 4px rgba(0,0,0,.42),0 3px 10px rgba(0,0,0,.28)}
.paper .pc-top,.paper .pc-mid,.paper .pc-bot{width:100%;background-size:100% auto;background-repeat:no-repeat}
.paper .pc-top{aspect-ratio:700/300;background-image:var(--img-lace-top)}
.paper .pc-mid{height:0;background-image:var(--img-lace-tile);background-repeat:repeat-y;margin-top:-1px}
.paper .pc-bot{aspect-ratio:700/700;background-image:var(--img-lace-bottom);margin-top:-1px}
.letter-text{position:absolute;inset:17.5% 19.3% 0 19.3%;
  display:flex;flex-direction:column;justify-content:center;text-align:center;color:var(--ink)}
.letter-text h1{font-family:var(--script);font-weight:400;font-size:1.4em;line-height:1.3;margin-bottom:.3em;color:var(--ink-2)}
.letter-text .body{font-weight:500;line-height:1.35;white-space:pre-line;overflow-wrap:anywhere}
.letter-text .body:is(:dir(rtl),.rtl){font-family:var(--arabic);line-height:1.85}
.letter-text>*{opacity:0;transform:translateY(8px);transition:opacity .8s,transform .8s var(--ease-out)}
.paper.inked .letter-text>*{opacity:1;transform:none}
.paper.inked .letter-text>*:nth-child(2){transition-delay:.25s}
.next{margin:30px 0 40px;background:none;border:1px solid var(--gold-dim);color:var(--gold);
  font:500 23px var(--serif);letter-spacing:.04em;padding:9px 28px;border-radius:999px;cursor:pointer;
  opacity:0;pointer-events:none;transition:opacity .6s .9s}
.paper.inked~.next{opacity:1;pointer-events:auto}   /* no tap until the letter is out */

/* ---------- 3 · photos → counter → special days → ending ---------- */
#s3{justify-content:flex-start;padding-top:max(48px,env(safe-area-inset-top));padding-bottom:90px}
#s3 h2,.sec-title{font-family:var(--script);font-weight:400;font-size:clamp(32px,8.8vw,42px);line-height:1.3;margin-bottom:28px;
  text-shadow:0 2px 12px rgba(0,0,0,.45);text-align:center}
/* the pile spans the whole screen width and clips at its edges: a photo flying out to the side (or dragged)
   used to make the page wider than the phone → the browser zoomed the whole page out and back in.
   clip keeps it vertical-free where supported; older browsers fall back to hidden (padding gives the
   tilted cards and shadows room) */
.memories{display:flex;flex-direction:column;align-items:center;align-self:stretch;margin:-28px -16px 0;padding:28px 16px 6px;
  overflow:hidden;overflow-x:clip;overflow-y:visible}
.stack{position:relative;width:min(80vw,340px);aspect-ratio:340/430;touch-action:none;user-select:none;-webkit-user-select:none}
/* every card is the same portrait frame. Photos fill it (cover); wide ones — that cover would cut badly — are
   drawn whole on a blurred copy of themselves (done in the page's bake(), once the photo's size is known). */
.photo{position:absolute;inset:0;border-radius:14px;overflow:hidden;cursor:grab;background:#2a070c;
  box-shadow:0 2px 3px rgba(0,0,0,.25),0 16px 32px rgba(0,0,0,.5);
  transition:transform .38s var(--ease-out)}
.photo.deep{display:none}   /* deep in the pile: out of the page entirely (up to 300 photos) */
.photo img{width:100%;height:100%;object-fit:cover;display:block;pointer-events:none;-webkit-user-drag:none}
/* plain-<img> fallback (photo host without CORS): wide photos shown whole on black */
.photo.fit{background:#000}
.photo.fit img{object-fit:contain}
/* normally each photo is painted onto a frame-sized canvas instead (see loadPhoto() in letter.html) */
.photo canvas.main{position:absolute;inset:0;width:100%;height:100%;display:block}
.photo::before{ /* depth shade for cards further back (opacity is cheaper than filter) */
  content:"";position:absolute;inset:0;background:#1a0508;opacity:var(--shade,0);transition:opacity .38s;pointer-events:none;z-index:3}
.photo::after{ /* glossy light + thin gold hairline instead of a white border */
  content:"";position:absolute;inset:0;pointer-events:none;border-radius:inherit;z-index:2;
  box-shadow:inset 0 0 0 1px rgba(233,201,143,.28);
  background:linear-gradient(140deg,rgba(255,255,255,.18),transparent 35%)}
.photo .cap{position:absolute;left:0;right:0;bottom:0;padding:34px 12px 12px;text-align:center;z-index:1;
  font-family:var(--script);font-size:clamp(17px,4.8vw,21px);color:#fff4e0;text-shadow:0 2px 8px rgba(0,0,0,.6);
  background:linear-gradient(transparent,rgba(25,3,8,.72))}
.photo .cap:is(:dir(rtl),.rtl){font-family:var(--arabic);font-size:clamp(17px,4.8vw,21px)}
.photo.dragging{transition:none;cursor:grabbing}
.count{margin-top:24px;font-size:21px;letter-spacing:.2em;opacity:.75}
.tip{margin-top:4px;font-size:19px;opacity:.5}

.together,.moments{width:min(92vw,440px);margin-top:72px;text-align:center}
.memories+.together,.scene>.together:first-child,.scene>.moments:first-child{margin-top:0}
.mini-seal{width:54px;height:auto;display:block;margin:0 auto 12px;filter:drop-shadow(0 4px 6px rgba(0,0,0,.5))}
.together .sec-title{margin-bottom:22px}
.clock{display:grid;grid-template-columns:repeat(4,1fr);gap:9px}
.unit{position:relative;padding:16px 4px 12px;border-radius:12px;border:1px solid rgba(233,201,143,.35);
  background:linear-gradient(180deg,rgba(255,220,200,.07),rgba(0,0,0,.22));
  box-shadow:inset 0 1px 0 rgba(255,235,200,.12),0 10px 22px rgba(0,0,0,.3)}
.unit b{display:block;will-change:transform;font-weight:600;font-size:clamp(28px,8.4vw,40px);line-height:1;font-variant-numeric:lining-nums tabular-nums;
  background:linear-gradient(180deg,#fbe9c3 0%,#e2bb78 55%,#b98a4a 100%);-webkit-background-clip:text;background-clip:text;color:transparent}
.unit small{display:block;margin-top:8px;font-size:16px;letter-spacing:.12em;text-transform:uppercase;opacity:.7}
.since{margin-top:18px;font-size:23px;opacity:.85}
.csub{margin-top:6px;font-family:var(--script);font-size:19px;opacity:.9}
.csub:is(:dir(rtl),.rtl){font-family:var(--arabic);font-size:19px}

.timeline{list-style:none;position:relative;text-align:left;padding:6px 0}
.timeline::before{content:"";position:absolute;left:21px;top:10px;bottom:10px;width:1px;
  background:linear-gradient(transparent,rgba(233,201,143,.55) 8%,rgba(233,201,143,.55) 92%,transparent)}
/* notes rise in from below (sliding in from the side pushed the page wider than a phone → it zoomed out) */
.m{position:relative;padding-left:60px;margin-bottom:26px;opacity:0;transform:translateY(16px);
  transition:opacity .7s,transform .8s var(--ease-out)}
.m:last-child{margin-bottom:0}
.m.in{opacity:1;transform:none}
.m-seal{position:absolute;left:2px;top:12px;width:40px;aspect-ratio:174/176;background:var(--img-seal) center/contain no-repeat;
  filter:drop-shadow(0 3px 4px rgba(0,0,0,.5));transform:scale(0) rotate(-40deg);transition:transform .6s cubic-bezier(.34,1.56,.64,1) .1s}
.m.in .m-seal{transform:none}
.m-card{position:relative;padding:16px 18px 14px;border-radius:6px;color:var(--ink);
  background:linear-gradient(160deg,#f7ecd6,#ead8b4);box-shadow:0 10px 22px rgba(0,0,0,.35),inset 0 0 0 1px rgba(140,100,50,.12);
  transform:rotate(var(--tilt,0deg))}
.m-card::before{ /* little paper notch pointing at the seal */
  content:"";position:absolute;left:-7px;top:22px;width:14px;height:14px;background:#f4e7cd;transform:rotate(45deg);
  box-shadow:-2px 2px 3px rgba(0,0,0,.08)}
.m-text{position:relative;font-weight:500;font-size:25px;line-height:1.25;overflow-wrap:anywhere}
.m-text:is(:dir(rtl),.rtl){font-family:var(--arabic);font-size:19px;line-height:1.6;text-align:right}
.m-text .w{opacity:0;transition:opacity .45s}  /* opacity only (no blur/transform): cheap even with 40 notes */
.m.in .m-text .w{opacity:1}
.m-date{position:relative;margin-top:8px;font-weight:600;font-size:19px;letter-spacing:.04em;color:#8a5a2a;
  opacity:0;transition:opacity .5s}
.m-date::before{content:"— ";opacity:.6}
.m.in .m-date{opacity:1}

.ending{margin-top:84px;text-align:center}
.end-line{font-family:var(--script);font-size:clamp(30px,8.4vw,40px);line-height:1.35;text-shadow:0 2px 12px rgba(0,0,0,.45);padding:0 8px}
.end-line:is(:dir(rtl),.rtl){font-family:var(--arabic);font-size:clamp(26px,7vw,32px);font-weight:700}
.replay{margin-top:30px;display:inline-flex;align-items:center;gap:10px;background:none;border:1px solid var(--gold-dim);color:var(--gold);
  font:500 23px var(--serif);letter-spacing:.04em;padding:10px 28px;border-radius:999px;cursor:pointer;transition:background .25s}
.replay:hover,.replay:focus-visible{background:rgba(233,201,143,.1)}
.replay svg{width:17px;height:17px;transition:transform .6s var(--ease-out)}
.replay:hover svg{transform:rotate(-200deg)}

/* ---------- music player: a gold circle that grows to the left ---------- */
.player{position:fixed;right:16px;bottom:max(18px,env(safe-area-inset-bottom));z-index:40;width:50px;height:50px;border-radius:999px;overflow:hidden;
  border:1px solid rgba(233,201,143,.55);background:rgba(40,6,12,.9);
  box-shadow:0 8px 22px rgba(0,0,0,.42);color:var(--gold);
  opacity:0;transform:scale(.6);transition:width .5s var(--ease-out),opacity .5s,transform .5s cubic-bezier(.34,1.56,.64,1)}
.player[hidden]{display:none}
.player.shown{opacity:1;transform:none}
.player.open{width:min(320px,calc(100vw - 32px))}
.pl-toggle{position:absolute;right:0;top:0;width:48px;height:48px;border:0;background:none;cursor:pointer;
  display:flex;align-items:flex-end;justify-content:center;gap:3px;padding-bottom:15px}
.pl-toggle span{width:3px;height:5px;border-radius:2px;background:var(--gold)}
.player.playing .pl-toggle span{animation:eq 1s ease-in-out infinite}
.player.playing .pl-toggle span:nth-child(2){animation-delay:-.4s}
.player.playing .pl-toggle span:nth-child(3){animation-delay:-.7s}
.player.playing .pl-toggle span:nth-child(4){animation-delay:-.2s}
@keyframes eq{0%,100%{height:5px}50%{height:17px}}
.pl-body{position:absolute;top:0;bottom:0;right:48px;width:calc(min(320px,100vw - 32px) - 50px);
  display:flex;align-items:center;gap:2px;padding-left:18px;opacity:0;pointer-events:none;transition:opacity .2s}
.player.open .pl-body{opacity:1;pointer-events:auto;transition:opacity .3s .2s}
.pl-info{flex:1;min-width:0;display:flex;flex-direction:column;line-height:1.15}
.pl-name{font-size:22px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.pl-idx{font-size:11px;letter-spacing:.22em;opacity:.55;margin-top:2px}
.pl-btn{flex:none;width:38px;height:38px;border-radius:50%;border:0;background:none;color:inherit;cursor:pointer;display:grid;place-items:center;transition:background .2s}
.pl-btn[hidden]{display:none}
.pl-btn:hover,.pl-btn:focus-visible{background:rgba(233,201,143,.12)}
.pl-btn svg{width:16px;height:16px;fill:currentColor}
.pl-main{border:1px solid var(--gold-dim)}
.player .i-pause,.player.playing .i-play{display:none}
.player.playing .i-pause{display:block}
