/* =================================================================
   Vocalis Studio — Landing page styles
   Companion to tokens.css. Class names map 1:1 to the markup in
   template-parts/landing/*.php.
   ================================================================= */

[hidden] { display: none !important; }

/* WordPress admin bar compensation for fixed landing navbar */
.admin-bar .vx-navbar-wrap { top: 32px; }
@media screen and (max-width: 782px) { .admin-bar .vx-navbar-wrap { top: 46px; } }

#vx-landing {
  position: relative;
  min-height: 100vh;
  overflow-x: hidden;
  background: var(--background);
  /* Full-page gradient overlay — same radial blobs as hero but extended */
  background-image:
    radial-gradient(65% 45% at 50% 0%,  rgba(139, 92, 246, 0.22) 0%, transparent 60%),
    radial-gradient(55% 35% at 95% 10%, rgba(91, 156, 246, 0.24) 0%, transparent 60%),
    radial-gradient(45% 30% at  5% 20%, rgba(224, 123, 208, 0.16) 0%, transparent 55%);
}

.vx-section { position: relative; padding: 6rem 0; }
@media (min-width: 768px) { .vx-section { padding: 8rem 0; } }

.vx-section-head { margin-inline: auto; text-align: center; }
.vx-h2 { margin-top: 0.75rem; font-size: 2.25rem; font-weight: 700; letter-spacing: -0.03em; }
@media (min-width: 640px) { .vx-h2 { font-size: 3rem; } }
.vx-lede { margin-top: 1rem; font-size: 1rem; color: var(--muted-foreground); }
@media (min-width: 640px) { .vx-lede { font-size: 1.125rem; } }

