/* Adielle & Mathew — the locked dresser.
   Everything painted lives on one 2360 x 1640 "scene" that dresser.js scales
   to the viewport as a whole, so every position below is in scene pixels.
   The password strip, caption, names and lightbox sit outside the scene and
   stay at real size. Spec: docs/dresser-handoff.md. */

@font-face{font-family:'Moister';src:url('fonts/moister.woff2') format('woff2');font-display:swap}

:root{
  --cream:#FFF8F0;
  --ink:#21181B;
  --ink-rgb:33,24,27;
  --burgundy:#76120F;
  --blue:#0365BE;
  --tag-pink:#F2A9AE;
  --frame-mat:#F4EADB;
  --frame-wood:#7A4E35;
  --frame-wood-deep:#5E3B27;
  --font-script:'Moister','Lobster Two',cursive;
  --font-body:'EB Garamond',serif;
  --font-ui:'Instrument Sans',sans-serif;
  --ease-camera:cubic-bezier(.45,.05,.2,1);
  --ease-lift:cubic-bezier(.3,.7,.3,1.2);
}

html,body{margin:0;height:100%;background:var(--cream);overflow:hidden}
a{color:var(--burgundy)}
a:hover{color:var(--blue)}
input::placeholder{color:var(--burgundy);opacity:.7}

.dresser{position:fixed;inset:0;overflow:hidden;background:var(--cream);color:var(--ink)}
.vh{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);margin:0}
.noscript{position:absolute;left:50%;bottom:20px;transform:translateX(-50%);margin:0;padding:7px 16px;
  background:var(--cream);border:1px solid rgba(var(--ink-rgb),.35);border-radius:999px;
  font-family:var(--font-body);font-size:16px;line-height:1.3;text-align:center}

/* Applied for one frame when a state has to appear without animating:
   first paint for a returning guest, and prefers-reduced-motion. */
.is-instant,.is-instant *{transition:none!important}

/* ---- the scene ---- */
.scene{position:absolute;left:0;top:0;width:2360px;height:1640px;transform-origin:0 0;visibility:hidden}
.scene.is-fit{visibility:visible}
.scene-in{position:absolute;inset:0}
.plate{position:absolute;inset:0;width:100%;height:100%;display:block}

/* Flipbook: each frame fades in on top of the last. They stack and are never
   faded back out, so there is no flash of the closed dresser between frames. */
.frame,.plate--open{opacity:0;pointer-events:none;transition:opacity .12s linear}
.frame.is-on,.plate--open.is-on{opacity:1}

/* ---- drawer contents ----
   One layer that rides with the flipbook. dresser.js moves and clips it per
   frame, so the items are revealed between the top rail and the drawer front. */
.drawer{position:absolute;inset:0;pointer-events:none;opacity:0;transition:clip-path .12s linear}
.drawer-contents{position:absolute;inset:0;transform-origin:1150px 1485px;transition:transform .12s linear}
.item{position:absolute;display:block;pointer-events:none}
.item img{width:100%;height:100%;display:block;box-sizing:border-box;object-fit:cover;pointer-events:none}
.item--framed img{padding:14px;background:var(--frame-mat);
  box-shadow:inset 0 0 0 2px var(--frame-wood),0 0 0 5px var(--frame-wood-deep),0 8px 14px rgba(var(--ink-rgb),.25)}
.item--lift{padding:0;border:0;background:transparent;
  transition:translate .35s var(--ease-lift),filter .35s ease}
button.item--lift{cursor:zoom-in}
.drawer.is-open .item--lift{pointer-events:auto}
.item--lift:hover,.item--lift:focus{translate:0 -22px;
  filter:drop-shadow(0 26px 22px rgba(var(--ink-rgb),.28));outline:none}
/* Above every item, so they read as sitting under it. */
.drawer-shadow{position:absolute;left:0;top:600px;width:2360px;height:1040px;display:block;
  mix-blend-mode:multiply;pointer-events:none;z-index:100;opacity:0;transition:opacity 1.6s ease .3s}
.drawer-shadow.is-on{opacity:1}

