/* ==========================================================================
   Testimonial  —  Figma "Testomonial - Animate" (713:229456)
   1920 x 960 at y 7213, on Mono/Dark.

   A faint 0.15-opacity rule grid, a quote card, Prev/Next controls and a
   two-row dot field.

   Default -> Animate:
     rules        already drawn (the set's third variant, "Line Animate",
                  is the intermediate step where they stroke in)
     eyebrow      translateY +40  -> 0
     nav circles  translateY +120 -> 0  (Figma's Drag pill, now two buttons)
     dot field    opacity 0 -> 1
     card         fades and rises into place
   ========================================================================== */

.testimonial {
  top: calc(7213 * var(--s));
  height: calc(960 * var(--s));
  background: var(--c-mono-dark);
  overflow: hidden;
  z-index: 5;
}

/* --- rule grid ----------------------------------------------------------- */

.testimonial__rule {
  position: absolute;
  background: var(--c-mono-light);
  opacity: 0.15;
}
.testimonial__rule--h { height: 1px; }
.testimonial__rule--v { width: 1px; }

.testimonial__rule--h1 { left: calc(49 * var(--s)); top: calc(30.5 * var(--s));  width: calc(1823 * var(--s)); }
.testimonial__rule--h2 { left: calc(49 * var(--s)); top: calc(281 * var(--s));   width: calc(1822 * var(--s)); }
.testimonial__rule--h3 { left: calc(49 * var(--s)); top: calc(680.5 * var(--s)); width: calc(1822 * var(--s)); }
.testimonial__rule--h4 { left: calc(48 * var(--s)); top: calc(929.5 * var(--s)); width: calc(1823 * var(--s)); }

.testimonial__rule--v1 { left: calc(49 * var(--s));            top: calc(30 * var(--s)); height: calc(899 * var(--s)); }
.testimonial__rule--v2 { left: calc(25% + 162 * var(--s));     top: calc(31 * var(--s)); height: calc(649 * var(--s)); }
.testimonial__rule--v3 { left: calc(66.67% - 4 * var(--s));    top: calc(31 * var(--s)); height: calc(649 * var(--s)); }
.testimonial__rule--v4 { left: calc(91.67% + 109 * var(--s));  top: calc(31 * var(--s)); height: calc(899 * var(--s)); }

/* --- eyebrow ------------------------------------------------------------- */

.testimonial__eyebrow {
  position: absolute;
  left: calc(8.33% + 22 * var(--s));
  top: calc(136 * var(--s));
  width: calc(174 * var(--s));
  height: calc(38 * var(--s));
}

/* --- prev / next ---------------------------------------------------------
   Figma 928:17413 (Prev) and 928:17404 (Next): 80px circles, vertically
   centred on the card, one in each empty column beside it. They replace the
   "Drag" badge that used to follow the pointer, and they inherit its reveal
   (Figma rises the pill 120px into place).

   Figma specifies a 0.5px border. That is a hairline the browser rounds
   inconsistently once it is multiplied by --s, and it disappears outright at
   1x, so these use the 1px the rest of the theme's hairlines use.
   -------------------------------------------------------------------------- */

.testimonial__nav {
  position: absolute;
  top: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  width: calc(80 * var(--s));
  height: calc(80 * var(--s));
  padding: 0;
  border: 1px solid var(--c-mono-light);
  border-radius: 50%;
  background: transparent;
  color: var(--c-mono-light);
  font-family: inherit;
  font-size: max(11px, calc(16 * var(--s)));
  font-weight: 300;
  line-height: 1.4;
  letter-spacing: calc(-0.48 * var(--s));
  white-space: nowrap;
  cursor: pointer;
  z-index: 6;
  opacity: 0;
  /* Two translateY: the -50% centres it, the second is the reveal offset. */
  transform: translateY(-50%) translateY(calc(120 * var(--s)));
  transition:
    opacity var(--rv-dur) var(--rv-ease),
    transform var(--rv-dur) var(--rv-ease),
    background-color 220ms var(--ui-ease),
    border-color 220ms var(--ui-ease);
}

.testimonial__nav--prev { left: calc(25% + 19 * var(--s)); }
.testimonial__nav--next { left: calc(66.67% + 61 * var(--s)); }

