/* =========================================================
   index.css — HOMEPAGE-ONLY styles. Tokens, resets and corner
   marks live in includes/base.css (loaded before this file).
   ========================================================= */

/* =========================================================
   NAVIGATION
   ========================================================= */
/* Header (fixed CTAs, menu overlay, .cta, .btn, .brand) lives in
   includes/header.css and is loaded as a separate stylesheet. */

/* =========================================================
   HERO (inset image on cream)
   ========================================================= */
.hero {
  position: relative;
  width: 100%;
  height: 100vh;
  min-height: 640px;
  background: var(--cream);
  color: #fff;
  isolation: isolate;
  padding: 28px;
  z-index: 2; /* sits above the fixed black footer */
  /* compress smoothly when JS updates inline padding-l/r on scroll */
  transition: padding-left 0.12s linear, padding-right 0.12s linear;
}

.hero__frame {
  position: relative;
  width: 100%;
  height: 100%;
  border-radius: 25px;
  overflow: hidden;
  isolation: isolate;
}

.hero__bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  z-index: 0;
  transform: scale(1.04);
  animation: heroZoom 14s var(--ease) forwards;
  border-radius: 25px;
  /* Slideshow: all five stack in the same spot, JS toggles which one
     carries .is-active, and this opacity transition is what actually
     performs the crossfade between them. */
  opacity: 0;
  transition: opacity 1.6s ease;
}

.hero__bg.is-active {
  opacity: 1;
}

@keyframes heroZoom {
  to { transform: scale(1); }
}

.hero__vignette {
  position: absolute;
  inset: 0;
  z-index: 1;
  background:
    linear-gradient(180deg, rgba(0, 0, 0, 0.35) 0%, rgba(0, 0, 0, 0.05) 28%, rgba(0, 0, 0, 0.05) 60%, rgba(0, 0, 0, 0.6) 100%),
    radial-gradient(ellipse at 50% 60%, rgba(0,0,0,0) 30%, rgba(0,0,0,0.4) 100%);
  pointer-events: none;
  border-radius: 25px;
}

/* Scroll-driven black overlay over the house image */
.hero__darken {
  position: absolute;
  inset: 0;
  z-index: 1;
  background: #000;
  opacity: 0;
  pointer-events: none;
  border-radius: 25px;
  will-change: opacity;
}

/* Bottom-left location label */
.hero__locale {
  position: absolute;
  z-index: 3;
  left: 40px;
  bottom: 36px;
  display: inline-flex;
  align-items: center;
  gap: 22px;
  color: #fff;
  font-family: var(--sans);
  font-size: 36px;
  font-weight: 400;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  text-shadow: 0 2px 22px rgba(0, 0, 0, 0.45);
  line-height: 1;
}

.hero__locale-dot {
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: #fff;
  display: inline-block;
  animation: pulse 2.4s ease-in-out infinite;
  flex-shrink: 0;
}

/* =========================================================
   INTRO — text-only, left-aligned, on cream, with scroll reveal
   ========================================================= */
.intro {
  position: relative;
  background: var(--cream);
  color: var(--ink);
  padding: 96px 56px 96px;
  z-index: 2;
}

.intro__inner {
  max-width: none;
  margin: 0; /* span the full width of the page */
  text-align: left;
}

/* Body copy — large editorial serif. Each character is its own span and
   "fills with ink" from top to bottom as the user scrolls past. */
.intro__paragraph {
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(26px, 3.4vw, 58px);
  line-height: 1.15;
  letter-spacing: -0.012em;
  color: var(--ink);
  margin: 0;
  text-align: left;
}

/* Words are inline-block so a long word never breaks across letters mid-fill. */
.intro__word {
  display: inline-block;
  white-space: nowrap;
}

/* The "outline" letter sits beneath at low opacity. The ::before clones the
   letter on top in full ink, clipped from the bottom up via --fill (0 → 1). */
.intro__char {
  position: relative;
  display: inline-block;
  color: rgba(15, 15, 13, 0.12);
  --fill: 0;
}

.intro__char::before {
  content: attr(data-char);
  position: absolute;
  inset: 0;
  color: var(--ink);
  clip-path: inset(0 0 calc((1 - var(--fill)) * 100%) 0);
  pointer-events: none;
  transition: clip-path 0.18s linear;
  will-change: clip-path;
}

/* Oversize the very first generated character (the W of "Welcome") so it
   reads as an editorial drop-initial. The ::before clone scales with it,
   so the ink-fill effect still works on this letter. */
