/*
 * VPN theme design system.
 *
 * Layered on top of the Bootstrap bundle the theme ships, so pages this theme
 * does not override still render correctly. Everything here is scoped to a
 * custom class (.vpn-*, .vpnpay-*) or a deliberate Bootstrap override.
 *
 * Structure:
 *   1. Tokens          design decisions as custom properties
 *   2. Base            document, typography, focus
 *   3. Frame           page shell, header, navigation
 *   4. Surfaces        cards, subscription hero, meters, stats
 *   5. Controls        buttons, pills, forms, tiles
 *   6. Content         plans, tables, lists, empty states
 *   7. Payments        markup emitted by Vpnpay\PaymentRenderer
 *   8. Bootstrap       harmonisation for non-overridden pages
 *   9. Motion          reduced-motion and print
 *
 * Colour is defined once on :root and re-pointed under [data-bs-theme="dark"],
 * so the header's theme toggle switches the whole system.
 */

/* ================================================================== */
/* 1. Tokens                                                          */
/* ================================================================== */

:root {
    /* Brand ramp -- indigo through violet, matching the reference design */
    --vpn-brand-50: #eef2ff;
    --vpn-brand-100: #e0e7ff;
    --vpn-brand-200: #c7d2fe;
    --vpn-brand-300: #a5b4fc;
    --vpn-brand-400: #818cf8;
    --vpn-brand-500: #6366f1;
    --vpn-brand-600: #4f46e5;
    --vpn-brand-700: #4338ca;
    --vpn-brand-800: #3730a3;

    --vpn-violet-400: #c084fc;
    --vpn-violet-500: #a855f7;
    --vpn-violet-600: #9333ea;
    --vpn-pink-300: #f9a8d4;
    --vpn-pink-400: #f472b6;
    --vpn-pink-500: #ec4899;
    --vpn-cyan-400: #22d3ee;

    /* Semantic */
    --vpn-success: #10b981;
    --vpn-success-ink: #047857;
    --vpn-success-soft: #d1fae5;
    --vpn-warning: #f59e0b;
    --vpn-warning-ink: #b45309;
    --vpn-warning-soft: #fef3c7;
    --vpn-danger: #ef4444;
    --vpn-danger-ink: #b91c1c;
    --vpn-danger-soft: #fee2e2;
    --vpn-info: #0ea5e9;
    --vpn-info-ink: #0369a1;
    --vpn-info-soft: #e0f2fe;

    /* Surfaces */
    --vpn-page: #eaeefb;
    --vpn-surface: #ffffff;
    --vpn-surface-2: #f8fafc;
    --vpn-surface-3: #f1f5f9;
    --vpn-surface-sunken: #eef2f7;
    --vpn-border: #e6ebf3;
    --vpn-border-strong: #cbd5e1;
    --vpn-hairline: rgba(15, 23, 42, .07);

    /* Ink */
    --vpn-text: #0b1220;
    --vpn-text-2: #4a5568;
    --vpn-text-3: #94a3b8;
    --vpn-on-brand: #ffffff;

    /* Referenced throughout but previously never defined, so every rule that
       used them was discarded by the browser. */
    --vpn-accent: #7c3aed;
    --vpn-text-muted: var(--vpn-text-3);

    /* Radii -- generous and consistent, the core of the "soft" feel */
    --vpn-r-xs: 8px;
    --vpn-r-sm: 12px;
    --vpn-r-md: 16px;
    --vpn-r-lg: 22px;
    --vpn-r-xl: 28px;
    --vpn-r-2xl: 34px;
    --vpn-r-pill: 999px;

    /* Elevation -- layered, tinted toward the brand rather than pure black,
       which is what keeps the surfaces feeling soft instead of dirty. */
    --vpn-shadow-xs: 0 1px 2px rgba(30, 41, 90, .05);
    --vpn-shadow-sm: 0 1px 2px rgba(30, 41, 90, .04),
                     0 2px 6px rgba(30, 41, 90, .05);
    --vpn-shadow-md: 0 2px 4px rgba(30, 41, 90, .04),
                     0 8px 16px -4px rgba(30, 41, 90, .08);
    --vpn-shadow-lg: 0 4px 8px rgba(30, 41, 90, .04),
                     0 16px 32px -8px rgba(30, 41, 90, .10),
                     0 32px 64px -16px rgba(30, 41, 90, .10);
    --vpn-shadow-xl: 0 8px 16px -4px rgba(30, 41, 90, .06),
                     0 24px 48px -12px rgba(30, 41, 90, .12),
                     0 48px 96px -24px rgba(30, 41, 90, .14);

    --vpn-glow-brand: 0 8px 24px -6px rgba(99, 102, 241, .48),
                      0 2px 6px -1px rgba(99, 102, 241, .30);
    --vpn-glow-pink: 0 8px 24px -6px rgba(236, 72, 153, .45),
                     0 2px 6px -1px rgba(236, 72, 153, .28);

    /* Gradients */
    --vpn-grad-brand: linear-gradient(135deg, #4f46e5 0%, #7c3aed 48%, #a855f7 100%);
    --vpn-grad-accent: linear-gradient(135deg, #6366f1 0%, #c026d3 55%, #f472b6 100%);
    --vpn-grad-sheen: linear-gradient(180deg, rgba(255, 255, 255, .18), rgba(255, 255, 255, 0));

    /* Focus ring */
    --vpn-ring: 0 0 0 3px rgba(99, 102, 241, .32);

    /* Motion */
    --vpn-ease: cubic-bezier(.22, .61, .36, 1);
    --vpn-ease-out: cubic-bezier(.16, 1, .3, 1);
    --vpn-fast: 140ms;
    --vpn-med: 240ms;
}

[data-bs-theme="dark"] {
    --vpn-page: #070b16;
    --vpn-surface: #101728;
    --vpn-surface-2: #161f33;
    --vpn-surface-3: #1d2740;
    --vpn-surface-sunken: #0c1220;
    --vpn-border: #223049;
    --vpn-border-strong: #33415c;
    --vpn-hairline: rgba(255, 255, 255, .07);

    --vpn-text: #eaf0fb;
    --vpn-text-2: #a3b1c9;
    --vpn-text-3: #6b7c99;
    --vpn-accent: #a855f7;

    --vpn-success-ink: #6ee7b7;
    --vpn-success-soft: rgba(16, 185, 129, .16);
    --vpn-warning-ink: #fcd34d;
    --vpn-warning-soft: rgba(245, 158, 11, .16);
    --vpn-danger-ink: #fca5a5;
    --vpn-danger-soft: rgba(239, 68, 68, .16);
    --vpn-info-ink: #7dd3fc;
    --vpn-info-soft: rgba(14, 165, 233, .16);

    --vpn-shadow-xs: 0 1px 2px rgba(0, 0, 0, .35);
    --vpn-shadow-sm: 0 1px 3px rgba(0, 0, 0, .40);
    --vpn-shadow-md: 0 6px 16px -4px rgba(0, 0, 0, .55);
    --vpn-shadow-lg: 0 16px 40px -12px rgba(0, 0, 0, .65);
    --vpn-shadow-xl: 0 28px 64px -18px rgba(0, 0, 0, .72);

    --vpn-ring: 0 0 0 3px rgba(129, 140, 248, .38);
}

/* ================================================================== */
/* 2. Base                                                            */
/* ================================================================== */

body {
    background-color: var(--vpn-page);
    color: var(--vpn-text);
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI Variable Text",
                 "Segoe UI", Inter, Roboto, "Helvetica Neue", Arial, sans-serif;
    font-size: 15px;
    line-height: 1.55;
    letter-spacing: -0.011em;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-rendering: optimizeLegibility;
    min-height: 100vh;
    position: relative;
}

/* Aurora field behind the app. Fixed and non-interactive, so it costs one
   composited layer and never affects scrolling or hit-testing. */
body::before {
    content: "";
    position: fixed;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    background:
        radial-gradient(46rem 30rem at 12% -8%, rgba(99, 102, 241, .22), transparent 60%),
        radial-gradient(38rem 26rem at 92% 4%, rgba(168, 85, 247, .18), transparent 62%),
        radial-gradient(34rem 24rem at 78% 96%, rgba(236, 72, 153, .14), transparent 60%),
        radial-gradient(30rem 22rem at 4% 88%, rgba(34, 211, 238, .12), transparent 62%);
}

[data-bs-theme="dark"] body::before {
    background:
        radial-gradient(46rem 30rem at 12% -8%, rgba(99, 102, 241, .26), transparent 62%),
        radial-gradient(38rem 26rem at 92% 4%, rgba(168, 85, 247, .20), transparent 64%),
        radial-gradient(34rem 24rem at 78% 96%, rgba(236, 72, 153, .14), transparent 62%);
}

/* Everything above the aurora. */
.vpn-app,
.vpn-auth,
.vpn-tabbar,
.toast-container {
    position: relative;
    z-index: 1;
}

h1, h2, h3, h4, h5, h6 {
    color: var(--vpn-text);
    font-weight: 700;
    letter-spacing: -0.024em;
    line-height: 1.25;
}

a {
    text-decoration: none;
    transition: color var(--vpn-fast) var(--vpn-ease);
}

::selection {
    background: var(--vpn-brand-200);
    color: var(--vpn-brand-800);
}

[data-bs-theme="dark"] ::selection {
    background: rgba(129, 140, 248, .35);
    color: #fff;
}

/* One consistent, visible focus ring for keyboard users everywhere. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
[tabindex]:focus-visible {
    outline: 2px solid transparent;
    box-shadow: var(--vpn-ring);
    border-radius: var(--vpn-r-xs);
}

/* Numeric UI reads better with tabular figures. */
.vpn-stat__value,
.vpn-sub__days,
.vpn-sub__id,
.vpn-plan__price,
.vpn-meterrow strong,
.vpn-table td {
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
}

/*
 * The shell grows with the screen instead of stopping at a laptop width.
 *
 * A fixed 1280px cap left a 1920px monitor two-thirds full and a 2560px one
 * exactly half empty, which is what made the pages feel small and unfinished.
 *
 * It is still capped, because removing the cap entirely is the opposite
 * mistake: a paragraph 2400px wide cannot be read, the eye loses the line on
 * the way back. So the shell scales with the viewport up to a ceiling, and the
 * few places that hold running text are constrained separately below by their
 * own measure rather than by the width of the window.
 */
.vpn-shell {
    /*
     * width:100% rather than a vw fraction: a percentage of the viewport would
     * leave a dead strip down both sides of a phone, which is the one screen
     * that can least afford it. The padding below does the breathing room, and
     * the max-width is only a ceiling for very large displays.
     */
    width: 100%;
    max-width: 2100px;
    margin-inline: auto;
    padding-inline: clamp(14px, 3vw, 48px);
}

/*
 * Running text keeps a readable measure however wide the shell gets. Around
 * 70 characters is the span the eye tracks comfortably; past that it starts
 * losing its place returning to the left edge.
 *
 * Grids, tables and card rows are deliberately not included: those are meant
 * to use the whole width, and are what makes a wide screen worth having.
 */
.vpn-page__lead,
.vpn-empty p,
.vpn-card__body > p,
.vpn-section__lead {
    max-width: 70ch;
}

/* ================================================================== */
/* 3. Frame                                                           */
/* ================================================================== */

.vpn-app {
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    padding-block: clamp(14px, 3vw, 30px) 44px;
}

/* The floating panel from the reference design. */
.vpn-frame {
    flex: 1;
    background: var(--vpn-surface);
    border: 1px solid var(--vpn-hairline);
    border-radius: var(--vpn-r-2xl);
    box-shadow: var(--vpn-shadow-xl);
    padding: clamp(18px, 2.6vw, 32px) clamp(16px, 3vw, 40px) clamp(30px, 4vw, 48px);
}

@media (max-width: 767.98px) {
    .vpn-app {
        padding: 0;
    }

    .vpn-frame {
        border: 0;
        border-radius: 0;
        box-shadow: none;
        background: transparent;
        padding: 14px 16px 104px;
    }
}

/* ---- Header ---- */

.vpn-header {
    display: flex;
    align-items: center;
    gap: 14px;
    padding-bottom: clamp(20px, 3vw, 34px);
}

.vpn-brand {
    display: inline-flex;
    align-items: center;
    gap: 11px;
    font-weight: 800;
    font-size: 1.0625rem;
    letter-spacing: -0.03em;
    color: var(--vpn-text);
    flex-shrink: 0;
}

.vpn-brand:hover {
    color: var(--vpn-brand-600);
}

.vpn-brand__mark {
    width: 36px;
    height: 36px;
    border-radius: 12px;
    background: var(--vpn-grad-brand);
    color: #fff;
    display: grid;
    place-items: center;
    box-shadow: var(--vpn-glow-brand);
    flex-shrink: 0;
    position: relative;
    overflow: hidden;
}

/* Glass highlight across the top of the mark. */
.vpn-brand__mark::after {
    content: "";
    position: absolute;
    inset: 0;
    background: var(--vpn-grad-sheen);
}

.vpn-brand__mark svg {
    width: 19px;
    height: 19px;
    position: relative;
}

.vpn-brand img {
    max-height: 36px;
    width: auto;
}

.vpn-nav {
    display: flex;
    align-items: center;
    gap: 2px;
    margin-inline: auto;
    padding: 4px;
    border-radius: var(--vpn-r-pill);
    background: var(--vpn-surface-3);
    border: 1px solid var(--vpn-hairline);
}

.vpn-nav__link {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 8px 15px;
    border-radius: var(--vpn-r-pill);
    font-size: .875rem;
    font-weight: 600;
    color: var(--vpn-text-2);
    white-space: nowrap;
    transition: color var(--vpn-fast) var(--vpn-ease),
                background-color var(--vpn-fast) var(--vpn-ease),
                box-shadow var(--vpn-fast) var(--vpn-ease);
}

.vpn-nav__link svg {
    width: 16px;
    height: 16px;
    opacity: .7;
    transition: opacity var(--vpn-fast) var(--vpn-ease);
}

.vpn-nav__link:hover {
    color: var(--vpn-text);
    background: color-mix(in srgb, var(--vpn-surface) 70%, transparent);
}

.vpn-nav__link:hover svg {
    opacity: 1;
}

.vpn-nav__link.is-active {
    color: var(--vpn-brand-700);
    background:
        radial-gradient(90% 130% at 50% -20%,
            color-mix(in srgb, var(--vpn-accent) 26%, transparent) 0%,
            color-mix(in srgb, var(--vpn-accent) 10%, transparent) 45%,
            transparent 75%),
        var(--vpn-surface);
    box-shadow:
        inset 0 0 0 1px color-mix(in srgb, var(--vpn-accent) 34%, transparent),
        var(--vpn-shadow-sm);
    font-weight: 650;
}

.vpn-nav__link.is-active svg {
    opacity: 1;
}

[data-bs-theme="dark"] .vpn-nav__link.is-active {
    color: var(--vpn-brand-300);
    background: var(--vpn-surface-2);
}

.vpn-header__actions {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-inline-start: auto;
}

.vpn-userpill {
    display: inline-flex;
    align-items: center;
    gap: 9px;
    padding: 5px 14px 5px 5px;
    border-radius: var(--vpn-r-pill);
    background: var(--vpn-surface);
    border: 1px solid var(--vpn-border);
    box-shadow: var(--vpn-shadow-sm);
    color: var(--vpn-text);
    font-weight: 600;
    font-size: .875rem;
    transition: box-shadow var(--vpn-med) var(--vpn-ease),
                border-color var(--vpn-med) var(--vpn-ease),
                transform var(--vpn-fast) var(--vpn-ease);
}

.vpn-userpill:hover {
    border-color: var(--vpn-brand-300);
    box-shadow: var(--vpn-shadow-md);
}

.vpn-userpill:active {
    transform: translateY(1px);
}

.vpn-userpill img,
.vpn-userpill .vpn-userpill__avatar {
    width: 30px;
    height: 30px;
    border-radius: 50%;
    object-fit: cover;
    flex-shrink: 0;
    box-shadow: 0 0 0 2px var(--vpn-surface), 0 0 0 3px var(--vpn-brand-200);
}

[data-bs-theme="dark"] .vpn-userpill img,
[data-bs-theme="dark"] .vpn-userpill .vpn-userpill__avatar {
    box-shadow: 0 0 0 2px var(--vpn-surface), 0 0 0 3px var(--vpn-border-strong);
}

.vpn-userpill__name {
    max-width: 130px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.vpn-iconbtn {
    width: 38px;
    height: 38px;
    display: grid;
    place-items: center;
    border-radius: 12px;
    border: 1px solid var(--vpn-border);
    background: var(--vpn-surface);
    color: var(--vpn-text-2);
    flex-shrink: 0;
    transition: color var(--vpn-fast) var(--vpn-ease),
                border-color var(--vpn-fast) var(--vpn-ease),
                background-color var(--vpn-fast) var(--vpn-ease),
                transform var(--vpn-fast) var(--vpn-ease);
}

.vpn-iconbtn:hover {
    color: var(--vpn-brand-600);
    border-color: var(--vpn-brand-300);
    background: var(--vpn-brand-50);
    transform: translateY(-1px);
}

[data-bs-theme="dark"] .vpn-iconbtn:hover {
    background: var(--vpn-surface-3);
    color: var(--vpn-brand-300);
}

.vpn-iconbtn svg {
    width: 17px;
    height: 17px;
}

/* ---- Page head ---- */

.vpn-pagehead {
    display: grid;
    grid-template-columns: minmax(200px, 1fr) minmax(0, 1.6fr);
    gap: clamp(14px, 2.5vw, 30px);
    align-items: center;
    margin-bottom: clamp(18px, 3vw, 30px);
}

@media (max-width: 991.98px) {
    .vpn-pagehead {
        grid-template-columns: 1fr;
        gap: 14px;
    }
}

.vpn-pagetitle {
    font-size: clamp(1.5rem, 1.15rem + 1.5vw, 2.125rem);
    font-weight: 800;
    letter-spacing: -0.035em;
    margin: 0;
}

.vpn-pagesub {
    color: var(--vpn-text-2);
    font-size: .9375rem;
    margin: 6px 0 0;
}

/* Expiry banner: pill action, message, dismiss. */
.vpn-banner {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 8px 16px 8px 8px;
    border-radius: var(--vpn-r-pill);
    background: var(--vpn-surface);
    border: 1px solid var(--vpn-border);
    box-shadow: var(--vpn-shadow-sm);
    font-size: .9375rem;
    color: var(--vpn-text-2);
}

.vpn-banner--warn {
    border-color: color-mix(in srgb, var(--vpn-pink-400) 42%, transparent);
    background:
        linear-gradient(90deg,
            color-mix(in srgb, var(--vpn-pink-400) 12%, transparent),
            transparent 58%),
        var(--vpn-surface);
}

.vpn-banner__close {
    margin-inline-start: auto;
    border: 0;
    background: none;
    color: var(--vpn-text-3);
    font-size: 1.25rem;
    line-height: 1;
    padding: 4px 8px;
    border-radius: var(--vpn-r-xs);
    transition: color var(--vpn-fast) var(--vpn-ease),
                background-color var(--vpn-fast) var(--vpn-ease);
}

.vpn-banner__close:hover {
    color: var(--vpn-danger);
    background: var(--vpn-danger-soft);
}

@media (max-width: 575.98px) {
    .vpn-banner {
        border-radius: var(--vpn-r-md);
        flex-wrap: wrap;
        padding: 12px;
    }
}

/* ---- Layout grid ---- */

.vpn-grid {
    display: grid;
    grid-template-columns: minmax(270px, 340px) minmax(0, 1fr);
    gap: clamp(16px, 2.2vw, 26px);
    align-items: start;
}

@media (max-width: 991.98px) {
    .vpn-grid {
        grid-template-columns: 1fr;
    }
}

.vpn-stack {
    display: grid;
    gap: clamp(16px, 2.2vw, 24px);
    min-width: 0;
}

/* Content beside a fixed-width companion (the QR panel on the config page).
   A class rather than an inline style, so the stacking rule below can win. */
.vpn-split {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: clamp(16px, 2.5vw, 28px);
    align-items: start;
}

@media (max-width: 767.98px) {
    .vpn-split {
        grid-template-columns: minmax(0, 1fr);
    }
}

/* ================================================================== */
/* 4. Surfaces                                                        */
/* ================================================================== */

.vpn-card {
    background: var(--vpn-surface);
    border: 1px solid var(--vpn-border);
    border-radius: var(--vpn-r-lg);
    box-shadow: var(--vpn-shadow-sm);
    overflow: hidden;
    transition: box-shadow var(--vpn-med) var(--vpn-ease),
                border-color var(--vpn-med) var(--vpn-ease);
}

.vpn-card:hover {
    box-shadow: var(--vpn-shadow-md);
}

.vpn-card__body {
    padding: clamp(16px, 2.2vw, 26px);
}

.vpn-card__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: clamp(16px, 2.2vw, 24px) clamp(16px, 2.2vw, 26px) 0;
}

.vpn-card__title {
    font-size: 1rem;
    font-weight: 700;
    letter-spacing: -0.02em;
    margin: 0;
}

.vpn-eyebrow {
    font-size: .6875rem;
    font-weight: 700;
    letter-spacing: .13em;
    text-transform: uppercase;
    color: var(--vpn-text-3);
    margin: 0 0 6px;
}

/* ---- Subscription hero ---- */

.vpn-sub {
    border-radius: var(--vpn-r-lg);
    background: var(--vpn-surface);
    border: 1px solid var(--vpn-border);
    box-shadow: var(--vpn-shadow-md);
    overflow: hidden;
}

.vpn-sub__top {
    position: relative;
    background: var(--vpn-grad-brand);
    color: #fff;
    padding: 28px 24px 34px;
    isolation: isolate;
    overflow: hidden;
}

/* Two soft light blobs plus a wave band, echoing the reference artwork
   without shipping an image. Animated with transform only. */
.vpn-sub__top::before {
    content: "";
    position: absolute;
    inset: -40% -20%;
    z-index: -2;
    background:
        radial-gradient(38% 42% at 26% 24%, rgba(255, 255, 255, .34), transparent 66%),
        radial-gradient(32% 38% at 82% 78%, rgba(255, 255, 255, .20), transparent 64%),
        radial-gradient(30% 30% at 68% 12%, rgba(244, 114, 182, .34), transparent 66%);
    animation: vpn-drift 22s var(--vpn-ease) infinite alternate;
}

/* Wave crest along the bottom edge. */
.vpn-sub__top::after {
    content: "";
    position: absolute;
    left: -12%;
    right: -12%;
    bottom: -58%;
    height: 90%;
    z-index: -1;
    border-radius: 46% 54% 42% 58% / 62% 58% 42% 38%;
    background: linear-gradient(180deg, rgba(255, 255, 255, .16), rgba(255, 255, 255, .05));
    animation: vpn-wave 18s var(--vpn-ease) infinite alternate;
}

@keyframes vpn-drift {
    from { transform: translate3d(-3%, -2%, 0) scale(1); }
    to   { transform: translate3d(4%, 3%, 0) scale(1.10); }
}

@keyframes vpn-wave {
    from { transform: translate3d(-2%, 0, 0) rotate(-2deg); }
    to   { transform: translate3d(2%, -3%, 0) rotate(2.5deg); }
}

.vpn-sub__icon {
    width: 46px;
    height: 46px;
    border-radius: 15px;
    background: rgba(255, 255, 255, .20);
    border: 1px solid rgba(255, 255, 255, .28);
    display: grid;
    place-items: center;
    margin: 0 auto 18px;
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    box-shadow: 0 6px 18px -6px rgba(0, 0, 0, .35);
}

.vpn-sub__icon svg {
    width: 23px;
    height: 23px;
}

.vpn-sub__label {
    text-align: center;
    font-size: .625rem;
    font-weight: 700;
    letter-spacing: .18em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, .82);
    margin: 0 0 10px;
}

.vpn-sub__id {
    text-align: center;
    font-size: clamp(1.0625rem, .95rem + .75vw, 1.4375rem);
    font-weight: 800;
    letter-spacing: .08em;
    line-height: 1.3;
    margin: 0;
    word-break: break-word;
    text-shadow: 0 1px 12px rgba(0, 0, 0, .18);
}

.vpn-sub__id .muted {
    opacity: .5;
    font-weight: 700;
    letter-spacing: .04em;
}

.vpn-sub__bottom {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 14px;
    padding: 18px 22px 20px;
    flex-wrap: wrap;
}

.vpn-sub__expiry {
    min-width: 0;
}

.vpn-sub__expiry-label {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    font-size: .6875rem;
    font-weight: 700;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--vpn-text-3);
    margin: 0 0 3px;
}