.testimonial.is-in .testimonial__nav {
  opacity: 1;
  transform: translateY(-50%);
}

.testimonial__nav:hover,
.testimonial__nav:focus-visible {
  background: rgba(236, 247, 255, 0.08);
}

/* Nudge in the direction the card will travel, so the two buttons read as
   opposite movements before anything is clicked. */
.testimonial__nav-label {
  display: block;
  transition: transform 220ms var(--ui-ease);
}
.testimonial__nav--prev:hover .testimonial__nav-label { transform: translateX(calc(-3 * var(--s))); }
.testimonial__nav--next:hover .testimonial__nav-label { transform: translateX(calc(3 * var(--s))); }

.testimonial__nav:active { background: rgba(236, 247, 255, 0.14); }

@media (prefers-reduced-motion: reduce) {
  .testimonial__nav { opacity: 1; transform: translateY(-50%); transition: none; }
  .testimonial__nav-label { transition: none; }
}

/* --- quote card ---------------------------------------------------------- */

/* The card is still draggable; the buttons are the primary control, so this
   is the only hint it gets. */
.testimonial__card { cursor: grab; }
.testimonial__card.is-dragging { cursor: grabbing; }

/* The card collapses toward one pair of corner brackets while dragging.
     --collapse  0 = full width, 1 = squeezed to the bracket sliver
     --anchor    0 = left brackets hold still, 1 = right brackets hold still
   Width and left are derived from those two, so JS only sets numbers. */
.testimonial__card {
  --collapse: 0;
  --anchor: 0;

  position: absolute;
  left: calc(33.33% + (3 + 622 * var(--collapse) * var(--anchor)) * var(--s));
  top: calc(280 * var(--s));
  width: calc((634 - 622 * var(--collapse)) * var(--s));
  height: calc(400 * var(--s));
  background: var(--c-light-dark);
  --brk-color: var(--c-accent-yellow);
  overflow: hidden;
  opacity: 0;
  transform: translateY(calc(48 * var(--s)));
  transition:
    opacity calc(var(--rv-dur) * 0.8) var(--rv-ease),
    transform calc(var(--rv-dur) * 0.9) var(--rv-ease);
  transition-delay: 220ms;
  user-select: none;
  touch-action: pan-y;
}
.testimonial.is-in .testimonial__card { opacity: 1; transform: none; }

/* Only while settling — during the drag itself the card tracks the pointer
   one-to-one with no easing. */
/* Two easings, not one. Closing wants to gather pace into the squeeze and
   opening wants to arrive slowly, so the phase's curve is set alongside its
   duration rather than sharing --rv-ease for both. */
.testimonial__card.is-settling {
  transition:
    width var(--close-ms, 620ms) var(--close-ease, var(--rv-ease)),
    left var(--close-ms, 620ms) var(--close-ease, var(--rv-ease));
  transition-delay: 0s;
}

/* While the pointer is down the card tracks it one-to-one — no easing, and a
   compositor hint so wide cards do not stutter. */
.testimonial__card.is-dragging {
  transition: none;
  will-change: width, left;
}

/* Contents fade out as the card squeezes shut so text never crushes. */
.testimonial__card > *:not(.brk__c) {
  opacity: calc(1 - var(--collapse) * 2.2);
}

.testimonial__brand {
  position: absolute;
  left: calc(32 * var(--s));
  top: calc(32 * var(--s));
  display: flex;
  align-items: center;
  gap: calc(8.14 * var(--s));
}
.testimonial__brand img { width: calc(34.45 * var(--s)); height: calc(36 * var(--s)); }
.testimonial__brand span {
  font-family: "DM Sans", var(--f-sans);
  font-weight: 500;
  font-size: calc(22.085 * var(--s));
  line-height: calc(23.247 * var(--s));
  color: var(--c-mono-light);
}

.testimonial__quote {
  position: absolute;
  left: calc(32 * var(--s));
  top: calc(108 * var(--s));
  width: calc(554 * var(--s));
  font-size: calc(24 * var(--s));
  line-height: 1.4;
  letter-spacing: calc(-0.72 * var(--s));
  color: var(--c-mono-light);
}

