/*
Theme Name: VPN Market
Theme URI: https://vpn.moinlabs.tech
Author: Moinlabs
Description: Custom marketplace theme for selling VPN subscription plans. Designed for WooCommerce with manual payment verification and manual fulfilment.
Version: 1.0.0
Requires at least: 6.4
Tested up to: 7.1
Requires PHP: 7.4
License: GPL-2.0-or-later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Text Domain: vpnmarket
Tags: e-commerce, custom-colors, custom-menu, custom-logo, featured-images, translation-ready
*/

/* =========================================================================
   1. Design tokens

   The Ledger palette. These names are load-bearing: functions.php prints an
   inline :root from the WordPress Customizer, and sections 14, 17 and 18 are
   written against the same names, so nothing here may be renamed.
   ========================================================================= */
:root {
	--vm-bg: #f5f4f1;            /* the page */
	--vm-surface: #fbfaf8;       /* cards, panels, the pop-ups */
	--vm-band: #ece8e1;          /* the section band that alternates with the page */
	--vm-ink: #1a1a19;
	--vm-body: #4a4945;
	--vm-muted: #68665f;

	/* One hairline. --vm-line-strong is kept because the account and form
	   rules are written against it, but this design has a single weight. */
	--vm-line: rgba(26, 26, 25, .14);
	--vm-line-strong: rgba(26, 26, 25, .14);

	--vm-primary: #7a5c2e;
	--vm-primary-dark: #6b5027;
	--vm-accent: #7a5c2e;

	/* This design has no navy. --vm-navy stays as the name for a dark fill,
	   and a dark fill is now the ink colour. */
	--vm-navy: #1a1a19;
	--vm-bg-tint: #ece8e1;
	--vm-primary-soft: rgba(122, 92, 46, .08);

	/* Status colours: quiet, and only ever used on a state the shop must
	   shout about (an error, a sold-out plan, a payment still unverified). */
	--vm-green: #2f6b4f;
	--vm-green-soft: #e7f7ee;
	--vm-purple-soft: #f2ecff;
	--vm-red: #9c3a2e;
	--vm-red-soft: #fdecec;
	--vm-amber: #8a6220;
	--vm-amber-soft: #fdf3e3;

	/* 4px for controls, 6px for a block. --vm-radius-pill is kept as a name
	   (the account pills use it) but there are no pills in this design. */
	--vm-radius: 4px;
	--vm-radius-lg: 6px;
	--vm-radius-sm: 4px;
	--vm-radius-pill: 4px;

	/* Nothing on this page has a shadow. The one exception is the pop-up
	   panel, which has to lift off the page it covers. */
	--vm-shadow-sm: none;
	--vm-shadow: none;
	--vm-shadow-lg: 0 18px 48px rgba(26, 26, 25, .20);

	--vm-max: 1120px;
	--vm-gutter: 16px;
	--vm-section-y: 44px;

	/* No font is loaded from anywhere: the system stack is the design. */
	--vm-font: system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
	--vm-font-size: 16px;
	--vm-btn-radius: 4px;
	--vm-card-radius: 6px;
	--vm-grid-gap: 20px;
}

/* =========================================================================
   2. Base
   ========================================================================= */
*, *::before, *::after { box-sizing: border-box; }

/*
 * A `display` rule in author CSS beats the user-agent `[hidden] { display: none }`,
 * so any element we hide with the `hidden` attribute AND style with display:flex
 * or display:grid silently stays visible. Everything here is toggled via `hidden`,
 * so make that attribute win.
 */
[hidden] { display: none !important; }

/*
 * scroll-padding-top keeps in-page anchors (#plans, #how) clear of the sticky
 * header. Without it the browser scrolls the target flush to the top of the
 * viewport and the header covers the first ~60px of it — hiding the very
 * heading the user just tapped.
 */
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; scroll-padding-top: 72px; }

body {
	margin: 0;
	background: var(--vm-bg);
	color: var(--vm-body);
	font-family: var(--vm-font);
	font-size: var(--vm-font-size);
	line-height: 1.6;
	-webkit-font-smoothing: antialiased;
}

body.vm-modal-open { overflow: hidden; }

h1, h2, h3, h4, h5, h6 {
	color: var(--vm-ink);
	font-weight: 600;
	line-height: 1.22;
	margin: 0 0 .5em;
	letter-spacing: -.015em;
}

p { margin: 0 0 1em; }

/*
 * Links carry the ink colour, not the accent. The accent is reserved for the
 * one action on a screen, so a link inside a sentence stays plain and quiet.
 */
a { color: var(--vm-ink); text-decoration: none; }

/* Prose links read as an entry in a ledger: ink text on a hairline rule. */
.vm-content a,
.vm-entry a { border-bottom: 1px solid var(--vm-line); }
.vm-content a:hover,
.vm-entry a:hover { border-bottom-color: var(--vm-ink); }

img { max-width: 100%; height: auto; display: block; }

button, input, select, textarea { font: inherit; color: inherit; }

:focus-visible {
	outline: 2px solid var(--vm-accent);
	outline-offset: 2px;
}

.screen-reader-text {
	position: absolute !important;
	width: 1px; height: 1px;
	padding: 0; margin: -1px;
	overflow: hidden; clip: rect(0, 0, 0, 0);
	white-space: nowrap; border: 0;
}

.vm-skip-link {
	position: absolute; left: -9999px; top: 0;
	background: var(--vm-surface); color: var(--vm-ink);
	padding: 12px 16px;
	border: 1px solid var(--vm-line);
	border-radius: var(--vm-radius);
	z-index: 999;
}
.vm-skip-link:focus { left: 16px; top: 16px; }

.vm-container {
	width: 100%;
	max-width: var(--vm-max);
	margin-inline: auto;
	padding-inline: var(--vm-gutter);
}

.vm-section { padding-block: var(--vm-section-y); }

/*
 * Section bands.
 *
 * The plans and the testimonial sit on the band colour, the rest of the page on
 * the page colour. The colour is painted with a 100vw shadow and then clipped
 * back to the section's own box: that is what makes it reach both screen edges
 * without adding a single pixel of layout width, which a plain background on a
 * padded container could not do.
 *
 * Two rules, not one: :has() is what finds the testimonial section, and if a
 * browser does not know it the whole selector list would be dropped — this way
 * the plans band survives on its own.
 */
#plans {
	background: var(--vm-band);
	box-shadow: 0 0 0 100vw var(--vm-band);
	clip-path: inset(0 -100vw);
}
.vm-section:has(.vm-testimonial) {
	background: var(--vm-band);
	box-shadow: 0 0 0 100vw var(--vm-band);
	clip-path: inset(0 -100vw);
}

/* Nothing moves for anyone who has asked for no motion. */
@media (prefers-reduced-motion: reduce) {
	*, *::before, *::after {
		animation-duration: .001ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: .001ms !important;
		scroll-behavior: auto !important;
	}
}

/* =========================================================================
   3. Buttons
   ========================================================================= */
/*
 * One filled action per screen, and it is the accent colour. `.vm-btn` alone is
 * that action; `.vm-btn--dark` (the Subscribe button on a card) needs no rule of
 * its own for the same reason.
 */