.vpn-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--vpn-text-3);
    flex-shrink: 0;
    position: relative;
}

.vpn-dot--ok { background: var(--vpn-success); }
.vpn-dot--warn { background: var(--vpn-warning); }
.vpn-dot--danger { background: var(--vpn-danger); }

/* Slow pulse on the urgent states only, so it signals rather than decorates. */
.vpn-dot--warn::after,
.vpn-dot--danger::after {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: 50%;
    background: inherit;
    animation: vpn-pulse 2.4s var(--vpn-ease-out) infinite;
}

@keyframes vpn-pulse {
    0%   { transform: scale(1); opacity: .7; }
    70%  { transform: scale(2.6); opacity: 0; }
    100% { transform: scale(2.6); opacity: 0; }
}

.vpn-sub__days {
    font-size: 1.75rem;
    font-weight: 800;
    letter-spacing: -0.04em;
    line-height: 1.05;
    margin: 0;
}

.vpn-sub__days small {
    font-size: .875rem;
    font-weight: 600;
    color: var(--vpn-text-2);
    letter-spacing: -0.01em;
}

/* ---- Meters ---- */

.vpn-meter {
    height: 9px;
    border-radius: var(--vpn-r-pill);
    background: var(--vpn-surface-sunken);
    overflow: hidden;
    box-shadow: inset 0 1px 2px rgba(15, 23, 42, .07);
}

[data-bs-theme="dark"] .vpn-meter {
    box-shadow: inset 0 1px 2px rgba(0, 0, 0, .45);
}

.vpn-meter__fill {
    height: 100%;
    border-radius: var(--vpn-r-pill);
    background: var(--vpn-grad-brand);
    position: relative;
    transition: width 600ms var(--vpn-ease-out);
}

.vpn-meter__fill::after {
    content: "";
    position: absolute;
    inset: 0;
    background: var(--vpn-grad-sheen);
    border-radius: inherit;
}

