/* =====================================================================
   Woulfe's K9 — Client testimonials
   Depends on tokens.css.

   Replaces the Elfsight Google Reviews embed that used to sit here — a
   third-party script, on a third-party grid, in a third-party typeface.

   Composition: a quote either side of a tall photograph, arrows underneath.
   Built from the hero's vocabulary — rounded bordered frames, a shade that
   lifts toward the bottom, glass, display numerals, pill arrows that invert
   on hover — so the two read as the same page. See DESIGN-SYSTEM.md §9.

   Paging model: every card for every page is in the DOM at once, stacked in
   the same grid cell. Only the active one is visible. Nothing is measured,
   so a long quote and a short one can sit on consecutive pages without the
   section changing height mid-flick — the column is simply as tall as the
   tallest card in it.
   ===================================================================== */

.wk9-tm {
    /* Anchor target — the sticky bar would otherwise land on the heading. */
    scroll-margin-top: calc(var(--wk9-header-offset, 108px) + var(--k9-space-4));
    position: relative;
    box-sizing: border-box;
    padding: var(--k9-section-y) 0;
    background: var(--k9-surface);
    color: var(--k9-text);
    font-family: var(--k9-font-body);
    isolation: isolate;
    overflow: hidden;

    /* Full-bleed out of whatever container it is dropped into. */
    width: 100vw;
    max-width: 100vw;
    left: 50%;
    right: 50%;
    margin-left: -50vw;
    margin-right: -50vw;
}

.wk9-tm *,
.wk9-tm *::before,
.wk9-tm *::after { box-sizing: border-box; }

/* An ambient lift behind the photograph. Flat black across a full-width band
   reads as a gap between sections rather than a section; this gives the
   middle of the block somewhere to sit. Same radial the preloader uses. */
.wk9-tm__glow {
    position: absolute;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    background: radial-gradient(70% 55% at 50% 38%, var(--k9-ink-800) 0%, transparent 72%);
}

.wk9-tm__intro,
.wk9-tm__stage,
.wk9-tm__nav {
    width: min(var(--k9-container), calc(100% - (var(--k9-gutter) * 2)));
    margin-left: auto;
    margin-right: auto;
}

/* Intro ---------------------------------------------------------------- */

/* Centred, unlike the training rows above it. The stage below is symmetrical
   — a quote, a photograph, a quote — and a left-aligned heading over a
   symmetrical composition looks like a mistake rather than a decision. */
.wk9-tm__intro {
    max-width: 760px;
    margin-bottom: var(--k9-space-16);
    text-align: center;
}

.wk9-tm__eyebrow {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--k9-space-3);
    margin: 0 0 var(--k9-space-4);
    font-size: var(--k9-text-micro);
    font-weight: var(--k9-weight-bold);
    letter-spacing: var(--k9-tracking-micro);
    text-transform: uppercase;
    color: var(--k9-text-muted);
}

/* Rules both sides, because the label is centred. One rule on the left of a
   centred label reads as a bullet that has fallen over. */
.wk9-tm__eyebrow-rule {
    display: block;
    width: 32px;
    height: 1px;
    flex: 0 0 32px;
    background: var(--k9-text-faint);
}

.wk9-tm__heading {
    margin: 0;
    font-family: var(--k9-font-display);
    font-weight: var(--k9-weight-display);
    font-size: var(--k9-text-display-md);
    line-height: var(--k9-leading-display);
    letter-spacing: var(--k9-tracking-display);
    text-transform: uppercase;
    color: var(--k9-text);
    text-wrap: balance;
}

.wk9-tm__lede {
    margin: var(--k9-space-4) auto 0;
    max-width: 56ch;
    font-size: var(--k9-text-body-lg);
    line-height: var(--k9-leading-snug);
    color: var(--k9-text-muted);
}

/* Glass credibility pill under the heading — the one thing worth keeping
   from a reviews widget is the aggregate, so it survives the swap. */
.wk9-tm__badge {
    display: inline-flex;
    align-items: center;
    gap: var(--k9-space-3);
    margin-top: var(--k9-space-6);
    padding: var(--k9-space-2) var(--k9-space-5);
    border-radius: var(--k9-radius-pill);
    border: 1px solid rgba(255, 255, 255, 0.14);
    background: rgba(255, 255, 255, 0.06);
    -webkit-backdrop-filter: blur(18px) saturate(140%);
    backdrop-filter: blur(18px) saturate(140%);
    box-shadow: var(--k9-shadow-inset);
    font-size: var(--k9-text-micro);
    font-weight: var(--k9-weight-bold);
    letter-spacing: var(--k9-tracking-micro);
    text-transform: uppercase;
    color: var(--k9-text-secondary);
}