.vm-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 8px;
	min-height: 44px;
	padding: 0 16px;
	border: 1px solid var(--vm-primary);
	border-radius: var(--vm-btn-radius);
	background: var(--vm-primary);
	color: #fbfaf8;
	font-weight: 500;
	font-size: 15px;
	line-height: 1.2;
	cursor: pointer;
	text-align: center;
	text-decoration: none;
}
.vm-btn:hover { background: var(--vm-primary-dark); border-color: var(--vm-primary-dark); color: #fbfaf8; }
.vm-btn[disabled], .vm-btn[aria-disabled="true"] { opacity: .55; cursor: not-allowed; }

/* The quiet second action: a hairline box, no fill. */
.vm-btn--ghost {
	background: transparent;
	border-color: var(--vm-line);
	color: var(--vm-ink);
}
.vm-btn--ghost:hover { background: transparent; border-color: var(--vm-ink); color: var(--vm-ink); }

.vm-btn--sm { padding: 0 12px; font-size: 14px; }
.vm-btn--lg { padding: 0 20px; font-size: 16px; }

/*
 * Base size for every icon.
 *
 * vpnmarket_icon() prints <svg class="vm-i vm-i--arrow" viewBox="0 0 24 24"> with
 * NO width/height attributes. A bare SVG has an intrinsic aspect ratio but no
 * intrinsic size, so as a flex item it falls back to the 300x150 default object
 * size and stretches to fill its container. Inside .vm-btn (display:inline-flex)
 * that rendered a ~100px arrow which dwarfed the label and inflated every button
 * on the site to several times its intended height.
 *
 * Every icon carries .vm-i, so it gets a sane default box here. The per-component
 * rules further down (.vm-card__glyph svg, .vm-stars svg, .vm-brand__mark svg …)
 * are more specific and still override this.
 */
.vm-i { width: 18px; height: 18px; flex: 0 0 auto; }

/* =========================================================================
   4. Header
   ========================================================================= */
.vm-header {
	position: sticky; top: 0; z-index: 60;
	background: var(--vm-bg);
	border-bottom: 1px solid var(--vm-line);
}
/* Sticky is a Customizer choice, so the "static" variant has to undo it. */
.vm-header--static { position: static; }

.vm-header__inner {
	display: flex; align-items: center; gap: 18px;
	min-height: 60px;
}
.vm-brand { display: flex; align-items: center; gap: 10px; min-height: 44px; font-weight: 600; font-size: 16px; letter-spacing: -.01em; color: var(--vm-ink); }
.vm-brand:hover { color: var(--vm-ink); }
.vm-brand__mark {
	width: 34px; height: 34px; flex: 0 0 34px;
	border: 1px solid var(--vm-line);
	border-radius: var(--vm-radius);
	background: var(--vm-surface);
	color: var(--vm-ink);
	display: grid; place-items: center;
}
.vm-brand__mark svg { width: 18px; height: 18px; }
.vm-brand__name { font-size: 16px; letter-spacing: -.01em; }
.vm-brand img { max-height: 34px; width: auto; }

/* Plain links, not a pill: the header is a hairline and a row of words. */
.vm-nav {
	display: flex; align-items: center; gap: 4px;
	margin-inline: auto;
}
.vm-nav ul { list-style: none; margin: 0; padding: 0; display: flex; align-items: center; gap: 20px; }
.vm-nav a {
	display: inline-flex; align-items: center;
	min-height: 44px;
	color: var(--vm-body);
	font-weight: 400; font-size: 14.5px;
}
.vm-nav a:hover { color: var(--vm-ink); }
.vm-nav .current-menu-item > a { color: var(--vm-ink); }

.vm-header__actions { display: flex; align-items: center; gap: 6px; margin-left: auto; }

/*
 * The header's one primary action (the design's "Browse plans").
 *
 * From 901px up it sits in the bar beside Sign in. Below that the bar is only
 * brand + search + sign in + menu, so the button is hidden here and the same
 * action is rendered inside the mobile menu instead -- hiding it without that
 * would leave a phone with no way to reach the plans from the header.
 */
.vm-header__cta { display: none; }
@media (min-width: 901px) {
	.vm-header__cta { display: inline-flex; }
}

.vm-mobile-nav__cta { margin: 16px 0 0; }
.vm-mobile-nav__cta .vm-btn { width: 100%; justify-content: center; }
/*
 * The CTA inside the menu is a button, not a menu link. `.vm-mobile-nav a` sets the
 * ink colour for the list and, at 0-1-1, it outranks `.vm-btn`'s own colour at
 * 0-1-0 -- so the accent button rendered near-black text on bronze. Two classes
 * puts it back.
 */
.vm-mobile-nav .vm-btn,
.vm-mobile-nav .vm-btn:hover { color: #fbfaf8; }
@media (min-width: 901px) {
	.vm-mobile-nav__cta { display: none; }
}

.vm-icon-btn {
	width: 44px; height: 44px;
	display: grid; place-items: center;
	border-radius: var(--vm-radius);
	border: 0;
	background: transparent; color: var(--vm-ink);
	cursor: pointer;
}
.vm-icon-btn:hover { background: rgba(26, 26, 25, .05); color: var(--vm-ink); }
.vm-icon-btn svg { width: 18px; height: 18px; }

.vm-signin {
	display: inline-flex; align-items: center;
	min-height: 44px; padding: 0 4px;
	font-size: 14.5px; color: var(--vm-ink);
}
.vm-signin:hover { text-decoration: underline; text-underline-offset: 3px; text-decoration-color: var(--vm-line); }

.vm-burger { display: none; }

.vm-mobile-nav {
	display: none;
	border-top: 1px solid var(--vm-line);
	background: var(--vm-surface);
	padding: 8px var(--vm-gutter) 20px;
}
.vm-mobile-nav.is-open { display: block; }
.vm-mobile-nav ul { list-style: none; margin: 0; padding: 0; }
.vm-mobile-nav li + li { border-top: 1px solid var(--vm-line); }
.vm-mobile-nav a { display: flex; align-items: center; min-height: 48px; color: var(--vm-ink); font-size: 15px; }

/* Search drawer */
.vm-searchbar {
	display: none;
	border-top: 1px solid var(--vm-line);
	background: var(--vm-surface);
	padding: 14px var(--vm-gutter) 18px;
}
.vm-searchbar.is-open { display: block; }
.vm-searchbar form { display: flex; gap: 10px; max-width: var(--vm-max); margin-inline: auto; }
.vm-searchbar input[type="search"] {
	flex: 1;
	min-height: 44px;
	padding: 0 12px;
	border: 1px solid var(--vm-line);
	border-radius: var(--vm-radius);
	background: var(--vm-bg);
	color: var(--vm-ink);
}
.vm-searchbar input[type="search"]::placeholder { color: var(--vm-muted); }

/* =========================================================================
   5. Hero
   ========================================================================= */
.vm-hero { padding-block: 44px 22px; }
.vm-hero__grid {
	display: grid;
	grid-template-columns: minmax(0, 62fr) minmax(0, 38fr);
	gap: 56px;
	align-items: start;
}
.vm-hero__copy { min-width: 0; }

/* Wrapper for the badge. */
.vm-hero__top { display: flex; align-items: flex-start; gap: 14px; margin-bottom: 22px; }

.vm-eyebrow {
	display: inline-flex; align-items: center; gap: 8px;
	min-height: 32px;
	padding: 4px 12px;
	border: 1px solid var(--vm-line);
	border-radius: var(--vm-radius);
	background: transparent;
	color: var(--vm-muted);
	font-size: 12.5px; font-weight: 400;
	line-height: 1.4;
}
.vm-eyebrow__dot { width: 6px; height: 6px; flex: 0 0 6px; border-radius: 50%; background: var(--vm-accent); }

.vm-hero__title {
	font-size: 38px;
	line-height: 1.18;
	font-weight: 600;
	letter-spacing: -.015em;
	color: var(--vm-ink);
	margin: 0;
	max-width: 24ch;
}
/* The phrase the owner marks in the Customizer keeps the accent, and nothing else. */
.vm-hero__title .vm-hl { color: var(--vm-accent); font-style: normal; font-family: inherit; font-weight: 600; }

.vm-hero__text { margin: 14px 0 0; font-size: 16.5px; line-height: 1.6; color: var(--vm-body); max-width: 54ch; }
.vm-hero__cta { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 24px; }

/* Hero image slot
 *
 * Was a decorative collage of absolutely positioned cards; now a single image
 * frame. Nothing here is absolutely positioned, so it cannot collide with
 * itself at any width and needs no responsive de-collaging rules.
 */
.vm-hero__visual { position: relative; }

.vm-hero__media {
	display: grid;
	place-items: center;
	overflow: hidden;
	aspect-ratio: 4 / 3;
	padding: 16px;
	background: var(--vm-surface);
	border: 1px solid var(--vm-line);
	border-radius: var(--vm-radius);
}
.vm-hero__media-img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: contain;
}
.vm-hero__media-empty {
	display: grid;
	place-items: center;
	gap: 10px;
	padding: 24px;
	text-align: center;
	color: var(--vm-muted);
}
.vm-hero__media-empty svg { width: 22px; height: 22px; opacity: .55; }
.vm-hero__media-hint { max-width: 34ch; font-size: 12.5px; line-height: 1.5; }

/* =========================================================================
   6. Section headings
   ========================================================================= */
.vm-section-head {
	display: flex; align-items: flex-end; justify-content: space-between;
	gap: 24px; margin-bottom: 28px; flex-wrap: wrap;
}
.vm-section-head h1 { font-size: 38px; line-height: 1.18; margin-bottom: 6px; }
.vm-section-head h2 { font-size: 30px; line-height: 1.22; margin-bottom: 6px; }
.vm-section-head p { margin: 0; color: var(--vm-muted); max-width: 60ch; }

/* =========================================================================
   7. Filter pills
   ========================================================================= */
.vm-filters {
	display: flex; flex-wrap: wrap; gap: 4px;
	margin: 0 0 20px;
}
.vm-filter {
	display: inline-flex; align-items: center; gap: 7px;
	min-height: 44px;
	padding: 0 12px;
	border: 1px solid transparent;
	border-radius: var(--vm-radius);
	background: transparent;
	color: var(--vm-body);
	font-weight: 400; font-size: 14.5px;
	cursor: pointer;
}
.vm-filter:hover { color: var(--vm-ink); }
/* The chosen category: the accent and a hairline box, nothing filled in. */
.vm-filter.is-active { color: var(--vm-accent); border-color: var(--vm-line); font-weight: 500; }
.vm-filter__count { font-size: 12.5px; color: var(--vm-muted); }

/*
 * While the catalog is being swapped in, dim it and stop clicks landing twice.
 * Without this a slow response looks like the click did nothing at all.
 */
[data-vm-catalog].is-loading {
	opacity: .55;
	pointer-events: none;
	transition: opacity .15s ease;
}

/* =========================================================================
   8. Product grid + cards
   ========================================================================= */
.vm-grid {
	display: grid;
	grid-template-columns: repeat(var(--vm-cols, 3), minmax(0, 1fr));
	gap: var(--vm-grid-gap);
}

.vm-card {
	display: flex; flex-direction: column;
	background: var(--vm-surface);
	border: 1px solid var(--vm-line);
	border-radius: var(--vm-card-radius);
	overflow: hidden;
	height: 100%;
}

/*
 * The picture slot is a logo band, not a picture window.
 *
 * The plans carry wide wordmark logos (3:1 up to 5:1). In the 16:10 box this
 * used to be, a logo was contained to the width and then floated tiny in the
 * middle of a mostly empty tile, and each card's logo sat at a different size
 * depending on its shape. A fixed height gives every card the same band and lets
 * a wide logo use the full width. The page colour inside a hairline stays, so a
 * card with a logo and a card without one are still the same object.
 */
.vm-card__media {
	position: relative;
	height: 150px;
	background: var(--vm-bg);
	border-bottom: 1px solid var(--vm-line);
	display: grid; place-items: center;
	overflow: hidden;
}
/*
 * A plan logo is a company mark, not a photo, so it must never be cropped:
 * "contain" keeps the whole mark visible in the band.
 *
 * The image is pinned with inset:0 rather than height:100%, so it cannot fall
 * back to its own ratio and overflow the band.
 */
.vm-card__media img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; padding: 18px 22px; }
/*
 * A white logo on the near-white band is invisible, so the band turns ink for
 * those and only those. Which ones is measured from the picture itself -- see
 * vpnmarket_logo_is_light() -- because a blanket dark band would swallow the
 * shop's black logos instead (Express VPN's is pure black).
 *
 * The single-product half of this rule lives beside .vm-single__frame in the
 * single-product section: same specificity, so it has to come after its base
 * rule or it silently loses.
 */
.vm-card__media--ink { background: var(--vm-ink); }
@media (max-width: 640px) {
	.vm-card__media { height: 132px; }
}
.vm-card__glyph { color: var(--vm-muted); }
.vm-card__glyph svg { width: 36px; height: 36px; }
.vm-card--out .vm-card__glyph { opacity: .45; }

.vm-card__badges { position: absolute; top: 12px; left: 12px; display: flex; gap: 6px; flex-wrap: wrap; }
/*
 * Small meta tags: a hairline box and muted text. The one exception is the
 * discount, which is the accent because it is money off.
 */
.vm-badge {
	display: inline-flex; align-items: center;
	min-height: 22px;
	padding: 1px 8px;
	border: 1px solid var(--vm-line);
	border-radius: var(--vm-radius);
	background: var(--vm-surface);
	color: var(--vm-muted);
	font-size: 12px; font-weight: 400; letter-spacing: 0;
}
.vm-badge--sale { color: var(--vm-accent); }

.vm-stock {
	position: absolute; top: 12px; right: 12px;
	min-height: 22px; padding: 1px 8px;
	border: 1px solid var(--vm-line);
	border-radius: var(--vm-radius);
	background: var(--vm-band);
	color: var(--vm-muted);
	font-size: 12px; font-weight: 400;
}
.vm-stock--low { background: var(--vm-amber-soft); border-color: transparent; color: var(--vm-amber); }

.vm-card__body { padding: 20px 20px 0; display: flex; flex-direction: column; flex: 1 1 auto; }
.vm-card__cat { font-size: 12.5px; font-weight: 400; letter-spacing: 0; text-transform: none; color: var(--vm-muted); margin-bottom: 6px; display: block; }
.vm-card__cat a { display: inline-block; padding-block: 3px; color: inherit; }
.vm-card__title { font-size: 18px; line-height: 1.25; letter-spacing: -.01em; margin-bottom: 6px; }
.vm-card__title a { display: inline-block; padding-block: 4px; color: inherit; }
.vm-card__title a:hover { color: var(--vm-accent); }
.vm-card__desc { font-size: 14px; line-height: 1.55; color: var(--vm-body); margin-bottom: 14px; }

.vm-tags { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 16px; }
.vm-tag {
	display: inline-flex; align-items: center; gap: 5px;
	min-height: 22px;
	padding: 1px 8px;
	border: 1px solid var(--vm-line);
	border-radius: var(--vm-radius);
	background: transparent;
	color: var(--vm-muted);
	font-size: 12px; font-weight: 400;
}
.vm-tag svg { width: 13px; height: 13px; }

.vm-card__foot {
	margin-top: auto;
	padding: 16px 20px 20px;
	border-top: 1px solid var(--vm-line);
	/*
	 * Price on its own line, the two buttons on the line below it. Sharing one
	 * row made them fight for width: a price range wrapped onto two lines and
	 * the "Details" link was pushed off the card edge.
	 */
	display: flex; flex-direction: column; align-items: stretch; gap: 12px;
}
.vm-price { display: flex; flex-direction: column; gap: 2px; }
.vm-price__label { font-size: 12.5px; color: var(--vm-muted); }
.vm-price__now { font-size: 24px; font-weight: 600; color: var(--vm-ink); letter-spacing: -.015em; font-variant-numeric: tabular-nums; overflow-wrap: break-word; }
.vm-price del { color: var(--vm-muted); font-size: 14px; font-weight: 400; }
.vm-price ins { text-decoration: none; }

/*
 * A plan with no price yet. The shop prints an empty string there, and an empty
 * line looks like a broken card — so it prints the same waiting dash the account
 * pages use for a value that is not known yet.
 */
.vm-price__now:empty::before,
#vm-details-price:empty::before,
.vm-summary__price:empty::before { content: "—"; color: var(--vm-muted); }