.vpn-meter__fill--warn { background: linear-gradient(90deg, #fbbf24, #f59e0b); }
.vpn-meter__fill--danger { background: linear-gradient(90deg, #fb7185, #ef4444); }

.vpn-meterrow {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
    font-size: .8125rem;
    color: var(--vpn-text-2);
    margin-bottom: 8px;
}

.vpn-meterrow strong {
    color: var(--vpn-text);
    font-weight: 700;
}

/* ---- Stats ---- */

.vpn-stats {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(136px, 1fr));
    gap: 12px;
}

.vpn-stat {
    position: relative;
    background: var(--vpn-surface);
    border: 1px solid var(--vpn-border);
    border-radius: var(--vpn-r-md);
    padding: 15px 16px;
    overflow: hidden;
    transition: transform var(--vpn-med) var(--vpn-ease),
                box-shadow var(--vpn-med) var(--vpn-ease),
                border-color var(--vpn-med) var(--vpn-ease);
}

/* Accent rail on the reading edge, revealed on hover. Logical, so it moves
   to the right-hand side in Arabic and Persian. */
.vpn-stat::before {
    content: "";
    position: absolute;
    inset-inline-start: 0;
    top: 0;
    bottom: 0;
    width: 3px;
    background: var(--vpn-grad-brand);
    opacity: 0;
    transition: opacity var(--vpn-med) var(--vpn-ease);
}

.vpn-stat:hover {
    transform: translateY(-2px);
    box-shadow: var(--vpn-shadow-md);
    border-color: var(--vpn-brand-200);
}

.vpn-stat:hover::before {
    opacity: 1;
}

.vpn-stat__label {
    font-size: .75rem;
    color: var(--vpn-text-3);
    font-weight: 600;
    margin: 0 0 4px;
}

.vpn-stat__value {
    font-size: 1.375rem;
    font-weight: 800;
    letter-spacing: -0.03em;
    line-height: 1.2;
    margin: 0;
}

/* ================================================================== */
/* 5. Controls                                                        */
/* ================================================================== */

.vpn-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 11px 22px;
    border-radius: var(--vpn-r-pill);
    border: 1px solid transparent;
    font-size: .875rem;
    font-weight: 700;
    line-height: 1.2;
    letter-spacing: -0.005em;
    cursor: pointer;
    white-space: nowrap;
    position: relative;
    overflow: hidden;
    transition: transform var(--vpn-fast) var(--vpn-ease),
                box-shadow var(--vpn-med) var(--vpn-ease),
                background-color var(--vpn-med) var(--vpn-ease),
                border-color var(--vpn-med) var(--vpn-ease),
                color var(--vpn-med) var(--vpn-ease);
}

.vpn-btn:hover {
    transform: translateY(-1px);
}

.vpn-btn:active {
    transform: translateY(0);
}

.vpn-btn svg {
    width: 16px;
    height: 16px;
    flex-shrink: 0;
}

.vpn-btn--primary {
    background: var(--vpn-grad-brand);
    color: #fff;
    box-shadow: var(--vpn-glow-brand);
}

.vpn-btn--primary::after {
    content: "";
    position: absolute;
    inset: 0;
    background: var(--vpn-grad-sheen);
    opacity: .9;
    pointer-events: none;
}

.vpn-btn--primary:hover {
    color: #fff;
    box-shadow: 0 12px 30px -6px rgba(99, 102, 241, .58),
                0 3px 8px -1px rgba(99, 102, 241, .34);
}

.vpn-btn--accent {
    background: var(--vpn-grad-accent);
    color: #fff;
    box-shadow: var(--vpn-glow-pink);
}

.vpn-btn--accent::after {
    content: "";
    position: absolute;
    inset: 0;
    background: var(--vpn-grad-sheen);
    opacity: .9;
    pointer-events: none;
}

.vpn-btn--accent:hover {
    color: #fff;
    box-shadow: 0 12px 30px -6px rgba(236, 72, 153, .55),
                0 3px 8px -1px rgba(236, 72, 153, .32);
}

.vpn-btn--ghost {
    background: var(--vpn-surface);
    border-color: var(--vpn-border-strong);
    color: var(--vpn-text);
}

.vpn-btn--ghost:hover {
    border-color: var(--vpn-brand-400);
    color: var(--vpn-brand-600);
    background: var(--vpn-brand-50);
    box-shadow: var(--vpn-shadow-sm);
}

[data-bs-theme="dark"] .vpn-btn--ghost:hover {
    background: var(--vpn-surface-3);
    color: var(--vpn-brand-300);
}

.vpn-btn--soft {
    background: var(--vpn-brand-50);
    color: var(--vpn-brand-700);
}

.vpn-btn--soft:hover {
    background: var(--vpn-brand-100);
    color: var(--vpn-brand-800);
}

[data-bs-theme="dark"] .vpn-btn--soft {
    background: rgba(99, 102, 241, .18);
    color: var(--vpn-brand-300);
}

[data-bs-theme="dark"] .vpn-btn--soft:hover {
    background: rgba(99, 102, 241, .26);
    color: var(--vpn-brand-200);
}

.vpn-btn--sm {
    padding: 8px 16px;
    font-size: .8125rem;
}

.vpn-btn--lg {
    padding: 14px 30px;
    font-size: .9375rem;
}

.vpn-btn--block {
    width: 100%;
}

.vpn-btn[disabled],
.vpn-btn.is-disabled {
    opacity: .5;
    pointer-events: none;
}

/* ---- Status pills ---- */

.vpn-pill {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 5px 12px;
    border-radius: var(--vpn-r-pill);
    font-size: .75rem;
    font-weight: 700;
    letter-spacing: .005em;
    background: var(--vpn-surface-3);
    color: var(--vpn-text-2);
    white-space: nowrap;
}

/* Leading dot gives the pill a status read at a glance. */
.vpn-pill::before {
    content: "";
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: currentColor;
    opacity: .85;
    flex-shrink: 0;
}

.vpn-pill--success { background: var(--vpn-success-soft); color: var(--vpn-success-ink); }
.vpn-pill--warning { background: var(--vpn-warning-soft); color: var(--vpn-warning-ink); }
.vpn-pill--danger  { background: var(--vpn-danger-soft);  color: var(--vpn-danger-ink); }
.vpn-pill--info    { background: var(--vpn-info-soft);    color: var(--vpn-info-ink); }

/* ---- Wizard steps ---- */

.vpn-step {
    display: flex;
    align-items: baseline;
    gap: 9px;
    margin: 0 0 18px;
    font-size: 1.125rem;
    font-weight: 700;
    letter-spacing: -0.025em;
}

.vpn-step__n {
    color: var(--vpn-brand-600);
}

[data-bs-theme="dark"] .vpn-step__n {
    color: var(--vpn-brand-300);
}

/* ---- Selection tiles ---- */

.vpn-tiles {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(146px, 1fr));
    gap: clamp(10px, 1.5vw, 16px);
}

@media (max-width: 420px) {
    .vpn-tiles {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

.vpn-tile {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 13px;
    min-height: 138px;
    padding: 20px 12px;
    border-radius: var(--vpn-r-md);
    border: 1px solid var(--vpn-border);
    background: var(--vpn-surface);
    color: var(--vpn-text);
    font-weight: 600;
    font-size: .875rem;
    text-align: center;
    cursor: pointer;
    overflow: hidden;
    transition: transform var(--vpn-med) var(--vpn-ease),
                box-shadow var(--vpn-med) var(--vpn-ease),
                border-color var(--vpn-med) var(--vpn-ease),
                color var(--vpn-med) var(--vpn-ease);
}

/* Gradient wash that fades in behind the content on hover. */
.vpn-tile::before {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(160deg,
        color-mix(in srgb, var(--vpn-brand-500) 10%, transparent),
        transparent 62%);
    opacity: 0;
    transition: opacity var(--vpn-med) var(--vpn-ease);
}

.vpn-tile:hover {
    transform: translateY(-3px);
    box-shadow: var(--vpn-shadow-lg);
    border-color: var(--vpn-brand-300);
    color: var(--vpn-text);
}

.vpn-tile:hover::before {
    opacity: 1;
}

.vpn-tile__icon,
.vpn-tile > span {
    position: relative;
}

.vpn-tile__icon {
    width: 44px;
    height: 44px;
    display: grid;
    place-items: center;
    color: var(--vpn-text-2);
    transition: color var(--vpn-med) var(--vpn-ease),
                transform var(--vpn-med) var(--vpn-ease-out);
}

.vpn-tile__icon svg {
    width: 36px;
    height: 36px;
}

.vpn-tile:hover .vpn-tile__icon {
    color: var(--vpn-brand-600);
    transform: scale(1.06);
}

/* Selected state -- the highlighted card from the reference design. */
.vpn-tile.is-selected {
    background: var(--vpn-grad-accent);
    border-color: transparent;
    color: #fff;
    box-shadow: 0 14px 34px -10px rgba(168, 85, 247, .58),
                0 3px 10px -2px rgba(168, 85, 247, .32);
}

.vpn-tile.is-selected::before {
    opacity: 0;
}

.vpn-tile.is-selected::after {
    content: "";
    position: absolute;
    inset: 0;
    background: var(--vpn-grad-sheen);
    pointer-events: none;
}

.vpn-tile.is-selected .vpn-tile__icon,
.vpn-tile.is-selected:hover .vpn-tile__icon {
    color: #fff;
}

.vpn-tile input {
    position: absolute;
    opacity: 0;
    pointer-events: none;
}

.vpn-tile:focus-visible {
    box-shadow: var(--vpn-ring), var(--vpn-shadow-md);
}

/* ---- Copy field / QR ---- */

.vpn-copyfield {
    display: flex;
    align-items: stretch;
    gap: 8px;
    flex-wrap: wrap;
}

.vpn-copyfield__input {
    flex: 1 1 240px;
    min-width: 0;
    padding: 12px 15px;
    border-radius: var(--vpn-r-sm);
    border: 1px solid var(--vpn-border);
    background: var(--vpn-surface-sunken);
    color: var(--vpn-text);
    font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
    font-size: .8125rem;
    line-height: 1.5;
    overflow-x: auto;
    white-space: nowrap;
    scrollbar-width: thin;
}

.vpn-qr {
    display: grid;
    place-items: center;
    padding: 16px;
    background: #fff;
    border-radius: var(--vpn-r-md);
    border: 1px solid var(--vpn-border);
    box-shadow: var(--vpn-shadow-sm);
    width: fit-content;
    margin-inline: auto;
}

.vpn-qr canvas,
.vpn-qr img,
.vpn-qr svg {
    display: block;
    width: 190px;
    height: 190px;
}

/* ---- Forms ---- */

.vpn-field {
    margin-bottom: 16px;
}

.vpn-field label {
    display: block;
    font-size: .8125rem;
    font-weight: 600;
    color: var(--vpn-text-2);
    margin-bottom: 7px;
}

.vpn-input,
.vpn-field input:not([type="checkbox"]):not([type="radio"]),
.vpn-field select,
.vpn-field textarea {
    width: 100%;
    padding: 11px 15px;
    border-radius: var(--vpn-r-sm);
    border: 1px solid var(--vpn-border);
    background: var(--vpn-surface);
    color: var(--vpn-text);
    font-size: .9375rem;
    font-family: inherit;
    transition: border-color var(--vpn-fast) var(--vpn-ease),
                box-shadow var(--vpn-fast) var(--vpn-ease);
}

.vpn-input:focus,
.vpn-field input:focus,
.vpn-field select:focus,
.vpn-field textarea:focus {
    outline: none;
    border-color: var(--vpn-brand-500);
    box-shadow: var(--vpn-ring);
}

/* ---- Mobile tab bar ---- */

.vpn-tabbar {
    display: none;
}

@media (max-width: 767.98px) {
    .vpn-tabbar {
        position: fixed;
        left: 0;
        right: 0;
        bottom: 0;
        z-index: 1030;
        display: grid;
        grid-auto-flow: column;
        grid-auto-columns: 1fr;
        gap: 2px;
        padding: 8px 6px calc(8px + env(safe-area-inset-bottom));
        /* Solid first: browsers without color-mix keep an opaque bar rather
           than a transparent one with content scrolling behind it. */
        background: var(--vpn-surface);
        background: color-mix(in srgb, var(--vpn-surface) 88%, transparent);
        backdrop-filter: blur(16px) saturate(180%);
        -webkit-backdrop-filter: blur(16px) saturate(180%);
        border-top: 1px solid var(--vpn-border);
        box-shadow: 0 -6px 24px rgba(30, 41, 90, .10);
    }

    .vpn-tabbar__item {
        display: flex;
        flex-direction: column;
        align-items: center;
        gap: 4px;
        padding: 7px 4px;
        border-radius: var(--vpn-r-sm);
        font-size: .625rem;
        font-weight: 600;
        color: var(--vpn-text-3);
        transition: color var(--vpn-fast) var(--vpn-ease),
                    background-color var(--vpn-fast) var(--vpn-ease);
    }

    .vpn-tabbar__item svg {
        width: 21px;
        height: 21px;
    }

    .vpn-tabbar__item.is-active {
        color: var(--vpn-brand-600);
        background: var(--vpn-brand-50);
    }

    [data-bs-theme="dark"] .vpn-tabbar__item.is-active {
        color: var(--vpn-brand-300);
        background: rgba(99, 102, 241, .16);
    }

    /* The tab bar replaces the desktop nav on small screens. */
    .vpn-nav {
        display: none;
    }
}

/* ================================================================== */
/* 6. Content                                                         */
/* ================================================================== */

.vpn-plans {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(268px, 1fr));
    gap: clamp(14px, 2vw, 22px);
    align-items: stretch;
}

.vpn-plan {
    position: relative;
    display: flex;
    flex-direction: column;
    background: var(--vpn-surface);
    border: 1px solid var(--vpn-border);
    border-radius: var(--vpn-r-lg);
    padding: clamp(20px, 2.4vw, 28px);
    box-shadow: var(--vpn-shadow-sm);
    overflow: hidden;
    transition: transform var(--vpn-med) var(--vpn-ease),
                box-shadow var(--vpn-med) var(--vpn-ease),
                border-color var(--vpn-med) var(--vpn-ease);
}

.vpn-plan:hover {
    transform: translateY(-4px);
    box-shadow: var(--vpn-shadow-lg);
    border-color: var(--vpn-brand-200);
}

/* Featured plan carries the brand gradient, as the price anchor. */
.vpn-plan--featured {
    border-color: transparent;
    background: var(--vpn-grad-brand);
    color: #fff;
    box-shadow: var(--vpn-glow-brand);
}

.vpn-plan--featured::before {
    content: "";
    position: absolute;
    inset: -50% -30% auto -30%;
    height: 120%;
    background: radial-gradient(40% 46% at 30% 20%, rgba(255, 255, 255, .26), transparent 68%);
    pointer-events: none;
}

.vpn-plan--featured:hover {
    box-shadow: 0 16px 40px -8px rgba(99, 102, 241, .6),
                0 4px 12px -2px rgba(99, 102, 241, .36);
}

.vpn-plan--featured .vpn-plan__name,
.vpn-plan--featured .vpn-plan__price,
.vpn-plan--featured .vpn-plan__spec strong {
    color: #fff;
}

.vpn-plan--featured .vpn-plan__desc,
.vpn-plan--featured .vpn-plan__period,
.vpn-plan--featured .vpn-plan__spec {
    color: rgba(255, 255, 255, .84);
}

.vpn-plan--featured .vpn-plan__specs {
    border-color: rgba(255, 255, 255, .22);
}

.vpn-plan--featured .vpn-btn--ghost {
    background: rgba(255, 255, 255, .16);
    border-color: rgba(255, 255, 255, .34);
    color: #fff;
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
}

.vpn-plan--featured .vpn-btn--ghost:hover {
    background: #fff;
    border-color: #fff;
    color: var(--vpn-brand-700);
}

.vpn-plan > * {
    position: relative;
}

.vpn-plan__badge {
    position: absolute;
    top: 16px;
    inset-inline-end: 16px;
    padding: 5px 12px;
    border-radius: var(--vpn-r-pill);
    background: rgba(255, 255, 255, .22);
    border: 1px solid rgba(255, 255, 255, .3);
    color: #fff;
    font-size: .6875rem;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
}

.vpn-plan__name {
    font-size: 1.1875rem;
    font-weight: 800;
    letter-spacing: -0.03em;
    margin: 0 0 3px;
}

.vpn-plan__desc {
    font-size: .875rem;
    color: var(--vpn-text-2);
    margin: 0 0 18px;
}

.vpn-plan__price {
    font-size: 2.375rem;
    font-weight: 800;
    letter-spacing: -0.045em;
    line-height: 1.05;
    margin: 0;
}

.vpn-plan__period {
    font-size: .8125rem;
    color: var(--vpn-text-2);
    font-weight: 600;
}

.vpn-plan__specs {
    list-style: none;
    margin: 20px 0;
    padding: 18px 0 0;
    border-top: 1px solid var(--vpn-border);
    display: grid;
    gap: 11px;
    flex: 1;
}

.vpn-plan__spec {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: .875rem;
    color: var(--vpn-text-2);
}

.vpn-plan__spec svg {
    width: 17px;
    height: 17px;
    flex-shrink: 0;
    opacity: .85;
}

.vpn-plan__spec strong {
    color: var(--vpn-text);
    font-weight: 700;
}

/* ---- Lists & tables ---- */

.vpn-list {
    display: grid;
}

.vpn-listitem {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 14px;
    padding: 15px 0;
    border-bottom: 1px solid var(--vpn-border);
    color: var(--vpn-text);
    flex-wrap: wrap;
}

.vpn-listitem:last-child {
    border-bottom: 0;
}

.vpn-listitem__main {
    min-width: 0;
}

.vpn-listitem__title {
    font-weight: 700;
    font-size: .9375rem;
    margin: 0 0 2px;
}

.vpn-listitem__meta {
    font-size: .8125rem;
    color: var(--vpn-text-3);
    margin: 0;
}

.vpn-table-wrap {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    margin-inline: calc(clamp(16px, 2.2vw, 26px) * -1);
    padding-inline: clamp(16px, 2.2vw, 26px);
}

.vpn-table {
    width: 100%;
    border-collapse: collapse;
    font-size: .875rem;
    min-width: 520px;
}

.vpn-table th {
    text-align: start;
    font-size: .6875rem;
    font-weight: 700;
    letter-spacing: .09em;
    text-transform: uppercase;
    color: var(--vpn-text-3);
    padding: 0 14px 12px;
    white-space: nowrap;
}

.vpn-table td {
    padding: 14px;
    border-top: 1px solid var(--vpn-border);
    color: var(--vpn-text-2);
    vertical-align: middle;
}

.vpn-table td strong,
.vpn-table td a {
    color: var(--vpn-text);
    font-weight: 600;
}

.vpn-table td a:hover {
    color: var(--vpn-brand-600);
}

.vpn-table tbody tr {
    transition: background-color var(--vpn-fast) var(--vpn-ease);
}

.vpn-table tbody tr:hover td {
    background: var(--vpn-surface-2);
}

.vpn-table tbody tr:first-child td {
    border-top-color: var(--vpn-border);
}

/* ---- Empty state ---- */

.vpn-empty {
    text-align: center;
    padding: clamp(28px, 5vw, 52px) 20px;
    color: var(--vpn-text-2);
}

.vpn-empty__icon {
    width: 64px;
    height: 64px;
    border-radius: 20px;
    background: linear-gradient(150deg, var(--vpn-brand-50), var(--vpn-surface-3));
    border: 1px solid var(--vpn-border);
    display: grid;
    place-items: center;
    margin: 0 auto 18px;
    color: var(--vpn-brand-400);
}

[data-bs-theme="dark"] .vpn-empty__icon {
    background: linear-gradient(150deg, rgba(99, 102, 241, .16), var(--vpn-surface-3));
}

.vpn-empty__icon svg {
    width: 28px;
    height: 28px;
}

.vpn-empty__title {
    font-weight: 700;
    font-size: 1.0625rem;
    color: var(--vpn-text);
    margin: 0 0 6px;
    letter-spacing: -0.02em;
}

/* ---- Auth ---- */

.vpn-auth {
    min-height: 100vh;
    display: grid;
    place-items: center;
    padding: 32px 16px;
}

.vpn-auth__card,
.vpn-auth .card {
    width: 100%;
    max-width: 440px;
    background: var(--vpn-surface);
    border: 1px solid var(--vpn-hairline);
    border-radius: var(--vpn-r-xl);
    box-shadow: var(--vpn-shadow-xl);
    padding: clamp(26px, 4vw, 40px);
}

.vpn-auth__title {
    font-size: 1.5rem;
    font-weight: 800;
    letter-spacing: -0.03em;
    margin: 0 0 4px;
    text-align: center;
}

.vpn-auth__sub {
    color: var(--vpn-text-2);
    font-size: .9375rem;
    text-align: center;
    margin: 0 0 26px;
}

/* ================================================================== */
/* 7. Payments (markup from Vpnpay\PaymentRenderer)                   */
/* ================================================================== */

.vpnpay-pay {
    max-width: 740px;
}

.vpnpay-pay__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
    padding-bottom: 20px;
    margin-bottom: 20px;
    border-bottom: 1px solid var(--vpn-border);
}

.vpnpay-pay__title {
    font-size: 1.3125rem;
    font-weight: 800;
    letter-spacing: -0.03em;
    margin: 0;
}

.vpnpay-pay__amount {
    text-align: end;
}

.vpnpay-pay__amount-label {
    display: block;
    font-size: .6875rem;
    font-weight: 700;
    letter-spacing: .11em;
    text-transform: uppercase;
    color: var(--vpn-text-3);
    margin-bottom: 2px;
}

.vpnpay-pay__amount strong {
    font-size: 1.5rem;
    font-weight: 800;
    letter-spacing: -0.03em;
    background: var(--vpn-grad-brand);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
}

.vpnpay-pay__notice {
    padding: 13px 16px;
    border-radius: var(--vpn-r-sm);
    background: var(--vpn-warning-soft);
    color: var(--vpn-warning-ink);
    font-size: .875rem;
    font-weight: 500;
    margin-bottom: 18px;
}

/* Shown instead of the bank details when a customer is not entitled to them:
   a locked state that explains itself, not an error. */
.vpnpay-pay--blocked .vpnpay-pay__head {
    margin-bottom: 4px;
}

.vpnpay-blocked {
    text-align: center;
    padding: 26px 22px 28px;
    border: 1.5px dashed var(--vpn-border);
    border-radius: var(--vpn-r-md);
    background: var(--vpn-surface-2);
}

.vpnpay-blocked__icon {
    width: 52px;
    height: 52px;
    margin: 0 auto 16px;
    display: grid;
    place-items: center;
    border-radius: 50%;
    background: var(--vpn-warning-soft);
    color: var(--vpn-warning-ink);
}

.vpnpay-blocked__icon svg {
    width: 26px;
    height: 26px;
}

.vpnpay-blocked__text {
    font-size: .9375rem;
    line-height: 1.7;
    color: var(--vpn-text-2);
    max-width: 46ch;
    margin: 0 auto 18px;
}

.vpnpay-blocked__steps {
    text-align: start;
    max-width: 42ch;
    margin: 0 auto 22px;
    padding-inline-start: 22px;
    font-size: .875rem;
    line-height: 1.9;
    color: var(--vpn-text-2);
}

.vpnpay-blocked__steps li::marker {
    font-weight: 700;
    color: var(--vpn-brand-500);
}

/* The renderer emits raw HTML, so it cannot use the .vpn-btn component. */
.vpnpay-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 44px;
    padding: 11px 22px;
    border: 0;
    border-radius: var(--vpn-r-sm);
    font-size: .9375rem;
    font-weight: 650;
    text-decoration: none;
    cursor: pointer;
    transition: transform var(--vpn-fast) var(--vpn-ease), box-shadow var(--vpn-med) var(--vpn-ease);
}

.vpnpay-btn--primary {
    background: var(--vpn-grad-brand);
    color: #fff;
    box-shadow: var(--vpn-shadow-sm);
}

.vpnpay-btn--primary:hover {
    transform: translateY(-1px);
    box-shadow: var(--vpn-shadow-md);
    color: #fff;
}

.vpnpay-pay__instructions {
    font-size: .9375rem;
    color: var(--vpn-text-2);
    margin-bottom: 20px;
    line-height: 1.7;
}

.vpnpay-pay__details {
    margin: 0 0 20px;
    border: 1px solid var(--vpn-border);
    border-radius: var(--vpn-r-md);
    overflow: hidden;
    background: var(--vpn-surface-2);
}

.vpnpay-pay__row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 13px 16px;
    border-bottom: 1px solid var(--vpn-border);
    flex-wrap: wrap;
}

.vpnpay-pay__row:last-child {
    border-bottom: 0;
}

.vpnpay-pay__row dt {
    flex: 0 0 auto;
    min-width: 150px;
    font-size: .8125rem;
    font-weight: 600;
    color: var(--vpn-text-3);
    margin: 0;
}

.vpnpay-pay__row dd {
    margin: 0;
    display: flex;
    align-items: center;
    gap: 10px;
    flex: 1 1 200px;
    min-width: 0;
}

.vpnpay-pay__value {
    font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
    font-size: .875rem;
    font-weight: 600;
    color: var(--vpn-text);
    word-break: break-all;
}

.vpnpay-copy {
    border: 1px solid var(--vpn-border-strong);
    background: var(--vpn-surface);
    color: var(--vpn-text-2);
    border-radius: var(--vpn-r-pill);
    padding: 5px 13px;
    font-size: .75rem;
    font-weight: 700;
    cursor: pointer;
    flex-shrink: 0;
    transition: color var(--vpn-fast) var(--vpn-ease),
                border-color var(--vpn-fast) var(--vpn-ease),
                background-color var(--vpn-fast) var(--vpn-ease);
}

.vpnpay-copy:hover {
    border-color: var(--vpn-brand-400);
    color: var(--vpn-brand-600);
    background: var(--vpn-brand-50);
}

.vpnpay-pay__figure {
    margin: 0 0 20px;
    text-align: center;
}

.vpnpay-pay__figure img {
    max-width: 210px;
    width: 100%;
    height: auto;
    border-radius: var(--vpn-r-md);
    border: 1px solid var(--vpn-border);
    background: #fff;
    padding: 10px;
    box-shadow: var(--vpn-shadow-sm);
}

.vpnpay-pay__figure figcaption {
    font-size: .75rem;
    color: var(--vpn-text-3);
    margin-top: 9px;
}

.vpnpay-choices {
    display: flex;
    gap: 9px;
    flex-wrap: wrap;
    margin-bottom: 20px;
}

.vpnpay-choice {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 1px;
    padding: 11px 18px;
    border-radius: var(--vpn-r-sm);
    border: 1px solid var(--vpn-border);
    background: var(--vpn-surface);
    color: var(--vpn-text-2);
    cursor: pointer;
    font-size: .875rem;
    transition: transform var(--vpn-fast) var(--vpn-ease),
                border-color var(--vpn-med) var(--vpn-ease),
                box-shadow var(--vpn-med) var(--vpn-ease),
                color var(--vpn-med) var(--vpn-ease);
}

.vpnpay-choice:hover {
    border-color: var(--vpn-brand-300);
    transform: translateY(-1px);
}

.vpnpay-choice.is-active {
    background: var(--vpn-grad-brand);
    border-color: transparent;
    color: #fff;
    box-shadow: var(--vpn-glow-brand);
}

.vpnpay-choice__name {
    font-weight: 700;
}

.vpnpay-choice__net {
    font-size: .6875rem;
    opacity: .78;
}

.vpnpay-panel {
    display: none;
}

.vpnpay-panel.is-active {
    display: block;
    animation: vpn-fade-up var(--vpn-med) var(--vpn-ease-out);
}

@keyframes vpn-fade-up {
    from { opacity: 0; transform: translate3d(0, 6px, 0); }
    to   { opacity: 1; transform: none; }
}

