/* ============================================================================
   Every rule the site needs. There is no engine and no canvas any more —
   the page is ordinary flow from the hero to the venue block.
   ========================================================================== */

*, *::before, *::after { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--s-bg);
  color: var(--s-ink);
  font-family: var(--s-font-micro);
  font-size: var(--s-body);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}
img { max-width: 100%; display: block; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }

/* Shared micro register. Every label on the page is one of these. */
.micro {
  font-family: var(--s-font-micro);
  font-size: var(--s-micro);
  font-weight: 500;
  letter-spacing: var(--s-micro-track);
  text-transform: uppercase;
  color: var(--s-ink-soft);
}
.macro {
  font-family: var(--s-font-macro);
  font-size: var(--s-macro);
  font-weight: 400;
  line-height: 1.05;
  letter-spacing: -0.015em;
  margin: 0;
}

/* Skip link — the page is one long scroll, so this matters. */
.skip {
  position: absolute; left: -9999px; top: 0; z-index: 999;
  background: var(--s-accent); color: #fff; padding: 12px 18px;
}
.skip:focus { left: 16px; }

:focus-visible { outline: 2px solid var(--s-accent-soft); outline-offset: 3px; }

/* ---------------------------------------------------------------------------
   1. Explore Benaka — one film of the real property
   Two things stood here before and both were rejected: a scroll-scrubbed
   canvas driven by scrub-engine.js, then six rendered legs laid out zigzag.
   With them went every .sw-* override, the per-beat copy placement, the scrim
   kill, the bounded text-shadow, the canvas veil and the .leg grid — around
   300 lines that no longer had an element to style.

   What replaces them is footage shot on the property. Note what it does NOT
   carry: no tint, no scrim, nothing over the picture at all. The wash on the
   rendered legs existed to take the sheen off generated footage. This is the
   place itself and gets no help.
   ------------------------------------------------------------------------ */
.explore {
  position: relative; z-index: 30;
  /* The forest ground, the same one the brochure's closing band used, so this
     stays the one dark chapter between the ivory hero above and the ivory
     gallery below. Without this it inherits the near-black :root tokens and
     sits outside the theme entirely. */
  --s-bg:          #1c2f26;
  --s-bg-raised:   #16261e;
  --s-line:        #33493d;
  --s-ink:         #f1ece1;
  --s-ink-soft:    #b3bfb5;
  --s-ink-faint:   #8b9990;
  --s-accent:      #dd9169;
  background: var(--s-bg);
  color: var(--s-ink);
  padding: clamp(56px, 9vh, 130px) var(--s-gut);
}
.explore__intro { max-width: 62ch; margin: 0 auto clamp(30px, 4vh, 54px); text-align: center; }
.explore__intro .micro { display: block; color: var(--s-accent); }
.explore__intro .macro { margin: 14px 0 0; }
.explore__line { color: var(--s-ink-soft); margin: 18px auto 0; max-width: 46ch; }

/* 53:30 is the file's exact display aspect (848x480), so the frame is the
   picture and there is no letterbox to hide. The width cap is not taste: the
   source is 848px wide, and past about 1000 the softening starts to show. */
.explore__film {
  margin: 0 auto; position: relative; overflow: hidden;
  max-width: 1000px; aspect-ratio: 53 / 30;
  background: var(--s-bg-raised);
  border: 1px solid var(--s-line);
}
.explore__film video { width: 100%; height: 100%; object-fit: cover; display: block; }

