@font-face{font-family:'Gilda Display';font-style:normal;font-weight:400;font-display:swap;src:url('../fonts/gilda-display-normal-400-latin-ext.woff2') format('woff2');unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}
@font-face{font-family:'Gilda Display';font-style:normal;font-weight:400;font-display:swap;src:url('../fonts/gilda-display-normal-400-latin.woff2') format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}
@font-face{font-family:'Gilda Display';font-style:normal;font-weight:500;font-display:swap;src:url('../fonts/gilda-display-normal-400-latin-ext.woff2') format('woff2');unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}
@font-face{font-family:'Gilda Display';font-style:normal;font-weight:500;font-display:swap;src:url('../fonts/gilda-display-normal-400-latin.woff2') format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}
@font-face{font-family:'Archivo';font-style:normal;font-weight:400;font-stretch:112%;font-display:swap;src:url('../fonts/archivo-normal-400-latin-ext.woff2') format('woff2');unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}
@font-face{font-family:'Archivo';font-style:normal;font-weight:400;font-stretch:112%;font-display:swap;src:url('../fonts/archivo-normal-400-latin.woff2') format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}
@font-face{font-family:'Archivo';font-style:normal;font-weight:500;font-stretch:112%;font-display:swap;src:url('../fonts/archivo-normal-400-latin-ext.woff2') format('woff2');unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}
@font-face{font-family:'Archivo';font-style:normal;font-weight:500;font-stretch:112%;font-display:swap;src:url('../fonts/archivo-normal-400-latin.woff2') format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}
@font-face{font-family:'Archivo';font-style:normal;font-weight:600;font-stretch:112%;font-display:swap;src:url('../fonts/archivo-normal-400-latin-ext.woff2') format('woff2');unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}
@font-face{font-family:'Archivo';font-style:normal;font-weight:600;font-stretch:112%;font-display:swap;src:url('../fonts/archivo-normal-400-latin.woff2') format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}
@font-face{font-family:'Archivo';font-style:normal;font-weight:700;font-stretch:112%;font-display:swap;src:url('../fonts/archivo-normal-400-latin-ext.woff2') format('woff2');unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}
@font-face{font-family:'Archivo';font-style:normal;font-weight:700;font-stretch:112%;font-display:swap;src:url('../fonts/archivo-normal-400-latin.woff2') format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}
@font-face{font-family:'Italianno';font-style:normal;font-weight:400;font-display:swap;src:url('../fonts/italianno-normal-400-latin-ext.woff2') format('woff2');unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}
@font-face{font-family:'Italianno';font-style:normal;font-weight:400;font-display:swap;src:url('../fonts/italianno-normal-400-latin.woff2') format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}

/* ══════════════════════════════════════════════════════════════
   TOKENS
   ══════════════════════════════════════════════════════════════ */
:root{
  color-scheme: light;

  /* surfaces: bone paper, velvet plum, blush */
  --bone:#F4F1EA;
  --bone-2:#EDE8DE;
  --plum:#340C24;
  --plum-2:#4A1734;
  --blush:#F8BBCB;
  --blush-2:#F6D9E1;
  --pink:#D94A80;
  --pink-deep:#A82F5D;
  --champagne:#DCCBA9;

  /* theme slots: a section flips all of them at once */
  --bg:var(--bone);
  --fg:var(--plum);
  --fg-60:color-mix(in srgb, var(--plum) 60%, transparent);
  --fg-30:color-mix(in srgb, var(--plum) 30%, transparent);
  --line:color-mix(in srgb, var(--plum) 16%, transparent);
  --mark:var(--pink);

  /* grid */
  --gap:16px;
  --offset:48px;
  --cell-v:96px;

  /* type: design values are px at a 16px root, then scaled by 1vw */
  --h1:12rem; --h2:8.5rem; --h3:6rem; --h4:3.9375rem; --h5:2.5rem; --h6:1.75rem;
  --c1:1.5625rem; --a1:14.4rem; --a2:9.2rem;
  --l1:.6875rem; --l2:.8125rem; --body:1.05rem; --lede:1.45rem;

  /* ── THE MOTION SYSTEM ───────────────────────────────────────
     Five curves and four durations, and nothing on the site is allowed a
     sixth. That single restriction is what makes a page feel authored by
     one hand rather than assembled: every arrival shares a deceleration,
     every departure shares an acceleration, so the eye stops noticing the
     transitions and starts trusting them.
     ─────────────────────────────────────────────────────────── */
  --e-out:cubic-bezier(.25,1,.5,1);      /* arrivals: comes in fast, lands soft  */
  --e-in:cubic-bezier(.5,0,.75,0);       /* departures: leaves the way it came   */
  --e-io:cubic-bezier(.75,0,.25,1);      /* swaps: symmetric, for A→B            */
  --e-soft:cubic-bezier(.25,.1,.25,1);   /* small UI: hovers, colour, opacity    */
  --e-silk:cubic-bezier(.62,0,.06,1);    /* curtains and masks: a held breath    */
  --e-ken:cubic-bezier(.22,.61,.36,1);   /* the slow push on a photograph        */

  --d-s:.4s;      /* a state change you should not have to watch */
  --d-m:.72s;     /* a hover, a swap, a line of type             */
  --d-l:1.2s;     /* an arrival: the full gesture                */
  --d-xl:1.6s;    /* a curtain, a scene, a release               */
  --stag:.055s;   /* between characters                          */
  --stag-l:.1s;   /* between lines and blocks                    */
}
html{ font-size:clamp(8.5px, 1vw, 16.5px) }
@media (max-width:1023px){
  :root{
    --offset:24px; --cell-v:80px;
    --h1:4.9rem; --h2:3.9rem; --h3:3.1rem; --h4:2.5rem; --h5:1.85rem; --h6:1.45rem;
    --c1:1.02rem; --a1:5.3rem; --a2:3.8rem;
    --l1:.74rem; --l2:.82rem; --body:1.02rem; --lede:1.25rem;
  }
  html{ font-size:clamp(11px, 2.85vw, 15px) }
}

.t-plum{ --bg:var(--plum); --fg:var(--bone); --mark:var(--blush);
  --fg-60:color-mix(in srgb, var(--bone) 60%, transparent);
  --fg-30:color-mix(in srgb, var(--bone) 30%, transparent);
  --line:color-mix(in srgb, var(--bone) 20%, transparent); color-scheme:dark }
.t-blush{ --bg:var(--blush-2); --fg:var(--plum); --mark:var(--pink-deep) }
.t-bone2{ --bg:var(--bone-2) }

/* ══════════════════════════════════════════════════════════════
   BASE
   ══════════════════════════════════════════════════════════════ */
*,*::before,*::after{ box-sizing:border-box }
/* The burst throws sweets a couple of thousand pixels sideways on purpose, and
   with the clip only on the body the page could still be dragged 3000px into
   empty bone. On the root it cannot, and unlike hidden, clip does not turn the
   root into a scroll container, so the sticky scenes stay stuck. */
html{ overflow-x:clip; scrollbar-gutter:stable; -webkit-text-size-adjust:100% }
body{
  margin:0; background:var(--bone); color:var(--plum);
  font-family:'Archivo','Helvetica Neue',Arial,sans-serif;
  font-stretch:112%; font-size:var(--body); font-weight:400; line-height:1.5;
  overflow-x:clip; -webkit-font-smoothing:antialiased;
}
img,svg{ display:block; max-width:100% }
h1,h2,h3,h4,h5,h6,p,figure,blockquote,ul,ol,dl,dd{ margin:0; padding:0 }
ul,ol{ list-style:none }
a{ color:inherit; text-decoration:none }
button,input,textarea,select{ font:inherit; color:inherit; font-stretch:inherit }
::selection{ background:var(--blush); color:var(--plum) }
:focus-visible{ outline:2px solid var(--pink); outline-offset:3px }
.sr-only{ position:absolute; width:1px; height:1px; padding:0; margin:-1px;
  overflow:hidden; clip-path:inset(50%); white-space:nowrap; border:0 }
.skip{ position:fixed; top:.5rem; left:.5rem; z-index:220; padding:.8rem 1.2rem;
  background:var(--plum); color:var(--bone); transform:translateY(-180%);
  transition:transform .4s var(--e-soft); font-size:var(--l1);
  letter-spacing:.048em; text-transform:uppercase; font-weight:700 }
.skip:focus{ transform:none }

/* ══════════════════════════════════════════════════════════════
   TYPE ROLES  (mirrors era-residence: h/l/c/a)
   ══════════════════════════════════════════════════════════════ */
.h1,.h2,.h3,.h4,.h5,.h6{
  font-family:'Gilda Display',Didot,'Bodoni 72',Georgia,serif;
  font-weight:400; font-stretch:normal; text-transform:uppercase;
  font-variant-numeric:lining-nums tabular-nums; text-wrap:balance;
}
.h1{ font-size:var(--h1); line-height:.875; letter-spacing:-.024em }
.h2{ font-size:var(--h2); line-height:.878; letter-spacing:-.024em }
.h3{ font-size:var(--h3); line-height:.917; letter-spacing:-.024em }
.h4{ font-size:var(--h4); line-height:.95;  letter-spacing:-.016em }
.h5{ font-size:var(--h5); line-height:1;    letter-spacing:-.008em }
.h6{ font-size:var(--h6); line-height:1.05; letter-spacing:0 }
.a1,.a2{ font-family:'Italianno',cursive; font-weight:400; font-stretch:normal;
  text-transform:none; letter-spacing:.012em; line-height:.92;
  /* Italianno rides lower and smaller on the em than the face it replaced, so
     the optical margins and the scale are set for it, not inherited */
  margin-top:.06em; margin-bottom:-.14em; color:var(--mark) }
.a1{ font-size:var(--a1) } .a2{ font-size:var(--a2) }
.l1{ font-size:var(--l1); line-height:1.45; letter-spacing:.048em;
  text-transform:uppercase; font-weight:700 }
.l2{ font-size:var(--l2); line-height:1.45; letter-spacing:.03em;
  text-transform:uppercase; font-weight:600 }
.c1{ font-family:'Gilda Display',Georgia,serif; font-stretch:normal;
  font-size:var(--c1); line-height:1.26; letter-spacing:var(--tr,.8em);
  text-transform:uppercase; font-weight:400 }
.body{ font-size:var(--body); line-height:1.55; color:var(--fg-60) }
.lede{ font-size:var(--lede); line-height:1.35; letter-spacing:-.01em }
.dim{ color:var(--fg-60) }
.idx{ font-family:'Gilda Display',Georgia,serif; font-stretch:normal;
  font-variant-numeric:lining-nums tabular-nums; font-size:var(--l2);
  letter-spacing:.06em; color:var(--mark) }

/* ══════════════════════════════════════════════════════════════
   GRID  (10 columns, 16px gutters, 48/24px offsets)
   ══════════════════════════════════════════════════════════════ */
.sect{ position:relative; background:var(--bg); color:var(--fg); isolation:isolate }
.wrap{ padding-inline:var(--offset) }
.grid{ display:grid; grid-template-columns:repeat(10,minmax(0,1fr)); column-gap:var(--gap) }
@media (max-width:1023px){ .grid{ grid-template-columns:repeat(4,minmax(0,1fr)) } }
.pad-v{ padding-block:calc(var(--cell-v) * 1.5) }
.pad-v-lg{ padding-block:calc(var(--cell-v) * 2.25) }

/* the arch: the signature shape, and a wedding arch besides.
   Default is a wide, shallow arch; --full is the true semicircle. */
.arch{ border-top-left-radius:50% 14rem; border-top-right-radius:50% 14rem;
  position:relative; z-index:1; overflow:clip }
.arch--full{ border-top-left-radius:50rem; border-top-right-radius:50rem;
  padding-top:clamp(110px, 18vw, 300px) }
.js [data-archgrow]{ border-top-left-radius:calc(var(--ag,1) * 50rem);
  border-top-right-radius:calc(var(--ag,1) * 50rem) }
@media (max-width:1023px){
  .arch{ border-top-left-radius:50% 5rem; border-top-right-radius:50% 5rem }
  .arch--full{ border-top-left-radius:50% 10rem; border-top-right-radius:50% 10rem;
    padding-top:clamp(90px, 18vw, 180px) }
}
.arch-img{ position:relative; overflow:clip; aspect-ratio:var(--ar,144/168);
  border-top-left-radius:50%; border-top-right-radius:50% }
.arch-img.tall{ aspect-ratio:120/168 }

/* ── IMAGE FRAMES + PARALLAX ──────────────────────────────────
   Era moves every photograph inside its own frame as the page passes it, and
   that one habit is most of why their page feels alive rather than printed.
   The travel is deliberately small — a photograph that slides is a gimmick, a
   photograph that breathes is a window. The image is cropped taller than the
   frame rather than scaled up inside it, so it gains room to move without
   losing a single pixel of sharpness.
   ──────────────────────────────────────────────────────────── */
