/* ============================================================================
   Virtual Change Room - public marketing site (vm-*)
   Flat, dark-only, lilac accent, Inter. Loaded globally via IStylesheetContributor;
   every rule is namespaced under .vm-site so nothing leaks into the app.
   No blur/soft shadows anywhere (flat design rule). Mobile-first.
   ========================================================================== */

.vm-site {
    --vm-ground: #09090b;
    --vm-panel: #141416;
    --vm-panel-2: #0d0d0f;
    --vm-line: #2e2e35;
    --vm-ink: #fafafa;
    --vm-muted: #a1a1aa;
    --vm-accent: #af85ff;
    --vm-accent-ink: #241344;

    background: var(--vm-ground);
    color: var(--vm-ink);
    font-family: 'Inter', system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
    font-size: 1rem;
    line-height: 1.6;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    scroll-behavior: smooth;
}

.vm-site a { text-decoration: none; }
.vm-shell { width: 100%; max-width: 72rem; margin: 0 auto; padding: 0 1.25rem; }

/* ---------- buttons ---------- */
.vm-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .5rem;
    /* Explicit transparent background: the waitlist CTAs are real <button> elements, and without
       this the UA's dark-scheme buttonface paints them solid grey while the <a> CTAs stay flat. */
    background: transparent;
    border: 1px solid transparent;
    border-radius: .625rem;
    padding: .625rem 1.25rem;
    font-weight: 600;
    font-size: .9375rem;
    white-space: nowrap;
    transition: background-color .15s ease, border-color .15s ease, color .15s ease;
}
.vm-btn-primary { background: var(--vm-accent); color: #fff; }
.vm-btn-primary:hover { background: #c3a3ff; color: #fff; }
.vm-btn-outline { border-color: var(--vm-line); color: var(--vm-ink); }
.vm-btn-outline:hover { border-color: var(--vm-accent); color: var(--vm-accent); background: var(--vm-panel-2); }
.vm-btn-lg { padding: .875rem 1.75rem; font-size: 1.0625rem; border-radius: .75rem; }

/* Responsive label swap: "Open the app" -> "Open app" on very narrow screens (<450px). */
.vm-narrow-only { display: none; }
@media (max-width: 449.98px) {
    .vm-wide-only { display: none; }
    .vm-narrow-only { display: inline; }
}

/* ---------- nav ---------- */
.vm-nav {
    position: sticky;
    top: 0;
    z-index: 100;
    /* Slightly transparent glass bar (owner request): page content blurs behind it on scroll. */
    background: rgba(9, 9, 11, .8);
    -webkit-backdrop-filter: blur(12px);
    backdrop-filter: blur(12px);
    border-bottom: 1px solid var(--vm-line);
}
.vm-nav-inner {
    display: flex;
    align-items: center;
    /* Mobile default: this is the hamburger<->logo gap, kept at 1.5rem to match the app header
       (source of truth). At >=lg (992px) it becomes the last-link -> CTA gap, widened 4px to
       1.75rem (owner preference) so the filled CTA gets a touch more breathing room and reads as
       its own element rather than crowding the last text link. */
    gap: 1.5rem;
    min-height: 7.5rem;
}
.vm-brand { display: flex; align-items: center; }
.vm-brand img { height: auto; max-height: 70px; width: auto; display: block; }
.vm-nav-links {
    /* Show/hide and right-alignment are handled by the d-none/d-lg-flex + ms-auto utility classes
       on the <nav> (hidden on mobile where the hamburger drives navigation, shown at >=lg). The
       rules here are just the static inline-link layout. */
    align-items: center;
    gap: 1.5rem;
}
.vm-nav-links a { display: inline-flex; align-items: center; gap: .45rem; color: var(--vm-muted); font-weight: 500; font-size: .9375rem; }
.vm-nav-links a i { color: var(--vm-accent); font-size: .9em; }
.vm-nav-links a:hover { color: var(--vm-ink); }
/* Five links plus Log in plus the CTA have to share the row with a 70px-tall logo mark. Between lg
   and xl the gaps and type tighten so the row never collides with the mark; at xl it relaxes back. */
@media (min-width: 992px) and (max-width: 1199.98px) {
    .vm-nav-links { gap: 1.125rem; }
    .vm-nav-links a { font-size: .875rem; }
}
/* Active page: the current top-level route (each nav item is a real page now, so exact match). */
.vm-nav-links a.active { color: var(--vm-accent); font-weight: 600; }
/* The header CTA shows only at >=lg, alongside the inline links (d-none/d-lg-flex on this element) -
   below lg it is hidden here and reached through the slide-out sidebar instead. At >=lg the visible
   .vm-nav-links carries the ms-auto that right-aligns the links + CTA together. */
.vm-nav-actions { display: flex; align-items: center; gap: 1rem; }

/* Animated hamburger (adapted from the reference site): borderless, no padding, three thin
   lines; the middle line is 60% wide and grows to full width on hover; the lines morph to an X
   while the sidebar is open. Show/hide is driven by the d-flex/d-lg-none utility classes on the
   button (visible on mobile, hidden at >=lg); the rules here are just the static shape. */
.vm-burger {
    flex-direction: column;
    justify-content: space-between;
    width: 30px;
    height: 20px;
    padding: 0;
    border: 0;
    background: none;
    cursor: pointer;
}
.vm-burger-line {
    width: 100%;
    height: 2px;
    background: var(--vm-ink);
    border-radius: 2px;
    transition: .4s cubic-bezier(.4, 0, .2, 1);
    transform-origin: center center;
}
.vm-burger-line:nth-child(2) { width: 60%; margin-left: auto; }
.vm-burger:hover .vm-burger-line:nth-child(2) { width: 100%; }
.vm-burger.open .vm-burger-line:nth-child(1) { transform: translateY(9px) rotate(45deg); }
.vm-burger.open .vm-burger-line:nth-child(2) { opacity: 0; width: 0; }
.vm-burger.open .vm-burger-line:nth-child(3) { transform: translateY(-9px) rotate(-45deg); }

/* Slide-out mobile sidebar (mirrors the app's .side-menu): slides in from the LEFT, shared
   header component (logo + top-right close) at the top, links below. */
.vm-sidebar {
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    /* Every box metric matches the app side-menu (source of truth): same width (--side-w),
       padding, right border, fill and shadow. The nav content uses the app's .side-menu-nav +
       .menu-link classes (ez-platform-nav.css). Only the slide mechanism differs (transform here
       vs the app's `left`), which is visually identical. */
    width: var(--side-w, 17.5rem);
    z-index: 200;
    background: var(--bs-body-bg);
    padding: 0.875rem;
    border-right: 1px solid var(--bs-border-color);
    box-shadow: var(--bs-box-shadow);
    transform: translateX(-100%);
    transition: transform .3s cubic-bezier(.4, 0, .2, 1);
    display: flex;
    flex-direction: column;
    overflow-y: auto;
}
.vm-sidebar.open { transform: translateX(0); }
/* The CTA button keeps its own primary styling (the app side-menu has no CTA); sit it at the
   bottom of the nav with a little breathing room, full-width across the menu (website only). */
.vm-sidebar-cta { display: flex; width: 100%; margin-top: .75rem; text-align: center; justify-content: center; }
/* Backdrop reuses the app's shared .ez-backdrop (dim + blur, source of truth); this only adds
   the z-index and the hidden-until-open toggle. */
.vm-sidebar-backdrop { display: none; z-index: 150; }
.vm-sidebar-backdrop.open { display: block; }
body.vm-nav-lock { overflow: hidden; }

/* The only menu rule that cannot be a Bootstrap utility class: the nav gap widens 4px at >=lg
   (1.75rem is off the Bootstrap spacer scale). Show/hide and the CTA margin are handled by the
   d-none/d-lg-flex and ms-auto/ms-lg-0 utilities on the elements, so this is the single remaining
   menu media query. */
@media (min-width: 992px) {
    .vm-nav-inner { gap: 1.75rem; }
}
/* The sidebar/backdrop are only reachable via the hamburger, which only shows <992px, so no extra
   desktop guard is needed - they stay off-screen and invisible until toggled. */

/* ---------- shared section rhythm ---------- */
.vm-section { padding: 4rem 0; }
.vm-section-alt { background: var(--vm-panel-2); border-top: 1px solid var(--vm-line); border-bottom: 1px solid var(--vm-line); }
.vm-eyebrow {
    font-size: .75rem;
    font-weight: 600;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: var(--vm-accent);
    margin: 0 0 .75rem;
}
.vm-h1 {
    font-size: clamp(2.25rem, 6vw, 3.75rem);
    font-weight: 700;
    letter-spacing: -.02em;
    line-height: 1.08;
    margin: 0 0 1rem;
    text-wrap: balance;
}
.vm-h2 {
    font-size: clamp(1.625rem, 4vw, 2.25rem);
    font-weight: 700;
    letter-spacing: -.015em;
    line-height: 1.15;
    margin: 0 0 .75rem;
    text-wrap: balance;
}
.vm-lede { color: var(--vm-muted); font-size: 1.125rem; max-width: 38rem; margin: 0 0 1.5rem; }
.vm-center { text-align: center; }
.vm-center .vm-lede { margin-left: auto; margin-right: auto; }

/* ---------- hero ---------- */
.vm-hero { padding: 4rem 0 3.5rem; }
.vm-hero-grid { display: grid; gap: 2.5rem; align-items: center; }
@media (min-width: 992px) { .vm-hero-grid { grid-template-columns: 1.05fr .95fr; } }
.vm-hero-ctas { display: flex; flex-wrap: wrap; gap: .75rem; margin-bottom: .75rem; }
/* In a centred single-column hero (the SEO landing pages) the button row centres with the copy;
   the homepage's side-by-side hero grid is not .vm-center, so it keeps the left edge on desktop. */
.vm-center .vm-hero-ctas { justify-content: center; }
/* Centred CTA button row used under sections (e.g. how-it-works) - same .75rem gap as the hero CTAs. */
.vm-btn-group { display: flex; flex-wrap: wrap; justify-content: center; gap: .75rem; }
.vm-hero-note { color: var(--vm-muted); font-size: .875rem; margin: 0 0 1.5rem; }
/* Under 450px the note splits onto two lines: the derived free offer ("Your first two looks are on
   us.") on the first, and the .vm-note-tail (the standing "No subscription, no ads, ever.") on the
   second. The tail also stands alone when no welcome bundle is configured and the offer is absent. */
@media (max-width: 449.98px) {
    .vm-note-tail { display: block; }
}

/* Hero V2: V1's side-by-side structure (copy left, visual right - the shape that naturally fits
   a fold), with the visual upgraded to ONE big living result card plus a small "recipe" cluster
   of the two inputs pinned to its corner. The main media is height-capped against the viewport
   (min of a vh-based budget and a rem ceiling), so the hero always fits the fold. Flat. */
.vm-hero-v2 { padding: 2.5rem 0 3rem; }
/* padding-left reserves hang space so the input cluster sits mostly BESIDE the result card,
   only its arrow edge overlapping the video. */
.vm-showcase { position: relative; display: flex; justify-content: center; padding-left: 9rem; }
.vm-showcase-main {
    margin: 0;
    position: relative;
    /* fit-content makes the card frame hug its media on every size - never a stretched frame
       with the image crammed on one side (the circular-width bug when width referenced 100%). */
    width: fit-content;
    background: var(--vm-panel);
    border: 1px solid var(--vm-accent);
    border-radius: .875rem;
    padding: .5rem;
}
.vm-showcase-main img, .vm-showcase-main video {
    height: min(calc(100vh - 17rem), 32rem);
    max-width: 100%;
    width: auto;
    display: block;
    /* cover kills the hairline letterbox from the video's real ratio vs the styled box; the
       inner radius is concentric with the card (outer .875rem - .5rem padding). */
    object-fit: cover;
    border-radius: .375rem;
}
.vm-showcase-main figcaption {
    position: absolute;
    right: 1.125rem;
    bottom: 1.125rem;
    background: var(--vm-accent);
    color: #fff;
    border-radius: .375rem;
    padding: .1875rem .625rem;
    font-size: .75rem;
    font-weight: 600;
    white-space: nowrap;
}
/* Double-class selector REQUIRED: it must out-rank ".vm-showcase-main img" (class+type),
   or the poster renders alongside the video (the stacked double-image bug). */
.vm-showcase-main .vm-showcase-poster { display: none; }
.vm-showcase-inputs {
    position: absolute;
    /* Sits a touch left of the result card's edge (into the empty right of the copy column) so the
       "recipe" reads clearly beside the result. Verified: at >=1152px it just touches the copy
       column's right edge (over empty space, no text collision); narrower desktops keep a gap. */
    left: -2rem;
    bottom: 1.5rem;
    display: flex;
    align-items: center;
    gap: .25rem;
    z-index: 2;
}
/* The two input thumbs + the "+" ride together in a pair so the trailing arrow can sit beside
   them (desktop) or drop onto its own line beneath them (mobile). */
.vm-showcase-pair { display: flex; align-items: center; gap: .25rem; }
.vm-showcase-thumb {
    margin: 0;
    background: var(--vm-panel);
    border: 1px solid var(--vm-line);
    border-radius: .625rem;
    padding: .3125rem .3125rem 0;
    transition: transform .25s ease;
}
/* Desktop input-thumb size (mobile overrides this with a width-based rule below). Both thumbs are
   locked to ONE box - the person shot's native .558 - so "Your photo" and "Outfit photo" are
   identical in width AND height; the wider outfit shot loses a little from its sides to object-fit,
   where its subject is centered. Same discipline as the welcome strip (.vm-welcome .vm-strip img):
   an equal-box cluster declares the ratio, it never inherits it from the assets. The ratio is fixed
   here rather than passed as --vm-tile-ratio because it is a property of this LAYOUT, not the asset. */
.vm-showcase-thumb img {
    height: 13.5rem;
    width: auto;
    aspect-ratio: .558;
    display: block;
    object-fit: cover;
    border-radius: .3125rem;
}
.vm-showcase-thumb figcaption {
    font-size: .6875rem;
    color: var(--vm-muted);
    text-align: center;
    padding: .3125rem 0 .4375rem;
    white-space: nowrap;
}
.vm-showcase-thumb-a { transform: rotate(-4deg); }
.vm-showcase-thumb-b { transform: rotate(3deg); }
.vm-showcase-thumb-a:hover, .vm-showcase-thumb-b:hover { transform: rotate(0); }
.vm-showcase-op { width: 1.75rem; height: 1.75rem; font-size: .75rem; margin: 0 -0.4375rem; z-index: 3; position: relative; }
@media (prefers-reduced-motion: reduce) {
    .vm-showcase video { display: none; }
    .vm-showcase .vm-showcase-poster { display: block; }
    .vm-showcase-thumb-a, .vm-showcase-thumb-b { transform: none; }
}
/* Tablet + phone: stack the showcase cleanly (result card on top, a centered "made from" input
   row below) instead of the desktop overlap - the overlap only reads right when the card hangs
   beside the cluster. Media sized by VIEWPORT (never the parent %) so the frame can't stretch. */
@media (max-width: 991.98px) {
    .vm-showcase { flex-direction: column; align-items: center; padding-left: 0; margin-top: 1rem; gap: 1.25rem; }
    /* Inputs on TOP, result below, so the flow reads top-to-bottom: your two photos -> the result. */
    .vm-showcase-inputs { position: static; order: 1; flex-direction: column; }
    .vm-showcase-main { order: 2; margin: 0 auto; }
    .vm-showcase-main img, .vm-showcase-main video { height: auto; width: min(82vw, 24rem); }
    /* Inputs (Your photo + Outfit photo) fill the column up to a sensible cap - the SAME width as
       the result card below - so they read as a proper "recipe", not tiny thumbnails. The two
       thumbs share the pair width equally (the plus sits between them); each image is sized by
       width, its height following the 0.558 aspect. */
    .vm-showcase-pair { width: min(82vw, 24rem); }
    .vm-showcase-thumb { flex: 1 1 0; min-width: 0; }
    .vm-showcase-thumb img { width: 100%; height: auto; }
    /* The trailing arrow drops onto its own centered line beneath the pair and rotates to point
       DOWN at the result card below it. */
    .vm-showcase-op-arrow { transform: rotate(90deg); margin: .25rem 0 0; }

    /* Stacked hero + spotlight: centre the copy like every other single-column section, and let
       the button row and proof chips centre with it instead of hugging the left edge. */
    .vm-hero-grid > div:first-child { text-align: center; }
    .vm-hero-grid > div:first-child .vm-lede { margin-left: auto; margin-right: auto; }
    .vm-hero-ctas { justify-content: center; }
    /* Stacked hero: the proof chips each drop onto their own centred line (no 2-up wrap). The size
       bump lives in its own media query AFTER the base .vm-chips li rule (below) so it wins. */
    .vm-chips { flex-direction: column; align-items: center; }
    .vm-spotlight { text-align: center; }
    .vm-spotlight .vm-lede { margin-left: auto; margin-right: auto; }
}
.vm-chips { display: flex; flex-wrap: wrap; gap: .5rem; padding: 0; margin: 0; list-style: none; }
.vm-chips li {
    border: 1px solid var(--vm-line);
    border-radius: 999px;
    padding: .375rem .875rem;
    font-size: .8125rem;
    color: var(--vm-muted);
    display: inline-flex;
    align-items: center;
    gap: .45rem;
}
.vm-chips i { color: var(--vm-accent); }
/* Accent-coloured inline text links inside marketing copy (replaces per-link inline styles). */
.vm-link-accent { color: var(--vm-accent); }
/* Stacked hero (< 992px): the centred one-per-line chips grow a touch for readability + tap comfort.
   Placed after the base .vm-chips li so it wins on equal specificity. */
@media (max-width: 991.98px) {
    .vm-chips li { padding: .5rem 1.125rem; font-size: .875rem; }
}

/* the real three-image proof strip: [you] + [outfit] -> [result].
   Tiles NEVER crop: each figure's flex-grow equals its image's width/height ratio (--vm-r,
   set inline), with flex-basis 0 - widths become proportional to ratios, so all tiles share
   one height and every image shows in full. */
.vm-strip { display: flex; gap: .5rem; align-items: center; }
.vm-strip-op, .vm-look-op {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2rem;
    height: 2rem;
    border-radius: 50%;
    background: var(--vm-panel);
    color: var(--vm-muted);
    border: 1px solid var(--vm-line);
    font-size: .85rem;
    flex: none;
}
/* Per-tile ratio comes from the markup as the --vm-tile-ratio custom property (value = the asset's
   true width/height ratio), because it is a property of the ASSET, not of the layout. Widths
   proportional to ratios = one shared height with no cropping, and the aspect-ratio reserves the
   correct box before lazy media loads. Set as a custom property rather than an inline
   flex/aspect-ratio declaration: dynamic values travel as custom properties, never as inline style
   declarations. Falls back to the person shot's .558 if a tile omits it. */
.vm-strip figure {
    margin: 0;
    position: relative;
    min-width: 0;
    flex: var(--vm-tile-ratio, .558) 1 0;
}
.vm-strip img, .vm-strip video {
    width: 100%;
    height: auto;
    aspect-ratio: var(--vm-tile-ratio, .558);
    border-radius: .75rem;
    border: 1px solid var(--vm-line);
    display: block;
}
/* Reduced motion: swap living tiles for their still frames. The selectors must out-rank
   ".vm-strip img" / ".vm-look img" (class+type), hence the double-class form. */
.vm-strip .vm-strip-poster, .vm-looks .vm-live-poster { display: none; }
@media (prefers-reduced-motion: reduce) {
    .vm-strip video, .vm-looks video { display: none; }
    .vm-strip .vm-strip-poster, .vm-looks .vm-live-poster { display: block; }
}
.vm-strip figcaption {
    position: absolute;
    left: .5rem;
    bottom: .5rem;
    background: rgba(9, 9, 11, .82);
    border: 1px solid var(--vm-line);
    border-radius: .375rem;
    padding: .125rem .5rem;
    font-size: .6875rem;
    color: var(--vm-muted);
}
.vm-strip .vm-strip-result img { border-color: var(--vm-accent); }
.vm-strip-caption { color: var(--vm-muted); font-size: .8125rem; margin-top: .625rem; text-align: center; }

/* ---------- steps ---------- */
.vm-steps { display: grid; gap: 1rem; margin-top: 2rem; }
/* Desktop: the three cards with the recipe operators between them - [photo] + [outfit] -> [you],
   the same + / -> chips as the hero cluster and the gallery rows. auto tracks hug the chips. */
@media (min-width: 768px) { .vm-steps { grid-template-columns: 1fr auto 1fr auto 1fr; } }
.vm-steps-op { align-self: center; justify-self: center; }
/* Stacked: the connectors sit centred between the cards and the arrow points down at step 3. */
@media (max-width: 767.98px) { .vm-steps-op-arrow { transform: rotate(90deg); } }
/* The number badge sits inline with the heading (grid row 1); the description(s) span the full
   width on the rows below. */
.vm-step {
    display: grid;
    grid-template-columns: auto 1fr;
    align-items: center;
    /* Pack rows to the TOP: cards stretch to equal height in the row, and without this the grid's
       auto rows stretch to fill (spreading a shorter card's content vertically). */
    align-content: start;
    gap: .625rem .75rem;
    border: 1px solid var(--vm-line);
    border-radius: .75rem;
    background: var(--vm-panel);
    /* Roomier than .vm-card: the trimmed-down step copy is short, so extra padding + the larger
       heading below keep the cards from feeling empty. */
    padding: 1.75rem;
    text-align: left;
}
.vm-step-num {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2rem;
    height: 2rem;
    border-radius: 999px;
    background: var(--vm-accent);
    color: #fff;
    font-weight: 700;
    font-size: .9375rem;
}
.vm-step h3 { font-size: 1.25rem; font-weight: 600; margin: 0; }
.vm-step p { grid-column: 1 / -1; color: var(--vm-muted); font-size: .9375rem; margin: 0; }
.vm-step .vm-micro { grid-column: 1 / -1; font-size: .8125rem; margin: 0; }
.vm-micro { color: var(--vm-muted); font-size: .8125rem; }

/* ---------- benefits ---------- */
.vm-cards { display: grid; gap: 1rem; margin-top: 2rem; }
@media (min-width: 768px) { .vm-cards { grid-template-columns: repeat(2, 1fr); } }
/* Icon sits inline with the heading (grid row 1); the description spans the full width below. */
.vm-card {
    display: grid;
    grid-template-columns: auto 1fr;
    /* Top-align so the icon stays on the heading's FIRST line when the heading wraps to two lines
       (a centred icon would float between the lines). The icon's 1.35rem line-height matches the
       heading's, so its glyph sits centred on that first line. */
    align-items: start;
    align-content: start;
    gap: .5rem .75rem;
    border: 1px solid var(--vm-line);
    border-radius: .75rem;
    background: var(--vm-panel);
    padding: 1.5rem;
    /* Cards are always left-aligned, even inside a centred section (.vm-center) - otherwise the
       inline icon + heading and the description inherit text-align:center and break apart. */
    text-align: left;
}
/* Direct child only: the card's leading accent icon. A descendant selector here would also
   repaint the icon inside a .vm-card-cta button purple-on-purple (invisible) - real bug. */
.vm-card > i { color: var(--vm-accent); font-size: 1.25rem; line-height: 1.35rem; margin: 0; width: 1.5rem; text-align: center; }
.vm-card h3 { font-size: 1.125rem; font-weight: 600; margin: 0; }
.vm-card p { grid-column: 1 / -1; color: var(--vm-muted); font-size: .9375rem; margin: 0; }
/* Optional CTA inside a card (e.g. the "Free to start" pricing teaser): its own full-width row
   under the description, hugging the left edge like the rest of the card content. */
.vm-card-cta { grid-column: 1 / -1; justify-self: start; margin-top: .375rem; }

/* ---------- spotlight (feed + video) ---------- */
.vm-spotlight { display: grid; gap: 2.5rem; align-items: center; margin-top: 1rem; }
@media (min-width: 992px) { .vm-spotlight { grid-template-columns: 1fr 1fr; } }
.vm-spotlight video {
    width: 100%;
    max-width: 24rem;
    margin: 0 auto;
    display: block;
    border-radius: .75rem;
    border: 1px solid var(--vm-line);
}


/* ---------- look rows (mirrors the app's history feed: photo + outfit -> result) ----------
   One full-width row per set, constrained for readability. Same no-crop flex-ratio technique
   as the hero strip. */
.vm-looks { display: grid; gap: 1rem; margin: 2rem auto 0; max-width: 56rem; }
.vm-look {
    display: flex;
    gap: .5rem;
    align-items: center;
    border: 1px solid var(--vm-line);
    border-radius: .75rem;
    background: var(--vm-panel);
    padding: .75rem;
}
/* Per-tile ratio arrives from the markup as --vm-tile-ratio (the asset's true width/height), the
   same contract as .vm-strip above. Result tiles are all .746, so that is the fallback. */
.vm-look figure {
    margin: 0;
    position: relative;
    min-width: 0;
    flex: var(--vm-tile-ratio, .746) 1 0;
}
.vm-look img, .vm-look video {
    width: 100%;
    height: auto;
    aspect-ratio: var(--vm-tile-ratio, .746);
    display: block;
    border-radius: .5rem;
    border: 1px solid var(--vm-line);
}
.vm-look .vm-look-result img, .vm-look .vm-look-result video { border-color: var(--vm-accent); }
.vm-look figcaption {
    position: absolute;
    left: .375rem;
    bottom: .375rem;
    max-width: calc(100% - .75rem);
    overflow: hidden;
    text-overflow: ellipsis;
    background: rgba(9, 9, 11, .82);
    border: 1px solid var(--vm-line);
    border-radius: .375rem;
    padding: .125rem .5rem;
    font-size: .6875rem;
    color: var(--vm-muted);
    white-space: nowrap;
}
/* Phone: the three recipe tiles are too small to also carry a legible source label - the caption
   would overflow the ~78px result tile. Drop it; the recipe images tell the story on their own. */
@media (max-width: 575.98px) {
    .vm-look figcaption { display: none; }
    .vm-look-op { width: 1.5rem; height: 1.5rem; font-size: .6875rem; }
}

.vm-quotes { display: grid; gap: 1rem; margin-top: 2.5rem; }
@media (min-width: 768px) { .vm-quotes { grid-template-columns: repeat(3, 1fr); } }
.vm-quote {
    border: 1px solid var(--vm-line);
    border-radius: .75rem;
    background: var(--vm-panel);
    padding: 1.5rem;
    display: flex;
    flex-direction: column;
    gap: .75rem;
}
.vm-quote-stars { color: var(--vm-accent); font-size: .8125rem; letter-spacing: .1em; }
.vm-quote blockquote { margin: 0; font-size: .9375rem; line-height: 1.55; flex-grow: 1; }
.vm-quote footer { color: var(--vm-muted); font-size: .8125rem; }

/* ---------- pricing ---------- */
.vm-pricing-teaser-cards { display: grid; gap: 1rem; margin: 2rem 0 1.5rem; }
@media (min-width: 768px) { .vm-pricing-teaser-cards { grid-template-columns: repeat(3, 1fr); } }

/* Pricing groups: packs and plans are two stacked full-width sections, each a 3-up card grid
   (1-up on mobile, packs section first). Cards are tall, centered, price-forward, button pinned
   to the bottom so all three buttons align. */
.vm-price-group { margin-top: 2.5rem; }
.vm-price-group-head { text-align: center; margin-bottom: 1.75rem; }
.vm-price-group-head h2 { font-size: 1.625rem; font-weight: 700; margin: 0 0 .375rem; letter-spacing: -.015em; }
.vm-price-group-head p { color: var(--vm-muted); font-size: .9375rem; margin: 0; }

/* "No subscription" reassurance. The single most-asked question about a credit product is whether
   buying once quietly signs you up to something, so the answer is stated as a plain claim strip
   under the h1 and repeated as a pill on the pay-as-you-go group itself. */
.vm-freedoms {
    list-style: none;
    margin: 1.5rem auto 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: .5rem .75rem;
}
.vm-freedoms li {
    display: inline-flex;
    align-items: center;
    gap: .5rem;
    border: 1px solid var(--vm-line);
    border-radius: 999px;
    background: var(--vm-panel);
    padding: .4375rem 1rem;
    font-size: .875rem;
    color: var(--vm-ink);
}
.vm-freedoms li i { color: var(--vm-accent); }
.vm-freedoms li strong { font-weight: 700; }

/* Pill sitting above a pricing group's heading, naming what the whole group is. */
.vm-group-pill {
    display: inline-flex;
    align-items: center;
    gap: .375rem;
    border: 1px solid var(--vm-accent);
    border-radius: 999px;
    color: var(--vm-accent);
    font-size: .6875rem;
    font-weight: 700;
    letter-spacing: .08em;
    text-transform: uppercase;
    padding: .25rem .875rem;
    margin-bottom: .75rem;
}

/* The one comparative line: what a look costs pay-as-you-go against what it costs on a plan.
   Rendered only while the numbers back it up (MarketingSnapshot.PlanSavingsPercent). */
.vm-compare {
    max-width: 46rem;
    /* Bottom margin matches the group head's 1.75rem so the strip never touches the price grid
       that follows it (same flow at every breakpoint). */
    margin: 1.25rem auto 1.75rem;
    border: 1px solid var(--vm-line);
    border-radius: .75rem;
    background: var(--vm-panel);
    padding: 1rem 1.25rem;
    font-size: .9375rem;
    color: var(--vm-muted);
    text-align: center;
}
.vm-compare strong { color: var(--vm-ink); }
.vm-price-grid { display: grid; gap: 1rem; align-items: stretch; }
@media (min-width: 768px) { .vm-price-grid { grid-template-columns: repeat(3, 1fr); } }
.vm-price-card {
    border: 1px solid var(--vm-line);
    border-radius: 1rem;
    background: var(--vm-panel);
    padding: 2rem 1.75rem 1.75rem;
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: .25rem;
}
.vm-price-card.vm-featured { border: 2px solid var(--vm-accent); }
.vm-price-badge {
    position: absolute;
    top: -0.8125rem;
    left: 50%;
    transform: translateX(-50%);
    background: var(--vm-accent);
    color: #fff;
    border-radius: 999px;
    font-size: .6875rem;
    font-weight: 700;
    letter-spacing: .08em;
    text-transform: uppercase;
    padding: .25rem .875rem;
    white-space: nowrap;
}
.vm-price-name { font-size: 1rem; font-weight: 700; letter-spacing: .02em; text-transform: uppercase; color: var(--vm-muted); }
.vm-price-amount { font-size: 2.5rem; font-weight: 700; letter-spacing: -.02em; line-height: 1.1; }
.vm-price-amount small { font-size: .9375rem; font-weight: 500; color: var(--vm-muted); letter-spacing: 0; }
.vm-price-credits {
    color: var(--vm-accent);
    font-size: .9375rem;
    font-weight: 600;
    margin: .5rem 0 0;
    border: 1px solid var(--vm-line);
    border-radius: 999px;
    padding: .25rem .875rem;
}
.vm-price-equiv { color: var(--vm-ink); font-size: .875rem; margin: .625rem 0 0; }
.vm-price-tag { color: var(--vm-muted); font-size: .875rem; margin: .375rem 0 1.25rem; }
.vm-price-card .vm-btn { margin-top: auto; width: 100%; }
.vm-price-foot { color: var(--vm-muted); font-size: .8125rem; margin-top: 1.25rem; text-align: center; }
/* The free-swap banner: one clean accent-outlined band (gift icon + one-line offer + CTA),
   following the h1 directly. Flat, no shadows; the bright CTA is the only solid accent so the
   eye lands on it. Replaced the old ticket-stub / perforation voucher, which read as clutter. */
.vm-free-hero {
    margin-top: 2.5rem;
    display: flex;
    align-items: center;
    gap: 1.5rem;
    border: 1px solid var(--vm-accent);
    border-radius: 1rem;
    background: var(--vm-panel);
    padding: 1.75rem 2rem;
}
.vm-free-hero-icon {
    flex: none;
    width: 3.5rem;
    height: 3.5rem;
    display: grid;
    place-items: center;
    border-radius: 50%;
    background: rgba(175, 133, 255, .14);
    color: var(--vm-accent);
    font-size: 1.5rem;
}
.vm-free-hero-body { flex: 1 1 auto; min-width: 0; }
.vm-free-hero-body h2 {
    font-size: clamp(1.375rem, 3vw, 1.875rem);
    font-weight: 700;
    letter-spacing: -.02em;
    margin: 0 0 .25rem;
}
.vm-free-hero-body p { margin: 0; font-size: .9375rem; color: var(--vm-muted); }
.vm-free-hero .vm-btn { flex: none; }
/* Periodic sheen sweep across the CTA - the single animated element in the block. */
.vm-btn-shine { position: relative; overflow: hidden; }
.vm-btn-shine::after {
    content: "";
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    width: 50%;
    background: linear-gradient(100deg, transparent, rgba(255, 255, 255, .35), transparent);
    transform: translateX(-130%) skewX(-18deg);
    animation: vm-shine 4.5s ease-in-out infinite;
}
@keyframes vm-shine {
    0% { transform: translateX(-130%) skewX(-18deg); }
    45%, 100% { transform: translateX(330%) skewX(-18deg); }
}
@media (prefers-reduced-motion: reduce) {
    .vm-btn-shine::after { content: none; }
}
@media (max-width: 767.98px) {
    .vm-free-hero { flex-direction: column; text-align: center; gap: 1rem; padding: 1.75rem 1.5rem; }
    .vm-free-hero .vm-btn { width: 100%; }
}

/* Alignment rule (owner feedback): every standalone section heading on the page is CENTERED;
   list/bullet content below stays left-aligned and constrained to the FAQ's readable width. */
.vm-fineprint {
    border: 1px solid var(--vm-line);
    border-radius: .75rem;
    background: var(--vm-panel-2);
    padding: 1.75rem 2rem;
    margin: 3.5rem auto 0;
    max-width: 46rem;
}
.vm-fineprint h2 { font-size: 1.375rem; font-weight: 700; margin: 0 0 1rem; text-align: center; }
.vm-fineprint ul { margin: 0; padding: 0 0 0 1.125rem; color: var(--vm-muted); font-size: .9375rem; display: grid; gap: .5rem; text-align: left; }

.vm-helper { margin-top: 3.5rem; text-align: center; }
.vm-helper ul { list-style: none; max-width: 46rem; margin: 1.5rem auto 0; padding: 0; display: grid; gap: .75rem; text-align: left; }
.vm-helper li {
    border: 1px solid var(--vm-line);
    border-radius: .625rem;
    background: var(--vm-panel);
    padding: .875rem 1.25rem;
    font-size: .9375rem;
    color: var(--vm-muted);
}
.vm-helper li strong { color: var(--vm-ink); }
/* Opt-in centring for helper lists that are short instruction lines rather than bullets
   (the /download home-screen steps), so they read with the centred heading above them. */
.vm-helper-center ul { text-align: center; }

/* ---------- the three ways to use it (/download) ---------- */
/* Cards are always left-aligned even inside a centred section, same rule as .vm-card. */
.vm-ways { display: grid; gap: 1rem; align-items: stretch; margin-top: 2rem; text-align: left; }
@media (min-width: 768px) { .vm-ways { grid-template-columns: repeat(3, 1fr); } }
.vm-way {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: .625rem;
    border: 1px solid var(--vm-line);
    border-radius: 1rem;
    background: var(--vm-panel);
    padding: 1.75rem;
}
/* The browser option is the one that actually works today, so it carries the accent border. */
.vm-way-primary { border-color: var(--vm-accent); }
.vm-way > i { font-size: 1.5rem; color: var(--vm-accent); }
.vm-way h3 { font-size: 1.125rem; font-weight: 600; margin: 0; }
.vm-way p { color: var(--vm-muted); font-size: .9375rem; margin: 0; }
/* Pushed to the bottom so the buttons line up across cards of unequal copy length. */
.vm-way-foot { margin-top: auto; padding-top: .5rem; }
.vm-way-badge {
    border-radius: 999px;
    padding: .1875rem .625rem;
    font-size: .6875rem;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    background: var(--vm-accent);
    color: #fff;
}
/* Not-yet-shipped options read visibly quieter than the one you can open right now. */
.vm-way-soon > i { color: var(--vm-muted); }
.vm-way-soon .vm-way-badge { background: transparent; border: 1px solid var(--vm-line); color: var(--vm-muted); }

/* ---------- FAQ (pure CSS accordion via details/summary) ---------- */
/* Accordion content is always left-aligned, even inside centered sections. */
/* Group heading on the full /faq page (centered, like every standalone heading). */
.vm-faq-group {
    max-width: 46rem;
    margin: 3rem auto .5rem;
    font-size: 1.375rem;
    font-weight: 700;
    letter-spacing: -.01em;
    text-align: center;
}
.vm-faq-group:first-child { margin-top: 0; }
.vm-faq { max-width: 46rem; margin: 2rem auto 0; display: grid; gap: .625rem; text-align: left; }
.vm-faq-group + .vm-faq { margin-top: 1rem; }
.vm-faq details {
    border: 1px solid var(--vm-line);
    border-radius: .625rem;
    background: var(--vm-panel);
}
.vm-faq summary {
    cursor: pointer;
    list-style: none;
    padding: 1rem 1.25rem;
    font-weight: 600;
    font-size: .9375rem;
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
}
.vm-faq summary::-webkit-details-marker { display: none; }
.vm-faq summary::after {
    content: "+";
    color: var(--vm-accent);
    font-size: 1.25rem;
    font-weight: 500;
    line-height: 1;
    transition: transform .3s ease;
}
/* The + rotates into an x while open (replaces the old +/- content swap, which can't animate). */
.vm-faq details[open] summary::after { transform: rotate(45deg); }
.vm-faq details > p { padding: 0 1.25rem 1rem; margin: 0; color: var(--vm-muted); font-size: .9375rem; }

/* ---------- beta band ----------
   A centred announcement strip for features that are live but still being tuned (currently hair
   and makeup on /how-it-works). Accent-tinted so it reads as news rather than as another section,
   with the three studios listed as chips and the newer two flagged. Flat: tint + hairlines only. */
.vm-beta {
    background: rgba(175, 133, 255, .06);
    border-top: 1px solid var(--vm-line);
    border-bottom: 1px solid var(--vm-line);
    padding: 3.25rem 0;
    text-align: center;
}
.vm-beta-pill {
    display: inline-flex;
    align-items: center;
    gap: .4375rem;
    margin: 0 0 1rem;
    border: 1px solid var(--vm-accent);
    border-radius: 999px;
    padding: .3125rem .875rem;
    color: var(--vm-accent);
    font-size: .75rem;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
}
.vm-beta-title {
    font-size: 1.625rem;
    font-weight: 700;
    letter-spacing: -.015em;
    line-height: 1.25;
    margin: 0 0 .75rem;
}
.vm-beta-copy {
    color: var(--vm-muted);
    font-size: 1rem;
    max-width: 40rem;
    margin: 0 auto;
}
.vm-beta-chips {
    list-style: none;
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: .5rem .75rem;
    margin: 1.5rem 0 0;
    padding: 0;
}
.vm-beta-chips li {
    display: inline-flex;
    align-items: center;
    gap: .5rem;
    border: 1px solid var(--vm-line);
    border-radius: 999px;
    background: var(--vm-panel);
    padding: .4375rem 1rem;
    font-size: .875rem;
    font-weight: 600;
}
.vm-beta-chips li i { color: var(--vm-accent); }
/* The "Beta" flag inside a chip - quieter than the chip label it qualifies. */
.vm-beta-flag {
    border-radius: 999px;
    background: rgba(175, 133, 255, .16);
    padding: .0625rem .4375rem;
    color: var(--vm-accent);
    font-size: .6875rem;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
}
/* The settled counterpart on the finished studio: same shape, no accent, so "Beta" stays the flag
   that catches the eye and "Live" just answers the question the other two raise. */
.vm-beta-flag-live {
    background: rgba(255, 255, 255, .08);
    color: var(--vm-muted);
}
@media (min-width: 768px) {
    .vm-beta { padding: 4rem 0; }
    .vm-beta-title { font-size: 2rem; }
}

/* ---------- CTA band ---------- */

.vm-cta-band { background: var(--vm-panel-2); border-top: 1px solid var(--vm-line); text-align: center; padding: 4.5rem 0; position: relative; overflow: hidden; }
.vm-cta-band .vm-h2 { margin-bottom: 1.25rem; }
.vm-cta-band .vm-micro { display: block; margin-top: .875rem; }
/* Ambient background clip behind the final CTA (subtle, decorative only). */
.vm-cta-bg {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    opacity: .3;
    pointer-events: none;
}
.vm-cta-band .vm-shell { position: relative; }
@media (prefers-reduced-motion: reduce) { .vm-cta-bg { display: none; } }

/* ---------- legal pages ---------- */
.vm-legal { max-width: 46rem; margin: 0 auto; padding: 3.5rem 1.25rem 5rem; }
.vm-legal h1 { font-size: 2rem; font-weight: 700; letter-spacing: -.02em; margin: 0 0 .5rem; }
.vm-legal h2 { font-size: 1.25rem; font-weight: 700; margin: 2rem 0 .5rem; }
.vm-legal p, .vm-legal li { color: var(--vm-muted); font-size: .9375rem; }
.vm-legal-updated { font-size: .8125rem; color: var(--vm-muted); margin-bottom: 2rem; }

/* ---------- footer ----------
   Redesigned: a brand column (desaturated logo + tagline) beside evenly-weighted link columns,
   then a slim divider and a single copyright line. The logo is greyscale/dimmed by default and
   returns to full colour on hover - a quieter footer treatment than the header mark. */
.vm-footer { margin-top: auto; border-top: 1px solid var(--vm-line); background: var(--vm-panel-2); }
.vm-footer-top {
    display: grid;
    gap: 2.5rem 3rem;
    padding: 3.5rem 1.25rem 2.75rem;
    grid-template-columns: 1fr;
}
@media (min-width: 768px) { .vm-footer-top { grid-template-columns: 1.6fr 1fr 1fr 1fr; align-items: start; } }
.vm-footer-brand { display: flex; flex-direction: column; align-items: flex-start; gap: 1.25rem; max-width: 24rem; }
/* Greyscale + dimmed by default; full colour on hover (a subtle, designed footer touch). */
.vm-footer-logo img {
    height: auto;
    max-height: 3.25rem;
    width: auto;
    display: block;
    filter: grayscale(1);
    opacity: .65;
    transition: filter .2s ease, opacity .2s ease;
}
.vm-footer-logo:hover img,
.vm-footer-logo:focus-visible img { filter: none; opacity: 1; }
.vm-footer-tag { color: var(--vm-muted); font-size: .9375rem; margin: 0; line-height: 1.5; }
/* Store badge under the brand column - only rendered once the Play listing URL is configured. */
.vm-footer-app { margin-top: 1rem; align-self: flex-start; font-size: .875rem; }
/* Social icons: outlined circular buttons that fill with accent on hover. */
.vm-social { list-style: none; display: flex; flex-wrap: wrap; gap: .625rem; margin: .25rem 0 0; padding: 0; }
.vm-social a {
    display: grid;
    place-items: center;
    width: 2.25rem;
    height: 2.25rem;
    border: 1px solid var(--vm-line);
    border-radius: 50%;
    color: var(--vm-muted);
    font-size: 1rem;
    transition: color .15s ease, border-color .15s ease, background-color .15s ease;
}
.vm-social a:hover { color: #fff; border-color: var(--vm-accent); background: var(--vm-accent); }
/* On desktop the two link columns are their own grid cells (2fr 1fr 1fr); on mobile they sit side
   by side under the brand block. */
.vm-footer-nav { display: contents; }
@media (max-width: 767.98px) { .vm-footer-nav { display: grid; grid-template-columns: repeat(2, 1fr); gap: 2rem; } }
.vm-footer-heading { font-size: .75rem; font-weight: 700; letter-spacing: .12em; text-transform: uppercase; color: var(--vm-muted); margin: 0 0 1rem; }
/* Scoped to the nav link columns only - must NOT hit .vm-social (a ul in the brand block),
   or its grid would out-specify the social row's flex and stack the icons vertically. */
.vm-footer-nav ul { list-style: none; margin: 0; padding: 0; display: grid; gap: .625rem; }
/* Scoped to the link columns only - a bare ".vm-footer a" (class+type) would out-rank
   ".vm-btn-primary" and repaint the brand block's CTA text muted (real bug). */
.vm-footer-nav a { color: var(--vm-ink); font-size: .9375rem; transition: color .15s ease; }
.vm-footer-nav a:hover { color: var(--vm-accent); }
/* "Good to know" reassurance column: icon-led promise lines (not links). */
.vm-footer-trust-list li { display: flex; align-items: center; gap: .5rem; color: var(--vm-muted); font-size: .9375rem; }
.vm-footer-trust-list i { color: var(--vm-accent); width: 1rem; text-align: center; }
/* Foot: just the copyright now, under one divider. */
.vm-footer-foot { border-top: 1px solid var(--vm-line); padding: 1.5rem 1.25rem 2.25rem; }
.vm-footer-copy { text-align: center; color: var(--vm-muted); font-size: .8125rem; }

/* ---------- contact form (public /contact, static-SSR) ---------- */
.vm-contact { max-width: 34rem; margin: 2.5rem auto 0; }
.vm-form { display: grid; gap: 1.25rem; }
.vm-field { display: grid; gap: .375rem; text-align: left; }
.vm-field label { font-size: .875rem; font-weight: 600; color: var(--vm-ink); }
.vm-input {
    width: 100%;
    background: var(--vm-panel);
    border: 1px solid var(--vm-line);
    border-radius: .625rem;
    color: var(--vm-ink);
    padding: .75rem .875rem;
    font: inherit;
    transition: border-color .15s ease;
}
.vm-input:focus { outline: none; border-color: var(--vm-accent); }
textarea.vm-input { resize: vertical; min-height: 8rem; }
.vm-val { color: #ff8f8f; font-size: .8125rem; }
.vm-form .vm-btn { justify-self: start; }
.vm-contact-error {
    border: 1px solid #7a2f2f;
    background: rgba(255, 90, 90, .1);
    color: #ffb0b0;
    border-radius: .625rem;
    padding: .75rem 1rem;
    font-size: .9375rem;
    margin: 0 0 1.25rem;
}
/* ---------- waitlist modal (public, shown while payments are unconfigured) ----------
   The shared EzModal (Bootstrap modal markup, opened by ezModal.js because this page is static
   SSR). These rules only dress its .modal-content in the marketing palette so it reads as part of
   the site rather than the app; structure, focus trap and Escape all come from the component.
   It is NOT a native <dialog> - showModal()'s top layer breaks password-manager autofill.
   Reuses the contact form's field styles above so the two public forms look like one family. */
.vm-waitlist-modal {
    max-width: min(28rem, calc(100vw - 2rem));
    margin-inline: auto;
    border: 1px solid var(--vm-line);
    border-radius: 1rem;
    background: var(--vm-panel);
    color: var(--vm-ink);
    /* The panel is dark whatever colour mode the visitor's app cookie asks for, so the shared
       btn-close has to stay light-on-dark rather than follow [data-bs-theme]. */
    --bs-btn-close-filter: invert(1) grayscale(100%) brightness(200%);
}
.vm-waitlist-modal .modal-header,
.vm-waitlist-modal .modal-footer { border-color: var(--vm-line); }
.vm-waitlist-modal .modal-header { padding: 1.75rem 1.75rem 1rem; }
.vm-waitlist-modal .modal-title { font-size: 1.375rem; font-weight: 700; }
.vm-waitlist-modal .modal-body { padding: 0; }
.vm-waitlist-modal .modal-footer { padding: 1.25rem 1.75rem 1.75rem; }
/* The footer holds the single submit button, which should fill the width like it used to. */
.vm-waitlist-modal .modal-footer .vm-btn { flex: 1 1 auto; justify-content: center; }
.vm-waitlist-body { padding: 1rem 1.75rem 0; display: grid; gap: 1.25rem; }
.vm-waitlist-lede { color: var(--vm-muted); font-size: .9375rem; margin: 0; }
/* The bonus-credits promise: the one thing on this dialog worth an accent. */
.vm-waitlist-bonus {
    display: flex; gap: .625rem; align-items: flex-start;
    border: 1px solid var(--vm-accent);
    border-radius: .625rem;
    padding: .75rem .875rem;
    font-size: .9375rem;
}
.vm-waitlist-bonus i { color: var(--vm-accent); margin-top: .15rem; }
.vm-waitlist-fine { color: var(--vm-muted); font-size: .8125rem; margin: 0; }
/* Outcome banner after the POST redirect - fixed, server-owned copy keyed by a bounded code. */
.vm-waitlist-result {
    display: flex; gap: .625rem; align-items: center;
    border: 1px solid var(--vm-accent);
    border-radius: .75rem;
    padding: .875rem 1rem;
    margin: 0 0 1.5rem;
    font-size: .9375rem;
}
.vm-waitlist-result i { color: var(--vm-accent); }

.vm-contact-done { text-align: center; display: grid; gap: .75rem; justify-items: center; padding: 1rem 0; }
.vm-contact-done i { font-size: 2.5rem; color: var(--vm-accent); }
.vm-contact-done h2 { font-size: 1.5rem; font-weight: 700; margin: 0; }
.vm-contact-done p { color: var(--vm-muted); margin: 0; }
.vm-contact-done .vm-btn { margin-top: .5rem; }
/* Honeypot: keep it in the DOM/accessibility-hidden but off-screen for humans. */
.vm-hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* ============================================================================
   Motion. Flat-friendly by design: opacity + small translate/scale only - no
   shadows, no parallax. Everything here is disabled wholesale under
   prefers-reduced-motion (blanket rule at the bottom; the hero keyframes all
   animate FROM a hidden state TO the element's natural styles, so removing
   the animation simply leaves content visible).
   ========================================================================== */

/* Lets ::details-content transition to block-size: auto in supporting browsers
   (Chromium 129+); elsewhere it is ignored and the FAQ opens instantly. */
.vm-site { interpolate-size: allow-keywords; }

/* ---------- scroll reveal ----------
   The layout script tags below-the-fold building blocks with .vm-reveal and
   flips .vm-in the first time each scrolls into view. Tagging happens in JS,
   never in markup, so content is ALWAYS visible without JS. --vm-reveal-delay
   staggers matched siblings inside a grid (cards, steps, looks). */
.vm-reveal {
    opacity: 0;
    transform: translateY(16px);
    transition: opacity .6s ease, transform .6s ease;
    transition-delay: var(--vm-reveal-delay, 0s);
}
.vm-reveal.vm-in { opacity: 1; transform: none; }
/* How-it-works: on desktop all five children (step + step -> step) sit on one grid
   row and enter the viewport together, so fixed delays play them strictly in
   story order. On mobile they stack and enter one at a time while scrolling -
   the default quick sibling stagger stays, or step 2 would lag its own arrival. */
@media (min-width: 768px) {
    .vm-steps > .vm-reveal:nth-child(1) { transition-delay: 0s; }
    .vm-steps > .vm-reveal:nth-child(2) { transition-delay: .3s; }
    .vm-steps > .vm-reveal:nth-child(3) { transition-delay: .5s; }
    .vm-steps > .vm-reveal:nth-child(4) { transition-delay: .8s; }
    .vm-steps > .vm-reveal:nth-child(5) { transition-delay: 1s; }
}

/* ---------- hero entrance ---------- */
@keyframes vm-rise {
    from { opacity: 0; transform: translateY(14px); }
}
@keyframes vm-pop {
    from { opacity: 0; transform: scale(.85); }
}
/* Copy column settles first, top to bottom. */
.vm-hero .vm-h1 { animation: vm-rise .55s ease-out backwards; }
.vm-hero .vm-lede { animation: vm-rise .55s ease-out .1s backwards; }
.vm-hero .vm-hero-ctas { animation: vm-rise .55s ease-out .2s backwards; }
.vm-hero .vm-hero-note { animation: vm-rise .55s ease-out .3s backwards; }
.vm-hero .vm-chips { animation: vm-rise .55s ease-out .4s backwards; }
/* Then the showcase tells the product story in NARRATIVE order:
   [your photo] -> + -> [outfit] -> arrow -> the result lands last as the payoff.
   (vm-pop's implicit "to" state is each element's own computed transform, so the
   tilted thumbs scale in straight into their rotation - no end-of-animation snap.) */
.vm-hero-v2 .vm-showcase-thumb-a { animation: vm-pop .45s ease-out .5s backwards; }
.vm-hero-v2 .vm-showcase-op:not(.vm-showcase-op-arrow) { animation: vm-pop .35s ease-out .75s backwards; }
.vm-hero-v2 .vm-showcase-thumb-b { animation: vm-pop .45s ease-out .9s backwards; }
.vm-hero-v2 .vm-showcase-op-arrow { animation: vm-pop .35s ease-out 1.15s backwards; }
.vm-hero-v2 .vm-showcase-main { animation: vm-rise .6s ease-out 1.35s backwards; }
/* V1 strip equivalent (kept compiled like the hero itself): tiles left to right. */
.vm-strip > :nth-child(1) { animation: vm-pop .45s ease-out .3s backwards; }
.vm-strip > :nth-child(2) { animation: vm-pop .35s ease-out .55s backwards; }
.vm-strip > :nth-child(3) { animation: vm-pop .45s ease-out .7s backwards; }
.vm-strip > :nth-child(4) { animation: vm-pop .35s ease-out .95s backwards; }
.vm-strip > :nth-child(5) { animation: vm-pop .45s ease-out 1.1s backwards; }
.vm-strip-caption { animation: vm-rise .5s ease-out 1.4s backwards; }

/* ---------- button icon micro-interactions ---------- */
.vm-btn i { transition: transform .2s ease; }
.vm-btn:hover .fa-arrow-right,
.vm-btn:hover .fa-arrow-right-long { transform: translateX(3px); }
.vm-btn:hover .fa-wand-magic-sparkles { transform: rotate(-14deg); }

/* ---------- FAQ smooth expand ---------- */
.vm-faq details::details-content {
    block-size: 0;
    overflow: hidden;
    transition: block-size .35s ease, content-visibility .35s allow-discrete;
}
.vm-faq details[open]::details-content { block-size: auto; }

/* ---------- studio welcome (/welcome) ----------
   The app host's signed-out front door - the first screen of the installed mobile app. One
   centered column: logo -> proof strip -> pitch -> free offer -> the two ways in. Reuses the
   marketing components (.vm-strip with its shared pop-in entrance, .vm-btn, .vm-h1); the rules
   here are layout plus the copy's entrance, timed to follow the strip (.3s-1.1s). */
.vm-welcome-main {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    width: 100%;
    max-width: 30rem;
    margin: 0 auto;
    /* Safe-area aware: the mobile WebView is edge-to-edge, so the resting page must clear the
       status bar (top) and the gesture bar (bottom) on every device, not just tall phones. */
    padding: calc(2.5rem + env(safe-area-inset-top, 0px)) 1.5rem calc(3rem + env(safe-area-inset-bottom, 0px));
}
/* The stage aura bleeds past the column edges by design; clip the page so it can never create a
   sideways pan on a phone (the layout root is the scroll container for this page). */
.vm-welcome { overflow-x: clip; }
.vm-welcome-brand img { max-height: 88px; width: auto; display: block; }
/* Welcome-only tile discipline: all three tiles the SAME width and aspect ratio, so the strip
   reads as one calm equation. The shared ratio is the PERSON shot's native .558 - the tallest
   asset - so object-fit never crops vertically (heads and feet always visible on every tile);
   the two wider shots lose a little from their sides, where their subjects are centered.
   (The marketing hero keeps its native, mixed-ratio tiles; these rules are welcome-scoped.) */
.vm-welcome .vm-strip figure { flex: 1 1 0; }
.vm-welcome .vm-strip img,
.vm-welcome .vm-strip video {
    aspect-ratio: .558;
    height: auto;
    object-fit: cover;
}
/* Stage behind the strip: a faint accent aura (a background wash, not a depth shadow - the flat
   rule stands) so the product proof reads as the page's glowing centrepiece. */
.vm-welcome-stage { position: relative; width: 100%; margin: 2.25rem 0 2.25rem; }
.vm-welcome-stage::before {
    content: "";
    position: absolute;
    inset: -18% -12%;
    background: radial-gradient(closest-side, rgba(175, 133, 255, .13), transparent 72%);
    pointer-events: none;
}
.vm-welcome .vm-h1 { margin: 0 0 .75rem; }
.vm-welcome-lede { color: var(--vm-muted); font-size: 1.0625rem; margin: 0 0 1.75rem; }
/* Both ways in, stacked and equal width - primary on top (carrying the free-looks offer),
   thumb-reachable on a phone. */
.vm-welcome-ctas { display: flex; flex-direction: column; gap: .75rem; width: 100%; max-width: 21rem; }
/* The secondary way in reads as a REAL button, not a hairline box: filled panel surface with a
   brighter edge (welcome-mat only - the marketing pages keep their quieter outline style). The
   primary stays visually dominant; this just makes "tappable" unmistakable. */
.vm-welcome-ctas .vm-btn-outline {
    background: var(--vm-panel);
    border-color: #43434c;
}
/* Stacked primary CTA: action on the big line, the offer on a quiet second line - one tap
   target that fits any screen width. */
.vm-welcome-cta { flex-direction: column; gap: .0625rem; padding-top: .625rem; padding-bottom: .625rem; line-height: 1.25; }
.vm-welcome-cta-main { display: inline-flex; align-items: center; gap: .5rem; }
.vm-welcome-cta-sub { font-size: .75rem; font-weight: 500; opacity: .85; }
/* One voice of social proof: quiet stars, a short quote, a named owner. Panel-free so it reads
   as a person talking, not another UI card. */
.vm-welcome-quote { margin: 1.75rem 0 0; max-width: 24rem; }
.vm-welcome-quote-stars { display: block; color: var(--vm-accent); font-size: .6875rem; letter-spacing: .2em; margin-bottom: .5rem; }
.vm-welcome-quote blockquote {
    margin: 0 0 .375rem;
    font-size: .9375rem;
    line-height: 1.55;
    font-style: italic;
    color: var(--vm-fg);
}
.vm-welcome-quote figcaption { color: var(--vm-muted); font-size: .8125rem; }
/* Tablets and up: let the mat breathe a little wider so it does not read as a stretched phone. */
@media (min-width: 768px) {
    .vm-welcome-main { max-width: 34rem; }
}
/* Short viewports (compact phones, landscape-ish): compress the vertical rhythm so the headline
   AND the primary CTA land on the first screen - the mat must sell and convert without a scroll.
   Tall phones keep the airy spacing above. */
@media (max-height: 800px) {
    .vm-welcome-main {
        padding: calc(1.75rem + env(safe-area-inset-top, 0px)) 1.5rem calc(2.25rem + env(safe-area-inset-bottom, 0px));
    }
    .vm-welcome-brand img { max-height: 60px; }
    .vm-welcome-stage { margin: 1.5rem 0 1.5rem; }
    .vm-welcome .vm-h1 { font-size: clamp(1.875rem, 5vw, 2.5rem); margin-bottom: .5rem; }
    .vm-welcome-lede { font-size: 1rem; margin-bottom: 1.25rem; }
    .vm-welcome-quote { margin-top: 1.25rem; }
    .vm-welcome-foot { margin-top: 1.25rem; }
}
/* Trust lines: one short claim per row, each with its own icon. */
.vm-welcome-foot {
    display: flex;
    flex-direction: column;
    gap: .375rem;
    margin: 1.75rem 0 0;
    padding: 0;
    list-style: none;
}
.vm-welcome-foot i { color: var(--vm-accent); margin-right: .25rem; }
/* Narrow phones: the three tiles are small, so the overlay caption pills would cover half of
   each image (verified at 375px: 74px tiles vs 67px pills). Shrink the operator chips to give
   the tiles the width back, and move the captions BELOW the tiles as quiet centered microtext. */
@media (max-width: 479.98px) {
    .vm-welcome .vm-strip { gap: .375rem; }
    .vm-welcome .vm-strip-op { width: 1.25rem; height: 1.25rem; font-size: .65rem; }
    .vm-welcome .vm-strip figcaption {
        /* width: max-content (NOT fit-content, which caps at the tile width before max-width can
           grant anything) lets a caption run slightly wider than its tile - borrowing from the
           page's 1.5rem side padding, so it still cannot reach the screen edge. "You, wearing it"
           then holds ONE line at every real phone width, keeping all three images top-aligned.
           left + translateX centers it even when overflowing (auto margins resolve to 0 there);
           wrap remains the fallback for anything narrower than ~320px. */
        position: relative;
        left: 50%;
        transform: translateX(-50%);
        width: max-content;
        max-width: calc(100% + 1.25rem);
        margin: .375rem 0 0;
        background: none;
        border: 0;
        padding: 0;
        font-size: .625rem;
        white-space: normal;
        text-align: center;
        line-height: 1.3;
    }
}
/* Entrance: logo first, then the strip pops (shared .vm-strip keyframes), then the copy and
   CTAs rise in reading order as the payoff settles. */
.vm-welcome .vm-welcome-brand { animation: vm-rise .55s ease-out backwards; }
.vm-welcome .vm-h1 { animation: vm-rise .55s ease-out 1.15s backwards; }
.vm-welcome .vm-welcome-lede { animation: vm-rise .55s ease-out 1.25s backwards; }
.vm-welcome .vm-welcome-ctas { animation: vm-rise .55s ease-out 1.35s backwards; }
.vm-welcome .vm-welcome-quote { animation: vm-rise .55s ease-out 1.45s backwards; }
.vm-welcome .vm-welcome-foot { animation: vm-rise .55s ease-out 1.55s backwards; }

/* ---------- reduced motion: kill every animation and transition on the site.
   The reveal script also skips tagging, but belt and braces. ---------- */
@media (prefers-reduced-motion: reduce) {
    .vm-site *,
    .vm-site *::before,
    .vm-site *::after {
        animation: none !important;
        transition: none !important;
    }
    .vm-reveal { opacity: 1; transform: none; }
}

/* ── Marketing utilities ─────────────────────────────────────────────────────
   Named classes for the few presentation values that were being written as
   inline style="" attributes across the marketing pages. Inline styles are
   banned repo-wide; dynamic values travel as custom properties (see
   --vm-tile-ratio above) and fixed ones get a name here.
   ------------------------------------------------------------------------- */

/* Inline link rendered in the brand accent (used in body copy pointing at the FAQ). */
.vm-link-accent { color: var(--vm-accent); }

/* Block-level spacing after a section's copy or card grid. Named by size because
   the marketing pages use their own rhythm, not the Bootstrap spacer scale. */
.vm-mt-sm { margin-top: .75rem; }
.vm-mt-md { margin-top: 1.25rem; }
.vm-mt-lg { margin-top: 2rem; }

/* A .vm-micro line that needs to sit on its own row rather than run inline. */
.vm-micro-block { display: block; }
