/* ==========================================================================
   FAMILY TREE DENTAL — reviews.css
   The Reviews page's hero and the review marquee.
   ---------------------------------------------------------------------------
   Loaded after style.css and system.css. Everything shared — tokens, the nav
   pill, buttons, the headline mask, the appointment band, the testimonial
   split, the clinic panel, the wave — comes from those two and from the global
   components. What is here is only:

     01. The hero
     02. The wall        the section the marquee lives in
     03. The stage       rows, tracks and the two edge fades
     04. The card
     05. The controls
     06. Entry states
     07. Responsive
     08. Reduced motion

   TWO LAYOUTS, ONE LIST OF CARDS, AND THE GRID IS THE DEFAULT.

     unbuilt   `.rv-list` is a card grid. This is what ships in the response,
               what a visitor with no JavaScript keeps, and what a visitor who
               has asked for reduced motion is left with. Every review is
               present, in order, once.
     built     reviews.js adds `.is-built`, having MOVED those same cards into
               rows. The grid rules switch off and the row rules switch on.

   Authoring it in that order — rather than hiding the list and revealing the
   marquee — is what makes the failure state the readable one.
   ========================================================================== */


/* ==========================================================================
   01. THE HERO
   ========================================================================== */
.rv-hero {
  position: relative;
  isolation: isolate;
  overflow: clip;
  padding-top: calc(var(--util-h) + var(--nav-h) + var(--hero-inset) + var(--hero-pad));
  background: var(--sv-ivory);
}

.rv-hero__inner {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.06fr);
  align-items: stretch;
  /* The band's height is set here and nowhere else; the photograph is taken
     out of flow below so it cannot drive this row. */
  min-height: clamp(22rem, 48vh, 31rem);
}