.explore__sound {
  position: absolute; right: 12px; bottom: 12px;
  min-height: 44px; padding: 0 18px;          /* 44 so a thumb can land on it */
  border: 1px solid color-mix(in srgb, var(--s-accent) 50%, transparent);
  border-radius: 999px; cursor: pointer;
  background: color-mix(in srgb, #0e1411 62%, transparent);
  color: var(--s-ink);
  backdrop-filter: blur(6px);
  transition: background .2s ease, border-color .2s ease;
}
.explore__sound:hover, .explore__sound:focus-visible {
  background: color-mix(in srgb, #0e1411 82%, transparent);
  border-color: var(--s-accent);
}

@media (max-width: 860px) {
  .explore { padding: clamp(40px, 7vh, 80px) var(--s-gut); }
  .explore__film { max-width: none; }
}

/* ---------------------------------------------------------------------------
   2. The mark and the section menu
   The round logo fixed top left, which doubles as the way home, and the
   section menu top right: a hamburger up to 820px, a quiet row of links above
   it. The menu wears forest glass, so nothing up there needs to change ink
   between the hero and the ivory pages.

   The menu's 820px is deliberately NOT the hero's 700px. Seven links in a row
   need about 615px plus the mark, and between 701 and ~720 the row ran 8px
   into the logo. Keep NAV_Q in site.js in step with this number.
   ------------------------------------------------------------------------ */
.brand {
  position: fixed; z-index: 120;
  top: clamp(12px, 2vw, 22px); left: clamp(14px, 2.4vw, 30px);
  width: 56px; height: 56px; border-radius: 50%;
  display: block;
  /* A soft lift so the disc separates from an ivory page as well as from the
     photograph. Not a scrim: it sits under the logo, not over any picture. */
  box-shadow: 0 1px 2px rgba(20, 24, 20, .18), 0 6px 18px rgba(20, 24, 20, .20);
  transition: transform var(--s-quick);
}
.brand img { width: 100%; height: 100%; display: block; }
.brand:hover { transform: scale(1.04); }
.brand:focus-visible { outline-offset: 4px; }

.nav {
  position: fixed; z-index: 120;
  top: clamp(20px, 2.6vw, 30px); right: clamp(16px, 3vw, 34px);
}
.nav__toggle, .nav__share { display: none; }
.nav__list {
  list-style: none; margin: 0; padding: 4px 8px;
  display: flex; gap: 2px;
  background: color-mix(in srgb, #1c2f26 62%, transparent);
  border: 1px solid color-mix(in srgb, #f2ede2 26%, transparent);
  border-radius: var(--s-radius);
  backdrop-filter: blur(6px);
}
.nav__list a {
  display: block; padding: 8px 11px;
  font-family: var(--s-font-micro);
  font-size: var(--s-micro); font-weight: 600;
  letter-spacing: var(--s-micro-track); text-transform: uppercase;
  color: #f2ede2; text-decoration: none;
  border-radius: var(--s-radius);
  transition: background var(--s-quick), color var(--s-quick);
}
.nav__list a:hover, .nav__list a:focus-visible {
  background: color-mix(in srgb, #f2ede2 12%, transparent); color: #fff;
}
/* The logo is already the way home on a wide screen. */
.nav__home { display: none; }
/* Tighter tracking where the row only just fits beside the mark. */
@media (max-width: 1000px) and (min-width: 821px) {
  .nav__list a { padding: 8px 8px; letter-spacing: .12em; }
}

@media (max-width: 700px) {
  .brand { width: 44px; height: 44px; }
}

@media (max-width: 820px) {
  /* Two icon-only squares, stacked: the hamburger, and under it Share. Same
     size and the same forest glass, so they read as one control column. */
  .nav { top: 14px; right: 14px; display: flex; flex-direction: column; gap: 8px; }
  .nav__toggle, .nav__share {
    position: relative; z-index: 2;
    display: grid; place-items: center;
    width: 44px; height: 44px; padding: 0;     /* 44 so a thumb can land on it */
    color: #f2ede2;
    background: color-mix(in srgb, #1c2f26 62%, transparent);
    border: 1px solid color-mix(in srgb, #f2ede2 26%, transparent);
    border-radius: var(--s-radius);
    backdrop-filter: blur(6px);
  }
  .nav__share svg { display: block; }
  /* The panel covers the page; the share square must not float over it. */
  .nav.is-open .nav__share { display: none; }
  .nav__bars { display: grid; gap: 4px; width: 18px; }
  .nav__bars i {
    display: block; height: 1.5px; background: currentColor; border-radius: 1px;
    transition: transform .3s var(--s-ease), opacity .2s;
  }
  .nav.is-open .nav__bars i:nth-child(1) { transform: translateY(5.5px) rotate(45deg); }
  .nav.is-open .nav__bars i:nth-child(2) { opacity: 0; }
  .nav.is-open .nav__bars i:nth-child(3) { transform: translateY(-5.5px) rotate(-45deg); }

  /* The open panel: the forest ground, full height, section names in the
     serif. It is the one place the macro register is used for navigation,
     because on a phone these are the targets a thumb is aiming for. */
  .nav__list {
    position: fixed; inset: 0; z-index: 1;
    flex-direction: column; justify-content: center; gap: 0;
    padding: 88px var(--s-gut) 48px;
    background: #1c2f26; border: 0; border-radius: 0;
    backdrop-filter: none;
    opacity: 0; visibility: hidden;
    transition: opacity .3s var(--s-ease), visibility .3s;
  }
  .nav.is-open .nav__list { opacity: 1; visibility: visible; }
  .nav__home { display: block; }
  .nav__list li + li { border-top: 1px solid #33493d; }
  .nav__list a {
    padding: 14px 0;
    font-family: var(--s-font-macro); font-weight: 400;
    font-size: clamp(1.7rem, 8vw, 2.3rem); line-height: 1.1;
    letter-spacing: -0.01em; text-transform: none;
    border-radius: 0;
  }
  .nav__list a:hover, .nav__list a:focus-visible { background: none; color: #e9b795; }
  body.nav-open { overflow: hidden; }
}
@media (prefers-reduced-motion: reduce) {
  .nav__list, .nav__bars i { transition: none; }
}

/* ===========================================================================
   3. THE EDITORIAL BAND — the brochure the visitor reads before the film
   starts. Same stacking contract as .after: its own level and an opaque ground,
   because the engine's fixed layers paint the whole document underneath it.
   ======================================================================== */
.before {
  position: relative; z-index: 30;
  background: var(--s-bg);
  color: var(--s-ink);
}

/* --- hero: one image at full height, the name over it ----------------------
   The wash is one-sided and clears well before the pool and the house, which
   are what the picture is of. Its stops are measured against this particular
   photograph -- see the phone override further down. */
.ed-hero__frame {
  position: relative;
  /* No pixel cap. It used to be min(88svh, 820px), which stopped the
     photograph at 820px on any taller screen and left the mosaic sliced by the
     fold — at 2560x1440 the hero filled only 57% of the display. A pure
     viewport unit peeks by the same proportion at every size. */
  min-height: 88svh;
  display: grid;
  isolation: isolate;
}
.ed-hero__img {
  position: absolute; inset: 0;
  /* Centred, because each viewport is now served a source already cut to its
     shape: the 60%/55% bias existed to keep an arch signboard in frame when a
     single 16:9 photograph had to serve every width. */
  width: 100%; height: 100%; object-fit: cover; object-position: 50% 50%;
  z-index: -2;
}
/* The hero's living loop, on phones AND desktop now: each is served the clip
   cut for its own still (site.js picks by the same 700px query the <picture>
   uses). It sits directly over the still, at the same z-index but later in the
   DOM, so it paints on top of it while the gradient wash (-1) stays above
   both. Hidden until it can actually play, so a stalled download never shows a
   black rectangle where the photograph was. */
.ed-hero__loop {
  position: absolute; inset: 0; z-index: -2;
  width: 100%; height: 100%; object-fit: cover; object-position: 50% 50%;
  opacity: 0; transition: opacity .9s var(--s-ease);
  pointer-events: none;
}
.ed-hero__loop.is-live { opacity: 1; }
@media (prefers-reduced-motion: reduce) { .ed-hero__loop { display: none; } }

.ed-hero__frame::after {
  content: ''; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background: linear-gradient(100deg,
    rgba(14, 20, 17, 0.74) 0%,
    rgba(14, 20, 17, 0.48) 34%,
    rgba(14, 20, 17, 0.07) 62%,
    transparent 78%);
}
.ed-hero__copy {
  align-self: end;
  padding: var(--s-gut) var(--s-gut) clamp(46px, 8vh, 96px);
  max-width: min(46ch, 100%);
  color: #f3efe6;
}
.ed-hero__copy .micro { display: block; color: rgba(243, 239, 230, .72); }
.ed-hero__name {
  font-family: var(--s-font-macro); font-weight: 400;
  /* Sized off the viewport so the two lines the <br> creates are the only two. */
  font-size: clamp(2.6rem, 6.4vw, 5.2rem); line-height: .96;
  letter-spacing: -0.02em; margin: 20px 0 0; color: #f6f2e9;
  text-wrap: nowrap;
}
@supports not (text-wrap: nowrap) { .ed-hero__name { white-space: nowrap; } }
.ed-hero__name em { font-style: italic; color: #e9b795; }
.ed-hero__line {
  font-family: var(--s-font-macro); font-size: clamp(1.1rem, 2.2vw, 1.55rem);
  line-height: 1.35; margin: 22px 0 0; max-width: 24ch; color: #ece7dc;
}
.ed-hero__where { margin: 24px 0 0 !important; color: rgba(243, 239, 230, .6) !important; }

/* The strip: the grounds and the pool as a live mosaic, with one short note.
   It used to sit directly under the hero; it now follows the story section, so
   the visitor is told what the place is before being handed a wall of it. */
.ed-strip {
  display: grid; gap: clamp(18px, 3vw, 40px);
  grid-template-columns: minmax(0, 0.72fr) minmax(0, 2.28fr);
  align-items: start;
  padding: clamp(30px, 5vw, 68px) var(--s-gut);
  /* A rule ABOVE, not below: the grounds now follow the story, and what needs
     separating is the two ivory sections from each other. Below it is the
     forest band, which separates itself. */
  border-top: 1px solid var(--s-line);
}
.ed-strip__intro .micro { display: block; }
.ed-strip__h {
  font-family: var(--s-font-macro); font-weight: 400;
  font-size: clamp(1.5rem, 2.6vw, 2.3rem); line-height: 1.06;
  letter-spacing: -0.015em; margin: 16px 0 0;
}
.ed-strip__note {
  margin: 18px 0 0; color: var(--s-ink-soft); max-width: 32ch;
  font-size: calc(var(--s-body) * .96);
}
.ed-strip__hint { margin: 26px 0 0; color: var(--s-ink-faint); }
/* The mosaic reuses the gallery's .tile/.tiles rules for the cell shapes and
   the turn-over transition, and only overrides the grid it sits on: taller
   rows and wider columns than the contact-sheet gallery, because these are
   hero-sized pictures rather than thumbnails. */
.ed-mosaic.tiles {
  /* FOUR columns, not auto-fill. Auto-fill produced eight narrow columns at
     1920 and the wide/tall spans vanished into a filmstrip of thumbnails — the
     asymmetry only reads when a span-2 cell is a meaningful fraction of the
     row. Rows are sized off the viewport so the cells stay hero-sized. */
  grid-template-columns: repeat(4, minmax(0, 1fr));
  grid-auto-rows: clamp(96px, 9.4vw, 178px);
  gap: clamp(8px, .8vw, 14px);
}
.ed-mosaic.tiles .tile { background: var(--s-bg-raised); }
.ed-mosaic.tiles .tile figcaption { display: none; }   /* the note carries the words */

@media (max-width: 900px) {
  .ed-strip { grid-template-columns: 1fr; }
}
@media (max-width: 700px) {
  /* A QUARTER of what it was. Phones used to re-cut the mosaic into two
     columns at 26vw rows - ten rows, about 1,090px of a 390px screen, and the
     owner read it as tiles blown up far past their worth. Phones now keep the
     desktop's four columns, so every cell is half as wide and half as tall (a
     quarter of the area) and the band is about 270px tall.

     Four columns is also what HERO_SHAPES in site.js was solved for: 4+2+1+2+
     1+2+2+1+4+1 = 20 cells of area in five rows of four, flush, no hole. So the
     phone needs no shape overrides of its own any more. */
  .ed-mosaic.tiles {
    grid-auto-rows: 12.5vw;
    gap: 5px;
  }
}

/* PHONES: the gate photograph takes the whole screen with the name on it —
   svh, not vh, so the browser's own chrome cannot crop the bottom off it. The
   strip follows immediately, two frames across. */
@media (max-width: 700px) {
  .ed-hero__frame { min-height: 100svh; }
  /* No object-position override here any more. Phones are served the 9:16
     source by the <picture> element, so there is nothing to rescue from a
     landscape crop. */
  /* Deepened through the middle when the hero photograph changed. The old
     stops were cut against a dark arch picture; over a sunset frame the 12px
     "Coorg . Karnataka" line, which sits highest in the copy block where a
     bottom-up wash is weakest, measured 3.27:1 against the 4.5 that size needs.
     These are measured numbers, not taste - re-measure if the picture changes
     again rather than nudging them. */
  .ed-hero__frame::after {
    background: linear-gradient(to top,
      rgba(14, 20, 17, 0.90) 0%,
      rgba(14, 20, 17, 0.78) 30%,
      rgba(14, 20, 17, 0.58) 45%,
      rgba(14, 20, 17, 0.18) 68%,
      rgba(14, 20, 17, 0.26) 100%);
  }
  .ed-hero__copy { padding-bottom: clamp(54px, 12vh, 110px); }
  .ed-hero__name { font-size: clamp(2.7rem, 13vw, 4rem); }
}

/* --- story: the words alone -----------------------------------------------
   It used to sit beside three overlapping photographs and a line saying they
   were taken on the property. The owner took both out: the grounds band right
   under it already shows the place, and the story reads better on its own. */
.ed-story {
  padding: var(--s-section) var(--s-gut);
  border-top: 1px solid var(--s-line);
}
.ed-story__text .micro { display: block; margin-bottom: 20px; }
.ed-story__text p { color: var(--s-ink-soft); max-width: 40ch; margin: 22px 0 0; }
/* Wide screens: the heading on the left, the paragraph across from it on the
   right, both hung from the same top line. On its own in one column the story
   left the right half of a desktop page empty. */
@media (min-width: 901px) {
  .ed-story__text {
    display: grid; column-gap: clamp(40px, 7vw, 120px);
    grid-template-columns: minmax(0, 1.1fr) minmax(0, .9fr);
    align-items: end;
  }
  .ed-story__text .micro { grid-column: 1 / -1; }
  .ed-story__text .macro { grid-column: 1; max-width: 16ch; }
  .ed-story__text p      { grid-column: 2; margin: 0; font-size: calc(var(--s-body) * 1.06); }
}

/* ---------------------------------------------------------------------------
   4. Page sections after the film
   .before and .after each carry the light palette and their own stacking
   level, with the forest .explore band between them.
   ------------------------------------------------------------------------ */
.after {
  position: relative; z-index: 30;
  background: var(--s-bg);
  /* `color` is inherited as a COMPUTED value, so redeclaring --s-ink here is not
     enough on its own: body already computed the dark theme's cream and every
     heading below inherited that, invisible on ivory. The band has to restate
     the colour as well as the token. */
  color: var(--s-ink);
}
.section { padding: var(--s-section) var(--s-gut); }
.section__head { max-width: 62ch; margin-bottom: clamp(32px, 5vh, 64px); }
.section__head .micro { display: block; margin-bottom: 18px; }
.section__head p { color: var(--s-ink-soft); margin: 18px 0 0; max-width: 48ch; }

/* Reveal on entry — quiet, and never load-bearing. */
.reveal { opacity: 0; transform: translateY(18px); transition: opacity .7s var(--s-ease), transform .7s var(--s-ease); }
.reveal.in { opacity: 1; transform: none; }

/* ---------------------------------------------------------------------------
   5. Gallery — three stacks of prints, and the tile rules the mosaic needs
   ------------------------------------------------------------------------ */
/* The gallery used to be three columns of ~90px tiles showing all 38
   photographs at once. It is three stacks now: five prints laid over each
   other, the section's name beside them, and one control that opens the whole
   group in the lightbox.

   .tiles / .tile BELOW ARE STILL LOAD-BEARING. The hero mosaic up the page is
   built on them (.ed-mosaic.tiles), so they are not dead with the tile gallery
   gone — deleting them collapses the band under the story. */

/* --- the three rows ------------------------------------------------------ */
.stack-row {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, .85fr);
  align-items: center;
  gap: clamp(28px, 5vw, 90px);
}
.stack-row + .stack-row { margin-top: clamp(56px, 10vh, 128px); }
/* The zigzag. Ordering by column rather than reordering the DOM keeps the
   reading order — picture, then its words — intact for a screen reader and for
   keyboard focus, whichever side the pictures are on.

   The template is mirrored as well as the order: `order` alone moves the figure
   into the narrower column, which shrank the middle row's prints to 23% of the
   viewport against 31% either side of it. The pictures are the wide column on
   both sides. */
.stack-row:nth-child(even) {
  grid-template-columns: minmax(0, .85fr) minmax(0, 1.15fr);
}
.stack-row:nth-child(even) .stack       { order: 2; }
.stack-row:nth-child(even) .stack__words { order: 1; }

/* --- the stack of prints -------------------------------------------------- */
/* Every offset, width and angle below is a FIXED value per nth-child, not a
   random one. A random fan cannot be reviewed: it would compose differently on
   every load, and a bad overlap would be unreproducible. Angles stay inside
   +/-3.4deg — enough to read as prints put down by hand, short of the angular
   look the brief rules out.

   --spread scales every offset from one place, so phones can hold the same
   composition at a smaller amplitude instead of needing a second set of
   numbers. */
.stack {
  position: relative; margin: 0;
  aspect-ratio: 4 / 3;
  --spread: 1;
  cursor: pointer;
}
.stack__card {
  position: absolute;
  display: block;
  background: #fbf9f5;                 /* the mount, warmer than white */
  padding: 8px 8px 8px;
  border-radius: var(--s-radius);
  box-shadow: 0 1px 2px rgba(20, 24, 20, .10),
              0 14px 34px rgba(20, 24, 20, .13);
  transition: transform .55s var(--s-ease), box-shadow .55s var(--s-ease);
  will-change: transform;
}
.stack__card img { display: block; width: 100%; height: 100%; object-fit: cover; }

/* 1 is the top card and the largest; 2-5 sit at the four corners around it.

   EVERY SUPPORTING CARD KEEPS A CLEAR CORNER. The first cut of these numbers
   put card 5 at left 30%, wholly inside the hero card's span, so all that
   showed of it was a thin strip along the top — and in all three stacks that
   strip happened to be blown sky or a white ceiling, which read as an empty
   mount rather than a photograph. Card 1 spans x 16-76%, y 14-74% of the frame;
   keep the others outside that box on at least one side.

   `left`/`top` percentages resolve against the frame's width and height
   respectively, and the frame is 4:3, so a card's height as a fraction of the
   frame is (width x 3/4) / (3/4) = its width percentage for a 4:3 card. */
.stack__card:nth-child(1) {           /* hero: x 16-76%, y 14-74% */
  width: 60%; left: calc(16% * var(--spread)); top: calc(14% * var(--spread));
  aspect-ratio: 4 / 3; z-index: 5; transform: rotate(-1.6deg);
}
.stack__card:nth-child(2) {           /* top right, clear above and right */
  width: 38%; left: calc(58% * var(--spread)); top: 0;
  aspect-ratio: 4 / 3; z-index: 4; transform: rotate(3.1deg);
}
.stack__card:nth-child(3) {           /* bottom right, upright */
  width: 32%; left: calc(62% * var(--spread)); top: calc(40% * var(--spread));
  aspect-ratio: 3 / 4; z-index: 3; transform: rotate(-2.4deg);
}
.stack__card:nth-child(4) {           /* bottom left, clear of the hero's edge */
  width: 30%; left: 0; top: calc(48% * var(--spread));
  aspect-ratio: 4 / 3; z-index: 2; transform: rotate(2.6deg);
}
.stack__card:nth-child(5) {           /* top left, a clear column down its side */
  width: 26%; left: calc(1% * var(--spread)); top: calc(4% * var(--spread));
  aspect-ratio: 1 / 1; z-index: 1; transform: rotate(-3.4deg);
}

/* Hover/focus lifts the top card and eases the fan open a little. Focus is
   driven from the button, which is the thing that actually takes focus. */
.stack-row:hover .stack__card:nth-child(1),
.stack-row:focus-within .stack__card:nth-child(1) {
  transform: rotate(-1.6deg) translate(-6px, -8px);
  box-shadow: 0 2px 4px rgba(20, 24, 20, .12), 0 22px 48px rgba(20, 24, 20, .18);
}
.stack-row:hover .stack__card:nth-child(2),
.stack-row:focus-within .stack__card:nth-child(2) { transform: rotate(3.1deg) translate(8px, -5px); }
.stack-row:hover .stack__card:nth-child(3),
.stack-row:focus-within .stack__card:nth-child(3) { transform: rotate(-2.4deg) translate(9px, 7px); }
.stack-row:hover .stack__card:nth-child(4),
.stack-row:focus-within .stack__card:nth-child(4) { transform: rotate(2.6deg) translate(-9px, 6px); }
.stack-row:hover .stack__card:nth-child(5),
.stack-row:focus-within .stack__card:nth-child(5) { transform: rotate(-3.4deg) translate(-4px, -9px); }

@media (prefers-reduced-motion: reduce) {
  .stack__card { transition: none; }
  .stack-row:hover .stack__card, .stack-row:focus-within .stack__card { transform: none; }
  /* Without the rotations the fan would stack dead square, so keep the angles
     and drop only the movement. */
  .stack-row:hover .stack__card:nth-child(1),
  .stack-row:focus-within .stack__card:nth-child(1) { transform: rotate(-1.6deg); }
  .stack-row:hover .stack__card:nth-child(2),
  .stack-row:focus-within .stack__card:nth-child(2) { transform: rotate(3.1deg); }
  .stack-row:hover .stack__card:nth-child(3),
  .stack-row:focus-within .stack__card:nth-child(3) { transform: rotate(-2.4deg); }
  .stack-row:hover .stack__card:nth-child(4),
  .stack-row:focus-within .stack__card:nth-child(4) { transform: rotate(2.6deg); }
  .stack-row:hover .stack__card:nth-child(5),
  .stack-row:focus-within .stack__card:nth-child(5) { transform: rotate(-3.4deg); }
}

/* --- the words beside them ------------------------------------------------ */
.stack__eyebrow { display: block; color: var(--s-ink-faint); }
.stack__eyebrow::after {
  content: ''; display: inline-block; width: 34px; height: 1px;
  background: currentColor; margin-left: 12px; vertical-align: middle;
}
/* Forest green on the headings ONLY. The eyebrow, blurb and control stay the
   page's charcoal, so the gallery reads as the same document as the story and
   the footer rather than as a separate chapter. */
.stack__h {
  font-family: var(--s-font-macro); font-weight: 400;
  font-size: clamp(2rem, 4.2vw, 3.4rem); line-height: 1.02;
  letter-spacing: -0.015em; margin: 14px 0 0;
  max-width: 11ch;
  color: #1c2f26;
}
.stack__blurb { color: var(--s-ink-soft); margin: 18px 0 0; max-width: 34ch; }
.stack__cta {
  margin-top: clamp(22px, 3vh, 34px);
  display: inline-flex; align-items: center; gap: 12px;
  min-height: 44px; padding: 0;
  background: none; border: 0; cursor: pointer;
  font-family: var(--s-font-micro); font-size: .78rem;
  letter-spacing: .16em; text-transform: uppercase;
  color: var(--s-ink);
}
.stack__cta i { font-style: normal; transition: transform var(--s-quick); }
.stack__cta:hover i, .stack__cta:focus-visible i { transform: translateX(6px); }
.stack__cta:hover, .stack__cta:focus-visible { color: var(--s-accent); }

/* --- phones ---------------------------------------------------------------
   One column, stack above its words, and the prints stay LARGE. The brief is
   explicit that they must never collapse into a dense grid, so the amplitude
   comes down through --spread while the cards themselves keep their share of
   a full-width frame. */
@media (max-width: 860px) {
  /* BOTH selectors, and that is not belt-and-braces. A media query adds no
     specificity, so `.stack-row` alone (0,1,0) loses to the mirrored
     `.stack-row:nth-child(even)` (0,2,0) above and the middle row stayed in two
     columns on a phone — its stack squeezed into a third of the width while the
     words ran alongside. */
  .stack-row,
  .stack-row:nth-child(even) { grid-template-columns: 1fr; gap: clamp(22px, 4vh, 36px); }
  .stack-row:nth-child(even) .stack        { order: 0; }
  .stack-row:nth-child(even) .stack__words { order: 0; }
  .stack-row + .stack-row { margin-top: clamp(48px, 8vh, 88px); }
  .stack { aspect-ratio: 5 / 4; --spread: .92; }
  .stack__card { padding: 6px; }
  .stack__h { max-width: none; }
  .stack__blurb { max-width: 42ch; }
}

.tiles {
  display: grid;
  /* Narrower cells: three columns share the width now, and the groups hold 19,
     18 and 10 images, so the tiles have to be small enough to balance. */
  grid-template-columns: repeat(auto-fill, minmax(88px, 1fr));
  grid-auto-rows: 70px;
  grid-auto-flow: dense;   /* fill the holes the shape cycle leaves */
  gap: 6px;
}
.tile {
  position: relative; overflow: hidden; padding: 0;
  background: var(--s-bg-raised); border-radius: var(--s-radius);
  grid-column: span 1; grid-row: span 1;
}
.tile--w { grid-column: span 2; }
.tile--t { grid-row: span 2; }
.tile--b { grid-column: span 2; grid-row: span 2; }
.tile img {
  width: 100%; height: 100%; object-fit: cover;
  transition: transform .6s var(--s-ease), opacity .6s var(--s-ease);
  /* Full strength on the ivory ground. The old .82 was a dimmer for the dark
     theme, where a bright photograph punched a hole in the page; on paper the
     same value just reads as a faded print. */
  opacity: 1;
}
/* Live tiles: a tile turning over to show another photograph from its group.
   The outgoing image fades and lifts, the incoming one settles in behind it. */
.tile img.turning { opacity: 0; transform: scale(1.06); }
.tile.lit img { opacity: 1; }
.tile.lit { outline: 1px solid color-mix(in srgb, var(--s-accent) 55%, transparent); outline-offset: -1px; }
.tile.lit img { opacity: 1; }
.tile:hover img, .tile:focus-visible img { transform: scale(1.045); opacity: 1; }
.tile figcaption {
  position: absolute; left: 0; right: 0; bottom: 0; padding: 10px 12px;
  background: linear-gradient(transparent, color-mix(in srgb, var(--s-bg-sunk) 92%, transparent));
  opacity: 0; transition: opacity var(--s-quick); text-align: left;
}
.tile:hover figcaption, .tile:focus-visible figcaption { opacity: 1; }

@media (max-width: 720px) {
  .tiles { grid-template-columns: repeat(auto-fill, minmax(92px, 1fr)); grid-auto-rows: 74px; }
}

/* ---------------------------------------------------------------------------
   6. Lightbox — horizontal carousel over one group
   ------------------------------------------------------------------------ */
.lb {
  position: fixed; inset: 0; z-index: 200;
  background: color-mix(in srgb, var(--s-bg-sunk) 96%, transparent);
  display: flex; flex-direction: column;
  opacity: 0; visibility: hidden; transition: opacity .35s var(--s-ease), visibility .35s;
}
.lb.open { opacity: 1; visibility: visible; }
.lb__bar { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 18px var(--s-gut); }
.lb__close { padding: 8px 14px; border: 1px solid var(--s-line); border-radius: var(--s-radius); }
.lb__close:hover { border-color: var(--s-accent); color: var(--s-accent-soft); }
.lb__track {
  flex: 1; display: flex; gap: 0; overflow-x: auto; overflow-y: hidden;
  scroll-snap-type: x mandatory; scrollbar-width: none;
}
.lb__track::-webkit-scrollbar { display: none; }
.lb__slide {
  flex: 0 0 100%; scroll-snap-align: center;
  display: grid; place-items: center; padding: 0 var(--s-gut) 12px;
}
.lb__slide img { max-height: 76vh; width: auto; object-fit: contain; border-radius: var(--s-radius); }
.lb__foot { padding: 12px var(--s-gut) 26px; display: flex; justify-content: space-between; gap: 16px; align-items: center; }
.lb__nav { display: flex; gap: 8px; }
.lb__nav button { width: 42px; height: 42px; border: 1px solid var(--s-line); border-radius: var(--s-radius); display: grid; place-items: center; }
.lb__nav button:hover { border-color: var(--s-accent); color: var(--s-accent-soft); }
body.lb-open { overflow: hidden; }

/* ---------------------------------------------------------------------------
   7. Footer
   ------------------------------------------------------------------------ */
.foot { background: var(--s-bg-sunk); border-top: 1px solid var(--s-line); padding: var(--s-section) var(--s-gut) 40px; }
.foot__grid { display: grid; gap: clamp(32px, 6vw, 80px); grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }
.foot h2 { font-family: var(--s-font-macro); font-weight: 400; font-size: clamp(1.8rem, 4vw, 3rem); margin: 0 0 18px; }
.foot dl { margin: 0; }
.foot dt { margin-bottom: 6px; }
.foot dd { margin: 0 0 20px; color: var(--s-ink); }
.foot a { color: var(--s-ink); text-decoration: none; border-bottom: 1px solid var(--s-line); }
.foot a:hover { border-color: var(--s-accent); color: var(--s-accent-soft); }
/* The WhatsApp button is a link, so it has to opt back out of the footer's
   underlined-link treatment above or it paints ink on the accent. */
.foot a.btn, .foot a.btn:hover { color: #fff; border-bottom: 0; }
/* Instagram and Facebook: each platform's own mark in its own colours, its
   name, and the handle the visitor will find there, so it is clear where each
   link goes before it is tapped. Inline SVG - no icon font, no third-party
   script, nothing for the CSP to allow. Footer only: the venue block used to
   repeat them and the owner asked for one set. */
.social { display: grid; gap: 10px; }
.foot .social__link {
  display: inline-flex; align-items: center; gap: 10px;
  border-bottom: 0; width: max-content; min-height: 32px;
}
.social__link > span { border-bottom: 1px solid var(--s-line); }
.social__link:hover > span { border-color: var(--s-accent); }
.social__icon { width: 22px; height: 22px; flex: none; display: block; }
.social__handle { color: var(--s-ink-soft); }

.foot__bar { margin-top: 56px; padding-top: 22px; border-top: 1px solid var(--s-line); display: flex; justify-content: space-between; gap: 16px; flex-wrap: wrap; }

.btn {
  display: inline-flex; align-items: center; gap: 10px;
  padding: 15px 26px; border-radius: var(--s-radius);
  text-decoration: none;          /* .btn is used on <a> too: the map link */
  background: var(--s-accent); color: #fff;
  font-family: var(--s-font-micro); font-size: var(--s-micro); font-weight: 600;
  letter-spacing: var(--s-micro-track); text-transform: uppercase;
  transition: background var(--s-quick), transform var(--s-quick);
}
.btn:hover { background: var(--s-accent-soft); transform: translateY(-1px); }
.btn--ghost { background: none; color: var(--s-ink); border: 1px solid var(--s-line); }
.btn--ghost:hover { background: none; border-color: var(--s-accent); color: var(--s-accent-soft); }

/* ---------------------------------------------------------------------------
   8. The venue — last block on the page, after the footer.
   The name at the size it deserves, the address, both numbers, and one button
   out to Google Maps. No embedded map: an iframe would need google.com in the
   CSP and would put third-party cookies on a site that has none, and on a phone
   a plain link opens the visitor's own map app, which is what they want.
   ------------------------------------------------------------------------ */
.venue {
  border-top: 1px solid var(--s-line);
  padding: clamp(56px, 10vw, 110px) var(--s-gutter) clamp(64px, 11vw, 120px);
  text-align: center;
  display: grid; justify-items: center; gap: 22px;
}
.venue__mark { display: grid; justify-items: center; gap: 2px; }
.venue__name {
  font-family: var(--s-font-macro); font-weight: 400;
  /* Deliberately the largest type on the page after the hero. */
  font-size: clamp(3.2rem, 13vw, 7rem); line-height: .92;
  letter-spacing: -0.02em; color: var(--s-ink);
}
.venue__sub {
  font-family: var(--s-font-macro); font-style: italic;
  font-size: clamp(1.25rem, 4.6vw, 2.3rem); line-height: 1;
  color: var(--s-accent-soft);
}
.venue__where {
  font-style: normal; font-family: var(--s-font-micro);
  color: var(--s-ink-soft); line-height: 1.7; margin: 0;
}
.venue__contact { display: flex; flex-wrap: wrap; justify-content: center; gap: 10px 28px; }
.venue__tel {
  font-family: var(--s-font-macro); font-size: clamp(1.15rem, 4.2vw, 1.6rem);
  color: var(--s-ink); text-decoration: none;
  border-bottom: 1px solid var(--s-line); padding-bottom: 2px;
}
.venue__tel:hover { color: var(--s-accent-soft); border-color: var(--s-accent); }
.venue__wa { color: var(--s-ink-faint); margin: 0; max-width: 34ch; line-height: 2; }
.venue__wa a { color: var(--s-ink-soft); text-decoration: none; border-bottom: 1px solid var(--s-line); }
.venue__wa a:hover { color: var(--s-accent-soft); border-color: var(--s-accent); }
.venue__map { margin-top: 8px; }