/* Subscribe and Details, side by side and the same width. */
.vm-card__actions { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.vm-card__actions .vm-btn { width: 100%; }
.vm-card__more { width: 100%; padding-inline: 10px; }

/* =========================================================================
   9. Pagination
   ========================================================================= */
.vm-pager {
	display: flex; align-items: center; justify-content: space-between;
	gap: 18px; margin-top: 28px; flex-wrap: wrap;
}
.vm-pager__info { margin: 0; color: var(--vm-muted); font-size: 14px; font-variant-numeric: tabular-nums; }
.vm-pager__list { display: flex; align-items: center; gap: 4px; list-style: none; margin: 0; padding: 0; }
/*
 * The box belongs to the <li>: paginate_links prints the current page as
 * <li class="… is-current"><span class="page-numbers current">, so styling the
 * link and the span as well gave the current page two boxes, one inside the other.
 */
.vm-pager__list li { display: grid; place-items: center; }
.vm-pager__list a,
.vm-pager__list span {
	display: grid; place-items: center;
	min-width: 44px; min-height: 44px; padding: 0 10px;
	border: 1px solid transparent;
	border-radius: var(--vm-radius);
	color: var(--vm-body);
	font-size: 14.5px; font-variant-numeric: tabular-nums;
}
.vm-pager__list li:hover > * { border-color: var(--vm-line); color: var(--vm-ink); }
.vm-pager__list .is-current > * { border-color: var(--vm-line); color: var(--vm-accent); font-weight: 500; }
.vm-pager__list .is-dots > * { border-color: transparent; color: var(--vm-muted); }

/* =========================================================================
   10. Promises (why buy here)
   ========================================================================= */
/*
 * Three boxes in a row, stacked on a phone, in the same box language as the
 * testimonial card: hairline, 6px corner, surface fill, 20px padding. No icons
 * and no motion — the promise reads as a sentence led by its own name.
 */
.vm-promises {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: var(--vm-grid-gap);
}
.vm-promise {
	background: var(--vm-surface);
	border: 1px solid var(--vm-line);
	border-radius: var(--vm-card-radius);
	padding: 20px;
	display: flex; flex-direction: column; gap: 10px;
}
.vm-promise__name { font-size: 15px; font-weight: 500; color: var(--vm-ink); line-height: 1.35; }
.vm-promise__line { margin: 0; font-size: 14.5px; line-height: 1.6; color: var(--vm-body); }

/* =========================================================================
   11. Testimonial
   ========================================================================= */
.vm-testimonial {
	background: var(--vm-surface);
	border: 1px solid var(--vm-line);
	border-radius: var(--vm-card-radius);
	padding: 20px;
	color: var(--vm-body);
}
.vm-stars { display: flex; gap: 3px; margin-bottom: 14px; color: var(--vm-accent); }
.vm-stars svg { width: 14px; height: 14px; }
.vm-testimonial blockquote {
	margin: 0 0 14px; max-width: 62ch;
	font-size: 15px; line-height: 1.6; font-style: normal; color: var(--vm-body);
}
.vm-testimonial__person { display: flex; align-items: center; gap: 10px; }
.vm-avatar {
	width: 36px; height: 36px; flex: 0 0 36px;
	border: 1px solid var(--vm-line);
	border-radius: 50%;
	background: transparent;
	display: grid; place-items: center;
	font-size: 13.5px; font-weight: 400; color: var(--vm-ink);
	overflow: hidden;
}
.vm-avatar img { width: 100%; height: 100%; object-fit: cover; }
.vm-testimonial__name { display: block; text-align: left; font-size: 14.5px; font-weight: 500; color: var(--vm-ink); }
.vm-testimonial__role { display: block; text-align: left; font-size: 13px; color: var(--vm-muted); }

/* =========================================================================
   12. Footer
   ========================================================================= */
.vm-footer { background: var(--vm-bg); color: var(--vm-body); border-top: 1px solid var(--vm-line); }
.vm-footer__top {
	display: grid; grid-template-columns: minmax(0, 1.6fr) repeat(3, minmax(0, 1fr));
	gap: 40px; padding-block: 44px 40px;
}
.vm-footer .vm-brand { color: var(--vm-ink); }
.vm-footer__about p { font-size: 14.5px; color: var(--vm-body); max-width: 44ch; margin: 12px 0 16px; }
/* The support link is the one action down here, so it stays quiet. */
.vm-footer__about .vm-btn { background: transparent; border-color: var(--vm-line); color: var(--vm-ink); }
.vm-footer__about .vm-btn:hover { background: transparent; border-color: var(--vm-ink); color: var(--vm-ink); }
.vm-footer h3 {
	color: var(--vm-ink);
	font-size: 14px; font-weight: 500;
	letter-spacing: 0; text-transform: none;
	margin-bottom: 8px;
}
.vm-footer ul { list-style: none; margin: 0; padding: 0; }
.vm-footer li { margin: 0; }
.vm-footer a { display: inline-flex; align-items: center; min-height: 44px; font-size: 14.5px; color: var(--vm-body); }
.vm-footer a:hover { color: var(--vm-ink); text-decoration: underline; text-underline-offset: 3px; }
.vm-footer__bottom {
	border-top: 1px solid var(--vm-line);
	padding-block: 18px;
	display: flex; align-items: center; justify-content: space-between;
	gap: 18px; flex-wrap: wrap; font-size: 13px; color: var(--vm-muted);
}
.vm-footer__legal { display: flex; gap: 20px; flex-wrap: wrap; }
.vm-footer__legal a { color: var(--vm-muted); }
.vm-footer__legal a:hover { color: var(--vm-ink); }

/* =========================================================================
   13. Modal
   ========================================================================= */
.vm-modal {
	position: fixed; inset: 0; z-index: 200;
	display: none;
	align-items: flex-start; justify-content: center;
	padding: 20px;
	overflow-y: auto;
}
.vm-modal.is-open { display: flex; }
.vm-modal__backdrop {
	position: fixed; inset: 0;
	background: rgba(26, 26, 25, .42);
}
/*
 * The one thing on the site that lifts: a hairline panel on the ink scrim.
 * It has to stay readable over whatever is behind it, which is what the
 * --vm-shadow-lg token is for.
 */
.vm-modal__panel {
	position: relative;
	background: var(--vm-surface);
	border: 1px solid var(--vm-line);
	border-radius: var(--vm-card-radius);
	width: 100%; max-width: 640px;
	margin: auto;
	box-shadow: var(--vm-shadow-lg);
	animation: vm-pop 140ms ease-out;
	/*
	 * A column, so a tall dialog pins its head and its buttons and scrolls the
	 * middle rather than running off the bottom of the window: the plan details
	 * are 924px tall in an 844px window, which put the buttons below the fold.
	 * When the content fits, this changes nothing -- the panel is still its
	 * natural height and the middle shows no scrollbar.
	 *
	 * 40px is the overlay's own padding (20px top + 20px bottom): the panel must
	 * not be taller than the space left inside it.
	 */
	display: flex;
	flex-direction: column;
	max-height: calc(100vh - 40px);
	max-height: calc(100dvh - 40px);
}
/* The subscribe and checkout pop-ups wrap their body and foot in a form, so the
   form has to carry the column too or the middle has nothing to scroll inside. */
.vm-modal__panel > form { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; }
@keyframes vm-pop { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }

.vm-modal__head {
	display: flex; align-items: center; justify-content: space-between; gap: 12px;
	padding: 10px 10px 10px 20px;
	border-bottom: 1px solid var(--vm-line);
	flex: 0 0 auto;
}
.vm-modal__head h2 { font-size: 15px; font-weight: 500; color: var(--vm-muted); margin-bottom: 2px; }
.vm-modal__head p { margin: 0; font-size: 13.5px; color: var(--vm-muted); }
.vm-modal__close {
	width: 44px; height: 44px; flex: 0 0 44px;
	border-radius: var(--vm-radius); border: 0;
	background: transparent; cursor: pointer;
	display: grid; place-items: center; color: var(--vm-ink);
}
.vm-modal__close:hover { background: rgba(26, 26, 25, .05); }
.vm-modal__body { padding: 22px 20px; flex: 1 1 auto; min-height: 0; overflow-y: auto; -webkit-overflow-scrolling: touch; }
.vm-modal__foot {
	padding: 14px 20px;
	border-top: 1px solid var(--vm-line);
	display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
	flex: 0 0 auto;
}
.vm-modal__foot .vm-total { margin-left: auto; text-align: right; }
.vm-modal__foot .vm-total span { display: block; font-size: 12.5px; color: var(--vm-muted); }
.vm-modal__foot .vm-total strong { font-size: 24px; font-weight: 600; color: var(--vm-ink); letter-spacing: -.015em; font-variant-numeric: tabular-nums; }

/* Popup icon (Customizer: 8. Checkout popup → Popup icon / image) */
.vm-modal__icon {
	flex: 0 0 40px; width: 40px; height: 40px;
	border: 1px solid var(--vm-line);
	border-radius: var(--vm-radius);
	overflow: hidden;
	display: grid; place-items: center;
	background: var(--vm-bg);
}
.vm-modal__icon img { width: 100%; height: 100%; object-fit: cover; }
.vm-modal__head > div { flex: 1 1 auto; min-width: 0; }

/* Sign in / register tabs shown to signed-out visitors */
.vm-tabs {
	display: flex; gap: 4px;
	border-bottom: 1px solid var(--vm-line);
	margin-bottom: 20px;
}
.vm-tab {
	min-height: 44px; padding: 0 14px;
	border: 0; border-bottom: 2px solid transparent;
	border-radius: 0;
	cursor: pointer;
	background: transparent; color: var(--vm-muted);
	font: inherit; font-size: 14.5px;
}
.vm-tab:hover { color: var(--vm-ink); }
.vm-tab.is-active { background: transparent; color: var(--vm-accent); border-bottom-color: var(--vm-accent); font-weight: 500; }
.vm-auth__title { font-size: 17px; font-weight: 600; margin: 0 0 6px; }
.vm-auth__lead { margin: 0 0 18px; font-size: 14.5px; color: var(--vm-body); }
.vm-auth__submit { width: 100%; justify-content: center; margin-top: 4px; }

/* Plan details popup (Customizer: 9. Plan details popup) */
#vm-details-modal .vm-modal__foot { flex-wrap: wrap; }
.vm-details__loading { margin: 0; color: var(--vm-muted); font-size: 14px; }
.vm-details__top { display: flex; gap: 16px; align-items: flex-start; margin-bottom: 20px; }
/* The same empty frame as the hero's, one size down. */
.vm-details__thumb {
	flex: 0 0 72px; width: 72px; height: 72px;
	border: 1px solid var(--vm-line);
	border-radius: var(--vm-radius);
	overflow: hidden;
	background: var(--vm-bg); display: grid; place-items: center;
}
.vm-details__thumb img { width: 100%; height: 100%; object-fit: cover; }
.vm-details__intro { flex: 1 1 auto; min-width: 0; }
.vm-details__intro h3 { margin: 6px 0; font-size: 20px; font-weight: 600; letter-spacing: -.01em; }
.vm-details__desc { color: var(--vm-body); font-size: 14.5px; max-width: 46ch; }
.vm-details__desc p { margin: 0 0 8px; }
.vm-details__desc p:last-child { margin-bottom: 0; }

/* The facts, between two hairlines, with no boxes around them. */
.vm-details__specs {
	display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 14px 20px; margin: 0; padding: 16px 0;
	border-top: 1px solid var(--vm-line);
	border-bottom: 1px solid var(--vm-line);
}
.vm-details__spec dt { font-size: 12.5px; color: var(--vm-muted); margin-bottom: 2px; }
.vm-details__spec dd { margin: 0; font-size: 15px; color: var(--vm-ink); font-variant-numeric: tabular-nums; }

.vm-details__features { margin-top: 22px; }
.vm-details__features h4 { margin: 0 0 10px; font-size: 15.5px; font-weight: 500; color: var(--vm-ink); }
.vm-details__features ul { margin: 0; padding: 0; list-style: none; display: grid; gap: 8px; }
.vm-details__features li { position: relative; padding-left: 16px; font-size: 14.5px; color: var(--vm-body); }
.vm-details__features li::before {
	content: ""; position: absolute; left: 0; top: .62em;
	width: 5px; height: 5px; border-radius: 50%; background: var(--vm-line);
}

/* ------------------------------------------------- Cost by duration (details)
 * One row per duration with its total and per-month cost. The row that is
 * cheapest per month is marked in the accent so the best value is obvious.
 */
.vm-details__terms { margin-top: 22px; }
.vm-details__terms h4 { margin: 0 0 10px; font-size: 15.5px; font-weight: 500; color: var(--vm-ink); }
/*
 * The cost-by-duration grid reuses the picker's card markup (.vm-option), so it
 * needs no table rules of its own -- the look comes from that block below.
 */
/*
 * The longest term is the one the shop wants picked, so it looks chosen: an accent
 * border, a soft tint and a chip. Shared by the duration picker in the subscribe
 * pop-up and the "cost by duration" grid in the details pop-up -- they are the same
 * cards, so they are the same rules.
 */
.vm-option.is-best { border-color: var(--vm-accent); background: var(--vm-band); }
.vm-option__chip {
	display: inline-block; margin-left: 7px; padding: 1px 8px;
	border-radius: 999px; background: var(--vm-accent); color: #fbfaf8;
	font-size: 10.5px; font-weight: 500; letter-spacing: .04em; text-transform: uppercase;
	vertical-align: 1px; white-space: nowrap;
}
/* The details grid is read-only: the cards are not buttons there. */
.vm-terms .vm-option { cursor: default; }
.vm-terms .vm-option:hover { border-color: var(--vm-line); }
.vm-terms .vm-option.is-best:hover { border-color: var(--vm-accent); }

/* --------------------------------------------- Duration picker (checkout popup)
 * A radio-style list of the durations a plan sells. Choosing one re-prices the
 * summary underneath and is what gets sent to the server as variation_id.
 */
/*
 * Two options per row, not one. A single column made the popup very tall and
 * pushed the summary and the pay button below the fold on a phone.
 */
.vm-options {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 10px;
	margin-bottom: 18px;
}
.vm-options__label {
	grid-column: 1 / -1;
	margin: 0; font-size: 12.5px; font-weight: 400;
	color: var(--vm-muted);
}
.vm-option {
	display: grid;
	grid-template-columns: minmax(0, 1fr) auto;
	align-items: baseline;
	gap: 2px 10px;
	width: 100%;
	min-height: 44px;
	padding: 10px 12px;
	background: var(--vm-surface);
	border: 1px solid var(--vm-line);
	border-radius: var(--vm-radius);
	text-align: left;
	font: inherit; font-size: 14.5px;
	color: var(--vm-ink);
	cursor: pointer;
}
.vm-option:hover { border-color: var(--vm-ink); }
.vm-option.is-active { border-color: var(--vm-accent); background: var(--vm-surface); }
.vm-option.is-out { opacity: .5; cursor: not-allowed; }
/* Duration and price share the first row; the per-month line sits under both. */
.vm-option__name { font-weight: 500; font-size: 14.5px; }
.vm-option__price { font-weight: 500; text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
.vm-option__per { grid-column: 1 / -1; font-size: 12.5px; color: var(--vm-muted); }
.vm-option__save {
	grid-column: 1 / -1;
	justify-self: start;
	margin-top: 4px;
	font-size: 12px; font-weight: 500;
	color: var(--vm-accent);
	white-space: nowrap;
}

/* One step of the four-step subscribe flow: a hairline between the steps, no box. */
.vm-step {
	border: 0; border-radius: 0; background: transparent;
	border-top: 1px solid var(--vm-line);
	padding: 22px 0 0;
	margin: 0 0 22px;
}
.vm-step:first-of-type { border-top: 0; padding-top: 0; }
.vm-step__head { display: flex; align-items: baseline; gap: 8px; margin-bottom: 14px; }
.vm-step__num {
	flex: 0 0 auto;
	background: transparent; color: var(--vm-muted);
	font-size: 12.5px; font-weight: 400;
}
.vm-step__head h3 { font-size: 17px; font-weight: 600; margin: 0; }

.vm-summary {
	display: flex; gap: 12px; align-items: center;
	padding: 12px 0;
	border-top: 1px solid var(--vm-line);
	border-bottom: 1px solid var(--vm-line);
}
.vm-summary__thumb {
	width: 48px; height: 48px; flex: 0 0 48px;
	border: 1px solid var(--vm-line);
	border-radius: var(--vm-radius);
	overflow: hidden;
	background: var(--vm-bg);
	display: grid; place-items: center; color: var(--vm-muted);
}
.vm-summary__thumb img { width: 100%; height: 100%; object-fit: cover; }
.vm-summary__meta { flex: 1 1 auto; min-width: 0; }
.vm-summary__meta strong { display: block; color: var(--vm-ink); font-weight: 500; }
.vm-summary__meta span { font-size: 13px; color: var(--vm-muted); }
.vm-summary__price { font-weight: 600; color: var(--vm-ink); white-space: nowrap; font-variant-numeric: tabular-nums; }

.vm-pay-methods { display: grid; gap: 8px; }
.vm-pay-method {
	display: flex; align-items: center; gap: 12px;
	min-height: 44px;
	border: 1px solid var(--vm-line); border-radius: var(--vm-radius);
	padding: 10px 12px; cursor: pointer; background: var(--vm-surface);
}
.vm-pay-method:hover { border-color: var(--vm-ink); }
.vm-pay-method input { width: 18px; height: 18px; accent-color: var(--vm-accent); }
.vm-pay-method.is-selected { border-color: var(--vm-accent); }
.vm-pay-method__logo { width: 34px; height: 34px; border: 1px solid var(--vm-line); border-radius: var(--vm-radius); object-fit: contain; background: var(--vm-bg); }
.vm-pay-method__name { font-weight: 500; color: var(--vm-ink); font-size: 14.5px; }
.vm-pay-method__meta { font-size: 12.5px; color: var(--vm-muted); }
/* Where to send the money: a note, not a coloured box. */
.vm-pay-instructions {
	margin-top: 12px; padding: 14px 16px;
	background: var(--vm-bg);
	border: 1px solid var(--vm-line);
	border-radius: var(--vm-radius);
	font-size: 14px; color: var(--vm-body);
}
.vm-pay-instructions ol { margin: 8px 0 0; padding-left: 20px; }
.vm-pay-instructions li { margin-bottom: 4px; }
.vm-pay-instructions .vm-copy { display: flex; align-items: center; gap: 8px; margin-top: 6px; }
.vm-pay-instructions code {
	background: var(--vm-surface); border: 1px solid var(--vm-line);
	padding: 4px 10px; border-radius: var(--vm-radius);
	font-weight: 500; color: var(--vm-ink); font-variant-numeric: tabular-nums;
}

/* Forms */
.vm-field { margin-bottom: 16px; }
.vm-field label { display: block; font-size: 14px; font-weight: 400; color: var(--vm-ink); margin-bottom: 6px; }
.vm-field .vm-req { color: var(--vm-accent); }
/*
 * "Optional" badge. These fields really can be skipped, but without a mark
 * they looked exactly like the required ones next to them.
 */
.vm-field .vm-opt {
	display: inline;
	margin-left: 4px;
	padding: 0;
	background: none;
	color: var(--vm-muted);
	font-size: 12.5px;
	font-weight: 400;
	letter-spacing: 0;
	text-transform: none;
}
.vm-field input[type="text"],
.vm-field input[type="email"],
.vm-field input[type="tel"],
.vm-field input[type="password"],
.vm-field input[type="date"],
.vm-field input[type="number"],
.vm-field input[type="datetime-local"],
.vm-field input[type="file"],
.vm-field select,
.vm-field textarea {
	width: 100%;
	min-height: 44px;
	padding: 10px 12px;
	border: 1px solid var(--vm-line);
	border-radius: var(--vm-radius);
	background: var(--vm-bg);
	color: var(--vm-ink);
	font-size: 15px;
}
.vm-field input[type="file"] { padding: 8px 12px; font-size: 14px; }
.vm-field input:focus, .vm-field select:focus, .vm-field textarea:focus {
	border-color: var(--vm-accent);
	outline: 2px solid var(--vm-primary-soft);
	outline-offset: 0;
}
.vm-field__hint { font-size: 12.5px; color: var(--vm-muted); margin-top: 6px; line-height: 1.5; }
.vm-field__error { font-size: 12.5px; color: var(--vm-red); margin-top: 6px; font-weight: 500; display: none; }
.vm-field.has-error input, .vm-field.has-error select, .vm-field.has-error textarea { border-color: var(--vm-red); }
.vm-field.has-error .vm-field__error { display: block; }
.vm-grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 0 14px; }

/* Notices and warnings: a hairline box with quiet text, never a coloured slab. */
.vm-alert {
	border: 1px solid var(--vm-line);
	border-radius: var(--vm-radius);
	padding: 12px 14px;
	font-size: 14px; line-height: 1.55;
	color: var(--vm-ink);
	margin-bottom: 16px;
}
.vm-alert--info { color: var(--vm-body); }
.vm-alert--ok { border-color: var(--vm-green); color: var(--vm-green); }
.vm-alert--warn { border-color: var(--vm-amber); color: var(--vm-amber); }
.vm-alert--error { border-color: var(--vm-red); color: var(--vm-red); }

.vm-spinner {
	width: 16px; height: 16px;
	border: 2px solid rgba(251, 250, 248, .4);
	border-top-color: #fbfaf8;
	border-radius: 50%;
	animation: vm-spin .7s linear infinite;
	display: none;
}
.vm-btn.is-busy .vm-spinner { display: block; }
@keyframes vm-spin { to { transform: rotate(360deg); } }

/* =========================================================================
   14. Account dashboard
   ========================================================================= */
.vm-dash { display: grid; grid-template-columns: 232px minmax(0, 1fr); gap: 28px; align-items: start; }
.vm-dash__nav { background: var(--vm-surface); border: 1px solid var(--vm-line); border-radius: var(--vm-radius); padding: 10px; position: sticky; top: 92px; }
.vm-dash__nav ul { list-style: none; margin: 0; padding: 0; }
.vm-dash__nav a {
	display: block; padding: 10px 14px; border-radius: 10px;
	color: var(--vm-body); font-weight: 600; font-size: .92rem;
}
.vm-dash__nav a:hover { background: var(--vm-bg-tint); color: var(--vm-ink); text-decoration: none; }
.vm-dash__nav .is-active > a { background: var(--vm-navy); color: #fff; }

.vm-cards-4 { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 16px; margin-bottom: 26px; }
/*
 * Label on top, number at the bottom.
 *
 * Both are <span>s, and an inline span ignores `margin-top` and simply sits on
 * the same line as its neighbour — so every card read "ACTIVE 1" in one run
 * instead of a caption over a figure. A column flex container blockifies them
 * and lets the auto top margin on the value push the number to the card's
 * bottom edge, which is what keeps the four cards looking deliberate when one
 * label wraps to two lines and the others do not.
 */
.vm-kpi {
	display: flex;
	flex-direction: column;
	background: var(--vm-surface); border: 1px solid var(--vm-line); border-radius: var(--vm-radius);
	padding: 18px; box-shadow: var(--vm-shadow-sm);
}
.vm-kpi__label { font-size: .8rem; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: var(--vm-muted); }
.vm-kpi__value { font-size: 1.7rem; font-weight: 700; color: var(--vm-ink); line-height: 1.15; margin-top: auto; padding-top: 6px; }

.vm-panel { background: var(--vm-surface); border: 1px solid var(--vm-line); border-radius: var(--vm-radius); box-shadow: var(--vm-shadow-sm); overflow: hidden; }
.vm-panel__head { padding: 18px 20px; border-bottom: 1px solid var(--vm-line); display: flex; align-items: center; justify-content: space-between; gap: 14px; flex-wrap: wrap; }
.vm-panel__head h2, .vm-panel__head h3 { margin: 0; font-size: 1.08rem; }
.vm-panel__body { padding: 20px; }
.vm-panel__body--flush { padding: 0; }

.vm-table { width: 100%; border-collapse: collapse; font-size: .92rem; }
.vm-table th, .vm-table td { text-align: left; padding: 13px 16px; border-bottom: 1px solid var(--vm-line); vertical-align: middle; }
.vm-table th { font-size: .76rem; letter-spacing: .06em; text-transform: uppercase; color: var(--vm-muted); background: var(--vm-bg); }
.vm-table tr:last-child td { border-bottom: 0; }
.vm-table td strong { color: var(--vm-ink); }
.vm-table__actions { display: flex; gap: 8px; flex-wrap: wrap; }
.vm-scroll-x { overflow-x: auto; }

.vm-status {
	display: inline-flex; align-items: center; gap: 6px;
	padding: 4px 11px; border-radius: var(--vm-radius-pill);
	font-size: .76rem; font-weight: 700; white-space: nowrap;
}
.vm-status--active { background: var(--vm-green-soft); color: #15803d; }
.vm-status--pending { background: var(--vm-amber-soft); color: var(--vm-amber); }
.vm-status--unverified { background: var(--vm-amber-soft); color: var(--vm-amber); }
.vm-status--verified { background: var(--vm-green-soft); color: #15803d; }
.vm-status--rejected { background: var(--vm-red-soft); color: #b91c1c; }
.vm-status--expired { background: #eef1f6; color: #55637d; }
.vm-status--cancelled { background: var(--vm-red-soft); color: #b91c1c; }
.vm-status--awaiting { background: var(--vm-purple-soft); color: #5b21b6; }

.vm-empty { text-align: center; padding: 46px 20px; color: var(--vm-muted); }
.vm-empty svg { width: 40px; height: 40px; color: var(--vm-line-strong); margin-bottom: 12px; }

.vm-detail-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 24px; }
.vm-detail { padding: 12px 0; border-bottom: 1px solid var(--vm-line); }
.vm-detail dt { font-size: .78rem; text-transform: uppercase; letter-spacing: .06em; color: var(--vm-muted); font-weight: 700; }
.vm-detail dd { margin: 4px 0 0; color: var(--vm-ink); font-weight: 600; word-break: break-word; }

/* WooCommerce notices / generic content */
.vm-content { background: var(--vm-surface); border: 1px solid var(--vm-line); border-radius: var(--vm-radius); padding: 28px; box-shadow: var(--vm-shadow-sm); }
.vm-content h1 { font-size: 1.8rem; }
.woocommerce-message, .woocommerce-info, .woocommerce-error {
	list-style: none; padding: 14px 18px; border-radius: var(--vm-radius-sm);
	border-left: 4px solid var(--vm-primary); background: var(--vm-surface);
	box-shadow: var(--vm-shadow-sm); margin: 0 0 20px;
}
.woocommerce-message { border-left-color: var(--vm-green); }
.woocommerce-error { border-left-color: var(--vm-red); }
.woocommerce-message::before, .woocommerce-info::before, .woocommerce-error::before { display: none; }
.vm-content .woocommerce-message, .vm-content .woocommerce-info { background: var(--vm-primary-soft); box-shadow: none; }

/*
 * A notice with an action button is a ROW, not a sentence.
 *
 * WooCommerce floats that button to the right from woocommerce-general
 * (`.woocommerce-info a.button { float: right }`), a stylesheet this theme
 * switches off. Without it the button becomes just another word in the
 * sentence, which breaks in two visible ways:
 *   1. the message text wraps around it, and the wrapped line returns to the
 *      far left — under the button — instead of staying beside it;
 *   2. a 12px vertical padding on an INLINE element does not grow its line box,
 *      so the button's pill printed 10px above and 8px below its own line and
 *      collided with the text next to it.
 *
 * A flex row restores the intent — message on the left, action on the right,
 * both vertically centred — and, unlike a float, needs no clearfix and does not
 * care whether the button is printed before or after the text (`order` decides).
 *
 * `flex-wrap: wrap` is not decoration, it is load-bearing. The message needs
 * ~525px and the button is a fixed 212px, so the two cannot share a line in a
 * 688px notice — and `nowrap` does not degrade gracefully: the text shrinks to
 * its min-content (a 65px column, 11 lines) and then the button still spills
 * 13-192px out of the notice between 720px and 1119px viewport, where the
 * account sidebar eats the width. Wrapping lets the message have the full line
 * and drops the button onto the next one, right-aligned via `margin-left: auto`
 * — so it lines up with the "View" button in the orders table below it.
 */
.woocommerce-message, .woocommerce-info {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 12px 18px;
}
.woocommerce-message a.button,
.woocommerce-info a.button {
	order: 2;                /* the button always ends up on the right */
	flex: 0 0 auto;
	display: inline-block;   /* contains the padding inside the line box */
	margin: 0 0 0 auto;
	max-width: 100%;         /* never wider than the notice, however narrow it gets */
}
.woocommerce-message > *, .woocommerce-info > * { min-width: 0; }

/*
 * On a phone, give the action the full width instead of a 212px button sitting
 * in the right corner — it is easier to hit.
 */
@media (max-width: 640px) {
	.woocommerce-message a.button,
	.woocommerce-info a.button { flex: 0 0 100%; margin-left: 0; text-align: center; }
}

/* =========================================================================
   15. Single product
   ========================================================================= */
.vm-feature-list { list-style: none; margin: 0 0 22px; padding: 0; display: grid; gap: 9px; }
.vm-feature-list li { display: flex; align-items: flex-start; gap: 9px; color: var(--vm-body); font-size: 14.5px; }
.vm-feature-list svg { width: 16px; height: 16px; flex: 0 0 16px; margin-top: 3px; color: var(--vm-accent); }

/*
 * Single product — image left, details right.
 *
 * WooCommerce's own template stacks a 900px-wide gallery ABOVE the summary, so
 * the title and price fall off the first screen and the page reads as an empty
 * grey box. This is a plain two-column grid: the media column is capped so the
 * image can never dominate, and the detail column reuses the home page card's
 * pieces (badges, tags, .vm-price, Subscribe + Details) so the plan behaves
 * identically wherever the customer meets it.
 *
 * These base rules MUST stay above section 15. The breakpoints below override
 * .vm-single with the same specificity, so a base rule declared after them
 * would silently win at every width and the layout would never stack.
 */
.vm-single {
	display: grid;
	grid-template-columns: minmax(0, 460px) minmax(0, 1fr);
	gap: clamp(22px, 4vw, 56px);
	align-items: start;
	margin-bottom: var(--vm-section-y);
}
.vm-single__media { min-width: 0; }

/* The same empty frame as the hero's, holding the plan's picture. */
.vm-single__frame {
	position: relative;
	display: grid;
	place-items: center;
	/*
	 * A band, for the same reason as the card's media area: the plan pictures
	 * are wide logos, and a 4:3 frame left one floating small in the middle.
	 */
	height: clamp(180px, 24vw, 300px);
	overflow: hidden;
	border: 1px solid var(--vm-line);
	border-radius: var(--vm-radius);
	background: var(--vm-surface);
}
.vm-single__img { width: 100%; height: 100%; object-fit: contain; display: block; padding: 24px; }
/* The ink band for a light logo, for the reason given beside .vm-card__media--ink. */
.vm-single__frame--ink { background: var(--vm-ink); }
.vm-single__glyph { color: var(--vm-muted); }
.vm-single__glyph svg { width: 56px; height: 56px; }
.vm-single__badge { position: absolute; top: 12px; left: 12px; }

.vm-single__thumbs { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 12px; }
.vm-single__thumb { width: 76px; height: 58px; overflow: hidden; border: 1px solid var(--vm-line); border-radius: var(--vm-radius); }
.vm-single__thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }

.vm-single__info { min-width: 0; }
.vm-single__title { font-size: 38px; line-height: 1.18; letter-spacing: -.015em; margin: 8px 0 12px; }
.vm-single__desc { color: var(--vm-body); font-size: 16px; }
.vm-single__desc p:last-child { margin-bottom: 0; }

.vm-single__buy {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: 16px;
	margin-top: 24px;
	padding-top: 20px;
	border-top: 1px solid var(--vm-line);
}
.vm-single__actions { display: flex; flex-wrap: wrap; gap: 10px; }
.vm-single__out { color: var(--vm-muted); margin: 0; }

/* WooCommerce's own single-product markup, for anything the theme does not render. */
.woocommerce div.product .product_title { font-size: 38px; letter-spacing: -.015em; margin-bottom: 10px; }
.woocommerce div.product div.images { border: 1px solid var(--vm-line); border-radius: var(--vm-radius); overflow: hidden; background: var(--vm-surface); }
.woocommerce div.product .woocommerce-product-details__short-description { color: var(--vm-body); }
.woocommerce div.product form.cart { margin: 0; }
.woocommerce .quantity input.qty { width: 84px; min-height: 44px; padding: 10px 12px; border: 1px solid var(--vm-line); border-radius: var(--vm-radius); background: var(--vm-bg); color: var(--vm-ink); }
.woocommerce div.product .product_meta { font-size: 13.5px; color: var(--vm-muted); border-top: 1px solid var(--vm-line); padding-top: 14px; margin-top: 18px; }
.woocommerce .woocommerce-tabs ul.tabs { padding: 0; margin: 0 0 22px; border-bottom: 1px solid var(--vm-line); }
.woocommerce .woocommerce-tabs ul.tabs li { background: transparent; border: 0; margin: 0 18px 0 0; }
.woocommerce .woocommerce-tabs ul.tabs li a { padding: 12px 0; color: var(--vm-muted); font-weight: 500; }
.woocommerce .woocommerce-tabs ul.tabs li.active a { color: var(--vm-accent); box-shadow: inset 0 -2px 0 var(--vm-accent); }
.woocommerce .woocommerce-tabs ul.tabs::before { display: none; }
.woocommerce #reviews #comments ol.commentlist li img.avatar { border-radius: 50%; }

/* Shop archive */
.woocommerce ul.products { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--vm-grid-gap); margin: 0; padding: 0; }
.woocommerce ul.products::before, .woocommerce ul.products::after { display: none; }
.woocommerce ul.products li.product { width: auto !important; margin: 0 !important; float: none !important; background: var(--vm-surface); border: 1px solid var(--vm-line); border-radius: var(--vm-card-radius); padding: 0 0 18px; overflow: hidden; }
.woocommerce ul.products li.product a img { margin: 0; border-radius: 0; }
.woocommerce ul.products li.product .woocommerce-loop-product__title { font-size: 17px; padding: 14px 18px 4px; }
.woocommerce ul.products li.product .price { padding: 0 18px; font-size: 24px; font-weight: 600; letter-spacing: -.015em; color: var(--vm-ink); }
.woocommerce ul.products li.product .button { margin: 12px 18px 0; }
.woocommerce .woocommerce-result-count, .woocommerce .woocommerce-ordering { margin: 0 0 20px; color: var(--vm-muted); }
.woocommerce .woocommerce-ordering select { min-height: 44px; padding: 10px 12px; border: 1px solid var(--vm-line); border-radius: var(--vm-radius); background: var(--vm-bg); color: var(--vm-ink); }
.woocommerce nav.woocommerce-pagination ul { border: 0; display: flex; gap: 4px; justify-content: center; margin-top: 28px; }
.woocommerce nav.woocommerce-pagination ul li { border: 0; }
.woocommerce nav.woocommerce-pagination ul li a,
.woocommerce nav.woocommerce-pagination ul li span { min-width: 44px; height: 44px; display: grid; place-items: center; border: 1px solid var(--vm-line); border-radius: var(--vm-radius); color: var(--vm-body); font-weight: 400; }
.woocommerce nav.woocommerce-pagination ul li span.current { border-color: var(--vm-accent); color: var(--vm-accent); font-weight: 500; background: transparent; }

/* =========================================================================
   16. Responsive

   Breakpoints: 1280 (table stacking), 1080 (small laptop), 900 (tablet and
   phone), 768 (phone), 640 (small phone). Three rules hold everywhere below:
   no page scrolls sideways, nothing is clipped by a container, and every
   tappable control is at least 44px tall.
   ========================================================================= */

/*
 * --- Tables stack into cards ---------------------------------------------
 * WooCommerce normally ships woocommerce-smallscreen to do this, but the theme
 * dequeues that stylesheet (see vpnmarket_dequeue_wc_styles), so the theme has
 * to provide it. Each row becomes a card and every cell is prefixed with its
 * column name, read from the data-title attribute WooCommerce already prints.
 *
 * 1280, not 900: these tables cannot shrink below their own content. The
 * subscriptions table has seven columns and the orders table measures a 498px
 * minimum, so wherever the content column falls under ~500px the table sticks
 * out of its card (168px out at 1081px, 48px at 1201px, measured live). Below
 * this breakpoint a table is a stack of cards, which always fits, so the number
 * only has to be high enough to cover the narrow window — and 1280 is the first
 * round width where the content column is comfortably wider than 498px.
 */
@media (max-width: 1280px) {
	/*
	 * display:block on the <table> itself is required. Leaving it as
	 * display:table while its thead/tbody/tr become blocks makes the table size
	 * to its content instead of its container, so every row came out ~100px too
	 * narrow and the values looked cramped and half-cut.
	 */
	.woocommerce table.shop_table_responsive,
	.vm-table--stack { display: block; width: 100%; border: 0; }

	.woocommerce table.shop_table_responsive thead,
	.vm-table--stack thead { display: none; }

	.woocommerce table.shop_table_responsive tbody,
	.vm-table--stack tbody { display: block; }

	.woocommerce table.shop_table_responsive tr,
	.vm-table--stack tr {
		display: block;
		background: var(--vm-surface);
		border: 1px solid var(--vm-line);
		border-radius: var(--vm-radius);
		margin-bottom: 12px;
		overflow: hidden;
	}
	.woocommerce table.shop_table_responsive tr:last-child,
	.vm-table--stack tr:last-child { margin-bottom: 0; }

	.woocommerce table.shop_table_responsive th,
	.woocommerce table.shop_table_responsive td,
	.vm-table--stack th,
	.vm-table--stack td {
		display: flex;
		align-items: baseline;
		justify-content: space-between;
		gap: 14px;
		width: auto;
		padding: 11px 15px;
		border-bottom: 1px solid var(--vm-line);
		text-align: right;
	}
	.woocommerce table.shop_table_responsive th:last-child,
	.woocommerce table.shop_table_responsive td:last-child,
	.vm-table--stack th:last-child,
	.vm-table--stack td:last-child { border-bottom: 0; }

	.woocommerce table.shop_table_responsive th::before,
	.woocommerce table.shop_table_responsive td::before,
	.vm-table--stack th::before,
	.vm-table--stack td::before {
		content: attr(data-title);
		flex: 0 0 auto;
		font-size: .72rem;
		font-weight: 700;
		letter-spacing: .07em;
		text-transform: uppercase;
		color: var(--vm-muted);
		text-align: left;
	}
	.woocommerce table.shop_table_responsive th[data-title=""],
	.woocommerce table.shop_table_responsive td[data-title=""],
	.vm-table--stack th[data-title=""],
	.vm-table--stack td[data-title=""] { justify-content: flex-end; }
	.woocommerce table.shop_table_responsive th[data-title=""]::before,
	.woocommerce table.shop_table_responsive td[data-title=""]::before,
	.vm-table--stack th[data-title=""]::before,
	.vm-table--stack td[data-title=""]::before { display: none; }
}

/* --- Small laptops: 3- and 4-up grids become 2-up ------------------------ */
@media (max-width: 1080px) {
	/*
	 * The plan grid carries its column count as an INLINE custom property
	 * (style="--vm-cols:N") because the shop owner chooses it in the Customizer.
	 * An inline custom property outranks any media query, so writing
	 * --vm-cols here would do nothing at all. Re-declare the property that
	 * actually consumes it instead.
	 */
	.vm-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }

	.vm-cards-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
	.vm-footer__top { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 32px; }

	/* Single product: shrink the media column so the details keep their room. */
	.vm-single { grid-template-columns: minmax(0, 360px) minmax(0, 1fr); }
}

/* --- Tablet and phone ---------------------------------------------------- */
@media (max-width: 900px) {
	/*
	 * Hero, top to bottom: the badge, the headline, the lead and the one button.
	 * The picture slot is desktop-only now (see .vm-hero__visual below), so there
	 * is no frame to size here any more.
	 *
	 * Equal top and bottom. The owner spotted that the hero sat 26px from the top
	 * of the section but only 6px from the plans band below it, which read as the
	 * copy being shoved into the next section. The desktop rule keeps its 44/22 --
	 * the band's own 44px of top padding makes up the difference there -- but on a
	 * phone the two edges are what the eye compares.
	 */
	.vm-hero { padding-block: 26px; }
	.vm-hero__grid { grid-template-columns: minmax(0, 1fr); gap: 22px; }
	/*
	 * The hero picture is desktop-only.
	 *
	 * On a phone it came first -- the design put it above the words -- which
	 * pushes the headline and the button below the fold. The owner wants the hero
	 * to open with the words, so the picture is dropped here and only here; on a
	 * desktop it still fills the right-hand column. The `order: -1` and the 16:9
	 * frame that existed to make it lead on a phone went with it.
	 */
	.vm-hero__visual { display: none; }
	.vm-hero__top { margin-bottom: 18px; }
	.vm-hero__title { font-size: 28px; max-width: 22ch; }
	.vm-hero__text { font-size: 16px; }

	/* Every heading steps down with the hero, so the page keeps one voice. */
	.vm-section-head h1 { font-size: 28px; }
	.vm-section-head h2 { font-size: 24px; }

	/* Header: the inline nav gives way to the burger. */
	.vm-nav { display: none; }
	/*
	 * The menu and the search drawer float over the page instead of sitting in the
	 * header's flow.
	 *
	 * As a block they were part of the document, so opening one pushed everything
	 * below it down and the content jumped -- which is exactly what the owner
	 * reported. Absolutely positioned under the header they affect no other
	 * element at all. `top: 100%` needs a containing block: the header is
	 * `position: sticky`, which is already one, and the static variant gets
	 * `position: relative` just below.
	 */
	.vm-header--static { position: relative; }
	.vm-mobile-nav,
	.vm-searchbar {
		position: absolute;
		top: 100%;
		left: 0;
		right: 0;
		z-index: 70;
		max-height: 100vh;                            /* fallback for a browser without dvh */
		max-height: calc(100dvh - 64px);              /* the bar is at least 60px tall */
		overflow-y: auto;
		box-shadow: 0 16px 32px rgba(26, 26, 25, .10);
	}
	/* While a panel is open the page behind it is held still, so the content
	   cannot scroll under the panel. */
	body.vm-panel-open { overflow: hidden; }

	.vm-burger { display: grid; }

	/* Single product: one column, image on top, details below, full-width buttons. */
	.vm-single { grid-template-columns: minmax(0, 1fr); }
	.vm-single__frame { aspect-ratio: 16 / 10; }
	.vm-single__title { font-size: 28px; }
	.vm-single__buy { flex-direction: column; align-items: stretch; }
	.vm-single__actions { flex-direction: column; }
	.vm-single__actions .vm-btn { justify-content: center; }

	/* Account dashboard: one column, and the navigation becomes a scrollable strip. */
	.vm-dash { grid-template-columns: 1fr; }
	.vm-dash__nav { position: static; }
	.vm-dash__nav ul { display: flex; gap: 6px; overflow-x: auto; }
	.vm-dash__nav a { white-space: nowrap; }

	/* Account forms and the plugin's dashboard detail grid go one column. */
	.vm-grid-2, .vm-detail-grid { grid-template-columns: 1fr; }
}

/* --- Phone: the promise boxes and the facts strip go one per row ---------- */
@media (max-width: 768px) {
	.vm-promises { grid-template-columns: 1fr; }
}

/* --- Small phone --------------------------------------------------------- */
@media (max-width: 640px) {
	.vm-grid { grid-template-columns: 1fr; }

	/*
	 * The four subscription counters stay a 2x2 grid on a phone. One per row
	 * cost four rows of screen for four single digits, and stacked they read as
	 * a list rather than a summary. Two columns of ~157px still hold the longest
	 * label ("Awaiting activation") on two lines, so the card only needs its
	 * padding trimmed.
	 */
	.vm-cards-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
	.vm-kpi { padding: 13px 13px 11px; }
	.vm-kpi__label { font-size: .72rem; letter-spacing: .03em; }
	.vm-kpi__value { font-size: 1.5rem; }
	.vm-footer__top { grid-template-columns: 1fr; gap: 28px; }

	/*
	 * Header: the bar only has room for the logo, the search button, the sign-in
	 * link and the burger. The brand name has to be allowed to give way, or a
	 * long site title pushes the burger off the right edge.
	 */
	.vm-header__inner { gap: 8px; min-height: 56px; }
	.vm-brand { min-width: 0; }
	.vm-brand__name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
	.vm-header__actions { gap: 4px; min-width: 0; }

	/* The price is the biggest number on a phone card, so step it down with the type. */
	.vm-price__now { font-size: 22px; }

	/* Pop-ups fill the screen so nothing is squeezed. */
	.vm-modal { padding: 0; align-items: stretch; }
	/* The overlay has no padding on a phone, so the panel gets the whole window
	   (the base rule subtracts the 20px padding it does not have here). */
	.vm-modal__panel { border: 0; border-radius: 0; margin: 0; min-height: 100%; max-width: none; max-height: 100vh; max-height: 100dvh; }
	.vm-modal__head { padding: 8px 8px 8px 16px; }
	.vm-modal__body { padding: 18px 16px; }
	.vm-modal__foot { padding: 12px 16px; }
	.vm-modal__foot .vm-btn { flex: 1 1 100%; justify-content: center; }
	.vm-modal__foot .vm-total { margin-left: 0; text-align: left; }

	/* Plan details popup: stack the picture above the text, specs to one column. */
	.vm-details__top { flex-direction: column; gap: 14px; }
	.vm-details__specs { grid-template-columns: 1fr; }

	/* Tables keep the stacked layout, just tighter. */
	.vm-table th, .vm-table td { padding: 10px 13px; }

	/*
	 * WooCommerce's own checkboxes are tiny. (The show/hide password toggle is
	 * sized in section 17 instead — its base rule is declared there, so an
	 * override up here would silently lose.)
	 */
	.woocommerce form .form-row input[type="checkbox"],
	.woocommerce-form__input-checkbox { width: 20px; height: 20px; }
}

/* =========================================================================
   17. My Account
   ========================================================================= */
.woocommerce-account .woocommerce { display: grid; grid-template-columns: 232px minmax(0, 1fr); gap: 28px; align-items: start; }
/*
 * That grid only makes sense when the navigation is there to fill its first
 * column. Logged out there is no navigation, so auto-placement put the notices
 * wrapper in the 232px slot, pushed the "Login" heading into the content column
 * beside it, and dropped the form itself into the narrow slot — a 232px login
 * card with an orphaned heading and ~860px of empty card next to it. One
 * centred column instead; this covers login, lost-password and reset-password.
 */
.woocommerce-account .woocommerce:not(:has(.woocommerce-MyAccount-navigation)) { display: block; max-width: 460px; margin: 0 auto; }
/* Login and Register are two cards side by side, so that state gets more room. */
.woocommerce-account .woocommerce:has(.u-columns.col2-set) { max-width: 880px; }
/*
 * WooCommerce lays login and register out as floats (`.u-column1` / `.u-column2`
 * inside `.u-columns.col2-set`) and that float rule lives in woocommerce-general,
 * so with registration switched on the two cards arrived stacked in one narrow
 * column. Grid instead, which needs no clearfix and stacks on its own.
 */
.woocommerce-account .u-columns.col2-set { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 24px; align-items: start; }
.woocommerce-account .u-columns.col2-set h2 { font-size: 1.3rem; margin: 0 0 16px; }
/* The register form's own note and the privacy line, which the theme never styled. */
.woocommerce-account .woocommerce-form-register > p:not(.form-row),
.woocommerce-account .woocommerce-privacy-policy-text p { color: var(--vm-body); font-size: .88rem; margin: 0 0 14px; }
/* The tab bar is a phone affordance — above the breakpoint both cards are shown. */
.woocommerce-account .vm-tabs--auth { display: none; }
@media (max-width: 860px) {
	.woocommerce-account .u-columns.col2-set { grid-template-columns: 1fr; }
	/*
	 * One card at a time, chosen by the tab bar. The choice lives as a class on
	 * the grid rather than as `hidden` on a card, so widening past the breakpoint
	 * simply stops this rule matching and both cards return.
	 */
	.woocommerce-account .vm-tabs--auth { display: flex; }
	.woocommerce-account .u-columns.col2-set.vm-auth--login > .u-column2,
	.woocommerce-account .u-columns.col2-set.vm-auth--register > .u-column1 { display: none; }
	/* The active tab already names the form; a second heading just adds height. */
	.woocommerce-account .u-columns.col2-set h2 { display: none; }
}
.woocommerce-account .woocommerce-MyAccount-navigation { background: var(--vm-surface); border: 1px solid var(--vm-line); border-radius: var(--vm-radius); padding: 10px; box-shadow: var(--vm-shadow-sm); }
.woocommerce-account .woocommerce-MyAccount-navigation ul { list-style: none; margin: 0; padding: 0; }
.woocommerce-account .woocommerce-MyAccount-navigation li a { display: block; padding: 10px 14px; border-radius: 10px; color: var(--vm-body); font-weight: 600; font-size: .92rem; }
.woocommerce-account .woocommerce-MyAccount-navigation li a:hover { background: var(--vm-bg-tint); color: var(--vm-ink); text-decoration: none; }
.woocommerce-account .woocommerce-MyAccount-navigation li.is-active a { background: var(--vm-navy); color: #fff; }
.woocommerce-account .woocommerce-MyAccount-content { background: var(--vm-surface); border: 1px solid var(--vm-line); border-radius: var(--vm-radius); padding: 24px; box-shadow: var(--vm-shadow-sm); min-width: 0; }
.woocommerce-account .woocommerce-MyAccount-content h2 { font-size: 1.3rem; }
.woocommerce-account .woocommerce-MyAccount-content .vm-panel { box-shadow: none; }
/*
 * .vm-panel__body--flush means "no inner padding" — it exists so a table can run
 * edge to edge inside its panel. Without the :not() the account rule below
 * re-added 18px and the table lost 36px of width on every phone.
 */
.woocommerce-account .woocommerce-MyAccount-content .vm-panel .vm-panel__body:not(.vm-panel__body--flush) { padding: 18px; }
.woocommerce-account .woocommerce-form-login,
.woocommerce-account .woocommerce-form-register { border: 1px solid var(--vm-line); border-radius: var(--vm-radius); padding: 22px; background: var(--vm-surface); }
/* WooCommerce puts "Remember me" and "Log in" on one line and relies on
   woocommerce-general for the gap between them. */
.woocommerce-form-login__rememberme { margin-right: 14px; }
.woocommerce form .form-row input.input-text,
.woocommerce form .form-row textarea,
.woocommerce form .form-row select { width: 100%; padding: 11px 14px; border: 1px solid var(--vm-line-strong); border-radius: var(--vm-radius-sm); background: var(--vm-bg); }
/*
 * Label above the field.
 *
 * `label { display: block }` is WooCommerce's own default and it is declared in
 * woocommerce-general, which this theme switches off — so every label stayed
 * inline and rendered to the LEFT of its input (measured: label right edge 690,
 * input left edge 695, on one 49.6px line). A form is much easier to scan with
 * the caption above the box, and the password rows looked worst because the
 * three labels are long sentences.
 *
 * Checkbox labels are excluded: those wrap their own checkbox and a block
 * display there would stack the box above its text.
 */
.woocommerce form .form-row label { display: block; font-weight: 600; color: var(--vm-ink); font-size: .88rem; margin-bottom: 6px; }
.woocommerce form .form-row label.checkbox,
.woocommerce form .form-row label.woocommerce-form__label-for-checkbox { display: inline-block; margin-bottom: 0; }

/*
 * The "Password change" group.
 *
 * Nothing styled it, so it rendered with the browser's default 1px groove border
 * and no margins — which also meant the paragraph holding "Save changes" sat
 * flush against its bottom border (measured gap: exactly 0px). Give the group a
 * real border, padding and a bottom gap.
 */
.woocommerce form fieldset {
	border: 1px solid var(--vm-line);
	border-radius: var(--vm-radius-sm);
	padding: 16px 18px 18px;
	margin: 0 0 22px;
}
.woocommerce form fieldset legend {
	padding: 0 8px;
	margin-left: 4px;
	font-weight: 600;
	color: var(--vm-ink);
	font-size: .88rem;
}

/*
 * Account details: details on the left, password group on the right.
 *
 * The form was one 724px column of 264px inputs, so two thirds of the card was
 * empty. The password group is the natural thing to move across: it is a
 * self-contained box, and its height lands within a few pixels of the four
 * detail rows, so the two columns come out level.
 *
 * The condition here is "is there room in the CARD", not "how wide is the
 * window" — the Hostinger Agent widget takes 360px off the page for a logged-in
 * admin, so one viewport width yields a 774px card in the visitor layout and a
 * 414px card in the admin one. A container query asks the element that actually
 * knows, and degrades to the single column if unsupported.
 */
.woocommerce-account .woocommerce-MyAccount-content { container-type: inline-size; }

@container (min-width: 620px) {
	.woocommerce form.woocommerce-EditAccountForm {
		display: grid;
		grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
		column-gap: 30px;
	}
	/* No floats in a grid — these clearfix divs would be empty grid items. */
	.woocommerce form.woocommerce-EditAccountForm > .clear { display: none; }
	.woocommerce form.woocommerce-EditAccountForm > .form-row { grid-column: 1; }
	/*
	 * span 4 = the four detail rows above it, and the default `stretch` makes the
	 * box the same height as that column rather than leaving a gap under it.
	 */
	.woocommerce form.woocommerce-EditAccountForm > fieldset { grid-column: 2; grid-row: 1 / span 4; margin: 0; }
	/*
	 * The submit row is a bare <p> with no class of its own, so match it as the
	 * last paragraph — `.form-row:last-child` silently never fired.
	 */
	.woocommerce form.woocommerce-EditAccountForm > p:last-of-type { grid-column: 1 / -1; margin-top: 22px; }
}

/*
 * Show / hide password toggle.
 *
 * WooCommerce draws the eye with a \e010 glyph from its own icon font, and that
 * @font-face is declared in woocommerce-general — the stylesheet this theme
 * switches off. So the <button> arrived with no icon AND no styling at all:
 * measured at a 1500px viewport it was 16x6px of default user-agent button
 * chrome (#efefef background, 2px outset border) — the "small grey dash" sitting
 * at the end of every password field. Its wrapper was `display: inline` with the
 * button landing *after* the input instead of over it, and the input reserved no
 * room for it.
 *
 * The icon is an inline SVG background instead: no font file to load, no extra
 * request, and it cannot fall back to a missing glyph. The two states are driven
 * by `display-password`, the class WooCommerce's own JS toggles — verified live:
 * a click adds it and switches the input to type=text.
 */
.woocommerce form .password-input { position: relative; }
/*
 * The input needs room for the icon, and this must out-specify the
 * `.woocommerce form .form-row input.input-text` padding rule above — a
 * `.woocommerce form .password-input input` selector (0,2,2) loses to it (0,3,1)
 * and the padding silently stayed at 14px, i.e. typed dots ran under the eye.
 *
 * No `display` change on the wrapper: left inline, its line box is exactly as
 * wide as the input, so `right: 5px` lands on the input's right edge. Making it
 * `display: block` was tried and put the eye 423px away at desktop widths — the
 * wrapper spanned the whole form row while the input stayed 264px. And leaving
 * it inline keeps the phone behaviour where `input { width: 100% }` resolves
 * against the form row.
 */
.woocommerce form .form-row .password-input input.input-text { padding-right: 46px; }
.woocommerce form .show-password-input {
	position: absolute; top: 50%; right: 5px; transform: translateY(-50%);
	width: 34px; height: 34px; min-width: 0; padding: 0; margin: 0;
	display: grid; place-items: center;
	background: transparent; border: 0; box-shadow: none;
	color: var(--vm-body); opacity: .7; cursor: pointer;
}
.woocommerce form .show-password-input:hover { opacity: 1; background: transparent; }
.woocommerce form .show-password-input::after {
	content: ""; display: block; width: 20px; height: 20px;
	background-repeat: no-repeat; background-position: center; background-size: 20px 20px;
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2346536e' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2.5 12S6 5.5 12 5.5 21.5 12 21.5 12 18 18.5 12 18.5 2.5 12 2.5 12Z'/%3E%3Ccircle cx='12' cy='12' r='3'/%3E%3C/svg%3E");
}
.woocommerce form .show-password-input.display-password::after {
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2346536e' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M10.6 5.7A10 10 0 0 1 12 5.5c6 0 9.5 6.5 9.5 6.5a18.4 18.4 0 0 1-2.6 3.6'/%3E%3Cpath d='M17.9 17.6A10 10 0 0 1 12 18.5c-6 0-9.5-6.5-9.5-6.5a18.4 18.4 0 0 1 4.9-5.6'/%3E%3Cpath d='M9.8 9.8a3.1 3.1 0 0 0 4.4 4.4'/%3E%3Cpath d='M3.2 3.2l19.6 19.6'/%3E%3C/svg%3E");
}
@media (max-width: 640px) {
	/* 34px is under the 44px touch guideline; this is a small control, so 40. */
	.woocommerce form .show-password-input { width: 40px; height: 40px; right: 3px; }
	.woocommerce form .form-row .password-input input.input-text { padding-right: 52px; }
}
.woocommerce button.button, .woocommerce a.button, .woocommerce input.button {
	background: var(--vm-primary); color: #fff; border-radius: var(--vm-btn-radius);
	padding: 12px 20px; font-weight: 600; border: 0;
}
.woocommerce button.button:hover, .woocommerce a.button:hover { background: var(--vm-primary-dark); color: #fff; }
/*
 * My Account -> Orders: the LIST of orders.
 *
 * This table has no template of its own in the theme, so it renders through
 * WooCommerce's own `myaccount/orders.php` — and, like the single-order view
 * above, it arrived unstyled because the theme switches WooCommerce's
 * stylesheets off. Measured on the live page it came out 595px wide inside a
 * 774px card: a shrink-to-fit table, i.e. 154px of dead white space to the
 * right of the "View" button, with no header background and no row rules.
 *
 * `width: 100%` is the whole fix for the width — woocommerce-general is where
 * WooCommerce sets `.shop_table { width: 100% }`, so this restores it. The
 * Action column is then right-aligned so the button ends flush with the card
 * edge instead of leaving a gap after itself inside a wider column.
 */
.woocommerce-orders-table {
	width: 100%;
	border-collapse: collapse;
	background: var(--vm-surface);
}
.woocommerce-orders-table th,
.woocommerce-orders-table td {
	padding: 12px 16px;
	text-align: left;
	vertical-align: middle;
	border-bottom: 1px solid var(--vm-line);
}
.woocommerce-orders-table thead th {
	background: var(--vm-surface);
	font-size: .8rem;
	letter-spacing: .05em;
	text-transform: uppercase;
	color: var(--vm-muted);
}
.woocommerce-orders-table tbody tr:last-child th,
.woocommerce-orders-table tbody tr:last-child td { border-bottom: 0; }
.woocommerce-orders-table th.woocommerce-orders-table__header-order-actions,
.woocommerce-orders-table td.woocommerce-orders-table__cell-order-actions { text-align: right; }
/* An inline anchor's padding does not grow its cell — contain it. */
.woocommerce-orders-table a.button { display: inline-block; }
.woocommerce .woocommerce-MyAccount-content p:last-child { margin-bottom: 0; }

/*
 * Customer order view (My account -> Orders -> an order).
 *
 * The theme switches WooCommerce's own stylesheets off, and nothing replaced
 * them for this page, so it arrived unstyled: an unruled table with 1px cell
 * padding, and an "Order again" button that spilled 8px out of its paragraph
 * and printed on top of the "Billing address" heading.
 *
 * The button fix is the `display: inline-block`: an inline anchor's vertical
 * padding does NOT grow its parent block, so the 12px padding above and below
 * hung outside the paragraph and collided with the next section.
 */
.woocommerce-order-details,
.woocommerce-customer-details { margin-top: 28px; }

.woocommerce-order-details__title,
.woocommerce-customer-details .woocommerce-column__title {
	margin: 0 0 12px;
	font-size: 1.15rem;
	color: var(--vm-ink);
}

.woocommerce-table--order-details {
	width: 100%;
	border-collapse: collapse;
	background: var(--vm-surface);
	border: 1px solid var(--vm-line);
	border-radius: var(--vm-radius);
	overflow: hidden;
}
.woocommerce-table--order-details th,
.woocommerce-table--order-details td {
	padding: 12px 16px;
	text-align: left;
	vertical-align: top;
	border-bottom: 1px solid var(--vm-line);
}
.woocommerce-table--order-details thead th {
	background: var(--vm-surface);
	font-size: .8rem;
	letter-spacing: .05em;
	text-transform: uppercase;
	color: var(--vm-muted);
}
.woocommerce-table--order-details tbody tr:last-child td,
.woocommerce-table--order-details tfoot tr:last-child th,
.woocommerce-table--order-details tfoot tr:last-child td { border-bottom: 0; }
.woocommerce-table--order-details tfoot th { color: var(--vm-muted); font-weight: 600; }
.woocommerce-table--order-details .product-quantity { color: var(--vm-muted); font-weight: 600; }

.order-again { margin: 20px 0 0; }
.order-again .button { display: inline-block; }

.woocommerce-customer-details address {
	font-style: normal;
	line-height: 1.75;
	color: var(--vm-body);
	background: var(--vm-surface);
	border: 1px solid var(--vm-line);
	border-radius: var(--vm-radius);
	padding: 16px 18px;
}
.woocommerce-customer-details address p { margin: 0; }

/* The "placed on ... and is currently ..." sentence highlights three values. */
.woocommerce-MyAccount-content mark {
	background: var(--vm-primary-soft);
	color: var(--vm-primary);
	font-weight: 700;
	padding: 1px 7px;
	border-radius: 6px;
}

@media (max-width: 900px) {
	.woocommerce-account .woocommerce { grid-template-columns: 1fr; }
	.woocommerce ul.products { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 640px) {
	.woocommerce ul.products { grid-template-columns: 1fr; }

	/*
	 * Account pages nest the content inside three padded cards in a row:
	 * .vm-content (28px) + .woocommerce-MyAccount-content (24px) + .vm-panel__body
	 * (18px). That is 140px of the 358px a phone has, leaving ~210px for the
	 * actual content — narrow enough that the subscriptions table looked cramped
	 * and half cut off. Tighten every layer.
	 *
	 * This block lives AFTER section 17 on purpose: the base rules it overrides
	 * are declared in section 17, so the same selectors earlier in the file lose.
	 */
	.vm-content { padding: 16px; }
	.vm-panel__body { padding: 16px; }
	.vm-panel__head { padding: 14px 16px; }
	.woocommerce-account .woocommerce-MyAccount-content { padding: 14px; }
	.woocommerce-account .woocommerce-MyAccount-content .vm-panel .vm-panel__body:not(.vm-panel__body--flush) { padding: 14px; }
	.woocommerce-account .woocommerce-form-login,
	.woocommerce-account .woocommerce-form-register { padding: 18px; }

	/* Forms fill the screen so fields are not half width. */
	.woocommerce form .form-row input.input-text,
	.woocommerce form .form-row textarea,
	.woocommerce form .form-row select { width: 100%; }

	/*
	 * The order table is a plain two-column table with a Subtotal/Total
	 * footer, so it only needs tighter padding on a phone — it fits without
	 * being restacked.
	 */
	.woocommerce-table--order-details th,
	.woocommerce-table--order-details td { padding: 10px 12px; }
	.woocommerce-customer-details address { padding: 14px; }
}


/* =========================================================================
   18. Admin pills (order screens)
   ========================================================================= */
.vm-pill {
	display: inline-block; padding: 2px 9px; border-radius: 999px;
	font-size: 11px; font-weight: 700; line-height: 1.7;
	background: #eef1f6; color: #46536e;
}
.vm-pill--verified, .vm-pill--active { background: #e7f7ee; color: #15803d; }
.vm-pill--unverified, .vm-pill--pending { background: #fdf3e3; color: #b45309; }
.vm-pill--rejected, .vm-pill--cancelled { background: #fdecec; color: #b91c1c; }
.vm-pill--expired { background: #eef1f6; color: #55637d; }
.vm-admin-box p { margin: 0 0 12px; }

/* =========================================================================
   19. Testimonial wall
   -------------------------------------------------------------------------
   Three columns of quote cards drifting upward behind a soft fade, as in the
   design. Each track holds its quotes twice; the second copy exists only so the
   loop has no gap. The drift itself is JS (assets/js/theme.js) so that hand
   scrolling, hovering and prefers-reduced-motion all behave.
   ========================================================================= */
.vm-wall {
	display: flex; justify-content: center; gap: 20px; margin-top: 22px;
	max-height: 620px; overflow: hidden;
	-webkit-mask-image: linear-gradient(to bottom, transparent, #000 20%, #000 80%, transparent);
	mask-image: linear-gradient(to bottom, transparent, #000 20%, #000 80%, transparent);
}
.vm-wall__col {
	/*
	 * Equal columns that fill the container. A fixed 330px cap came from the
	 * mockup, which was drawn for a 1120px page: once the container went to 1320
	 * the three columns stayed 330 wide and the wall sat centred with a dead
	 * margin down each side. They now share the row instead.
	 */
	flex: 1 1 0;
	min-width: 0;
	height: 620px; overflow: hidden;
	scrollbar-width: none; -ms-overflow-style: none;
}
.vm-wall__col::-webkit-scrollbar { display: none; }
.vm-wall__col:focus-visible { outline: 2px solid var(--vm-primary); outline-offset: 4px; }
.vm-wall__track {
	display: flex; flex-direction: column;
	/*
	 * The drift is a transform, not a scroll. Scrolling looks the same but the
	 * browser quantises a scroll offset to whole pixels: a 0.8px step and a 0.6px
	 * step both become 1px per frame, so every column ended up at exactly 60px/s
	 * and the wall moved as one block. A transform keeps the fraction, so the
	 * columns drift at their own speeds as the design intends.
	 *
	 * -50% is exactly one copy of the quotes -- see the margin-bottom on .vm-tcard,
	 * which makes the two halves add up evenly -- so the loop has no visible jump.
	 */
	animation: vm-wall-drift var(--dur, 16s) linear infinite;
	will-change: transform;
}
@keyframes vm-wall-drift { from { transform: translateY(0); } to { transform: translateY(-50%); } }
/* Stop for a reader who is looking at one column, or has asked for less motion. */
.vm-wall__col:hover .vm-wall__track,
.vm-wall__col:focus-within .vm-wall__track { animation-play-state: paused; }
@media (prefers-reduced-motion: reduce) { .vm-wall__track { animation: none; } }
/* One column on a phone, two from 768, three from 1024: the design's steps. */
.vm-wall__col:nth-child(2), .vm-wall__col:nth-child(3) { display: none; }

.vm-tcard {
	background: var(--vm-surface); border: 1px solid var(--vm-line); border-radius: var(--vm-card-radius);
	padding: 20px; display: flex; flex-direction: column; gap: 14px;
	/* Space between cards lives here rather than on the track's `gap`, so the two
	   copies in a track are exactly half its height and -50% lands seamlessly. */
	margin-bottom: 20px;
}
.vm-tcard .vm-stars { justify-content: flex-start; }
.vm-tcard__text { margin: 0; font-size: 14.5px; line-height: 1.6; color: var(--vm-body); }
.vm-tcard__who { display: flex; align-items: center; gap: 10px; margin-top: auto; }
.vm-tcard__mark {
	width: 36px; height: 36px; flex: 0 0 auto;
	border: 1px solid var(--vm-line); border-radius: 50%;
	display: flex; align-items: center; justify-content: center;
	font-size: 13.5px; color: var(--vm-ink);
}
.vm-tcard__name { font-size: 14.5px; color: var(--vm-ink); font-weight: 500; line-height: 1.35; }
.vm-tcard__role { font-size: 13px; color: var(--vm-muted); line-height: 1.35; }
/* A customer photo fills the circle; without one the initial stays. */
.vm-tcard__mark img { width: 100%; height: 100%; object-fit: cover; border-radius: 50%; display: block; }

@media (min-width: 768px) { .vm-wall__col:nth-child(2) { display: block; } }
@media (min-width: 1024px) { .vm-wall__col:nth-child(3) { display: block; } }

/* On a phone the wall is a plain list: one column, no fade, nothing drifting,
   and the looping copy hidden so no quote appears twice. */
@media (max-width: 767px) {
	.vm-wall {
		max-height: none; overflow: visible; flex-direction: column; align-items: center;
		/*
		 * No gap here: the cards carry their own 20px bottom margin, and the wall's
		 * own gap added another 20 on top of it at every column boundary. Measured
		 * on a phone the spacing ran 20, 20, 40, 20, 20, 40 -- the 40s were exactly
		 * where one column ended and the next began.
		 */
		gap: 0;
		-webkit-mask-image: none; mask-image: none;
	}
	/* Stacked, so the columns must not try to share a row's width: `flex: 1 1 0`
	   from the base rule would set a zero height basis in a column. */
	.vm-wall__col { flex: 0 0 auto; height: auto; overflow: visible; max-width: none; }
	/* All the quotes, stacked. Hiding columns 2 and 3 here (as the design does with
	   its three placeholder cards) would hide two thirds of the real testimonials. */
	.vm-wall__col:nth-child(2), .vm-wall__col:nth-child(3) { display: block; }
	.vm-wall__track { animation: none; }
	.vm-tcard--dupe { display: none; }
}

/* --- Phone corrections ---------------------------------------------------
 * Last in the file on purpose: these have to win over the blocks above, and
 * they are the rules the owner's phone reports are about.
 * ========================================================================= */
@media (max-width: 640px) {
	/*
	 * The copyright is the last thing on the page. It sat in 13px muted grey with
	 * ~10px under it, so it read as missing. Readable size, the ink colour, and a
	 * normal amount of room underneath -- the first attempt over-corrected with
	 * 84px to clear the chat bubble, which left a band of empty page instead. The
	 * bubble floats over the right-hand corner, and this line is short and
	 * left-aligned, so it does not need clearing at all.
	 */
	.vm-footer__bottom {
		flex-direction: column;
		align-items: flex-start;
		gap: 12px;
		padding-block: 20px 24px;
		font-size: 16px;
		color: var(--vm-body);
	}
	.vm-footer__bottom > span { color: var(--vm-ink); }
	.vm-footer__legal { font-size: 14px; gap: 16px; }
}