.wk9-tm__badge .wk9-tm__stars { color: var(--k9-text); }

/* Stretched link, so the stars and the words are all one target. */
.wk9-tm__badge {
    position: relative;
    transition: border-color var(--k9-duration-fast) var(--k9-ease);
}

.wk9-tm__badge-link {
    position: absolute;
    inset: 0;
    border-radius: inherit;
    text-decoration: none;
}

.wk9-tm__badge:hover { border-color: rgba(255, 255, 255, 0.32); }

.wk9-tm__badge:focus-within {
    outline: none;
    box-shadow: var(--k9-focus-ring);
}

/* Stage ---------------------------------------------------------------- */

.wk9-tm__stage {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.02fr) minmax(0, 1fr);
    align-items: center;
    gap: clamp(var(--k9-space-6), 3vw, var(--k9-space-12));
}

/* Every card in a column shares one grid cell, so the column is as tall as
   its tallest card and pages cross-fade in place. */
/* Stretch to the row rather than centring inside it, so both columns are as
   tall as the photograph between them — and the two cards therefore match
   each other. Centring each column independently leaves a long quote and a
   short one sitting at visibly different heights. */
.wk9-tm__col {
    display: grid;
    grid-template-areas: "stack";
    align-self: stretch;
    min-width: 0;
}

.wk9-tm__card {
    grid-area: stack;
    position: relative;
    height: 100%;
    display: flex;
    flex-direction: column;
    gap: var(--k9-space-5);
    padding: var(--k9-space-8) var(--k9-space-8) var(--k9-space-6);
    border-radius: var(--k9-radius-xl);
    border: 1px solid var(--k9-line);
    background:
        linear-gradient(180deg, rgba(255, 255, 255, 0.05) 0%, transparent 42%),
        var(--k9-surface-card);
    box-shadow: var(--k9-shadow-3), var(--k9-shadow-inset);

    /* visibility, not display — it takes the card out of the tab order and
       the accessibility tree while still allowing the fade. */
    opacity: 0;
    visibility: hidden;
    transform: translateY(10px);
    transition:
        opacity var(--k9-duration-slow) var(--k9-ease),
        transform var(--k9-duration-slow) var(--k9-ease),
        visibility 0s linear var(--k9-duration-slow);
}

.wk9-tm__card.is-active {
    opacity: 1;
    visibility: visible;
    transform: none;
    transition-delay: 0s;
}

/* The quote glyph. Staatliches is a caps display face and draws a thin
   straight mark, so this one comes from Archivo at its heaviest — it is a
   graphic element, and it has to have some weight to it. */
.wk9-tm__mark {
    display: block;
    font-family: var(--k9-font-body);
    font-weight: var(--k9-weight-black);
    font-size: 64px;
    line-height: 0.5;
    height: 32px;
    color: rgba(255, 255, 255, 0.22);
    user-select: none;
}

.wk9-tm__quote {
    margin: 0;
    font-size: var(--k9-text-body);
    line-height: 1.65;
    color: var(--k9-text-secondary);
    /* Keep the reviewer's own paragraph breaks. */
    white-space: pre-line;
}

/* Long reviews show their opening lines; the toggle reveals the rest. */
.wk9-tm__quote.is-long .wk9-tm__text {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 9;
    line-clamp: 9;
    overflow: hidden;
}
.wk9-tm__quote.is-long.is-open .wk9-tm__text {
    display: block;
    -webkit-line-clamp: unset;
    line-clamp: none;
    overflow: visible;
}

/* A text link, not a button. BeTheme styles button and button:hover at
   (0,1,1), hence the extra weight. */
html body .wk9-tm .wk9-tm__more,
html body .wk9-tm .wk9-tm__more:hover {
    appearance: none;
    align-self: flex-start;
    margin: var(--k9-space-2) 0 0;
    padding: 0;
    border: 0;
    background: none;
    box-shadow: none;
    color: var(--k9-text);
    font: inherit;
    font-size: var(--k9-text-caption);
    font-weight: var(--k9-weight-bold);
    letter-spacing: var(--k9-tracking-micro);
    text-transform: uppercase;
    text-decoration: underline;
    text-underline-offset: 3px;
    cursor: pointer;
    min-height: 0;
    width: auto;
}
html body .wk9-tm .wk9-tm__more:hover { color: var(--k9-text-secondary); }
html body .wk9-tm .wk9-tm__more:focus-visible { outline: 2px solid var(--k9-text); outline-offset: 3px; }

