/**
 * Hosting Configurator — plan-tile switcher (Web/Cloud/WordPress/Managed WordPress) + a real
 * plans table (one row per product) with a shared billing-term switcher above it. EXTRACTED
 * (2026-08-13) out of custom.css into its own shared stylesheet so it renders identically on both
 * the Smarty homepage's 4-type configurator and the 7 plain-PHP market/*.php hosting pages —
 * custom.css never loads on those. 2026-08-25: two redesign passes the same session real Cloud/
 * Standard-WordPress/Managed-WordPress-Hosting catalog data was imported — see the "Plans table +
 * term switcher" section below for the version that shipped, and hosting-configurator-render.php's
 * own docblock for the full history of what the user corrected and why.
 *
 * Linked by:
 *   - templates/vercaa-2026/includes/head.tpl (every Smarty client-area page, guest and logged-in —
 *     same as the other two shared component stylesheets above).
 *   - Each of the 7 market/*.php hosting pages, directly in their own <head> (same convention those
 *     pages already use for _tokens.css/_chrome.css).
 *
 * Token contract: every var() below resolves in BOTH contexts — custom.css's own :root (--bg,
 * --text, --primary, --success, --bg-inverted, --text-inverted, --rounding-2xl, --disabled-opacity,
 * etc.) on the Smarty side, and market/_tokens.css's alias block on the market-page side. No new
 * hex literal anywhere in this file.
 *
 * Markup contract: rendered by two different callers now sharing the SAME real PHP function,
 * templates/vercaa-2026/includes/hosting-configurator-render.php's vhp_render_plan_card() —
 * homepage.tpl calls it once per hosting type inside its own 4-tile switcher; each market/*.php
 * hosting page calls it once (via that same file's vhp_render_single_type_configurator() wrapper)
 * for its own single, page-relevant hosting type.
 *
 * MECHANISM: zero JS required for correctness anywhere in this file — hidden radio + :has(), the
 * same technique this theme's other CSS-only toggles already use, so exactly one tile/term-cell
 * can ever be selected/visible at once, by construction. js/hosting-configurator-slider.js adds a
 * purely decorative sliding-thumb layer on top of the term switcher; nothing about visibility
 * depends on it.
 */
/* 2026-08-25 redesign: soft ambient brand glow behind the card, same restrained "accent glow, not
   full translucency" language already established on this site's other refreshed surfaces (hero
   glass panel, header mega-menu panel) — kept opaque (not backdrop-blur) so real price/feature
   text inside keeps full contrast; the glow is purely decorative, `overflow:hidden` clips it to
   the card's own rounded corners. */
.vhp-configurator {
    position: relative; overflow: hidden; background: var(--bg); border: 1px solid var(--border-muted);
    border-radius: var(--rounding-2xl); box-shadow: var(--elevation-2); padding: clamp(1.75rem, 3vw, 2.5rem);
}
.vhp-configurator::before {
    content: ""; position: absolute; inset: -30% -10% auto -10%; height: 55%; z-index: 0; pointer-events: none;
    background: radial-gradient(60% 100% at 25% 0%, color-mix(in srgb, var(--primary) 13%, transparent), transparent 70%);
}
.vhp-config-head, .vhp-config-pane-grid { position: relative; z-index: 1; }
.vhp-config-head { display: flex; align-items: center; gap: 0.85rem; flex-wrap: wrap; margin-bottom: 1.75rem; }
.vhp-config-badge {
    font-family: var(--font-heading); font-weight: 700; font-size: 1.0625rem; color: var(--text); margin-right: auto;
}
.vhp-config-live-pill {
    display: inline-flex; align-items: center; gap: 0.4rem; background: var(--success-soft); color: var(--success-accented);
    font-weight: 700; font-size: var(--text-xs); text-transform: uppercase; letter-spacing: 0.03em;
    border-radius: 999px; padding: 0.35rem 0.75rem 0.35rem 0.6rem;
}
.vhp-config-live-dot {
    width: 6px; height: 6px; border-radius: 50%; background: var(--success); flex-shrink: 0;
    animation: vhpLivePulse 2.4s ease-out infinite;
}
@media (prefers-reduced-motion: reduce) { .vhp-config-live-dot { animation: none; } }
.vhp-config-pricing-label { font-size: var(--text-sm); font-weight: 600; color: var(--text-muted); }