.vpnpay-links {
    display: grid;
    gap: 12px;
    margin-bottom: 22px;
}

.vpnpay-link {
    display: flex;
    align-items: center;
    gap: 16px;
    padding: 17px;
    border: 1px solid var(--vpn-border);
    border-radius: var(--vpn-r-md);
    background: var(--vpn-surface);
    flex-wrap: wrap;
    transition: transform var(--vpn-med) var(--vpn-ease),
                border-color var(--vpn-med) var(--vpn-ease),
                box-shadow var(--vpn-med) var(--vpn-ease);
}

.vpnpay-link:hover {
    border-color: var(--vpn-brand-300);
    box-shadow: var(--vpn-shadow-md);
    transform: translateY(-2px);
}

.vpnpay-link__logo {
    width: 48px;
    height: 48px;
    object-fit: contain;
    border-radius: var(--vpn-r-sm);
    flex-shrink: 0;
    background: var(--vpn-surface-2);
}

.vpnpay-link__body {
    flex: 1 1 200px;
    min-width: 0;
}

.vpnpay-link__name {
    font-size: 1rem;
    font-weight: 700;
    letter-spacing: -0.02em;
    margin: 0;
}

.vpnpay-link__desc,
.vpnpay-link__hint {
    font-size: .8125rem;
    color: var(--vpn-text-2);
    margin: 4px 0 0;
}

.vpnpay-link__cta {
    margin-inline-start: auto;
    display: inline-flex;
    align-items: center;
    padding: 11px 26px;
    border-radius: var(--vpn-r-pill);
    background: var(--vpn-grad-brand);
    color: #fff;
    font-weight: 700;
    font-size: .875rem;
    box-shadow: var(--vpn-glow-brand);
    flex-shrink: 0;
    transition: box-shadow var(--vpn-med) var(--vpn-ease),
                transform var(--vpn-fast) var(--vpn-ease);
}

.vpnpay-link__cta:hover {
    color: #fff;
    transform: translateY(-1px);
    box-shadow: 0 12px 30px -6px rgba(99, 102, 241, .58);
}

.vpnpay-form {
    border: 1px solid var(--vpn-border);
    border-radius: var(--vpn-r-md);
    padding: clamp(18px, 2.4vw, 24px);
    background: var(--vpn-surface-2);
}

.vpnpay-form__title {
    font-size: 1.0625rem;
    font-weight: 700;
    letter-spacing: -0.02em;
    margin: 0 0 6px;
}

.vpnpay-form__hint {
    font-size: .875rem;
    color: var(--vpn-text-2);
    margin: 0 0 18px;
    line-height: 1.65;
}

/* Two-up field layout on wider screens, stacking on phones. */
.vpnpay-form__grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 0 14px;
}

.vpnpay-form__field {
    margin-bottom: 15px;
}

.vpnpay-form__field select {
    width: 100%;
    padding: 11px 15px;
    border-radius: var(--vpn-r-sm);
    border: 1px solid var(--vpn-border);
    background: var(--vpn-surface);
    color: var(--vpn-text);
    font-size: .9375rem;
    font-family: inherit;
    cursor: pointer;
    transition: border-color var(--vpn-fast) var(--vpn-ease),
                box-shadow var(--vpn-fast) var(--vpn-ease);
}

.vpnpay-form__field select:focus {
    outline: none;
    border-color: var(--vpn-brand-500);
    box-shadow: var(--vpn-ring);
}

/* ---- Previous submission summary ---- */

.vpnpay-status {
    border: 1px solid var(--vpn-border);
    border-radius: var(--vpn-r-md);
    background: var(--vpn-surface-2);
    padding: 16px 18px;
}

.vpnpay-status--rejected {
    border-color: color-mix(in srgb, var(--vpn-danger) 35%, transparent);
}

.vpnpay-status--info_requested {
    border-color: color-mix(in srgb, var(--vpn-info) 35%, transparent);
}

.vpnpay-status--approved {
    border-color: color-mix(in srgb, var(--vpn-success) 35%, transparent);
}

.vpnpay-status__head {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    margin-bottom: 12px;
}

.vpnpay-status__time {
    font-size: .8125rem;
    color: var(--vpn-text-3);
    margin-inline-start: auto;
}

.vpnpay-status__list {
    display: grid;
    gap: 9px;
    margin: 0;
}

.vpnpay-status__list > div {
    display: flex;
    gap: 12px;
    flex-wrap: wrap;
}

.vpnpay-status__list dt {
    flex: 0 0 auto;
    min-width: 150px;
    font-size: .8125rem;
    font-weight: 600;
    color: var(--vpn-text-3);
    margin: 0;
}

.vpnpay-status__list dd {
    margin: 0;
    flex: 1 1 200px;
    min-width: 0;
    font-size: .875rem;
    color: var(--vpn-text);
    word-break: break-word;
}

.vpnpay-status__list code {
    font-size: .8125rem;
    color: var(--vpn-text);
}

.vpnpay-status__note {
    font-size: .875rem;
    color: var(--vpn-text-2);
    margin-top: 12px;
}

.vpnpay-form__field label {
    display: block;
    font-size: .8125rem;
    font-weight: 600;
    color: var(--vpn-text-2);
    margin-bottom: 7px;
}

.vpnpay-form__field input,
.vpnpay-form__field textarea {
    width: 100%;
    padding: 11px 15px;
    border-radius: var(--vpn-r-sm);
    border: 1px solid var(--vpn-border);
    background: var(--vpn-surface);
    color: var(--vpn-text);
    font-size: .9375rem;
    font-family: inherit;
    transition: border-color var(--vpn-fast) var(--vpn-ease),
                box-shadow var(--vpn-fast) var(--vpn-ease);
}

.vpnpay-form__field input:focus,
.vpnpay-form__field textarea:focus {
    outline: none;
    border-color: var(--vpn-brand-500);
    box-shadow: var(--vpn-ring);
}

.vpnpay-form__field input[type="file"] {
    padding: 9px 12px;
    cursor: pointer;
}

.vpnpay-form__field small {
    display: block;
    font-size: .75rem;
    color: var(--vpn-text-3);
    margin-top: 6px;
}

.vpnpay-req {
    color: var(--vpn-danger);
}

.vpnpay-form__submit {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 13px 28px;
    border: 0;
    border-radius: var(--vpn-r-pill);
    background: var(--vpn-grad-brand);
    color: #fff;
    font-weight: 700;
    font-size: .9375rem;
    font-family: inherit;
    cursor: pointer;
    box-shadow: var(--vpn-glow-brand);
    transition: box-shadow var(--vpn-med) var(--vpn-ease),
                transform var(--vpn-fast) var(--vpn-ease);
}

.vpnpay-form__submit:hover:not([disabled]) {
    transform: translateY(-1px);
    box-shadow: 0 12px 30px -6px rgba(99, 102, 241, .58);
}

.vpnpay-form__submit[disabled] {
    opacity: .5;
    cursor: not-allowed;
}

.vpnpay-form__result {
    margin-top: 15px;
    font-size: .875rem;
    font-weight: 600;
}

.vpnpay-form__result.is-success,
.vpnpay-form__result.is-error {
    padding: 13px 16px;
    border-radius: var(--vpn-r-sm);
    animation: vpn-fade-up var(--vpn-med) var(--vpn-ease-out);
}

.vpnpay-form__result.is-success {
    background: var(--vpn-success-soft);
    color: var(--vpn-success-ink);
}

.vpnpay-form__result.is-error {
    background: var(--vpn-danger-soft);
    color: var(--vpn-danger-ink);
}

/* ------------------------------------------------------------------ */
/* Cart & checkout (markup from the Orderbutton module)                */
/* ------------------------------------------------------------------ */

/* This flow ships as a Bootstrap accordion with stock tables and radio
   buttons. The rules below restyle it in place - the module templates are
   left untouched so a FOSSBilling update cannot conflict with them. */

#vpn-cart .accordion {
    --bs-accordion-border-color: transparent;
    --bs-accordion-bg: transparent;
    --bs-accordion-btn-focus-box-shadow: none;
    display: grid;
    gap: 10px;
}

#vpn-cart .accordion-item {
    background: var(--vpn-surface);
    border: 1px solid var(--vpn-border);
    border-radius: var(--vpn-r-md) !important;
    overflow: hidden;
}

#vpn-cart .accordion-header {
    margin: 0;
}

#vpn-cart .accordion-button {
    background: var(--vpn-surface);
    color: var(--vpn-text);
    font-weight: 700;
    font-size: .9375rem;
    letter-spacing: -0.015em;
    padding: 15px 18px;
    box-shadow: none;
    gap: 10px;
}

#vpn-cart .accordion-button:not(.collapsed) {
    background: var(--vpn-brand-50);
    color: var(--vpn-brand-700);
}

[data-bs-theme="dark"] #vpn-cart .accordion-button:not(.collapsed) {
    background: rgba(99, 102, 241, .16);
    color: var(--vpn-brand-300);
}

#vpn-cart .accordion-button::after {
    filter: none;
    opacity: .5;
}

#vpn-cart .accordion-button .icon {
    width: 18px;
    height: 18px;
    opacity: .7;
}

#vpn-cart .accordion-body {
    padding: 18px;
}

/* Step counters ("3 Items", "1") become pills rather than raw badges. */
#vpn-cart .badge {
    background: var(--vpn-grad-brand) !important;
    color: #fff;
    font-size: .6875rem;
    padding: .35em .75em;
}

/* Cart table */
#vpn-cart .table {
    --bs-table-bg: transparent;
    margin-bottom: 0;
    border-collapse: separate;
    border-spacing: 0;
}

#vpn-cart .table,
#vpn-cart .table-bordered > :not(caption) > * > * {
    border-color: var(--vpn-border);
}

#vpn-cart .table thead th {
    background: transparent;
    border-bottom: 1px solid var(--vpn-border);
    font-size: .6875rem;
    font-weight: 700;
    letter-spacing: .09em;
    text-transform: uppercase;
    color: var(--vpn-text-3);
    padding: 0 14px 10px;
}

#vpn-cart .table tbody td {
    background: transparent;
    border-top: 1px solid var(--vpn-border);
    border-bottom: 0;
    padding: 14px;
    color: var(--vpn-text);
    vertical-align: middle;
}

#vpn-cart .table-striped > tbody > tr:nth-of-type(odd) > * {
    --bs-table-accent-bg: transparent;
    box-shadow: none;
    color: var(--vpn-text);
}

/* The order total, given the weight it deserves. */
#vpn-cart .table tbody tr:last-child td {
    font-weight: 700;
}

#vpn-cart .table .btn-danger,
#vpn-cart .table .btn-dark {
    background: var(--vpn-surface-3);
    border: 1px solid var(--vpn-border);
    color: var(--vpn-text-3);
    border-radius: 50%;
    width: 32px;
    height: 32px;
    padding: 0;
    display: inline-grid;
    place-items: center;
}

#vpn-cart .table .btn-danger:hover,
#vpn-cart .table .btn-dark:hover {
    background: var(--vpn-danger-soft);
    border-color: transparent;
    color: var(--vpn-danger);
}

/* ---- Payment method picker ----------------------------------------
   The module renders each option as a radio + a label carrying the mark as an
   inline background-image, with the gateway name only in a tooltip. These rules
   turn that into a proper tile: a physical icon plate, a visible caption pulled
   from the tooltip attribute, and a clear selected state - all without editing
   the module template. */

.invoice-gateway {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 106px;
    padding: 16px 10px 34px !important;
    border: 1.5px solid var(--vpn-border);
    border-radius: 20px;
    background:
        linear-gradient(180deg, rgba(255, 255, 255, .55), rgba(255, 255, 255, 0) 42%),
        var(--vpn-surface);
    box-shadow: var(--vpn-shadow-xs);
    cursor: pointer;
    /* Slight overshoot on settle: the selection feels physical rather than abrupt. */
    transition: transform 220ms cubic-bezier(.34, 1.42, .64, 1),
                border-color 200ms var(--vpn-ease),
                box-shadow 260ms var(--vpn-ease);
}

[data-bs-theme="dark"] .invoice-gateway {
    background:
        linear-gradient(180deg, rgba(255, 255, 255, .06), rgba(255, 255, 255, 0) 42%),
        var(--vpn-surface-2);
}

.invoice-gateway:hover {
    transform: translateY(-3px);
    border-color: var(--vpn-border-strong);
    box-shadow: var(--vpn-shadow-lg);
}

/* The label is the whole hit target and carries the icon plate. */
.invoice-gateway .btn {
    position: static;
    border: 0;
    padding: 0;
    margin: 0;
    /* Beat the template's inline width/height so the plate is optically sized. */
    width: 56px !important;
    height: 56px !important;
    background-size: 56px 56px !important;
    background-position: center !important;
    border-radius: 15px;
    /* Grounds the icon plate so it reads as a physical object on the tile. */
    filter: drop-shadow(0 4px 10px rgba(30, 41, 90, .22));
    transition: transform 220ms cubic-bezier(.34, 1.42, .64, 1);
}

.invoice-gateway:hover .btn {
    transform: scale(1.05);
}

.invoice-gateway .btn::after {
    /* Caption, taken from the tooltip the template already provides. */
    content: attr(data-bs-title);
    position: absolute;
    left: 0;
    right: 0;
    bottom: 11px;
    font-size: .75rem;
    font-weight: 600;
    letter-spacing: -0.01em;
    color: var(--vpn-text-2);
    text-align: center;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    padding-inline: 8px;
    transition: color 200ms var(--vpn-ease);
}

/* Selected state: brand ring, lifted plate, and a confirming check. */
.invoice-gateway:has(.btn-check:checked) {
    border-color: var(--vpn-brand-500);
    box-shadow: 0 0 0 4px rgba(99, 102, 241, .16), var(--vpn-shadow-md);
    transform: translateY(-2px);
}

.invoice-gateway:has(.btn-check:checked) .btn {
    transform: scale(1.04);
}

.invoice-gateway:has(.btn-check:checked) .btn::after {
    color: var(--vpn-brand-700);
    font-weight: 700;
}

[data-bs-theme="dark"] .invoice-gateway:has(.btn-check:checked) .btn::after {
    color: var(--vpn-brand-300);
}

.invoice-gateway::after {
    content: "";
    position: absolute;
    top: 9px;
    inset-inline-end: 9px;
    width: 19px;
    height: 19px;
    border-radius: 50%;
    background: var(--vpn-brand-600)
        url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6L9 17l-5-5'/%3E%3C/svg%3E")
        center / 11px 11px no-repeat;
    box-shadow: 0 2px 6px rgba(79, 70, 229, .45);
    opacity: 0;
    transform: scale(.4);
    transition: opacity 180ms var(--vpn-ease),
                transform 260ms cubic-bezier(.34, 1.56, .64, 1);
    pointer-events: none;
}

.invoice-gateway:has(.btn-check:checked)::after {
    opacity: 1;
    transform: scale(1);
}

/* Keyboard users get the same ring the pointer gets. */
.invoice-gateway:has(.btn-check:focus-visible) {
    box-shadow: var(--vpn-ring), var(--vpn-shadow-md);
}

/* Browsers without :has() still show a usable, if plainer, picker. */
@supports not selector(:has(*)) {
    .invoice-gateway::after {
        display: none;
    }
}

/* Checkout call to action */
#checkoutButton {
    background: var(--vpn-grad-brand);
    border: 0;
    border-radius: var(--vpn-r-pill);
    color: #fff;
    font-weight: 700;
    padding: 13px 34px;
    font-size: .9375rem;
    box-shadow: var(--vpn-glow-brand);
    transition: transform var(--vpn-fast) var(--vpn-ease),
                box-shadow var(--vpn-med) var(--vpn-ease);
}

#checkoutButton:hover {
    transform: translateY(-1px);
    box-shadow: 0 12px 30px -6px rgba(99, 102, 241, .58);
}

#vpn-cart .form-control,
#vpn-cart .form-select {
    border-radius: var(--vpn-r-sm);
    border-color: var(--vpn-border);
}

/* The pay-as-you-go card sits beside the priced plans, so it is distinguished
   by a dashed edge rather than by shouting a number it cannot honestly quote. */
.vpn-plan--hourly {
    border-style: dashed;
    border-color: var(--vpn-brand-300);
    background:
        linear-gradient(160deg, var(--vpn-brand-50), transparent 55%),
        var(--vpn-surface);
}

[data-bs-theme="dark"] .vpn-plan--hourly {
    background:
        linear-gradient(160deg, rgba(99, 102, 241, .14), transparent 55%),
        var(--vpn-surface);
}

.vpn-plan__badge--soft {
    background: var(--vpn-brand-100);
    border-color: transparent;
    color: var(--vpn-brand-700);
}

[data-bs-theme="dark"] .vpn-plan__badge--soft {
    background: rgba(99, 102, 241, .22);
    color: var(--vpn-brand-200);
}

/* A word, not a figure: the same slot as a price, without the false precision. */
.vpn-plan__price--word {
    font-size: 1.75rem;
    letter-spacing: -0.03em;
    background: var(--vpn-grad-brand);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
}

/* ------------------------------------------------------------------ */
/* Billing-mode switch (Monthly / Hourly)                              */
/* ------------------------------------------------------------------ */

.vpn-switch {
    display: inline-flex;
    gap: 4px;
    padding: 5px;
    margin: 0 auto clamp(20px, 3vw, 30px);
    border-radius: var(--vpn-r-pill);
    background: var(--vpn-surface-3);
    border: 1px solid var(--vpn-hairline);
    /* Centred without a wrapper, and never wider than the screen. */
    display: flex;
    width: fit-content;
    max-width: 100%;
}

.vpn-switch__opt {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 10px 24px;
    border: 0;
    border-radius: var(--vpn-r-pill);
    background: none;
    font: inherit;
    font-size: .9375rem;
    font-weight: 600;
    color: var(--vpn-text-2);
    cursor: pointer;
    white-space: nowrap;
    transition: color var(--vpn-fast) var(--vpn-ease),
                background-color var(--vpn-fast) var(--vpn-ease),
                box-shadow var(--vpn-med) var(--vpn-ease);
}

.vpn-switch__opt svg {
    width: 17px;
    height: 17px;
    opacity: .7;
}