.wk9-tm__stars {
    display: inline-flex;
    gap: 3px;
    color: var(--k9-text);
    line-height: 0;
}

.wk9-tm__stars svg { display: block; }
.wk9-tm__star--off { color: var(--k9-text-faint); }

/* Attribution ---------------------------------------------------------- */

.wk9-tm__by {
    display: flex;
    align-items: center;
    gap: var(--k9-space-4);
    margin-top: auto;
    padding-top: var(--k9-space-5);
    border-top: 1px solid var(--k9-line);
}

.wk9-tm__avatar {
    position: relative;
    flex: 0 0 48px;
    width: 48px;
    height: 48px;
    overflow: hidden;
    border-radius: var(--k9-radius-pill);
    border: 1px solid var(--k9-line-strong);
    background: var(--k9-surface-card-2);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-family: var(--k9-font-display);
    font-weight: var(--k9-weight-display);
    font-size: var(--k9-text-title-sm);
    letter-spacing: var(--k9-tracking-display);
    color: var(--k9-text-secondary);
}

.wk9-tm__avatar img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.wk9-tm__name {
    display: block;
    margin: 0;
    font-size: var(--k9-text-body-sm);
    font-weight: var(--k9-weight-bold);
    color: var(--k9-text);
}

.wk9-tm__meta {
    display: block;
    margin: 2px 0 0;
    font-size: var(--k9-text-caption);
    color: var(--k9-text-muted);
}

/* Media ---------------------------------------------------------------- */

.wk9-tm__media { min-width: 0; }

/* The hero card, reused: same radius, same hairline, same elevation. */
.wk9-tm__frame {
    position: relative;
    display: grid;
    grid-template-areas: "stack";
    grid-template-columns: 100%;
    grid-template-rows: 100%;
    overflow: hidden;
    margin: 0;
    aspect-ratio: 4 / 5;
    border-radius: var(--k9-radius-xl);
    border: 1px solid var(--k9-line);
    background: var(--k9-surface-card);
    box-shadow: var(--k9-shadow-4);
}

/* Scoped to two classes deliberately. BeTheme ships img:not([src$=".svg"])
   at specificity (0,1,1), which beats a single class and forces height:auto —
   the picture then falls back to its own ratio and leaves a strip of bare
   card at the bottom of the frame. See DESIGN-SYSTEM.md §12, rule 9. */
.wk9-tm__frame .wk9-tm__img {
    grid-area: stack;
    width: 100%;
    height: 100%;
    object-fit: cover;
    opacity: 0;
    transform: scale(1.04);
    transition:
        opacity var(--k9-duration-slow) var(--k9-ease),
        transform 1.2s var(--k9-ease);
}

.wk9-tm__frame .wk9-tm__img.is-active {
    opacity: 1;
    transform: scale(1.001);
}

.wk9-tm__img--empty {
    grid-area: stack;
    opacity: 1;
    background: repeating-linear-gradient(
        135deg,
        var(--k9-surface-inset) 0 12px,
        var(--k9-surface-card) 12px 24px
    );
}

.wk9-tm__shade {
    grid-area: stack;
    position: relative;
    pointer-events: none;
    background: linear-gradient(
        to top,
        rgba(var(--k9-black-rgb), 0.66) 0%,
        rgba(var(--k9-black-rgb), 0.14) 40%,
        rgba(var(--k9-black-rgb), 0) 68%
    );
}

/* Caption riding the bottom of the frame, on the hero's glass. */
.wk9-tm__caption {
    grid-area: stack;
    position: relative;
    align-self: end;
    justify-self: start;
    margin: var(--k9-space-5);
    padding: var(--k9-space-3) var(--k9-space-5);
    border-radius: var(--k9-radius-pill);
    border: 1px solid rgba(255, 255, 255, 0.16);
    background: rgba(var(--k9-black-rgb), 0.42);
    -webkit-backdrop-filter: blur(18px) saturate(140%);
    backdrop-filter: blur(18px) saturate(140%);
    box-shadow: var(--k9-shadow-inset);
    font-size: var(--k9-text-micro);
    font-weight: var(--k9-weight-bold);
    letter-spacing: var(--k9-tracking-micro);
    text-transform: uppercase;
    color: var(--k9-text-secondary);
}

/* Nav ------------------------------------------------------------------ */

.wk9-tm__nav {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--k9-space-4);
    margin-top: var(--k9-space-12);
}

/* Same pill arrow as the hero deck, so the two carousels on the page are
   operated by the same control. */