.rv-hero__panel {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  display: flex;
  align-items: center;
  padding: clamp(2rem, 5vw, 4.5rem) clamp(2.5rem, 6vw, 6rem) clamp(2rem, 5vw, 4.5rem) clamp(1.25rem, 5vw, 5rem);
  background:
    radial-gradient(120% 90% at 84% 12%, rgba(127, 227, 212, .2) 0%, rgba(127, 227, 212, 0) 62%),
    linear-gradient(152deg, #5aad38 0%, #4c9c2e 46%, #3d7f25 100%);
}

.rv-hero__grain {
  position: absolute;
  inset: -20%;
  z-index: -1;
  background:
    radial-gradient(38% 34% at 22% 28%, rgba(255, 255, 255, .14) 0%, rgba(255, 255, 255, 0) 70%),
    radial-gradient(30% 40% at 78% 76%, rgba(6, 33, 58, .16) 0%, rgba(6, 33, 58, 0) 72%);
  pointer-events: none;
}

.rv-hero__leaf {
  position: absolute;
  left: -5%;
  bottom: -36%;
  z-index: -1;
  width: min(28vw, 20rem);
  color: rgba(255, 255, 255, .085);
  pointer-events: none;
}
.rv-hero__leaf svg { width: 100%; height: auto; }

.rv-hero__copy {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 30rem;
  margin-left: auto;
}

.rv-hero__title {
  margin-top: clamp(.9rem, 2.5vh, 1.5rem);
  font-family: var(--f-display);
  font-size: clamp(2.6rem, 1rem + 5.6vw, 4.6rem);
  font-weight: 400;
  line-height: 1.02;
  letter-spacing: -0.022em;
  color: #fff;
}
.rv-hero__title em { font-style: italic; color: rgba(255, 255, 255, .93); }

.rv-hero__tag {
  margin-top: clamp(.6rem, 1.6vh, 1rem);
  font-family: var(--f-display);
  font-style: italic;
  font-size: clamp(1rem, .9rem + .45vw, 1.28rem);
  color: rgba(255, 255, 255, .88);
}

.rv-hero__stage {
  position: relative;
  z-index: 1;
  display: flex;
  margin-left: calc(clamp(1.25rem, 3vw, 3.25rem) * -1);
  padding: clamp(.75rem, 1.6vw, 1.75rem);
  padding-left: 0;
}

.rv-hero__frame {
  position: relative;
  flex: 1;
  margin: 0;
  overflow: hidden;
  border-radius: var(--sv-r-xl);
  background: linear-gradient(120deg, #dceaf8, #bcd8f2);
  box-shadow: 0 30px 70px rgba(11, 45, 82, .22);
}
.rv-hero__photo {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 38%;
  will-change: transform;
}
.rv-hero__grade {
  position: absolute;
  inset: 0;
  background: radial-gradient(120% 90% at 50% 45%, rgba(6, 33, 58, 0) 46%, rgba(6, 33, 58, .26) 100%);
  pointer-events: none;
}


/* ==========================================================================
   02. THE WALL
   ---------------------------------------------------------------------------
   THE GROUND UNDER THE ROWS IS DELIBERATELY FLAT. The section fades in from
   the ivory above and out to #e8f2fd at the bottom — which is the colour the
   appointment band opens with — but it holds ONE tone across the whole depth
   the rows occupy. The edge fades in section 03 are painted in that tone, and
   a fade painted over a gradient is a fade with a visible seam down it.
   ========================================================================== */
.rv-wall {
  position: relative;
  isolation: isolate;
  overflow: clip;
  padding-block: clamp(3.5rem, 10vh, 7rem) clamp(3rem, 8vh, 5.5rem);
  background: linear-gradient(180deg,
              var(--sv-ivory) 0%,
              #eaf3fd 16%,
              #eaf3fd 76%,
              #e8f2fd 100%);
}

.rv-wall__wash {
  position: absolute;
  top: -14%;
  right: -8%;
  z-index: -1;
  width: min(56vw, 42rem);
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 50%,
              rgba(127, 227, 212, .2) 0%,
              rgba(110, 178, 244, .12) 46%,
              rgba(110, 178, 244, 0) 70%);
  filter: blur(18px);
  pointer-events: none;
}

.rv-wall__head {
  width: min(46rem, 100% - 2 * var(--gutter));
  margin-inline: auto;
  margin-bottom: clamp(2rem, 5vh, 3.5rem);
  text-align: center;
}

/* A drawn rule where a label would go. The design carries no eyebrow above
   this heading and inventing one would be inventing content, so the section
   opens with a mark instead of a word. */
.rv-wall__rule {
  display: block;
  width: 62px;
  height: 2px;
  margin: 0 auto clamp(1.1rem, 3vh, 1.8rem);
  border-radius: 2px;
  background: linear-gradient(90deg, var(--c-mint), var(--c-blue-500));
  transform: scaleX(0);
  transform-origin: 50% 50%;
}

.rv-wall__title { color: var(--c-blue-700); }
.rv-wall__title em { font-style: italic; color: var(--c-blue-500); }

.rv-wall__lede {
  max-width: 56ch;
  margin: clamp(1rem, 2.5vh, 1.5rem) auto 0;
  font-size: clamp(.98rem, .95rem + .18vw, 1.08rem);
  line-height: 1.75;
  color: var(--c-ink-soft);
}


/* ==========================================================================
   03. THE STAGE
   ---------------------------------------------------------------------------
   FULL BLEED, because a marquee that stops at a margin is a list that slides.
   The cards have to leave the frame, which is what the two fades are for.
   ========================================================================== */
.rv-stage {
  position: relative;
  /* The rows run the whole width of the page; only the card gutters are
     inset, and those come off the track's own padding. */
  width: 100%;
}

/* --- The unbuilt state: a card grid -------------------------------------- */
.rv-list {
  width: var(--sv-shell);
  margin-inline: auto;
  padding: 0;
  list-style: none;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 19rem), 1fr));
  gap: clamp(.9rem, 1.8vw, 1.4rem);
  align-items: stretch;
}
.rv-cell { display: flex; }

