/* ============================================================
   10-testimonials — cinematic quote carousel + opposite-direction
   vertical review marquee ("Proof Wall"). Scoped under
   .sec-10-testimonials
   ============================================================ */

/* --- Carousel --- */
.sec-10-testimonials__carousel {
  max-width: 48rem;
  margin: 0 auto clamp(3.5rem, 6vw, 5rem);
  text-align: center;
}

.sec-10-testimonials__viewport {
  position: relative;
  overflow: hidden;
  min-height: 15rem;
}

.sec-10-testimonials__track {
  position: relative;
  display: block;
}

.sec-10-testimonials__slide {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  opacity: 0;
  transform: translateX(24px);
  transition: opacity 600ms var(--ease-out), transform 600ms var(--ease-out);
  pointer-events: none;
}

.sec-10-testimonials__slide.is-active {
  position: relative;
  opacity: 1;
  transform: translateX(0);
  pointer-events: auto;
}

.sec-10-testimonials__slide.is-prev {
  transform: translateX(-24px);
}

.sec-10-testimonials__glyph {
  font-family: var(--font-quote);
  font-size: clamp(3.5rem, 4vw, 5.5rem);
  line-height: 0.6;
  color: var(--accent);
  opacity: 0.85;
}

.sec-10-testimonials__quote {
  font-family: var(--font-quote);
  font-style: italic;
  font-size: clamp(1.4rem, 1.1rem + 1.2vw, 2rem);
  line-height: 1.35;
  margin: 0.5rem 0 1.5rem;
  max-width: 42ch;
}

.sec-10-testimonials__stars {
  color: var(--ember);
  letter-spacing: 0.15em;
  margin-bottom: 0.6rem;
  font-size: 0.95rem;
}

.sec-10-testimonials__attr {
  color: var(--text-on-ink-dim);
  font-size: 0.9rem;
}

.sec-10-testimonials__controls {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1.25rem;
  margin-top: 2rem;
}

.sec-10-testimonials__arrow {
  width: 2.75rem;
  height: 2.75rem;
  border-radius: 50%;
  border: 1px solid hsl(0 0% 100% / 0.2);
  background: transparent;
  color: var(--text-on-ink);
  font-size: 1.1rem;
  cursor: pointer;
  transition: background 250ms var(--ease-out), border-color 250ms var(--ease-out), transform 250ms var(--ease-spring);
}

.sec-10-testimonials__arrow:hover {
  background: hsl(0 0% 100% / 0.1);
  border-color: var(--accent);
  transform: translateY(-2px);
}

.sec-10-testimonials__dots {
  display: flex;
  gap: 0.5rem;
}

.sec-10-testimonials__dot {
  width: 0.55rem;
  height: 0.55rem;
  border-radius: 50%;
  border: none;
  background: hsl(0 0% 100% / 0.25);
  cursor: pointer;
  padding: 0;
  transition: background 250ms var(--ease-out), transform 250ms var(--ease-out);
}

.sec-10-testimonials__dot.is-active {
  background: var(--accent);
  transform: scale(1.3);
}

/* --- Review wall ---
   Opposite-direction vertical marquee. This was frozen to a static grid at one point
   because clients read the moving cards as "cut off mid-review". It is animated again,
   rebuilt so it does not reproduce that complaint:
     1. the viewport is tall enough that whole reviews are always readable, never slivers
     2. the top and bottom edges are a gradient mask, so partials fade rather than hard-cut
     3. it pauses on hover and on focus-within, so anyone can stop it and read
     4. mobile and reduced-motion fall back to the plain static grid
   DO NOT shorten the wall or thin the review count without redoing the maths below. Both
   are load-bearing, and getting either wrong brings the "truncated" complaint straight back. */