.vx-grid { display: grid; gap: 1.25rem; grid-template-columns: 1fr; }
.vx-grid--3 { }
@media (min-width: 640px) { .vx-grid--3 { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1024px) { .vx-grid--3 { grid-template-columns: repeat(3, 1fr); } }

.vx-pill {
	display: inline-flex; align-items: center; gap: 0.5rem;
	border-radius: var(--r-full); padding: 0.375rem 0.875rem;
	font-size: 0.75rem; font-weight: 500; color: rgba(30, 27, 75, 0.8);
}
.vx-pill svg { color: #8b5cf6; color: var(--brand-purple); }
.vx-pill-muted {
	display: inline-flex; align-items: center; border-radius: var(--r-full);
	background: var(--secondary); padding: 0.25rem 0.75rem;
	font-size: 0.7rem; font-weight: 600; color: var(--muted-foreground);
}

.vx-btn-lg { padding: 0.875rem 1.5rem; }

/* ---- tints used by feature/testimonial card glows ---- */
.vx-tint-1 { background: linear-gradient(135deg, color-mix(in oklab, var(--brand-blue) 20%, transparent), color-mix(in oklab, var(--brand-purple) 10%, transparent)); }
.vx-tint-2 { background: linear-gradient(135deg, color-mix(in oklab, var(--brand-purple) 25%, transparent), color-mix(in oklab, var(--brand-pink) 15%, transparent)); }
.vx-tint-3 { background: linear-gradient(135deg, color-mix(in oklab, var(--brand-pink) 20%, transparent), color-mix(in oklab, var(--brand-blue) 10%, transparent)); }
.vx-tint-4 { background: linear-gradient(135deg, color-mix(in oklab, var(--brand-blue) 25%, transparent), color-mix(in oklab, var(--brand-pink) 10%, transparent)); }
.vx-tint-5 { background: linear-gradient(135deg, color-mix(in oklab, var(--brand-purple) 20%, transparent), color-mix(in oklab, var(--brand-blue) 15%, transparent)); }
.vx-tint-6 { background: linear-gradient(135deg, color-mix(in oklab, var(--brand-pink) 25%, transparent), color-mix(in oklab, var(--brand-purple) 10%, transparent)); }

/* =================================================================
   Navbar
   ================================================================= */
/* `.vx-container-xl` and `.vx-btn-outline` are used by the front page but
   were not available to it: the first is defined in app.css (never enqueued
   here), the second was not defined anywhere at all — so the hero's "Hear a
   sample" button has been rendering unstyled. Both defined here.

   `.vx-container-xl` intentionally matches app.css's value exactly, so the
   homepage header and the studio header line up at the same width. */
.vx-container-xl { max-width: 80rem; margin-inline: auto; }

.vx-btn-outline {
	background: var(--card);
	color: var(--foreground);
	box-shadow: inset 0 0 0 1px var(--border), var(--shadow-soft);
}
.vx-btn-outline:hover { background: var(--secondary); }

/* ── Navigation ───────────────────────────────────────────────────────────
   A floating glass pill, matching the studio's own header so the marketing
   site and the app read as one product.

   The row is a strict three-part flex — brand / links / actions — and every
   part is `flex-shrink: 0` except the link list, which is the only thing
   allowed to give way. That is what stops the previous version's failure:
   the buttons were in a nested wrapper with no room reserved for it, so on a
   narrow screen the row wrapped onto a second line and spilled out of the
   pill.
   ------------------------------------------------------------------------ */
/* `sticky`, not `fixed`. The studio's header is fixed because its pages
   scroll under a permanently-visible bar; here the pill starts in normal
   flow, which means the hero's existing top padding still clears it and
   nothing below had to be re-spaced. It still pins to the top on scroll —
   same look, none of the overlap. */
.vx-navbar-wrap { position: sticky; top: 0; z-index: 50; padding: 0.75rem 0.75rem 0; }
@media (min-width: 640px) { .vx-navbar-wrap { padding: 1rem 1.25rem 0; } }

.vx-navbar {
	display: flex;
	align-items: center;
	gap: 0.5rem;
	border-radius: var(--r-full);
	padding: 0.5rem 0.75rem;
	box-shadow: var(--shadow-soft);
}
@media (min-width: 640px) { .vx-navbar { padding: 0.5rem 1rem; } }

.vx-navbar__brand { display: flex; align-items: center; gap: 0.5rem; flex-shrink: 0; }
.vx-navbar__mark { width: 2rem; height: 2rem; flex-shrink: 0; }
.vx-navbar__brand-name { font-size: 1rem; font-weight: 600; letter-spacing: -0.02em; white-space: nowrap; }

/* The only flexible part of the row. Hidden below 1024px, where the drawer
   takes over. */
.vx-navbar__links {
	display: none;
	align-items: center;
	gap: 0.125rem;
	list-style: none;
	margin: 0 auto;
	padding: 0;
	min-width: 0;
}
.vx-navbar__links a {
	display: block;
	border-radius: var(--r-full);
	padding: 0.375rem 0.75rem;
	font-size: 0.875rem;
	font-weight: 500;
	color: var(--muted-foreground);
	white-space: nowrap;
	transition: background-color 0.2s ease, color 0.2s ease;
}
.vx-navbar__links a:hover { background: var(--secondary); color: var(--foreground); }

/* Pushed hard right, and never allowed to shrink or wrap. */
.vx-navbar__actions {
	display: flex;
	align-items: center;
	gap: 0.375rem;
	margin-inline-start: auto;
	flex-shrink: 0;
}
.vx-navbar__signin { display: none; padding: 0.375rem 0.75rem; font-size: 0.875rem; font-weight: 500; color: var(--muted-foreground); border-radius: var(--r-full); white-space: nowrap; }
.vx-navbar__signin:hover { color: var(--foreground); }
.vx-navbar__cta { display: none; padding: 0.5rem 1rem; white-space: nowrap; }

/* `.vx-icon-btn` lives in app.css, which is NOT enqueued on the front page —
   so on the homepage these two buttons had no styling at all and fell back to
   the browser's default button chrome (a bordered rounded rectangle). Defined
   here with the same values as the app's, so the header matches the studio's.

   Worth noting how this got through: the check that confirmed "every class is
   defined" concatenated ALL stylesheets before searching, so a class defined
   in app.css looked present even on a page that never loads app.css. Which
   file a rule lives in matters as much as whether it exists. */
.vx-icon-btn {
	display: grid;
	place-items: center;
	width: 2.25rem;
	height: 2.25rem;
	border: none;
	cursor: pointer;
	border-radius: var(--r-full);
	background: var(--secondary);
	color: var(--foreground);
	transition: transform 0.15s ease;
}
.vx-icon-btn:hover { transform: scale(1.05); }
.vx-icon-btn:active { transform: scale(0.95); }

/* Theme switch — writes the same `vx-theme` key and `data-vx-theme`
   attribute the studio's own switcher uses, so one choice covers the site. */
.vx-navbar__theme-moon { display: none; }
[data-vx-theme="dark"] .vx-navbar__theme-sun { display: none; }
[data-vx-theme="dark"] .vx-navbar__theme-moon { display: block; }

.vx-navbar__mobile {
	display: none;
	margin-top: 0.5rem;
	border-radius: var(--r-3xl);
	padding: 0.75rem;
	max-height: 70vh;
	overflow-y: auto;
	overscroll-behavior: contain;
}
.vx-navbar__mobile:not([hidden]) { display: block; }
.vx-navbar__mobile ul { list-style: none; margin: 0; padding: 0; }
.vx-navbar__mobile a { display: block; border-radius: var(--r-2xl); padding: 0.6875rem 1rem; font-size: 0.9375rem; font-weight: 500; color: var(--foreground); }
.vx-navbar__mobile a:hover { background: var(--secondary); }
.vx-navbar__mobile-label { margin: 0.75rem 0 0.25rem; padding-inline: 1rem; font-size: 0.6875rem; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; color: var(--muted-foreground); }
.vx-navbar__mobile-label:first-child { margin-top: 0.25rem; }
.vx-navbar__mobile-cta { margin-top: 0.5rem; }

@media (min-width: 1024px) {
	.vx-navbar__links { display: flex; }
	.vx-navbar__signin { display: inline-block; }
	.vx-navbar__cta { display: inline-flex; }
	.vx-navbar__toggle { display: none; }
}

/* ── Hero ─────────────────────────────────────────────────────────────────
   No blobs. The old hero ran three large blurred, continuously-animating
   surfaces behind the first thing that has to paint on the page; the section
   is now flat, which is both the cleaner look and one less thing competing
   for the first frame. */
.vx-hero { padding: 3.5rem 0 2.25rem; }
@media (min-width: 768px) { .vx-hero { padding: 5rem 0 3rem; } }
.vx-hero__inner { max-width: 52rem; margin-inline: auto; text-align: center; }

.vx-hero__badge {
	display: inline-flex; align-items: center; gap: 0.4375rem;
	border-radius: var(--r-full);
	background: var(--secondary);
	padding: 0.4375rem 0.875rem;
	font-size: 0.75rem; font-weight: 600;
	color: var(--muted-foreground);
	text-decoration: none;
	transition: background-color 0.2s ease;
}
.vx-hero__badge:hover { background: var(--accent); }
.vx-hero__badge svg { color: var(--brand-purple); }

.vx-hero__title {
	margin-top: 1.25rem;
	font-size: clamp(2.125rem, 7.5vw, 4rem);
	font-weight: 700;
	line-height: 1.04;
	letter-spacing: -0.035em;
}
.vx-hero__subtitle {
	margin: 1.125rem auto 0;
	max-width: 38rem;
	font-size: 1rem;
	line-height: 1.6;
	color: var(--muted-foreground);
}
@media (min-width: 640px) { .vx-hero__subtitle { font-size: 1.0625rem; } }

.vx-hero__ctas { margin-top: 1.75rem; display: flex; flex-wrap: wrap; justify-content: center; gap: 0.625rem; }
.vx-hero__note { margin-top: 1.125rem; font-size: 0.75rem; color: var(--muted-foreground); }

.vx-play-btn {
	display: grid; place-items: center; flex-shrink: 0; width: 3rem; height: 3rem; border-radius: var(--r-full);
	background-image: var(--gradient-brand); color: #fff; border: none; box-shadow: var(--shadow-glow);
	transition: transform 0.2s ease;
}
.vx-play-btn:hover { transform: scale(1.05); }
.vx-play-btn:active { transform: scale(0.95); }
.vx-play-btn--lg { width: 3.5rem; height: 3.5rem; }
.vx-play-btn:disabled { opacity: 0.6; cursor: default; }

.vx-waveform { display: flex; align-items: center; gap: 3px; height: 3.5rem; flex: 1; min-width: 0; }
.vx-waveform__bar { width: 3px; border-radius: var(--r-full); background-image: var(--gradient-brand); transform-origin: center; transition: transform 0.3s ease; }
.vx-waveform--player { height: 3.5rem; margin-top: 1.25rem; }

.vx-chip {
	position: absolute; display: none; align-items: center; border-radius: var(--r-2xl);
	padding: 0.5rem 0.75rem; font-size: 0.75rem; font-weight: 500; box-shadow: var(--shadow-soft);
}
@media (min-width: 640px) { .vx-chip { display: flex; } }
.vx-hero__chip-left { left: -1rem; top: -1rem; }
.vx-hero__chip-right { right: -1rem; bottom: 1.5rem; }

/* =================================================================
   Features
   =================================================================

   These cards used to get their surface from `.vx-glass-panel`, which meant
   six simultaneous `backdrop-filter: saturate(180%) blur(24px)` surfaces.
   A backdrop filter cannot be cached: as the card travels over the page
   background during a scroll, its backdrop changes, so the blur is recomputed
   every frame, per card. On a mid-range Android that alone is the difference
   between 60fps and ~25fps through this section.

   The declarations below are the SAME values `.vx-glass-panel` supplied —
   identical background, identical border, identical shadow — with only the
   filter dropped. Measured difference: under 2/255 on one colour channel,
   because the only thing behind these cards is a smooth radial gradient and
   blurring a smooth gradient returns the same gradient.
   ================================================================= */
.vx-feature-card {
	position: relative;
	overflow: hidden;
	border-radius: var(--r-card, var(--r-3xl));
	padding: 1.5rem;
	background: var(--glass);
	border: var(--card-border-width, 1px) solid var(--glass-border);
	box-shadow: var(--shadow-glass);
	transition: transform 0.5s ease, box-shadow 0.5s ease;
}
.vx-feature-card:hover { transform: translateY(-0.25rem); box-shadow: var(--shadow-elevated); }
.vx-feature-card__glow { position: absolute; right: -2.5rem; top: -2.5rem; width: 10rem; height: 10rem; border-radius: 999px; filter: blur(28px); opacity: 0.7; pointer-events: none; transition: opacity 0.5s ease; }
.vx-feature-card:hover .vx-feature-card__glow { opacity: 1; }
/* Kept so a cached page served with the old markup still renders correctly. */
.vx-feature-card__body { position: relative; }
/* The wrapper is gone from the template; the children now establish their own
   positioning so they still paint above the decorative glow. */
.vx-feature-card__icon,
.vx-feature-card__title,
.vx-feature-card__desc { position: relative; }
.vx-feature-card__icon { display: grid; place-items: center; width: 3rem; height: 3rem; border-radius: var(--r-2xl); background: #fff; box-shadow: var(--shadow-soft); }
.vx-feature-card__title { margin: 1.25rem 0 0; font-size: 1.125rem; font-weight: 600; letter-spacing: -0.02em; }
.vx-feature-card__desc { margin: 0.5rem 0 0; font-size: 0.875rem; line-height: 1.6; color: var(--muted-foreground); }

/* =================================================================
   Studio (live demo)
   ================================================================= */
.vx-studio-section { position: relative; }
.vx-studio-section__glow {
	position: absolute; inset-inline: 0; top: 25%; z-index: -1; height: 26rem; pointer-events: none;
	background: linear-gradient(to bottom, color-mix(in oklab, var(--brand-purple) 10%, transparent), transparent, transparent);
	filter: blur(48px);
}
.vx-studio-grid { margin-top: 3rem; display: grid; gap: 1.25rem; grid-template-columns: 1fr; }
@media (min-width: 1024px) { .vx-studio-grid { grid-template-columns: 1.2fr 1fr; } }

.vx-studio-panel, .vx-studio-player { border-radius: 28px; padding: 1.5rem; }
@media (min-width: 640px) { .vx-studio-panel, .vx-studio-player { padding: 2rem; } }

.vx-field-label { display: block; margin-bottom: 0.375rem; font-size: 0.75rem; font-weight: 500; color: var(--muted-foreground); }
.vx-textarea {
	width: 100%; resize: none; border-radius: var(--r-2xl); border: 1px solid var(--border);
	background: #fff; padding: 1rem; font-size: 0.9375rem; line-height: 1.6; color: var(--foreground);
	box-shadow: var(--shadow-soft); outline: none; transition: border-color 0.2s ease, box-shadow 0.2s ease;
	font-family: inherit;
}
.vx-textarea:focus { border-color: color-mix(in oklab, var(--ring) 50%, transparent); box-shadow: var(--shadow-elevated); }
.vx-studio-textmeta { margin-top: 0.375rem; display: flex; align-items: center; justify-content: space-between; font-size: 0.75rem; color: var(--muted-foreground); }

.vx-studio-controls { margin-top: 1.25rem; display: grid; gap: 1rem; grid-template-columns: 1fr; }
@media (min-width: 640px) { .vx-studio-controls { grid-template-columns: repeat(2, 1fr); } }

.vx-dropdown { position: relative; }
.vx-dropdown__trigger {
	display: flex; width: 100%; align-items: center; justify-content: space-between;
	border-radius: var(--r-2xl); border: 1px solid var(--border); background: #fff;
	padding: 0.75rem 1rem; text-align: left; font-size: 0.875rem; font-weight: 500;
	box-shadow: var(--shadow-soft); color: var(--foreground); transition: border-color 0.2s ease;
}
.vx-dropdown__trigger:hover { border-color: color-mix(in oklab, var(--ring) 40%, transparent); }
.vx-dropdown__trigger svg { transition: transform 0.3s ease; }
.vx-dropdown.is-open .vx-dropdown__trigger svg { transform: rotate(180deg); }
.vx-dropdown__panel { position: absolute; z-index: 20; margin-top: 0.5rem; width: 100%; overflow: hidden; border-radius: var(--r-2xl); padding: 0.25rem; }
.vx-dropdown__option { display: block; width: 100%; border-radius: var(--r-xl); padding: 0.625rem 0.75rem; text-align: left; font-size: 0.875rem; color: var(--muted-foreground); background: none; border: none; transition: background-color 0.2s ease; }
.vx-dropdown__option:hover { background: var(--secondary); }
.vx-dropdown__option.is-selected { font-weight: 600; color: var(--foreground); }

.vx-voice-pills { display: flex; gap: 0.5rem; overflow-x: auto; padding-bottom: 0.25rem; }
.vx-voice-pill {
	flex-shrink: 0; border-radius: var(--r-2xl); border: 1px solid var(--border); background: #fff;
	padding: 0.5rem 0.875rem; text-align: left; transition: transform 0.2s ease; cursor: pointer;
}
.vx-voice-pill:hover { transform: translateY(-2px); }
.vx-voice-pill.is-active { border-color: transparent; background-image: var(--gradient-brand); color: #fff; box-shadow: var(--shadow-glow); }
.vx-voice-pill__name { display: block; font-size: 0.75rem; font-weight: 600; }
.vx-voice-pill__tag { display: block; font-size: 0.625rem; color: var(--muted-foreground); }
.vx-voice-pill.is-active .vx-voice-pill__tag { color: rgba(255,255,255,0.8); }

.vx-studio-generate { width: 100%; margin-top: 1.5rem; }
.vx-studio-generate:hover { transform: scale(1.01); }
.vx-studio-generate:active { transform: scale(0.99); }
.vx-studio-generate:disabled { opacity: 0.8; }
.vx-studio-generate[data-busy="true"] .vx-studio-generate__idle { display: none; }
.vx-studio-generate[data-busy="true"] .vx-studio-generate__busy { display: inline-flex; }
.vx-studio-generate__busy { display: none; align-items: center; gap: 0.5rem; }
.vx-studio-generate__idle { display: inline-flex; align-items: center; gap: 0.5rem; }

.vx-studio-player { display: flex; flex-direction: column; }
.vx-studio-player__top { display: flex; align-items: center; justify-content: space-between; }
.vx-studio-player__voice { display: flex; min-width: 0; align-items: center; gap: 0.75rem; }
.vx-studio-player__name { margin: 0; font-size: 0.875rem; font-weight: 600; }
.vx-studio-player__tag { margin: 0; font-size: 0.75rem; color: var(--muted-foreground); }
.vx-studio-player__textbox { position: relative; margin-top: 1.5rem; border-radius: var(--r-2xl); background: var(--surface); padding: 1rem; min-height: 5rem; }
.vx-studio-player__textbox p { margin: 0; font-size: 0.875rem; line-height: 1.6; color: color-mix(in oklab, var(--foreground) 80%, transparent); }
.vx-studio-player__shimmer { position: absolute; inset: 1rem; flex-direction: column; gap: 0.625rem; }
.vx-studio-player__shimmer:not([hidden]) { display: flex; }
.vx-studio-player__shimmer span { height: 0.75rem; border-radius: var(--r-full); background: var(--muted); }
.vx-studio-player__shimmer span:nth-child(1) { width: 75%; }
.vx-studio-player__shimmer span:nth-child(2) { width: 50%; }
.vx-studio-player__shimmer span:nth-child(3) { width: 66%; }
.vx-progress { margin-top: 0.75rem; height: 0.375rem; width: 100%; overflow: hidden; border-radius: var(--r-full); background: var(--secondary); }
.vx-progress__bar { height: 100%; width: 0%; background-image: var(--gradient-brand); transition: width 0.15s ease; }
.vx-studio-player__time { margin-top: 0.5rem; display: flex; align-items: center; justify-content: space-between; font-size: 0.6875rem; font-weight: 600; color: var(--muted-foreground); }
.vx-studio-player__actions { margin-top: auto; padding-top: 1.5rem; display: flex; align-items: center; justify-content: center; gap: 0.75rem; }

/* =================================================================
   Pricing
   ================================================================= */
.vx-toggle { display: inline-flex; align-items: center; gap: 0.5rem; border-radius: var(--r-full); padding: 0.375rem; margin-top: 2rem; }
.vx-toggle__opt { border: none; background: none; border-radius: var(--r-full); padding: 0.375rem 1rem; font-size: 0.75rem; font-weight: 600; color: var(--muted-foreground); cursor: pointer; transition: background-color 0.2s ease, color 0.2s ease, box-shadow 0.2s ease; }
.vx-toggle__opt.is-active { background-image: var(--gradient-brand); color: #fff; box-shadow: var(--shadow-soft); }

.vx-pricing-grid { margin-top: 3.5rem; }
.vx-pricing-card { position: relative; border-radius: 28px; padding: 1.75rem; transition: transform 0.5s ease; color: var(--foreground); }
.vx-pricing-card:hover { transform: translateY(-0.25rem); }
.vx-pricing-card:not(.is-featured):hover { box-shadow: var(--shadow-elevated); }
.vx-pricing-card.is-featured { color: #fff; }
.vx-pricing-card__badge {
	position: absolute; top: -0.75rem; left: 50%; transform: translateX(-50%);
	border-radius: var(--r-full); background: #fff; padding: 0.25rem 0.75rem;
	font-size: 0.625rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em;
	color: var(--primary); box-shadow: var(--shadow-soft);
}
.vx-pricing-card__name { margin: 0; font-size: 1.25rem; font-weight: 600; }
.vx-pricing-card__desc { margin: 0.25rem 0 0; font-size: 0.875rem; }
.vx-pricing-card:not(.is-featured) .vx-pricing-card__desc { color: var(--muted-foreground); }
.vx-pricing-card.is-featured .vx-pricing-card__desc { color: rgba(255,255,255,0.8); }
.vx-pricing-card__price { margin-top: 1.5rem; display: flex; align-items: baseline; gap: 0.25rem; }
.vx-pricing-card__amount { font-size: 3rem; font-weight: 700; letter-spacing: -0.03em; }
.vx-pricing-card__period { font-size: 0.875rem; }
.vx-pricing-card:not(.is-featured) .vx-pricing-card__period { color: var(--muted-foreground); }
.vx-pricing-card.is-featured .vx-pricing-card__period { color: rgba(255,255,255,0.8); }
/* The CTA holds an inline <svg> next to its label. `display: block` left the
   SVG on the text baseline, which sits it a couple of pixels high — visible
   on the "Get Pro" button. Flex centring puts the icon on the text's optical
   centre instead. `width: 100%` is preserved, so the button is exactly the
   same size and position as before; only the icon moves. */
.vx-pricing-card__cta {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 0.5rem;
	width: 100%;
	margin-top: 1.5rem;
	border-radius: var(--r-2xl);
	padding: 0.75rem 1.25rem;
	text-align: center;
	transition: transform 0.2s ease;
}
.vx-pricing-card__cta:hover { transform: scale(1.02); }
.vx-pricing-card__cta:active { transform: scale(0.99); }
.vx-pricing-card__cta--light { background: #fff; color: var(--primary); box-shadow: var(--shadow-soft); }
.vx-pricing-card__features { list-style: none; margin: 1.75rem 0 0; padding: 0; display: flex; flex-direction: column; gap: 0.75rem; }
.vx-pricing-card__features li { display: flex; align-items: flex-start; gap: 0.75rem; font-size: 0.875rem; }
.vx-pricing-card__check { display: grid; place-items: center; flex-shrink: 0; margin-top: 0.125rem; width: 1.25rem; height: 1.25rem; border-radius: var(--r-full); }
.vx-pricing-card:not(.is-featured) .vx-pricing-card__check { background: var(--secondary); color: var(--primary); }
.vx-pricing-card.is-featured .vx-pricing-card__check { background: rgba(255,255,255,0.2); color: #fff; }
.vx-pricing-card:not(.is-featured) .vx-pricing-card__features span:last-child { color: color-mix(in oklab, var(--foreground) 80%, transparent); }
.vx-pricing-card.is-featured .vx-pricing-card__features span:last-child { color: rgba(255,255,255,0.9); }

/* =================================================================
   Testimonials
   =================================================================
   Same change as the Feature cards: the `.vx-glass-panel` surface has been
   inlined here minus its `backdrop-filter`, so three more per-frame backdrop
   blurs disappear. Every value below is the one the card already had.
   ================================================================= */
.vx-testimonial-card {
	position: relative;
	overflow: hidden;
	border-radius: var(--r-card, var(--r-3xl));
	padding: 1.75rem;
	background: var(--glass);
	border: var(--card-border-width, 1px) solid var(--glass-border);
	box-shadow: var(--shadow-glass);
	transition: transform 0.5s ease, box-shadow 0.5s ease;
}
.vx-testimonial-card:hover { transform: translateY(-0.25rem); box-shadow: var(--shadow-elevated); }
.vx-testimonial-card__glow { position: absolute; right: -3rem; top: -3rem; width: 11rem; height: 11rem; border-radius: 999px; filter: blur(28px); pointer-events: none; }
/* Kept so a cached page served with the old markup still renders correctly. */
.vx-testimonial-card__body { position: relative; }
/* Wrapper removed from the template — children position themselves instead. */
.vx-testimonial-card__stars,
.vx-testimonial-card__quote,
.vx-testimonial-card__person { position: relative; }
.vx-testimonial-card__stars { display: flex; align-items: center; gap: 0.125rem; color: var(--brand-purple); }
.vx-testimonial-card__quote { margin: 1rem 0 0; font-size: 1.125rem; line-height: 1.4; letter-spacing: -0.02em; }
.vx-testimonial-card__person { margin-top: 1.5rem; display: flex; align-items: center; gap: 0.75rem; }
.vx-avatar-gradient { display: grid; place-items: center; width: 2.5rem; height: 2.5rem; border-radius: var(--r-full); background-image: var(--gradient-brand); font-size: 0.875rem; font-weight: 600; color: #fff; box-shadow: var(--shadow-soft); flex-shrink: 0; }
.vx-testimonial-card__name { margin: 0; font-size: 0.875rem; font-weight: 600; }
.vx-testimonial-card__role { margin: 0; font-size: 0.75rem; color: var(--muted-foreground); }

/* =================================================================
   FAQ
   ================================================================= */
.vx-faq-list { margin-top: 3rem; display: flex; flex-direction: column; gap: 0.75rem; }
.vx-faq-item { overflow: hidden; border-radius: var(--r-3xl); transition: box-shadow 0.3s ease; }
.vx-faq-item.is-open { box-shadow: var(--shadow-elevated); }
.vx-faq-item__q { display: flex; width: 100%; align-items: center; justify-content: space-between; gap: 1rem; border: none; background: none; padding: 1.25rem 1.5rem; text-align: left; cursor: pointer; }
.vx-faq-item__q span:first-child { font-size: 1rem; font-weight: 600; letter-spacing: -0.02em; }
@media (min-width: 640px) { .vx-faq-item__q span:first-child { font-size: 1.125rem; } }
.vx-faq-item__toggle { display: grid; place-items: center; flex-shrink: 0; width: 2rem; height: 2rem; border-radius: var(--r-full); background: var(--secondary); color: var(--foreground); transition: transform 0.5s ease, background-color 0.3s ease, color 0.3s ease; }
.vx-faq-item.is-open .vx-faq-item__toggle { transform: rotate(45deg); background-image: var(--gradient-brand); color: #fff; }
.vx-faq-item__panel { display: grid; grid-template-rows: 0fr; transition: grid-template-rows 0.5s ease-out; }
.vx-faq-item.is-open .vx-faq-item__panel { grid-template-rows: 1fr; }
/* `min-height: 0` is the whole fix for answers showing while collapsed.
   A grid item defaults to `min-height: auto`, which refuses to shrink below
   its own content — so `grid-template-rows: 0fr` on the panel could never
   actually reach zero, and a few lines of every answer stayed visible. This
   is the standard trap with the 0fr accordion technique. */
.vx-faq-item__panel > p { min-height: 0; overflow: hidden; margin: 0; padding: 0 1.5rem 1.5rem; font-size: 0.875rem; line-height: 1.6; color: var(--muted-foreground); }
.vx-faq-item__panel { overflow: hidden; }

/* =================================================================
   Landing footer
   ================================================================= */
.vx-landing-footer { position: relative; padding: 6rem 0 3rem; }
.vx-landing-footer__panel { border-radius: 32px; padding: 2rem; }
@media (min-width: 640px) { .vx-landing-footer__panel { padding: 3rem; } }
.vx-landing-footer__top { display: grid; gap: 3rem; grid-template-columns: 1fr; }
@media (min-width: 768px) { .vx-landing-footer__top { grid-template-columns: 1.4fr 2fr; } }
.vx-landing-footer__brand-name { font-size: 1.125rem; font-weight: 600; letter-spacing: -0.02em; }
.vx-landing-footer__tagline { margin-top: 1rem; max-width: 20rem; font-size: 0.875rem; color: var(--muted-foreground); }
.vx-landing-footer__subscribe { margin-top: 1.5rem; display: flex; max-width: 24rem; align-items: center; gap: 0.5rem; }
.vx-landing-footer__subscribe input { min-width: 0; flex: 1; border-radius: var(--r-2xl); border: 1px solid var(--border); background: #fff; padding: 0.75rem 1rem; font-size: 0.875rem; box-shadow: var(--shadow-soft); outline: none; }
.vx-landing-footer__cols { display: grid; grid-template-columns: repeat(2, 1fr); gap: 2rem; }
@media (min-width: 640px) { .vx-landing-footer__cols { grid-template-columns: repeat(4, 1fr); } }
.vx-landing-footer__col h4 { margin: 0; font-size: 0.75rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; }
.vx-landing-footer__col ul { list-style: none; margin: 1rem 0 0; padding: 0; display: flex; flex-direction: column; gap: 0.625rem; }
.vx-landing-footer__col a { font-size: 0.875rem; color: var(--muted-foreground); transition: color 0.2s ease; }
.vx-landing-footer__col a:hover { color: var(--foreground); }
.vx-landing-footer__bottom { margin-top: 2.5rem; display: flex; flex-direction: column; align-items: center; justify-content: space-between; gap: 0.75rem; border-top: 1px solid color-mix(in oklab, var(--border) 60%, transparent); padding-top: 1.5rem; font-size: 0.75rem; color: var(--muted-foreground); }
@media (min-width: 640px) { .vx-landing-footer__bottom { flex-direction: row; } }

/* The mobile block that used to live here disabled float animations on the
   hero card and chips, dimmed the blobs, and hid surplus waveform bars. Every
   element it named has been removed from the hero, so the whole block was
   dead code.

   (`.vx-waveform__bar:nth-child(n+20)` looked like it might still bite the
   app's waveforms — but landing.css is enqueued only under is_front_page(),
   so it never reached them. Checked rather than assumed.) */

/* ══════════════════════════════════════════════════════════════════════
   HOMEPAGE DEMO PANEL + LONGFORM SECTIONS
   ══════════════════════════════════════════════════════════════════════
   Reuses .vx-container, .vx-section-head, .vx-h2, .vx-lede, .vx-pill and
   .vx-btn from above — only what is genuinely new is defined here.

   No backdrop-filter anywhere in this block, and every transition is
   transform/opacity/colour only, so nothing here can force a layout pass
   while the page scrolls.
   ══════════════════════════════════════════════════════════════════════ */

.vx-demo-sect { padding: 0 0 3.5rem; }

.vx-demo {
	border-radius: var(--r-2xl, 34px);
	background: var(--secondary);
	box-shadow: inset 0 0 0 1px var(--border);
	padding: 0.5rem;
}

/* Tab strip: horizontally scrollable on narrow screens, snapped, no visible
   scrollbar. `overscroll-behavior-x: contain` stops a sideways flick that
   reaches the end of the strip from turning into a page-level gesture. */
.vx-demo__tabs {
	display: flex;
	gap: 0.25rem;
	overflow-x: auto;
	scrollbar-width: none;
	-webkit-overflow-scrolling: touch;
	overscroll-behavior-x: contain;
	scroll-snap-type: x proximity;
	padding: 0.25rem;
}
.vx-demo__tabs::-webkit-scrollbar { display: none; }
.vx-demo__tabs button {
	flex-shrink: 0;
	scroll-snap-align: center;
	border: 0;
	cursor: pointer;
	border-radius: var(--r-full);
	background: transparent;
	padding: 0.625rem 1.125rem;
	font-size: 0.9375rem;
	font-weight: 600;
	color: var(--muted-foreground);
	white-space: nowrap;
	transition: background-color 0.2s ease, color 0.2s ease;
}
.vx-demo__tabs button.is-active {
	background: var(--card);
	color: var(--foreground);
	box-shadow: var(--shadow-soft);
}

.vx-demo__panels {
	margin-top: 0.5rem;
	border-radius: var(--r-xl);
	background: var(--card);
	box-shadow: inset 0 0 0 1px var(--border);
	padding: 1.25rem;
}
.vx-demo__panel { display: none; }
.vx-demo__panel.is-active { display: block; }
.vx-demo__note { margin: 1rem 0 0; font-size: 0.8125rem; line-height: 1.55; color: var(--muted-foreground); }
.vx-demo__empty { margin: 2rem 0; text-align: center; color: var(--muted-foreground); font-size: 0.875rem; }

/* ── Voice rows ── */
.vx-vlist { display: grid; gap: 0.125rem; }
.vx-vrow {
	display: flex;
	align-items: center;
	gap: 0.75rem;
	padding: 0.625rem 0.75rem;
	border-radius: var(--r-md);
	cursor: pointer;
	transition: background-color 0.18s ease;
}
.vx-vrow:active { background: var(--secondary); }
.vx-vrow.is-selected { background: var(--secondary); box-shadow: inset 0 0 0 1px var(--border); }

.vx-vrow__avwrap { position: relative; flex-shrink: 0; line-height: 0; }
.vx-vrow__av { width: 2.125rem; height: 2.125rem; border-radius: var(--r-full); object-fit: cover; background: var(--border); }
.vx-vrow__av--blank { display: block; }
.vx-vrow__check {
	position: absolute;
	top: -0.1875rem; right: -0.1875rem;
	width: 0.9375rem; height: 0.9375rem;
	border-radius: var(--r-full);
	background: var(--foreground);
	color: var(--card);
	display: none;
	place-items: center;
	box-shadow: 0 0 0 2px var(--card);
}
.vx-vrow.is-selected .vx-vrow__check { display: grid; }

.vx-vrow__body { flex: 1; min-width: 0; display: flex; align-items: center; gap: 0.625rem; }
.vx-vrow__name { font-size: 0.9375rem; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.vx-vrow__style { margin-left: auto; flex-shrink: 0; max-width: 45%; font-size: 0.8125rem; color: var(--muted-foreground); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* Every row carries the raised circular play button, not just the selected
   one — a control that only appears once you have already tapped the row
   gives no signal that the row is tappable in the first place. */
.vx-vrow__play {
	width: 2.125rem; height: 2.125rem;
	flex-shrink: 0;
	border: 0;
	cursor: pointer;
	border-radius: var(--r-full);
	display: grid;
	place-items: center;
	background: var(--card);
	color: var(--foreground);
	box-shadow: var(--shadow-soft), inset 0 0 0 1px var(--border);
	transition: transform 0.2s ease, background-color 0.2s ease, color 0.2s ease;
}
.vx-vrow__play:active { transform: scale(0.9); }
.vx-vrow.is-playing .vx-vrow__play { background-image: var(--gradient-brand); background-color: transparent; color: #fff; box-shadow: var(--shadow-soft); }
.vx-vrow__p2 { display: none; }
.vx-vrow.is-playing .vx-vrow__p1 { display: none; }
.vx-vrow.is-playing .vx-vrow__p2 { display: block; }

.vx-vfoot { display: flex; align-items: center; gap: 0.75rem; margin-top: 0.875rem; }
.vx-vfoot__hint { font-size: 0.8125rem; color: var(--muted-foreground); }
.vx-vfoot__nav { margin-left: auto; display: flex; gap: 0.125rem; }
.vx-vfoot__nav button {
	width: 2rem; height: 2rem;
	border: 0; cursor: pointer; background: transparent;
	border-radius: var(--r-full);
	display: grid; place-items: center;
	color: var(--muted-foreground);
	transition: background-color 0.2s ease, color 0.2s ease;
}
.vx-vfoot__nav button:hover:not(:disabled) { background: var(--secondary); color: var(--foreground); }
.vx-vfoot__nav button:disabled { opacity: 0.3; cursor: default; }

/* Tinted strip flush to the panel's bottom edge. The negative margins pull it
   out to the panel's padding so it meets the corners cleanly. */
.vx-vexplore {
	margin: 0.875rem -1.25rem -1.25rem;
	padding: 0.9375rem 1.25rem;
	text-align: center;
	border-bottom-left-radius: var(--r-xl);
	border-bottom-right-radius: var(--r-xl);
	background-image: linear-gradient(180deg, transparent, rgba(91, 156, 246, 0.10));
}
.vx-vexplore a { font-size: 0.9375rem; font-weight: 600; color: #2563eb; text-decoration: underline; text-underline-offset: 3px; }

/* ── Library panel ── */
.vx-libgrid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.5rem; }
@media (min-width: 640px) { .vx-libgrid { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.vx-libchip {
	display: flex; align-items: baseline; justify-content: space-between; gap: 0.5rem;
	border-radius: var(--r-md);
	background: var(--secondary);
	padding: 0.75rem 0.875rem;
	font-size: 0.875rem; font-weight: 600;
	text-decoration: none;
	transition: background-color 0.2s ease;
}
.vx-libchip:hover { background: var(--accent); }
.vx-libchip b { font-size: 0.75rem; color: var(--muted-foreground); font-variant-numeric: tabular-nums; }

/* ── Cloning panel ── */
.vx-clone__lead { margin: 0 0 0.875rem; font-size: 0.875rem; line-height: 1.55; color: var(--muted-foreground); }
.vx-clone { display: grid; gap: 0.625rem; }
.vx-clone__slot {
	display: flex; align-items: center; gap: 0.875rem;
	border-radius: var(--r-lg);
	padding: 1rem;
	cursor: pointer;
}
.vx-clone__slot--orig { background: var(--secondary); box-shadow: inset 0 0 0 1px var(--border); }
.vx-clone__slot--clone { background-image: linear-gradient(120deg, #c4b5fd, #f0abfc, #fda4af); color: #2b1055; }
.vx-clone__play {
	width: 2.5rem; height: 2.5rem;
	flex-shrink: 0;
	border: 0; cursor: pointer;
	border-radius: var(--r-full);
	display: grid; place-items: center;
	background: var(--card);
	color: var(--foreground);
	box-shadow: var(--shadow-soft);
	transition: transform 0.2s ease;
}
.vx-clone__slot--clone .vx-clone__play { background: rgba(255, 255, 255, 0.85); color: #2b1055; }
.vx-clone__play:active { transform: scale(0.9); }
.vx-clone__body { min-width: 0; display: grid; }
.vx-clone__title { font-size: 0.9375rem; font-weight: 700; }
.vx-clone__sub { margin-top: 0.125rem; font-size: 0.75rem; opacity: 0.75; }

/* ── Steps (share panel + cloning longform) ── */
.vx-steps { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.625rem; }
.vx-steps li { display: flex; align-items: flex-start; gap: 0.75rem; border-radius: var(--r-lg); background: var(--secondary); padding: 0.875rem 1rem; }
.vx-steps__n { flex-shrink: 0; width: 1.75rem; height: 1.75rem; border-radius: var(--r-full); background-image: var(--gradient-brand); color: #fff; display: grid; place-items: center; font-size: 0.75rem; font-weight: 800; }
.vx-steps__b { min-width: 0; display: grid; }
.vx-steps__b b { font-size: 0.9375rem; font-weight: 600; }
.vx-steps__b small { margin-top: 0.1875rem; font-size: 0.8125rem; line-height: 1.5; color: var(--muted-foreground); }

/* ── Longform: how cloning works ── */
.vx-longform { padding: 4rem 0; }
.vx-longform__head { text-align: center; max-width: 42rem; margin-inline: auto; }
.vx-lfsteps { display: grid; gap: 1rem; margin-top: 2.5rem; }
@media (min-width: 900px) { .vx-lfsteps { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.vx-lfstep { border-radius: var(--r-xl); background: var(--card); box-shadow: inset 0 0 0 1px var(--border), var(--shadow-soft); padding: 1.5rem; }
.vx-lfstep__n { display: grid; place-items: center; width: 2rem; height: 2rem; border-radius: var(--r-full); background-image: var(--gradient-brand); color: #fff; font-size: 0.8125rem; font-weight: 800; }
.vx-lfstep h3 { margin: 0.875rem 0 0; font-size: 1.0625rem; font-weight: 700; letter-spacing: -0.01em; }
.vx-lfstep p { margin: 0.5rem 0 0; font-size: 0.875rem; line-height: 1.65; color: var(--muted-foreground); }

.vx-lfnotes { display: grid; gap: 1rem; margin-top: 1rem; }
@media (min-width: 900px) { .vx-lfnotes { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.vx-lfnote { border-radius: var(--r-xl); background: var(--secondary); padding: 1.25rem 1.5rem; }
.vx-lfnote h3 { margin: 0; font-size: 0.9375rem; font-weight: 700; }
.vx-lfnote p { margin: 0.4375rem 0 0; font-size: 0.8125rem; line-height: 1.65; color: var(--muted-foreground); }

.vx-longform__cta { display: flex; flex-wrap: wrap; gap: 0.625rem; justify-content: center; margin-top: 2.25rem; }

/* ── Use cases ── */
.vx-usecases { padding: 4rem 0; }
.vx-uccards { display: grid; gap: 1rem; margin-top: 2.5rem; }
@media (min-width: 700px) { .vx-uccards { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.vx-uccard { border-radius: var(--r-xl); background: var(--card); box-shadow: inset 0 0 0 1px var(--border), var(--shadow-soft); padding: 1.5rem; }
.vx-uccard__ic { display: grid; place-items: center; width: 2.5rem; height: 2.5rem; border-radius: var(--r-lg); background: var(--accent); color: var(--brand-purple); }
.vx-uccard h3 { margin: 0.875rem 0 0; font-size: 1.0625rem; font-weight: 700; letter-spacing: -0.01em; }
.vx-uccard p { margin: 0.5rem 0 0; font-size: 0.875rem; line-height: 1.65; color: var(--muted-foreground); }

/* ── Languages ── */
.vx-langsect { padding: 4rem 0; }
.vx-langgrid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.625rem; margin-top: 2.5rem; }
@media (min-width: 640px) { .vx-langgrid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 1000px) { .vx-langgrid { grid-template-columns: repeat(5, minmax(0, 1fr)); } }
.vx-langcard {
	display: grid; gap: 0.125rem;
	border-radius: var(--r-lg);
	background: var(--card);
	box-shadow: inset 0 0 0 1px var(--border);
	padding: 0.875rem 1rem;
	text-decoration: none;
	transition: transform 0.2s ease, box-shadow 0.2s ease;
}
@media (hover: hover) and (pointer: fine) {
	.vx-langcard:hover { transform: translateY(-2px); box-shadow: inset 0 0 0 1px var(--border), var(--shadow-soft); }
}
.vx-langcard__name { font-size: 0.9375rem; font-weight: 600; }
.vx-langcard__n { font-size: 0.75rem; color: var(--muted-foreground); font-variant-numeric: tabular-nums; }

/* ── Icon centring inside the demo's round buttons ────────────────────────
   Same fix already applied to `.vx-play-btn` in app.css, and the same root
   cause: there is no `svg { display: block }` reset anywhere in the theme,
   so an <svg> is inline-level and sits on a TEXT BASELINE. Each icon is
   wrapped in a <span> that grid blockifies, and that span's line box is
   `line-height` tall with descender space reserved beneath it. The grid
   centres the span; the span is taller than the glyph; the glyph ends up
   above the middle of the circle.

   `line-height: 0` collapses the wrapper to the glyph, `display: block`
   takes the SVG off the baseline entirely. Both are needed — the first for
   the wrapped icons, the second for any bare ones. */
/* CORRECTION: this first shipped as
       .vx-vrow__play > * { display: grid; place-items: center; line-height: 0; }
   which sits LATER in this file than `.vx-vrow__p2 { display: none }` at the
   same specificity — so it overrode the rule that hides the pause icon, and
   both glyphs rendered stacked inside every circle.

   `line-height: 0` alone is enough. The spans are already grid items of the
   button (which is `display: grid; place-items: center`), so they are
   centred without being given a display of their own — and leaving `display`
   untouched means the show/hide rules keep working. app.css escaped the same
   mistake only because it carries `[hidden] { display: none !important }`. */
.vx-vrow__play > *,
.vx-clone__play > * { line-height: 0; }
.vx-vrow__play svg,
.vx-clone__play svg { display: block; }

/* ── Playing indicator on the cloning comparison ──────────────────────────
   Three bars that rise and fall while a clip is sounding, so it is obvious
   WHICH of the two is playing when they are compared back to back.

   Deliberately cheap: three 2px spans animating `transform: scaleY` only —
   a compositor-only property, no layout, no paint. They are not rendered at
   all until a clip plays (`display: none` by default), so an idle page pays
   nothing, and the animation stops the moment the class comes off. */
.vx-clone__bars {
	display: none;
	align-items: center;
	gap: 2px;
	height: 1rem;
	margin-inline-start: auto;
	padding-inline-start: 0.5rem;
}
.vx-clone__slot.is-playing .vx-clone__bars { display: flex; }
.vx-clone__bars i {
	display: block;
	width: 2px;
	height: 100%;
	border-radius: 2px;
	background: currentColor;
	opacity: 0.85;
	transform-origin: center;
	animation: vx-clone-bar 0.9s ease-in-out infinite;
}
.vx-clone__bars i:nth-child(2) { animation-delay: 0.15s; }
.vx-clone__bars i:nth-child(3) { animation-delay: 0.3s; }
@keyframes vx-clone-bar {
	0%, 100% { transform: scaleY(0.35); }
	50%      { transform: scaleY(1); }
}

/* A soft ring on the button while its clip plays. `box-shadow` on a single
   small element is cheap; the alternative — an ::after with its own
   transform animation — would promote a second layer per slot for no gain. */
.vx-clone__slot.is-playing .vx-clone__play {
	animation: vx-clone-pulse 1.6s ease-out infinite;
}
@keyframes vx-clone-pulse {
	0%   { box-shadow: 0 0 0 0 rgba(139, 92, 246, 0.45); }
	70%  { box-shadow: 0 0 0 0.5rem rgba(139, 92, 246, 0); }
	100% { box-shadow: 0 0 0 0 rgba(139, 92, 246, 0); }
}

@media (prefers-reduced-motion: reduce) {
	.vx-clone__bars i,
	.vx-clone__slot.is-playing .vx-clone__play { animation: none; }
}

/* ── Testimonials: cost on phones ─────────────────────────────────────────
   The glow itself is left exactly as it was — `filter: blur(28px)` on an
   11rem disc, unchanged. An earlier attempt dropped the filter below 700px
   to save GPU work, but the tint underneath is an OPAQUE brand gradient and
   the blur was the only thing softening its edge, so removing it left a hard
   circle on the card. Reverted; the two optimisations below cost nothing
   visually.

   `contain: paint` promises the card's painting cannot escape its own
   bounds — which was already true, since the card clips with
   `overflow: hidden` — so the browser can skip it entirely once it scrolls
   out of view instead of weighing it every frame.

   The hover transform is disabled on phones: there is no hover there, so the
   0.5s transition only ever fires as a slow tap-highlight, and it moves a
   contained element mid-scroll. */
.vx-testimonial-card { contain: paint; }

@media (max-width: 699px) {
	.vx-testimonial-card { transition: none; }
	.vx-testimonial-card:hover { transform: none; box-shadow: var(--shadow-glass); }
}
