/* ==========================================================================
   Current Listings

   Carroll's #listings rebuilt. Theirs is a shell around a mount point: the
   header, the arrows and the "View all" pill are static, and everything
   between them is painted at runtime by the IDXBoost React slider. This clone
   has no live feed, so ours ships real markup. A section that renders nothing
   until a third party script lands is not a section.

   Kept from theirs
     the shape: italic name line over a display headline, a row of property
       cards, a control row underneath
     the card language: photograph, gradient scrim, address and price sitting
       inside the image, a status pill, a VIEW panel that wipes in on hover
     the reveal: one class added when the section reaches mid viewport and
       never removed, children staggered in 0.1s steps

   Ours
     LEFT ALIGNED, header and controls both. Theirs is centred throughout.
     Brand tokens and the brand serif, so no literal colour appears below.
     A real scroll container instead of a transform track (see the rail).

   Depends on _shared.css for .yp-sec, .yp-wrap, .yp-shead and .yp-rise, and
   on sections.js for the .yp-anim / .yp-in flip.
   ========================================================================== */

/* The gutter arithmetic everywhere below assumes border-box. On this page
   that reset arrives from Bootstrap, which is a Loopt dependency and not
   ours to rely on: .yp-wrap is width:100% plus a 30px gutter, so under
   content-box it renders 60px wider than the viewport and the whole section
   overhangs. Scoped to this section so it cannot disturb Divi. */
.yp-listings,
.yp-listings *,
.yp-listings *::before,
.yp-listings *::after { box-sizing: border-box; }

/* Ground is Sand so this block separates from the Shell sections either side
   of it. One class, one knob: flip it to .yp-sec-shell on the section itself
   if the page order changes and this lands next to another Sand block. */
.yp-listings {
  /* clip, not hidden: hidden would make this a scroll container and swallow
     the rail's own horizontal scrolling. The two header words travel 20px
     sideways on reveal, and this guarantees that travel can never reach the
     page's scroll width at any viewport. */
  overflow-x: clip;
}

/* ---- header --------------------------------------------------------------
   .yp-shead does the type. Only the watermark is new here. */

/* Carroll floats their group mark over the centred heading with no z-index at
   all, which only reads because the PNG happens to be transparent. Ours is
   parked at the right end of the header block, behind the type by an explicit
   stacking order, so a future mark with an opaque ground still cannot hide
   the headline. */
.yp-listings-mark {
  position: absolute;
  right: 0;
  bottom: clamp(30px, 3.2vw, 60px);
  z-index: 0;
  width: clamp(180px, 20vw, 300px);
  height: auto;
  opacity: 0.07;
  pointer-events: none;
}

.yp-listings .yp-shead-name,
.yp-listings .yp-shead-label {
  position: relative;
  z-index: 1;
}

/* The headline is two words on purpose. They carry the same delay and part
   ways by direction, so they converge on their final position rather than
   arriving as one block. Left aligned that still reads, because the travel is
   20px against a 60px display size. */
.yp-listings .yp-lw { display: inline-block; }

/* Below 900 the headline needs the full measure and the mark would sit under
   the second line. */
@media (max-width: 900px) {
  .yp-listings-mark { display: none; }
}

/* ---- rail ----------------------------------------------------------------
   A native scroll container, not a transform track. Three reasons.

   1. It works with no script: touch, trackpad, shift plus wheel, and tabbing
      through the card links all scroll it.
   2. The reveal animates transform on the card itself. Carroll gets away with
      that because greatslider transforms the track and not the slides; any
      slider that moves individual slides would overwrite the reveal mid
      flight. A scroll container moves neither.
   3. It satisfies the house rule that wide content scrolls inside its own
      box rather than widening the page.

   The 4px inline padding and its matching negative margin exist so a focused
   card's outline has somewhere to sit: the scroll container clips at its
   padding edge, so without the padding the leftmost ring would be shaved off.
   scroll-padding keeps snapping aligned to the same edge. */

.yp-listings-rail {
  --cols: 1.12;   /* the 0.12 is the next card peeking, which is the cue that
                     the row scrolls. Carroll does the same at 639 and below. */
  --gap: 14px;

  display: flex;
  gap: var(--gap);
  margin: 0 -4px;
  padding: 4px;
  list-style: none;
  overflow-x: auto;
  overscroll-behavior-x: contain;   /* a swipe past the end must not walk the
                                       browser back a page */
  scroll-snap-type: x proximity;
  scroll-padding-inline: 4px;
  scroll-behavior: smooth;
  scrollbar-width: thin;
  scrollbar-color: rgb(var(--yp-ink-rgb) / 0.28) transparent;
}

.yp-listings-card {
  flex: 0 0 calc((100% - (var(--cols) - 1) * var(--gap)) / var(--cols));
  scroll-snap-align: start;
}