.sec-10-testimonials__wall {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--sp-gap);
  align-items: start;
  /* Sizing is driven by the loop maths, not by eye. With card height C, gap G and pitch
     P = C + G, the number of cards guaranteed FULLY inside the clear zone at EVERY phase
     of the scroll is floor((clear - C) / P). For three full cards, clear >= 3P + C.
     With C=188 and G=20 => P=208, so the clear zone must be >= 812px. The fade bands are a
     fixed 120px each (not a %, so they cannot grow with the section and eat the clear
     zone), hence a minimum height of ~812 + 240.
     The two columns carry DISJOINT sets of 6 reviews (12 unique in total). Both halves of
     that matter:
       - disjoint, because rotating ONE shared list by half only separates the columns at
         t=0; they run at different speeds (54s vs 62s) and drift back into sync, so the
         same reviewer appears in both columns.
       - 6 per column, because a set must be TALLER than the window or a void opens at an
         edge on every loop. 6 cards = 1248px against a ~1060px window. 4 would be 832px.
     Two sets per column and translateY(-50%) = exactly one set, so the loop has no seam. */
  height: clamp(1060px, 108vh, 1180px);
  overflow: hidden;
  position: relative;
  /* 120px is deep relative to a ~188px card, so a partial fades across most of its body
     instead of showing crisp text and then vanishing at a hard edge. */
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 120px, #000 calc(100% - 120px), transparent 100%);
          mask-image: linear-gradient(to bottom, transparent 0, #000 120px, #000 calc(100% - 120px), transparent 100%);
}

.sec-10-testimonials__col {
  height: 100%;
  overflow: hidden;
}

.sec-10-testimonials__col-track {
  display: flex;
  flex-direction: column;
  gap: 0;
  will-change: transform;
}

.sec-10-testimonials__col-set {
  display: flex;
  flex-direction: column;
  gap: 20px;
  /* The set carries its own TRAILING gap and the track has gap:0. If the gap lived on the
     track instead, the seam between set 1 and set 2 would be one gap short and the loop
     would visibly jump every cycle. */
  padding-bottom: 20px;
}

.sec-10-testimonials [data-marquee-dup] { display: flex; }

.sec-10-testimonials__col[data-dir="up"] .sec-10-testimonials__col-track {
  animation: sec-10-marquee-up 54s linear infinite;
}
.sec-10-testimonials__col[data-dir="down"] .sec-10-testimonials__col-track {
  animation: sec-10-marquee-down 62s linear infinite;
}

/* Anyone can stop it to actually read a review */
.sec-10-testimonials__wall:hover .sec-10-testimonials__col-track,
.sec-10-testimonials__wall:focus-within .sec-10-testimonials__col-track {
  animation-play-state: paused;
}

/* --- Mobile: static grid ---
   A narrow screen makes moving text materially harder to read, and the mask would eat a
   larger share of a small viewport. Below 820px this reverts to the plain grid: full
   height, no mask, no animation, duplicate sets hidden. */
@media (max-width: 820px) {
  .sec-10-testimonials__wall {
    grid-template-columns: 1fr;
    height: auto;
    overflow: visible;
    -webkit-mask-image: none;
            mask-image: none;
  }
  .sec-10-testimonials__col {
    height: auto;
    overflow: visible;
    display: flex;
    flex-direction: column;
    gap: var(--sp-gap);
  }
  .sec-10-testimonials__col-track { animation: none !important; transform: none !important; }
  .sec-10-testimonials__col-set { padding-bottom: 0; gap: var(--sp-gap); }
  .sec-10-testimonials [data-marquee-dup] { display: none; }
  /* Both columns stay visible and simply stack. The columns hold DISJOINT reviews, so
     hiding either one drops half of them from every phone. */
  /* The mobile column is static, so height is free: stop truncating mid-sentence. */
  .sec-10-testimonials__snippet { -webkit-line-clamp: 6; }
}

/* --- Reduced motion: static grid, and the height/mask must go too, or the wall keeps a
   fixed tall box with most of its cards masked out and unreachable. --- */
@media (prefers-reduced-motion: reduce) {
  .sec-10-testimonials__wall {
    height: auto;
    overflow: visible;
    -webkit-mask-image: none;
            mask-image: none;
  }
  .sec-10-testimonials__col { height: auto; overflow: visible; }
  .sec-10-testimonials__col-track { animation: none !important; transform: none !important; }
  .sec-10-testimonials__col-set { padding-bottom: 0; }
  .sec-10-testimonials [data-marquee-dup] { display: none; }
}
/* core.js also sets html.reduced-motion; mirror it so the toggle works without a reload. */
html.reduced-motion .sec-10-testimonials__wall {
  height: auto;
  overflow: visible;
  -webkit-mask-image: none;
          mask-image: none;
}
html.reduced-motion .sec-10-testimonials__col { height: auto; overflow: visible; }
html.reduced-motion .sec-10-testimonials__col-track { animation: none !important; transform: none !important; }
html.reduced-motion .sec-10-testimonials__col-set { padding-bottom: 0; }
html.reduced-motion .sec-10-testimonials [data-marquee-dup] { display: none; }

