/**
 * Section: Testimonials
 *
 * Ported from _mockups/testimonials.html `.ts-grid` / `.ts-card` /
 * `.ts-featured` / `.ts-stars` / `.ts-intro`. That page is the only consumer of
 * this component in the 27, so there is no drift to resolve.
 *
 * The starter's stylesheet that this replaces belonged to a different design
 * and carried a hardcoded 20px quote size (inventory §A.3). Nothing in here is
 * a literal colour or a literal type size, and the comment above is worded to
 * keep that greppable gate clean.
 *
 * WHAT IS DELIBERATELY NOT HERE, because components.css already owns it and a
 * second owner for one rule is how the button system broke in Phase 0:
 *
 *   .card      the paper ground, hairline, radius and resting shadow. The card
 *              markup is `class="card ts-card"` and only the delta is below.
 *   .note      the small grey line, which `.ts-intro` only positions.
 *   .ph-badge  including its `.on-dark` form, which the featured card's
 *              placeholder uses.
 *   .icon      the star glyph sizing, in em, so the row tracks its own text
 *              rather than needing a pixel width.
 *
 * Every override of `.card` below is written at `.ts-card.ts-featured`, two
 * classes, so it beats `.card` on specificity rather than on load order.
 *
 * ---------------------------------------------------------------------------
 * CONTRAST, MEASURED, NOT ESTIMATED
 *
 * The featured card is `linear-gradient(150deg, var(--forest), var(--deep-forest))`,
 * so --forest #0e4038 is the worst case and every number below is taken on it.
 * The deep-forest end of the gradient is darker and therefore kinder.
 *
 *   --paper           #ffffff                11.61:1   headline, name
 *   --on-dark-strong  rgba(255,255,255,.82)   8.36:1   the quote
 *   --on-dark         rgba(255,255,255,.66)   6.01:1   district and date
 *   --gold-bright     #d8b25e                 5.78:1   stars, badge border
 *
 * All four clear WCAG AA for normal text. NEVER a tint token here: --brand-tint
 * is translucent forest and composites to 1.00:1 on this ground, and --gold-deep
 * measures 2.03:1. AGENTS.md §1.7.
 *
 * On the light card the text is --ink (16.28:1), --ink-soft (8.18:1 on paper)
 * and --ink-faint (5.55:1 on paper).
 *
 * THE ONE VALUE BELOW 3:1, STATED PLAINLY. The star row on a light card is
 * --gold on --paper, 2.56:1. It is the signed-off colour and it stays, and the
 * exemption is stronger than "decorative":
 *
 *   - The row conveys NO RATING BY CONSTRUCTION. It is five fixed stars on
 *     every card, tied to no field, so "a graphic required to understand the
 *     content" under SC 1.4.11 is not arguable, it is false. Its `role="img"`
 *     label carries the whole of what it means, including that it is
 *     illustrative.
 *   - The featured row is --gold-bright on forest, 5.78:1, so the light card is
 *     the ONLY instance in the section under 3:1.
 *   - `.ts-stars` never appears outside a `.card`, so --paper is genuinely the
 *     operative ground. On the mist band it would be 2.33:1, and that case
 *     cannot arise.
 *
 * This is open question D4 in the inventory, where the star row goes back to the
 * client. The measurement belongs there too, not only in this header.
 * ------------------------------------------------------------------------- */

/* --- the note above the cards -------------------------------------------- */
/* Flex rather than a plain block because the line is written to end in a
   `.ph-badge` and the two must sit on one baseline when it does. */
.testimonials .ts-intro {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .6em;
  margin-bottom: var(--s-5);
}

/* --- the grid ------------------------------------------------------------
   The column count is DERIVED FROM THE CONTENT and arrives as `ts-cols-1`,
   `ts-cols-2` or `ts-cols-3` from the renderer, so one or two testimonials fill
   the row instead of leaving a hole beside a third of a grid. Not a field: the
   client never chooses this, the number of published quotes does.

   auto-fit was tried first and rejected. It collapses empty tracks, which is
   the appealing part, but the track count then depends on the container width
   rather than on a breakpoint, and the featured card's `span 2` does not: there
   is a band around 620 to 650px where auto-fit has already dropped to one
   column and the span is still asking for two, which creates an implicit second
   column and pushes the page sideways. Fixed counts and the mock-up's own
   breakpoints keep the two facts in step.

   `minmax(0, 1fr)` rather than `1fr`, so a long unbroken word cannot push a
   track wider than its share. */