@media (min-width: 640px) {
  .yp-listings-rail { --cols: 2; --gap: 20px; }
}

@media (min-width: 1024px) {
  .yp-listings-rail { --cols: 3; --gap: 24px; }
}

/* ---- card ----------------------------------------------------------------
   Carroll's .ms-property, which is the best card design in their stylesheet
   and, per their own markup, never actually rendered on the home page. */

.yp-listings-link {
  position: relative;
  display: block;
  overflow: hidden;
  color: var(--yp-white);
  text-decoration: none;
}

/* The ring is inset because the rail clips at its own edge, and an offset
   ring on the first or last card would be cut in half. */
.yp-listings-link:focus-visible {
  outline: 2px solid var(--yp-white);
  outline-offset: -6px;
}

/* Theirs is 1:0.87 on mobile and 1:0.54 above 768, which suits a two up grid
   of wide photographs. At three up those ratios give a card about 450 by 240,
   too short to carry an address and a price inside the image. Square is the
   compromise: it is the tallest frame the 16:9 source photography survives
   without cropping past the subject. Phones get one card at a time, where a
   portrait frame fills the hand better. */
.yp-listings-media {
  position: relative;
  overflow: hidden;
  aspect-ratio: 4 / 5;
  background: var(--yp-ink);
}

@media (min-width: 640px) {
  .yp-listings-media { aspect-ratio: 1 / 1; }
}

.yp-listings-media img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  transition: transform 0.9s cubic-bezier(0.22, 1, 0.36, 1);
}

/* Alpha lives in the gradient stops rather than as opacity on the layer.
   Carroll fades a solid black ramp to 0.7, which means the number written in
   the file is not the number on screen; here the darkest stop is exactly as
   dark as it says. */
.yp-listings-media::after {
  content: "";
  position: absolute;
  inset: auto 0 0 0;
  height: 72%;
  background: linear-gradient(180deg,
    rgb(var(--yp-ink-rgb) / 0) 0%,
    rgb(var(--yp-ink-rgb) / 0.82) 100%);
}

/* Theirs is a grey wash at the top right, which is where the VIEW panel wipes
   in and covers it. Top left keeps both readable and puts the pill on the
   same vertical as everything else in the card. */
.yp-listings-status {
  position: absolute;
  top: 14px;
  left: 14px;
  z-index: 2;
  padding: 7px 15px;
  color: var(--yp-ink);
  background: rgb(var(--yp-shell-rgb) / 0.92);
  font-family: var(--yp-serif);
  font-size: 0.6875rem;
  line-height: 1;
  letter-spacing: 0.22em;
  text-transform: uppercase;
}

/* The right padding reserves the width of the VIEW panel, so a long address
   never runs underneath it. Carroll hardcodes 70px; this scales with the card
   because the panel does too. */
.yp-listings-detail {
  position: absolute;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 1;
  padding: 0 clamp(56px, 18%, 96px) clamp(18px, 2.2vw, 28px) clamp(18px, 2vw, 28px);
}

/* No font-weight here on purpose: typography.css sets every heading to
   --yp-w-sub with !important, so a weight declared here would be a lie the
   cascade throws away. Uppercase and the sub tracking come from the same
   place. */
.yp-listings-address {
  display: flex;
  flex-direction: column;
  margin: 0;
  color: var(--yp-white);
  font-family: var(--yp-serif);
  font-size: clamp(1.0625rem, 0.86rem + 0.55vw, 1.375rem);
  line-height: 1.16;
}

.yp-listings-area {
  margin-top: 7px;
  color: rgb(var(--yp-white-rgb) / 0.78);
  font-size: clamp(0.6875rem, 0.62rem + 0.22vw, 0.8125rem);
  letter-spacing: 0.16em;
}

/* 0.2em is Carroll's tracking on the price and it is the one measurement in
   their card worth copying verbatim: it is what makes a number read as a
   price rather than as data. */
.yp-listings-price {
  margin: 12px 0 0;
  color: var(--yp-white);
  font-family: var(--yp-serif);
  font-size: clamp(1rem, 0.87rem + 0.42vw, 1.25rem);
  line-height: 1.2;
  letter-spacing: 0.2em;
}

.yp-listings-view {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 clamp(11px, 1.4vw, 18px);
  color: var(--yp-white);
  background: rgb(var(--yp-ink-rgb) / 0.82);
  font-family: var(--yp-serif);
  font-size: clamp(0.625rem, 0.53rem + 0.3vw, 0.8125rem);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  opacity: 0;
  transform: translateX(50%);
  transition: opacity 0.3s ease,
              transform 0.45s cubic-bezier(0.22, 1, 0.36, 1);
}