@keyframes sec-10-marquee-up {
  from { transform: translateY(0); }
  to { transform: translateY(-50%); }
}

@keyframes sec-10-marquee-down {
  from { transform: translateY(-50%); }
  to { transform: translateY(0); }
}

.sec-10-testimonials__review {
  background: #fbfbf9;
  color: var(--text-on-bone);
  border-radius: var(--radius-card);
  padding: 1.6rem 1.65rem;
  box-shadow: var(--shadow-soft);
}

.sec-10-testimonials__review-head {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  margin-bottom: 0.5rem;
}

.sec-10-testimonials__avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.1rem;
  height: 2.1rem;
  border-radius: 50%;
  background: var(--accent-soft);
  color: var(--accent-strong);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 0.9rem;
  flex-shrink: 0;
}

.sec-10-testimonials__review-name {
  font-weight: 600;
  font-size: 0.9rem;
}

.sec-10-testimonials__review .sec-10-testimonials__stars {
  color: var(--ember);
  font-size: 0.8rem;
  margin-bottom: 0.4rem;
}

.sec-10-testimonials__snippet {
  font-size: var(--fs-small);
  line-height: 1.5;
  color: var(--text-on-bone);
  margin-bottom: 0.55rem;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.sec-10-testimonials__via {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.75rem;
  color: var(--text-on-bone-dim);
}

/* --- Google lockup --- */
.sec-10-testimonials__lockup {
  margin-top: clamp(2rem, 4vw, 3rem);
  text-align: center;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 1rem 1.5rem;
}

.sec-10-testimonials__lockup-rating {
  font-weight: 600;
  color: var(--text-on-ink);
}

.sec-10-testimonials__lockup-link {
  color: var(--accent);
  font-weight: 600;
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: border-color 200ms var(--ease-out);
}

.sec-10-testimonials__lockup-link:hover {
  border-color: currentColor;
}

/* Mobile stacking for the wall lives with the wall rules above, not here: it used to also
   carry `.__col--b { display: none }`, which silently dropped half the reviews from every
   phone once the two columns held DISJOINT sets. */

/* --- Reduced motion: no auto-slide feel --- */
@media (prefers-reduced-motion: reduce) {
  .sec-10-testimonials__slide { transition: opacity 200ms linear; transform: none; }
}

html.reduced-motion .sec-10-testimonials__slide { transition: opacity 200ms linear; transform: none; }

/* --- Client build: static wall ---
   The animated marquee's maths need two DISJOINT columns of six, so twelve unique
   reviews. Action Rehab has five real ones. Padding the wall would mean inventing
   reviewers, so the wall ships in the static form the section already falls back to on
   mobile and under reduced motion: same markup, same cards, no animation, no mask, no
   duplicate sets, nothing truncated. These declarations are copied from the existing
   mobile/reduced-motion blocks above, not new behaviour. */
.sec-10-testimonials__wall--static {
  height: auto;
  overflow: visible;
  -webkit-mask-image: none;
          mask-image: none;
  align-items: start;
}
.sec-10-testimonials__wall--static .sec-10-testimonials__col {
  height: auto;
  overflow: visible;
  display: flex;
  flex-direction: column;
  gap: var(--sp-gap);
}
.sec-10-testimonials__wall--static .sec-10-testimonials__col-track {
  animation: none !important;
  transform: none !important;
}
.sec-10-testimonials__wall--static .sec-10-testimonials__col-set {
  padding-bottom: 0;
  gap: var(--sp-gap);
}
/* The wall is static here, so height is free: never clip a review mid-sentence. */
.sec-10-testimonials__wall--static .sec-10-testimonials__snippet {
  -webkit-line-clamp: unset;
  display: block;
}

/* Odd fifth review: spans both grid tracks and centers itself at one column's width,
   rather than being pinned to the left edge of whichever column it would otherwise fall
   into. See the HTML comment at .sec-10-testimonials__solo for why it exists. */
.sec-10-testimonials__wall--static .sec-10-testimonials__solo {
  grid-column: 1 / -1;
  display: flex;
  justify-content: center;
}
.sec-10-testimonials__wall--static .sec-10-testimonials__solo .sec-10-testimonials__review {
  width: 100%;
  max-width: calc(50% - (var(--sp-gap) / 2));
}
@media (max-width: 820px) {
  .sec-10-testimonials__wall--static .sec-10-testimonials__solo .sec-10-testimonials__review {
    max-width: 100%;
  }
}