.vpn-switch__opt:hover {
    color: var(--vpn-text);
}

.vpn-switch__opt.is-active {
    background: var(--vpn-surface);
    color: var(--vpn-brand-700);
    box-shadow: var(--vpn-shadow-sm);
}

.vpn-switch__opt.is-active svg { opacity: 1; }

[data-bs-theme="dark"] .vpn-switch__opt.is-active {
    background: var(--vpn-surface-2);
    color: var(--vpn-brand-300);
}

.vpn-billing-panel {
    display: none;
}

.vpn-billing-panel.is-active {
    display: block;
    animation: vpn-fade-up var(--vpn-med) var(--vpn-ease-out);
}

.vpn-hourly__intro {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
}

.vpn-hourly__wallet {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}

.vpn-hourly__wallet strong {
    font-size: 1.125rem;
    font-weight: 800;
    letter-spacing: -0.02em;
}

/* Read-only country tiles on the plans page: informative, not selectable. */
.vpn-country--buy {
    cursor: default;
}

.vpn-country--buy:hover {
    transform: none;
    border-color: var(--vpn-border);
    box-shadow: none;
}

/* ------------------------------------------------------------------ */
/* Gift vouchers                                                       */
/* ------------------------------------------------------------------ */

/* Codes are read aloud and copied by hand, so they get monospace, wide
   letter-spacing and no ambiguity between similar glyphs. */
.vpn-code {
    font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
    font-size: .875rem;
    font-weight: 700;
    letter-spacing: .06em;
    padding: 3px 9px;
    border-radius: var(--vpn-r-xs);
    background: var(--vpn-surface-3);
    color: var(--vpn-text);
    white-space: nowrap;
}

.vpn-code-input {
    font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
    font-size: 1.0625rem !important;
    font-weight: 700;
    letter-spacing: .10em;
    text-transform: uppercase;
    text-align: center;
}

.vpn-voucheritem {
    align-items: flex-start;
}

.vpn-voucheritem .vpnpay-copy {
    margin-inline-start: 8px;
    vertical-align: middle;
}

/* ------------------------------------------------------------------ */
/* Referral tiers                                                      */
/* ------------------------------------------------------------------ */

.vpn-tiers {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(110px, 1fr));
    gap: 10px;
}

.vpn-tier {
    display: flex;
    flex-direction: column;
    gap: 3px;
    padding: 14px 12px;
    border-radius: var(--vpn-r-md);
    border: 1px solid var(--vpn-border);
    background: var(--vpn-surface-2);
    text-align: center;
}

.vpn-tier__pct {
    font-size: 1.375rem;
    font-weight: 800;
    letter-spacing: -0.03em;
    background: var(--vpn-grad-brand);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
}

.vpn-tier__label {
    font-size: .75rem;
    font-weight: 600;
    color: var(--vpn-text-3);
    line-height: 1.35;
}

/* ------------------------------------------------------------------ */
/* Wallet                                                              */
/* ------------------------------------------------------------------ */

.vpn-walletcard__top {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 10px;
}

.vpn-walletcard__balance {
    font-size: 1.75rem;
    font-weight: 800;
    letter-spacing: -0.035em;
    line-height: 1.1;
    margin: 0;
    font-variant-numeric: tabular-nums;
}

.vpn-walletcard__mark {
    width: 40px;
    height: 40px;
    border-radius: 13px;
    display: grid;
    place-items: center;
    background: var(--vpn-grad-brand);
    color: #fff;
    box-shadow: var(--vpn-glow-brand);
    flex-shrink: 0;
}

.vpn-walletcard__mark svg { width: 20px; height: 20px; }


.vpn-amounts {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(76px, 1fr));
    gap: 8px;
}

.vpn-amount {
    padding: 12px 8px;
    border-radius: var(--vpn-r-sm);
    border: 1.5px solid var(--vpn-border);
    background: var(--vpn-surface);
    color: var(--vpn-text);
    font-weight: 700;
    font-size: .9375rem;
    cursor: pointer;
    transition: transform var(--vpn-fast) var(--vpn-ease),
                border-color var(--vpn-med) var(--vpn-ease),
                box-shadow var(--vpn-med) var(--vpn-ease),
                color var(--vpn-med) var(--vpn-ease);
}

.vpn-amount:hover {
    border-color: var(--vpn-brand-300);
    transform: translateY(-2px);
}

.vpn-amount.is-selected {
    border-color: var(--vpn-brand-500);
    background: var(--vpn-brand-50);
    color: var(--vpn-brand-700);
    box-shadow: 0 0 0 3px rgba(99, 102, 241, .14);
}

[data-bs-theme="dark"] .vpn-amount.is-selected {
    background: rgba(99, 102, 241, .18);
    color: var(--vpn-brand-300);
}

/* Credits and debits read at a glance in the history. */
.vpn-amount-cell {
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.vpn-amount-cell.is-credit { color: var(--vpn-success-ink); }
.vpn-amount-cell.is-debit { color: var(--vpn-text-2); }

/* ------------------------------------------------------------------ */
/* Hourly (pay-as-you-go)                                              */
/* ------------------------------------------------------------------ */

/* The picker holds every country in the world, so it needs a way to search
   and a way to reveal more a batch at a time. */
.vpn-countries__tools {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
    margin: 4px 0 14px;
}

.vpn-countries__search {
    position: relative;
    display: flex;
    align-items: center;
    flex: 1 1 220px;
    max-width: 340px;
}

.vpn-countries__search svg {
    position: absolute;
    inset-inline-start: 13px;
    width: 17px;
    height: 17px;
    color: var(--vpn-text-3);
    pointer-events: none;
}

.vpn-countries__search input {
    width: 100%;
    padding: 11px 14px 11px 38px;
    font-size: .9375rem;
    color: var(--vpn-text);
    background: var(--vpn-surface-2);
    border: 1.5px solid var(--vpn-border);
    border-radius: var(--vpn-r-md);
    transition: border-color var(--vpn-med) var(--vpn-ease), box-shadow var(--vpn-med) var(--vpn-ease);
}

.vpn-countries__search input:focus {
    outline: none;
    border-color: var(--vpn-brand-500);
    box-shadow: 0 0 0 4px rgba(99, 102, 241, .15);
}

/* Safari draws its own clear button on a search field; the theme's is enough. */
.vpn-countries__search input::-webkit-search-decoration,
.vpn-countries__search input::-webkit-search-cancel-button {
    -webkit-appearance: none;
}

.vpn-countries__count {
    margin: 0;
    font-size: .8125rem;
    font-weight: 600;
    color: var(--vpn-text-3);
    white-space: nowrap;
}

.vpn-countries__more {
    display: flex;
    justify-content: center;
    margin-top: 16px;
}

.vpn-countries__none {
    text-align: center;
}

.vpn-countries {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(168px, 1fr));
    gap: clamp(10px, 1.5vw, 14px);
}

/* Hidden by the search or the reveal limit. Must beat the grid display. */
.vpn-country.is-hidden {
    display: none !important;
}

.vpn-country {
    position: relative;
    display: grid;
    grid-template-columns: auto 1fr;
    grid-template-areas:
        "flag name"
        "flag rate"
        "day  day";
    align-items: center;
    gap: 2px 12px;
    padding: 15px 16px;
    border-radius: var(--vpn-r-md);
    border: 1.5px solid var(--vpn-border);
    background: var(--vpn-surface);
    text-align: start;
    cursor: pointer;
    transition: transform 200ms cubic-bezier(.34, 1.4, .64, 1),
                border-color var(--vpn-med) var(--vpn-ease),
                box-shadow var(--vpn-med) var(--vpn-ease);
}

.vpn-country:hover {
    transform: translateY(-3px);
    border-color: var(--vpn-brand-300);
    box-shadow: var(--vpn-shadow-md);
}

.vpn-pick.is-selected {
    border-color: var(--vpn-brand-500);
    box-shadow: 0 0 0 4px rgba(99, 102, 241, .15), var(--vpn-shadow-md);
}

/* Countries we do not run a server in yet. Listed so a customer can see where
   we are, but visibly inert: no hover lift, no pointer, nothing to press. */
.vpn-country--soon {
    cursor: default;
    background: var(--vpn-surface-2);
    border-style: dashed;
    border-color: var(--vpn-border);
}

.vpn-country--soon:hover {
    transform: none;
    border-color: var(--vpn-border);
    box-shadow: none;
}

.vpn-country--soon .vpn-country__flag,
.vpn-country--soon .vpn-country__name {
    opacity: .55;
}

.vpn-country__soon {
    font-size: .75rem;
    font-weight: 700;
    letter-spacing: .01em;
    color: var(--vpn-text-3);
    text-transform: none;
}

.vpn-country__flag {
    grid-area: flag;
    width: 34px;
    height: 34px;
    border-radius: 9px;
    overflow: hidden;
    display: grid;
    place-items: center;
    background: var(--vpn-surface-3);
    color: var(--vpn-text-3);
}

.vpn-country__flag .fi {
    width: 34px;
    height: 34px;
    background-size: cover;
    background-position: center;
}

.vpn-country__flag svg { width: 20px; height: 20px; }

.vpn-country__name {
    grid-area: name;
    font-weight: 700;
    font-size: .9375rem;
    color: var(--vpn-text);
    line-height: 1.25;
}

.vpn-country__rate {
    grid-area: rate;
    font-size: .875rem;
    font-weight: 700;
    color: var(--vpn-brand-600);
    font-variant-numeric: tabular-nums;
}

.vpn-country__rate small { font-weight: 600; opacity: .7; }

[data-bs-theme="dark"] .vpn-country__rate { color: var(--vpn-brand-300); }

.vpn-country__day {
    grid-area: day;
    margin-top: 8px;
    padding-top: 8px;
    border-top: 1px solid var(--vpn-border);
    font-size: .75rem;
    color: var(--vpn-text-3);
    font-variant-numeric: tabular-nums;
}

/* Selected tick, matching the payment tiles. */
.vpn-country.is-selected::after {
    content: "";
    position: absolute;
    top: 8px;
    inset-inline-end: 8px;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    background: var(--vpn-brand-600)
        url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6L9 17l-5-5'/%3E%3C/svg%3E")
        center / 10px 10px no-repeat;
    box-shadow: 0 2px 6px rgba(79, 70, 229, .45);
}

.vpn-hourly__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
}

.vpn-hourly__where {
    display: flex;
    align-items: center;
    gap: 12px;
    min-width: 0;
}

.vpn-flag,
.vpn-hourly__where .fi {
    width: 34px;
    height: 34px;
    border-radius: 9px;
    background-size: cover;
    background-position: center;
    flex-shrink: 0;
}

.vpn-hourly__cta {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 14px;
    flex-wrap: wrap;
    margin-top: 20px;
    padding-top: 18px;
    border-top: 1px solid var(--vpn-border);
}

/* ================================================================== */
/* 8. Bootstrap harmonisation                                         */
/* ================================================================== */

/* Pages this theme does not override still use Bootstrap components; soften
   them so they sit alongside the VPN surfaces instead of looking foreign. */

.card {
    border-radius: var(--vpn-r-lg);
    border-color: var(--vpn-border);
    box-shadow: var(--vpn-shadow-sm);
    background: var(--vpn-surface);
}

.card-header {
    background: transparent;
    border-bottom-color: var(--vpn-border);
    font-weight: 700;
    letter-spacing: -0.015em;
}

.card-footer {
    background: transparent;
    border-top-color: var(--vpn-border);
}

.btn {
    border-radius: var(--vpn-r-pill);
    font-weight: 600;
    padding-inline: 1.15rem;
    transition: transform var(--vpn-fast) var(--vpn-ease),
                box-shadow var(--vpn-med) var(--vpn-ease),
                background-color var(--vpn-med) var(--vpn-ease);
}

.btn:hover {
    transform: translateY(-1px);
}

.btn-primary {
    background: var(--vpn-grad-brand);
    border-color: transparent;
    box-shadow: var(--vpn-glow-brand);
}

.btn-primary:hover,
.btn-primary:focus,
.btn-primary:active {
    background: var(--vpn-grad-brand);
    border-color: transparent;
    filter: saturate(1.1) brightness(1.04);
}

.btn-outline-primary {
    border-color: var(--vpn-brand-400);
    color: var(--vpn-brand-600);
}

.btn-outline-primary:hover {
    background: var(--vpn-brand-500);
    border-color: var(--vpn-brand-500);
}

.form-control,
.form-select {
    border-radius: var(--vpn-r-sm);
    border-color: var(--vpn-border);
    background-color: var(--vpn-surface);
    color: var(--vpn-text);
    padding: .625rem .875rem;
}

.form-control:focus,
.form-select:focus {
    border-color: var(--vpn-brand-500);
    box-shadow: var(--vpn-ring);
}

.form-label {
    font-size: .8125rem;
    font-weight: 600;
    color: var(--vpn-text-2);
}

.table {
    --bs-table-bg: transparent;
    color: var(--vpn-text-2);
}

.table > :not(caption) > * > * {
    border-bottom-color: var(--vpn-border);
}

.badge {
    border-radius: var(--vpn-r-pill);
    font-weight: 700;
    padding: .42em .9em;
    letter-spacing: .005em;
}

.breadcrumb {
    font-size: .8125rem;
    margin-bottom: 16px;
}

.breadcrumb a {
    color: var(--vpn-text-3);
}

.breadcrumb a:hover {
    color: var(--vpn-brand-600);
}

.alert {
    border-radius: var(--vpn-r-md);
    border: 1px solid var(--vpn-border);
}

.dropdown-menu {
    border-radius: var(--vpn-r-md);
    border-color: var(--vpn-border);
    box-shadow: var(--vpn-shadow-lg);
    padding: 6px;
    background: var(--vpn-surface);
}

.dropdown-item {
    border-radius: var(--vpn-r-xs);
    padding: 8px 12px;
    font-size: .875rem;
    font-weight: 500;
    color: var(--vpn-text-2);
}

.dropdown-item:hover,
.dropdown-item:focus {
    background: var(--vpn-brand-50);
    color: var(--vpn-brand-700);
}

[data-bs-theme="dark"] .dropdown-item:hover,
[data-bs-theme="dark"] .dropdown-item:focus {
    background: var(--vpn-surface-3);
    color: var(--vpn-brand-300);
}

.modal-content {
    border-radius: var(--vpn-r-xl);
    border-color: var(--vpn-border);
    box-shadow: var(--vpn-shadow-xl);
    background: var(--vpn-surface);
}

.toast {
    border-radius: var(--vpn-r-md);
    box-shadow: var(--vpn-shadow-lg);
}

/* Scrollbars, where the browser lets us style them. */
* {
    scrollbar-width: thin;
    scrollbar-color: var(--vpn-border-strong) transparent;
}

::-webkit-scrollbar {
    width: 10px;
    height: 10px;
}

::-webkit-scrollbar-track {
    background: transparent;
}

::-webkit-scrollbar-thumb {
    background: var(--vpn-border-strong);
    border-radius: var(--vpn-r-pill);
    border: 3px solid transparent;
    background-clip: content-box;
}

::-webkit-scrollbar-thumb:hover {
    background: var(--vpn-text-3);
    background-clip: content-box;
}

/* ================================================================== */
/* 9. Responsive safety net                                           */
/* ================================================================== */

/* A single element wider than the viewport makes the whole page scroll
   sideways, which on a phone reads as "the page didn't load properly".
   These rules stop that at the source rather than hiding it with
   overflow:hidden, which would also clip sticky and fixed children. */

html,
body {
    max-width: 100%;
    overflow-x: hidden;
}

/* Grid and flex children default to min-width:auto, so a long URL or a wide
   table refuses to shrink and pushes the layout out. */
.vpn-grid > *,
.vpn-stack > *,
.vpn-split > *,
.vpn-card__body > *,
.vpn-listitem > * {
    min-width: 0;
}

/* Media never exceeds its column. */
img,
svg,
video,
canvas,
iframe {
    max-width: 100%;
}

/* Long, unbroken strings (subscription URLs, wallet addresses, UUIDs). */
.vpn-listitem__meta,
.vpn-card__body p,
.vpnpay-status__list dd,
.vpn-plan__desc {
    overflow-wrap: anywhere;
}

@media (max-width: 575.98px) {
    /* The header has to fit brand + theme toggle + account on a 320px screen. */
    .vpn-header {
        gap: 8px;
    }

    .vpn-userpill {
        padding: 4px 10px 4px 4px;
        gap: 7px;
    }

    .vpn-userpill__name {
        /* Below ~360px the name is the first thing worth dropping; the avatar
           still identifies the account and the menu still opens. */
        display: none;
    }

    .vpn-brand span:not(.vpn-brand__mark) {
        max-width: 40vw;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    /* Tables stay readable by scrolling inside their own box. */
    .vpn-table {
        min-width: 440px;
    }

    /* Full-width primary actions are easier to hit with a thumb. */
    .vpn-hourly__cta .vpn-btn,
    .vpn-hourly__cta {
        width: 100%;
    }

    .vpn-hourly__cta .vpn-btn {
        justify-content: center;
    }

    .vpn-countries {
        grid-template-columns: repeat(auto-fill, minmax(148px, 1fr));
    }

    .invoice-gateway {
        width: calc(33.333% - 8px);
        min-width: 92px;
    }
}

/* ---- Tablet & small laptop (768-1199) -----------------------------
   The two-column dashboard needs ~610px of usable width before the left
   column stops squeezing the right one. Below that, stack. */
@media (max-width: 1199.98px) {
    .vpn-grid {
        grid-template-columns: minmax(0, 1fr);
    }

    /* The nav is the first thing to overflow on a tablet: let it scroll
       horizontally instead of pushing the header wider than the screen. */
    .vpn-nav {
        margin-inline: 0 auto;
        overflow-x: auto;
        scrollbar-width: none;
        max-width: 100%;
    }

    .vpn-nav::-webkit-scrollbar {
        display: none;
    }
}

@media (max-width: 991.98px) {
    /* Below this the label text costs more than it earns. */
    .vpn-nav__link {
        padding-inline: 12px;
    }

    .vpn-stats {
        grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
    }
}

@media (max-width: 767.98px) {
    /* Clear the fixed tab bar, including the home indicator on iPhone. */
    .vpn-frame {
        padding-bottom: calc(96px + env(safe-area-inset-bottom));
    }

    /* The billing switch becomes two equal halves. */
    .vpn-switch {
        width: 100%;
    }

    .vpn-switch__opt {
        flex: 1;
        padding-inline: 12px;
    }

    .vpn-hourly__intro,
    .vpn-hourly__wallet {
        width: 100%;
    }

    /* The search field takes the whole row and the running count moves under
       it, rather than the two fighting over a phone's width. */
    .vpn-countries__tools {
        flex-direction: column;
        align-items: stretch;
        gap: 8px;
    }

    .vpn-countries__search {
        max-width: none;
    }

    /* 16px keeps iOS from zooming the page when the field takes focus. */
    .vpn-countries__search input {
        font-size: 1rem;
    }

    .vpn-countries__count {
        text-align: center;
    }

    /* Full-width so the next batch is one easy thumb press. */
    .vpn-countries__more .vpn-btn {
        width: 100%;
    }

    /* Anchored jumps should not land under the tab bar. */
    html {
        scroll-padding-bottom: calc(96px + env(safe-area-inset-bottom));
    }

    /* The QR sits under the URL rather than beside it. */
    .vpn-split {
        grid-template-columns: minmax(0, 1fr);
    }

    .vpn-qr {
        margin-inline: auto;
    }
}

/* Coarse pointers get larger hit targets. */
@media (pointer: coarse) {
    .vpn-btn {
        min-height: 44px;
    }

    .vpn-tabbar__item {
        min-height: 48px;
        justify-content: center;
    }
}

/* ================================================================== */
/* 10. Motion & print                                                 */
/* ================================================================== */

@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: .01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: .01ms !important;
        scroll-behavior: auto !important;
    }

    .vpn-btn:hover,
    .vpn-tile:hover,
    .vpn-plan:hover,
    .vpn-stat:hover,
    .vpnpay-link:hover {
        transform: none;
    }
}