.wk9-tm__arrow {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 52px;
    height: 52px;
    flex: 0 0 52px;
    padding: 0;
    border: 1px solid var(--k9-line-strong);
    border-radius: var(--k9-radius-pill);
    background: rgba(255, 255, 255, 0.04);
    color: var(--k9-text);
    cursor: pointer;
    transition:
        background var(--k9-duration-fast) var(--k9-ease),
        border-color var(--k9-duration-fast) var(--k9-ease),
        color var(--k9-duration-fast) var(--k9-ease),
        transform var(--k9-duration-fast) var(--k9-ease);
}

.wk9-tm__arrow:hover {
    background: var(--k9-action);
    border-color: var(--k9-action);
    color: var(--k9-action-text);
}

.wk9-tm__arrow:active { transform: translateY(1px); }

.wk9-tm__arrow:focus-visible {
    outline: none;
    box-shadow: var(--k9-focus-ring);
}

/* Forward is the primary action, so it carries the solid fill — the only
   accent this system has is contrast. */
.wk9-tm__arrow--primary {
    background: var(--k9-action);
    border-color: var(--k9-action);
    color: var(--k9-action-text);
}

.wk9-tm__arrow--primary:hover {
    background: var(--k9-action-hover);
    border-color: var(--k9-action-hover);
}

.wk9-tm__count {
    min-width: 68px;
    text-align: center;
    font-size: var(--k9-text-micro);
    font-weight: var(--k9-weight-bold);
    letter-spacing: var(--k9-tracking-micro);
    text-transform: uppercase;
    color: var(--k9-text-muted);
    font-variant-numeric: tabular-nums;
}

/* Responsive ----------------------------------------------------------- */

/* Three columns stop working long before the container does — the quote
   cards hit a two-word measure first. */
@media (max-width: 1080px) {
    .wk9-tm__stage {
        grid-template-columns: minmax(0, 1fr);
        gap: var(--k9-space-8);
        max-width: 640px;
    }

    /* Photograph first: it is the thing worth leading with, and stacking it
       between two quotes would separate them for no reason. */
    .wk9-tm__media { order: -1; }
    .wk9-tm__frame { aspect-ratio: 16 / 11; }

    .wk9-tm__intro { margin-bottom: var(--k9-space-10); }
    .wk9-tm__nav { margin-top: var(--k9-space-10); }
}

@media (max-width: 600px) {
    .wk9-tm__card { padding: var(--k9-space-6); }
    .wk9-tm__frame { aspect-ratio: 4 / 3; }
    .wk9-tm__mark { font-size: 52px; height: 26px; }
}

@media (prefers-reduced-motion: reduce) {
    .wk9-tm__card,
    .wk9-tm__frame .wk9-tm__img,
    .wk9-tm__arrow { transition: none; }
    .wk9-tm__card { transform: none; }
    .wk9-tm__frame .wk9-tm__img,
    .wk9-tm__frame .wk9-tm__img.is-active { transform: none; }
}

/* Google ------------------------------------------------------------------
   Under the carousel when the reviews come from Google: "See all reviews"
   (with Google's G, as its attribution rules ask), "Leave a review", and a
   quiet source line. */

.wk9-tm__google {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: var(--k9-space-3);
    width: min(var(--k9-container), calc(100% - (var(--k9-gutter) * 2)));
    margin: var(--k9-space-8) auto 0;
}

.wk9-tm__gbtn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--k9-space-2);
    min-height: 48px;
    padding: 0 var(--k9-space-5);
    border-radius: var(--k9-radius-pill);
    background: var(--k9-action);
    color: var(--k9-action-text) !important;
    font-family: var(--k9-font-body);
    font-size: var(--k9-text-body-sm);
    font-weight: var(--k9-weight-bold);
    letter-spacing: 0.03em;
    text-transform: uppercase;
    text-decoration: none !important;
    transition:
        transform var(--k9-duration) var(--k9-ease),
        background var(--k9-duration) var(--k9-ease);
}

.wk9-tm__gbtn:hover { background: var(--k9-action-hover); transform: translateY(-1px); }

.wk9-tm__gbtn--ghost {
    background: transparent;
    color: var(--k9-text) !important;
    box-shadow: inset 0 0 0 1px var(--k9-line-strong);
}

.wk9-tm__gbtn--ghost:hover { background: var(--k9-surface-hover); }

.wk9-tm__g { flex: 0 0 auto; display: block; }

.wk9-tm__source {
    flex-basis: 100%;
    margin: var(--k9-space-1) 0 0;
    text-align: center;
    font-size: var(--k9-text-caption);
    color: var(--k9-text-faint);
}

/* Google photos arrive as plain <img>; fill the round avatar like ours. */
.wk9-tm__avatar img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    border-radius: inherit;
}