/* --- The built state: rows ------------------------------------------------ */
.rv-rows { display: none; }

.rv-stage.is-built .rv-list { display: none; }
.rv-stage.is-built .rv-rows {
  display: flex;
  flex-direction: column;
  gap: clamp(.9rem, 1.8vw, 1.4rem);
}

.rv-row {
  position: relative;
  overflow: hidden;
  /* A row is its own clipping frame. `clip` rather than `hidden` so a card's
     focus ring is not turned into a scroll position by the browser. */
  overflow: clip;
}

.rv-row__track {
  display: flex;
  align-items: stretch;
  gap: clamp(.9rem, 1.8vw, 1.4rem);
  /* max-content, so the track is as wide as its cards and never wraps them —
     the whole loop depends on one unbroken line. */
  width: max-content;
  padding: 6px 0;
  margin: 0;
  list-style: none;
  /* The engine writes `transform` on this element and nothing else writes to
     it, which is what keeps the marquee off the layout path entirely. */
  will-change: transform;
}

.rv-stage.is-built .rv-cell {
  flex: 0 0 auto;
  width: var(--w, 22rem);
}

/* --- The two edge fades ---------------------------------------------------
   Painted in the wall's own flat tone. They sit above the rows and take no
   pointer events, so a card under a fade is still hoverable. --------------- */
.rv-stage__fade {
  position: absolute;
  top: 0; bottom: 0;
  z-index: 3;
  width: clamp(2.5rem, 9vw, 11rem);
  pointer-events: none;
  opacity: 0;
  transition: opacity var(--t-med) var(--ease-out);
}
.rv-stage.is-built .rv-stage__fade { opacity: 1; }