/* :focus-visible on the link matters as much as :hover here. The panel is the
   only affordance that says the card is clickable, and a keyboard user would
   otherwise never see it. */
.yp-listings-link:hover .yp-listings-media img,
.yp-listings-link:focus-visible .yp-listings-media img { transform: scale(1.06); }

.yp-listings-link:hover .yp-listings-view,
.yp-listings-link:focus-visible .yp-listings-view { opacity: 1; transform: translateX(0); }

/* ---- controls ------------------------------------------------------------
   Carroll's arrows are inert in their own theme: .prev-listing and
   .next-listing are bound by the IDX bundle and by nothing else, while the
   slider library's own arrows are hidden by CSS. Copy that markup and you
   ship two dead buttons.

   Ours are anchors into the rail. The browser scrolls the nearest scrollable
   ancestor to reach a target, so they move the row to its start and to its
   end with no script at all, which with six cards at three across is exactly
   its two pages. What an anchor cannot do is step page by page, because it
   has no memory of where the row already is. When the Loopt feed replaces the
   cards it replaces the ids too, so bind these same two elements to the
   slider API at that point and nothing else in the markup moves. */

.yp-listings-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding-top: clamp(28px, 3.4vw, 56px);
}

.yp-listings-all {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 200px;
  height: 46px;
  padding: 0 26px;
  border: 1px solid var(--yp-ink);
  border-radius: 50px;
  color: var(--yp-white);
  background: var(--yp-ink);
  font-family: var(--yp-serif);
  font-size: 0.75rem;
  letter-spacing: var(--yp-track-nav, 0.18em);
  text-transform: uppercase;
  text-decoration: none;
  transition: color 0.25s cubic-bezier(0.22, 1, 0.36, 1),
              background-color 0.25s cubic-bezier(0.22, 1, 0.36, 1);
}

.yp-listings-all:hover,
.yp-listings-all:focus-visible {
  color: var(--yp-ink);
  background: transparent;
}

.yp-listings-nav { display: flex; gap: 10px; }

/* Hollow at rest, filled on hover, which is the reverse of Carroll's. The
   pill sitting beside these is already a solid ink shape, and two solid
   shapes in one short row read as a toolbar rather than as a heading and its
   controls. */
.yp-listings-nav-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 46px;
  height: 46px;
  border: 1px solid var(--yp-ink);
  border-radius: 50%;
  color: var(--yp-ink);
  background: transparent;
  text-decoration: none;
  transition: color 0.25s cubic-bezier(0.22, 1, 0.36, 1),
              background-color 0.25s cubic-bezier(0.22, 1, 0.36, 1);
}

.yp-listings-nav-btn:hover,
.yp-listings-nav-btn:focus-visible {
  color: var(--yp-white);
  background: var(--yp-ink);
}

/* The glyph points where the control goes. Carroll rotates the whole 45px
   circle 90 degrees either way so one vertical arrow icon can serve both,
   which means dropping a horizontal chevron into that markup gives you two
   arrows pointing up and down. */
.yp-listings-nav-btn svg {
  display: block;
  width: 15px;
  height: 15px;
}

@media (min-width: 1024px) {
  .yp-listings-all { height: 54px; min-width: 250px; font-size: 0.8125rem; }
  .yp-listings-nav-btn { width: 54px; height: 54px; }
}

/* ---- reveal --------------------------------------------------------------
   _shared.css owns the transition, the .yp-anim resting state, the .yp-in
   flip and the reduced motion escape. Everything below only re-times and
   re-aims it, so the visibility contract still lives in exactly one file:
   the CSS default is visible, JS opts into the hidden state, JS then plays it.

   These carry one class more than the shared rules they override. Nothing in
   this project enforces stylesheet order, and at equal specificity the winner
   would depend on which <link> the page happens to list first.

   Ladder: name 0.3, headline 0.4, cards 0.5 upward, controls 0.8, mark 0.9.
   The cards start before the controls finish, which is what makes the block
   arrive as one movement instead of three. */

.yp-listings.yp-anim .yp-shead .yp-lw {
  opacity: 0;
  transition: opacity 0.3s ease,
              transform 0.6s cubic-bezier(0.25, 0.46, 0.45, 0.94);
  transition-delay: 0.40s;
}
.yp-listings.yp-anim .yp-shead .yp-lw-1 { transform: translateX(-20px); }
.yp-listings.yp-anim .yp-shead .yp-lw-2 { transform: translateX(20px); }
.yp-listings.yp-anim.yp-in .yp-shead .yp-lw { opacity: 1; transform: translateX(0); }