.frame{ display:block; position:relative; overflow:clip; isolation:isolate }
.frame > img{ width:100%; height:100%; object-fit:cover; display:block }
.frame.par > img{ position:absolute; left:0; top:0; width:100%; height:140%;
  object-fit:cover }
/* the sleeve is what moves; the frame keeps its reveal and the picture keeps
   its own settle, so three separate ideas never share one transform */
.psl{ display:block; position:absolute; inset:-7% 0; will-change:transform }
.psl > img{ width:100%; height:100%; object-fit:cover; display:block }
@media (prefers-reduced-motion:reduce){ .psl{ transform:none !important } }
.frame[data-enter] > img{ image-rendering:auto }
/* the image arrives slightly large and settles as it enters, era does this
   on every picture and it is most of what makes the page feel alive */
.frame::after{ content:''; position:absolute; inset:0; pointer-events:none; z-index:1;
  background:linear-gradient(190deg, rgb(52 12 36/.05), rgb(220 203 169/.05));
  mix-blend-mode:soft-light }
.shade{ position:absolute; inset:0; z-index:2; pointer-events:none;
  background:linear-gradient(#0000, #00000047) }
.shade.top{ background:linear-gradient(#00000047, #0000) }
.hero__media .shade{ background:linear-gradient(rgb(52 12 36/0) 42%, rgb(52 12 36/.30) 74%, rgb(52 12 36/.62)) }
.hero__media .shade.top{ background:linear-gradient(rgb(52 12 36/.34), rgb(52 12 36/0) 36%) }
/* A plum pool in the middle was there to hold up white type. The photograph
   is pale now and the type is plum, so the pool works the other way: a soft
   breath of paper right where the wordmark stands. */
.hero__media::before{ content:''; position:absolute; inset:0; z-index:2; pointer-events:none;
  background:none }
/* On a narrow screen the crop puts the bottle exactly behind the script, and
   a pink script over a pink bow is not a script. The bed of paper has to be
   deeper there, because there is nowhere else for the wordmark to stand. */
@media (max-width:1023px){
  .hero__media::before{ background:none }
}

/* grain over everything, one field per section */
.sect::after{ content:''; position:absolute; inset:0; z-index:6; pointer-events:none;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.82' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size:160px 160px; mix-blend-mode:overlay; opacity:.045 }
.t-plum::after{ mix-blend-mode:soft-light; opacity:.07 }

.rule{ height:.75px; width:100%; background:var(--line) }

/* ══════════════════════════════════════════════════════════════
   BUTTONS
   ══════════════════════════════════════════════════════════════ */
.pill{
  display:inline-flex; align-items:center; gap:.9em; cursor:pointer; border:0;
  height:calc(var(--l1) * 4.2); padding:0 1.9em; border-radius:99rem;
  background:var(--plum); color:var(--bone);
  font-size:var(--l1); font-weight:700; letter-spacing:.048em; text-transform:uppercase;
  transition:background-color .4s var(--e-soft), color .4s var(--e-soft),
             transform 90ms var(--e-soft);
}
.pill:active{ transform:scale(.98) }
.pill--hot{ background:var(--pink); color:#fff }
.pill--hot:hover{ background:var(--pink-deep) }
.t-plum .pill{ background:var(--bone); color:var(--plum) }
.t-plum .pill--hot{ background:var(--pink); color:#fff }
/* ── THE ROLL ─────────────────────────────────────────────────
   Two stacked copies of the same word; hovering rolls the first out of the
   top and the second in from the bottom. Split into letters it stops being a
   swap and becomes a sweep: each letter leaves a fraction after the one to
   its left, so the word reads as one movement passing through it rather than
   two blocks changing places. Without script the letters are never made, and
   the two whole words roll as before.
   ──────────────────────────────────────────────────────────── */
.roll{ position:relative; display:block; overflow:clip; height:1.45em }
.roll > span{ display:block; line-height:1.45; transition:transform var(--d-m) var(--e-out) }
.roll > span+span{ position:absolute; inset:0; transform:translateY(100%) }
.pill:hover .roll > span:first-child,.navlink:hover .roll > span:first-child,
.lnk:hover .roll > span:first-child,.wa:hover .roll > span:first-child{ transform:translateY(-100%) }
.pill:hover .roll > span+span,.navlink:hover .roll > span+span,
.lnk:hover .roll > span+span,.wa:hover .roll > span+span{ transform:translateY(0) }

/* the split form: the parent stops moving and hands the job to the letters */
.roll > span:has(.rc){ transform:none !important }
.rc{ display:inline-block; white-space:pre;
  transition:transform var(--d-m) var(--e-out) calc(var(--ci,0) * 24ms) }
.roll > span+span .rc{ transform:translateY(100%) }
.pill:hover .roll > span:first-child .rc,.navlink:hover .roll > span:first-child .rc,
.lnk:hover .roll > span:first-child .rc,.menub:hover .roll > span:first-child .rc,
.wa:hover .roll > span:first-child .rc,.wa:focus-visible .roll > span:first-child .rc{
  transform:translateY(-100%) }
.pill:hover .roll > span+span .rc,.navlink:hover .roll > span+span .rc,
.lnk:hover .roll > span+span .rc,.menub:hover .roll > span+span .rc,
.wa:hover .roll > span+span .rc,.wa:focus-visible .roll > span+span .rc{
  transform:translateY(0) }
@media (prefers-reduced-motion:reduce){ .rc{ transition:none } }
.arrow{ position:relative; width:1.15em; height:.75px; background:currentColor }
.arrow::after{ content:''; position:absolute; right:0; top:-2.5px; width:6px; height:6px;
  border-top:.75px solid currentColor; border-right:.75px solid currentColor;
  transform:rotate(45deg) }

/* the big circular button era uses for its primary calls */
.circle{
  position:relative; display:grid; place-items:center; aspect-ratio:1;
  width:calc(var(--cell-v) * 2 + var(--gap)); border-radius:50%;
  background:var(--pink); color:#fff; text-align:center; cursor:pointer; border:0;
  font-size:var(--l1); font-weight:700; letter-spacing:.048em; text-transform:uppercase;
  transition:background-color .45s var(--e-soft), transform .6s var(--e-out);
}
.circle:hover{ background:var(--pink-deep) }
.circle svg{ position:absolute; inset:0; width:100%; height:100%;
  animation:spin 22s linear infinite }
@keyframes spin{ to{ transform:rotate(360deg) } }

/* ══════════════════════════════════════════════════════════════
   PRELOADER + CURTAIN
   ══════════════════════════════════════════════════════════════ */
/* The preloader is only ever taken down by script. Without script it would sit
   over the whole site for good, so it only exists when script is there. */
/* The curtain opens by itself. Script only short-circuits it, so a script that
   never runs leaves the site visible instead of a cream sheet for ever. */
.pre{ display:none }
.js .pre{ display:block; position:fixed; inset:0; z-index:200; pointer-events:none }
.js .pre__half{ animation:preopen 1.05s var(--e-out) 2.6s forwards }
.js .pre__mark{ animation:premark .4s var(--e-soft) 2.6s forwards }
@keyframes preopen{ to{ transform:translateX(var(--pd,-101%)) } }
@keyframes premark{ to{ opacity:0 } }
.pre__half.l{ --pd:-101% } .pre__half.r{ --pd:101% }
html.pre-done .pre__half,html.pre-done .pre__mark{ animation:none }
.pre__half{ position:absolute; top:-1%; bottom:0; width:calc(50% + 1px);
  background:var(--bone); transition:transform 1.05s var(--e-out) .35s }
.pre__half.l{ left:0 } .pre__half.r{ right:0 }
.pre__mark{ position:absolute; inset:0; display:grid; place-items:center; z-index:1;
  transition:opacity .4s var(--e-soft) }
/* ── THE HEART BEATS WHILE YOU WAIT ───────────────────────────
   A heart does not throb evenly, it goes lub-dub and then rests, and the
   rest is most of the cycle. That silence is the whole reason a real
   heartbeat reads as alive and a pulsing logo reads as a loading spinner:
   two quick knocks, the second smaller than the first, and then nothing
   for the best part of a second. Set here at about 52 beats a minute,
   which is a person at rest rather than a person in a hurry.
   ────────────────────────────────────────────────────────────── */
.pre__heart{ position:relative; display:block;
  width:clamp(88px, 11vw, 152px); aspect-ratio:1; line-height:0 }
.pre__heart img{ width:100%; height:100%; object-fit:contain; position:relative; z-index:1 }
.js .pre__heart img{ transform-origin:50% 56%;
  animation:beat 1.15s cubic-bezier(.3,0,.2,1) infinite }
@keyframes beat{
  0%   { transform:scale(1) }
  6%   { transform:scale(1.125) }   /* lub */
  13%  { transform:scale(1.015) }
  19%  { transform:scale(1.075) }   /* dub */
  31%  { transform:scale(1) }
  100% { transform:scale(1) }
}
/* what the beat pushes out: two rings on the same clock, the second a beat
   behind, so the room keeps a little of the last one while the next arrives */
.pre__pulse{ position:absolute; inset:0; border-radius:50%; z-index:0;
  background:radial-gradient(circle,
    color-mix(in srgb, var(--pink) 26%, transparent) 0 42%, transparent 68%);
  opacity:0; transform:scale(.7) }
.js .pre__pulse{ animation:beatRing 1.15s cubic-bezier(.22,.61,.36,1) infinite }
.js .pre__pulse--2{ animation-delay:.13s }
@keyframes beatRing{
  0%  { opacity:0;   transform:scale(.72) }
  8%  { opacity:.85; transform:scale(1.05) }
  46% { opacity:0;   transform:scale(1.95) }
  100%{ opacity:0;   transform:scale(1.95) }
}
@media (prefers-reduced-motion:reduce){
  .js .pre__heart img{ animation:none } .js .pre__pulse{ animation:none; opacity:0 }
}
html.pre-done .pre__half.l{ transform:translateX(-101%) }
html.pre-done .pre__half.r{ transform:translateX(101%) }
html.pre-done .pre__mark{ opacity:0; transition-duration:.28s }
html.pre-done .pre{ transition:visibility 0s linear 1.5s; visibility:hidden }

/* ── LEAVING A PAGE ───────────────────────────────────────────
   There are two pages here, and a browser's own white flash between them
   undoes everything the rest of the site is doing. The same curtain that
   opened the page closes it, and the next page opens its own. The link still
   works with the script gone: this only intercepts what it can finish.
   ──────────────────────────────────────────────────────────── */
html.pre-out .pre{ visibility:visible; transition:none }
/* has to out-rank html.pre-done .pre__half.l, which is what parked them open */
html.pre-out .pre__half.l,html.pre-out .pre__half.r{ animation:none; transform:none;
  transition:transform .62s var(--e-silk) }
html.pre-out .pre__mark{ animation:none; opacity:1;
  transition:opacity .5s var(--e-soft) .16s }
@media (prefers-reduced-motion:reduce){
  html.pre-out .pre__half.l,html.pre-out .pre__half.r,
  html.pre-out .pre__mark{ transition:none }
}

/* ══════════════════════════════════════════════════════════════
   NAV
   ══════════════════════════════════════════════════════════════ */
/* ── THE NAV GETS OUT OF THE WAY ──────────────────────────────
   A fixed bar with no background sits on top of whatever is underneath it,
   and on a phone that is a heading it collides with. So it leaves when you
   are reading forward and comes back the moment you look for it, which is
   the only two states a menu ever needs. Coming back it brings just enough
   paper with it to be legible over anything.
   ──────────────────────────────────────────────────────────── */
.nav{ position:fixed; top:0; left:0; right:0; z-index:120;
  display:flex; align-items:center; justify-content:space-between;
  padding:calc(var(--offset) * .55) var(--offset);
  color:var(--plum); mix-blend-mode:normal;
  transition:color .55s var(--e-soft), padding .45s var(--e-soft),
             transform .62s var(--e-io), background-color .5s var(--e-soft) }
.nav.is-tuck{ transform:translateY(-102%) }
.nav.is-set{ padding-block:calc(var(--offset) * .34);
  background:color-mix(in srgb, var(--bg,var(--bone)) 86%, transparent);
  -webkit-backdrop-filter:blur(14px) saturate(1.1);
  backdrop-filter:blur(14px) saturate(1.1) }
.nav.is-set.on-dark{ background:color-mix(in srgb, var(--plum) 80%, transparent) }
html.menu-open .nav{ transform:none }
@media (prefers-reduced-motion:reduce){ .nav.is-tuck{ transform:none } }
/* light is what most of the site is, and it is what a page opens on with no
   script yet: the dark variant is the exception and has to ask for itself */
.nav.on-dark{ color:var(--bone) }
/* ── THE SEAL ─────────────────────────────────────────────────
   The wordmark gave way to a seal, the way era-residence does it: the studio's
   name set around a circle, turning, with the mark of the house at its centre.
   The ring never stops, and the scroll drives it — faster while you are moving
   and the other way round when you go back up — so the corner of the page
   answers to what your hand is doing rather than to a clock.
   ────────────────────────────────────────────────────────────── */
.nav__logo{ position:relative; display:block; line-height:0; color:inherit; flex:0 0 auto }
.seal{ width:calc(var(--l1) * 10.2); aspect-ratio:1; display:grid; place-items:center }
.seal__ring{ position:absolute; inset:0; width:100%; height:100%; overflow:visible;
  fill:currentColor; rotate:var(--seal,0deg) }
 /* the ring is one lap of the name exactly: textLength pins it to the
    circumference, so it can never lap itself and collide at the seam */
.seal__ring text{ font-family:'Gilda Display',Georgia,serif; font-size:9.4px;
  text-transform:uppercase }
.seal__heart{ position:relative; width:52%; height:auto;
  transform-origin:50% 58%;
  filter:drop-shadow(0 .06em .14em rgb(52 12 36/.26)) }
.js .seal__heart{ animation:lgBeat 3.6s cubic-bezier(.3,0,.2,1) infinite }
@keyframes lgBeat{
  0%   { transform:scale(1) }
  5%   { transform:scale(1.14) }
  10%  { transform:scale(1.02) }
  15%  { transform:scale(1.085) }
  24%  { transform:scale(1) }
  100% { transform:scale(1) }
}
.seal:hover .seal__heart{ filter:drop-shadow(0 .1em .22em rgb(169 47 93/.45)) }
@media (max-width:1023px){ .seal{ width:calc(var(--l1) * 7.4) }
  .seal__ring text{ font-size:9.8px } }
@media (prefers-reduced-motion:reduce){ .js .seal__heart{ animation:none } }

.nav__mid{ display:flex; gap:2.4rem; align-items:center; flex:0 0 auto; white-space:nowrap }
.navlink{ font-size:var(--l1); font-weight:700; letter-spacing:.048em; white-space:nowrap;
  text-transform:uppercase; position:relative }
.navlink.is-active{ color:var(--mark) }
.nav__right{ display:flex; align-items:center; gap:1.6rem }
.lang{ display:flex; align-items:center; gap:.35em; font-size:var(--l1);
  font-weight:700; letter-spacing:.048em }
.lang button{ background:none; border:0; padding:.4em .2em; cursor:pointer; opacity:.45;
  transition:opacity .35s var(--e-soft) }
.lang button[aria-pressed="true"]{ opacity:1 }
.lang i{ opacity:.35; font-style:normal }
.menub{ display:flex; align-items:center; gap:.7em; background:none; border:0;
  cursor:pointer; font-size:var(--l1); font-weight:700; letter-spacing:.048em;
  text-transform:uppercase; padding:.4em 0 }
.menub__dots{ display:grid; gap:3px }
.menub__dots i{ width:3px; height:3px; border-radius:50%; background:currentColor;
  display:block; transition:transform .4s var(--e-out) }
.menub:hover .menub__dots i:first-child{ transform:translateY(-1px) }
.menub:hover .menub__dots i:last-child{ transform:translateY(1px) }
@media (max-width:1023px){ .nav__mid{ display:none } }

/* full-screen menu */
/* The menu comes down as an arch, not a rectangle. It is the same shape the
   hero closes into and the same shape two sections are cut to, and using it
   here is what turns a motif into a grammar. */
.menu{ position:fixed; inset:0; z-index:150; background:var(--plum); color:var(--bone);
  display:grid; align-content:center; padding:var(--offset);
  clip-path:inset(0 0 100% 0 round 0 0 46rem 46rem);
  transition:clip-path .92s var(--e-silk) }
.menu.is-open{ clip-path:inset(0 0 0 0 round 0 0 0 0) }
.menu a.big{ font-family:'Gilda Display',Georgia,serif; font-size:var(--h3);
  line-height:1.06; text-transform:uppercase; letter-spacing:-.02em; display:block;
  padding-block:.12em; opacity:0; transform:translateY(24px);
  transition:opacity .6s var(--e-out) calc(var(--i) * 70ms + 180ms),
             transform .6s var(--e-out) calc(var(--i) * 70ms + 180ms) }
.menu.is-open a.big{ opacity:1; transform:none }
/* the rule draws itself out from under the word, left to right */
.menu a.big{ position:relative; width:max-content; max-width:100% }
.menu a.big::after{ content:''; position:absolute; left:0; right:0; bottom:.16em;
  height:.75px; background:currentColor; transform:scaleX(0); transform-origin:0 50%;
  transition:transform .62s var(--e-out) }
.menu a.big:hover,.menu a.big:focus-visible{ color:var(--blush) }
.menu a.big:hover::after,.menu a.big:focus-visible::after{ transform:scaleX(1) }
.menu__foot{ margin-top:calc(var(--cell-v) * .7); padding-top:1.2rem;
  border-top:.75px solid var(--line); display:flex; gap:1.5rem 2.5rem; flex-wrap:wrap;
  font-size:var(--l1); font-weight:700; letter-spacing:.048em; text-transform:uppercase }
.menu__close{ position:absolute; top:calc(var(--offset) * .55); right:var(--offset);
  background:none; border:0; color:inherit; cursor:pointer; font-size:var(--l1);
  font-weight:700; letter-spacing:.048em; text-transform:uppercase; padding:.4em 0 }
html.menu-open{ overflow:hidden }

/* ══════════════════════════════════════════════════════════════
   HERO
   ══════════════════════════════════════════════════════════════ */
/* ── THE PINS ─────────────────────────────────────────────────
   A dot on the photograph with two rings breathing out of it, and a small
   card that opens when you go near. Era uses them on their render and they
   are the one piece of interface that earns a place on top of a photograph:
   they turn a nice picture into a catalogue you can read. They live inside
   the picture's own layer, so they travel and clip with it, and they leave
   as soon as the arch starts closing — by then they have nothing to point at.
   ────────────────────────────────────────────────────────────── */
.pin{ position:absolute; left:var(--px); top:var(--py); z-index:4;
  width:34px; height:34px; margin:-17px 0 0 -17px;
  display:grid; place-items:center; color:var(--bone);
  opacity:calc(1 - var(--k,0)); pointer-events:auto }
.pin__dot{ width:7px; height:7px; border-radius:50%; background:currentColor;
  box-shadow:0 0 0 1px rgb(52 12 36/.28), 0 2px 8px rgb(20 6 14/.4);
  transition:transform var(--d-m) var(--e-out) }
.pin:hover .pin__dot{ transform:scale(1.5) }
.pin__pulse{ position:absolute; width:14px; height:14px; border-radius:50%;
  border:.75px solid currentColor; opacity:0 }
.js .pin__pulse{ animation:pinPulse 2.6s var(--e-ken) infinite }
.js .pin__pulse--2{ animation-delay:.55s }
@keyframes pinPulse{
  0%  { opacity:.9; width:14px; height:14px }
  70% { opacity:0;  width:38px; height:38px }
  100%{ opacity:0;  width:38px; height:38px }
}
/* the little window: it opens above the dot, and it opens by unrolling from
   the pin rather than fading in, so it reads as attached to the thing */
.pin__tip{ position:absolute; bottom:calc(100% + 6px); left:50%;
  translate:-50% 0; transform-origin:50% 100%;
  display:grid; justify-items:center; white-space:nowrap;
  opacity:0; scale:.86; pointer-events:none;
  transition:opacity .34s var(--e-soft), scale .42s var(--e-out) }
.pin:hover .pin__tip,.pin:focus-visible .pin__tip{ opacity:1; scale:1 }
.pin__tip b{ display:block; padding:.62em 1.05em; border-radius:99rem;
  background:var(--bone); color:var(--plum);
  font-size:calc(var(--l1) * .92); font-weight:700; letter-spacing:.048em;
  text-transform:uppercase; box-shadow:0 8px 26px rgb(20 6 14/.28) }
.pin__tip s{ display:block; width:1px; height:7px; background:var(--bone) }
@media (max-width:1023px){ .pin{ display:none } }
@media (prefers-reduced-motion:reduce){ .js .pin__pulse{ animation:none; opacity:.5 } }

/* ── THE HERO CLOSES INTO THE ARCH ──────────────────────────────
   The old exit was a rectangle of paper sliding up over a photograph, which
   is the one move a page should never make: it announces that there are two
   sheets and that one is on top of the other. Instead the photograph closes
   into the arch — the shape the whole site is built on, and the shape a
   ribbon makes over a box — so for one moment the wordmark stands framed
   inside it like a poster, and then the poster lifts out of a page that was
   already bone. There is no seam left to see, because there is no seam.
   ────────────────────────────────────────────────────────────── */
/* A sticky pin always ends with one viewport of itself scrolling away, and
   here that viewport was blank paper: a whole screen of nothing between the
   arch leaving and the box arriving. The next section is pulled up over that
   tail, and the pin's own paper is faded out at the last moment, so what was
   a dead screen is now the handover. */
.hero{ height:230svh; color:var(--bone); z-index:6;
  /* The section itself must carry no paper of its own. All of it is above the
     section that was pulled up underneath, and an opaque background here would
     hide that section for its whole length. The pin is what holds the paper,
     and the pin is exactly one screen tall. */
  background:transparent }
.hero::after{ content:none }
.hero__pin{ position:sticky; top:0; height:100svh; overflow:clip; display:grid;
  background:color-mix(in srgb, var(--bone) calc((1 - var(--hend,0)) * 100%), transparent) }
.hero__media{ position:absolute; inset:-3.5%; z-index:0;
  --k:var(--hclose,0);
  /* one shape, driven by one number: full bleed at 0, a standing arch at 1 */
  clip-path:inset(
    calc(var(--k) * 7%)  calc(var(--k) * 28%)
    calc(var(--kc,0) * 104%) calc(var(--k) * 28%)
    round calc(var(--k) * 40rem) calc(var(--k) * 40rem) 0 0);
  translate:0 calc(var(--hlift,0) * -13vh);
  /* Lifting an arch off the floor exposes its base, and a base cut straight
     across reads as a photograph that ran out rather than a shape that left.
     So the foot dissolves into the paper exactly as much as it has risen. */
  -webkit-mask-image:linear-gradient(to top, transparent calc(var(--kc,0) * 104%),
     #000 calc(var(--kc,0) * 104% + var(--hlift,0) * 20% + .5%));
  mask-image:linear-gradient(to top, transparent calc(var(--kc,0) * 104%),
     #000 calc(var(--kc,0) * 104% + var(--hlift,0) * 20% + .5%)) }
@media (max-width:1023px){
  .hero{ height:205svh }
  /* On a phone an arch that keeps the full width is just a screen with
     rounded corners. It has to be clearly narrower than the page before the
     crown reads as a crown. */
  .hero__media{ clip-path:inset(
    calc(var(--k) * 10%) calc(var(--k) * 14%)
    calc(var(--kc,0) * 108%) calc(var(--k) * 14%)
    round calc(var(--k) * 22rem) calc(var(--k) * 22rem) 0 0) }
}
.hero__media img{ width:100%; height:100%; object-fit:cover }
.hero__inner{ position:relative; z-index:3; height:100%; grid-area:1/1;
  display:grid; grid-template-rows:1fr auto; align-items:center;
  padding-block:calc(var(--offset) * 3.4) calc(var(--offset) * .8) }
/* On a phone the crop puts the bottle in the middle of the frame, and the
   script is a hairline face: over satin it simply is not there. Rather than
   thickening the letters or bleaching the photograph, the wordmark moves up
   to the empty wall, which is where it wanted to be anyway. */
/* ── THE CALL ─────────────────────────────────────────────────
   Era's circular button, in this brand's colours: no box, no fill, just the
   words standing inside a hairline ring with one short arc drawn on it. Go
   near it and the arc runs round to half the circle — a dial turning, not a
   button lighting up — while the label rolls letter by letter. The arc maths
   is theirs: a circle of r=103.5, so the circumference is 650.3, and the arc
   goes from 4.17% of it to 50%.
   ────────────────────────────────────────────────────────────── */
.wa{ --wa-ink:var(--plum);
  position:fixed; right:calc(var(--offset) * .7); bottom:calc(var(--offset) * .62);
  z-index:118; display:grid; place-items:center;
  width:calc(var(--l1) * 11.6); aspect-ratio:1; color:var(--wa-ink);
  opacity:0; translate:0 18px; pointer-events:none;
  transition:opacity .65s var(--e-soft), translate .65s var(--e-out), color .5s var(--e-io) }
.wa.is-up{ opacity:1; translate:0 0; pointer-events:auto }
.wa.on-dark{ --wa-ink:var(--bone) }
.wa__ring{ position:absolute; inset:0; width:100%; height:100%; fill:none;
  stroke:currentColor; rotate:-90deg }
.wa__hair{ stroke-width:1; opacity:.26 }
.wa__arc{ stroke-width:1.6; stroke-linecap:round;
  stroke-dasharray:27.1 650.3;
  transition:stroke-dasharray var(--d-m) var(--e-io) }
.wa:hover .wa__arc,.wa:focus-visible .wa__arc{ stroke-dasharray:325.2 650.3 }
.wa__in{ display:grid; justify-items:center; gap:.55em; text-align:center;
  padding:0 1.6em }
.wa__ico{ width:1.62em; height:1.62em; color:#25D366;
  transition:color .5s var(--e-io) }
.wa:hover .wa__ico,.wa:focus-visible .wa__ico{ color:var(--mark) }
.wa__lab{ font-size:calc(var(--l1) * .92); font-weight:700; letter-spacing:.048em;
  text-transform:uppercase; line-height:1.36; height:auto; text-wrap:balance }
/* No roll here. The label runs to three lines inside the circle, and the
   roll is built to slide one line under another: with three it just stacks
   two copies on top of each other. The arc is the gesture on this button. */
@media (max-width:1023px){ .wa{ width:calc(var(--l1) * 9.6) }
  .wa__lab{ font-size:calc(var(--l1) * .82) } .wa__in{ padding:0 1.15em } }
@media (prefers-reduced-motion:reduce){ .wa{ transition:none } }

.hero__foot{ transition:opacity var(--d-m) var(--e-soft) }
.hero .petals{ opacity:calc(1 - var(--hgone,0)) }
@keyframes eyeIn{ to{ opacity:1; transform:none } }
.hero__foot{ display:flex; align-items:flex-end; justify-content:space-between; gap:2rem }
.hero__scroll{ display:flex; align-items:center; gap:.9em }
.hero__scroll s{ display:block; width:56px; height:.75px; background:currentColor;
  opacity:.5; text-decoration:none; position:relative; overflow:hidden }
.hero__scroll s::after{ content:''; position:absolute; inset:0; background:currentColor;
  animation:sweep 2.8s var(--e-soft) infinite }
@keyframes sweep{ 0%{ transform:translateX(-100%) } 62%,100%{ transform:translateX(100%) } }
@media (max-width:1023px){
  .hero__foot{ flex-direction:column; align-items:flex-start; gap:1rem }
}

/* ══════════════════════════════════════════════════════════════
   CURTAIN SECTION: two bone halves slide apart on scroll
   ══════════════════════════════════════════════════════════════ */
.curtain{ position:relative; height:255svh; z-index:5; margin-top:-100svh }
.curtain__pin{ position:sticky; top:0; height:100svh; display:grid }
/* The two halves are what the scene hides behind, and only script opens them.
   Without script they must not exist, or the box section is a blank sheet. */
.curtain__half{ position:absolute; top:-1%; bottom:-1%; width:calc(50% + 1px);
  background:transparent; z-index:2 }
.js .curtain__half{ background:var(--bone) }
.curtain__half.l{ left:0 } .curtain__half.r{ right:0 }
.curtain__cap{ position:relative; z-index:5; align-self:start; justify-self:center;
  text-align:center; color:var(--plum); padding:calc(var(--cell-v) * 1.55) var(--offset) 0;
  /* the wide tracking makes this line far wider than a phone: without a cap it
     runs off the right edge and the clip on the root eats the last letters */
  max-width:min(94vw, 62rem) }
.curtain__cap .c1{ display:block }
.cap__lab{ display:block; margin-bottom:1.05rem; color:var(--pink) }
/* the script face carries its own size and its own pink from .a2: no second
   opinion here, or this line stops matching the ones elsewhere on the site */
.cap__script{ display:block; margin-top:.85rem }
.curtain__cap{ text-wrap:balance }

/* ══════════════════════════════════════════════════════════════
   THE BOX OPENS — a 2.5D stage driven by scroll
   No ancestor may clip or filter it, or the browser flattens the 3D.
   ══════════════════════════════════════════════════════════════ */
.scene{ position:absolute; inset:0; z-index:1; display:grid; place-items:center;
  overflow:visible;
  perspective:1400px; perspective-origin:50% 44% }
/* the third term is the one that matters on a short window: 10/17 off the
   width alone put the base of the box below the bottom of the pin */
.scene__panel{ position:relative; width:min(46vw, 470px, 54svh); aspect-ratio:10/17;
  transform-style:flat; perspective:1150px; perspective-origin:50% 42% }
.scene__glow{ position:absolute; inset:-14% -34% -8%; border-radius:50%;
  scale:calc(.86 + var(--aBox,1) * .14);
  background:color-mix(in srgb, var(--blush) 30%, transparent);
  filter:blur(70px); opacity:calc(.25 + var(--open,0) * .6) }
.boxfig{ position:absolute; inset:0 }
.boxfig img{ display:block; position:absolute; height:auto }
/* Paint order is the whole trick, and it mirrors the real object:
   2 the rim and inside of the box, then the sweets, then 1 the front wall
   that hides them while they are still in there, then 3 the lid on top. */
/* Every number here comes from the source photograph, where ChatGPT drew the
   two pieces in one frame at one scale: the lid crop is 776 wide, the body crop
   567, so the lid IS 1.369x the body — nothing to invent. Their crop origins in
   that frame were (122,59) and (225,801), which fixes the horizontal alignment,
   and D=256 is the drop that closes the box (measured: the interior stops
   showing at 240). One body pixel = 0.1222% of the stage width. */
/* Each piece arrives on its own ramp, so the box is built rather than wiped in.
   Nothing turns out of plane: the lid rotates in the picture plane only. */
.boxfig__back { left:15.22%; width:69.29%; top:43.17%; z-index:1;
  opacity:var(--aBox,1);
  transform:translate3d(0, calc(var(--rise,0) * 1px), 0) }
/* the box is filled after it exists, not before: without this the sweets
   float in the air while the walls are still on their way in */
.sweets--in   { z-index:2 }
.boxfig__front{ left:15.22%; width:69.29%; top:43.17%; z-index:3;
  opacity:var(--aBox,1);
  transform:translate3d(0, calc(var(--rise,0) * 1px), 0);
  filter:drop-shadow(0 16px 22px rgb(52 12 36/.16)) }
.boxfig__lid  { left:2.63%;  width:94.83%; top:8.24%;  z-index:4;
  transform-origin:50% 86%; opacity:var(--aLid,1);
  filter:drop-shadow(0 10px 16px rgb(52 12 36/.14));
  transform:
    /* no Z here: .boxfig is flat and the stage's perspective does not reach a
       grandchild, so a translateZ would be a lie that costs a repaint */
    translate3d(calc(var(--open,0) * 16% + var(--fly,0) * 30%),
                calc((1 - var(--aLid,1)) * -58% + var(--settle,0) * 4%
                     + var(--open,0) * -46% + var(--fly,0) * -88%), 0)
    rotateZ(calc((1 - var(--aLid,1)) * -12deg
                 + var(--open,0) * -13deg + var(--fly,0) * -24deg)) }
/* once a sweet is out of the box it flies over everything */
.sweets--out{ z-index:6 }
/* a shadow on the ground rather than on the cut-outs, so the edges stay soft */
.scene__shadow{ position:absolute; left:17%; right:15%; bottom:6.6%; height:4%;
  border-radius:50%; background:radial-gradient(ellipse at 50% 50%,
    rgb(20 6 14/.30), rgb(20 6 14/0) 70%);
  transform:scale(calc(1 + var(--open,0) * .12)); z-index:1 }

/* ── the sweets ──────────────────────────────────────────────
   Real photographs, cut out with an alpha channel from a single studio
   sheet. Which side of the front wall a sweet is drawn on is read off its
   position every frame, never latched: inside the box it is behind, past the
   rim or wide of the walls it is in front. Fall back in and it hides again.
   ──────────────────────────────────────────────────────────── */

/* ── THE WORKBENCH: film on one side, washed into the type on the other ──
   No photographs here at all. The video holds the left of the frame and is
   masked out across the middle, so there is no edge, no card and no island:
   the footage simply becomes the page. */

/* ── THE CONTACT SHEET ────────────────────────────────────────
   One presentation instead of two. A list of six names and a drag
   carousel of the same six things said everything twice; this puts all
   six photographs on the page at once, on three tracks that read down
   and drift at different rates, so the composition breathes without a
   pin and without asking anyone to drag anything.
   ──────────────────────────────────────────────────────────── */

/* ── HOW AN ORDER WORKS: a ribbon that ties itself ───────────
   The four photographs that used to cross-fade in an arch here were the
   same pieces the work section already shows, so they said nothing new.
   What is actually true of every order is that it ends in a knot, so the
   section is a ribbon: it draws itself down the page from step to step
   and finishes in the bow, which never stops moving.
   ──────────────────────────────────────────────────────────── */
/* The bow sits on the seam between this section and the one above, so this
   section cannot clip vertically any more. Clip is not hidden: one axis may
   stay visible, so the sideways clip that kept the ribbon in is untouched. */
.tie{ position:relative; overflow-x:clip; overflow-y:visible }
.tie__head{ margin-bottom:calc(var(--cell-v) * 1.1) }
.tie__lab{ grid-column:1 / -1; margin-bottom:1.5rem }
.tie__title{ grid-column:1 / 8 }
/* The third column used to hold the bow. With the bow moved up onto the seam
   it holds nothing, and an even 1fr either side of the ribbon left the whole
   right half of the page empty while all the ink sat on the left. Half a
   column is enough of a margin, and it carries the script line. */
.tie__body{ position:relative; padding-inline:var(--offset);
  display:grid; grid-template-columns:1fr auto .5fr; align-items:start;
  column-gap:calc(var(--gap) * 2) }
.tie__ribbon{ grid-column:2; width:clamp(90px, 12vw, 170px); height:auto;
  color:var(--blush); overflow:visible;
  align-self:stretch; min-height:64svh }
.tie__line{ opacity:.85; stroke-linecap:round }
.tie__node{ fill:var(--blush);
  transform-box:fill-box; transform-origin:50% 50%;
  scale:calc(var(--n0,0)); transition:scale .5s var(--e-out) }
.tie__node:nth-of-type(2){ scale:calc(var(--n1,0)) }
.tie__node:nth-of-type(3){ scale:calc(var(--n2,0)) }
.tie__node:nth-of-type(4){ scale:calc(var(--n3,0)) }

.tie__steps{ grid-column:1; grid-row:1; display:grid; align-content:space-between;
  gap:calc(var(--cell-v) * .55); min-height:64svh; text-align:right; padding-right:.4rem }
.tie__step{ opacity:0; transform:translate3d(28px,0,0);
  transition:opacity .7s var(--e-soft) calc(var(--s,0) * 40ms),
             transform .8s var(--e-out) calc(var(--s,0) * 40ms) }
.tie__step.is-lit{ opacity:1; transform:none }
.tie__step .idx{ display:block; color:var(--mark); margin-bottom:.5rem }
.tie__step .h5{ margin-bottom:.5rem }
.tie__step .l1{ max-width:34ch; margin-left:auto }

/* ── THE BOW LIES ACROSS THE SEAM ─────────────────────────────
   It used to sit in the third column of the steps, politely inside the
   section. Laid across the join instead, hard against the left margin, it
   does the one thing a ribbon is for: it holds two things together. The
   finished pieces are above it and how they are made is below it, and the
   knot is what ties them.
   ────────────────────────────────────────────────────────────── */
.bow{ position:absolute; z-index:3; margin:0;
  left:calc(var(--offset) * .36); top:0;
  width:min(28vw, 470px); aspect-ratio:760 / 715;
  /* just under half of it stands on the paper above the seam */
  translate:0 -45%;
  /* soft and warm: half of this shadow falls on bone, and a hard black one
     there reads as a sticker rather than satin */
  filter:drop-shadow(0 18px 34px rgb(52 12 36/.30));
  opacity:var(--bowin,0); transform:scale(calc(.94 + var(--bowin,0) * .06));
  transition:opacity 1s var(--e-soft), transform 1.2s var(--e-out) }
/* ── ONE RIBBON, ONE LAYER ────────────────────────────────────
   The satin used to be three cut-outs of the same photograph stacked on each
   other. Each was feathered wide at its cut, so a quarter of the bow was two
   half-transparent copies laid over one another: the middle of the ribbon let
   the paper through, and because every piece drifted on its own clock, a
   second fainter bow moved behind the first. It is now a single opaque
   picture, rebuilt by taking each pixel from whichever cut-out held it
   sharpest and filling the silhouette solid.
   The motion survives. Two nested sways on periods that do not divide into
   each other keep the composite from ever repeating, which is what made the
   old rig feel like cloth rather than a loop.
   ────────────────────────────────────────────────────────────── */
.bow__sway,.bow__flex,.bow__breathe{ display:block; position:absolute; inset:0 }
.bow__p{ position:absolute; inset:0; display:block;
  width:100%; height:100%; object-fit:contain; will-change:transform }
/* Three sways, three origins, three periods that do not divide into each
   other, so the composite never repeats. The origins are what make one flat
   picture read as cloth: the turn happens at the knot, the shear happens low
   down where the tails hang, and the breath happens up in the loops. A shear
   about a low origin swings the tails several times further than the knot,
   which is exactly what a ribbon does in a draught. */
/* All three origins sit at the knot, because that is the one place a ribbon
   is actually held. Anything pinned there barely moves and everything hanging
   from it swings, which is the whole difference between cloth and a picture
   being rotated. A rigid translate would move the knot as much as the tails,
   so there is almost none of it. */
.js .bow__sway   { transform-origin:50% 15%; animation:bowSway 19s ease-in-out infinite }
.js .bow__flex   { transform-origin:50% 11%; animation:bowFlex 13.7s ease-in-out infinite }
.js .bow__breathe{ transform-origin:50% 9%;  animation:bowBreathe 17.3s ease-in-out infinite }
@keyframes bowSway{
  0%,100%{ transform:rotate(-1.75deg) translate3d(0,0,0) }
  33%    { transform:rotate(1.4deg)   translate3d(2px,-1.5px,0) }
  66%    { transform:rotate(.4deg)    translate3d(-1.5px,1px,0) }
}
@keyframes bowFlex{
  0%,100%{ transform:skew(1.6deg, .2deg) }
  28%    { transform:skew(-1.7deg, -.45deg) }
  61%    { transform:skew(.6deg, .34deg) }
}
@keyframes bowBreathe{
  0%,100%{ transform:scale(1.000, 1.000) }
  35%    { transform:scale(1.010, 1.022) }
  70%    { transform:scale(.994, .988) }
}
.bow__cap{ position:absolute; right:calc(var(--offset) + 1vw); bottom:-.4em;
  color:var(--mark); opacity:var(--knotin,0); transition:opacity 1s var(--e-soft) .3s }

@media (max-width:1023px){
  .tie__title{ grid-column:1 / -1 }
  .tie__body{ grid-template-columns:auto 1fr; column-gap:var(--gap) }
  .tie__ribbon{ grid-column:1; width:54px; min-height:0 }
  .tie__steps{ grid-column:2; grid-row:1; text-align:left; min-height:0;
    gap:calc(var(--cell-v) * .5); padding-right:0 }
  .tie__step .l1{ margin-left:0 }
  .bow{ left:auto; right:calc(var(--offset) * -.18); width:min(62vw, 300px);
    translate:0 -42% }
  .bow__cap{ position:static; display:block; text-align:center; margin-top:.2em }
}
@media (prefers-reduced-motion:reduce){
  .js .bow__sway,.js .bow__flex,.js .bow__breathe{ animation:none }
  .tie__step{ opacity:1; transform:none }
}

/* ── PETALS ───────────────────────────────────────────────────
   Nine of them, no more. Each has its own drift, its own turn and its own
   period, none of which divide into each other, so nothing ever lines up
   and the air never looks like a loop. They cost nine transforms and no
   script at all.
   ──────────────────────────────────────────────────────────── */
.petals{ position:absolute; inset:0; z-index:2; pointer-events:none; overflow:hidden }
.petal{ position:absolute; height:auto; fill:var(--blush); opacity:0;
  filter:drop-shadow(0 2px 5px rgb(52 12 36/.28)); will-change:transform }
.js .petal{ animation:petalFall var(--d,26s) linear var(--t,0s) infinite }
.petal:nth-child(1){ left:6%;  --d:31s;   --t:-2s;  width:13px }
.petal:nth-child(2){ left:17%; --d:24s;   --t:-11s; width:9px }
.petal:nth-child(3){ left:29%; --d:38s;   --t:-5s;  width:16px }
.petal:nth-child(4){ left:41%; --d:28s;   --t:-19s; width:10px }
.petal:nth-child(5){ left:54%; --d:34s;   --t:-8s;  width:12px }
.petal:nth-child(6){ left:66%; --d:26s;   --t:-23s; width:8px }
.petal:nth-child(7){ left:76%; --d:41s;   --t:-14s; width:15px }
.petal:nth-child(8){ left:86%; --d:29s;   --t:-3s;  width:11px }
.petal:nth-child(9){ left:94%; --d:36s;   --t:-27s; width:9px }
@keyframes petalFall{
  0%   { transform:translate3d(0,-14vh,0) rotate(0deg); opacity:0 }
  9%   { opacity:.86 }
  50%  { transform:translate3d(5vw,50vh,0) rotate(190deg); opacity:.72 }
  88%  { opacity:.5 }
  100% { transform:translate3d(-2vw,116vh,0) rotate(380deg); opacity:0 }
}
@media (max-width:1023px){ .petal:nth-child(n+6){ display:none } }
@media (prefers-reduced-motion:reduce){ .petals{ display:none } }

.sheet{ overflow:clip }
.sheet__head{ align-items:end; margin-bottom:calc(var(--cell-v) * 1.15) }
.sheet__intro{ grid-column:1 / 6 }
.sheet__note{ margin-top:1.6rem; max-width:34ch }
.sheet__index{ grid-column:7 / -1; position:relative }
.sheet__index ul{ display:grid; grid-template-columns:1fr 1fr; column-gap:var(--gap) }
.sheet__index button{ display:flex; align-items:baseline; gap:.9rem; width:100%;
  padding:.62rem 0 .62rem 1rem; border:0; border-top:.75px solid var(--line);
  background:none; color:inherit; text-align:left; cursor:pointer; position:relative;
  transition:color .3s var(--e-soft), padding-left .35s var(--e-out) }
/* the mark belongs to the name, not to the row: two columns share a row and a
   rail down the side cannot say which of the two you are pointing at */
.sheet__index button::before{ content:''; position:absolute; left:0; top:.35rem; bottom:.35rem;
  width:2.5px; background:var(--pink); transform:scaleY(0); transform-origin:50% 0;
  transition:transform .32s var(--e-out) }
.sheet__index button:hover,.sheet__index button:focus-visible{ color:var(--pink); padding-left:1.5rem }
.sheet__index button:hover::before,.sheet__index button:focus-visible::before,
.sheet__index button[aria-current="true"]::before{ transform:scaleY(1) }
.sheet__index .idx{ opacity:.5 }

.sheet__body{ align-items:start;
  transform:translate3d(calc(var(--smx,0) * -8px), calc(var(--smy,0) * -6px), 0) }
.sheet__track{ display:grid; gap:calc(var(--cell-v) * 1.05);
  margin-top:calc(var(--off) * var(--cell-v) * .9);
  transform:translate3d(0, calc(var(--ty,0) * 1px), 0) }
.sheet__track:nth-of-type(1){ grid-column:1 / 4 }
.sheet__track:nth-of-type(2){ grid-column:4 / 8 }
.sheet__track:nth-of-type(3){ grid-column:8 / -1 }
.sheet__btn{ display:block; width:100%; padding:0; border:0; background:none; cursor:pointer }
.sheet__fig .frame{ display:block; overflow:hidden; background:var(--line) }
.sheet__fig .frame img{ width:100%; height:auto; display:block }
.sheet__rule{ display:block; height:.75px; background:var(--line); margin-top:1.1rem }
.sheet__fig figcaption{ display:block; margin-top:.85rem }
.sheet__cap{ display:flex; align-items:baseline; gap:.9rem }
/* the speed is spent on the number, which is three characters and cannot rewrap;
   on the name it changed the line count and moved the photograph below it */
.sheet__cap .idx{ opacity:.5;
  letter-spacing:calc(.14em + var(--svs,0) * .06em) }
.sheet__desc{ display:block; margin-top:.5rem; max-width:26ch }
.sheet__fig{ transition:opacity .32s var(--e-soft) }
.sheet.is-hovering .sheet__fig:not(.is-hot){ opacity:.5 }

/* revealed by the figure, clipped on the frame: an element clipped to nothing
   never triggers the observer that is supposed to reveal it */
.js .sheet__fig .frame{ clip-path:inset(0 0 100% 0);
  transition:clip-path .82s var(--e-out) calc(var(--i,0) * 90ms) }
.js .sheet__fig .frame img{ transform:translateY(6%) scale(1.03);
  transition:transform 1.05s var(--e-out) calc(var(--i,0) * 90ms) }
/* the sleeve owns the box now; the picture just fills it */
.sheet__fig .frame .psl > img,.parfig .frame .psl > img{
  width:100%; height:100%; object-fit:cover }
.js .sheet__fig.is-in .frame{ clip-path:inset(0 0 0 0) }
.js .sheet__fig.is-in .frame img{ transform:none }
/* the piece is placed first, and only then is it labelled */
.js .sheet__rule{ transform:scaleX(0); transform-origin:0 50%;
  transition:transform .5s var(--e-out) calc(var(--i,0) * 90ms + 300ms) }
.js .sheet__fig.is-in .sheet__rule{ transform:none }
.js .sheet__fig figcaption{ opacity:0; transform:translateY(10px);
  transition:opacity .5s var(--e-soft) calc(var(--i,0) * 90ms + 340ms),
             transform .5s var(--e-out) calc(var(--i,0) * 90ms + 340ms) }
.js .sheet__fig.is-in figcaption{ opacity:1; transform:none }
.sheet__btn:focus-visible .frame{ outline:2px solid var(--pink); outline-offset:3px }
.sheet__fig.is-flash .sheet__rule{ background:var(--pink); height:2.5px }
.sheet__fig.is-flash .sheet__cap .idx{ opacity:1; color:var(--pink) }
.sheet__track{ transition:transform .22s var(--e-soft) }

@media (max-width:1023px){
  .sheet__intro{ grid-column:1 / -1 }
  .sheet__index{ display:none }
  .sheet__track{ grid-column:1 / -1 !important; margin-top:0;
    gap:calc(var(--cell-v) * .8); transform:none }
  .sheet__body{ row-gap:calc(var(--cell-v) * .8); transform:none }
  .sheet__fig:nth-child(2){ margin-left:18%; }
  .sheet__desc{ max-width:32ch }
}
@media (prefers-reduced-motion:reduce){
  .sheet__track,.sheet__body{ transform:none; transition:none }
  .sheet{ --svs:0 !important }
}

.vsplit{ position:relative; overflow:clip; min-height:96svh; display:grid; align-items:center;
  padding-block:calc(var(--cell-v) * 1.5) calc(var(--cell-v) * 1.35) }
/* The mask has to be finished before the type starts, or the words sit on the
   footage and neither one wins. Media ends at 52% of the frame, the mask is out
   by 80% of that, and the text column begins at 50%. */
/* no rule down the middle: the fade is the division, and a hairline next to it
   just draws the edge back in */
.vsplit__media{ position:absolute; inset:0 auto 0 0; width:min(52%, 860px); z-index:0;
  overflow:hidden;
  -webkit-mask-image:linear-gradient(to right, #000 0 46%, rgb(0 0 0/.42) 66%, transparent 88%),
                     linear-gradient(to bottom, transparent, #000 9%, #000 88%, transparent);
          mask-image:linear-gradient(to right, #000 0 46%, rgb(0 0 0/.42) 66%, transparent 88%),
                     linear-gradient(to bottom, transparent, #000 9%, #000 88%, transparent);
  -webkit-mask-composite:source-in; mask-composite:intersect }
@supports not (mask-composite:intersect){
  .vsplit__media{ -webkit-mask-image:linear-gradient(to right, #000 0 46%, rgb(0 0 0/.42) 66%, transparent 88%);
                          mask-image:linear-gradient(to right, #000 0 46%, rgb(0 0 0/.42) 66%, transparent 88%) } }
.vsplit__vid{ position:absolute; inset:-6%; width:112%; height:112%;
  object-fit:cover; object-position:52% 42%;
  transform:translate3d(0, calc(var(--vp,0) * -3.2%), 0) scale(calc(1.06 - var(--vin,0) * .06));
  filter:saturate(.92) contrast(1.02) }
.vsplit__wash{ position:absolute; inset:0;
  background:linear-gradient(to right,
    color-mix(in srgb, var(--plum) 30%, transparent),
    color-mix(in srgb, var(--plum) 8%, transparent) 52%, transparent 78%),
    linear-gradient(to top, color-mix(in srgb, var(--bone) 62%, transparent), transparent 46%),
    linear-gradient(to bottom, color-mix(in srgb, var(--bone) 50%, transparent), transparent 34%) }
.vsplit__tag{ position:absolute; left:var(--offset); bottom:calc(var(--cell-v) * 1.5); z-index:3;
  /* plum on the washed footage: bone on a light frame of the clip was a label
     nobody could read */
  color:var(--plum); display:flex; align-items:center; gap:.7rem;
  background:color-mix(in srgb, var(--bone) 82%, transparent);
  padding:.5rem .9rem; backdrop-filter:blur(6px);
  transform:translate3d(0, calc(var(--vp,0) * -22px), 0) }
.vsplit__tag i{ width:22px; height:.75px; background:currentColor; display:block;
  transform-origin:0 50%; transform:scaleX(calc(var(--vin,0)))}
.vsplit__grid{ position:relative; z-index:2 }
.vsplit__body{ grid-column:6 / -1; padding-left:var(--gap) }
.vsplit__marks{ margin-top:calc(var(--cell-v) * .8);
  display:grid; gap:calc(var(--cell-v) * .42) }
.vsplit__body .stmt__lab{ margin-bottom:1.4rem }
.vsplit__body .chips{ margin-top:calc(var(--cell-v) * .6) }
@media (max-width:1023px){
  .vsplit__media{ inset:0 0 auto 0; width:100%; height:58svh;
    -webkit-mask-image:linear-gradient(to bottom, #000 0 46%, transparent 96%);
            mask-image:linear-gradient(to bottom, #000 0 46%, transparent 96%) }
  .vsplit{ padding-top:calc(58svh - var(--cell-v) * .4) }
  .vsplit__rule{ display:none }
  .vsplit__body{ grid-column:1 / -1 }
  .vsplit__tag{ bottom:auto; top:calc(58svh - var(--cell-v) * 1.1) }
}
@media (prefers-reduced-motion:reduce){
  .vsplit__vid{ transform:none }
  .vsplit__tag{ transform:none }
}

/* the fill fades on BOTH lists: a sweet that has already crossed to the front
   one would otherwise be on screen at full strength before the box exists */
.sweets{ position:absolute; inset:0; margin:0; padding:0; list-style:none;
  pointer-events:none; transform-style:preserve-3d; opacity:var(--aFill,1);
  transform:translate3d(0, calc((1 - var(--aFill,1)) * -14%), 0) }
.sweet{ position:absolute; left:50.95%; top:66.94%;
  --w:calc(var(--sz,40px) * var(--sscale,1));
  width:var(--w); height:calc(var(--w) * var(--ar,1));
  margin:calc(var(--w) * var(--ar,1) / -2) 0 0 calc(var(--w) / -2);
  background-image:var(--img); background-size:contain;
  background-repeat:no-repeat; background-position:center;
  filter:drop-shadow(0 calc(var(--w) * .10) calc(var(--w) * .16) rgb(52 12 36 / .22))
         blur(calc(var(--mb,0) * 1px));
  transform:translate3d(calc(var(--x,0) * 1px), calc(var(--y,0) * 1px), calc(var(--z,0) * 1px))
            rotateZ(calc(var(--rz,0) * 1deg)) }

.sweet.d01{ --img:url('../img/doces2/d01.webp'); --ar:0.9848; --sz:64.2px }
.sweet.d02{ --img:url('../img/doces2/d02.webp'); --ar:0.9574; --sz:55.1px }
.sweet.d03{ --img:url('../img/doces2/d03.webp'); --ar:1.0248; --sz:47.3px }
.sweet.d04{ --img:url('../img/doces2/d04.webp'); --ar:0.9521; --sz:36.7px }
.sweet.d05{ --img:url('../img/doces2/d05.webp'); --ar:0.9260; --sz:66.0px }
.sweet.d06{ --img:url('../img/doces2/d06.webp'); --ar:0.9679; --sz:54.7px }
.sweet.d07{ --img:url('../img/doces2/d07.webp'); --ar:0.9372; --sz:40.4px }
.sweet.d08{ --img:url('../img/doces2/d08.webp'); --ar:1.1222; --sz:35.1px }
.sweet.d09{ --img:url('../img/doces2/d09.webp'); --ar:0.9048; --sz:65.6px }
.sweet.d10{ --img:url('../img/doces2/d10.webp'); --ar:1.0783; --sz:44.9px }
.sweet.d11{ --img:url('../img/doces2/d11.webp'); --ar:1.0053; --sz:37.1px }
.sweet.d12{ --img:url('../img/doces2/d12.webp'); --ar:1.0041; --sz:47.8px }
.sweet.d13{ --img:url('../img/doces2/d13.webp'); --ar:0.9738; --sz:52.1px }
.sweet.d14{ --img:url('../img/doces2/d14.webp'); --ar:1.0167; --sz:46.7px }
.sweet.d15{ --img:url('../img/doces2/d15.webp'); --ar:1.0112; --sz:34.8px }
.sweet.d16{ --img:url('../img/doces2/d16.webp'); --ar:0.9962; --sz:50.8px }

@media (max-width:1023px){
  .scene__panel{ width:min(80vw, 360px, 50svh) }
  .curtain{ height:180svh }
}
@media (prefers-reduced-motion:reduce){
  /* nothing animates, so the honest still is the shut box, not an open empty one */
  .curtain{ height:auto }
  .sweet{ opacity:.9 }
  .scene__panel{ transform:none }
}

/* ══════════════════════════════════════════════════════════════
   STATEMENT / MANIFESTO
   ══════════════════════════════════════════════════════════════ */
.stmt__lab{ grid-column:1 / 3; grid-row:1; align-self:start }
@media (max-width:1023px){
  .stmt__lab{ grid-column:1 / 5; grid-row:1; margin-bottom:2rem }
}

/* ══════════════════════════════════════════════════════════════
   ARCH FEATURE
   ══════════════════════════════════════════════════════════════ */
.archsec{ margin-top:calc(var(--cell-v) * -1.1) }
.archfeat{ grid-column:3 / 9 }
.archfeat .arch-img{ width:100% }
.archfeat__cap{ grid-column:3 / 9; display:flex; justify-content:space-between;
  gap:1.5rem; margin-top:1.2rem; flex-wrap:wrap }
.archsec__t{ grid-column:1 / 11; text-align:center; margin-bottom:calc(var(--cell-v) * .9) }
.archsec__t .a2{ display:block }
@media (max-width:1023px){
  .archfeat,.archfeat__cap,.archsec__t{ grid-column:1 / 5 }
}

/* ══════════════════════════════════════════════════════════════
   SPEC LIST (services)
   ══════════════════════════════════════════════════════════════ */
@media (max-width:1023px){
}

/* ══════════════════════════════════════════════════════════════
   PICTURES
   One treatment for every photograph: a plain rectangle. The arch
   stays, but only where it is the signature. Variety comes from
   the composition, not from cutting shapes into the pictures.
   ══════════════════════════════════════════════════════════════ */
.sh{ position:relative; overflow:clip; border-radius:2px }

/* ══════════════════════════════════════════════════════════════
   THE STUDIO DUO
   Two pictures in two shapes, drifting at different speeds, with a
   blush disc behind them. One picture centred in an arch was the
   flattest moment on the page.
   ══════════════════════════════════════════════════════════════ */
.js .duo__a > img,.js .duo__b > img{ will-change:transform }
@media (max-width:1023px){
}

/* ══════════════════════════════════════════════════════════════
   MARKS
   The three promises. Numbers set in the Didone, a rule that draws
   itself, and the whole thing on a row instead of stacked in a gap.
   ══════════════════════════════════════════════════════════════ */
.mark{ position:relative; padding-top:1.5rem }
.mark__rule{ position:absolute; left:0; top:0; width:100%; height:.75px;
  background:var(--fg-30); transform-origin:0 50% }
.mark__n{ display:block; font-family:'Gilda Display',Georgia,serif;
  font-size:var(--h5); line-height:.82; color:var(--mark); opacity:.85;
  margin-bottom:.7rem; font-feature-settings:'lnum' 1 }
.mark h3{ margin-bottom:.45rem }
.chips{ display:flex; flex-wrap:wrap; gap:.5rem; margin-top:.6rem }
.chip{ display:inline-flex; align-items:center; gap:.55rem;
  padding:.62rem 1.05rem; border:.75px solid var(--line); border-radius:999rem;
  font-size:var(--l1); letter-spacing:.048em; text-transform:uppercase;
  font-weight:700; line-height:1; transition:border-color .5s var(--e-out),
  background-color .5s var(--e-out) }
.chip::before{ content:''; width:.38rem; height:.38rem; border-radius:50%;
  background:var(--mark); flex:none }
.chip:hover{ border-color:var(--mark); background:color-mix(in srgb, var(--mark) 8%, transparent) }

/* ══════════════════════════════════════════════════════════════
   SERVICES: the picture follows the cursor
   ══════════════════════════════════════════════════════════════ */
@media (hover:none),(max-width:1023px){ .specfloat{ display:none } }

/* ══════════════════════════════════════════════════════════════
   WORK RAIL
   ══════════════════════════════════════════════════════════════ */
.rail__open{ display:block; width:100%; padding:0; border:0; background:none;
  color:inherit; font:inherit; cursor:inherit; -webkit-appearance:none; appearance:none }
/* the rail varies by proportion and by how each slide sits on the
   baseline, not by cutting a different window into every picture */
@media (max-width:1023px){ .rail__item:nth-child(even){ margin-top:1.4rem } }
@media (max-width:1023px){
}

/* ── botanical sprigs: the vector flourish era animates with Lottie ── */
@media (max-width:1023px){ .sprig{ width:clamp(110px,32vw,190px); opacity:.34 } }

/* ── scroll progress ──────────────────────────────────────────
   A percentage counter is what a property developer puts in the margin. This
   studio ties ribbon, so the margin gets ribbon: a hairline that fills as you
   go, a knot that rides the leading edge, and the name of the room you are
   in. The bar stays for phones, where the margin belongs to the thumb.
   ──────────────────────────────────────────────────────────── */
.prog{ position:fixed; top:0; left:0; right:0; height:2px; z-index:140;
  background:var(--mark); transform:scaleX(var(--sp,0)); transform-origin:0 50%;
  opacity:.85; pointer-events:none }

.thread{ display:none }
@media (min-width:1024px){
  .prog{ display:none }
  .thread{ display:block; position:fixed; z-index:118; right:calc(var(--offset) * .46);
    top:26vh; bottom:14vh; width:1px; pointer-events:none;
    color:var(--fg,var(--plum));
    opacity:var(--thop,0); transition:opacity .7s var(--e-soft) }
  .thread__line{ position:absolute; inset:0; background:currentColor; opacity:.17 }
  .thread__line > i{ position:absolute; inset:0; display:block; background:var(--mark);
    transform:scaleY(var(--sp,0)); transform-origin:50% 0 }
  /* Percentage top resolves against the thread's own height, so the knot rides
     the line with no measuring and no second source of truth. */
  .thread__knot{ position:absolute; left:50%; top:calc(var(--sp,0) * 100%);
    width:13px; height:13px; margin:-6.5px 0 0 -6.5px; color:var(--mark) }
  .thread__knot svg{ width:100%; height:100%; fill:none; stroke:currentColor;
    stroke-width:1.35; stroke-linecap:round; stroke-linejoin:round;
    /* it turns as it travels, the way a knot does when the ribbon is pulled */
    rotate:calc(var(--sp,0) * 190deg) }
  /* Set across, the word needs its own column and takes it out of the text.
     Set down the margin, like a spine, it is eleven pixels wide and fits in the
     gutter the grid already leaves — so it can stay at every desktop width. */
  .thread__lab{ position:absolute; right:15px; top:calc(var(--sp,0) * 100%);
    display:block; white-space:nowrap; writing-mode:vertical-rl;
    translate:0 -50% }
  .thread__lab b{ display:block; font-size:calc(var(--l1) * .92); font-weight:700;
    letter-spacing:.16em; text-transform:uppercase;
    opacity:var(--tlop,0); translate:calc((1 - var(--tlop,0)) * -5px) 0;
    transition:opacity .5s var(--e-soft), translate .5s var(--e-out) }
}


/* companion cursor */
@media (hover:hover) and (pointer:fine){ .rail__scroller.has-cursor{ cursor:none } }
@media (hover:none),(pointer:coarse){ .cursor{ display:none } }
.touched .cursor{ display:none }

/* ══════════════════════════════════════════════════════════════
   ATELIER: pinned, split, crossfading
   ══════════════════════════════════════════════════════════════ */
@media (max-width:1023px){
}

/* ── THE ABOUT PAGE ───────────────────────────────────────────
   Nancy stands across this seam too, and for the same reason. The section
   above her is plum so that there is something for her to rise into, and her
   bone rim is what makes a black-haired woman in a plum blazer readable
   against a plum wall.
   ────────────────────────────────────────────────────────────── */
.about{ align-items:center; row-gap:var(--cell-v) }
/* Her overhang has to be a fixed number, not whatever falls out of the layout.
   She scales with the viewport width while the text beside her stops growing at
   the rem clamp, so on a wide screen she was rising three times higher than on
   a narrow one and landing on the heading above. Anchored to the section rather
   than to the grid, `max-height: 100% + N` caps the overhang at exactly N, and
   the section above reserves more than N at its foot. */
.abpage{ overflow:visible; z-index:7; padding-bottom:0; position:relative }
.about__fig{ position:absolute; left:var(--offset); bottom:0; z-index:3; margin:0;
  /* Height first, width follows. Her height is the section plus a fixed
     overhang, so she rises by the same amount on every screen and the section
     above can reserve for it once. Sizing her by width instead let her grow
     with the viewport while the text stopped at the rem clamp, and on a wide
     screen she climbed onto the heading. */
  height:calc(100% + 130px);
  max-width:calc((100% - 2 * var(--offset) - 9 * var(--gap)) / 10 * 5 + 4 * var(--gap)) }
.about__fig img{ display:block; height:100%; width:auto; max-width:100%;
  object-fit:contain; object-position:left bottom }
.about__body{ grid-column:6 / 11; grid-row:1; padding-block:calc(var(--cell-v) * .4) }
.about__body .h3{ margin:1.2rem 0 0 }
.about__body .a2{ display:block; margin-bottom:1.6rem }
.about__body p + p{ margin-top:1.1rem }
/* Nancy rises out of the section below into this one, and she comes up on the
   left. The line has to live on the right or it reads from behind her head. */
.abhero__sub{ grid-column:6 / 11; margin-top:1.8rem; color:var(--fg-60) }
.about__body > .l1:first-child{ color:var(--mark) }

/* ── HER LINE ─────────────────────────────────────────────────
   The best sentence on her whole site was buried in a paragraph. Given a
   plum field to itself and set at display size, it does what a mission
   statement is supposed to do and almost never does. */
.abquote{ padding-block:calc(var(--cell-v) * 2.2) }
.abquote__q{ grid-column:2 / 10; text-align:center; margin:0;
  font-family:'Gilda Display',Georgia,serif; font-stretch:normal;
  font-size:var(--h4); line-height:1.16; letter-spacing:-.012em; text-wrap:balance }
.abquote__by{ grid-column:1 / -1; text-align:center; margin-top:2.2rem; color:var(--mark) }

/* ── THE STORY ────────────────────────────────────────────────*/
.abstory{ row-gap:calc(var(--cell-v) * .5) }
.abstory__lab{ grid-column:1 / -1; margin-bottom:1.4rem; color:var(--mark) }
.abstory__col{ grid-column:span 5 }
.abstory__col:first-of-type{ grid-column:1 / 6 }
.abstory__col:last-of-type{ grid-column:6 / 11; padding-top:.35rem }
.abstory__col p + p{ margin-top:1.2rem }

.abfactsec{ margin-top:calc(var(--cell-v) * -.2) }
.abfacts__lab{ grid-column:1 / -1; margin-bottom:calc(var(--cell-v) * .7); color:var(--pink-deep) }
.wrap-none{ grid-column:1 / -1; padding-inline:0 }
.abfacts--4 .mark{ grid-column:span 2 !important }
.abfacts--4 .mark:nth-child(1){ grid-column:1 / 4 !important }
.abfacts--4 .mark:nth-child(2){ grid-column:4 / 6 !important }
.abfacts--4 .mark:nth-child(3){ grid-column:6 / 9 !important }
.abfacts--4 .mark:nth-child(4){ grid-column:9 / -1 !important }

.abclose{ text-align:center }
.abclose__lab{ grid-column:1 / -1; margin-bottom:1.2rem; color:var(--mark) }
.abclose__h{ grid-column:2 / 10 }
.abclose__p{ grid-column:3 / 9; margin-top:1.6rem; color:var(--fg-60) }
.abclose__cta{ grid-column:1 / -1; margin-top:2.4rem }
@media (max-width:1023px){
  /* Back in the flow on a phone, so every desktop rule that sized her has to
     be undone by name: a percentage height against an auto-height parent
     resolves to auto, and she came out small and floating. Here she is simply
     a wide picture standing on the section's bottom edge, under the words. */
  .about{ row-gap:calc(var(--cell-v) * .2) }
  .about__fig{ position:relative; left:auto; bottom:auto; grid-column:1 / -1;
    grid-row:2; width:100%; height:auto; max-width:none; margin-top:0 }
  .about__fig img{ width:112%; max-width:112%; height:auto;
    margin:0 -6% -1px; object-fit:fill }
  .about__body{ grid-column:1 / -1; grid-row:1; padding-block:calc(var(--cell-v) * .3) 0 }
  .abhero__sub{ grid-column:1 / -1; margin-top:1.2rem }
  .abquote__q{ grid-column:1 / -1; font-size:var(--h5) }
  .abstory__col,.abstory__col:first-of-type,.abstory__col:last-of-type{ grid-column:1 / -1 }
  .abfacts--4 .mark,.abfacts--4 .mark:nth-child(1),.abfacts--4 .mark:nth-child(2),
  .abfacts--4 .mark:nth-child(3),.abfacts--4 .mark:nth-child(4){ grid-column:1 / -1 !important }
  .abclose__p{ grid-column:1 / -1 }
  .abclose__h{ grid-column:1 / -1 }
}

/* ══════════════════════════════════════════════════════════════
   QUOTE
   ══════════════════════════════════════════════════════════════ */
.quote{ position:relative; overflow:clip; min-height:88svh; display:grid;
  align-items:center; color:var(--bone) }
.quote__bg{ position:absolute; inset:0; z-index:0 }
.quote__bg img{ width:100%; height:100%; object-fit:cover }
.quote__in{ position:relative; z-index:3; text-align:center; grid-column:2 / 10 }
.quote__stack{ position:relative; min-height:9em }
.quote__dots{ display:flex; gap:.6rem; justify-content:center; margin-top:2rem }
.quote__dots button{ width:44px; height:.75px; background:color-mix(in srgb,#fff 40%,transparent);
  border:0; padding:0; cursor:pointer; transition:background-color .4s var(--e-soft) }
.quote__dots button[aria-selected="true"]{ background:var(--blush) }
@media (max-width:1023px){ .quote__in{ grid-column:1 / 5 } .quote__stack{ min-height:13em } }

/* ══════════════════════════════════════════════════════════════
   REVIEWS
   ══════════════════════════════════════════════════════════════ */
.rev{ display:grid; gap:var(--gap) }
@media (max-width:1023px){
}
@media (prefers-reduced-motion:reduce){
}

/* ══════════════════════════════════════════════════════════════
   MARQUEE
   ══════════════════════════════════════════════════════════════ */
.marq{ overflow:clip; padding-block:calc(var(--cell-v) * .34);
  border-block:.75px solid var(--line) }
.marq__track{ display:flex; width:max-content; animation:marq var(--dur,44s) linear infinite }
.marq__track > span{ display:flex; align-items:center; gap:2.6rem; padding-right:2.6rem;
  white-space:nowrap; font-family:'Gilda Display',Georgia,serif; font-stretch:normal;
  font-size:var(--h5); text-transform:uppercase; letter-spacing:-.01em }
.marq__track > span::after{ content:''; width:6px; height:6px; border-radius:50%;
  background:var(--mark); flex:none }
@keyframes marq{ to{ transform:translateX(-50%) } }

/* ══════════════════════════════════════════════════════════════
   CONTACT
   ══════════════════════════════════════════════════════════════ */
.ct__head{ grid-column:1 / 6 }
.ct__head .h2{ margin:1.4rem 0 1.6rem }
.ct__list{ grid-column:1 / 6; margin-top:calc(var(--cell-v) * .7) }
.ct__list div{ display:flex; justify-content:space-between; gap:1.5rem; flex-wrap:wrap;
  padding-block:1rem; border-top:.75px solid var(--line) }
.ct__list div:last-child{ border-bottom:.75px solid var(--line) }
.form{ grid-column:7 / 11 }
.field{ position:relative; margin-bottom:1.1rem }
.field input,.field textarea,.field select{
  width:100%; background:none; border:0; border-bottom:.75px solid var(--line);
  padding:.9rem 0 .65rem; font-size:var(--body); border-radius:0;
  -webkit-appearance:none; appearance:none;
  transition:border-color .4s var(--e-soft) }
.field textarea{ resize:vertical; min-height:5.5em }
.field select option{ background:#340C24; color:#F4F1EA }
.field label{ position:absolute; left:0; top:.9rem; pointer-events:none;
  color:var(--fg-60); font-size:var(--body); transform-origin:0 0;
  transition:transform .35s var(--e-out), letter-spacing .35s var(--e-out),
             color .35s var(--e-out), font-size .35s var(--e-out) }
/* The rule under a field should be drawn, not recoloured. It arrives from the
   left on focus and retreats the same way, so tabbing through the form reads
   as a single line travelling down it. */
.field::after{ content:''; position:absolute; left:0; right:0; height:1.25px;
  bottom:0; background:var(--mark); transform:scaleX(0); transform-origin:0 50%;
  transition:transform .5s var(--e-out); pointer-events:none }
.field:has(textarea)::after{ display:none }
.field:focus-within::after{ transform:scaleX(1) }
.field input:focus,.field textarea:focus,.field select:focus{ outline:0;
  border-bottom-color:var(--mark) }
.field input:focus+label,.field textarea:focus+label,.field select:focus+label,
.field input:not(:placeholder-shown)+label,.field textarea:not(:placeholder-shown)+label,
.field select.has-value+label{
  transform:translateY(-1.35rem); font-size:var(--l1); letter-spacing:.048em;
  font-weight:700; color:var(--champagne) }
.field .err{ display:block; margin-top:.4rem; font-size:var(--l1); font-weight:700;
  letter-spacing:.048em; color:var(--blush); opacity:0; transform:translateY(-3px);
  transition:opacity .22s var(--e-out), transform .3s var(--e-out) }
.field.is-bad .err{ opacity:1; transform:none }
.field.is-bad input,.field.is-bad textarea,.field.is-bad select{ border-bottom-color:var(--blush) }

.drop{ position:relative; margin:.4rem 0 1.4rem; padding:1.3rem 1.4rem;
  border:.75px dashed var(--line-strong, var(--line)); border-radius:2px;
  transition:border-color .3s var(--e-soft), background-color .3s var(--e-soft) }
.drop.is-over{ border-color:var(--mark); background:color-mix(in srgb, var(--mark) 7%, transparent) }
.drop input[type=file]{ position:absolute; inset:0; width:100%; height:100%; opacity:0; cursor:pointer }
.drop label{ display:grid; gap:.35rem; pointer-events:none }
.drop__list{ margin-top:.9rem; display:grid; gap:.4rem }
.drop__list li{ display:flex; justify-content:space-between; gap:1rem;
  font-size:var(--l1); font-weight:700; letter-spacing:.048em; text-transform:uppercase;
  color:var(--fg-60) }
.drop__list li b{ color:var(--fg); font-weight:700 }
.form__note{ margin-top:1.4rem }
.form__done{ display:none }
.form.is-done .form__grid,.form.is-done .form__note{ display:none }
.form.is-done .form__done{ display:block }
@media (max-width:1023px){
  .ct__head,.ct__list,.form{ grid-column:1 / 5 }
  .form{ margin-top:calc(var(--cell-v) * .8) }
}

/* ══════════════════════════════════════════════════════════════
   FOOTER
   ══════════════════════════════════════════════════════════════ */
/* The footer used to close on a flat picture of the logo from the old site,
   which is the one place a mark should never be a picture: it is the last
   thing on the page and the one the eye rests on. It is the same type the
   nav is set in now, so it takes the theme, stays crisp at any size, and the
   ribbon breathes here as it does up there. */
.lg--foot{ font-size:calc(var(--l1) * 2.1); display:block }
@media (max-width:1023px){ .lg--foot{ font-size:calc(var(--l1) * 1.8) } }
.foot__top{ grid-column:1 / 11; display:flex; align-items:flex-start;
  justify-content:space-between; gap:2rem; flex-wrap:wrap;
  padding-bottom:calc(var(--cell-v) * .8) }
.foot__cols{ grid-column:1 / 11; display:grid; grid-template-columns:repeat(3,1fr);
  gap:2rem var(--gap); padding-top:calc(var(--cell-v) * .5);
  border-top:.75px solid var(--line) }
.foot__cols h4{ margin-bottom:1.1rem; color:var(--fg-60) }
.foot__cols li{ margin-bottom:.55rem }
/* The wordmark at the foot is the last thing on the page, so it is the last
   thing to arrive: it comes up out of its own line and settles, and it settles
   slowly, because nothing is chasing it. */
.foot__mega{ grid-column:1 / 11; margin-top:calc(var(--cell-v) * .8);
  font-family:'Gilda Display',Georgia,serif; font-stretch:normal;
  font-size:clamp(3rem,13vw,13rem); line-height:.8; letter-spacing:-.03em;
  text-transform:uppercase; text-align:center; color:var(--fg);
  opacity:.14; user-select:none; white-space:nowrap; overflow:clip;
  padding-bottom:.04em }
.js .foot__mega{ opacity:0 }
.js .foot__mega > i{ display:block; font-style:normal;
  transform:translate3d(0,108%,0);
  transition:transform var(--d-xl) var(--e-out) }
.js .foot__mega.is-in{ opacity:.14;
  transition:opacity var(--d-l) var(--e-soft) }
.js .foot__mega.is-in > i{ transform:none }

/* ── LINKS THAT ANSWER ────────────────────────────────────────
   A rule that wipes out under the cursor and comes back from the other side,
   so the word is never underlined twice and the movement always has a
   direction. Era does this on every text link and it is the cheapest way to
   make a list of addresses feel like it was set rather than typed.
   ──────────────────────────────────────────────────────────── */
.lnk{ position:relative; display:inline-block }
.lnk::after{ content:''; position:absolute; left:0; right:0; bottom:-.18em;
  height:.75px; background:currentColor; opacity:.42;
  transform:scaleX(1); transform-origin:100% 50%;
  transition:transform var(--d-m) var(--e-io) }
.lnk:hover::after,.lnk:focus-visible::after{
  transform-origin:0 50%;
  animation:lnkWipe var(--d-m) var(--e-io) }
@keyframes lnkWipe{ 0%{ transform:scaleX(1); transform-origin:100% 50% }
  49.9%{ transform:scaleX(0); transform-origin:100% 50% }
  50%{ transform:scaleX(0); transform-origin:0 50% }
  100%{ transform:scaleX(1); transform-origin:0 50% } }
@media (prefers-reduced-motion:reduce){ .lnk::after{ animation:none !important } }
.foot__legal{ grid-column:1 / 11; display:flex; justify-content:space-between;
  gap:1.5rem; flex-wrap:wrap; margin-top:calc(var(--cell-v) * .6);
  padding-top:1.1rem; border-top:.75px solid var(--line) }
@media (max-width:1023px){
  .foot__top,.foot__cols,.foot__mega,.foot__legal{ grid-column:1 / 5 }
  .foot__cols{ grid-template-columns:1fr }
}

/* ══════════════════════════════════════════════════════════════
   LIGHTBOX
   ══════════════════════════════════════════════════════════════ */
.lb{ border:0; padding:0; background:transparent; overflow:visible;
  max-inline-size:min(92vw,1180px); max-block-size:92vh; opacity:0; scale:.96;
  transition:opacity .4s var(--e-out), scale .5s var(--e-out),
             display .4s allow-discrete, overlay .4s allow-discrete }
.lb[open]{ opacity:1; scale:1 }
@starting-style{ .lb[open]{ opacity:0; scale:.96 } }
.lb::backdrop{ background:rgb(52 12 36/.86);
  -webkit-backdrop-filter:blur(14px); backdrop-filter:blur(14px);
  opacity:0; transition:opacity .45s var(--e-out) }
.lb[open]::backdrop{ opacity:1 }
@starting-style{ .lb[open]::backdrop{ opacity:0 } }
.lb img{ width:100%; height:auto; max-block-size:80vh; object-fit:contain;
  border-top-left-radius:22rem; border-top-right-radius:22rem }
.lb__bar{ display:flex; justify-content:space-between; align-items:center; gap:2rem;
  margin-top:1rem; color:var(--bone); font-size:var(--l1); font-weight:700;
  letter-spacing:.048em; text-transform:uppercase }
.lb__bar button{ background:none; border:0; color:inherit; cursor:pointer;
  padding:.5rem .7rem; opacity:.7; transition:opacity .35s var(--e-soft) }
.lb__bar button:hover{ opacity:1 }
html:has(dialog[open]){ overflow:hidden }

/* ══════════════════════════════════════════════════════════════
   REVEALS
   ══════════════════════════════════════════════════════════════ */
.js [data-up]{ opacity:0; transform:translateY(18px);
  transition:opacity .75s var(--e-out) calc(var(--i,0) * 85ms),
             transform .75s var(--e-out) calc(var(--i,0) * 85ms) }
.js [data-up].is-in{ opacity:1; transform:none }
.js [data-mask] > img{ clip-path:inset(100% 0 0 0); transform:scale(1.14);
  transition:clip-path 1.15s var(--e-out) calc(var(--i,0) * 90ms),
             transform 1.35s var(--e-out) calc(var(--i,0) * 90ms) }
.js [data-mask].is-in > img{ clip-path:inset(0 0 0 0); transform:scale(1) }
.js [data-rule]{ transform:scaleX(0); transform-origin:0 50%;
  transition:transform .95s var(--e-out) calc(var(--i,0) * 60ms) }
.js [data-rule].is-in{ transform:scaleX(1) }
/* Two elements, two jobs. The outer line carries the sideways offset and the
   scroll drift, with no transition, because it is written every frame. The
   inner one carries the rise, which is a one-off transition and would fight the
   drift if they shared a transform. */
.ln{ display:block; overflow:hidden; padding-bottom:.055em;
  transform:translate3d(calc(var(--ox,0) * 1em + var(--dx,0) * var(--lead,0) * 1px), 0, 0) }
.ln > i{ display:block; font-style:inherit; transform:translate3d(0,112%,0);
  transition:transform var(--d-l) var(--e-out) calc(var(--i,0) * var(--stag-l)) }
.is-in .ln > i{ transform:none }
@media (max-width:1023px){ .ln{ --ox:0 !important; --lead:0 !important } }

/* ── DISPLAY TYPE SETS ITSELF UPRIGHT ───────────────────────────
   A line mask alone slides; it does not arrive. On the big Didot capitals
   each letter instead starts folded back onto its own baseline, below the
   fold of the line, and stands up as it rises — which is what a place card
   does when it is set on a table. Literal for this business, and it is the
   one gesture on the page that is worth a full second and a quarter.
   The rotation is on glyphs, never on a photograph: type has no texture to
   flatten, a photograph does.
   ────────────────────────────────────────────────────────────── */
.ln--c{ perspective:26em; perspective-origin:50% 96% }
.ln--c > i{ transform:none; transition:none }
.ch{ display:inline-block; white-space:pre; will-change:transform;
  transform-origin:50% 92%; backface-visibility:hidden;
  transform:translate3d(0,112%,0) rotateX(-84deg);
  transition:transform var(--d-l) var(--e-out)
             calc(var(--i,0) * var(--stag-l) + var(--ci,0) * var(--cs,var(--stag))) }
.is-in .ln--c .ch{ transform:none }
/* Once it has landed the layer is worth nothing and costs sharpness, so it
   goes: the glyphs go back to being painted straight into the page. */
.is-in .ln--c{ perspective:none }
.is-in .ln--c .ch{ will-change:auto }

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{ animation-duration:.01ms !important; animation-iteration-count:1 !important;
    transition-duration:.01ms !important; scroll-behavior:auto !important }
  [data-up]{ opacity:1 !important; transform:none !important }
  [data-mask] > img{ clip-path:none !important; transform:none !important }
  [data-rule]{ transform:none !important }
  .foot__mega{ opacity:.14 !important } .foot__mega > i{ transform:none !important }
  .ln > i{ transform:none !important }
  .ch{ transform:none !important }
  .ln{ transform:translate3d(calc(var(--ox,0) * 1em),0,0) }
  /* the hero is a single screen here, so there is no pinned tail to pull the
     next section up over: leave that margin in and the box section is parked
     underneath an opaque hero and never seen at all */
  .curtain{ height:auto; margin-top:0 } .curtain__pin{ position:static; height:70svh }
  .curtain__half{ display:none }
  .marq__track{ animation:none } .circle svg{ animation:none }
  .hero{ height:100svh } .hero__pin{ position:static; height:100svh }
  [data-float] img{ transform:none !important }
}

/* ── ABOUT: its own page now, with a short bridge left on the home page ── */
/* ── NANCY STANDS ACROSS THE JOIN ─────────────────────────────
   She was a small picture parked politely in the first three columns. Now she
   is life-size and her head rises out of this section into the dark one above
   it, which is the same idea as the bow on the other seam: the person who
   makes the work is not contained by the box the work is described in. The
   cut-out has no background of its own, so there is nothing to give the trick
   away — she simply stands there.
   ────────────────────────────────────────────────────────────── */
/* She is taken out of the grid's height so that two things can be true at
   once: her waist sits exactly on the line where the next section starts, and
   her head is above the line where this one starts. If she stayed in the flow
   the section would be as tall as she is and there would be nothing to rise
   into. Nothing is drawn behind her — no shadow, no glow, no disc. It is a
   photograph with a transparent background and that is all it needs to be. */
.abbridge{ align-items:center; row-gap:calc(var(--cell-v) * .6) }
.abbridge__fig{ position:absolute; left:var(--offset); bottom:0; z-index:3; margin:0;
  /* Height first, width follows. Her height is the section plus a fixed
     overhang, so she rises by the same amount on every screen and the section
     above can reserve for it once. Sizing her by width instead let her grow
     with the viewport while the text stopped at the rem clamp, and on a wide
     screen she climbed onto the heading. */
  height:calc(100% + 130px);
  max-width:calc((100% - 2 * var(--offset) - 9 * var(--gap)) / 10 * 5 + 4 * var(--gap)) }
/* A negative margin would shrink the grid row instead of lifting her out of
   it, so the rise is a transform: it moves what you see and leaves the layout
   exactly where it was. */
.abbridge__fig img{ display:block; height:100%; width:auto; max-width:100%;
  object-fit:contain; object-position:left bottom }
.abbridge__body{ grid-column:6 / 11; padding-block:calc(var(--cell-v) * .35) }
.abbridge__body .h3{ margin-top:1.2rem }
.abbridge__script{ display:block; margin:.6rem 0 1.7rem; color:var(--pink) }
/* the section she overflows out of cannot clip her, and it has to sit above
   the one she overflows into, or her head is painted over by it */
/* no padding at the foot, so the section's bottom edge is where she ends */
.sect:has(.abbridge){ overflow:visible; z-index:7; padding-bottom:0; position:relative }
.abhero{ padding-block:calc(var(--cell-v) * 2.1) calc(var(--cell-v) * 2.1) }
.abhero__lab{ grid-column:1 / -1; margin-bottom:1.6rem }
.abhero__h{ grid-column:1 / 9 }
.abpage{ padding-top:calc(var(--cell-v) * .6) }
.abfacts{ row-gap:calc(var(--cell-v) * .6) }
.abfacts .mark{ grid-column:span 3 }
.abfacts .mark:nth-child(2){ grid-column:5 / 8 }
.abfacts .mark:nth-child(3){ grid-column:8 / -1 }
@media (max-width:1023px){
  .abbridge{ row-gap:calc(var(--cell-v) * .2) }
  .abbridge__fig{ position:relative; left:auto; bottom:auto; grid-column:1 / -1;
    grid-row:2; width:100%; height:auto; max-width:none; margin-top:0 }
  .abbridge__fig img{ width:112%; max-width:112%; height:auto;
    margin:0 -6% -1px; object-fit:fill }
  .abbridge__body{ grid-column:1 / -1; grid-row:1; padding-block:calc(var(--cell-v) * .3) 0 }
  .abhero__h{ grid-column:1 / -1 }
  .abfacts .mark,.abfacts .mark:nth-child(2),.abfacts .mark:nth-child(3){ grid-column:1 / -1 }
}

/* you are here */
.navlink[aria-current="page"],.menu a.big[aria-current="page"]{ color:var(--pink) }
.navlink[aria-current="page"]::after{ transform:scaleX(1) }

/* Between a phone and a laptop she should not bleed off both edges: at 768 a
   112% width is 106% of the screen. The bleed is for phones only. */
@media (min-width:600px) and (max-width:1023px){
  .abbridge__fig img,.about__fig img{ width:64%; max-width:64%; margin:0 auto -1px }
}
