/* ---------- THE TYPEFACES, HOSTED HERE ----------
   These used to come from Google, which meant two round trips to two different
   hosts before a word could be drawn in Cormorant: one to fetch the stylesheet
   that names the font files, and another to fetch the files themselves. The
   headline rendered in Georgia in the meantime and then jumped -- that is the
   different font you were seeing.

   Served from this site now, so there is one host, already connected, and the
   two files the hero needs are named in the head and start immediately.

   font-display:swap is kept deliberately. The alternative hides the text until
   the font arrives, and a blank headline is worse than a plain one.

   Cormorant Garamond, Karla and Great Vibes are all under the SIL Open Font
   Licence, which permits this. See fonts/OFL.txt. */
@font-face{font-family:'Cormorant Garamond';font-style:normal;font-weight:300;font-display:swap;src:url('fonts/cormorant-normal-300.woff2') format('woff2')}
@font-face{font-family:'Cormorant Garamond';font-style:normal;font-weight:400;font-display:swap;src:url('fonts/cormorant-normal-400.woff2') format('woff2')}
@font-face{font-family:'Cormorant Garamond';font-style:normal;font-weight:500;font-display:swap;src:url('fonts/cormorant-normal-500.woff2') format('woff2')}
@font-face{font-family:'Cormorant Garamond';font-style:italic;font-weight:300;font-display:swap;src:url('fonts/cormorant-italic-300.woff2') format('woff2')}
@font-face{font-family:'Cormorant Garamond';font-style:italic;font-weight:400;font-display:swap;src:url('fonts/cormorant-italic-400.woff2') format('woff2')}
@font-face{font-family:'Cormorant Garamond';font-style:italic;font-weight:500;font-display:swap;src:url('fonts/cormorant-italic-500.woff2') format('woff2')}
@font-face{font-family:'Karla';font-style:normal;font-weight:400;font-display:swap;src:url('fonts/karla-normal-400.woff2') format('woff2')}
@font-face{font-family:'Karla';font-style:normal;font-weight:500;font-display:swap;src:url('fonts/karla-normal-500.woff2') format('woff2')}
@font-face{font-family:'Karla';font-style:normal;font-weight:600;font-display:swap;src:url('fonts/karla-normal-600.woff2') format('woff2')}
@font-face{font-family:'Great Vibes';font-style:normal;font-weight:400;font-display:swap;src:url('fonts/greatvibes-normal-400.woff2') format('woff2')}

:root{
  --bg:#FBF7F0; --bg-alt:#DEC5A1; --card:#FFFFFF;
  --ink:#2A2521; --muted:#6B5D50; --line:#E6DBC9;
  --spine:#C2A277;          /* timeline rule + markers */
  --accent:#A9835C; --blush:#CE9A97;
  --bg-deep:#CEAF87;        /* the deeper band -- kept clear of --bg-alt */
  --accent-deep:#7E5C38;    /* label colour that survives on it   */
  --display:'Cormorant Garamond',Georgia,serif;
  --body:'Karla',system-ui,sans-serif;
  /* one spacing scale for the whole page -- was clamp(76px,10vw,130px) */
  --sect:clamp(51px,6.7vw,87px);--barh:75px;   /* section top/bottom */
  --gap:34px;                      /* heading -> content  */
}
*{box-sizing:border-box;margin:0;padding:0}
img{max-width:100%;display:block}
body{background:var(--bg);color:var(--ink);font-family:var(--body);font-weight:400;
  -webkit-font-smoothing:antialiased;line-height:1.6}

.wrap{max-width:1240px;margin:0 auto;padding:0 6vw}
.center{text-align:center}

.eyebrow{font-family:var(--body);font-size:20px;font-weight:600;letter-spacing:.4em;
  text-transform:uppercase;color:var(--ink)}
.h2{font-family:var(--display);font-weight:500;font-size:clamp(2.2rem,5.1vw,3.85rem);
  line-height:1.1;letter-spacing:.005em}
.h2 em{font-style:italic;color:var(--accent)}
.sub{color:var(--ink);font-size:16.5px;font-weight:500;max-width:60ch;
  line-height:1.75}

/* The washes are sized as a share of their section, not in pixels. A 1000px
   wash on a laptop lightens the middle and leaves the edges; on a 390px phone
   it is wider than the screen, lightens the whole band toward white, and the
   seam between one section and the next simply disappears. */

/* ornament */
.orn{display:flex;align-items:center;justify-content:center;gap:18px;
  margin:16px 0 24px}
.orn i{display:block;width:52px;height:1px;background:var(--line)}
/* A leaf either side of a small diamond. The bands read as two plain circles
   at this size -- there is not enough room for a 2.3px stroke to say "ring" --
   so the ornament says something it can actually say at 64px across. */
.orn .ornmark{width:64px;height:22px;display:block;overflow:visible}
.orn .ornmark .petal{fill:none;stroke:var(--accent);stroke-width:1.15}
.orn .ornmark .pip{fill:var(--accent)}


/* ---------- TEXTURE ----------
   Two layers, both very quiet on their own.

   1. A warm wash on the page ground, so the cream is never one flat value.
      Large soft pools of the deeper sand and a whisper of blush, fixed, so
      they drift under the content as you scroll.

   2. Paper grain over everything. Individually invisible; collectively it
      stops the page reading as flat screen colour and starts it reading as
      a printed surface. Generated rather than downloaded, so it costs
      nothing to load. */
body{
  background-color:var(--bg);
  background-image:
    radial-gradient(1100px 620px at 12% -5%,  rgba(214,190,158,.78), transparent 60%),
    radial-gradient(900px 520px at 92% 28%,  rgba(206,154,151,.34), transparent 58%),
    radial-gradient(1000px 700px at 45% 105%, rgba(214,190,158,.66), transparent 62%);
  background-attachment:fixed;
  background-repeat:no-repeat}

body::after{
  content:"";position:fixed;inset:0;z-index:45;pointer-events:none;
  opacity:.16;mix-blend-mode:multiply;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23n)' opacity='0.55'/%3E%3C/svg%3E");
  background-size:200px 200px}

/* the grain is a fixed overlay, so keep it off anything meant to sit above
   the page -- the enlarged photograph in particular */
.lb{z-index:90}

@media(prefers-reduced-motion:reduce){body{background-attachment:scroll}}

/* ---------- TOP BAR ---------- */
/* Transparent over the hero so the photographs stay uninterrupted; picks up
   a cream background once you have scrolled past it. */
.topbar{position:fixed;top:0;left:0;right:0;z-index:50;display:flex;
  align-items:center;justify-content:space-between;gap:16px;padding:22px 6vw;
  transition:background .45s ease,padding .45s ease,box-shadow .45s ease;
  pointer-events:none}
.topbar a{pointer-events:auto;font-family:var(--body);font-size:11px;font-weight:600;
  letter-spacing:.26em;text-transform:uppercase;text-decoration:none;color:#fff;
  opacity:.92;text-shadow:0 1px 14px rgba(0,0,0,.45);transition:color .45s ease,
  opacity .25s ease,text-shadow .45s ease;white-space:nowrap}
.topbar a:hover{opacity:1}
.topbar .mark{letter-spacing:.2em;display:flex;align-items:center}
/* Inlined rather than loaded through <img>, because an SVG in an img tag
   renders in isolation and cannot inherit currentColor from the page. */
.logo{width:clamp(126px,13vw,168px);height:auto;display:block;
  color:#fff;                                   /* white over the photographs */
  filter:drop-shadow(0 1px 10px rgba(0,0,0,.4));
  transition:color .45s ease,filter .45s ease}
.topbar.scrolled .logo{color:var(--ink);filter:none}
@media(max-width:520px){.logo{width:112px}}
.topnav{display:flex;gap:clamp(16px,2.4vw,34px);align-items:center}
.topnav a{position:relative;padding-bottom:3px}
/* a hairline that grows under the link you are on, and on hover */
.topnav a::after{content:"";position:absolute;left:0;right:0;bottom:0;height:1px;
  background:currentColor;transform:scaleX(0);transform-origin:left;
  transition:transform .35s cubic-bezier(.2,.7,.3,1)}
.topnav a:hover::after{transform:scaleX(1)}
.topnav a[aria-current="page"]{opacity:1}
.topnav a[aria-current="page"]::after{transform:scaleX(1)}
@media(max-width:520px){.topnav{gap:14px}}

/* ---------- MUSIC ----------
   Lives in the top bar beside the navigation, and follows its colour: white
   over the photographs, ink once the bar turns cream.

   The playing state says "Pause", not the song title. Showing the title told
   you music was on but not how to stop it, which is the one thing you need
   from a control that is already making noise. */
.barright{display:flex;align-items:center;gap:clamp(14px,2vw,26px)}
.music{pointer-events:auto;display:flex;align-items:center;gap:8px;cursor:pointer;
  padding:7px 15px;border-radius:40px;background:transparent;
  border:1px solid currentColor;
  font-family:var(--body);font-size:10px;font-weight:600;letter-spacing:.2em;
  text-transform:uppercase;transition:.25s;opacity:.92;white-space:nowrap}
/* A touch screen applies :hover on tap and then leaves it there, so pressing
   this filled it with whatever colour it was carrying -- white, over the
   photographs -- and left it that way. Hover is only offered to pointers that
   can actually hover. */
@media (hover: hover) and (pointer: fine){
  .music:hover{background:currentColor;opacity:1}
  .music:hover .label,.music:hover .musicnote{color:var(--bg);mix-blend-mode:normal}
  .music:hover .bars i{background:var(--bg)}
}
.music:focus-visible{outline:2px solid currentColor;outline-offset:3px}
/* follow the bar the same way the links and the logo do: white over the
   photographs, ink once it takes its cream background */