.intro__paragraph .intro__word:first-child .intro__char:first-child {
  font-style: italic;
  font-size: 2.6em;
  line-height: 0.8;
  vertical-align: -0.18em;
  margin-right: 0.04em;
  letter-spacing: -0.02em;
}

/* --- Editorial header row above the paragraph --- */
.intro__meta {
  display: flex;
  align-items: center;
  gap: 22px;
  margin-bottom: 32px;
  font-family: var(--sans);
  font-size: 12px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink);
}

.intro__index {
  font-family: var(--serif);
  font-style: italic;
  font-size: 22px;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink);
}

.intro__rule {
  flex: 1;
  height: 1px;
  background: rgba(15, 15, 13, 0.35);
  max-width: 220px;
}

.intro__tag {
  font-weight: 500;
  opacity: 0.78;
}

/* --- Italic signoff under the paragraph --- */
.intro__sign {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-top: 36px;
  font-family: var(--serif);
  font-size: 18px;
  color: rgba(15, 15, 13, 0.62);
}

.intro__google {
  display: inline-flex;
  align-items: center;
  gap: 14px;
  margin-top: 24px;
  text-decoration: none;
  transition: opacity 0.3s var(--ease);
}

.intro__google:hover {
  opacity: 0.65;
}

.intro__google-stars {
  color: var(--accent);
  font-size: 20px;
  letter-spacing: 3px;
  line-height: 1;
}

.intro__google-text {
  font-family: var(--sans);
  font-size: 20px;
  font-weight: 400;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}

.intro__sign-mark {
  font-size: 22px;
  line-height: 1;
  display: inline-block;
  transform: translateY(-1px);
  color: rgba(15, 15, 13, 0.55);
}

.intro__sign-text em {
  font-style: italic;
}

/* =========================================================
   ABOUT JODHA BAI ESTATE — replaces the old three-residences
   accommodation section. Two-column: the estate's real story
   (Fatepur Sikri origin, the seven year build) beside a short
   column of concrete facts, echoing the how-it-works numbered
   list treatment.
   ========================================================= */
.about-estate {
  position: relative;
  z-index: 2;
  background: var(--cream);
  padding: 20px 56px 120px;
}

.about-estate__inner {
  max-width: 1280px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: 1.4fr 1fr;
  gap: 72px;
  align-items: start;
}

.about-estate__copy {
  opacity: 0;
  transform: translateY(40px);
  transition: opacity 0.9s var(--ease), transform 0.9s var(--ease);
  will-change: transform, opacity;
}

.about-estate__copy.is-revealed {
  opacity: 1;
  transform: translateY(0);
}

.about-estate__tag {
  display: block;
  font-family: var(--sans);
  font-size: 22px;
  font-weight: 500;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 20px;
}

.about-estate__title {
  font-family: var(--serif);
  font-weight: 300;
  font-size: clamp(34px, 4.4vw, 64px);
  line-height: 1.05;
  letter-spacing: -0.02em;
  color: var(--ink);
  margin: 0 0 24px;
}

.about-estate__title em {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  color: var(--accent);
}

.about-estate__lede {
  font-family: var(--sans);
  font-size: 36px;
  font-weight: 400;
  line-height: 1.75;
  color: var(--muted);
  max-width: 56ch;
  margin: 0 0 32px;
}

.about-estate__link {
  display: inline-flex;
  align-items: center;
  gap: 16px;
  font-family: var(--sans);
  font-size: 24px;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink);
  text-decoration: none;
}

.about-estate__link-arrow {
  width: 42px;
  height: 42px;
  flex: 0 0 auto;
  border-radius: 50%;
  border: 1px solid var(--line);
  display: grid;
  place-items: center;
  transition: background 0.35s var(--ease), border-color 0.35s var(--ease),
    color 0.35s var(--ease), transform 0.35s var(--ease);
}

.about-estate__link-arrow svg {
  width: 16px;
  height: 16px;
}

.about-estate__link:hover .about-estate__link-arrow {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--cream);
  transform: rotate(45deg);
}

.about-estate__facts {
  display: flex;
  flex-direction: column;
  gap: 28px;
  margin-top: 8px;
  opacity: 0;
  transform: translateY(40px);
  transition: opacity 0.9s var(--ease) 0.12s, transform 0.9s var(--ease) 0.12s;
  will-change: transform, opacity;
}

.about-estate__facts.is-revealed {
  opacity: 1;
  transform: translateY(0);
}

.about-estate__fact {
  border-top: 1px solid var(--line);
  padding-top: 20px;
}

.about-estate__fact-num {
  display: block;
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(52px, 4.8vw, 68px);
  color: var(--accent);
  margin-bottom: 10px;
}