/* ---- the lock ---- */
/* will-change puts the drawer front on its own compositor layer, as the design
   reference does. Without it the browser snaps this layer to the pixel grid
   half a pixel differently and the key's ink outlines soften against the
   dresser underneath. */
.front{position:absolute;left:236px;top:683px;width:1830px;height:514px;pointer-events:none;will-change:transform}
.front.is-gone{opacity:0}
.key{position:absolute;left:884px;top:197px;width:525px;height:275px;transform-origin:15px 60px;
  transition:transform .22s cubic-bezier(.3,1.8,.5,1)}
.key.is-turned{transform:rotate(-1.2deg)}
.key img{position:absolute;inset:0;width:100%;height:100%;display:block;opacity:0;transition:opacity .05s linear}
.key img.is-on{opacity:1}

.tag{position:absolute;left:1223px;top:1076px;width:250px;height:365px;transform-origin:125px 0;
  transition:transform .8s cubic-bezier(.2,.7,.3,1.1),opacity .4s ease}
.tag.is-dropped{transform:translate(40px,620px) rotate(22deg);opacity:0;pointer-events:none;
  transition:transform .7s cubic-bezier(.5,0,.9,.6),opacity .5s ease .2s}
.tag-swing,.tag-shake{position:absolute;inset:0;transform-origin:125px 0}
.tag-swing{animation:am-swing 6s ease-in-out infinite}
.tag-swing img{position:absolute;inset:0;width:100%;height:100%;display:block;pointer-events:none}
.ribbon{position:absolute;left:87px;top:-136px;width:230px;height:310px;pointer-events:none}

.keyhole{position:absolute;left:1080px;top:860px;width:600px;height:620px;padding:0;border:0;
  background:transparent;cursor:pointer;border-radius:30%}
.keyhole.is-off{pointer-events:none}

/* ---- outside the scene: real pixels ---- */
.caption{position:absolute;left:50%;bottom:20px;transform:translateX(-50%);margin:0;
  max-width:calc(100vw - 32px);box-sizing:border-box;padding:7px 16px;background:var(--cream);
  border:1px solid rgba(var(--ink-rgb),.35);border-radius:999px;font-family:var(--font-body);
  font-size:16px;line-height:1.3;text-align:center;color:var(--ink);pointer-events:none;
  transition:opacity .3s ease}
.caption.is-error{color:var(--burgundy)}
.caption.is-off{opacity:0}

.tagform{position:absolute;width:250px;transform:translateX(-50%) rotate(-2deg);transform-origin:50% 0;
  opacity:0;pointer-events:none;transition:opacity .25s ease}
.tagform.is-on{opacity:1;pointer-events:auto;transition:opacity .4s ease .8s}
.strip{position:relative;display:flex;align-items:center;gap:6px;padding:6px 8px 6px 22px;
  background:var(--tag-pink);border:1.5px solid var(--ink);border-radius:3px;
  box-shadow:0 6px 14px rgba(var(--ink-rgb),.22)}
.strip::before{content:"";position:absolute;left:7px;top:50%;width:9px;height:9px;margin-top:-4.5px;
  border-radius:50%;background:var(--cream);box-shadow:0 0 0 1.3px var(--ink)}
.strip label{flex:1;min-width:0;display:flex}
.strip input{flex:1;min-width:0;width:100%;font-family:var(--font-body);font-style:italic;font-size:18px;
  padding:4px 2px 0;min-height:44px;box-sizing:border-box;background:transparent;border:0;
  border-bottom:1.5px solid var(--ink);border-radius:0;color:var(--ink);text-align:center;outline:none}
.strip button{flex:none;min-height:44px;padding:0 4px;background:transparent;border:0;
  font-family:var(--font-script);font-size:20px;line-height:1;color:var(--burgundy);cursor:pointer;
  white-space:nowrap}
.strip button:hover{color:var(--blue)}

.title{position:absolute;top:clamp(10px,2.4vh,24px);right:clamp(12px,2.4vw,32px);display:flex;
  flex-direction:column;align-items:flex-end;gap:2px;text-align:right;pointer-events:none}