/* 2026-08-25 redesign, TWO passes. Pass 1 (icon + top accent bar) was correct in direction but
   the user's next message called it "very huge" — each tile stacked icon-row/name/sub/price as 4
   full-width lines, needlessly tall for 4 tiles in a row. Pass 2 (this version): a compact 2-row
   grid — leading icon spans both rows on the left, name+tag share the top row, plan-count+price
   share the bottom row — the same real information, roughly half the height. Icons stay real
   inline SVG (one per hosting.key), never emoji. */
.vhp-config-tiles { display: grid; grid-template-columns: 1fr; gap: 0.6rem; margin-bottom: 1.75rem; }
@media (min-width: 640px) { .vhp-config-tiles { grid-template-columns: repeat(2, 1fr); } }

.vhp-config-tile {
    position: relative; overflow: hidden; cursor: pointer;
    display: grid; grid-template-columns: auto 1fr auto; grid-template-rows: auto auto;
    align-items: center; column-gap: 0.65rem; row-gap: 0.05rem;
    background: var(--bg-muted); border: 1.5px solid var(--border-muted); border-radius: var(--rounding-lg);
    padding: 0.75rem 0.9rem;
    transition: border-color var(--duration-fast) var(--ease-out), background-color var(--duration-fast) var(--ease-out), box-shadow var(--duration-fast) var(--ease-out), transform var(--duration-fast) var(--ease-out);
}
.vhp-config-tile::before {
    content: ""; position: absolute; top: 0; left: 0; right: 0; height: 2.5px;
    background: linear-gradient(90deg, var(--primary), var(--primary-lifted)); transform: scaleX(0); transform-origin: left;
    transition: transform var(--duration-slow) var(--ease-standard);
}
.vhp-config-tile input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.vhp-config-tile:hover { border-color: var(--border-lifted); transform: translateY(-1px); box-shadow: var(--elevation-1); }
.vhp-config-tile:has(input:checked) { background: var(--primary-soft); border-color: var(--primary); box-shadow: 0 0 0 1px var(--primary) inset; }
.vhp-config-tile:has(input:checked)::before { transform: scaleX(1); }
.vhp-config-tile:has(input:focus-visible) { box-shadow: var(--focus-ring); }
@media (prefers-reduced-motion: reduce) { .vhp-config-tile, .vhp-config-tile::before { transition: none; } .vhp-config-tile:hover { transform: none; } }

/* .vhp-config-tile-top wraps icon+tag in the markup (kept as one semantic unit there) but is
   laid out here as two independent grid items, not a row of its own — display:contents removes
   it from layout entirely without needing a markup change. */