.about-estate__fact-label {
  display: block;
  font-family: var(--sans);
  font-size: 28px;
  font-weight: 300;
  line-height: 1.6;
  color: var(--muted);
  max-width: 32ch;
}

@media (prefers-reduced-motion: reduce) {
  .about-estate__copy,
  .about-estate__facts {
    transition: none;
    opacity: 1;
    transform: none;
  }
}

@media (max-width: 900px) {
  .about-estate__inner {
    grid-template-columns: 1fr;
    gap: 48px;
  }
}

/* =========================================================
   GALLERY — three connected photos; hover expands one to 2/3
   ========================================================= */
.gallery {
  background: var(--cream);
  padding: 40px 28px 110px;
  position: relative;
  z-index: 2;
  /* Soft rounded bottom + drop shadow — the gallery now "lifts off"
     the section beneath it (mirrors the old amenities styling). */
  border-radius: 0 0 40px 40px;
  box-shadow: 0 60px 80px -50px rgba(0, 0, 0, 0.55);
}

.gallery__inner {
  max-width: 1280px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 0;
  height: 72vh;
  min-height: 540px;
  border-radius: 36px;
  /* smooth column resize + bottom shadow fade when a photo expands */
  transition: grid-template-columns 0.75s var(--ease),
              box-shadow 0.6s var(--ease);
}

/* Clean drop shadow under the gallery while any photo is zoomed in */
.gallery__inner:has(.gallery__frame:hover) {
  box-shadow: 0 38px 90px -22px rgba(0, 0, 0, 0.45);
}

.gallery__frame {
  position: relative;
  margin: 0;
  overflow: hidden;
  background: var(--cream-2);
  cursor: pointer;
  /* Initial scroll-in state — JS overrides on scroll */
  opacity: 0;
  transform: translateY(80px);
  will-change: transform, opacity;
}

/* Round only the outer corners so the gallery reads as one
   continuous strip, with the corner radius matching the outer hull. */
.gallery__frame--a { border-radius: 36px 0 0 36px; }
.gallery__frame--b { border-radius: 0; }
.gallery__frame--c { border-radius: 0 36px 36px 0; }

/* (Yellow hover border removed — frames now render clean edges.) */
.gallery__frame::before {
  content: none;
}

.gallery__frame img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Default rest state — JS overrides during reveal then clears */
  transform: scale(1);
  transition: transform 1.1s var(--ease);
  will-change: transform;
}

/* Expand the hovered column to take ~2/3 of the row.
   4 + 1 + 1 = 6, so the hovered column is 4/6 ≈ 2/3. */
.gallery__inner:has(.gallery__frame--a:hover) {
  grid-template-columns: 4fr 1fr 1fr;
}
.gallery__inner:has(.gallery__frame--b:hover) {
  grid-template-columns: 1fr 4fr 1fr;
}
.gallery__inner:has(.gallery__frame--c:hover) {
  grid-template-columns: 1fr 1fr 4fr;
}

/* Image stays at scale(1) so the full frame is always visible — the
   "zoom" is just the column expanding (object-fit: cover naturally
   reveals more of the photo as the frame widens). */

/* Subtle dim on the non-hovered photos so the active one pops */
.gallery__inner:has(.gallery__frame:hover) .gallery__frame::after {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(28, 29, 26, 0.32);
  transition: opacity 0.6s var(--ease);
  opacity: 1;
  pointer-events: none;
  z-index: 2;
}
.gallery__inner .gallery__frame:hover::after {
  opacity: 0;
}

/* ---- Bottom-right caption — large serif label, tucked to the left
       of the bottom-right corner bracket. ---- */
.gallery__label {
  position: absolute;
  bottom: 26px;
  right: 56px;
  z-index: 4;
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(28px, 3vw, 44px);
  line-height: 1;
  letter-spacing: -0.005em;
  color: rgba(243, 237, 225, 0.95);
  text-shadow: 0 2px 18px rgba(0, 0, 0, 0.55);
  pointer-events: none;
  white-space: nowrap;
  transition: color 0.4s var(--ease), transform 0.4s var(--ease);
}

.gallery__frame:hover .gallery__label {
  color: #fff;
  transform: translateX(-3px);
}

/* =========================================================
   ZOOM MOSAIC — single image scrolls into a 7x7 mosaic.
   The section is taller than the viewport; while it's pinned
   (position: sticky), JS drives the inner grid's scale from 1
   (only the centre cell visible — looks like one image) down
   to a smaller scale (all 7 rings visible, framed with cream
   margin). JS also rotates the grid up to 25deg as the user
   scrolls. Once fully zoomed out, sticky releases and the page
   scrolls on to amenities.
   ========================================================= */