.title-names{margin:0;font-family:var(--font-script);font-size:clamp(28px,4.2vw,56px);line-height:1;
  color:var(--burgundy)}
.title-date{margin:0;font-family:var(--font-body);font-size:clamp(13px,1.3vw,17px);line-height:1.3;
  color:var(--ink);animation:am-fade .8s ease}

.relock{pointer-events:auto;margin:8px 0 0;padding:0 14px;min-height:40px;background:var(--cream);
  border:1px solid rgba(var(--ink-rgb),.35);border-radius:999px;font-family:var(--font-body);
  font-size:16px;line-height:1.3;color:var(--ink);cursor:pointer;animation:am-fade .8s ease}
.relock:hover{color:var(--blue);border-color:var(--blue)}
.relock[hidden]{display:none}

/* ---- save the date lightbox ---- */
.lightbox{position:fixed;inset:0;z-index:100;display:flex;align-items:center;justify-content:center;
  box-sizing:border-box;padding:5vh 5vw;background:rgba(var(--ink-rgb),.78);cursor:zoom-out;
  animation:am-fade .3s ease}
.lightbox[hidden]{display:none}
.lightbox img{display:block;max-width:100%;max-height:100%;object-fit:contain;
  box-shadow:0 20px 60px rgba(0,0,0,.45);animation:am-pop .4s cubic-bezier(.2,.8,.3,1.1)}
.lightbox.is-closing{animation:am-fadeout .34s ease forwards}
.lightbox.is-closing img{animation:am-popout .34s cubic-bezier(.5,0,.8,.4) forwards}
.lightbox-close{position:absolute;top:16px;right:16px;width:44px;height:44px;border-radius:50%;
  border:1px solid var(--cream);background:transparent;color:var(--cream);font-family:var(--font-ui);
  font-size:22px;line-height:1;cursor:pointer}
.lightbox-close:hover{background:var(--cream);color:var(--ink)}

/* ---- motion ----
   The rattle and shake each exist twice under different names. Switching
   between the two names is what restarts the animation on a repeat mistake;
   re-applying the same name would do nothing. */
@keyframes am-rattle-0{0%,100%{transform:translateX(0)}15%{transform:translateX(-6px)}30%{transform:translateX(5px)}45%{transform:translateX(-3px)}60%{transform:translateX(2px)}75%{transform:translateX(-1px)}}
@keyframes am-rattle-1{0%,100%{transform:translateX(0)}15%{transform:translateX(-6px)}30%{transform:translateX(5px)}45%{transform:translateX(-3px)}60%{transform:translateX(2px)}75%{transform:translateX(-1px)}}
@keyframes am-shake-0{0%,100%{transform:rotate(0)}20%{transform:rotate(-8deg)}40%{transform:rotate(6deg)}60%{transform:rotate(-4deg)}80%{transform:rotate(2deg)}}
@keyframes am-shake-1{0%,100%{transform:rotate(0)}20%{transform:rotate(-8deg)}40%{transform:rotate(6deg)}60%{transform:rotate(-4deg)}80%{transform:rotate(2deg)}}
@keyframes am-swing{0%,100%{transform:rotate(-3deg)}50%{transform:rotate(-1.5deg)}}
@keyframes am-fade{from{opacity:0}to{opacity:1}}
@keyframes am-fadeout{from{opacity:1}to{opacity:0}}
@keyframes am-pop{from{opacity:0;transform:scale(.6) rotate(3deg)}to{opacity:1;transform:none}}
@keyframes am-popout{from{opacity:1;transform:none}to{opacity:0;transform:scale(.6) rotate(3deg)}}

/* dresser.js skips the unlock sequence under reduced motion; this stills
   everything that would otherwise move on its own. */
@media (prefers-reduced-motion:reduce){
  .tag-swing{animation:none;transform:rotate(-3deg)}
  .scene-in,.tag-shake,.strip{animation:none!important}
  .lightbox,.lightbox img,.title-date,.relock{animation:none}
  .item--lift{transition:none}
}