.testimonials .ts-grid {
  display: grid;
  gap: var(--s-4);
}

.testimonials .ts-cols-1 { grid-template-columns: minmax(0, 1fr); }
.testimonials .ts-cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.testimonials .ts-cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }

/* --- the card ------------------------------------------------------------- */
.testimonials .ts-card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
  padding: var(--s-5);
  overflow: hidden;
  transition: border-color var(--dur-normal) ease,
              box-shadow var(--dur-normal) ease,
              transform var(--dur-normal) var(--ease-out-soft);
}

.testimonials .ts-card:hover {
  border-color: var(--gold);
  box-shadow: var(--shadow-m);
  transform: translateY(-4px);
}

/* The oversized opening quotation mark, bled off the top-right corner and
   clipped by the card's own overflow. Decorative, pointer-transparent, and it
   is why the quote itself is never wrapped in marks the family did not write.

   The mock-up sets a flat 7rem and there is no token for a decorative display
   glyph at that scale, so this is expressed against the top of the type ladder:
   --text-3xl is clamp(2rem, 1.5rem + 2.3vw, 3.25rem), doubled.

   THAT IS A BEHAVIOUR CHANGE, NOT A NOTATION ONE, and calling it notation would
   mislead the next agent who copies the pattern somewhere it matters. Measured:
   104px at 1440, 7% under the mock-up's 112px, but 64px from 320 to 620 where
   --text-3xl sits on its clamp floor, which is 43% under. The impact here is
   near zero, because the glyph is a watermark at 0.12 alpha and a 7rem mark on
   a 280px card would dominate it, so the fluid behaviour is arguably the better
   one. Somewhere the size carries meaning it would not be.

   THE COLOUR WAS --gold-tint-10, A TINT TOKEN IN A `color` DECLARATION, which
   AGENTS.md §1.7 forbids without exception. --watermark-gold is that same tint
   flattened on the card's own --paper ground, 248,243,233 measured off a
   painted pixel rather than derived, so nothing about the rendering changes;
   the reasoning, and why it is exact for antialiased edges as well as solid
   coverage, is in tokens.css. The point is the mechanism, not
   the pixels: a tint is a surface fill, and every one of them sitting in a
   `color` is a place where the next reader "fixes" a contrast that was
   deliberate. A token named --watermark cannot be read as text. */
.testimonials .ts-card::before {
  content: "\201C";
  position: absolute;
  top: -.28em;
  right: .12em;
  font-family: var(--display);
  font-size: calc(var(--text-3xl) * 2);
  line-height: 1;
  color: var(--watermark-gold);
  pointer-events: none;
}

.testimonials .ts-card h3 {
  font-size: var(--text-xl);
}

.testimonials .ts-card h3,
.testimonials .ts-card blockquote {
  /* A pasted URL or a long unbroken word in a real quote must wrap rather than
     be clipped by the card's own overflow. */
  overflow-wrap: break-word;
}

.testimonials .ts-card blockquote {
  margin: 0;
  color: var(--ink-soft);
  font-size: var(--text-base);
  /* Pushes the meta row to the foot of every card so a row of cards agrees on
     where the names sit, whatever the quotes are worth in lines. */
  flex-grow: 1;
  /* A real testimonial arrives as the family wrote it, sometimes over two
     paragraphs. The quote is one textarea escaped with esc_html(), so those
     breaks have no markup to carry them; pre-line renders them as written. */
  white-space: pre-line;
}

/* --- the star row ---------------------------------------------------------
   Visual only. The section emits role="img" with an "illustrative only" label
   and never a Review or an AggregateRating. Sized in em through the shared
   .icon class, so no pixel width is needed here. */
.testimonials .ts-stars {
  display: inline-flex;
  align-items: center;
  gap: .15em;
  color: var(--gold);
}

/* --- who said it ---------------------------------------------------------- */
.testimonials .ts-card .meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .6em var(--s-3);
  border-top: 1px solid var(--line);
  padding-top: var(--s-3);
}