.zoom-mosaic {
  position: relative;
  z-index: 2;
  background: var(--cream);
  /* Total section height = 1 viewport for the visible stage +
     extra scroll distance used to drive the zoom-out animation.
     300vh gives 200vh of sticky animation — enough to reveal
     all 7 rings without rushing. */
  height: 300vh;
}

.zoom-mosaic__stage {
  position: sticky;
  top: 0;
  height: 100vh;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--cream);
}

/* The framed rectangle that contains the whole effect. Sized to
   match the amenities section's visible content area (max width
   1200px, side padding 28px, generous height). The single image
   at scale 1 fills exactly this frame — not the whole viewport. */
/* Wrapper holds the badge outside overflow:hidden */
.zoom-mosaic__frame-wrap {
  position: relative;
  width: min(calc(100% - 56px), 1200px);
  height: clamp(420px, 70vh, 720px);
}

.zoom-mosaic__frame {
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
  background: var(--cream-2);
  border-radius: 56px;
}

/* Google reviews badge — half overhanging the bottom-left of the
   frame, styled to read as a recognizable Google review (the brand's
   own "G" mark + numeric rating + stars) since it now links out to
   the real reviews. */
.zoom-mosaic__badge {
  position: absolute;
  bottom: -20px;
  left: 40px;
  z-index: 20;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: var(--cream);
  border-radius: 999px;
  padding: 10px 20px 10px 16px;
  box-shadow: 0 4px 24px rgba(0, 0, 0, 0.14), 0 1px 4px rgba(0, 0, 0, 0.08);
  text-decoration: none;
  transition: box-shadow 0.3s var(--ease), transform 0.3s var(--ease);
}

.zoom-mosaic__badge:hover {
  box-shadow: 0 8px 30px rgba(0, 0, 0, 0.2), 0 2px 6px rgba(0, 0, 0, 0.1);
  transform: translateY(-2px);
}

.zoom-mosaic__badge-g {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
}

.zoom-mosaic__badge-rating {
  font-family: var(--sans);
  font-size: 13px;
  font-weight: 400;
  color: var(--ink);
  line-height: 1;
}

.zoom-mosaic__badge-stars {
  font-size: 13px;
  letter-spacing: 1px;
  color: #f5b400;
  line-height: 1;
}

/* Grid intrinsic size = 5x the frame in each axis so at scale 1
   the centre cell exactly fills the frame. JS scales it down so the
   full 5x5 mosaic is visible with cream margin around it and rotates
   up to 25deg — fewer, bigger tiles than the old 7x7 layout. */
.zoom-mosaic__grid {
  position: absolute;
  top: 50%;
  left: 50%;
  /* +Xpx absorbs inter-cell gaps so each cell at scale 1 = the
     frame's exact dimensions (no slivers of gap leak into view). */
  width: calc(500% + 96px);
  height: calc(500% + 80px);
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  grid-template-rows: repeat(5, 1fr);
  column-gap: 24px;
  row-gap: 20px;
  transform: translate(-50%, -50%) scale(1) rotate(0deg);
  transform-origin: center center;
  will-change: transform;
}

.zm-cell {
  position: relative;
  margin: 0;
  overflow: hidden;
  background: #1a1a16;
  /* Soft rounded corners on each tile */
  border-radius: 22px;
  box-shadow: 0 14px 30px -18px rgba(0, 0, 0, 0.4);
}

.zm-cell img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  display: block;
}

/* When zoomed all the way out, soften the surrounding 8 tiles a
   touch so the centre stays the focal point. JS toggles
   .is-zoomed-out on the section once progress >= ~0.92. */
.zoom-mosaic.is-zoomed-out .zm-cell:not(.zm-cell--center) img {
  filter: brightness(0.82) saturate(0.95);
}

/* =========================================================
   ZOOM MOSAIC — overlay headline ("The Whole Estate")
   Sits centred inside the frame, above the grid. Each line
   rises up + fades in on its own scroll-progress threshold.
   ========================================================= */
.zoom-mosaic__text {
  position: absolute;
  inset: 0;
  z-index: 2;
  margin: 0;
  padding: 0 24px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  text-align: center;
  color: #fff;
  text-shadow: 0 8px 40px rgba(0, 0, 0, 0.6),
               0 2px 12px rgba(0, 0, 0, 0.4);
  letter-spacing: -0.02em;
  line-height: 0.95;
}

.zoom-mosaic__line {
  display: block;
  opacity: 0;
  transform: translateY(56px);
  transition:
    opacity 0.85s var(--ease),
    transform 1s var(--ease);
  will-change: transform, opacity;
}