.testimonial__author {
  position: absolute;
  left: calc(32 * var(--s));
  top: calc(304 * var(--s));
  display: flex;
  align-items: center;
  gap: calc(16 * var(--s));
}
.testimonial__avatar {
  flex: none;
  display: block;
  width: calc(64 * var(--s));
  height: calc(64 * var(--s));
  border-radius: 50%;
}
.testimonial__author img { width: 100%; height: 100%; object-fit: cover; }
.testimonial__author-name {
  font-size: calc(20 * var(--s));
  line-height: 1.4;
  letter-spacing: calc(-0.6 * var(--s));
  color: var(--c-mono-light);
}
.testimonial__author-role {
  font-weight: 300;
  font-size: max(11px, calc(16 * var(--s)));
  line-height: 1.4;
  letter-spacing: calc(-0.48 * var(--s));
  color: var(--c-light-grey-02);
}

/* Each star is the same SVG used as a mask, painted with a hard-stop gradient:
   --fill 100% = Accent/Yellow, 0% = grey, 50% = half. One element per star,
   exact halves, and the empty colour is a single token. */
/* --- dot field ----------------------------------------------------------- */

.testimonial__dots {
  position: absolute;
  left: calc(99 * var(--s));
  top: calc(753 * var(--s));
  width: calc(1722 * var(--s));
  height: calc(102 * var(--s));
  opacity: 0;
  transition: opacity calc(var(--rv-dur) * 1.1) var(--rv-ease);

  /* A canvas now, drawn by dotfield.js from the generated lattice in
     dotfield-data.js. It replaced a pair of repeating radial gradients, which
     looked identical at rest but had no individual dots to move. */
  display: block;
}
.testimonial.is-in .testimonial__dots { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  .testimonial__card { opacity: 1; transform: none; transition: none; }
  .testimonial__dots { opacity: 1; transition: none; }
}

/* ==========================================================================
   Reflow
   ========================================================================== */

@media (max-width: 1023px), (max-width: 1200px) and (orientation: portrait) {
  .testimonial { height: auto; padding: 48px 20px 56px; }
  .testimonial__rule, .testimonial__dots { display: none; }

  .testimonial__eyebrow { position: static; width: auto; height: auto; font-size: 12px; }

  .testimonial__card {
    position: relative;
    left: auto !important; top: auto;
    /* not !important: Contact sizes this card itself */ width: 100%;
    height: auto;
    margin-top: 24px;
    padding: 24px 20px 28px;
  }
  /* Swipe fades the card rather than squeezing it — a 12px sliver makes no
     sense at phone width. */
  .testimonial__card > *:not(.brk__c) { opacity: calc(1 - var(--collapse)); }
  .testimonial__brand,
  .testimonial__quote,
  .testimonial__author { position: static; width: auto; }
  .testimonial__quote { margin-top: 20px; font-size: 18px; }
  .testimonial__author { margin-top: 24px; }

  /* The columns the circles sat in do not exist at this width, so they come
     out from under the card as a plain pair. */
  .testimonial__navs {
    display: flex;
    justify-content: center;
    gap: 16px;
    margin-top: 28px;
  }
  .testimonial__nav {
    position: static;
    width: 56px;
    height: 56px;
    font-size: 13px;
    transform: none;
    opacity: 1;
  }
  .testimonial.is-in .testimonial__nav { transform: none; }
  .testimonial__nav--prev,
  .testimonial__nav--next { left: auto; }
}

/* --- switched off ---------------------------------------------------------
   The section stays in the markup -- the carousel script, the source list and
   the Contact page's card all still read it -- but it is not drawn anywhere.

   Below the reflow the sections are a flow column, so hiding it is enough.
   On the 1920 canvas each one carries its own absolute top, so hiding it
   would leave a 997 hole on the front page; the four sections after it close
   that up, and the page loses the same 997 off its height. */
.testimonial { display: none; }

@media (min-width: 1201px), (min-width: 1024px) and (orientation: landscape) {
  .o-page[class="o-page"] { --page-h: 10562; }
  .o-page[class="o-page"] > main > .faqbg,
  .o-page[class="o-page"] > main > .faq    { top: calc(7276 * var(--s)); }
  .o-page[class="o-page"] > main > .cta    { top: calc(8569 * var(--s)); }
  .o-page[class="o-page"] > main > .footer { top: calc(9626 * var(--s)); }
}