@media print {
    body::before,
    .vpn-header,
    .vpn-tabbar,
    .vpn-banner,
    .vpn-btn {
        display: none !important;
    }

    .vpn-frame,
    .vpn-card {
        box-shadow: none;
        border: 1px solid #ddd;
        padding: 0;
    }
}


/* ------------------------------------------------------------------ */
/* Plan cards: fair-use note                                           */
/* ------------------------------------------------------------------ */

/* Sits under "Unlimited traffic" on the plan that has a stated ceiling. */
.vpn-plan__fairuse {
    display: block;
    margin-top: 2px;
    font-size: .75rem;
    font-weight: 500;
    color: var(--vpn-text-3);
}

/* The card on a highlighted plan sits on a coloured ground, so the muted
   grey would disappear into it. */
.vpn-plan--featured .vpn-plan__fairuse {
    color: rgba(255, 255, 255, .78);
}

/* ================================================================== */
/* 11. Right-to-left                                                  */
/* ================================================================== */

/* Most of the layout mirrors itself, because the stylesheet uses logical
   properties (inset-inline, margin-inline, text-align: start). What is left
   here is the handful of things a direction swap cannot infer. */

/* An arrow means "onwards", and onwards is leftwards in Arabic and Persian. */
[dir="rtl"] .vpn-tile svg.icon use[href="#arrow-right"],
[dir="rtl"] .vpn-btn svg.icon,
[dir="rtl"] .vpn-nav__link svg.icon {
    transform: scaleX(-1);
}

/* The shield, wallet, receipt and lifebuoy read the same either way; only the
   arrows should flip, so the blanket rule above is narrowed back for them. */
[dir="rtl"] .vpn-nav__link svg.icon:not([data-flip]),
[dir="rtl"] .vpn-btn svg.icon:not([data-flip]) {
    transform: none;
}

/* Numbers, money, codes and URLs stay left-to-right inside right-to-left text.
   Without this a subscription URL or a card number is reordered on screen and
   becomes wrong when read aloud or copied by eye. */
[dir="rtl"] .vpn-code,
[dir="rtl"] .vpn-code-input,
[dir="rtl"] .vpnpay-pay__amount,
[dir="rtl"] .vpn-plan__amount,
[dir="rtl"] .vpn-country__rate,
[dir="rtl"] .vpn-country__day,
[dir="rtl"] .vpn-amount-cell,
[dir="rtl"] .vpnpay-pay__value,
[dir="rtl"] code,
[dir="rtl"] pre,
[dir="rtl"] .mono {
    direction: ltr;
    unicode-bidi: isolate;
}

/* A price is still read as a unit, so it is isolated but stays on the
   reading edge of its own cell. */
[dir="rtl"] .vpn-amount-cell {
    text-align: end;
}

/* The search icon sits inside the field's padding, which the logical padding
   above already moved; the icon needs the same treatment. */
[dir="rtl"] .vpn-countries__search input {
    padding-inline: 38px 14px;
}

/* Persian and Arabic digits sit lower and need a little more line height than
   Latin at the same size. */
[dir="rtl"] body {
    line-height: 1.75;
}

/* A plan whose price is withheld until sign-in. The lock keeps the card the
   same height as a priced one, so a row of cards does not go ragged. */
.vpn-plan__price--hidden {
    display: flex;
    align-items: center;
    justify-content: flex-start;
    color: var(--vpn-text-3);
}

.vpn-plan__price--hidden svg {
    width: 30px;
    height: 30px;
}

.vpn-plan--featured .vpn-plan__price--hidden {
    color: rgba(255, 255, 255, .8);
}

/* ================================================================== */
/* 12. Large screens                                                  */
/* ================================================================== */

/*
 * On a wide monitor the extra room should make things easier to read, not
 * simply fit more of them. Each grid below therefore raises its minimum tile
 * size as the screen grows: a 2560px display gets larger, calmer cards rather
 * than twice as many small ones.
 */

@media (min-width: 1400px) {
    /* The dashboard's left column can afford to be wider before the main
       column starts to suffer. */
    .vpn-grid {
        grid-template-columns: minmax(300px, 360px) minmax(0, 1fr);
    }

    /* auto-fit, not auto-fill: with four plans a reserved empty track
       would leave the row looking unfinished. */
    .vpn-plans {
        grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
    }

    .vpn-countries {
        grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
    }

    .vpn-tiles {
        grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
    }
}

@media (min-width: 1900px) {
    .vpn-grid {
        grid-template-columns: minmax(320px, 400px) minmax(0, 1fr);
    }

    .vpn-plans {
        grid-template-columns: repeat(auto-fit, minmax(330px, 1fr));
    }

    .vpn-countries {
        grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
    }

    /* Statistics read better spread out than stacked once there is room. */
    .vpn-stats {
        grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    }
}

/*
 * Very wide and very short - an ultrawide monitor, or a laptop with the window
 * maximised on a 21:9 panel. Height is the scarce dimension there, so the
 * generous vertical rhythm tuned for phones is trimmed back.
 */
@media (min-width: 1600px) and (max-height: 900px) {
    .vpn-app {
        padding-block: 16px 24px;
    }

    .vpn-header {
        padding-bottom: 18px;
    }

    .vpn-page__head {
        margin-bottom: 18px;
    }
}

/* =========================================================================
   13. Payment method icons
   =========================================================================
   A customer choosing how to pay is scanning a row of six similar tiles. The
   icons used to be thin grey outlines, so the row read as one grey block and
   the choice took reading rather than glancing.

   Each method now sits on a soft tinted square in the colour it is known by:
   Alipay blue, YooMoney violet, HesabPay green, bitcoin amber. The glyph takes
   its colour from the same token via currentColor, so a method is one line to
   restyle and the fills inside the SVGs follow automatically.
   ========================================================================= */

.vpn-payicon {
    --payicon: var(--vpn-text-2);

    width: 52px;
    height: 52px;
    flex: 0 0 52px;
    display: grid;
    place-items: center;
    border-radius: 16px;
    color: var(--payicon);
    background: color-mix(in srgb, var(--payicon) 12%, transparent);
    transition: transform var(--vpn-med) var(--vpn-ease-out),
                background var(--vpn-med) var(--vpn-ease);
}

.vpn-payicon svg {
    width: 30px;
    height: 30px;
    display: block;
}

/* The tile already lifts on hover; the badge deepens with it. */
.vpn-tile:hover .vpn-payicon,
a:hover > .vpn-payicon {
    transform: translateY(-1px) scale(1.04);
    background: color-mix(in srgb, var(--payicon) 20%, transparent);
}