.zoom-mosaic__line--1 {
  font-family: var(--serif);
  font-weight: 300;
  font-size: clamp(40px, 6vw, 92px);
}

.zoom-mosaic__line--2 {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(60px, 9.5vw, 152px);
  margin-top: 0.04em;
}

.zoom-mosaic.is-text-1 .zoom-mosaic__line--1,
.zoom-mosaic.is-text-2 .zoom-mosaic__line--2 {
  opacity: 1;
  transform: translateY(0);
}

@media (max-width: 720px) {
  .zoom-mosaic {
    height: auto;
  }
  .zoom-mosaic__stage {
    position: relative;
    height: auto;
    /* The 5-star badge overhangs 18px below the frame-wrap by design
       (see .zoom-mosaic__badge). On desktop the sticky 100vh stage has
       plenty of spare room around the frame, but on mobile the stage
       collapses to height:auto (hugging the frame-wrap exactly), so
       without this padding the overhang poked out into the Occasions
       section below — which paints on top (z-index 3 vs 2) and hid it
       entirely. This reserves room so the badge stays inside the
       section's own box. */
    padding: 0 0 28px;
  }
  .zoom-mosaic__line {
    opacity: 1;
    transform: translateY(0);
  }
  .zoom-mosaic__frame-wrap {
    width: min(calc(100% - 28px), 720px);
    height: clamp(230px, 39vh, 370px);
  }
  .zoom-mosaic__frame {
    border-radius: 36px;
  }
  .zoom-mosaic__badge {
    left: 22px;
    bottom: -18px;
    padding: 8px 16px 8px 13px;
    gap: 6px;
  }
  .zoom-mosaic__badge-g { width: 15px; height: 15px; }
  .zoom-mosaic__badge-rating { font-size: 11px; }
  .zoom-mosaic__badge-stars { font-size: 11px; }
  .zoom-mosaic__grid {
    column-gap: 14px;
    row-gap: 12px;
    width: calc(500% + 56px);
    height: calc(500% + 48px);
  }
  .zm-cell {
    border-radius: 14px;
  }
}

/* =========================================================
   HOW IT WORKS — dark ink panel between the Residences grid and
   the Gallery. Three short steps explaining the booking process.
   The panel is inset from the page edge with soft rounded corners
   (mirrors the .hero__frame inset-on-cream treatment) rather than
   running the dark fill edge to edge.
   ========================================================= */
.how-it-works {
  position: relative;
  z-index: 2;
  background: var(--cream);
  padding: 0 56px 130px;
}

.how-it-works__inner {
  max-width: 1280px;
  margin: 0 auto;
  background: var(--overlay);
  color: var(--cream);
  border-radius: 40px;
  /* Extra top clearance (vs. 90px bottom) — the tag sits top-left,
     the same corner as the fixed Jodha Bai home pill, and needs to
     clear it (bottom ~104px from viewport top) whenever this panel's
     top scrolls near the top of the viewport. */
  padding: 140px 56px 90px;
}

.how-it-works__head {
  margin-bottom: 64px;
}

.how-it-works__tag {
  display: block;
  font-family: var(--sans);
  font-size: 22px;
  font-weight: 500;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: rgba(243, 237, 225, 0.78);
  margin-bottom: 18px;
}

.how-it-works__title {
  font-family: var(--serif);
  font-weight: 300;
  font-size: clamp(34px, 4.4vw, 56px);
  line-height: 1.05;
  letter-spacing: -0.02em;
  color: var(--cream);
  margin: 0;
}

.how-it-works__title em {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  color: rgba(243, 237, 225, 0.75);
}

.how-it-works__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 48px;
}

.how-it-works__step {
  border-top: 1px solid rgba(243, 237, 225, 0.18);
  padding-top: 24px;
}

.how-it-works__num {
  display: block;
  font-family: var(--serif);
  font-style: italic;
  font-size: 15px;
  color: rgba(243, 237, 225, 0.5);
  margin-bottom: 14px;
}

.how-it-works__step-title {
  font-family: var(--serif);
  font-weight: 300;
  font-size: clamp(22px, 2vw, 28px);
  letter-spacing: -0.01em;
  color: var(--cream);
  margin: 0 0 10px;
}

.how-it-works__step-desc {
  font-family: var(--sans);
  font-size: 15px;
  line-height: 1.6;
  color: rgba(243, 237, 225, 0.7);
  max-width: 32ch;
  margin: 0;
}

@media (max-width: 720px) {
  .how-it-works {
    padding: 0 14px 72px;
  }
  .how-it-works__inner {
    padding: 56px 22px;
    border-radius: 24px;
  }
  .how-it-works__head {
    margin-bottom: 40px;
  }
  .how-it-works__grid {
    grid-template-columns: 1fr;
    gap: 32px;
  }
}

