/* ==========================================================================
   Testimonials

   The shadcn / framer-motion "testimonial-slider-1" layout, ported to plain
   CSS. Its three-column grid is kept exactly: a narrow meta rail on the left
   carrying the counter, a vertical REVIEWS label and the thumbnail strip; the
   photograph in the middle; the quote and the two round arrows on the right.

   Their tokens map onto ours:
     bg-background / text-foreground -> var(--yp-shell) / var(--yp-ink)
     text-muted-foreground           -> rgb(var(--yp-ink-rgb) / 0.6)
     bg-primary                      -> var(--yp-ink)
     rounded-lg / rounded-md         -> square, matching the listing cards
     font sans                       -> var(--yp-serif)

   The original animates with framer-motion variants. Here the same two moves,
   the image sliding vertically and the text sliding horizontally against the
   direction of travel, are CSS transitions driven by a data attribute the
   script sets. Same choreography, no runtime.
   ========================================================================== */

.yp-tst-grid {
  display: grid;
  grid-template-columns: 3fr 4fr 5fr;   /* their md:col-span 3 / 4 / 5 */
  gap: clamp(20px, 2.4vw, 34px);
  align-items: stretch;
  min-height: 560px;
}

/* ---- left rail ------------------------------------------------------------ */

.yp-tst-meta { display: flex; flex-direction: column; justify-content: flex-end; }

.yp-tst-thumbs { display: flex; gap: 8px; }

.yp-tst-thumb {
  width: 74px;
  height: 92px;
  padding: 0;
  border: 0;
  overflow: hidden;
  cursor: pointer;
  background: none;
  opacity: 0.68;
  transition: opacity 0.3s ease, transform 0.4s cubic-bezier(0.22, 1, 0.36, 1);
}

.yp-tst-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.yp-tst-thumb:hover { opacity: 1; transform: translateY(-3px); }
.yp-tst-thumb:focus-visible { opacity: 1; outline: 2px solid var(--yp-ink); outline-offset: 3px; }

/* ---- centre image --------------------------------------------------------- */

.yp-tst-media { position: relative; min-height: 460px; overflow: hidden; }

.yp-tst-media img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.6s cubic-bezier(0.4, 0, 0.2, 1),
              opacity 0.6s cubic-bezier(0.4, 0, 0.2, 1);
}

/* Their imageVariants: the outgoing frame leaves against the direction of
   travel while the incoming one arrives with it. */
.yp-tst-media img.is-out { opacity: 0; }
[data-dir="right"] .yp-tst-media img.is-out { transform: translateY(-100%); }
[data-dir="left"]  .yp-tst-media img.is-out { transform: translateY(100%); }
[data-dir="right"] .yp-tst-media img.is-in  { transform: translateY(100%); opacity: 0; }
[data-dir="left"]  .yp-tst-media img.is-in  { transform: translateY(-100%); opacity: 0; }

/* ---- right column --------------------------------------------------------- */

.yp-tst-body { display: flex; flex-direction: column; justify-content: space-between; }

/* The outgoing and incoming quote overlap for the length of the transition,
   so they are stacked rather than left in normal flow. In flow the container
   grew from 303px to 552px mid-change and the new text landed 249px below the
   old one, which is what made the change lurch instead of cross-fade. */
.yp-tst-text {
  position: relative;
  padding-top: clamp(8px, 4vw, 76px);
  min-height: 260px;
}

.yp-tst-text > div {
  position: absolute;
  left: 0;
  right: 0;
  top: clamp(8px, 4vw, 76px);
  transition: transform 0.6s cubic-bezier(0.4, 0, 0.2, 1),
              opacity 0.45s cubic-bezier(0.4, 0, 0.2, 1);
}

.yp-tst-text > div.is-out { opacity: 0; }
[data-dir="right"] .yp-tst-text > div.is-out { transform: translateX(-50px); }
[data-dir="left"]  .yp-tst-text > div.is-out { transform: translateX(50px); }

/* The entry state, which was missing entirely: the new quote used to appear at
   full opacity in the same frame it was inserted. */
.yp-tst-text > div.is-in { opacity: 0; }
[data-dir="right"] .yp-tst-text > div.is-in { transform: translateX(50px); }
[data-dir="left"]  .yp-tst-text > div.is-in { transform: translateX(-50px); }

.yp-tst-affiliation {
  margin: 0;
  font-family: var(--yp-serif);
  font-size: 0.8125rem;
  letter-spacing: var(--yp-track-sub, 0.09em);
  text-transform: uppercase;
  color: rgb(var(--yp-ink-rgb) / 0.6);
}

.yp-tst-name {
  margin: 6px 0 0;
  font-family: var(--yp-serif);
  font-size: clamp(1.0625rem, 0.5vw + 0.9rem, 1.375rem);
  font-weight: var(--yp-w-sub, 500);
  color: var(--yp-ink);
}

.yp-tst-quote {
  margin: clamp(18px, 2vw, 28px) 0 0;
  font-family: var(--yp-serif);
  font-size: clamp(1.25rem, 1.3vw + 0.9rem, 1.875rem);
  font-weight: 400;
  line-height: 1.32;
  color: var(--yp-ink);
  text-wrap: pretty;
}

.yp-tst-nav { display: flex; gap: 10px; margin-top: 28px; }

.yp-tst-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border-radius: 999px;
  cursor: pointer;
}

.yp-tst-btn svg { width: 20px; height: 20px; }

/* ---- responsive ----------------------------------------------------------
   Their md: breakpoint reorders to image, meta, text. Same here. */

@media (max-width: 900px) {
  .yp-tst-grid { grid-template-columns: 1fr; min-height: 0; }
  .yp-tst-media { order: 1; min-height: 380px; }
  .yp-tst-meta  { order: 2; flex-direction: row; align-items: center;
                  justify-content: space-between; gap: 16px; }
  .yp-tst-meta-top { flex-direction: row; align-items: center; gap: 14px; }
  .yp-tst-vertical { display: none; }
  .yp-tst-body  { order: 3; }
  .yp-tst-text  { padding-top: 4px; min-height: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .yp-tst-media img,
  .yp-tst-text > div,
  .yp-tst-thumb { transition: none; }
}