.vpn-payicon--card    { --payicon: #4F63D2; }  /* bank card, indigo */
.vpn-payicon--crypto  { --payicon: #F0952B; }  /* bitcoin amber */
.vpn-payicon--link    { --payicon: var(--vpn-brand-600); }
.vpn-payicon--alipay  { --payicon: #1677FF; }  /* Alipay blue */
.vpn-payicon--yandex  { --payicon: #8B3FFD; }  /* YooMoney violet */
.vpn-payicon--hesab   { --payicon: #10A37F; }  /* HesabPay green */
.vpn-payicon--generic { --payicon: var(--vpn-text-2); }

/* On a dark background the 12% tint disappears, so it is lifted and the glyph
   brightened enough to stay legible. */
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .vpn-payicon {
        background: color-mix(in srgb, var(--payicon) 22%, transparent);
        color: color-mix(in srgb, var(--payicon) 82%, white);
    }
}

:root[data-theme="dark"] .vpn-payicon {
    background: color-mix(in srgb, var(--payicon) 22%, transparent);
    color: color-mix(in srgb, var(--payicon) 82%, white);
}

/* The tiles hold a badge and a label side by side, so they need a little more
   room than the old 44px icon left them. */
.vpn-tile {
    gap: 14px;
}

@media (max-width: 480px) {
    .vpn-payicon {
        width: 46px;
        height: 46px;
        flex-basis: 46px;
        border-radius: 14px;
    }

    .vpn-payicon svg {
        width: 26px;
        height: 26px;
    }
}

/* -------------------------------------------------------------------------
   Support navigation dropdown

   Support opens a menu instead of jumping straight to tickets, so the nav item
   is a button rather than a link. It has to keep looking exactly like its
   neighbours, which are anchors - a button carries its own browser styling.
   ------------------------------------------------------------------------- */

.vpn-nav__dropdown {
    display: inline-flex;
}

.vpn-nav__dropdown > .vpn-nav__link {
    background: none;
    border: 0;
    font: inherit;
    cursor: pointer;
}

.vpn-nav__caret {
    width: 14px;
    height: 14px;
    margin-inline-start: 2px;
    opacity: .6;
    transition: transform var(--vpn-fast) var(--vpn-ease);
}

.vpn-nav__dropdown > .vpn-nav__link[aria-expanded="true"] .vpn-nav__caret {
    transform: rotate(180deg);
}

/* -------------------------------------------------------------------------
   Knowledge base

   Reached from Support, listed above the ticket form. The search box is the
   first thing on the page because most people arrive with a specific question,
   and the "open a ticket" card stays at the bottom so anyone the articles did
   not help can reach a person without going back to the menu.
   ------------------------------------------------------------------------- */

.vpn-kb-search {
    position: relative;
    display: flex;
    gap: 10px;
    align-items: center;
    max-width: 640px;
    margin-inline: auto;
}

.vpn-kb-search__icon {
    position: absolute;
    inset-inline-start: 16px;
    width: 20px;
    height: 20px;
    color: var(--vpn-text-2);
    pointer-events: none;
}

.vpn-kb-search__input {
    flex: 1;
    padding: 13px 18px 13px 46px;
    border: 1px solid var(--vpn-border);
    border-radius: var(--vpn-r-pill, 999px);
    background: var(--vpn-surface);
    color: var(--vpn-text);
    font-size: 15px;
    transition: border-color var(--vpn-fast) var(--vpn-ease),
                box-shadow var(--vpn-fast) var(--vpn-ease);
}

/* The icon sits on the leading edge, which flips with the writing direction. */
[dir="rtl"] .vpn-kb-search__input {
    padding: 13px 46px 13px 18px;
}

.vpn-kb-search__input:focus {
    outline: none;
    border-color: var(--vpn-brand-600);
    box-shadow: 0 0 0 4px color-mix(in srgb, var(--vpn-brand-600) 18%, transparent);
}

.vpn-kb-grid {
    display: grid;
    gap: 18px;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
}

.vpn-kb-cat__title {
    font-size: 17px;
    font-weight: 650;
    margin: 0 0 6px;
}

.vpn-kb-cat__title a {
    color: var(--vpn-text);
    text-decoration: none;
}

.vpn-kb-cat__title a:hover {
    color: var(--vpn-brand-600);
}

.vpn-kb-cat__lead {
    color: var(--vpn-text-2);
    font-size: 14px;
    margin-bottom: 14px;
}

.vpn-kb-cat__all {
    display: inline-block;
    margin-top: 12px;
    font-size: 14px;
}

.vpn-kb-list {
    list-style: none;
    margin: 0;
    padding: 0;
}

.vpn-kb-list li + li {
    border-top: 1px solid var(--vpn-border);
}

.vpn-kb-list a {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 12px 4px;
    color: var(--vpn-text);
    text-decoration: none;
    transition: color var(--vpn-fast) var(--vpn-ease),
                padding-inline-start var(--vpn-fast) var(--vpn-ease);
}

.vpn-kb-list--tight a {
    padding-block: 9px;
    font-size: 14px;
}

.vpn-kb-list a .icon {
    width: 16px;
    height: 16px;
    flex: 0 0 16px;
    opacity: 0;
    transition: opacity var(--vpn-fast) var(--vpn-ease);
}

.vpn-kb-list a:hover {
    color: var(--vpn-brand-600);
    padding-inline-start: 10px;
}

.vpn-kb-list a:hover .icon {
    opacity: .8;
}

/* The arrow points the way the language reads. */
[dir="rtl"] .vpn-kb-list a .icon {
    transform: scaleX(-1);
}

.vpn-kb-help .vpn-card__body {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 18px;
    flex-wrap: wrap;
}

/* =========================================================================
   14. Dark mode: the section you are in is lit
   =========================================================================
   In the dark theme the navigation reads as an unlit strip, and whichever
   section you are in has a small red lamp above it - the light belongs to that
   one item and moves with you as you click through the menu.

   The bar itself stays dark and quiet on purpose: if the whole strip glowed,
   nothing would stand out and the light would stop meaning "you are here".

   One hue token drives all of it, so the whole effect is a single line to
   retune. Everything is scoped to [data-bs-theme="dark"]; the light theme is
   untouched.

   Readability first. Resting labels stay a warm light grey rather than red -
   red text on near-black is hard to read at 14px - so the red is carried by
   the lamp, the bloom and the item that is lit.
   ========================================================================= */

[data-bs-theme="dark"] {
    --vpn-torch: #ff2d3f;
    --vpn-torch-soft: rgba(255, 45, 63, .55);
}

/* The bar: dark and unlit, so the one lamp on it has something to read against. */
[data-bs-theme="dark"] .vpn-nav {
    background: linear-gradient(180deg, #12080b 0%, #0a0508 100%);
    border-color: rgba(255, 45, 63, .14);
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, .04),
        0 8px 26px -12px rgba(0, 0, 0, .9);
}

[data-bs-theme="dark"] .vpn-nav__link {
    position: relative;
    color: #cbb9bd;
}

[data-bs-theme="dark"] .vpn-nav__link svg {
    opacity: .7;
}

/* Hover is a hand near the switch, not the switch thrown: a hint of the same
   light, well below what the active item gets. */
[data-bs-theme="dark"] .vpn-nav__link:hover {
    color: #f3e3e5;
    background: rgba(255, 45, 63, .07);
}

[data-bs-theme="dark"] .vpn-nav__link:hover svg {
    opacity: .95;
    filter: drop-shadow(0 0 5px rgba(255, 45, 63, .35));
}

/* ------------------------------------------------- the lit section ------ */

[data-bs-theme="dark"] .vpn-nav__link.is-active,
[data-bs-theme="dark"] .vpn-nav__dropdown > .vpn-nav__link[aria-expanded="true"] {
    color: #ff8a94;
    background:
        radial-gradient(90% 130% at 50% -20%,
            rgba(255, 45, 63, .34) 0%,
            rgba(255, 45, 63, .12) 45%,
            transparent 75%),
        rgba(255, 45, 63, .07);
    box-shadow:
        inset 0 0 0 1px rgba(255, 45, 63, .34),
        inset 0 10px 18px -12px rgba(255, 45, 63, .75),
        0 0 18px -5px rgba(255, 45, 63, .5);
    text-shadow: 0 0 11px rgba(255, 45, 63, .5);
}

/* The lamp: a short strip sitting on the top edge of the lit item only. */
[data-bs-theme="dark"] .vpn-nav__link.is-active::before,
[data-bs-theme="dark"] .vpn-nav__dropdown > .vpn-nav__link[aria-expanded="true"]::before {
    content: "";
    position: absolute;
    top: -1px;
    left: 50%;
    transform: translateX(-50%);
    width: 60%;
    max-width: 74px;
    height: 3px;
    border-radius: 999px;
    background: linear-gradient(90deg,
        transparent, var(--vpn-torch) 25%, #ff7f8a 50%, var(--vpn-torch) 75%, transparent);
    box-shadow:
        0 0 9px 1px var(--vpn-torch-soft),
        0 0 22px 5px rgba(255, 45, 63, .34);
    pointer-events: none;
}

[data-bs-theme="dark"] .vpn-nav__link.is-active svg,
[data-bs-theme="dark"] .vpn-nav__dropdown > .vpn-nav__link[aria-expanded="true"] svg {
    opacity: 1;
    filter: drop-shadow(0 0 7px var(--vpn-torch))
            drop-shadow(0 0 15px var(--vpn-torch-soft));
}

/* The lamp comes up rather than snapping on, so clicking through the menu reads
   as the light moving with you - and then it stays alive rather than freezing
   into a painted highlight. The entry runs once, the breathing takes over after
   it, and the halo swells on a different beat so the two never line up. */
@media (prefers-reduced-motion: no-preference) {
    [data-bs-theme="dark"] .vpn-nav__link.is-active::before {
        /* A wider gradient than the strip, so the bright spot has somewhere to
           travel to - that is the "drift" half of being alive. */
        background: linear-gradient(90deg,
            transparent 0%,
            var(--vpn-torch) 18%,
            #ff9aa3 30%,
            #ff7f8a 38%,
            var(--vpn-torch) 50%,
            transparent 68%,
            transparent 100%);
        background-size: 220% 100%;
        animation:
            vpn-torch-on .5s var(--vpn-ease-out, ease-out) both,
            vpn-torch-breathe 4.2s .5s ease-in-out infinite,
            vpn-torch-drift 6.5s .5s ease-in-out infinite;
    }

    [data-bs-theme="dark"] .vpn-nav__link.is-active {
        animation:
            vpn-torch-bloom .5s var(--vpn-ease-out, ease-out) both,
            vpn-torch-halo 5.3s .5s ease-in-out infinite;
    }

    [data-bs-theme="dark"] .vpn-nav__link.is-active svg {
        animation: vpn-torch-lamp 4.2s .5s ease-in-out infinite;
    }

    [data-bs-theme="dark"] .vpn-tabbar__item.is-active::before {
        animation: vpn-torch-breathe 4.2s ease-in-out infinite;
    }

    [data-bs-theme="dark"] .vpn-tabbar__item.is-active svg {
        animation: vpn-torch-lamp 4.2s ease-in-out infinite;
    }
}

@keyframes vpn-torch-on {
    0%   { opacity: 0; transform: translateX(-50%) scaleX(.3); }
    55%  { opacity: 1; transform: translateX(-50%) scaleX(1.06); }
    100% { opacity: 1; transform: translateX(-50%) scaleX(1); }
}

@keyframes vpn-torch-bloom {
    0%   { box-shadow: inset 0 0 0 1px rgba(255, 45, 63, .10), 0 0 0 0 rgba(255, 45, 63, 0); }
    100% { box-shadow: inset 0 0 0 1px rgba(255, 45, 63, .34),
                       inset 0 10px 18px -12px rgba(255, 45, 63, .75),
                       0 0 18px -5px rgba(255, 45, 63, .5); }
}

/* The strip rises and falls. The transform is repeated in every frame because
   the element is centred with one, and a keyframe that omits it would snap the
   lamp to the left edge. */
@keyframes vpn-torch-breathe {
    0%, 100% {
        opacity: 1;
        transform: translateX(-50%) scaleX(1);
        box-shadow: 0 0 9px 1px var(--vpn-torch-soft),
                    0 0 22px 5px rgba(255, 45, 63, .34);
    }
    38% {
        opacity: .74;
        transform: translateX(-50%) scaleX(.94);
        box-shadow: 0 0 6px 1px rgba(255, 45, 63, .38),
                    0 0 15px 4px rgba(255, 45, 63, .22);
    }
    62% {
        opacity: .96;
        transform: translateX(-50%) scaleX(1.02);
        box-shadow: 0 0 11px 2px var(--vpn-torch-soft),
                    0 0 26px 6px rgba(255, 45, 63, .38);
    }
}

/* The hotspot travels, so the light has a source that moves. */
@keyframes vpn-torch-drift {
    0%, 100% { background-position: 12% 50%; }
    50%      { background-position: 88% 50%; }
}

/* The glow around the lit item, on its own slower beat. */
@keyframes vpn-torch-halo {
    0%, 100% {
        box-shadow: inset 0 0 0 1px rgba(255, 45, 63, .34),
                    inset 0 10px 18px -12px rgba(255, 45, 63, .75),
                    0 0 18px -5px rgba(255, 45, 63, .5);
    }
    45% {
        box-shadow: inset 0 0 0 1px rgba(255, 45, 63, .28),
                    inset 0 10px 20px -12px rgba(255, 45, 63, .55),
                    0 0 26px -4px rgba(255, 45, 63, .62);
    }
}

/* The icon is what the lamp is pointed at, so it brightens with the strip. */
@keyframes vpn-torch-lamp {
    0%, 100% { filter: drop-shadow(0 0 7px var(--vpn-torch))
                       drop-shadow(0 0 15px var(--vpn-torch-soft)); }
    38%      { filter: drop-shadow(0 0 4px rgba(255, 45, 63, .75))
                       drop-shadow(0 0 10px rgba(255, 45, 63, .35)); }
    62%      { filter: drop-shadow(0 0 9px var(--vpn-torch))
                       drop-shadow(0 0 19px var(--vpn-torch-soft)); }
}

/* ------------------------------------------------- the phone tab bar ---- */

@media (max-width: 767.98px) {
    [data-bs-theme="dark"] .vpn-tabbar {
        background: #0b0507;
        background: color-mix(in srgb, #0b0507 92%, transparent);
        border-top-color: rgba(255, 45, 63, .16);
    }

    [data-bs-theme="dark"] .vpn-tabbar__item {
        position: relative;
        color: #bda9ac;
    }

    [data-bs-theme="dark"] .vpn-tabbar__item.is-active {
        color: #ff8a94;
        background:
            radial-gradient(90% 120% at 50% -10%,
                rgba(255, 45, 63, .30) 0%, transparent 70%),
            rgba(255, 45, 63, .07);
        box-shadow: inset 0 0 0 1px rgba(255, 45, 63, .28);
        text-shadow: 0 0 9px rgba(255, 45, 63, .45);
    }

    /* The bar sits at the bottom of the screen, so its lamp goes on the top
       edge of the tab - the edge the customer is looking at. */
    [data-bs-theme="dark"] .vpn-tabbar__item.is-active::before {
        content: "";
        position: absolute;
        top: 0;
        left: 50%;
        transform: translateX(-50%);
        width: 46%;
        height: 3px;
        border-radius: 999px;
        background: linear-gradient(90deg,
            transparent, var(--vpn-torch) 25%, #ff7f8a 50%, var(--vpn-torch) 75%, transparent);
        box-shadow: 0 0 9px 1px var(--vpn-torch-soft), 0 0 20px 5px rgba(255, 45, 63, .32);
        pointer-events: none;
    }

    [data-bs-theme="dark"] .vpn-tabbar__item.is-active svg {
        filter: drop-shadow(0 0 7px var(--vpn-torch))
                drop-shadow(0 0 15px var(--vpn-torch-soft));
    }
}

/* -------------------------------------------------------------------------
   Header on a phone

   Once the nav moves to the bottom tab bar, the header holds only the brand and
   the account controls. They are pinned to the two ends of the line so the row
   reads as a header rather than a cluster floating mid-page, and the brand is
   allowed to shrink first because the controls cannot.
   ------------------------------------------------------------------------- */

@media (max-width: 767.98px) {
    .vpn-header {
        justify-content: space-between;
        flex-wrap: nowrap;
    }

    .vpn-brand {
        min-width: 0;          /* so it can shrink instead of pushing the row wide */
        margin-inline-end: auto;
    }

    .vpn-brand img {
        max-height: 30px;
    }

    .vpn-header__actions {
        flex-shrink: 0;
    }
}

/* Only one of the two logos is ever visible, so the hidden one must not hold
   space or the brand keeps a gap beside it. */
.vpn-brand img.hide-theme-light,
.vpn-brand img.hide-theme-dark {
    display: none;
}

[data-bs-theme="light"] .vpn-brand img.hide-theme-dark,
:root:not([data-bs-theme="dark"]) .vpn-brand img.hide-theme-dark {
    display: block;
}

[data-bs-theme="dark"] .vpn-brand img.hide-theme-light {
    display: block;
}

/* ==========================================================================
   Scripts other than Latin
   ==========================================================================

   The body stack above is Latin-first and applies letter-spacing: -0.011em,
   which is right for Inter and Segoe UI and wrong for every script below.

   Persian and Arabic join their letters: negative tracking pulls the joins
   into each other. Burmese stacks marks above and below the baseline, so it
   needs vertical room the Latin line-height does not give it. CJK is designed
   on a fixed em square and tracking simply makes it look loose or crushed.

   The browser already falls back for missing glyphs, so this is not about
   whether the text appears - it is about it appearing at the right size and
   spacing. `lang` is set on <html> from the active locale, so :lang() matches
   the whole page and any element inside it.

   Font names are listed OS-first (Windows, macOS, Linux) because customers of
   this shop are on all three and none of these are webfonts - nothing is
   downloaded, so an unavailable name simply falls through to the next. */

:lang(fa),
:lang(ar),
:lang(ur) {
    font-family: Vazirmatn, "Segoe UI", Tahoma, "Iranian Sans", "IRANSans",
                 "Noto Naskh Arabic", "Geeza Pro", sans-serif;
    letter-spacing: normal;
    line-height: 1.75;
}

:lang(my) {
    font-family: "Myanmar Text", Padauk, "Noto Sans Myanmar", "Myanmar MN",
                 "Pyidaungsu", sans-serif;
    letter-spacing: normal;
    /* Burmese stacks up to three marks vertically; 1.55 clips the tall ones. */
    line-height: 1.9;
}

:lang(zh),
:lang(ja),
:lang(ko) {
    font-family: "Microsoft YaHei", "PingFang SC", "Hiragino Sans GB",
                 "Noto Sans CJK SC", "Source Han Sans SC", "Malgun Gothic",
                 sans-serif;
    letter-spacing: normal;
    line-height: 1.7;
}

/* Numbers, identifiers and money stay in the Latin stack whatever the page
   language is. A subscription UUID or an amount rendered in Myanmar Text is
   harder to read and harder to copy than the same string in a Latin face. */
:lang(fa) .vpn-mono,
:lang(my) .vpn-mono,
:lang(zh) .vpn-mono,
:lang(fa) code,
:lang(my) code,
:lang(zh) code,
:lang(fa) kbd,
:lang(my) kbd,
:lang(zh) kbd {
    font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
    letter-spacing: normal;
}

/* ==========================================================================
   Custom protocol builder
   ==========================================================================

   Three gated steps on the Custom tab: protocol, country, then the build.
   A locked step is dimmed and non-interactive rather than hidden, so the
   customer can see what is coming and why it is not ready yet.

   The unavailable state carries most of the weight in here. Every protocol and
   every country is listed whether or not this shop can sell it, so "you cannot
   pick this" has to read instantly and not look like a rendering fault. */

.vpn-custom__lead {
    color: var(--vpn-text-muted);
    max-width: 60ch;
}

.vpn-custom__step {
    font-weight: 650;
    margin: 1.75rem 0 0.85rem;
}

.vpn-custom__step:first-of-type {
    margin-top: 0;
}

/* A step whose prerequisite is unanswered. pointer-events rather than
   [disabled] on each control: the whole block is inert in one place, and it
   cannot drift out of sync with the buttons inside it. */
.vpn-custom__section.is-locked {
    opacity: 0.42;
    pointer-events: none;
    filter: saturate(0.5);
}

.vpn-custom__section {
    transition: opacity 0.25s ease, filter 0.25s ease;
}

/* ---- protocol grid ---- */

.vpn-protocols__family {
    font-size: 0.78rem;
    font-weight: 650;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--vpn-text-muted);
    margin: 1.15rem 0 0.55rem;
}

.vpn-protocols__family:first-child {
    margin-top: 0;
}

.vpn-protocols__grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(215px, 1fr));
    gap: 0.7rem;
}

.vpn-protocol {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.25rem;
    padding: 0.85rem 0.95rem;
    text-align: left;
    border: 1.5px solid var(--vpn-border);
    border-radius: 12px;
    background: var(--vpn-surface);
    color: inherit;
    cursor: pointer;
    transition: border-color 0.15s ease, background 0.15s ease, transform 0.15s ease;
}

.vpn-protocol:hover:not(:disabled) {
    border-color: var(--vpn-accent);
    transform: translateY(-1px);
}

.vpn-protocol.is-selected {
    border-color: var(--vpn-accent);
    background: color-mix(in srgb, var(--vpn-accent) 10%, transparent);
}

.vpn-protocol__name {
    font-weight: 600;
}

.vpn-protocol__note {
    font-size: 0.8rem;
    color: var(--vpn-text-muted);
    line-height: 1.4;
}

.vpn-protocol__tag {
    margin-top: 0.35rem;
    font-size: 0.72rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    padding: 0.12rem 0.5rem;
    border-radius: 999px;
    background: color-mix(in srgb, var(--vpn-accent) 14%, transparent);
    color: var(--vpn-accent);
}

/* Not sold here. Dimmed, greyed and not clickable - but still readable, since
   the whole point of listing it is to answer "do you have X?". */
.vpn-protocol.is-unavailable,
.vpn-pick.is-unavailable {
    opacity: 0.5;
    cursor: not-allowed;
    filter: grayscale(1);
}

.vpn-protocol.is-unavailable .vpn-protocol__tag {
    background: color-mix(in srgb, currentColor 12%, transparent);
    color: var(--vpn-text-muted);
}

/* ---- country grid ---- */

.vpn-custom__search {
    max-width: 340px;
}

.vpn-custom__countries {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
    gap: 0.5rem;
    /* 249 countries is a long page on its own. Scrolling the list keeps the
       rest of the builder reachable without paginating it. */
    max-height: 330px;
    overflow-y: auto;
    padding-right: 0.35rem;
}

.vpn-pick {
    display: flex;
    align-items: center;
    gap: 0.55rem;
    padding: 0.55rem 0.7rem;
    border: 1.5px solid var(--vpn-border);
    border-radius: 10px;
    background: var(--vpn-surface);
    color: inherit;
    cursor: pointer;
    text-align: left;
    transition: border-color 0.15s ease, background 0.15s ease;
}

.vpn-pick:hover:not(:disabled) {
    border-color: var(--vpn-accent);
}

.vpn-pick.is-selected {
    border-color: var(--vpn-accent);
    background: color-mix(in srgb, var(--vpn-accent) 10%, transparent);
}

.vpn-pick__name {
    flex: 1 1 auto;
    font-size: 0.88rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.vpn-pick__tag {
    font-size: 0.68rem;
    color: var(--vpn-text-muted);
    white-space: nowrap;
}

/* ---- sliders and the running total ---- */

.vpn-custom__sliders {
    display: grid;
    gap: 1.1rem;
    margin: 1.25rem 0;
}

.vpn-custom__slider {
    display: block;
}

.vpn-custom__sliderhead {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    font-size: 0.85rem;
    font-weight: 600;
    margin-bottom: 0.4rem;
}

.vpn-custom__sliderhead output {
    font-variant-numeric: tabular-nums;
    font-weight: 700;
    color: var(--vpn-accent);
}

.vpn-custom__slider input[type="range"] {
    width: 100%;
    accent-color: var(--vpn-accent);
}

.vpn-custom__quote {
    border: 1px solid var(--vpn-border);
    border-radius: 12px;
    padding: 0.85rem 1rem;
    margin-bottom: 1rem;
}

.vpn-custom__line {
    display: flex;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.28rem 0;
    font-size: 0.88rem;
    color: var(--vpn-text-muted);
    font-variant-numeric: tabular-nums;
}

.vpn-custom__line--total {
    margin-top: 0.4rem;
    padding-top: 0.6rem;
    border-top: 1px solid var(--vpn-border);
    font-size: 1.02rem;
    font-weight: 700;
    color: var(--vpn-text);
}

.vpn-custom__wallet {
    font-size: 0.88rem;
    color: var(--vpn-text-muted);
    margin-bottom: 0.85rem;
}

.vpn-custom__hint {
    font-size: 0.8rem;
    color: var(--vpn-text-muted);
    text-align: center;
    margin: 0.6rem 0 0;
}

/* Only the active billing mode inside the builder is rendered. */
.vpn-custom__mode {
    display: none;
}

.vpn-custom__mode.is-active {
    display: block;
}

.vpn-switch--inner {
    margin-bottom: 1.1rem;
}

@media (max-width: 575.98px) {
    .vpn-protocols__grid,
    .vpn-custom__countries {
        grid-template-columns: 1fr;
    }

    .vpn-custom__countries {
        max-height: 260px;
    }
}

/* The country list's paging control. Sits under the scroll box rather than
   inside it, so it does not scroll away from the person looking for it. */
.vpn-custom__more {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin-top: 0.7rem;
}

.vpn-custom__count {
    font-size: 0.8rem;
    color: var(--vpn-text-muted);
    font-variant-numeric: tabular-nums;
}

/* The variants line under a VPN type's name: "VLESS, VMess, Reality, ...".
   Smaller and quieter than the name, louder than the description, because it
   is what a customer scans for when they already know what they came for. */
.vpn-protocol__variants {
    font-size: 0.74rem;
    font-weight: 600;
    letter-spacing: 0.01em;
    color: var(--vpn-accent);
    opacity: 0.85;
    line-height: 1.35;
}

.vpn-protocol.is-unavailable .vpn-protocol__variants {
    color: var(--vpn-text-muted);
}

/* ==========================================================================
   Country flags
   ==========================================================================

   Flags are 4:3, not square. The hourly list was forcing them into a 34x34
   box with `background-size: cover`, which crops the left and right off every
   flag and stretches what is left - hence the "big and crooked" look. A
   horizontal tricolour survives that; the Union Jack, the Stars and Stripes
   and the Brazilian globe do not.

   Fixed by giving them their real proportions. 32x24 is exactly 4:3, so
   `cover` has nothing to crop and the image lands undistorted. Sizes are in
   px rather than em so a flag does not grow with the surrounding font - which
   is what made them look oversized next to a country name.

   These rules come last in the file deliberately: they override the earlier
   square sizing without editing rules other parts of the page still rely on. */

/* Every flag on the site, at its true proportions. `cover` on an exact 4:3 box
   has nothing to crop, so the image lands whole. Sized in px, not em, so a flag
   does not swell with the text beside it - which is what made them look
   oversized next to a country name. */
.vpn-flag,
.vpn-hourly__where .fi,
.vpn-country__flag .fi,
.vpn-pick > .fi {
    width: 30px;
    height: 22.5px;        /* 30 / 4 * 3 - the flag's own ratio */
    border-radius: 3px;
    background-size: cover;
    background-position: center;
    /* A hairline keeps flags with white edges (Japan, Switzerland) from
       bleeding into a light background. */
    box-shadow: inset 0 0 0 1px rgb(0 0 0 / 12%);
    flex-shrink: 0;
    display: inline-block;
    vertical-align: middle;
}

/*
   The hourly picker's tile is a grid area spanning two rows of text - the
   country name and its rate - so it is taller than one flag. Centring the flag
   in it keeps the tile's alignment with the text while letting the flag keep
   its own shape; forcing the tile down to the flag's height instead pulled the
   whole card out of line, which is what made these look crooked.
*/
.vpn-country__flag {
    width: 34px;
    height: 34px;
    border-radius: 8px;
    overflow: hidden;
    display: grid;
    place-items: center;
    background: transparent;
}

.vpn-country__flag svg {
    width: 18px;
    height: 18px;
}

/* The custom builder's country buttons draw the flag inline, in a flex row. */
.vpn-pick > .fi {
    margin-right: 0.15rem;
}

@media (max-width: 575.98px) {
    .vpn-flag,
    .vpn-hourly__where .fi,
    .vpn-country__flag .fi,
    .vpn-pick > .fi {
        width: 26px;
        height: 19.5px;
    }

    .vpn-country__flag {
        width: 30px;
        height: 30px;
    }
}

/* ==========================================================================
   Order progress
   ==========================================================================

   Shown under the buy button while the VPN panel is being called, then turned
   green when the account exists. The window is short but it is the window in
   which the customer has already been charged and can see nothing happening -
   which is when they press the button again. */

.vpn-progress {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    margin-top: 0.85rem;
    padding: 0.7rem 0.9rem;
    border-radius: 10px;
    border: 1px solid var(--vpn-border);
    background: var(--vpn-surface);
    font-size: 0.9rem;
    transition: border-color 0.3s ease, background 0.3s ease, color 0.3s ease;
}

.vpn-progress__spinner {
    width: 16px;
    height: 16px;
    flex-shrink: 0;
    border-radius: 50%;
    border: 2px solid color-mix(in srgb, var(--vpn-accent) 30%, transparent);
    border-top-color: var(--vpn-accent);
    animation: vpn-progress-spin 0.7s linear infinite;
}

@keyframes vpn-progress-spin {
    to { transform: rotate(360deg); }
}

/* Done: green, and the spinner becomes a tick. */
.vpn-progress.is-done {
    border-color: var(--vpn-ok, #2e9e63);
    background: color-mix(in srgb, var(--vpn-ok, #2e9e63) 12%, transparent);
    color: var(--vpn-ok, #2e9e63);
    font-weight: 600;
}

.vpn-progress.is-done .vpn-progress__spinner {
    animation: none;
    border: none;
    background: var(--vpn-ok, #2e9e63);
    position: relative;
}

.vpn-progress.is-done .vpn-progress__spinner::after {
    content: "";
    position: absolute;
    left: 5px;
    top: 2px;
    width: 4px;
    height: 8px;
    border: solid #fff;
    border-width: 0 2px 2px 0;
    transform: rotate(45deg);
}

/* Respect a reader who has asked for less motion: the state still changes,
   it just does not spin. */
@media (prefers-reduced-motion: reduce) {
    .vpn-progress__spinner {
        animation: none;
    }
}

/* Stopping an hourly subscription: the one destructive action a customer has
   on their own subscriptions, so it should not look like the buttons beside it.
   Outlined rather than solid red - it ends billing, which is reversible by
   starting again, so it warrants caution and not alarm. */
.vpn-btn--danger {
    background: transparent;
    border: 1.5px solid color-mix(in srgb, var(--vpn-danger, #d2544e) 55%, transparent);
    color: var(--vpn-danger, #d2544e);
}

.vpn-btn--danger:hover:not(:disabled) {
    background: color-mix(in srgb, var(--vpn-danger, #d2544e) 12%, transparent);
    border-color: var(--vpn-danger, #d2544e);
    color: var(--vpn-danger, #d2544e);
}

.vpn-btn--danger:disabled {
    opacity: 0.55;
    cursor: not-allowed;
}

/* ==========================================================================
   The payment QR code
   ==========================================================================

   Sized to be scannable, not decorative. A phone camera held at arm's length
   from a laptop needs roughly 220px of code; smaller than that and people
   lean in, move the phone about, and eventually give up and type the address
   by hand - which is where transposed characters and lost money come from.

   White padding around it is not styling either: a scanner needs the quiet
   zone, and a code sitting flush against a dark card often will not read. */

.vpnpay-pay__figure--qr {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.6rem;
    margin: 0 0 1.25rem;
}

.vpnpay-pay__figure--qr img {
    width: 240px;
    max-width: min(78vw, 300px);
    height: auto;
    padding: 12px;
    border-radius: 12px;
    /* Always white behind the code, in either theme: a QR inverted by a dark
       background does not scan on most phones. */
    background: #fff;
    box-shadow: 0 2px 14px rgb(0 0 0 / 18%);
}

.vpnpay-pay__figure--qr figcaption {
    font-size: 0.9rem;
    font-weight: 600;
    color: var(--vpn-text-muted);
}

@media (max-width: 400px) {
    .vpnpay-pay__figure--qr img {
        width: 200px;
        padding: 10px;
    }
}

/* ==========================================================================
   "Open in the payment app"
   ==========================================================================

   Shown only on touch devices. On a desktop the link opens a page that cannot
   pay - the app is not there - so the button would be a dead end, and the QR
   beside it is already the right answer for someone at a computer.

   `pointer: coarse` rather than a width query: what matters is whether the
   device is the one holding the payment app, not how wide the window is. */

.vpnpay-paylink {
    display: block;
    text-align: center;
    margin: 0 0 1.25rem;
}

/* The payee line is the one thing here worth reading slowly - it is the only
   place the customer can check who receives the money before they send it. */
.vpnpay-paylink__payee {
    margin: 0.7rem 0 0.15rem;
    font-size: 0.95rem;
}

.vpnpay-paylink__code {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.85rem;
    padding: 0.1rem 0.4rem;
    border-radius: 6px;
    background: var(--vpn-surface-2, rgba(127, 127, 127, 0.14));
    /* Selectable in one gesture: they will want to compare it with what their
       own Alipay app shows after scanning. */
    user-select: all;
    word-break: break-all;
}
.vpnpay-paylink__button {
    display: inline-block;
    padding: 0.85rem 1.6rem;
    border-radius: 12px;
    background: var(--vpn-grad-brand);
    box-shadow: var(--vpn-glow-brand);
    color: var(--vpn-on-brand);
    font-weight: 650;
    text-decoration: none;
    /* Comfortably above the 44px minimum touch target. */
    min-height: 48px;
    line-height: 1.9;
}

.vpnpay-paylink__button:hover,
.vpnpay-paylink__button:focus {
    filter: brightness(1.08);
    color: #fff;
    text-decoration: none;
}

/* The amount is the thing they have to carry into the app, so it is the
   loudest text here after the button itself, and selectable to copy. */
.vpnpay-paylink__amount {
    margin: 0.75rem 0 0.25rem;
    font-size: 1.05rem;
    user-select: all;
}

.vpnpay-paylink__note {
    margin: 0;
    font-size: 0.82rem;
    color: var(--vpn-text-muted);
    max-width: 34ch;
    margin-inline: auto;
}

/* Payment details that are not in the page until the customer asks.

   The placeholder keeps the row's height, so pressing the button swaps text in
   rather than making the panel jump - the customer's eye is already on the
   line they are waiting for. */
.vpnpay-pay__value--hidden {
    letter-spacing: 0.18em;
    color: var(--vpn-text-muted);
    user-select: none;
}

.vpnpay-withheld__button {
    display: inline-block;
    margin: 0.35rem 0 0;
    padding: 0.7rem 1.3rem;
    border: none;
    border-radius: 10px;
    background: var(--vpn-grad-brand);
    color: var(--vpn-on-brand);
    font-weight: 600;
    cursor: pointer;
    min-height: 44px;
}

.vpnpay-withheld__button:hover,
.vpnpay-withheld__button:focus {
    filter: brightness(1.08);
}

.vpnpay-withheld__button[disabled] {
    opacity: 0.7;
    cursor: default;
}

.vpnpay-withheld__note {
    margin: 0.5rem 0 0;
    font-size: 0.82rem;
    color: var(--vpn-text-muted);
}

/* ------------------------------------------------- the ordering flow ------

   FOSSBilling's order page is a stock Bootstrap accordion. This is the page
   where a customer decides whether to pay, so it should not be the one page
   that looks like a different product.

   Only presentation is changed. The module's JavaScript binds to .accordion-*,
   #orderManager and #payment-html, so those names are left exactly as they are;
   a prettier page that cannot take an order would be a worse page. */

.vpn-order {
    max-width: 780px;
    margin-inline: auto;
}

/* How far through they are. Four collapsed bars with no numbers leaves a
   customer guessing how much longer this takes. */
.vpn-order__steps {
    display: flex;
    gap: 0.4rem;
    list-style: none;
    counter-reset: vpn-order-step;
    margin: 0 0 1.1rem;
    padding: 0;
    flex-wrap: wrap;
}

.vpn-order__step {
    counter-increment: vpn-order-step;
    display: flex;
    align-items: center;
    gap: 0.45rem;
    flex: 1 1 0;
    min-width: 0;
    font-size: 0.8rem;
    color: var(--vpn-text-muted);
    white-space: nowrap;
}

.vpn-order__step::before {
    content: counter(vpn-order-step);
    display: grid;
    place-items: center;
    width: 1.45rem;
    height: 1.45rem;
    flex: 0 0 auto;
    border-radius: 50%;
    background: color-mix(in srgb, var(--vpn-accent) 16%, transparent);
    border: 1px solid color-mix(in srgb, var(--vpn-accent) 34%, transparent);
    color: var(--vpn-accent);
    font-size: 0.72rem;
    font-weight: 700;
}

.vpn-order__panel {
    border: 1px solid var(--vpn-border);
    border-radius: var(--vpn-r-lg);
    background: var(--vpn-surface);
    box-shadow: var(--vpn-shadow-md);
    overflow: hidden;
}

/* Bootstrap paints its own borders and radii on every item, which fights the
   panel's rounded edge. Removed so the group reads as one card. */
.vpn-order__accordion .accordion-item {
    background: transparent;
    border: 0;
    border-top: 1px solid var(--vpn-border);
}

.vpn-order__accordion .accordion-item:first-child {
    border-top: 0;
}

.vpn-order__accordion .accordion-button {
    background: transparent;
    color: var(--vpn-text);
    font-weight: 600;
    font-size: 0.98rem;
    padding: 1.05rem 1.25rem;
    box-shadow: none;
    /* Comfortably above the 44px minimum touch target. */
    min-height: 56px;
}

.vpn-order__accordion .accordion-button:not(.collapsed) {
    background: color-mix(in srgb, var(--vpn-accent) 10%, transparent);
    color: var(--vpn-accent);
    box-shadow: inset 3px 0 0 var(--vpn-accent);
}

.vpn-order__accordion .accordion-button:focus-visible {
    outline: none;
    box-shadow: var(--vpn-ring);
}

.vpn-order__accordion .accordion-button::after {
    filter: grayscale(1) opacity(0.55);
}

.vpn-order__accordion .accordion-button:not(.collapsed)::after {
    filter: none;
}

.vpn-order__accordion .accordion-body {
    padding: 1.1rem 1.25rem 1.4rem;
}

/* The cart table inherits Bootstrap's striped look, which is heavier than
   anything else in the shop. */
.vpn-order__accordion .table {
    --bs-table-bg: transparent;
    --bs-table-striped-bg: color-mix(in srgb, var(--vpn-text) 3%, transparent);
    --bs-table-color: var(--vpn-text);
    --bs-table-striped-color: var(--vpn-text);
    --bs-table-border-color: var(--vpn-border);
    margin-bottom: 0;
}

.vpn-order__reassurance {
    margin: 0.6rem 0 0;
    font-size: 0.85rem;
    color: var(--vpn-text-2);
    max-width: 42ch;
}

/* The module's loading overlay was a translucent grey sheet with an animated
   GIF centred in it. Same behaviour, same class name the script toggles. */
.vpn-order__loading {
    position: fixed;
    inset: 0;
    z-index: 999;
    display: grid;
    place-items: center;
    background: color-mix(in srgb, var(--vpn-page) 72%, transparent);
    backdrop-filter: blur(2px);
}

.vpn-order__spinner {
    width: 2.75rem;
    height: 2.75rem;
    border-radius: 50%;
    border: 3px solid color-mix(in srgb, var(--vpn-accent) 25%, transparent);
    border-top-color: var(--vpn-accent);
    animation: vpn-order-spin 0.8s linear infinite;
}

@keyframes vpn-order-spin {
    to { transform: rotate(360deg); }
}

/* Respecting a stated preference, not decoration. */
@media (prefers-reduced-motion: reduce) {
    .vpn-order__spinner {
        animation-duration: 2.4s;
    }
}

@media (max-width: 575.98px) {
    .vpn-order__steps {
        gap: 0.25rem;
    }

    /* The labels are the first thing to go when there is no room; the numbers
       still show the shape of the journey. */
    .vpn-order__step {
        font-size: 0;
        gap: 0;
        justify-content: center;
    }

    .vpn-order__step::before {
        font-size: 0.72rem;
    }

    .vpn-order__accordion .accordion-button,
    .vpn-order__accordion .accordion-body {
        padding-inline: 0.95rem;
    }
}

/* The currency chooser is a set of links now, not buttons: the panel that opens
   is decided by PHP, so it works whether or not the page's JavaScript ran. The
   payment HTML is injected with innerHTML inside the ordering flow, and scripts
   inserted that way never execute - which is why the buttons did nothing there.
   Links need the button's appearance back. */
a.vpnpay-choice,
a.vpnpay-choice:hover,
a.vpnpay-choice:focus {
    text-decoration: none;
}

/* ------------------------------------------- choosing a payment method ----

   Each method used to be an empty label with its logo painted on as a CSS
   background and its name only in a hover tooltip - so on a phone, where there
   is no hover, the customer saw unlabelled icons at the moment of paying.
   Logo and name are separate elements now; nothing overlaps because nothing is
   layered. */

.vpn-gateway {
    position: relative;
}

/* Kept in the page rather than display:none so it stays keyboard reachable and
   screen readers still announce the group as radio buttons. */
.vpn-gateway__input {
    position: absolute;
    opacity: 0;
    width: 1px;
    height: 1px;
    pointer-events: none;
}

.vpn-gateway__tile {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    width: 7.25rem;
    padding: 0.9rem 0.6rem;
    border: 1px solid var(--vpn-border);
    border-radius: var(--vpn-r-md);
    background: var(--vpn-surface);
    cursor: pointer;
    text-align: center;
    transition: border-color var(--vpn-fast) var(--vpn-ease),
                background var(--vpn-fast) var(--vpn-ease),
                transform var(--vpn-fast) var(--vpn-ease);
}

.vpn-gateway__tile:hover {
    border-color: var(--vpn-accent);
    transform: translateY(-1px);
}

.vpn-gateway__logo {
    width: 40px;
    height: 40px;
    object-fit: contain;
    flex: 0 0 auto;
}

/* The name has to survive "Card / bank transfer" without pushing the tile out
   of the row. */
.vpn-gateway__name {
    font-size: 0.78rem;
    line-height: 1.25;
    color: var(--vpn-text-2);
    overflow-wrap: anywhere;
}

/* Selected. The checkmark is drawn rather than imported so it needs no icon
   font and cannot fail to load. */
.vpn-gateway__input:checked + .vpn-gateway__tile {
    border-color: var(--vpn-accent);
    background: color-mix(in srgb, var(--vpn-accent) 12%, var(--vpn-surface));
    box-shadow: inset 0 0 0 1px var(--vpn-accent);
}

.vpn-gateway__input:checked + .vpn-gateway__tile .vpn-gateway__name {
    color: var(--vpn-text);
    font-weight: 600;
}

.vpn-gateway__input:checked + .vpn-gateway__tile::after {
    content: "";
    position: absolute;
    top: 0.4rem;
    right: 0.4rem;
    width: 0.85rem;
    height: 0.85rem;
    border-radius: 50%;
    background: var(--vpn-accent);
    box-shadow: 0 0 0 2px var(--vpn-surface);
}

/* Keyboard focus must be visible even though the radio itself is not. */
.vpn-gateway__input:focus-visible + .vpn-gateway__tile {
    outline: none;
    box-shadow: var(--vpn-ring);
}

@media (max-width: 575.98px) {
    .vpn-gateway__tile {
        width: 6.25rem;
        padding: 0.75rem 0.5rem;
    }
}

/* --------------------------------------------- the header on a phone ------

   On an iPhone the Register button was cut off at the right edge: the header is
   a non-wrapping flex row, and `overflow-x: hidden` further up clips whatever
   does not fit rather than letting it scroll. So the button was there, just
   unreachable - the shop owner found it in Safari.

   The widest item is the language picker. A native <select> sizes itself to its
   longest option, and this one carries 31 languages including "English
   (Australian)" - roughly 240px of a 390px screen spent on a control most
   customers touch once. Everything else in the row then has nowhere to go.

   Fixed by making the row able to shrink, rather than by hiding anything: a
   customer who cannot reach Register cannot become a customer. */

@media (max-width: 575.98px) {
    /* The row may wrap if it still cannot fit, so nothing is ever clipped. */
    .vpn-header {
        flex-wrap: wrap;
        row-gap: 10px;
    }

    /* The picker gives up its width first. The chosen language still shows;
       a longer name ends in an ellipsis and the full list is one tap away. */
    .vpn-header .form-select.js-locale-selector {
        width: auto;
        max-width: 6.5rem;
        min-width: 0;
        flex: 0 1 auto;
        padding-inline: 0.5rem;
        text-overflow: ellipsis;
    }

    /* Flex children refuse to shrink below their content by default, which is
       what pushed the button off the edge in the first place. */
    .vpn-header > * {
        min-width: 0;
    }

    /* The one control a visitor must be able to reach. It keeps its full size
       and is the last thing allowed to shrink. */
    .vpn-header .vpn-btn--primary {
        flex: 0 0 auto;
        margin-inline-start: auto;
    }
}

/* Narrower still - an iPhone SE. The brand name goes; the mark alone is enough
   to identify the site and is still a link home. */
@media (max-width: 359.98px) {
    .vpn-header .form-select.js-locale-selector {
        max-width: 4.5rem;
    }

    .vpn-brand img {
        max-width: 5.5rem;
    }
}