/* =========================================================
   THE OCCASIONS — editorial ledger on cream. Three oversized
   serif rows separated by hairline rules; hovering a row dims
   its siblings and floats a corner-marked photo that trails
   the cursor (index.js). Continues the cream field between the
   zoom mosaic and the gallery.
   ========================================================= */
.occasions {
  position: relative;
  /* One step above the other cream sections (2): the section's z-index
     creates a stacking context, so the fixed cursor-preview inside it
     would otherwise be clipped behind the gallery when hovering the
     last row. Still far below back-to-top (80), CTAs (90), menu (100). */
  z-index: 3;
  background: var(--cream);
  /* Extra top clearance (up from 110px) — the right-aligned copy block
     now runs taller (lede + explainer), and needs to clear the fixed
     Book now/Menu pills (bottom ~210px from viewport top) whenever this
     section's top scrolls near the top of the viewport. */
  padding: 230px 56px 130px;
}

.occasions__inner {
  max-width: 1280px;
  margin: 0 auto;
}

.occasions__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 32px;
  flex-wrap: wrap;
  margin-bottom: 56px;
}

.occasions__tag {
  font-family: var(--sans);
  font-size: 22px;
  font-weight: 500;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--muted);
}

.occasions__copy {
  display: flex;
  flex-direction: column;
  gap: 16px;
  max-width: 68ch;
}

.occasions__lede {
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(36px, 3.2vw, 44px);
  line-height: 1.55;
  color: var(--muted);
  margin: 0;
  text-align: right;
}

/* Plain-spoken line stating exactly what's bookable, nested under the
   poetic lede above — visitors need one concrete sentence answering
   "what does this place actually offer". */
.occasions__explainer {
  font-family: var(--sans);
  font-size: clamp(14px, 1vw, 15px);
  line-height: 1.6;
  color: var(--ink);
  margin: 0;
  text-align: right;
}

/* ---- Ledger rows ---- */
.occasions__list {
  display: block;
  border-bottom: 1px solid var(--line);
}

.occasion {
  position: relative;
  display: grid;
  grid-template-columns: 148px 84px 1fr minmax(240px, 340px);
  align-items: center;
  gap: 28px;
  padding: 32px 8px;
  border-top: 1px solid var(--line);
  color: var(--ink);
  /* Scroll-in state — index.js adds .is-revealed. Reveal animates
     opacity/transform (staggered); hover-dim animates filter on its
     own faster clock so the two never fight. */
  opacity: 0;
  transform: translateY(44px);
  transition:
    opacity 0.9s var(--ease) var(--reveal-delay, 0ms),
    transform 0.9s var(--ease) var(--reveal-delay, 0ms),
    filter 0.45s var(--ease);
  will-change: transform, opacity;
}

.occasion.is-revealed {
  opacity: 1;
  transform: translateY(0);
}

/* Dim siblings of the hovered row */
.occasions__list:hover .occasion.is-revealed:not(:hover) {
  filter: opacity(0.32);
}

.occasion__num {
  font-family: var(--serif);
  font-style: italic;
  font-size: 15px;
  color: var(--accent);
}

.occasion__title {
  font-family: var(--serif);
  font-weight: 300;
  font-size: clamp(40px, 6vw, 92px);
  line-height: 0.98;
  letter-spacing: -0.02em;
  transition: transform 0.5s var(--ease);
}

.occasion__title em {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  color: var(--accent);
  font-size: 0.72em;
  letter-spacing: -0.01em;
  white-space: nowrap;
}

.occasion:hover .occasion__title {
  transform: translateX(14px);
}

.occasion__side {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 18px;
}

.occasion__desc {
  font-family: var(--sans);
  font-size: 28px;
  font-weight: 300;
  line-height: 1.6;
  color: var(--muted);
  max-width: 30ch;
  text-align: right;
}

.occasion__arrow {
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: 1px solid var(--line);
  display: grid;
  place-items: center;
  color: var(--ink);
  transition:
    background 0.4s var(--ease),
    border-color 0.4s var(--ease),
    transform 0.4s var(--ease);
}

.occasion__arrow svg {
  width: 17px;
  height: 17px;
}

.occasion:hover .occasion__arrow {
  background: var(--ink);
  border-color: rgba(255, 255, 255, 0.2);
  color: var(--cream);
  transform: rotate(45deg);
}

/* Persistent thumbnail — gives each row real visual weight instead
   of relying only on the cursor-trailing label for imagery. */