.rv-stage__fade--l {
  left: 0;
  background: linear-gradient(90deg, #eaf3fd 12%, rgba(234, 243, 253, 0) 100%);
}
.rv-stage__fade--r {
  right: 0;
  background: linear-gradient(270deg, #eaf3fd 12%, rgba(234, 243, 253, 0) 100%);
}


/* ==========================================================================
   04. THE CARD
   ---------------------------------------------------------------------------
   Editorial rather than boxy: the Google mark and the rating on one line, the
   quote set in the serif at a size you can read from a moving row, and the
   patient's name last. The width comes from the review's own length — three
   steps, chosen in PHP, carried here as --w.
   ========================================================================== */
.rv-card {
  position: relative;
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100%;
  margin: 0;
  padding: clamp(1.15rem, 2.2vw, 1.6rem) clamp(1.2rem, 2.4vw, 1.75rem);
  background: linear-gradient(168deg, rgba(255, 255, 255, .96) 0%, rgba(247, 251, 255, .92) 100%);
  border: 1px solid rgba(127, 227, 212, .5);
  border-radius: var(--sv-r-lg);
  box-shadow: 0 6px 18px rgba(11, 45, 82, .06);
  transition: transform var(--t-med) var(--ease-out),
              box-shadow var(--t-med) var(--ease-out),
              border-color var(--t-med) var(--ease-out);
}
/* The hover lift. Small on purpose: the card is moving, and a card that jumps
   towards you as it passes is a card you cannot read. */
.rv-card:hover,
.rv-card:focus-visible {
  transform: translateY(-4px) scale(1.012);
  border-color: rgba(26, 114, 214, .5);
  box-shadow: 0 16px 40px rgba(11, 45, 82, .14);
}
.rv-card:focus-visible { outline: 2px solid var(--c-blue-500); outline-offset: 3px; }

.rv-card__top {
  display: flex;
  align-items: center;
  gap: .7rem;
  margin-bottom: clamp(.7rem, 1.6vh, 1rem);
}
.rv-card__g { display: grid; place-items: center; width: 26px; height: 26px; }
.rv-card__g svg { width: 20px; height: 20px; }

.rv-card__stars { display: inline-flex; gap: 2px; }
.rv-card__stars svg { width: 15px; height: 15px; fill: var(--c-star); }

.rv-card__quote {
  flex: 1;
  margin: 0;
  font-family: var(--f-display);
  font-size: clamp(1rem, .96rem + .22vw, 1.12rem);
  font-style: italic;
  line-height: 1.6;
  color: var(--c-blue-900);
}
.rv-card__quote p { margin: 0; }

.rv-card__by {
  display: flex;
  flex-direction: column;
  gap: .12rem;
  margin-top: clamp(.9rem, 2vh, 1.25rem);
  padding-top: clamp(.7rem, 1.6vh, 1rem);
  border-top: 1px solid rgba(120, 170, 225, .28);
}
.rv-card__name {
  font-family: var(--f-ui);
  font-size: .82rem;
  font-weight: 600;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--c-blue-900);
}
.rv-card__src {
  font-family: var(--f-ui);
  font-size: .76rem;
  color: var(--c-ink-faint);
}

/* --- A long review --------------------------------------------------------
   CLAMPED ONLY WHEN THE SCRIPT IS THERE TO UNDO IT. Without `.is-built` there
   is no Read More button, and text hidden behind a button that does not exist
   is text nobody can read. The mask fades the last line rather than cutting
   it, so it is obvious there is more.
   ------------------------------------------------------------------------- */
.rv-stage.is-built .rv-card[data-rv-long] .rv-card__quote {
  max-height: 9.6em;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(180deg, #000 68%, rgba(0, 0, 0, 0) 100%);
  mask-image: linear-gradient(180deg, #000 68%, rgba(0, 0, 0, 0) 100%);
  transition: max-height var(--t-slow) var(--ease-out);
}
.rv-stage.is-built .rv-card[data-rv-long].is-open .rv-card__quote {
  max-height: 40em;
  -webkit-mask-image: none;
  mask-image: none;
}

.rv-more {
  align-self: flex-start;
  margin-top: .6rem;
  padding: 0;
  font-family: var(--f-ui);
  font-size: .8rem;
  font-weight: 500;
  color: var(--c-blue-500);
  background: none;
  border: 0;
  cursor: pointer;
  transition: color var(--t-fast) var(--ease-out);
}
.rv-more:hover { color: var(--c-blue-900); }
.rv-more:focus-visible { outline: 2px solid var(--c-blue-500); outline-offset: 3px; }


/* ==========================================================================
   05. THE CONTROLS
   ---------------------------------------------------------------------------
   Three quiet buttons under the rows. They are `hidden` in the markup and
   revealed by reviews.js, because until the rows exist there is nothing for
   them to move.
   ========================================================================== */
.rv-ctrls {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: .6rem;
  margin-top: clamp(1.6rem, 4vh, 2.5rem);
}
.rv-ctrls[hidden] { display: none; }

.rv-ctrl {
  display: grid;
  place-items: center;
  /* 44px: a touch target before it is a button. */
  width: 44px; height: 44px;
  color: var(--c-blue-700);
  background: rgba(255, 255, 255, .8);
  border: 1px solid var(--sv-card-brd);
  border-radius: 50%;
  cursor: pointer;
  transition: transform var(--t-med) var(--ease-out),
              background var(--t-fast) var(--ease-out),
              box-shadow var(--t-med) var(--ease-out);
}
.rv-ctrl:hover { background: #fff; transform: translateY(-2px); box-shadow: var(--sh-sm); }
.rv-ctrl:focus-visible { outline: 2px solid var(--c-blue-500); outline-offset: 3px; }
.rv-ctrl svg { width: 18px; height: 18px; }
.rv-ctrl[data-rv-prev] svg { transform: rotate(180deg); }

/* One button, two glyphs — the same device the film's play control uses. */
.rv-ctrl--play { color: var(--c-blue-900); }
.rv-ctrl__pause,
.rv-ctrl__play { display: block; }
.rv-ctrl__pause {
  width: 3px; height: 13px;
  background: currentColor;
  border-radius: 2px;
  box-shadow: 6px 0 0 currentColor;
  transform: translateX(-3px);
}
.rv-ctrl__play {
  display: none;
  width: 0; height: 0;
  margin-left: 3px;
  border-top: 7px solid transparent;
  border-bottom: 7px solid transparent;
  border-left: 11px solid currentColor;
}
.rv-ctrl--play[aria-pressed="true"] .rv-ctrl__pause { display: none; }
.rv-ctrl--play[aria-pressed="true"] .rv-ctrl__play  { display: block; }


/* ==========================================================================
   06. ENTRY STATES
   ========================================================================== */
[data-rv-mask] { clip-path: inset(0% 0% 100% 0%); }
.no-js [data-rv-mask] { clip-path: none; }
.no-js .rv-wall__rule { transform: none; }


/* ==========================================================================
   07. RESPONSIVE
   ---------------------------------------------------------------------------
   Checked at 1440, 1280, 1024, 768, 480, 390 and 360.

   THE ROW COUNT IS NOT A MEDIA QUERY. reviews.js rebuilds the marquee with
   fewer rows below 980px and one row below 620px, because the number of rows
   changes how many cards each one holds — that is a rebuild, not a restyle.
   What is here is only what CSS can honestly own: widths, type and spacing.
   ========================================================================== */
@media (max-width: 1180px) {
  .rv-hero__inner { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .rv-hero__copy  { max-width: 26rem; }
}

@media (max-width: 980px) {
  .rv-hero__inner { grid-template-columns: minmax(0, 1fr); min-height: 0; }
  .rv-hero__copy  { max-width: none; margin-left: 0; }
  .rv-hero__panel { padding: clamp(2.25rem, 7vw, 3.5rem) clamp(1.25rem, 5vw, 3rem); }
  .rv-hero__leaf  { left: -14%; bottom: -42%; width: min(46vw, 18rem); }
  .rv-hero__stage { margin-left: 0; padding: 0; }
  .rv-hero__frame { aspect-ratio: 16 / 10; border-radius: var(--sv-r-lg) var(--sv-r-lg) 0 0; }
}

@media (max-width: 620px) {
  /* ONE CARD, AND A LOOK AT THE NEXT ONE. 82vw is the width that shows the
     edge of the following card without making the one you are reading
     narrower than a phone's comfortable measure — which is the whole point of
     the mobile carousel: it has to be obvious that it moves. */
  .rv-stage.is-built .rv-cell { width: min(82vw, 21rem); }
  /* Wide enough that the card leaving the screen fades out of a sentence
     rather than being cut off mid-word, narrow enough that it never covers
     the card you are reading. */
  .rv-stage__fade { width: clamp(1.75rem, 8vw, 3.5rem); }
  .rv-card__quote { font-size: 1.02rem; line-height: 1.62; }
}

@media (max-width: 400px) {
  .rv-stage.is-built .rv-cell { width: 84vw; }
}


/* ==========================================================================
   08. REDUCED MOTION
   ---------------------------------------------------------------------------
   reviews.js NEVER BUILDS THE MARQUEE when the query matches: it returns
   before touching the DOM, so `.is-built` is never added, the grid rules above
   stay in force and every review is on screen at once, in order, in a layout
   that holds still. That is the requirement met by not doing something, which
   is the only way to meet it honestly — a marquee with its animation paused is
   still a marquee with its content off screen.

   What is left here is the motion this file owns on its own: the card hover.
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  [data-rv-mask] { clip-path: none; }
  .rv-wall__rule { transform: none; }

  .rv-card { transition: none; }
  .rv-card:hover,
  .rv-card:focus-visible { transform: none; }
  .rv-ctrl { transition: none; }
  .rv-ctrl:hover { transform: none; }
  .rv-hero__photo { will-change: auto; }
}