.testimonials .ts-card .who {
  display: flex;
  flex-direction: column;
  gap: .1em;
  /* Pushes the placeholder badge to the far end of the row when there is one. */
  margin-right: auto;
}

.testimonials .ts-card .who strong {
  font-family: var(--display);
  font-weight: 600;
  color: var(--ink);
}

.testimonials .ts-card .who span {
  font-size: var(--text-sm);
  color: var(--ink-faint);
}

/* The middot between district and date. A pseudo-content separator would be
   read aloud by some screen readers, so it is a real element the section marks
   aria-hidden, and it only exists when both sides do. */
.testimonials .ts-card .who .sep {
  margin-inline: .45em;
  color: var(--line);
}

/* --- the featured card ---------------------------------------------------
   Two classes, so it beats .card in components.css on specificity and not on
   which file happened to load last. */
.testimonials .ts-card.ts-featured {
  grid-column: span 2;
  background: linear-gradient(150deg, var(--forest), var(--deep-forest));
  border-color: transparent;
}

/* THE ONE PLACE IN THIS FILE WHERE A COLOUR IS SUBSTITUTED RATHER THAN A UNIT,
   so it is stated exactly. The mock-up watermarks the featured card at
   rgba(216,178,94,.14): --gold-bright at 14%, a token that does not exist.
   --gold-tint-20 is rgba(201,154,71,.22), which is a different hue (--gold, not
   --gold-bright) at 57% more alpha. Not "a shade stronger".

   Kept anyway, and measured rather than assumed: the quote sitting under this
   watermark goes from 6.73:1 to 6.32:1, still clear of AA, on a decorative
   pseudo-element behind the copy. The alternative was to delete this rule and
   let the featured card inherit the light-card watermark (.12 alpha, much
   closer to .14), but that is base gold at 12% on deep forest, where it all but
   disappears and the card loses the watermark the design gives it. A
   --gold-bright-tint token would resolve this properly and is reported rather
   than added.

   THE ONE WATERMARK THAT STAYS TRANSLUCENT, and it is stated rather than
   fudged. The other two in this theme were flattened onto their grounds so no
   tint token sits in a `color` (AGENTS.md §1.7); this one paints on
   `linear-gradient(150deg, var(--forest), var(--deep-forest))`, so it
   composites to #36543b at one end of the gradient and #324630 at the other. A
   single solid value would be correct at one point on it and wrong along the
   rest, so the fix here is the NAME: --watermark-gold-on-dark is a decoration
   token, not a surface fill, and cannot be mistaken for a text colour. */
.testimonials .ts-card.ts-featured::before {
  color: var(--watermark-gold-on-dark);
}

.testimonials .ts-card.ts-featured h3 {
  color: var(--paper);           /* 11.61:1 */
  font-size: var(--text-2xl);
}

.testimonials .ts-card.ts-featured blockquote {
  color: var(--on-dark-strong);  /* 8.36:1 */
  font-family: var(--display);
  font-size: var(--text-lg);
}

.testimonials .ts-card.ts-featured .meta {
  border-top-color: var(--on-dark-line);
}

.testimonials .ts-card.ts-featured .who strong {
  color: var(--paper);           /* 11.61:1 */
}

.testimonials .ts-card.ts-featured .who span {
  color: var(--on-dark);         /* 6.01:1 */
}

.testimonials .ts-card.ts-featured .who .sep {
  color: var(--on-dark-faint);
}

.testimonials .ts-card.ts-featured .ts-stars {
  color: var(--gold-bright);     /* 5.78:1 */
}

.testimonials .ts-card.ts-featured:hover {
  border-color: var(--gold);
}

/* --- breakpoints (canonical: 1024 / 860 / 620 / 560) ---------------------- */
@media (max-width: 860px) {
  .testimonials .ts-cols-3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* One column here, so the featured card's span goes with it: two columns asked
   for in a one-column grid would create an implicit track and push the page
   sideways. Both facts change at the same breakpoint on purpose. */
@media (max-width: 620px) {
  .testimonials .ts-cols-2,
  .testimonials .ts-cols-3 { grid-template-columns: minmax(0, 1fr); }
  .testimonials .ts-card.ts-featured { grid-column: auto; }
  .testimonials .ts-card { padding: var(--s-4); }
}