.occasion__thumb {
  display: block;
  position: relative;
  width: 148px;
  aspect-ratio: 4 / 5;
  border-radius: 16px;
  overflow: hidden;
  background: var(--cream-2);
}

.occasion__thumb img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transform: scale(1.04);
  transition: transform 0.8s var(--ease);
}

.occasion:hover .occasion__thumb img {
  transform: scale(1.1);
}

.occasions__cta {
  display: flex;
  justify-content: flex-start;
  margin-top: 64px;
}

/* ---- Cursor-trailing label (desktop pointer only) ---- */
.occasion-label {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  gap: 8px;
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  transform: translate(-50%, -50%) scale(0.85);
  transition:
    opacity 0.3s var(--ease),
    transform 0.4s var(--ease);
  will-change: transform, opacity;
}

.occasion-label.is-active {
  opacity: 1;
  transform: translate(-50%, -50%) scale(1);
}

.occasion-label__dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--accent);
}

.occasion-label__text {
  font-family: var(--sans);
  font-size: 22px;
  font-weight: 500;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--ink);
}

/* Touch / no-hover devices never see the floating label */
@media (hover: none), (pointer: coarse) {
  .occasion-label {
    display: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .occasion,
  .occasion.is-revealed,
  .occasion__title,
  .occasion__arrow,
  .occasion-label {
    transition: none;
  }
  .occasion {
    opacity: 1;
    transform: none;
  }
  .occasion-label {
    display: none;
  }
}

/* Footer (.site-footer, .footer-col, .footer-social, brand) lives in
   includes/footer.css and is loaded as a separate stylesheet. */

/* =========================================================
   RESPONSIVE
   ========================================================= */
@media (max-width: 720px) {
  .hero {
    /* Mobile hero — aspect ratio nudged a touch taller (2/3 instead of
       3/4) so the card runs a little longer down the screen, giving
       the photo more vertical real estate. The photo itself is
       landscape (~2.1), so vertical was never being cropped — the
       extra length just lets the house render larger and breathes a
       bit more room beneath it before the LOCATED IN TERRANORA label. */
    padding: 14px;
    min-height: 0;
    height: auto;
    aspect-ratio: 1 / 1;
  }
  .hero__frame,
  .hero__bg,
  .hero__vignette,
  .hero__darken {
    /* Border radius on every corner — the hero now reads as a card.
       Matches the 20px radius used by the Our Love Story and Events
       hero cards on mobile. */
    border-radius: 20px;
  }
  .hero__bg {
    width: 100%;
    height: 100%;
    object-fit: cover;
    /* Anchor the photo to the bottom of the frame so the base of the
       house is ALWAYS visible — any cover-cropping happens at the top
       (sky) instead of the bottom. */
    object-position: center bottom;
    /* The hero has a subtle scale-in animation; pin its origin to the
       bottom so the zoom-in doesn't lift the house off the frame edge
       during the first few seconds of page load. */
    transform-origin: center bottom;
  }
  /* The default vignette darkens the bottom of the image hard (0.6
     opacity black at 100%). On mobile that black band reads as the
     image being cut off at the base — soften it dramatically so the
     bottom of the house stays clearly visible, and pull the heavy
     darkening up to the top instead (where the menu CTA sits). */
  .hero__vignette {
    background:
      linear-gradient(
        180deg,
        rgba(0, 0, 0, 0.18) 0%,
        rgba(0, 0, 0, 0.0) 22%,
        rgba(0, 0, 0, 0.0) 80%,
        rgba(0, 0, 0, 0.18) 100%
      ),
      radial-gradient(
        ellipse at 50% 50%,
        rgba(0, 0, 0, 0) 55%,
        rgba(0, 0, 0, 0.22) 100%
      );
  }
  .hero__locale {
    /* Raised so it doesn't get clipped by the rounded bottom edge or
       the new tighter hero padding. Slightly smaller so it fits on
       narrower phones without wrapping. */
    left: 16px;
    bottom: 32px;
    font-size: 13px;
    gap: 10px;
    letter-spacing: 0.12em;
  }
  .hero__locale-dot {
    width: 8px;
    height: 8px;
  }
  .intro {
    /* Bottom padding stripped — the signoff line should sit flush
       against the gallery / mosaic below on mobile. */
    padding: 28px 22px 0;
  }
  .intro__google {
    gap: 10px;
    margin-top: 32px;
  }
  .intro__google-stars {
    font-size: 14px;
    letter-spacing: 2px;
  }
  .intro__google-text {
    font-size: 12px;
  }
  .gallery {
    /* Top padding zeroed so it butts directly up against the intro
       signoff — no empty cream gap between the two. */
    padding: 0 18px 36px;
  }
  /* On mobile the frames are always visible — no scroll reveal. */
  .gallery__frame {
    opacity: 1;
    transform: none;
  }
  .gallery__inner {
    /* Stack the three landscape photos vertically so each one fills the
       full frame width and isn't cropped narrow. */
    grid-template-columns: 1fr;
    grid-template-rows: repeat(3, auto);
    height: auto;
    min-height: 0;
    border-radius: 24px;
  }
  .gallery__frame {
    aspect-ratio: 16 / 10;
  }
  .gallery__frame--a { border-radius: 24px 24px 0 0; }
  .gallery__frame--b { border-radius: 0; }
  .gallery__frame--c { border-radius: 0 0 24px 24px; }
  .gallery__frame img {
    object-fit: cover;
    object-position: center;
  }
  /* Disable the desktop hover behaviour on mobile — touch can't reliably
     trigger :hover and it leaves the gallery in a half-active state. */
  .gallery__inner,
  .gallery__inner:has(.gallery__frame--a:hover),
  .gallery__inner:has(.gallery__frame--b:hover),
  .gallery__inner:has(.gallery__frame--c:hover) {
    grid-template-columns: 1fr;
    box-shadow: none;
  }
  .gallery__inner:has(.gallery__frame:hover) .gallery__frame::after {
    content: none;
  }
  .gallery__frame:hover .gallery__label {
    transform: none;
    opacity: 1;
  }
  .gallery__label {
    font-size: 18px;
    right: 38px;
    bottom: 16px;
  }
  .occasions {
    padding: 72px 20px 90px;
  }
  .occasions__head {
    margin-bottom: 36px;
  }
  .occasions__copy {
    max-width: none;
  }
  .occasions__lede,
  .occasions__explainer {
    text-align: left;
  }
  .occasions__lede {
    font-size: 20px;
    line-height: 1.5;
  }
  .occasion {
    grid-template-columns: 1fr;
    gap: 14px;
    padding: 30px 2px 34px;
  }
  .occasion__thumb {
    display: block;
    position: relative;
    width: 100%;
    aspect-ratio: 21 / 10;
    border-radius: 16px;
    overflow: hidden;
    background: var(--cream-2);
  }
  .occasion__thumb img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
  }
  .occasion__num {
    font-size: 13px;
  }
  .occasion__title {
    font-size: clamp(34px, 10vw, 52px);
  }
  .occasion:hover .occasion__title {
    transform: none;
  }
  .occasion__side {
    justify-content: space-between;
  }
  .occasion__desc {
    text-align: left;
    max-width: none;
  }
  .occasion__arrow {
    width: 38px;
    height: 38px;
  }
  .occasions__cta {
    margin-top: 44px;
  }

  .about-estate {
    padding: 8px 20px 80px;
  }
  .about-estate__lede {
    font-size: 18px;
    line-height: 1.6;
  }
}