.vhp-config-tile-top { display: contents; }
.vhp-config-tile-icon {
    grid-row: 1 / span 2; grid-column: 1;
    display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; flex-shrink: 0;
    border-radius: var(--rounding-md); background: color-mix(in srgb, var(--primary) 14%, transparent); color: var(--primary-accented);
    transition: background-color var(--duration-fast) var(--ease-out);
}
.vhp-config-tile-icon svg { width: 15px; height: 15px; }
.vhp-config-tile:has(input:checked) .vhp-config-tile-icon { background: var(--primary); color: var(--white); }
.vhp-config-tile-tag {
    grid-row: 1; grid-column: 3; justify-self: end;
    font-size: 0.625rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.03em;
    border-radius: 999px; padding: 0.15rem 0.45rem; white-space: nowrap;
}
.vhp-config-tile-tag-live { background: var(--success-soft); color: var(--success-accented); }
.vhp-config-tile-tag-soon { background: var(--bg-accented); color: var(--text-muted); }
.vhp-config-tile-name { grid-row: 1; grid-column: 2; font-family: var(--font-heading); font-weight: 700; font-size: 0.9375rem; color: var(--text); }
.vhp-config-tile-sub { grid-row: 2; grid-column: 2; font-size: 0.75rem; color: var(--text-lifted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.vhp-config-tile-price { grid-row: 2; grid-column: 3; justify-self: end; font-family: var(--font-heading); font-weight: 700; font-size: 0.9375rem; color: var(--primary-accented); white-space: nowrap; }
.vhp-config-tile-price small { font-family: var(--font-body); font-weight: 600; font-size: 0.6875rem; color: var(--text-muted); }
.vhp-config-tile-price-soon { color: var(--text-muted); }

.vhp-config-panes { position: relative; display: grid; }
.vhp-config-pane {
    grid-area: 1 / 1; opacity: 0; pointer-events: none; visibility: hidden;
    transition: opacity var(--duration-slow) var(--ease-standard), visibility var(--duration-slow) var(--ease-standard);
}
.vhp-configurator:has(#vhpPlanWeb:checked) #vhpPaneWeb,
.vhp-configurator:has(#vhpPlanCloud:checked) #vhpPaneCloud,
.vhp-configurator:has(#vhpPlanWp:checked) #vhpPaneWp,
.vhp-configurator:has(#vhpPlanMwp:checked) #vhpPaneMwp {
    opacity: 1; pointer-events: auto; visibility: visible;
}
@media (prefers-reduced-motion: reduce) { .vhp-config-pane { transition: none; } }

.vhp-config-pane-grid { display: grid; grid-template-columns: 1.15fr 0.85fr; gap: clamp(1.5rem, 3vw, 2.5rem); align-items: start; }
@media (max-width: 760px) { .vhp-config-pane-grid { grid-template-columns: 1fr; } }
/* Grid items default to min-width:auto (content-based) — without this, long real product names
   (e.g. Cloud Hosting's "VER-Cun-R16G-Un" style SKUs) could stretch this whole grid column wider
   than intended instead of truncating/wrapping within it. */
.vhp-config-plan-card { min-width: 0; }

.vhp-config-pane-title {
    font-family: var(--font-heading); font-size: 1.375rem; font-weight: 700; color: var(--text);
    display: flex; flex-wrap: wrap; align-items: center; gap: 0.65rem; margin: 0 0 0.85rem;
}
.vhp-config-pane-badge { font-size: var(--text-xs); font-weight: 700; text-transform: uppercase; letter-spacing: 0.03em; border-radius: 999px; padding: 0.25rem 0.6rem; }
.vhp-config-pane-badge-live { background: var(--success-soft); color: var(--success-accented); }
.vhp-config-pane-badge-soon { background: var(--bg-accented); color: var(--text-muted); }
.vhp-config-pane-tagline { color: var(--text-lifted); font-size: 1rem; line-height: 1.6; margin: 0 0 1.25rem; max-width: 34rem; }
/* 2026-08-25: user asked for the type-level feature checklist to read as its own highlighted
   rectangle rather than plain list items floating in the info column — a tinted, bordered panel
   using the same --primary-soft/--primary tokens already used for the homepage tile's own
   "selected" state, so it reads as consistent with the rest of this component, not a new color. */
.vhp-config-checklist-box {
    background: var(--primary-soft); border: 1px solid color-mix(in srgb, var(--primary) 30%, transparent);
    border-radius: var(--rounding-lg); padding: 1.1rem 1.25rem;
}
.vhp-config-checklist { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.6rem; }
.vhp-config-checklist li { display: flex; align-items: flex-start; gap: 0.6rem; color: var(--text-accented); font-size: 0.9375rem; font-weight: 600; line-height: 1.4; }
.vhp-config-checklist li::before {
    content: ""; width: 17px; height: 17px; flex-shrink: 0; margin-top: 0.1rem; display: inline-block;
    background: var(--success);
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12.5l4.5 4.5L19 7'/%3E%3C/svg%3E") center / contain no-repeat;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12.5l4.5 4.5L19 7'/%3E%3C/svg%3E") center / contain no-repeat;
}

/* "Your Plan" summary card. Uses --bg-inverted/--text-inverted (already-existing, theme-reactive
   token pair — near-black card on the light theme, near-white card on the dark theme) rather than
   a permanently-dark navy chip: this project explicitly retired theme-invariant surfaces earlier in
   this same section's history (see the hero/closing-CTA rebuild notes above), so an always-flipped,
   always-high-contrast card is the deliberate, in-spirit choice here rather than reintroducing that
   pattern for one new component. */
.vhp-config-plan-card {
    background: var(--bg-inverted); color: var(--text-inverted); border-radius: var(--rounding-xl);
    padding: 1.75rem; box-shadow: var(--elevation-2);
}
.vhp-config-plan-label { display: block; font-size: var(--text-xs); font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; opacity: 0.65; margin-bottom: 0.5rem; }
.vhp-config-plan-name { font-family: var(--font-heading); font-size: 1.1875rem; font-weight: 700; margin: 0 0 0.6rem; }
.vhp-config-plan-price { font-family: var(--font-heading); font-size: 2.25rem; font-weight: 700; margin: 0; line-height: 1; }
.vhp-config-plan-price span { font-family: var(--font-body); font-size: 1rem; font-weight: 600; opacity: 0.7; }
.vhp-config-plan-price-soon { font-size: 1.375rem; opacity: 0.85; }
.vhp-config-plan-note { font-size: var(--text-sm); opacity: 0.65; margin: 0.35rem 0 1.25rem; line-height: 1.5; }
.vhp-config-plan-list { list-style: none; margin: 0 0 1.5rem; padding: 0; display: flex; flex-direction: column; gap: 0.55rem; }
.vhp-config-plan-list li { display: flex; align-items: flex-start; gap: 0.55rem; font-size: 0.875rem; font-weight: 600; line-height: 1.4; }
.vhp-config-plan-list li::before {
    content: ""; width: 15px; height: 15px; flex-shrink: 0; margin-top: 0.1rem; display: inline-block;
    background: var(--success);
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12.5l4.5 4.5L19 7'/%3E%3C/svg%3E") center / contain no-repeat;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12.5l4.5 4.5L19 7'/%3E%3C/svg%3E") center / contain no-repeat;
}
.vhp-config-plan-cta {
    display: inline-flex; align-items: center; gap: 0.5rem; width: 100%; justify-content: center;
    background: var(--white); color: var(--primary-accented); font-weight: 700; font-size: 0.9375rem;
    border-radius: 999px; padding: 0.75rem 1.25rem; text-decoration: none;
    transition: transform var(--duration-fast) var(--ease-out), box-shadow var(--duration-fast) var(--ease-out);
}
.vhp-config-plan-cta:hover { transform: translateY(-1px); box-shadow: 0 8px 18px -8px rgba(0, 0, 0, 0.35); text-decoration: none; }
/* 2026-08-14 dark-mode contrast fix (found live via a real getComputedStyle sweep of
   market/web-hosting.php's "Your Plan" card): .vhp-config-plan-card's whole point is an
   intentionally-INVERTED surface (--bg-inverted/--text-inverted flip near-black<->near-white with
   the theme, per this card's own comment above) -- so in dark mode this card is actually a
   near-WHITE card floating on the dark page. --primary-accented now correctly resolves to the
   brighter --primary-glow for its ~55 other, genuinely-on-DARK consumers sitewide (see custom.css's
   token comment) -- but that bright purple on THIS card's white pills (.vhp-config-plan-cta here,
   plus the plan/term slider's "checked" tick below) is only 3.54:1, a real regression versus the
   pre-fix ink value. Pinned to --primary-lifted (5.99:1 on white, stable in both themes) instead --
   same fix, same reasoning, as .app-gradient-banner-btn in custom.css for the identical situation. */
:root[data-theme="dark"] .vhp-config-plan-cta:not(.vhp-config-plan-card-soon .vhp-config-plan-cta) { color: var(--primary-lifted); }
.vhp-config-plan-cta svg { width: 15px; height: 15px; }
.vhp-config-plan-card-soon .vhp-config-plan-cta { background: transparent; color: var(--text-inverted); border: 1px solid color-mix(in srgb, var(--text-inverted) 35%, transparent); }
.vhp-config-plan-card-soon .vhp-config-plan-cta:hover { background: color-mix(in srgb, var(--text-inverted) 12%, transparent); }

.vhp-config-help { text-align: center; margin: 1.75rem 0 0; color: var(--text-lifted); font-size: 0.9375rem; }
.vhp-config-help a { display: inline-flex; align-items: center; gap: 0.3rem; color: var(--primary-accented); font-weight: 700; text-decoration: none; }
.vhp-config-help a:hover { color: var(--primary); text-decoration: underline; }
.vhp-config-help a svg { width: 13px; height: 13px; }

/* =========================================================================================
   Term switcher + plan slider + detail panel — 2026-08-25, THIRD redesign pass this session (see
   hosting-configurator-render.php's vhp_render_plan_card() docblock for the full pass-by-pass
   history of what the user corrected and why). Shipped version: ONE shared billing-term switcher
   (Monthly/Yearly/2yr/3yr) at the top driving every plan's price cell; a plan-picker slider (with
   explicit prev/next buttons, not drag-only, for clearer affordance) below it; a single detail
   panel showing the currently-selected plan's full real feature list + price for the currently-
   selected term. Two independent, composable CSS `:has()` mechanisms — which PLAN pane shows, and
   which TERM cell shows inside it — combine to select exactly one real price at a time, zero JS
   required for correctness.
   ========================================================================================= */
.vhp-config-plan-card-live { display: flex; flex-direction: column; }

.vhp-plan-card-head { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 0.85rem; margin-bottom: 1.25rem; }
.vhp-plan-card-head .vhp-config-plan-label { margin-bottom: 0; }
/* 2026-08-25 real responsive bug fix: flex-shrink:0 with no width cap meant that once this
   wrapped onto its own line below "Your Plan" (too narrow to sit beside it), it still rendered at
   its own unconstrained natural content width (driven by the 4-term track inside) instead of
   fitting the row it had actually wrapped into — overflowing past the card's own edge and getting
   clipped by `.vhp-configurator`'s `overflow:hidden`. max-width:100% caps it to whatever room the
   row genuinely has either way, letting the track's own internal wrap-to-2-rows fix (above) work. */
.vhp-term-slider { flex-shrink: 0; max-width: 100%; }

/* ---- Term switcher (one shared control per configurator, drives every plan's price) ----
   A real sliding-thumb segmented control (js/hosting-configurator-slider.js) — the individual
   tick's own `:has(input:checked)` background is the no-JS baseline; the thumb is a pure visual
   enhancement layered on top (see hosting-configurator-render.php's docblock). */
.vhp-term-slider-track { position: relative; display: flex; flex-wrap: wrap; background: color-mix(in srgb, var(--text-inverted) 12%, transparent); border-radius: 999px; padding: 3px; gap: 2px; }
.vhp-term-slider-tick {
    flex: 1 1 auto; min-width: 4.25rem; position: relative; z-index: 1; text-align: center; font-size: 0.75rem; font-weight: 700; border-radius: 999px;
    padding: 0.5rem 0.85rem; cursor: pointer; color: var(--text-inverted); opacity: 0.7; white-space: nowrap;
    transition: background-color var(--duration-fast) var(--ease-out), opacity var(--duration-fast) var(--ease-out), color var(--duration-fast) var(--ease-out);
}
.vhp-term-slider-tick input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.vhp-term-slider-tick:has(input:checked) { background: var(--white); color: var(--primary-accented); opacity: 1; }
:root[data-theme="dark"] .vhp-term-slider-tick:has(input:checked) { color: var(--primary-lifted); }
.vhp-term-slider-tick:has(input:focus-visible) { box-shadow: 0 0 0 2px color-mix(in srgb, var(--text-inverted) 40%, transparent); }
/* 2026-08-25 real responsive bug fix: 4 equal flex segments (`flex:1`, no min-width, nowrap text)
   never shrank below their own text's natural width, so on a narrow "Your Plan" card (the common
   case once `.vhp-config-pane-grid` stacks to 1 column below 760px) "3 Years" overflowed its tick
   and got clipped by `.vhp-configurator`'s own `overflow:hidden`. min-width above gives every
   label room to render in full; flex-wrap here + the min-width let 4 segments settle into a clean
   2x2 grid (via the pill's own border-radius, which reads fine wrapped) once genuinely too narrow
   for one row, instead of silently truncating billing-term text — a real word here matters more
   than a compressed row. js/hosting-configurator-slider.js's thumb math is unaffected: it already
   reads each tick's real offsetLeft/offsetTop, which is correct on 1 row or 2.

/* Sliding thumb (shared by both the term switcher above and the plan slider below) — positioned/
   sized/animated by js/hosting-configurator-slider.js (offsetLeft/offsetTop/offsetWidth/
   offsetHeight of the checked tick, translated via transform). Renders invisible (opacity:0)
   until JS has measured and placed it once (`.is-ready`), so there's never a flash at 0,0 before
   first paint; a no-JS visitor never sees it at all. */
.vhp-tier-slider-thumb {
    position: absolute; top: 0; left: 0; height: 100%; width: 0; border-radius: 999px;
    background: linear-gradient(155deg, var(--white), color-mix(in srgb, var(--white) 85%, var(--primary-lifted)));
    box-shadow: 0 8px 20px -8px rgba(0, 0, 0, 0.5), 0 0 0 1px color-mix(in srgb, var(--text-inverted) 6%, transparent);
    z-index: 0; opacity: 0; pointer-events: none; touch-action: none;
    transition: transform 420ms cubic-bezier(0.34, 1.3, 0.64, 1), width 420ms cubic-bezier(0.34, 1.3, 0.64, 1), opacity var(--duration-fast) var(--ease-out);
    will-change: transform, width;
}
.vhp-tier-slider-thumb.is-ready { opacity: 1; pointer-events: auto; cursor: grab; }
.vhp-tier-slider-thumb.is-dragging { transition: opacity var(--duration-fast) var(--ease-out); cursor: grabbing; }
@media (prefers-reduced-motion: reduce) {
    .vhp-tier-slider-thumb { transition: opacity var(--duration-fast) var(--ease-out); }
}
/* 2026-08-25 real bug fix, from a user screenshot: the plan-slider's own ticks stack a circle
   above short text (a near-square box, e.g. ~53x52px for "1 Swift") — a 999px pill radius on a
   near-square box renders as a big rounded blob, not a refined badge, looking visibly oversized/
   out of proportion next to the plain small circles on the other, unselected ticks (measured live:
   the thumb WAS correctly sized/positioned to match its tick exactly — this was a shape problem,
   not a positioning one). The term switcher's own thumb (wide, short "Monthly"-style ticks) keeps
   the full pill radius, which suits that shape correctly. */

/* =========================================================================================
   Plan picker — 2026-08-25, FOURTH pass, direct user report + screenshot: the pass-3 tick row
   (a horizontally-scrollable strip of every plan, real Cloud Hosting has 16) could land
   mid-scroll with a tile visibly clipped against the track's own rounded edge ("still miss
   aligned"), and the user asked directly for a different model: "it should show one plan and we
   can move between them". Replaced entirely with a real native `<input type="range">` — exactly
   one plan's index/name is ever rendered at a time, so there is no row to overflow or clip in the
   first place; prev/next buttons plus the range's own native drag+keyboard-arrow support move
   between plans. js/hosting-configurator-slider.js's initPlanRange() reads the range's value and
   directly toggles which `.vhp-plan-pane` is visible — see hosting-configurator-render.php's own
   docblock for why this one control needed JS (a numeric range value can't drive CSS `:has()` the
   way discrete radio ticks could).
   ========================================================================================= */
.vhp-plan-slider { margin-bottom: 1.5rem; display: flex; align-items: center; gap: 0.65rem; }
.vhp-plan-slider-arrow {
    flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px;
    border-radius: 50%; border: 1.5px solid color-mix(in srgb, var(--text-inverted) 25%, transparent); background: transparent;
    color: var(--text-inverted); cursor: pointer; padding: 0;
    transition: background-color var(--duration-fast) var(--ease-out), border-color var(--duration-fast) var(--ease-out);
}
.vhp-plan-slider-arrow svg { width: 16px; height: 16px; }
.vhp-plan-slider-arrow:hover { background: color-mix(in srgb, var(--text-inverted) 10%, transparent); border-color: color-mix(in srgb, var(--text-inverted) 45%, transparent); }
.vhp-plan-slider-arrow:focus-visible { box-shadow: 0 0 0 3px color-mix(in srgb, var(--text-inverted) 35%, transparent); }
.vhp-plan-slider-arrow:disabled { opacity: var(--disabled-opacity); cursor: not-allowed; }

.vhp-plan-slider-single { flex: 1; min-width: 0; }
.vhp-plan-slider-current { display: flex; align-items: baseline; justify-content: space-between; gap: 0.6rem; margin-bottom: 0.5rem; }
.vhp-plan-slider-current-index { font-size: var(--text-xs); font-weight: 700; opacity: 0.6; white-space: nowrap; }
.vhp-plan-slider-current-name {
    font-family: var(--font-heading); font-weight: 700; font-size: 0.9375rem; text-align: right;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; margin-left: 0.75rem;
}

/* Native range input, restyled to match this card's brand — a real slider track/thumb, not an
   emulated one, so drag/keyboard/touch all come free from the browser with zero custom hit-test
   or snap-to-step math (step="1" already snaps natively). */
.vhp-plan-range {
    -webkit-appearance: none; appearance: none; width: 100%; height: 28px; background: transparent; cursor: pointer; margin: 0;
}
.vhp-plan-range:focus-visible { outline: none; }
.vhp-plan-range::-webkit-slider-runnable-track {
    height: 6px; border-radius: 999px; background: color-mix(in srgb, var(--text-inverted) 16%, transparent);
}
.vhp-plan-range::-moz-range-track {
    height: 6px; border-radius: 999px; background: color-mix(in srgb, var(--text-inverted) 16%, transparent);
}
.vhp-plan-range::-webkit-slider-thumb {
    -webkit-appearance: none; margin-top: -8px; width: 22px; height: 22px; border-radius: 50%;
    background: var(--white); box-shadow: 0 4px 10px -3px rgba(0, 0, 0, 0.5), 0 0 0 5px color-mix(in srgb, var(--primary) 55%, transparent);
    transition: transform var(--duration-fast) var(--ease-out);
}
.vhp-plan-range::-moz-range-thumb {
    width: 22px; height: 22px; border: none; border-radius: 50%;
    background: var(--white); box-shadow: 0 4px 10px -3px rgba(0, 0, 0, 0.5), 0 0 0 5px color-mix(in srgb, var(--primary) 55%, transparent);
    transition: transform var(--duration-fast) var(--ease-out);
}
.vhp-plan-range:active::-webkit-slider-thumb { transform: scale(1.12); }
.vhp-plan-range:active::-moz-range-thumb { transform: scale(1.12); }
.vhp-plan-range:focus-visible::-webkit-slider-thumb { box-shadow: 0 4px 10px -3px rgba(0, 0, 0, 0.5), 0 0 0 3px var(--white), 0 0 0 6px var(--primary); }
.vhp-plan-range:focus-visible::-moz-range-thumb { box-shadow: 0 4px 10px -3px rgba(0, 0, 0, 0.5), 0 0 0 3px var(--white), 0 0 0 6px var(--primary); }
@media (prefers-reduced-motion: reduce) {
    .vhp-plan-range::-webkit-slider-thumb, .vhp-plan-range::-moz-range-thumb { transition: none; }
}

/* ---- Detail panel (the currently-selected plan's full price + real features + CTA) ----
   No-JS baseline: only the first plan (server-rendered as data-plan-index="0") shows — a real,
   correct plan, just not changeable without the range's JS. JS-enabled visitors get
   initPlanRange() toggling this directly per the range's current value. */
.vhp-plan-pane { display: none; }
.vhp-config-plan-card-single-plan .vhp-plan-pane,
.vhp-plan-pane:first-child { display: block; }

/* .vhp-term-cell lives inside EVERY .vhp-plan-pane, one per term in fixed $termOrder — governed
   by the SAME global term switcher above, independent of which plan-pane contains it. Only the
   selected plan's selected term-cell is ever both "inside a visible pane" AND "individually
   visible" at once — real 2-axis selection composed from two independent ladders. */
.vhp-term-cell { display: none; }
.vhp-config-plan-card:has(.vhp-term-slider-tick:nth-of-type(1) input:checked) .vhp-term-cell:nth-of-type(1),
.vhp-config-plan-card:has(.vhp-term-slider-tick:nth-of-type(2) input:checked) .vhp-term-cell:nth-of-type(2),
.vhp-config-plan-card:has(.vhp-term-slider-tick:nth-of-type(3) input:checked) .vhp-term-cell:nth-of-type(3),
.vhp-config-plan-card:has(.vhp-term-slider-tick:nth-of-type(4) input:checked) .vhp-term-cell:nth-of-type(4) {
    display: block;
}
.vhp-config-plan-price-na { font-size: 1.0625rem; font-weight: 600; opacity: 0.75; margin: 0 0 0.35rem; }

/* Vercaa Discounts (2026-08-25) — real, admin-configured per-product/group discount display.
   .vhp-config-plan-price-was is the real, undiscounted price struck through above the real
   discounted price; the "renews at" copy in .vhp-config-plan-note (rendered by
   hosting-configurator-render.php only when a real discount exists) makes clear the discount is a
   one-time thing, not a permanent price drop — matches the real one-time guarantee the actual
   InvoiceCreation hook enforces server-side (see includes/hooks/vercaa-discounts-loader.php). */
.vhp-config-plan-price-was {
    display: block;
    font-family: var(--font-body);
    font-size: 1.125rem;
    font-weight: 600;
    color: var(--text-muted);
    text-decoration: line-through;
    margin-bottom: 0.15rem;
}
.vhp-config-plan-price-badge {
    display: inline-block;
    vertical-align: middle;
    margin-left: 0.5rem;
    padding: 0.15rem 0.55rem;
    border-radius: var(--rounding-sm);
    background: var(--success-soft);
    color: var(--success-accented);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 700;
}

/* Homepage tile discount state (2026-08-25) -- .vhp-config-tile-price only gains
   .vhp-config-tile-price-discounted when a real discount applies to the tile's true cheapest
   product; without that modifier the base .vhp-config-tile-price rule above is untouched, so a
   non-discounted tile renders byte-identical to before. Same --success-soft/--success-accented
   pairing as .vhp-config-plan-price-badge above, scaled down for this denser card. */
.vhp-config-tile-price-discounted { display: flex; flex-direction: column; align-items: flex-end; gap: 0.1rem; }
.vhp-config-tile-price-was { font-family: var(--font-body); font-weight: 600; font-size: 0.625rem; color: var(--text-muted); text-decoration: line-through; line-height: 1; }
.vhp-config-tile-price-now { display: inline-flex; align-items: baseline; gap: 0.3rem; line-height: 1; }
.vhp-config-tile-price-badge {
    display: inline-block; font-family: var(--font-body); font-weight: 700; font-size: 0.5625rem;
    text-transform: uppercase; letter-spacing: 0.02em; white-space: nowrap;
    background: var(--success-soft); color: var(--success-accented); border-radius: 999px; padding: 0.1rem 0.4rem;
}