.yp-listings.yp-anim .yp-shead .yp-listings-mark {
  opacity: 0;
  transform: scale(0.86);
  transition: opacity 0.3s ease,
              transform 0.6s cubic-bezier(0.25, 0.46, 0.45, 0.94);
  transition-delay: 0.90s;
}
.yp-listings.yp-anim.yp-in .yp-shead .yp-listings-mark { opacity: 0.07; transform: scale(1); }

/* The base delay is the LAST rung of the ladder, not zero. Carroll writes
   nine hand rolled rules against a feed capped at sixteen cards, so cards ten
   and up inherit no delay and fire ahead of card one. Hidden today only
   because those cards are off screen. Here anything past the written ladder
   arrives with the group instead of before it. */
.yp-listings.yp-anim .yp-listings-rail .yp-listings-card {
  opacity: 0;
  transform: translateY(20%);
  transition: opacity 0.3s ease,
              transform 0.6s cubic-bezier(0.25, 0.46, 0.45, 0.94);
  transition-delay: 1.20s;
}
.yp-listings.yp-anim .yp-listings-rail .yp-listings-card:nth-child(1) { transition-delay: 0.50s; }
.yp-listings.yp-anim .yp-listings-rail .yp-listings-card:nth-child(2) { transition-delay: 0.60s; }
.yp-listings.yp-anim .yp-listings-rail .yp-listings-card:nth-child(3) { transition-delay: 0.70s; }
.yp-listings.yp-anim .yp-listings-rail .yp-listings-card:nth-child(4) { transition-delay: 0.80s; }
.yp-listings.yp-anim .yp-listings-rail .yp-listings-card:nth-child(5) { transition-delay: 0.90s; }
.yp-listings.yp-anim .yp-listings-rail .yp-listings-card:nth-child(6) { transition-delay: 1.00s; }
.yp-listings.yp-anim .yp-listings-rail .yp-listings-card:nth-child(7) { transition-delay: 1.10s; }
.yp-listings.yp-anim .yp-listings-rail .yp-listings-card:nth-child(8) { transition-delay: 1.20s; }
.yp-listings.yp-anim.yp-in .yp-listings-rail .yp-listings-card { opacity: 1; transform: translateY(0); }

.yp-listings.yp-anim .yp-wrap .yp-listings-foot {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity 0.3s ease,
              transform 0.6s cubic-bezier(0.25, 0.46, 0.45, 0.94);
  transition-delay: 0.80s;
}
.yp-listings.yp-anim.yp-in .yp-wrap .yp-listings-foot { opacity: 1; transform: translateY(0); }

/* ---- responsive ---------------------------------------------------------- */

/* 540, not 640: the same width where .yp-wrap, the header and the hero all
   change gutter, so every left edge on the page stays on one vertical. */
@media (max-width: 540px) {
  .yp-listings-all { min-width: 0; flex: 1 1 auto; }
  .yp-listings-status { top: 10px; left: 10px; }
}

/* ---- reduced motion ------------------------------------------------------
   sections.js reads the same query and returns before adding any class, so
   normally none of the .yp-anim states below can even exist. They are here
   for the case the setting is turned on after the page has loaded, with the
   resting state already applied and no script left to undo it. Specificity
   matches the rules above for the same reason those rules carry an extra
   class in the first place.

   Hover keeps working. It just stops travelling: the VIEW panel appears
   rather than wiping in, and the photograph holds still. */

@media (prefers-reduced-motion: reduce) {
  .yp-listings .yp-lw,
  .yp-listings .yp-listings-card,
  .yp-listings .yp-listings-foot,
  .yp-listings.yp-anim .yp-shead .yp-lw,
  .yp-listings.yp-anim .yp-listings-rail .yp-listings-card,
  .yp-listings.yp-anim .yp-wrap .yp-listings-foot {
    opacity: 1;
    transform: none;
    transition: none;
  }

  .yp-listings .yp-listings-mark,
  .yp-listings.yp-anim .yp-shead .yp-listings-mark {
    opacity: 0.07;
    transform: none;
    transition: none;
  }

  .yp-listings-rail { scroll-behavior: auto; }

  .yp-listings-media img,
  .yp-listings-view,
  .yp-listings-all,
  .yp-listings-nav-btn { transition: none; }

  .yp-listings-view { transform: none; }

  .yp-listings-link:hover .yp-listings-media img,
  .yp-listings-link:focus-visible .yp-listings-media img { transform: none; }
}


/* ---- paging controls -----------------------------------------------------
   Bound by rail.js. Disabled at each end rather than hidden, so the pair does
   not shift position as you page through. */

.yp-listings-nav-btn[disabled] {
  opacity: 0.35;
  cursor: default;
  pointer-events: none;
}

/* The rail is scrolled by script now, so its own scrollbar is redundant on
   the platforms that draw one permanently. */
.yp-listings-rail { scrollbar-width: none; }
.yp-listings-rail::-webkit-scrollbar { display: none; }