/* =========================================================
   SPLASH LOADER
   ========================================================= */
#page-loader {
  position: fixed;
  inset: 0;
  z-index: 999;
  background: var(--overlay);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: transform 0.9s var(--ease);
  will-change: transform;
}

#page-loader.is-hiding {
  transform: translateY(-100%);
  pointer-events: none;
}

.loader__inner {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 1s var(--ease), transform 1s var(--ease);
  text-align: center;
}

.loader__inner.is-visible {
  opacity: 1;
  transform: translateY(0);
}

.loader__welcome {
  font-family: var(--sans);
  font-size: 24px;
  font-weight: 400;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: rgba(243, 237, 225, 0.75);
}

.loader__name {
  display: block;
  width: clamp(220px, 34vw, 460px);
  height: auto;
}

/* ---------------------------------------------------------
   SPLASH LOADER FLOURISH — a single drawn line beneath the
   wordmark. index.js drives the whole draw-on reveal inline
   (dasharray/dashoffset/transition set from the path's real
   getTotalLength()) at the same moment it fades the text in,
   so the line extends in step with the name appearing rather
   than trailing after it. Nothing here sets dash values —
   without JS (or under reduced motion) the path is just a
   plain, fully visible stroke.
   --------------------------------------------------------- */
.loader__mark {
  font-size: 18px;
  color: rgba(243, 237, 225, 0.45);
}

.loader__flourish {
  width: min(72vw, 640px);
  height: auto;
  overflow: visible;
  margin-top: 4px;
}

.loader__flourish path {
  fill: none;
  stroke: rgba(243, 237, 225, 0.65);
  stroke-width: 1.4;
  stroke-linecap: round;
}