.topbar .music{color:#fff;text-shadow:none}
.topbar.scrolled .music{color:var(--ink)}
@media (hover: hover) and (pointer: fine){
  .topbar.scrolled .music:hover{color:var(--accent)}
}

/* Playing is a state, not a hover. It fills with the accent so it reads as on
   at a glance and stays legible over a photograph or the cream bar alike --
   rather than white on white, which is what it was doing. */
.music.playing{background:var(--accent);border-color:var(--accent);opacity:1;
  box-shadow:0 2px 14px rgba(80,60,40,.28)}
.music.playing .label{color:#fff}
.music.playing .bars i{background:#fff}

/* ---------- A WORD THAT THERE IS MUSIC ----------
   Built for phones only, where the button is a symbol with no words beside it.
   Hidden outright on wider screens, where the button already says PLAY OUR
   SONG and a label explaining a label would be noise. */
.music{position:relative}
.musichint{display:none;position:absolute;top:calc(100% + 11px);right:-4px;
  white-space:nowrap;padding:8px 13px;border-radius:9px;
  background:rgba(42,37,33,.93);color:#fff;
  font-family:var(--body);font-size:9.5px;font-weight:600;letter-spacing:.16em;
  text-transform:uppercase;pointer-events:none;z-index:30;
  box-shadow:0 8px 24px rgba(30,22,14,.34);
  opacity:0;transform:translateY(-5px);
  transition:opacity .55s ease,transform .55s ease}
.musichint::before{content:"";position:absolute;bottom:100%;right:16px;
  border:6px solid transparent;border-bottom-color:rgba(42,37,33,.93)}
.musichint.show{opacity:1;transform:none}

/* ---------- NAMING THE CAROUSEL, index.html?names=1 ----------
   Only for choosing which photographs to keep. It stops the drift, because a
   moving strip cannot be read, and writes each file's name on its picture. */
html.shownames .tickrow{animation:none !important;transform:none !important}
html.shownames .ticker{overflow-x:auto}
.filetag{display:none}
html.shownames .filetag{display:block;position:absolute;left:0;right:0;bottom:0;
  padding:7px 8px;background:rgba(20,14,9,.82);color:#fff;
  font-family:ui-monospace,Consolas,monospace;font-size:11px;letter-spacing:.02em;
  text-align:center;pointer-events:none}
html.shownames .tickcard{position:relative}

/* ---------- THE TICKER ON THE FUN PAGE ----------
   The Framer component's idea, rebuilt: a drifting row of portrait cards, each
   holding two photographs stacked one above the other. Hovering slides the pair
   up so the second takes the first's place.

   The whole row is drawn twice and the loop travels exactly -50%, so the seam
   lands where the copy begins and the join cannot be seen. */
.tickersec{padding:var(--sect) 0;overflow:hidden}
/* The home page's row carries a whole section on its own, so its cards are
   larger than the Fun page's, which sits under a picture. */
.feat .tickcard{width:clamp(180px,19vw,260px)}
.feat .ticker{--tickfade:var(--bg-deep)}
.ticker{margin-top:calc(var(--gap) + 10px);overflow:hidden;
  /* fade the ends rather than cutting them off square */
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 7%,#000 93%,transparent);
          mask-image:linear-gradient(90deg,transparent,#000 7%,#000 93%,transparent)}
.tickrow{display:flex;gap:clamp(12px,1.6vw,22px);width:max-content;
  animation:tick 46s linear infinite}
@keyframes tick{to{transform:translateX(-50%)}}
/* stopping on hover is the point -- a card cannot be hovered while it flees */
.ticker:hover .tickrow{animation-play-state:paused}

.tickcard{position:relative;flex:0 0 auto;margin:0;
  width:clamp(150px,15vw,214px);aspect-ratio:3/4;
  border-radius:14px;overflow:hidden;background:var(--bg-alt);
  box-shadow:0 1px 2px rgba(80,60,40,.10),0 10px 24px rgba(80,60,40,.13);
  transition:box-shadow .45s ease,transform .45s cubic-bezier(.2,.7,.3,1)}
.tickcard:hover{transform:translateY(-6px);
  box-shadow:0 2px 4px rgba(80,60,40,.12),0 18px 38px rgba(80,60,40,.20)}

/* two pictures stacked in a column twice the card's height; the slide moves
   exactly one card's worth, so the second lands where the first was */
.tickslide{position:absolute;inset:0;height:200%;
  display:grid;grid-template-rows:1fr 1fr;
  transition:transform .62s cubic-bezier(.2,.7,.3,1)}
.tickcard:hover .tickslide{transform:translateY(-50%)}
.tickslide img{width:100%;height:100%;object-fit:cover;display:block}
/* one photograph per card, in the naming view -- a full-height single row */
.tickslide.single{height:100%;grid-template-rows:1fr}
.tickcard:hover .tickslide.single{transform:none}

@media(prefers-reduced-motion:reduce){
  .tickrow{animation:none}
  .tickslide,.tickcard{transition:none}
}
@media(max-width:430px){.musichint{display:block}}
@media(prefers-reduced-motion:reduce){
  .musichint{transition:none;transform:none}
}
/* Renamed from .note, which the guestbook also uses for a paragraph. That
   paragraph sets color:var(--ink), and on an svg that beat the bar's white --
   so the symbol came out dark over the photographs while the links beside it
   stayed white. Two different things must not share a class name. */
.music .musicnote{width:13px;height:13px;flex:0 0 auto;fill:none;stroke:currentColor;
  stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}

/* five bars that dance while it plays -- unmistakable at a glance */
.music .bars{display:none;align-items:flex-end;gap:2px;height:12px;flex:0 0 auto}
.music.playing .bars{display:flex}
.music.playing .musicnote{display:none}
.music .bars i{display:block;width:2px;background:currentColor;border-radius:2px;
  animation:eq .9s ease-in-out infinite}
.music .bars i:nth-child(1){height:40%;animation-delay:-.5s}
.music .bars i:nth-child(2){height:85%;animation-delay:-.2s}
.music .bars i:nth-child(3){height:60%;animation-delay:-.7s}
.music .bars i:nth-child(4){height:95%;animation-delay:-.35s}
.music .bars i:nth-child(5){height:50%;animation-delay:-.85s}
@keyframes eq{0%,100%{transform:scaleY(.4)}50%{transform:scaleY(1)}}
@media(prefers-reduced-motion:reduce){.music .bars i{animation:none}}

@media(max-width:680px){
  .music{padding:6px 11px;font-size:9px;letter-spacing:.12em;gap:6px}
  .barright{gap:12px}
}
@media(max-width:430px){
  /* No circle. The symbol stands on its own beside HOME, GALLERY and FUN, in
     the same white they use, so the bar reads as one row of controls rather
     than a button parked next to three links. It also cannot sit off-centre in
     a ring that is no longer there. */
  .music .label{display:none}
  .music{width:auto;height:auto;padding:6px 2px;gap:0;border:0;background:none;
    border-radius:0;opacity:1}
  .music .musicnote{width:23px;height:23px;stroke-width:1.8}
  .music .bars{height:19px;gap:2.5px}
  .music .bars i{width:2.5px}
  /* the filled state belongs to the desktop pill, not to a bare symbol */
  .music.playing{background:none;border:0;box-shadow:none}
  /* and with no fill behind them the bars must follow the bar's own colour --
     white over the photographs, ink once it takes its cream background. White
     on cream would simply vanish. */
  .music.playing .bars i{background:currentColor}
}

/* ---------- BACK TO TOP ---------- */
.totop{position:fixed;right:clamp(16px,2.6vw,32px);bottom:clamp(16px,2.6vw,32px);
  z-index:60;width:48px;height:48px;border-radius:50%;cursor:pointer;
  border:1px solid var(--line);background:rgba(251,247,240,.92);
  backdrop-filter:blur(10px);color:var(--accent);
  box-shadow:0 6px 22px rgba(80,60,40,.18);
  display:flex;align-items:center;justify-content:center;
  opacity:0;visibility:hidden;transform:translateY(10px);
  transition:opacity .35s ease,transform .35s ease,visibility .35s,
             background .25s,color .25s}
.totop.show{opacity:1;visibility:visible;transform:none}
.totop:hover{background:var(--accent);color:#fff;border-color:var(--accent)}
.totop:focus-visible{outline:2px solid var(--accent);outline-offset:3px}
.totop svg{width:15px;height:15px;fill:none;stroke:currentColor;stroke-width:2;
  stroke-linecap:round;stroke-linejoin:round}

/* ---------- FUN PAGE ---------- */
.funpage{padding:calc(var(--sect) * 1.5) 0 var(--sect);text-align:center}
.funshot{margin:var(--gap) auto 0;max-width:1100px;background:var(--card);
  padding:14px 14px 16px;border-radius:4px;
  box-shadow:0 1px 2px rgba(80,60,40,.10),
             0 12px 28px rgba(80,60,40,.14),
             0 34px 68px rgba(80,60,40,.13)}
.funshot img{width:100%;display:block;border-radius:2px}
.funcap{margin-top:18px;font-family:var(--display);font-style:italic;
  font-size:1.15rem;color:var(--muted)}
.funnote{margin-top:10px;font-size:11px;letter-spacing:.2em;text-transform:uppercase;
  color:var(--ink);opacity:.75}
.topbar.scrolled{background:rgba(251,247,240,.93);backdrop-filter:blur(14px);
  padding:14px 6vw;box-shadow:0 1px 0 var(--line)}
.topbar.scrolled a{color:var(--ink);text-shadow:none}
.topbar.scrolled a:hover{color:var(--accent)}
@media(max-width:520px){
  .topbar{padding:16px 5vw}
  .topbar a{font-size:10px;letter-spacing:.2em}
}

/* ---------- HERO ---------- */
/* The blurred copy lives HERE, on the hero itself, not on the first slide.
   The slides are built in script, so a rule aimed at one of them matches
   nothing until every script has run -- and what painted in the meantime was
   this element's own black with the headline sitting on it. The hero is in the
   html from the first byte, so this paints with the stylesheet and there is no
   black frame left to see. */
.hero{position:relative;height:100svh;min-height:560px;overflow:hidden;
  background-color:#6b5a45;
  background-image:url("data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAwICQsJCAwLCgsODQwOEh4UEhEREiUbHBYeLCcuLisnKyoxN0Y7MTRCNCorPVM+QkhKTk9OLztWXFVMW0ZNTkv/2wBDAQ0ODhIQEiQUFCRLMisyS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0v/wAARCAArAEADASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAABAYDBQcC/8QAMRAAAgEDAwIFAgMJAAAAAAAAAQIDAAQRBRIhBjETQVFhcRQiI0LBFTIzRIGRoaLh/8QAFwEAAwEAAAAAAAAAAAAAAAAAAQIDAP/EABoRAAIDAQEAAAAAAAAAAAAAAAABAgMRMSH/2gAMAwEAAhEDEQA/AF9YvapFQHOCDjvipJkxAxC7uOV9R5ip4BbmzimQFfG5VQvkOKMrkhYUuSAhMsTK0qfhsOCDRFuUnztB47ZHcetTWGiSTXUjXUbNC+EgjBxn3wOeKsJNKOlptnkA+4bctncDnv75xU1ZLpaVSzmEFva7j2q0j0lnTdtOPiuLSWFGGWQfJpottb0+Cz2PJEGx2LDmpSvW5oY0vOCjPYbM8UHJb48qttR1WzLMRcRZ5wA4qluNZsUUFplDEcqOSPY0YXNizqwUxdXR/mH/AL039Orc3NiotdrTHuX7D3JpMSQHICBuOwP/ACtD6QvmbR1j+nmdofsGBhSvqSeDVpQUvAVzcdZcaTpzWcpuruYSzLuGQcKFPpmljri8S/SJtoMHi4Qn8xAOT8c1z1B1FM10tq8UkUSnc8RG1pF9M84qo17qJNVWG3Fr4ccJyMHJHlgccU/iWID1+sDgWBW/dXitC6egtf2Bc77eN3YEhiAccVnttcRowIhc/L/pimfTZEOnykMqSOOIjGxyPnI4qE0PAodYUQbih2bM52jvVfE7SQCRjuLeZFEX86eJJHtXHKk4oIyCNRGpGF4708V4JJkKXs0QARVb5zmtN0nUVnsIPAbCbVwBx/SstQ/jEegps6aJ+hfns5x/iqoUB60kI1dHBG14vL2Jpft7owXAfkgdwO5FMPVSK1uJWGXWRVB9Bg0rJ/EFK+hGKPX4mIXwJRk4Hau16oEYZVTg8Hcmf1oaBVMYOBQoRSXyo71mt6bcCZNbWQ5x/qaGOprjACn5FRSRoPyihmUelHgD/9k=");
  background-size:cover;background-position:50% 28%;background-repeat:no-repeat;
  /* tuned by hand, 20 Aug: overlay 21%, position 28%, zoom 19%, 6.5s a slide */
  --ov:.21; --pos:28%; --zoom:1.19}
.slide{position:absolute;inset:0;opacity:0;transition:opacity 1.1s ease;
  /* transparent, not black: the blurred hero behind must show through while
     a slide's own photograph is still on its way */
  background-color:transparent;background-size:cover;
  background-position:50% var(--pos);background-repeat:no-repeat;
  /* two layers: the real photograph sits on top of the blurred copy, so the
     blur is visible only for the moment before the real one arrives */
  background-image:var(--still, none), var(--lqip, none)}

/* The opening slide showed the dark background colour for a moment on
   refresh, because the real photograph -- however small -- still has to be
   fetched. This is a 28px blurred copy of that same photograph, written into
   the stylesheet itself, so it paints on the very first frame with no network
   request at all. The full picture then loads over it and nobody sees black. */
.slide[data-i="0"]{background-color:transparent}
/* A video element paints nothing -- an empty black box -- until it has decoded
   either its poster or a frame. The slide behind it already carries the same
   photograph as a background, so the video simply stays out of the way until it
   has something of its own to show, and fades in when it does. Without this it
   covers the photograph with black for a beat on every load. */
.slide video{opacity:0;transition:opacity .45s ease}
.slide video.ready{opacity:1}
@media(prefers-reduced-motion:reduce){.slide video{transition:none}}
.slide.on{opacity:1}
.slide img,.slide video{width:100%;height:100%;object-fit:cover;display:block;
  object-position:50% var(--pos);transform-origin:50% var(--pos)}

/* Phones crop these landscape photos to a narrow vertical strip, which cuts
   the couple out of frame. Two corrections, both mobile-only:
   a shorter hero, so less of the width is thrown away, and a per-photo
   horizontal position aimed at wherever the two of them actually are. */
/* order changed: the sunset embrace leads, and its film plays in place of
   the still. Aim follows the photograph, not the slot. */
/* The couple sit on the left of this frame, so a LOWER number brings them
   toward the middle of a phone screen. 28% was too far left; 40% was worse
   because it moved the window the wrong way. */
/* Keyed to the slide's own index rather than its position among the hero's
   children, so putting anything else in the hero cannot silently move these. */
.slide[data-i="0"] img,.slide[data-i="0"] video,
.slide[data-i="0"]{--posx:14%}
.slide[data-i="1"] img,.slide[data-i="1"] video{--posx:48%}   /* skyline, centred    */
.slide[data-i="2"] img{--posx:43%}   /* recessional, left of centre */
.slide[data-i="3"] img{--posx:45%}   /* portrait, pair centred      */

@media(max-width:820px){
  .hero{height:74svh;min-height:470px}
  .slide{background-position:var(--posx,50%) var(--pos)}
  .slide img,.slide video{object-position:var(--posx,50%) var(--pos);
             transform-origin:var(--posx,50%) var(--pos)}
}
/* alternating zoom in / zoom out so consecutive slides do not feel identical */
.slide.on img,.slide.on video{animation:kbIn 9s ease-out forwards}
.slide.on.alt img,.slide.on.alt video{animation:kbOut 9s ease-out forwards}
@keyframes kbIn {from{transform:scale(1.01)}  to{transform:scale(var(--zoom))}}
@keyframes kbOut{from{transform:scale(var(--zoom))} to{transform:scale(1.01)}}
.scrim{position:absolute;inset:0;z-index:2;
  background:
    linear-gradient(180deg,rgba(24,18,12,.20) 0%,rgba(24,18,12,0) 30%,
                    rgba(24,18,12,0) 60%,rgba(24,18,12,.55) 100%),
    rgba(0,0,0,var(--ov))}
.herotext{position:absolute;inset:0;z-index:3;display:flex;flex-direction:column;
  align-items:center;justify-content:center;text-align:center;color:#fff;padding:0 7vw}
.hero .kicker{font-size:12px;font-weight:600;letter-spacing:.46em;text-transform:uppercase;
  opacity:.92;margin-bottom:28px}
.hero h1{font-family:var(--display);font-weight:300;font-size:clamp(3rem,10.4vw,8.5rem);
  line-height:1;letter-spacing:.01em;text-shadow:0 2px 34px rgba(0,0,0,.32)}
.hero h1 em{font-style:italic}
.heroline{font-family:var(--display);font-style:italic;font-weight:300;
  font-size:clamp(1.3rem,3.1vw,2.3rem);opacity:.95;margin-top:24px;
  transition:opacity .45s ease;min-height:1.5em;text-shadow:0 2px 20px rgba(0,0,0,.3)}
/* The rings sit where the vertical rule used to. Slightly transparent with a
   soft glow beneath, so they read as part of the photograph rather than as a
   sticker laid on top of it. */
.herorings{width:clamp(110px,13.5vw,172px);height:auto;margin:9px auto 0;
  opacity:.58;
  filter:drop-shadow(0 3px 12px rgba(0,0,0,.35))
         drop-shadow(0 0 22px rgba(255,214,150,.18))}
@media(max-width:820px){.herorings{width:clamp(104px,26vw,150px);margin-top:20px}}
.herofoot{position:absolute;bottom:38px;left:0;right:0;z-index:3;text-align:center;
  color:#fff;font-size:10px;letter-spacing:.34em;text-transform:uppercase;opacity:.82}
.dots{position:absolute;bottom:84px;left:50%;transform:translateX(-50%);z-index:4;
  display:flex;gap:10px}
/* The tap target is 34px even though the ring is 13px, so they are easy to
   hit on a phone without looking heavy on a desktop. */
.dots button{width:30px;height:30px;border:0;background:none;padding:0;cursor:pointer;
  display:flex;align-items:center;justify-content:center}
.dots button::after{content:"";width:9px;height:9px;border-radius:50%;
  border:1.5px solid rgba(255,255,255,.85);background:transparent;
  box-shadow:0 1px 8px rgba(0,0,0,.35);transition:.32s cubic-bezier(.2,.7,.3,1)}
.dots button:hover::after{background:rgba(255,255,255,.45);transform:scale(1.12)}
.dots button[aria-current="true"]::after{background:#fff;transform:scale(1.18);
  box-shadow:0 0 0 3px rgba(255,255,255,.22),0 1px 10px rgba(0,0,0,.4)}
.dots button:focus-visible::after{outline:2px solid #fff;outline-offset:4px}
.dots button:focus-visible{outline:2px solid #fff;outline-offset:3px}

/* ---------- INTRO ---------- */
.intro{padding:var(--sect) 0}
.pair{display:grid;grid-template-columns:1fr auto 1fr;gap:clamp(24px,5vw,60px);
  align-items:center;margin-top:clamp(46px,6.2vw,84px)}
.pair figure{text-align:center}
.pair figure{text-align:center}
/* Mounted-print treatment. A white mat gives the bright photos a hard edge
   against the cream, which a shadow alone cannot do. */
.portrait{display:block;width:90%;margin:0 auto;background:var(--card);
  padding:13px 13px 15px;
  /* A fixed 200px is less than half this box once the column passes 412px, and
     the top stops being an arch: the corners no longer meet, leaving a flat
     plateau across the apex that reads as the picture being cut off. Asking
     for far more than could ever fit makes the browser scale the radii to
     exactly half the width, so it is a true semicircle at every size. */
  border-radius:999px 999px 7px 7px;
  /* three layers: contact, mid, ambient -- reads as depth, not as blur */
  box-shadow:0 1px 2px rgba(80,60,40,.10),
             0 10px 24px rgba(80,60,40,.13),
             0 30px 60px rgba(80,60,40,.14);
  transition:transform .6s cubic-bezier(.2,.7,.3,1),
             box-shadow .6s ease}
.pclip{display:block;overflow:hidden;border-radius:999px 999px 3px 3px;
  position:relative;aspect-ratio:3/4}
.pclip img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  object-position:center var(--portrait-pos,30%);
  opacity:0;transition:opacity 1.1s ease,transform .9s cubic-bezier(.2,.7,.3,1)}
.pclip img.on{opacity:1}
.pair figure:hover .portrait{transform:translateY(-12px);
  box-shadow:0 2px 4px rgba(80,60,40,.12),
             0 18px 36px rgba(80,60,40,.16),
             0 46px 90px rgba(80,60,40,.20)}
.pair figure:hover .pclip img{transform:scale(1.045)}
.pair figcaption{font-family:var(--display);font-size:1.65rem;margin-top:22px;
  letter-spacing:.02em}
.amp{font-family:var(--display);font-style:italic;font-size:clamp(2.4rem,6vw,4.4rem);
  color:var(--accent);line-height:1}
@media(max-width:760px){
  .pair{grid-template-columns:1fr;gap:26px}
  /* No order here. The markup already reads Sean, ampersand, Briana, so the
     column falls out right on its own -- and setting the ampersand to 2 while
     the two figures stayed at 0 put it after both of them, alone at the
     bottom under Briana. */
}

/* ---------- scroll reveal ---------- */
.reveal{opacity:0;transform:translateY(26px);
  transition:opacity .9s ease,transform .9s cubic-bezier(.2,.7,.3,1)}
.reveal.in{opacity:1;transform:none}
.amp.reveal{transform:translateY(0) scale(.7)}
.amp.reveal.in{transform:none}
@media(prefers-reduced-motion:reduce){
  .reveal{opacity:1;transform:none;transition:none}
}

/* ---------- MARRIED FOR ---------- */
/* kept although the section was folded into the hero -- restoring it
   is then a matter of markup alone */
.since{padding:var(--sect) 0;position:relative;overflow:hidden;
  background:radial-gradient(70% 54% at 50% 0%, rgba(255,255,255,.34), transparent 64%),
             var(--bg-alt)}
.counter{display:flex;flex-wrap:wrap;justify-content:center;
  gap:clamp(14px,3.4vw,44px);margin-top:calc(var(--gap) + 6px)}
.counter .unit{display:flex;flex-direction:column;align-items:center;min-width:66px;
  position:relative}
/* a hairline between each figure, the way a clock face is divided */
.counter .unit + .unit::before{content:"";position:absolute;left:calc(-1 * clamp(7px,1.7vw,22px));
  top:18%;bottom:34%;width:1px;background:var(--line)}
.counter .num{font-family:var(--display);font-weight:300;line-height:1;
  font-size:clamp(2.3rem,5.4vw,4rem);color:var(--ink);
  font-variant-numeric:tabular-nums}
.counter .cap{margin-top:9px;font-family:var(--body);font-size:9.5px;font-weight:600;
  letter-spacing:.28em;text-transform:uppercase;color:var(--accent)}
@media(max-width:560px){
  .counter{gap:10px}
  .counter .unit{min-width:52px}
  .counter .unit + .unit::before{display:none}
}

/* ---------- BOTANICAL FLOURISH ----------
   Drawn rather than an image: a few strokes, recolours with the palette,
   sharp at any size, and about nothing in weight. */
.sprig{display:block;width:clamp(150px,20vw,250px);height:auto;margin:0 auto;
  color:var(--accent);opacity:.5}
.sprig.top{margin-bottom:-6px}
.sprig.bottom{transform:rotate(180deg);margin-top:-6px}
.sprig path,.sprig line{fill:none;stroke:currentColor;stroke-width:1.1;
  stroke-linecap:round}
.sprig .leaf{fill:currentColor;stroke:none;opacity:.55}

/* ---------- MARRIED FOR, AT THE FOOT OF THE HERO ----------
   Placed after the .counter rules on purpose: these overrides and those share
   a specificity, so source order is what decides, and the hero must win. */
.herobottom{position:absolute;left:0;right:0;bottom:0;z-index:4;
  display:flex;flex-direction:column;align-items:center;
  gap:clamp(10px,1.5vh,18px);padding:0 5vw 42px}
/* the wash sits only beneath the figures, so the photograph keeps its light */
.herobottom::before{content:"";position:absolute;left:0;right:0;top:-64px;bottom:0;
  z-index:-1;pointer-events:none;
  background:linear-gradient(180deg,rgba(24,18,12,0),rgba(24,18,12,.32) 44%,rgba(24,18,12,.58))}
.dots{position:static;transform:none;margin-bottom:12px}
.herofoot{position:static;bottom:auto}
/* centre the headline in the room that is left, not behind the figures */
.herotext{padding-bottom:clamp(150px,23vh,255px);transform:translateY(8px)}

/* One counter design on this site, not two that can drift apart. Only the three
   palette variables are reset; every rule about its type is the shared one. */
.herocount{--ink:#fff;--accent:rgba(255,255,255,.82);--line:rgba(255,255,255,.34);
  text-align:center}
.herocount .sprig{width:clamp(120px,14vw,180px);color:#fff;opacity:.72;margin:0 auto;
  filter:drop-shadow(0 1px 6px rgba(0,0,0,.45))}
.hcount-label{margin-top:7px;font-family:var(--body);font-size:10px;font-weight:600;
  letter-spacing:.42em;text-transform:uppercase;color:rgba(255,255,255,.88)}
.herocount .counter{margin-top:13px;gap:clamp(11px,2.5vw,34px)}
.herocount .num{font-size:clamp(1.65rem,3.3vw,2.6rem);text-shadow:0 1px 16px rgba(0,0,0,.4)}
.herocount .cap{margin-top:7px;font-size:8.5px;letter-spacing:.24em}
.hcount-note{margin:13px 0 0;font-family:var(--display);font-style:italic;font-weight:300;
  font-size:clamp(.95rem,1.5vw,1.12rem);color:rgba(255,255,255,.82)}

/* A phone has no room for the flourish once the figures are there. The numbers
   and the line about the days are what matter, so those are what stay. */
@media(max-width:560px){
  .herocount .sprig{display:none}
  .herobottom{gap:8px;padding-bottom:30px}
  .herocount .counter{margin-top:10px}
  .hcount-label{letter-spacing:.34em}
  .hcount-note{margin-top:10px;font-size:.92rem}

  /* Six figures will not fit a phone at their natural width, and wrapping put
     SECONDS alone on a second row. Sharing the width equally keeps them on one
     line at any handset size instead of guessing at a breakpoint per phone. */
  .herocount{width:100%}        /* it is a centred flex item, so it shrink-wraps
                                   to its content unless told to fill */
  .herocount .counter{flex-wrap:nowrap;gap:6px}
  .herocount .unit{min-width:0;flex:1 1 0}
  .herocount .num{font-size:1.45rem}
  .herocount .cap{font-size:7.5px;letter-spacing:.1em;margin-top:6px}
}

/* On a phone the hero stops guessing. Rather than pinning the text across the
   whole box and then padding it back by however tall the counter happens to
   be -- a number that changes with the copy -- the hero becomes a column: the
   text takes whatever is left, the counter takes what it needs, and the text
   centres in exactly the gap that remains. Correct at any height, with nothing
   to keep in step by hand. The slides and the scrim are absolute, so they are
   untouched by this. */
@media(max-width:560px){
  .hero{display:flex;flex-direction:column}
  .herotext{position:relative;inset:auto;flex:1 1 auto;
    padding-top:var(--barh);padding-bottom:0;transform:none}
  .herobottom{position:relative;left:auto;right:auto;bottom:auto}
}

/* A short handset cannot hold the headline, the blessing, the rings AND the
   counter at full size. The rings give up the most for the least, so they
   shrink first, and the headline comes down a step. */
@media(max-width:560px) and (max-height:720px){
  .herorings{width:78px;margin-top:8px}
  .hero h1{font-size:2.55rem}
  .heroline{font-size:1.15rem;margin-top:16px}
}

/* ---------- TIMELINE ---------- */
.story{padding:var(--sect) 0;
  background:radial-gradient(72% 60% at 76% 46%, rgba(255,255,255,.26), transparent 62%),
             var(--bg-alt)}
.tl{margin-top:var(--gap);position:relative}
.tl::before{content:"";position:absolute;left:50%;top:0;bottom:0;width:2px;
  transform:translateX(-1px);border-radius:2px;
  background:linear-gradient(180deg,
    transparent 0%, var(--spine) 7%, var(--spine) 93%, transparent 100%)}
.mo{display:grid;grid-template-columns:1fr 1fr;gap:clamp(28px,5vw,64px);
  align-items:center;margin-bottom:38px;position:relative}
.mo:nth-child(even) .motext{order:2;text-align:left}
.mo:nth-child(even) .mophoto{order:1}
.mo:nth-child(odd) .motext{text-align:right}
/* Same mounted-print idea as the portraits, but a thinner mat -- 8px here
   against 13px up there, so the two portraits stay the featured pair. */
.mo .mophoto{background:var(--card);padding:8px;border-radius:5px;
  box-shadow:0 1px 2px rgba(80,60,40,.09),
             0 8px 20px rgba(80,60,40,.12),
             0 22px 44px rgba(80,60,40,.11);
  transition:transform .55s cubic-bezier(.2,.7,.3,1),box-shadow .55s ease}
/* width:100% matters more than it looks. Without it an <img> that has not
   loaded yet is 0 wide, so aspect-ratio gives it 0 height and the mat collapses
   to its 16px of padding -- then springs open when the photograph lands. Four
   of those in a column is 1,700px of page appearing under you as you read. With
   a width the box is full height from the first paint and nothing moves.
   The tone is what an empty mat shows: warm, not the stark white of a hole. */
.mo img{width:100%;aspect-ratio:4/3;object-fit:cover;object-position:center 30%;
  border-radius:2px;display:block;background:#EFE7DB}
.mo:hover .mophoto{transform:translateY(-7px);
  box-shadow:0 2px 4px rgba(80,60,40,.11),
             0 14px 30px rgba(80,60,40,.15),
             0 34px 66px rgba(80,60,40,.17)}
.mo h3{font-family:var(--display);font-weight:500;font-size:clamp(1.4rem,2.6vw,2rem);
  margin-bottom:8px}
.mo .when{font-size:10px;font-weight:600;letter-spacing:.34em;
  text-transform:uppercase;color:var(--ink);margin-bottom:12px}
.mo p{color:var(--ink);font-size:15.5px;font-weight:500;max-width:44ch;
  line-height:1.7;display:inline-block}
.dot{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);
  width:13px;height:13px;border-radius:50%;background:var(--accent);
  border:3px solid var(--bg-alt);
  box-shadow:0 0 0 1px rgba(169,131,92,.45);z-index:2}
@media(max-width:820px){
  .tl::before{left:9px}
  .mo{grid-template-columns:1fr;gap:16px;padding-left:36px;margin-bottom:44px}
  .mo:nth-child(odd) .motext,.mo:nth-child(even) .motext{text-align:left;order:2}
  .mo:nth-child(even) .mophoto{order:1}
  .dot{left:9px;top:14px}
}

/* ---------- MOSAIC ---------- */
.moments{padding:var(--sect) 0}
.mosaic{display:grid;grid-template-columns:repeat(4,1fr);gap:12px;margin-top:var(--gap)}
.mosaic img{width:100%;height:100%;object-fit:cover;border-radius:3px;transition:.5s}
.mosaic figure{overflow:hidden;border-radius:3px;cursor:zoom-in}
.mosaic figure:hover img{transform:scale(1.045)}
.m-tall{grid-row:span 2}
.m-wide{grid-column:span 2}
@media(max-width:820px){.mosaic{grid-template-columns:repeat(2,1fr)}}

/* ---------- FILM ---------- */
.film{background:var(--card);padding:var(--sect) 0;text-align:center}
.filmbox{margin:0 auto;max-width:none;aspect-ratio:16/9;background:#EDE2D2;
  border-radius:4px;display:flex;align-items:center;
  justify-content:center;color:var(--ink);font-size:12px;letter-spacing:.24em;
  text-transform:uppercase;overflow:hidden;position:relative;
  /* Same three-layer shadow as the mounted photographs, scaled up: a tight
     contact edge, a mid shadow, then a wide ambient one. The film sits on
     white here, so the shadow is what lifts it off the page. */
  box-shadow:0 1px 3px rgba(80,60,40,.12),
             0 16px 34px rgba(80,60,40,.16),
             0 44px 84px rgba(80,60,40,.17)}
.filmbox video{width:100%;height:100%;object-fit:cover;display:block}
.filmbox .placeholder{display:none}
/* only if the file itself fails */
.filmbox.failed video{display:none}
.filmbox.failed .placeholder{display:block}

/* ---------- THE FILM ----------
   No mount. The beige rules, the wash and the padding are gone; this is now
   only a positioning box, so the watercolour hangs off the corner of the
   picture instead of being held inside a frame. */
.filmframe{position:relative;max-width:960px;margin:calc(var(--gap) + 10px) auto 0}

/* ---------- THE WATERCOLOUR ON THE FILM ----------
   Two pieces, not one. As a single tall image its height was locked to the
   film's, which fixed its width at 31% AND fixed the empty stretch the artist
   left between the greenery and the bouquet -- a band measuring 0% coverage
   across 41% to 46% of its height, sitting right on the film's left edge.
   Cut at that empty band, each piece anchors to its own corner and takes its
   own size, so they can be grown until they meet and the gap simply is not
   there. Each was trimmed to its own leaves, so its box IS the drawing. */
.filmleaf{position:absolute;left:0;z-index:3;width:auto;pointer-events:none;
  user-select:none;filter:drop-shadow(0 6px 18px rgba(80,60,40,.16))}
.filmleaf.top{top:0;height:50%}
.filmleaf.bot{bottom:-8px;left:-8px;height:62%}

/* The two lines sit in the clear right-hand third, over sky and water --
   the one part of this frame with nothing happening in it. */
.filmtext{position:absolute;z-index:3;right:var(--ftr,9%);top:var(--ftt,26%);width:var(--ftw,34%);
  text-align:center;color:#fff;pointer-events:none;
  text-shadow:0 2px 18px rgba(20,14,8,.45)}
.ftline{margin:0;font-family:var(--display);font-weight:400;
  font-size:var(--ftl, clamp(.95rem,1.6vw,1.5rem));letter-spacing:.01em}
.ftname{margin:.35em 0 0;font-family:"Great Vibes",var(--display),cursive;
  font-weight:400;line-height:1.05;font-size:var(--ftn, clamp(2rem,4.4vw,4.2rem))}

/* A phone has room for the film or for the decoration, not both. The bouquet
   shrinks to a corner and the lines step aside -- the moving picture is the
   point of this section, and 318px of it is little enough already. */
/* The words were hidden on a phone, which was wrong -- they are half the
   design, and the right-hand third of this frame is sky either way. They stay;
   the block just takes a little more width and smaller type to fit it. */
@media(max-width:700px){
  .filmtext{right:6%;top:20%;width:46%}
  .ftline{font-size:11.5px}
  .ftname{font-size:27px}
}

/* A phone has no room to spend on a mount. At 390px the mat took the film down
   to 280px wide and the flourishes still sat on the footage, so below 560px
   they step aside and the rules alone do the framing. */
@media(max-width:560px){
}


/* ---------- GUEST COLLAGE ---------- */
.guests{padding:var(--sect) 0}   /* no background, so the wash shows */
.scatter{display:grid;grid-template-columns:repeat(3,1fr);
  gap:clamp(20px,3.4vw,46px);margin-top:calc(var(--gap) + 12px)}
@media(max-width:900px){.scatter{grid-template-columns:repeat(2,1fr)}}
@media(max-width:560px){.scatter{grid-template-columns:1fr}}

/* Snapshots laid on a table. The tilt lives in --rot so the reveal and the
   hover can both compose with it instead of overwriting it. */
.snap{--rot:0deg;
  background:var(--card);padding:11px 11px 42px;border-radius:2px;
  box-shadow:0 1px 2px rgba(80,60,40,.10),
             0 8px 20px rgba(80,60,40,.13),
             0 24px 48px rgba(80,60,40,.12);
  transform:rotate(var(--rot));
  transition:transform .55s cubic-bezier(.2,.7,.3,1),
             box-shadow .55s ease, opacity .7s ease;
  cursor:zoom-in;position:relative}
.snap img{width:100%;aspect-ratio:1/1;object-fit:cover;object-position:center 28%;
  display:block;border-radius:1px;background:#EFE7DB}

.snap:nth-child(1){--rot:-2.6deg}
.snap:nth-child(2){--rot:1.7deg}
.snap:nth-child(3){--rot:-1.2deg}
.snap:nth-child(4){--rot:2.4deg}
.snap:nth-child(5){--rot:-1.9deg}
.snap:nth-child(6){--rot:1.3deg}

/* arrives tilted and low, settles into its tilt */
.snap.reveal{opacity:0;transform:rotate(var(--rot)) translateY(28px)}
.snap.reveal.in{opacity:1;transform:rotate(var(--rot))}

/* straighten and lift, like picking one up off the pile */
.snap.in:hover{transform:rotate(0deg) translateY(-10px) scale(1.025);z-index:4;
  box-shadow:0 2px 5px rgba(80,60,40,.12),
             0 16px 34px rgba(80,60,40,.17),
             0 40px 78px rgba(80,60,40,.20)}

@media(prefers-reduced-motion:reduce){
  .snap,.snap.reveal,.snap.reveal.in,.snap.in:hover{transform:none;opacity:1}
}

/* ---------- CAROUSEL ---------- */
.feat{padding:var(--sect) 0;
  background:radial-gradient(70% 58% at 18% 0%, rgba(255,255,255,.26), transparent 62%),
             var(--bg-deep)}
.feat .eyebrow{color:var(--ink)}
.feat .h2 em{color:var(--accent-deep)}
.feat .orn i{background:rgba(126,92,56,.3)}
.feat .orn span{color:var(--accent-deep)}
@media(prefers-reduced-motion:reduce){
  .tickrow{animation:none}
  .mrow{overflow-x:auto}
}

/* ---------- GALLERY ---------- */
.gal{padding:var(--sect) 0 calc(var(--sect) * .45)}
/* The page's own heading, on cream directly under the hero -- the same place
   the home page puts a section heading, and above everything rather than
   buried a screen down. Two comments about a drifting strip used to sit here;
   that component is gone, replaced by the home page's own carousel. */
.galintro{padding:var(--sect) 0 calc(var(--sect) * .5);background:var(--bg)}

/* ---------- A CHAPTER'S GROUND ----------
   Cream punctuated by the two deeper tones, the way the home page does it,
   and darkening as the day goes on: morning on cream, the ceremony on tan,
   the reception back to cream, golden hour tan again, the night deepest. */
.chap{padding:calc(var(--sect) * .62) 0 calc(var(--sect) * .72)}
.chap .grid{margin-top:var(--gap)}
.tone-cream{background:var(--bg)}
.tone-alt{background:radial-gradient(66% 56% at 28% 38%, rgba(255,255,255,.22), transparent 62%),
                    var(--bg-alt)}
.tone-deep{background:radial-gradient(70% 58% at 74% 34%, rgba(255,255,255,.20), transparent 62%),
                     var(--bg-deep)}
/* An empty tile has to read as a frame waiting on every one of the three. */
.tone-cream .grid figure{background:#EDE3D5}
.tone-alt   .grid figure{background:#F3ECE1}
.tone-deep  .grid figure{background:#F3ECE1}
/* ---------- A CHAPTER MARK ----------
   Lighter than a section heading, because the section already has one above
   it. A rule that opens to let the words sit on it, so the eye reads a pause
   rather than a new beginning. */
.chapter{display:flex;align-items:center;justify-content:center;gap:16px;
  margin:calc(var(--gap) + 26px) 0 var(--gap);text-align:center}
.chapter::before,.chapter::after{content:"";flex:1;height:1px;max-width:190px;
  background:linear-gradient(90deg,transparent,rgba(42,37,33,.26))}
.chapter::after{background:linear-gradient(90deg,rgba(42,37,33,.26),transparent)}
.chapterlabel{font-family:var(--body);font-size:9.5px;font-weight:600;
  letter-spacing:.34em;text-transform:uppercase;color:var(--ink);opacity:.72;
  display:block;margin-bottom:5px}
.chaptertitle{font-family:var(--display);font-weight:400;font-style:italic;
  font-size:clamp(1.35rem,3vw,1.9rem);line-height:1.1;margin:0;color:var(--ink)}
/* Each chapter mark now opens its own coloured section, so the section's own
   padding is the air above it -- the mark's old top margin would stack on top
   of that and push every heading too far down its band. */
.chap .chapter{margin-top:0}
@media(max-width:600px){
  .chapter{gap:11px}
  .chapter::before,.chapter::after{max-width:60px}
}

/* ---------- THE GALLERY GRID ----------
   Four columns of staggered heights. The browser does the staggering itself:
   each picture keeps its own proportions and the columns balance, so nothing
   has to be measured or arranged in script.

   Bare, rather than mounted. Every other section on this site puts a white mat
   and a shadow round its photographs -- but this page is only photographs, and
   sixty little white frames read as sixty frames rather than sixty pictures. */
.grid{columns:4;column-gap:clamp(12px,1.5vw,22px);margin-top:var(--gap)}
@media(max-width:1100px){.grid{columns:3}}
@media(max-width:760px){.grid{columns:2}}
/* Not --bg-alt any more: that is the band this section now sits on, so an
   unloaded tile was an invisible hole rather than a frame waiting. The same
   warm tone the timeline and the snapshots use. */
.grid figure{break-inside:avoid;margin:0 0 clamp(12px,1.5vw,22px);cursor:zoom-in;
  position:relative;border-radius:6px;overflow:hidden;background:#F3ECE1;
  transition:transform .5s cubic-bezier(.2,.7,.3,1),box-shadow .5s ease,
             opacity .7s ease}
/* height:auto is not optional here. The markup declares each picture's real
   pixel size so the box can be reserved, and without this the browser honours
   that height literally -- a 2048px-tall tile in a 290px column. */
.grid img{display:block;width:100%;height:auto;border-radius:6px;
  transition:transform .7s cubic-bezier(.2,.7,.3,1)}
.grid figure:hover{transform:translateY(-5px);
  box-shadow:0 12px 30px rgba(80,60,40,.18),
             0 28px 56px rgba(80,60,40,.14)}
.grid figure:hover img{transform:scale(1.04)}

/* arrive as you scroll to them */
.shot{opacity:0;transform:translateY(24px)}
.shot.in{opacity:1;transform:none}
@media(prefers-reduced-motion:reduce){
  .shot{opacity:1;transform:none}
  .grid figure:hover{transform:none}
  .grid figure:hover img{transform:none}
}

/* ---------- GUESTBOOK ---------- */
.gb{background:radial-gradient(70% 54% at 50% 52%, rgba(255,255,255,.24), transparent 64%),
             var(--bg-alt);padding:var(--sect) 0;text-align:center;
  border-top:1px solid var(--line)}
/* ---------- THE GUESTBOOK ----------
   Left half holds the note, right half a photograph running to the edge of the
   page. The card keeps the same mounted treatment as the portraits, so it
   belongs to the site rather than looking like a form bolted to it. */
.gb{padding:0}
.gbsplit{display:grid;grid-template-columns:1.02fr .98fr;align-items:stretch;
  min-height:clamp(520px,72vh,760px)}
.gbside{display:flex;flex-direction:column;justify-content:center;
  text-align:center;padding:var(--sect) clamp(24px,5vw,72px)}
.gbphoto{position:relative;overflow:hidden;background:var(--bg-alt)}
.gbphoto img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  object-position:center 34%;display:block}

.gbcard{max-width:520px;margin:clamp(26px,3.4vw,44px) auto 0;
  background:var(--card);border:1px solid var(--line);border-radius:14px;
  padding:clamp(24px,3vw,34px) clamp(20px,2.6vw,30px);
  /* the three-layer shadow the mounted photographs use */
  box-shadow:0 1px 2px rgba(80,60,40,.10),
             0 10px 24px rgba(80,60,40,.13),
             0 30px 60px rgba(80,60,40,.12)}
.gbcard input,.gbcard textarea{width:100%;font-family:var(--body);font-size:14.5px;
  font-weight:400;padding:13px 15px;border:1px solid var(--line);background:var(--bg);
  border-radius:9px;margin-bottom:12px;color:var(--ink);transition:.2s}
.gbcard input::placeholder,.gbcard textarea::placeholder{color:#6B5D50;opacity:.75}
.gbcard input:focus,.gbcard textarea:focus{outline:none;border-color:var(--accent);
  box-shadow:0 0 0 3px rgba(169,131,92,.14)}
.gbcard textarea{min-height:112px;resize:vertical;line-height:1.6}
.gbcard button{width:100%;font-family:var(--body);font-size:11px;font-weight:600;
  letter-spacing:.26em;text-transform:uppercase;padding:15px 30px;
  border:1px solid var(--accent);background:var(--accent);color:#fff;cursor:pointer;
  border-radius:9px;transition:.25s;margin-top:2px}
.gbcard button:hover:not(:disabled){background:transparent;color:var(--accent)}
.gbcard button:disabled{opacity:.5;cursor:default}

/* One column on anything narrow, photograph first so it still opens on a face */
@media(max-width:860px){
  .gbsplit{grid-template-columns:1fr;min-height:0}
  .gbphoto{order:-1;height:clamp(240px,42vh,380px)}
  .gbside{padding:var(--sect) clamp(20px,6vw,40px)}
}
.note{font-size:11.5px;color:var(--ink);margin-top:14px;letter-spacing:.02em}

/* ---------- THE NOTES PEOPLE LEAVE ---------- */
/* Off the page entirely, and out of the tab order, so only a robot finds it */
.gbtrap{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}
.gblist{max-width:760px;margin:calc(var(--gap) + 8px) auto 0;
  display:flex;flex-direction:column;gap:16px}
/* With nothing in it the box is 0px tall but still claims its top margin,
   which strands a strip of page under the photograph. Once there are notes --
   or once it is connected and says there are none yet -- it is not empty and
   the margin comes back. */
.gblist:empty{display:none}
.gbdemo{margin:6px 0 0;text-align:center;font-family:var(--body);font-size:11px;
  letter-spacing:.06em;color:var(--ink);opacity:.5}
.gbempty{text-align:center;color:var(--ink);opacity:.6;font-size:14px;margin:0}
.gbnote-card{background:var(--card);border:1px solid var(--line);border-radius:14px;
  padding:22px 24px 18px;text-align:left;
  box-shadow:0 1px 2px rgba(80,60,40,.06),0 10px 24px rgba(80,60,40,.07)}
.gbmsg{margin:0;font-family:var(--display);font-style:italic;font-weight:400;
  font-size:clamp(1.05rem,1.7vw,1.32rem);line-height:1.6;color:var(--ink);
  /* a stranger's line breaks are kept, but a wall of them cannot stretch the card */
  white-space:pre-wrap;overflow-wrap:anywhere}
.gbwho{margin:14px 0 0;font-family:var(--body);font-size:10.5px;font-weight:600;
  letter-spacing:.22em;text-transform:uppercase;color:var(--ink);
  overflow-wrap:anywhere}
.gbwhen{display:block;margin-top:5px;font-weight:400;letter-spacing:.14em;
  color:var(--ink);opacity:.55}
@media(max-width:560px){ .gbnote-card{padding:18px 18px 15px} }

footer{padding:calc(var(--sect) * .7) 0 calc(var(--sect) * .9);text-align:center;color:var(--ink);font-size:11px;
  letter-spacing:.26em;text-transform:uppercase}
footer .amp2{font-family:var(--display);font-style:italic;font-size:1.6rem;
  text-transform:none;letter-spacing:0;color:var(--accent);display:block;margin-bottom:14px}
footer .credit{display:block;margin-top:26px;padding-top:20px;font-size:10px;
  letter-spacing:.16em;opacity:.75;line-height:2;
  border-top:1px solid var(--line);max-width:520px;margin-left:auto;margin-right:auto}
footer .credit a{color:inherit;text-decoration:none;
  border-bottom:1px solid var(--line);transition:.2s}
footer .credit a:hover{color:var(--accent);border-color:var(--accent)}

/* ---------- LIGHTBOX ---------- */
.lb{position:fixed;inset:0;z-index:90;background:rgba(20,15,10,.96);display:none;
  align-items:center;justify-content:center;padding:6vh 7vw;cursor:zoom-out;
  backdrop-filter:blur(6px)}
.lb.on{display:flex}
.lb img{max-height:88svh;max-width:100%;object-fit:contain;border-radius:3px;
  cursor:default;box-shadow:0 30px 80px rgba(0,0,0,.5)}

.lbnav,.lbclose{position:absolute;z-index:2;cursor:pointer;
  display:flex;align-items:center;justify-content:center;
  border:1px solid rgba(255,255,255,.22);background:rgba(255,255,255,.07);
  color:#fff;border-radius:50%;transition:.22s;backdrop-filter:blur(8px)}
.lbnav:hover,.lbclose:hover{background:rgba(255,255,255,.9);color:#141414;
  border-color:transparent}
.lbnav:focus-visible,.lbclose:focus-visible{outline:2px solid #fff;outline-offset:3px}
.lbnav{width:52px;height:52px;top:50%;transform:translateY(-50%)}
.lbnav.prev{left:clamp(10px,2.4vw,32px)}
.lbnav.next{right:clamp(10px,2.4vw,32px)}
.lbclose{width:44px;height:44px;top:clamp(14px,2.4vw,28px);right:clamp(14px,2.4vw,28px)}
.lbnav svg,.lbclose svg{width:20px;height:20px;fill:none;stroke:currentColor;
  stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
.lbcount{position:absolute;bottom:clamp(14px,3vw,32px);left:0;right:0;text-align:center;
  z-index:2;font-family:var(--body);font-size:11px;font-weight:600;letter-spacing:.28em;
  color:rgba(255,255,255,.7)}
@media(max-width:620px){
  .lbnav{width:44px;height:44px}
  .lb{padding:9vh 4vw}
}

@media(prefers-reduced-motion:reduce){
  .slide.on img{animation:none}
  *{transition-duration:.01ms !important}
}

/* ---------- call to action ---------- */
.btn{display:inline-block;margin-top:26px;font-family:var(--body);font-size:11px;
  font-weight:600;letter-spacing:.26em;text-transform:uppercase;text-decoration:none;
  padding:16px 40px;border:1px solid var(--accent);background:var(--accent);color:#fff;
  border-radius:3px;transition:.25s}
.btn:hover{background:transparent;color:var(--accent)}
.btn.ghost{background:transparent;color:var(--accent)}
.btn.ghost:hover{background:var(--accent);color:#fff}

/* ---------- gallery page ---------- */
.gallerypage{padding:calc(var(--sect) * 1.3) 0 var(--sect);text-align:center;
  background:var(--bg-alt)}

/* Gallery header with the film running behind it. Full bleed, so the page
   opens on something moving rather than a block of beige. */
.gallerypage.filmhead{position:relative;overflow:hidden;background:#241c15;
  min-height:clamp(520px,78svh,780px);display:flex;flex-direction:column;
  justify-content:center;padding:calc(var(--sect) * 1.2) 0}
.headfilm{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  object-position:center 38%;z-index:0}
.headscrim{position:absolute;inset:0;z-index:1;
  background:linear-gradient(180deg,rgba(20,14,9,.62),rgba(20,14,9,.34) 42%,
                             rgba(20,14,9,.72))}
.filmhead .wrap{position:relative;z-index:2}
.filmhead .backlink{color:rgba(255,255,255,.78)}
.filmhead .backlink:hover{color:#fff}
.filmhead .eyebrow{color:rgba(255,255,255,.9)}
.filmhead .h2{color:#fff;text-shadow:0 2px 30px rgba(0,0,0,.4)}
.filmhead .h2 em{color:#E8C49A}
.filmhead .sub{color:rgba(255,255,255,.82)}
.filmhead .count{color:rgba(255,255,255,.66)}
.headquote{margin:22px auto 0;max-width:34ch;font-family:var(--display);
  font-style:italic;font-weight:300;font-size:clamp(1.15rem,2.4vw,1.7rem);
  line-height:1.4;color:rgba(255,255,255,.94);
  text-shadow:0 2px 22px rgba(0,0,0,.42)}
.headquote cite{display:block;margin-top:14px;font-family:var(--body);
  font-style:normal;font-size:10px;font-weight:600;letter-spacing:.3em;
  text-transform:uppercase;color:rgba(255,255,255,.62)}
.filmhead .orn i{background:rgba(255,255,255,.32)}
.filmhead .ornmark .petal{stroke:#E8C49A}
.filmhead .ornmark .pip{fill:#E8C49A}

/* ---------- THE SLIDESHOW ON THE GALLERY HEADER ----------
   It sits behind the title and the quote, in the same full-bleed header the
   still used to fill, so nothing about that layout changes -- only what is
   moving behind it. */
.slideshow{position:absolute;inset:0;z-index:0}
.slideshow .slide{position:absolute;inset:0;opacity:0;transition:opacity 1s ease}
.slideshow .slide.on{opacity:1}
/* Where each photograph sits in its frame: 0% shows its top edge, 100% its
   bottom. Set per slide below, or dialled live at gallery.html?tune=1 */
.slideshow .slide img{width:100%;height:100%;object-fit:cover;display:block;
  object-position:center var(--slidepos, 50%)}
/* Set by eye at gallery.html?tune=1 -- a sixth slide would fall back to the
   50% in the rule above until it is given its own line here. */
.slideshow .slide:nth-child(1){--slidepos:34%}
.slideshow .slide:nth-child(2){--slidepos:50%}
.slideshow .slide:nth-child(3){--slidepos:22%}
.slideshow .slide:nth-child(4){--slidepos:24%}
.slideshow .slide:nth-child(5){--slidepos:39%}

/* ---------- THE HEADER WORDS, BACK ----------
   They were put away when this page had no other heading on it and the
   photographs were the whole point. The page has chapters now, so opening on a
   picture with nothing to read left it with no voice at all.

   Nothing is clickable up here, so the block ignores the pointer and the
   arrows underneath it keep working. */
.filmhead .wrap{pointer-events:none}

/* The scrim has words to hold again, so it goes back to carrying them: darker
   at the top and bottom, lighter through the middle where the photograph is. */
.gallerypage.filmhead .headscrim{background:
  linear-gradient(rgba(20,14,9,.42), rgba(20,14,9,.20) 38%, rgba(20,14,9,.52))}

.slidearrow{position:absolute;top:50%;transform:translateY(-50%);z-index:4;
  width:52px;height:52px;border-radius:50%;cursor:pointer;
  display:flex;align-items:center;justify-content:center;
  background:rgba(20,14,8,.30);border:1px solid rgba(255,255,255,.45);
  backdrop-filter:blur(6px);transition:.25s}
.slidearrow svg{width:22px;height:22px;fill:none;stroke:#fff;stroke-width:1.7;
  stroke-linecap:round;stroke-linejoin:round}
.slidearrow:hover{background:rgba(20,14,8,.5);border-color:#fff}
.slidearrow:focus-visible{outline:2px solid #fff;outline-offset:3px}
.slidearrow.prev{left:clamp(10px,2.4vw,30px)}
.slidearrow.next{right:clamp(10px,2.4vw,30px)}

.slidedots{position:absolute;bottom:clamp(14px,2.4vh,26px);left:50%;
  transform:translateX(-50%);z-index:4;display:flex;gap:10px}
.slidedots button{width:30px;height:30px;border:0;background:none;padding:0;
  cursor:pointer;display:flex;align-items:center;justify-content:center}
.slidedots button::after{content:"";width:9px;height:9px;border-radius:50%;
  border:1.5px solid rgba(255,255,255,.85);background:transparent;
  box-shadow:0 1px 8px rgba(0,0,0,.35);transition:.32s cubic-bezier(.2,.7,.3,1)}
.slidedots button[aria-current="true"]::after{background:#fff;transform:scale(1.18);
  box-shadow:0 0 0 3px rgba(255,255,255,.22),0 1px 10px rgba(0,0,0,.4)}
.slidedots button:focus-visible::after{outline:2px solid #fff;outline-offset:4px}

/* the repositioning panel -- only ever built on gallery.html?tune=1 */
.tunebox{position:fixed;right:14px;bottom:14px;z-index:300;width:248px;
  background:rgba(255,255,255,.97);border:1px solid var(--line);border-radius:13px;
  box-shadow:0 10px 40px rgba(80,60,40,.2);padding:13px 15px 15px;
  font-family:var(--body);max-height:84vh;overflow:auto}
.tunetitle{font-size:9.5px;font-weight:600;letter-spacing:.22em;text-transform:uppercase;
  color:var(--ink);margin-bottom:10px}
.tunerow{margin:10px 0}
.tunerow label{display:flex;justify-content:space-between;font-size:10.5px;
  font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:#6B5D50;
  margin-bottom:5px}
.tunerow label b{color:var(--ink);font-variant-numeric:tabular-nums}
.tunerow input{width:100%;accent-color:var(--accent)}
.tunebox button{width:100%;margin-top:12px;padding:9px 0;border:0;border-radius:8px;
  background:var(--accent);color:#fff;font-family:var(--body);font-size:10px;
  font-weight:600;letter-spacing:.14em;text-transform:uppercase;cursor:pointer}
.tunebox pre{display:none;margin:10px 0 0;padding:9px;border-radius:8px;
  background:var(--bg);border:1px solid var(--line);color:var(--ink);
  font-family:ui-monospace,Consolas,monospace;font-size:10px;line-height:1.6;
  white-space:pre-wrap}

/* ---------- CHOOSING WHAT TO REMOVE ----------
   gallery.html?prune=1 only. Every tile wears its filename, clicking marks it,
   and the panel writes out the rename commands. Invisible to a visitor. */
.prtag{position:absolute;left:0;right:0;bottom:0;padding:6px 7px;
  background:rgba(20,14,9,.84);color:#fff;
  font-family:ui-monospace,Consolas,monospace;font-size:10.5px;
  text-align:center;pointer-events:none;word-break:break-all}
html.pruning .grid figure{cursor:pointer}
html.pruning .grid figure.marked img{opacity:.26;filter:grayscale(1)}
html.pruning .grid figure.marked{outline:3px solid #B0402B;outline-offset:-3px}
html.pruning .grid figure.marked .prtag{background:#B0402B}
html.pruning .grid figure.marked::after{content:"REMOVE";position:absolute;
  top:8px;left:8px;padding:3px 7px;border-radius:3px;background:#B0402B;color:#fff;
  font-family:var(--body);font-size:9px;font-weight:600;letter-spacing:.16em}
html.pruning.hidemarked .grid figure.marked{display:none}
html.pruning.freeonly .grid figure.elsewhere{display:none}
/* The back-to-top button is fixed bottom right, exactly where the panel is,
   and was sitting on its lower corner. Nothing to scroll back to while you
   are choosing anyway. */
html.pruning .totop{display:none}
.prbar{position:fixed;top:0;left:0;right:0;z-index:400;
  background:#B0402B;color:#fff;padding:11px 18px;text-align:center;
  font-family:var(--body);font-size:12.5px;letter-spacing:.02em;
  box-shadow:0 2px 14px rgba(0,0,0,.22)}
.prbar b{font-weight:600}
.prbar i{font-style:normal;opacity:.82}
.prbar span{display:inline-block;padding:1px 9px;margin:0 3px;border-radius:9px;
  background:rgba(255,255,255,.19);font-weight:600;font-variant-numeric:tabular-nums}
body.hasprbar .topbar{top:var(--prbarh,44px)}
body.hasprbar{padding-top:var(--prbarh,44px)}
@media(max-width:700px){
  .prbar{font-size:11px;padding:9px 12px}
  .prbar i{display:none}
}
.prunebox .prquiet{background:transparent;color:#6B5D50;
  border:1px solid var(--line);margin-top:7px}
.prunebox label b{color:var(--accent);font-variant-numeric:tabular-nums}
.prused{position:absolute;top:8px;right:8px;max-width:70%;padding:3px 7px;
  border-radius:3px;background:rgba(169,131,92,.94);color:#fff;
  font-family:var(--body);font-size:9px;font-weight:600;letter-spacing:.06em;
  text-align:right;pointer-events:none;line-height:1.35}
.prwarn{display:none;margin-top:10px;padding:9px 10px;border-radius:8px;
  background:rgba(176,64,43,.09);border:1px solid rgba(176,64,43,.4);
  color:#8C3220;font-size:10px;line-height:1.55}
.prwarn b{display:block;margin-bottom:5px}
.prunebox .prfold{display:flex;align-items:center;justify-content:space-between;
  gap:10px;width:100%;padding:0;margin:0 0 4px;border:0;background:transparent;
  color:var(--ink);cursor:pointer;text-align:left;
  font-family:var(--body);letter-spacing:normal;text-transform:none}
.prunebox .prfold .tunetitle{margin:0;color:var(--ink)}
.prunebox .prchev{font-size:9px;color:var(--accent);line-height:1}
.prunebox .prfold:hover .tunetitle{color:var(--accent)}
.prunebox.folded > *:not(.prfold){display:none}
.prunebox.folded{padding-bottom:11px;width:auto;min-width:214px}

.prunebox label{display:flex;align-items:center;gap:8px;font-size:11px;
  font-weight:600;letter-spacing:.04em;color:#6B5D50;margin:10px 0;cursor:pointer;
  text-transform:none}
.prunebox label input{width:auto;accent-color:var(--accent)}
.prcount{font-size:22px;font-family:var(--display);color:var(--ink);
  font-variant-numeric:tabular-nums;margin:4px 0 2px}
.prcount span{color:#B0402B}
.prunebox textarea{width:100%;margin-top:8px;padding:8px;border-radius:8px;
  border:1px solid var(--line);background:var(--bg);color:var(--ink);
  font-family:ui-monospace,Consolas,monospace;font-size:10px;line-height:1.55;
  resize:vertical}
.prnote{font-size:10.5px;line-height:1.6;color:#6B5D50;margin-top:10px}
.prnote code{font-family:ui-monospace,Consolas,monospace;background:var(--bg);
  border:1px solid var(--line);border-radius:3px;padding:1px 4px}

/* a phone has no room for arrows over the picture; the dots and a swipe do */
@media(max-width:640px){
  .slidearrow{width:42px;height:42px}
  .slidearrow svg{width:18px;height:18px}
}
.backlink{display:inline-block;font-family:var(--body);font-size:10px;font-weight:600;
  letter-spacing:.3em;text-transform:uppercase;color:var(--ink);text-decoration:none;
  margin-bottom:22px;transition:.2s}
.backlink:hover{color:var(--accent)}
.count{font-family:var(--body);font-size:11px;letter-spacing:.28em;text-transform:uppercase;
  color:var(--ink);margin-top:18px}


/* ---------------------------------------------------------------------------
   The Coming Soon curtain. Built by gate.js, switched on in Pages CMS.

   .gating goes on <html> while the page is waiting to find out whether the
   curtain is up, and stays there while it is. Hiding the body's children rather
   than the body itself leaves the cover -- which is one of those children --
   free to show. display rather than visibility so nothing below is laid out,
   and the page cannot be scrolled behind the cover.
   --------------------------------------------------------------------------- */
html.gating{overflow:hidden}
html.gating body>*:not(.gate){display:none!important}

.gate{position:fixed;inset:0;z-index:1000;background:var(--bg);
  display:flex;align-items:center;justify-content:center;
  padding:clamp(24px,6vw,64px);
  /* the same soft warmth the sections have, so the cover belongs to the site */
  background-image:radial-gradient(72% 58% at 50% 34%,rgba(255,255,255,.75),transparent 64%);
  animation:gatein .5s ease both}
.gate.opening{animation:gateout .42s ease both;pointer-events:none}
@keyframes gatein{from{opacity:0}to{opacity:1}}
@keyframes gateout{from{opacity:1}to{opacity:0}}

.gatebox{width:100%;max-width:520px;text-align:center}

.gateeyebrow{font-family:var(--body);font-size:11px;font-weight:600;
  letter-spacing:.42em;text-transform:uppercase;color:var(--accent);margin:0}

.gate .orn{margin:14px 0 18px}

.gatetitle{font-family:var(--display);font-weight:300;
  font-size:clamp(42px,7.4vw,68px);line-height:1.04;letter-spacing:.01em;
  color:var(--ink);margin:0}
.gatetitle em{font-style:italic;color:var(--accent)}

.gateline{font-family:var(--body);font-size:15px;line-height:1.62;
  color:var(--muted);margin:18px auto 0;max-width:38ch}

.gateform{margin-top:30px}
.gatehint{display:block;font-family:var(--body);font-size:10.5px;font-weight:600;
  letter-spacing:.24em;text-transform:uppercase;color:var(--accent);
  margin-bottom:11px}

/* The box and its button read as one piece, the way the guestbook form does. */
.gaterow{display:flex;gap:9px;justify-content:center;flex-wrap:wrap}
.gatepw{flex:1 1 240px;min-width:0;max-width:300px;
  font-family:var(--body);font-size:15px;color:var(--ink);
  padding:13px 16px;background:var(--card);
  border:1px solid var(--line);border-radius:2px;outline:none;
  transition:border-color .2s ease,box-shadow .2s ease}
.gatepw:focus{border-color:var(--accent);
  box-shadow:0 0 0 3px rgba(169,131,92,.16)}

.gatego{font-family:var(--body);font-size:11px;font-weight:600;
  letter-spacing:.2em;text-transform:uppercase;color:#fff;
  padding:13px 26px;background:var(--accent);
  border:1px solid var(--accent);border-radius:2px;cursor:pointer;
  transition:background .2s ease,border-color .2s ease,opacity .2s ease}
.gatego:hover{background:var(--accent-deep);border-color:var(--accent-deep)}
.gatego:disabled{opacity:.55;cursor:default}

.gateerr{font-family:var(--body);font-size:13px;color:#9B4A3E;
  margin:12px 0 0;min-height:1.2em}

/* A short shake says "no" faster than reading the line under the box does. */
.gate.wrong .gatepw{border-color:#9B4A3E;animation:gateshake .34s ease}
@keyframes gateshake{
  0%,100%{transform:translateX(0)}
  20%{transform:translateX(-6px)} 40%{transform:translateX(5px)}
  60%{transform:translateX(-3px)} 80%{transform:translateX(2px)}}

@media (prefers-reduced-motion:reduce){
  .gate,.gate.opening{animation:none}
  .gate.wrong .gatepw{animation:none}}
