/* VirtFusion Extended module styles */

/* =========================================================================
   Foundation (client area)
   -------------------------------------------------------------------------
   Everything in this block except .vf-hidden is scoped to .vf-module, the
   wrapper overview.tpl puts around the whole service page, so none of it
   leaks into the theme (checkout and the admin tab load this file too). Sizes
   are em, relative to the theme's body text, never rem: Bootstrap 3 themes
   such as Six set the root (html) font size to 10px, which shrank every rem
   size here to 62%. Type steps: 1em (inherited), .875em (.vf-small), .75em
   (.vf-xs), never below 11px.
   ========================================================================= */
.vf-module {
    --vf-primary: var(--bs-primary, var(--primary, #337ab7));
    --vf-success: #2f7d32;
    --vf-success-bg: #e6f4ea;
    --vf-warning: #8a5a00;
    --vf-warning-bg: #fff4e0;
    --vf-danger: #b42318;
    --vf-danger-bg: #fdecea;
    --vf-info: #1f5f99;
    --vf-info-bg: #e8f1fb;
    --vf-muted: #6b7280;
    --vf-border: #e5e7eb;
    --vf-surface: #f7f8fa;
    --vf-radius: 4px;
    --vf-radius-lg: 8px;
    --vf-gap: 12px;
}

/* Type */
.vf-module .vf-small {
    font-size: max(11px, .875em);
}
.vf-module .vf-xs {
    font-size: max(11px, .75em);
}
.vf-module .vf-mono {
    font-family: SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
    font-size: .9375em;
}
.vf-module .vf-muted {
    color: var(--vf-muted);
}

/* Layout */
.vf-module .vf-body {
    padding: 15px;
}
.vf-module .vf-stack {
    display: flex;
    flex-direction: column;
    gap: var(--vf-gap);
}
.vf-module .vf-row-between {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    flex-wrap: wrap;
}
.vf-module .vf-cols {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: 8px 24px;
}
.vf-module .vf-kv {
    display: grid;
    grid-template-columns: minmax(90px, max-content) minmax(0, 1fr);
    gap: 6px 16px;
    align-items: baseline;
    margin: 0;
}
.vf-module .vf-kv > dt {
    font-weight: 400;
    color: var(--vf-muted);
    margin: 0;
}
.vf-module .vf-kv > dd {
    margin: 0;
    min-width: 0;
    overflow-wrap: anywhere;
}
.vf-module .vf-tiles {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
    gap: 8px;
}
.vf-module .vf-tile {
    background: var(--vf-surface);
    border-radius: var(--vf-radius-lg);
    padding: 10px 12px;
}
.vf-module .vf-tile-label {
    display: block;
    font-size: max(11px, .8125em);
    color: var(--vf-muted);
}
.vf-module .vf-tile-value {
    display: block;
    font-size: 1.25em;
    font-weight: 600;
    line-height: 1.3;
}
.vf-module .vf-section + .vf-section {
    border-top: 1px solid var(--vf-border);
    margin-top: 16px;
    padding-top: 16px;
}
.vf-module .vf-section-title {
    font-size: 1em;
    font-weight: 600;
    margin: 0 0 2px;
}
.vf-module .vf-help {
    color: var(--vf-muted);
    font-size: max(11px, .875em);
    margin: 0 0 8px;
}
.vf-module .vf-btn-row {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}
.vf-module .vf-inline-field {
    display: flex;
    gap: 6px;
    align-items: center;
}
.vf-module .vf-inline-field > .form-control {
    flex: 1 1 auto;
    min-width: 0;
    width: auto;
}

/* Components */
.vf-module .vf-spinner {
    display: inline-block;
    width: 1em;
    height: 1em;
    border: 2px solid currentColor;
    border-right-color: transparent;
    border-radius: 50%;
    animation: vf-spin .75s linear infinite; /* @keyframes vf-spin is defined further down */
    vertical-align: -.125em;
}
.vf-module .vf-meter {
    height: 8px;
    background: var(--vf-border);
    border-radius: 999px;
    overflow: hidden;
}
.vf-module .vf-meter > span {
    display: block;
    height: 100%;
    width: 0;
    background: var(--vf-primary);
    border-radius: inherit;
    transition: width .3s;
}
.vf-module .vf-meter--warn > span {
    background: #e8a33d;
}
.vf-module .vf-meter--danger > span {
    background: #d64545;
}
.vf-module .vf-pill {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: max(11px, .8125em);
    line-height: 1.5;
    padding: 2px 10px;
    border-radius: 999px;
    font-weight: 600;
    white-space: nowrap;
    color: var(--vf-muted);
    background: var(--vf-surface);
}
.vf-module .vf-pill::before {
    content: "";
    width: .55em;
    height: .55em;
    border-radius: 50%;
    background: currentColor;
}
.vf-module .vf-pill--success {
    color: var(--vf-success);
    background: var(--vf-success-bg);
}
.vf-module .vf-pill--warning {
    color: var(--vf-warning);
    background: var(--vf-warning-bg);
}
.vf-module .vf-pill--danger {
    color: var(--vf-danger);
    background: var(--vf-danger-bg);
}
.vf-module .vf-pill--info {
    color: var(--vf-info);
    background: var(--vf-info-bg);
}
.vf-module .vf-pill--muted {
    color: var(--vf-muted);
    background: var(--vf-surface);
}
.vf-module .vf-btn-danger-outline {
    color: var(--vf-danger);
    border-color: var(--vf-danger);
    background: transparent;
}
.vf-module .vf-btn-danger-outline:hover,
.vf-module .vf-btn-danger-outline:focus,
.vf-module .vf-btn-danger-outline:active {
    color: #fff;
    border-color: var(--vf-danger);
    background: var(--vf-danger);
}
.vf-module .vf-copy-btn {
    min-width: 32px;
    min-height: 32px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
.vf-module .vf-focusable:focus-visible {
    outline: 2px solid var(--vf-primary);
    outline-offset: 2px;
}
/* Not scoped: also hides things the module adds outside .vf-module. */
.vf-hidden {
    display: none !important;
}

@media (max-width: 575px) {
    .vf-module .vf-kv {
        grid-template-columns: 1fr;
    }
    .vf-module .vf-kv > dd {
        margin-bottom: 6px;
    }
    .vf-module .vf-btn-row--grid {
        display: grid;
        grid-template-columns: 1fr 1fr;
    }
}
@media (prefers-reduced-motion: reduce) {
    .vf-module .vf-spinner {
        animation-duration: 1.5s;
    }
}
/* ======================= End of foundation block ======================= */

/* Typography (.vf-small now lives in the foundation block) */
.vf-bold {
    font-weight: 800;
}

/* Buttons */
.vf-spinner-margin {
    margin-right: 7px;
}

/* Power Management */
/* Layout comes from .vf-btn-row / .vf-btn-row--grid, and size, weight and
   case from the theme's .btn. Only a minimum width is set, so the four
   buttons line up. */
.vf-module .vf-btn-power {
    min-width: 7.5em;
}
.vf-module #vf-power-alert {
    margin: 12px 0 0;
}

/* Hidden elements (initial state) */
#vf-server-info {
    display: none;
}
#vf-server-info-error {
    display: none;
    margin: 10px;
}

/* Skeleton Loading */
.vf-skeleton {
    background: linear-gradient(90deg, #e9ecef 25%, #f4f4f4 50%, #e9ecef 75%);
    background-size: 200% 100%;
    animation: vf-skeleton-pulse 1.5s ease-in-out infinite;
    border-radius: 4px;
}
.vf-skeleton-line {
    height: 14px;
    margin-bottom: 10px;
    border-radius: 4px;
}
.vf-skeleton-line-short {
    width: 60%;
}
.vf-skeleton-line-medium {
    width: 80%;
}
@keyframes vf-skeleton-pulse {
    0% { background-position: 200% 0; }
    100% { background-position: -200% 0; }
}

/* Loader */
#vf-server-info-loader {
    min-height: 136px;
}
#vf-loading {
    display: inline-block;
    width: 30px;
    height: 30px;
    border: 3px solid rgba(225, 224, 224, 0.3);
    border-radius: 50%;
    border-top-color: #0e151a;
    animation: vf-spin 1s ease-in-out infinite;
    -webkit-animation: vf-spin 1s ease-in-out infinite;
}
.vf-loader {
    margin: 30px;
}

@keyframes vf-spin {
    to {
        transform: rotate(360deg);
    }
}
@-webkit-keyframes vf-spin {
    to {
        transform: rotate(360deg);
    }
}

/* Network / IP Management */
.vf-ip-row {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 4px 0;
}
/* Backup Timeline */
.vf-timeline {
    position: relative;
    padding-left: 20px;
    border-left: 2px solid #dee2e6;
    margin-left: 8px;
}
.vf-timeline-item {
    position: relative;
    padding: 8px 0 8px 12px;
}
.vf-timeline-dot {
    position: absolute;
    left: -27px;
    top: 12px;
    width: 12px;
    height: 12px;
    border-radius: 50%;
    border: 2px solid #fff;
}
.vf-timeline-dot-success {
    background: var(--vf-success, #2f7d32);
}
.vf-timeline-dot-pending {
    background: #e8a33d;
}
.vf-module .vf-timeline-date {
    font-weight: 600;
}
.vf-timeline-content {
    font-size: max(11px, .875em);
}

/* Copy to Clipboard */
@keyframes vf-fade-in {
    from { opacity: 0; }
    to { opacity: 1; }
}

/* OS Template Gallery */
.vf-os-category-header {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 10px 12px;
    margin-top: 6px;
    border: 1px solid #dee2e6;
    border-radius: 6px;
    cursor: pointer;
    font-weight: 700;
    font-size: 1em;
    user-select: none;
    transition: background 0.15s;
}
.vf-os-category:first-child .vf-os-category-header {
    margin-top: 0;
}
.vf-os-category-header:hover {
    background: rgba(0,0,0,0.03);
}
.vf-os-category-icon {
    width: 28px;
    height: 28px;
    min-width: 28px;
    min-height: 28px;
    border-radius: 6px;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #fff;
    font-weight: 700;
    font-size: .875em;
    flex-shrink: 0;
    overflow: hidden;
}
.vf-os-category-icon img {
    max-width: 100%;
    max-height: 100%;
    width: auto;
    height: auto;
    object-fit: contain;
}
.vf-os-category-arrow {
    margin-left: auto;
    font-size: max(11px, .75em);
    color: #888;
}
.vf-os-grid {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    padding: 10px 0;
    margin-bottom: 4px;
}
.vf-os-card {
    width: 120px;
    border: 2px solid #dee2e6;
    border-radius: 8px;
    padding: 10px 8px;
    text-align: center;
    cursor: pointer;
    overflow: hidden;
    transition: border-color 0.15s, background-color 0.15s, box-shadow 0.15s;
}
.vf-os-card:hover {
    border-color: #337ab7;
}
.vf-os-card-selected {
    border-color: #337ab7;
    background: rgba(51,122,183,0.06);
    box-shadow: 0 0 0 1px rgba(51,122,183,0.3);
}
.vf-os-card-eol {
    opacity: 0.6;
}
.vf-os-icon {
    width: 40px;
    height: 40px;
    border-radius: 8px;
    margin: 0 auto 6px;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #fff;
    font-weight: 700;
    font-size: 1.25em;
    overflow: hidden;
    flex-shrink: 0;
}
.vf-os-icon img {
    max-width: 100%;
    max-height: 100%;
    width: 24px;
    height: 24px;
    object-fit: contain;
}
.vf-os-label {
    font-weight: 600;
    font-size: 12px;
    line-height: 1.2;
}
.vf-os-version {
    font-size: max(11px, .75em);
    color: #888;
    line-height: 1.2;
}
.vf-os-eol-badge {
    display: inline-block;
    background: #dc3545;
    color: #fff;
    font-size: max(11px, .75em);
    font-weight: 700;
    padding: 1px 5px;
    border-radius: 3px;
    margin-top: 3px;
}
.vf-os-search {
    margin-bottom: 10px;
}

@media (max-width: 768px) {
    .vf-os-grid {
        gap: 6px;
    }
    .vf-os-card {
        width: calc(50% - 3px);
        min-width: 100px;
    }
}

/* ---------------- Traffic panel ---------------- */
.vf-module #vf-traffic-chart {
    display: block;
    width: 100%;
    max-width: 100%;
    height: 240px;
}

/* Order form slider UI */
.vf-slider-container {
    padding: 8px 0;
}
.vf-slider-value {
    font-weight: 600;
    font-size: 1em;
    margin-bottom: 4px;
    text-align: center;
}
.vf-slider {
    width: 100%;
    height: 6px;
    -webkit-appearance: none;
    appearance: none;
    background: #ddd;
    border-radius: 3px;
    outline: none;
    cursor: pointer;
}
.vf-slider::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    width: 20px;
    height: 20px;
    border-radius: 50%;
    background: #337ab7;
    cursor: pointer;
    border: 2px solid #fff;
    box-shadow: 0 1px 3px rgba(0,0,0,0.2);
}
.vf-slider::-moz-range-thumb {
    width: 20px;
    height: 20px;
    border-radius: 50%;
    background: #337ab7;
    cursor: pointer;
    border: 2px solid #fff;
    box-shadow: 0 1px 3px rgba(0,0,0,0.2);
}

/* Toggle Switch */
.vf-toggle-input {
    display: none;
}
.vf-toggle-switch {
    position: relative;
    display: inline-block;
    width: 36px;
    height: 20px;
    background: #ccc;
    border-radius: 10px;
    transition: background 0.2s;
    flex-shrink: 0;
}
.vf-toggle-switch::after {
    content: '';
    position: absolute;
    top: 2px;
    left: 2px;
    width: 16px;
    height: 16px;
    background: #fff;
    border-radius: 50%;
    transition: transform 0.2s;
}
.vf-toggle-input:checked + .vf-toggle-switch {
    background: #28a745;
}
.vf-toggle-input:checked + .vf-toggle-switch::after {
    transform: translateX(16px);
}

/* Responsive adjustments */
@media (max-width: 768px) {
    .vf-ip-row {
        flex-wrap: wrap;
    }
}

/* =========================================================================
   Reverse DNS panel
   ========================================================================= */
/* One row per IP: address | PTR editor | status pill. The save message, or a
   subnet's add-host form, sits on a second line under the editor. The label
   column width lives in one place (the grid) instead of three 180px copies.
   Each row is its own grid, so the pill track is a fixed width that fits the
   longest label ("Unverified"): with `auto` it followed each row's own label
   and Save and the pills drifted sideways from row to row. */
.vf-module .vf-rdns-row {
    display: grid;
    grid-template-columns: minmax(8em, 16em) minmax(0, 1fr) 7.5em;
    align-items: center;
    gap: 6px 12px;
    padding: 8px 0;
    border-bottom: 1px solid var(--vf-border);
}
.vf-module .vf-rdns-row > .vf-pill {
    justify-self: start;
}
.vf-module .vf-rdns-row:last-child {
    border-bottom: none;
}
.vf-module .vf-rdns-ip {
    min-width: 0;
    font-weight: 600;
    overflow-wrap: anywhere;
}
.vf-module .vf-rdns-edit {
    display: flex;
    align-items: stretch;
    gap: 6px;
    min-width: 0;
}
/* height:auto + the row's stretch keep the input exactly as tall as Save in
   Bootstrap 4/5 too, where the smaller .vf-mono text would make it 1.5px shorter. */
.vf-module .vf-rdns-edit > .form-control {
    flex: 1 1 auto;
    width: auto;
    height: auto;
    min-width: 0;
    max-width: 420px;
}
.vf-module .vf-rdns-msg,
.vf-module .vf-rdns-subnet-form {
    grid-column: 2 / -1;
}
.vf-module .vf-rdns-msg {
    display: none;
}
.vf-module .vf-rdns-msg--success {
    color: var(--vf-success);
}
.vf-module .vf-rdns-msg--error {
    color: var(--vf-danger);
}

/* Subnet-only rows (IPv6 /64 allocations). Tinted so customers see "this is a
   range, not a host" without reading the pill. The negative margins equal the
   border + padding, so the tint reaches into the panel padding and the grid
   tracks stay in line with the other rows. */
.vf-module .vf-rdns-subnet-row {
    margin-left: -11px;
    margin-right: -8px;
    padding-left: 8px;
    padding-right: 8px;
    background: var(--vf-info-bg);
    border-left: 3px solid var(--vf-info);
}
.vf-module .vf-rdns-subnet-form {
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.vf-module .vf-rdns-subnet-inputs {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 6px;
}
.vf-module .vf-rdns-subnet-actions {
    display: flex;
    align-items: center;
    gap: 6px;
}
/* Phones: address and pill on the first line, the editor full width below. */
@media (max-width: 575px) {
    .vf-module .vf-rdns-row {
        grid-template-columns: minmax(0, 1fr) auto;
    }
    .vf-module .vf-rdns-ip {
        grid-column: 1;
        grid-row: 1;
    }
    .vf-module .vf-rdns-row > .vf-pill {
        grid-column: 2;
        grid-row: 1;
    }
    .vf-module .vf-rdns-edit,
    .vf-module .vf-rdns-msg,
    .vf-module .vf-rdns-subnet-form {
        grid-column: 1 / -1;
    }
    .vf-module .vf-rdns-edit > .form-control {
        max-width: none;
    }
}

/* Admin services tab (AdminHTML::rdnsSection; the admin area is Bootstrap 3). */
.vf-rdns-admin-row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 4px 0;
    font-size: 13px;
}
.vf-rdns-ip-admin {
    font-family: monospace;
    font-weight: 600;
    min-width: 180px;
}
.vf-rdns-ptr-admin {
    font-family: monospace;
    color: #333;
    flex: 1 1 auto;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* ---------------- Live Stats panel ---------------- */
/* Columns size to their content (min 180px), so "738 MB / 1.92 GB (38%)"
   stays on the Memory label's line at Bootstrap 4/5's 16px body text,
   where three equal columns would wrap it. */
.vf-module .vf-live-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, auto));
    gap: 12px 24px;
}
.vf-module .vf-live-item .vf-meter {
    margin-top: 6px;
}
.vf-module .vf-live-item .vf-row-between + .vf-row-between {
    margin-top: 6px;
}
.vf-module .vf-live-item .vf-help {
    margin: 6px 0 0;
}
.vf-module .vf-live-updated {
    font-weight: 400;
}
.vf-module #vf-live-unavailable {
    margin: 0;
}
/* Filesystem usage: a .vf-section after #vf-live-grid (also a .vf-section),
   so it gets the divider. */
.vf-module .vf-fs-row + .vf-fs-row {
    margin-top: 10px;
}
.vf-module .vf-fs-row .vf-meter {
    margin-top: 4px;
}

/* ---------------- Layout: side-by-side panel grid ---------------- */
/*
 * Used to lay out compact panels (Traffic + Live Stats) side-by-side on
 * wide screens. CSS Grid with auto-fit handles the case where one panel is
 * display:none (e.g. Live Stats hidden when remoteState is unavailable) —
 * the visible panel fills the row.
 */
.vf-panel-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 360px), 1fr));
    gap: 16px;
}
.vf-panel-grid > .panel,
.vf-panel-grid > .card {
    margin-bottom: 0 !important;
    height: 100%;
}

/* ---------------- Sensitive-input masking ---------------- */
/*
 * Companion to the JS-based IP text masking. When body.vf-mask-active is
 * set, render the value of any input.vf-sensitive as discs so the actual
 * characters don't leak into a screenshot. Hover/focus restores the real
 * value for editing — the customer can still see what they're typing.
 *
 * `text-security` is widely supported under the -webkit- prefix (Chrome,
 * Edge, Safari) and as the unprefixed property in modern Firefox. Falls
 * through to `-webkit-text-security: disc` everywhere else; if a browser
 * truly doesn't honour it the screenshot mask just isn't applied to the
 * input field — the IP cells still mask, so the customer's worst case is
 * an unmasked rDNS hostname (failsafe-soft, not security-critical).
 */
body.vf-mask-active input.vf-sensitive {
    -webkit-text-security: disc;
    text-security: disc;
    font-family: text-security-disc, sans-serif;
    transition: filter 0.15s ease;
}
body.vf-mask-active input.vf-sensitive:focus,
body.vf-mask-active input.vf-sensitive:hover {
    -webkit-text-security: none;
    text-security: none;
    font-family: inherit;
}

/* =========================================================================
   vfConfirm — in-page confirmation modal
   ========================================================================= */
.vf-confirm-backdrop{position:fixed;inset:0;z-index:99999;display:flex;align-items:center;justify-content:center;background:rgba(15,23,42,0);backdrop-filter:blur(0px);transition:background 0.2s ease,backdrop-filter 0.2s ease}
.vf-confirm-backdrop.vf-confirm-visible{background:rgba(15,23,42,0.45);backdrop-filter:blur(4px)}
.vf-confirm-dialog{background:#ffffff;border-radius:18px;box-shadow:0 24px 60px rgba(15,23,42,0.18),0 4px 12px rgba(15,23,42,0.08);padding:28px 28px 24px;max-width:420px;width:calc(100% - 32px);display:flex;flex-direction:column;gap:16px;transform:translateY(12px) scale(0.97);opacity:0;transition:transform 0.22s cubic-bezier(0.34,1.56,0.64,1),opacity 0.18s ease}
.vf-confirm-backdrop.vf-confirm-visible .vf-confirm-dialog{transform:translateY(0) scale(1);opacity:1}
.vf-confirm-icon{width:44px;height:44px;border-radius:12px;background:#f1f5f9;display:flex;align-items:center;justify-content:center;color:#64748b;flex-shrink:0}
.vf-confirm-icon.vf-confirm-icon-danger{background:#fff1f2;color:#e11d48}
.vf-confirm-body{display:flex;flex-direction:column;gap:6px}
.vf-confirm-title{font-size:16px;font-weight:700;color:#0f172a;line-height:1.3}
.vf-confirm-msg{font-size:13.5px;color:#475569;line-height:1.6}
.vf-confirm-actions{display:flex;gap:10px;justify-content:flex-end;margin-top:4px}
.vf-confirm-btn{appearance:none;border-radius:999px;padding:9px 20px;font-size:13.5px;font-weight:600;cursor:pointer;border:none;transition:all 0.15s ease;line-height:1}
.vf-confirm-btn-cancel{background:#f1f5f9;color:#475569;border:1.5px solid #e2e8f0}
.vf-confirm-btn-cancel:hover{background:#e2e8f0;color:#0f172a}
.vf-confirm-btn-danger{background:#e11d48;color:#ffffff;box-shadow:0 2px 8px rgba(225,29,72,0.30)}
.vf-confirm-btn-danger:hover{background:#be123c;box-shadow:0 4px 14px rgba(225,29,72,0.35)}
.vf-confirm-btn-danger:active{transform:translateY(1px)}
.vf-confirm-btn-primary{background:#2563eb;color:#ffffff;box-shadow:0 2px 8px rgba(37,99,235,0.28)}
.vf-confirm-btn-primary:hover{background:#1d4ed8}
.vf-confirm-btn:focus-visible{outline:2px solid #2563eb;outline-offset:2px}

/* =========================================================================
   Panel shell (shared by every panel; added by Task 5)
   The one place for panel-level rules: later tasks rely on these and add
   no panel margin or title rules of their own. They stand in for the
   Bootstrap 4-only mb-2 / m-0 utilities the panels used, and size every
   panel title at 1.143em (16px at a 14px body) in Bootstrap 3, 4 and 5;
   Bootstrap 4/5 would otherwise render the h3 at 28px.
   ========================================================================= */
.vf-module .panel.card {
    margin-bottom: var(--vf-gap);
}
.vf-module .panel-heading .panel-title,
.vf-module .card-header .card-title {
    margin: 0;
    font-size: 1.143em;
}

/* =========================================================================
   Server Overview (Task 5)
   ========================================================================= */
.vf-module #vf-server-info-error {
    margin: 0 0 12px;
}
.vf-module #vf-server-info-error .alert {
    margin-bottom: 0;
}

/* Meta bar: location, OS and created chips plus the Mask sensitive toggle.
   The font size comes from .vf-small on each chip and on the button. */
.vf-module .vf-overview-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin-bottom: 16px;
    padding: 8px 12px;
    background: var(--vf-surface);
    border: 1px solid var(--vf-border);
    border-radius: var(--vf-radius-lg);
}
.vf-module .vf-meta-chip {
    display: inline-block;
    padding: 2px 10px;
    line-height: 1.5;
    background: #fff;
    border: 1px solid var(--vf-border);
    border-radius: 999px;
}
.vf-module .vf-meta-chip-muted {
    padding-right: 4px;
    padding-left: 4px;
    color: var(--vf-muted);
    background: transparent;
    border-color: transparent;
}
.vf-module .vf-mask-ips-btn {
    margin-left: auto;
}

/* A <label> inside a .vf-kv dt keeps the dt look in every Bootstrap. */
.vf-module .vf-kv > dt > label {
    display: inline;
    margin: 0;
    font-weight: inherit;
    color: inherit;
}

/* Rename: field, suggest and Save on one line; the suggestions list
   overlays the rows below instead of pushing them down. */
.vf-module .vf-rename-wrap {
    position: relative;
}
.vf-module #vf-rename-input {
    min-width: 6em;
}
.vf-module #vf-randomise-btn,
.vf-module #vf-rename-save {
    flex: 0 0 auto;
    white-space: nowrap;
}
.vf-module #vf-name-dropdown {
    position: absolute;
    top: 100%;
    left: 0;
    z-index: 20;
    min-width: 200px;
    max-width: 100%;
    margin-top: 4px;
    padding: 4px 0;
    background: #fff;
    border: 1px solid var(--vf-border);
    border-radius: var(--vf-radius-lg);
    box-shadow: 0 4px 12px rgba(0, 0, 0, .12);
}
.vf-module .vf-name-option {
    display: block;
    width: 100%;
    padding: 6px 12px;
    color: inherit;
    text-align: left;
    background: transparent;
    border: 0;
    cursor: pointer;
}
.vf-module .vf-name-option:hover,
.vf-module .vf-name-option:focus {
    background: var(--vf-surface);
}
.vf-module .vf-name-option--more {
    margin-top: 4px;
    font-size: max(11px, .875em);
    color: var(--vf-muted);
    text-align: center;
    border-top: 1px solid var(--vf-border);
}
.vf-module #vf-rename-alert {
    margin: 6px 0 0;
    padding: 6px 10px;
    font-size: max(11px, .875em);
}

/* IP rows: one address per row, each with a 32px copy target. */
.vf-module .vf-ip-cell-row {
    display: flex;
    align-items: center;
    gap: 6px;
    min-height: 32px;
}
.vf-module .vf-ip-cell-row .vf-ip-address {
    min-width: 0;
    overflow-wrap: anywhere;
}

/* Copy buttons (vfCopyButton; usable in any panel): a quiet icon button.
   The "Copied" / "Copy failed" note is a child of the button, to its right. */
.vf-module .vf-copy-ghost {
    position: relative;
    padding: 0 6px;
    line-height: 1;
    color: var(--vf-muted);
    background: transparent;
    border: 1px solid transparent;
    border-radius: var(--vf-radius);
    box-shadow: none;
}
.vf-module .vf-copy-ghost:hover,
.vf-module .vf-copy-ghost:focus {
    color: var(--vf-primary);
    background: var(--vf-surface);
    border-color: var(--vf-border);
}
.vf-module .vf-copy-ghost svg {
    display: block;
}
.vf-module .vf-copy-tooltip {
    position: absolute;
    top: 50%;
    left: 100%;
    z-index: 5;
    margin-left: 6px;
    padding: 2px 8px;
    font-size: max(11px, .75em);
    font-weight: 600;
    line-height: 1.5;
    color: #fff;
    white-space: nowrap;
    background: var(--vf-success);
    border-radius: var(--vf-radius);
    transform: translateY(-50%);
    pointer-events: none;
    animation: vf-fade-in .2s ease;
}
.vf-module .vf-copy-tooltip--error {
    background: var(--vf-danger);
}

/* Footer: Log in to control panel. */
.vf-module .vf-overview-footer {
    margin-top: 16px;
    padding-top: 16px;
    border-top: 1px solid var(--vf-border);
}
.vf-module #vf-login-error {
    margin-bottom: 12px;
}
.vf-module p.vf-overview-footer-note {
    margin: 8px 0 0;
}
.vf-module .vf-link-btn {
    padding: 0;
    font: inherit;
    color: var(--vf-primary);
    text-decoration: underline;
    background: none;
    border: 0;
    cursor: pointer;
}

@media (max-width: 575px) {
    .vf-module .vf-mask-ips-btn {
        width: 100%;
        margin-left: 0;
    }
}

/* =========================================================================
   Manage panel — login credentials, root password shown once, backups
   ========================================================================= */
.vf-module #vf-sec-manage .alert {
    margin: 12px 0 0;
}
.vf-module .vf-secret-result {
    margin-top: 12px;
}
.vf-module .vf-secret-result label {
    display: block;
    font-weight: 600;
    margin: 0 0 4px;
}
.vf-module .vf-secret-result .vf-inline-field + label {
    margin-top: 10px;
}
.vf-module .vf-secret-result .vf-inline-field > .btn {
    flex: 0 0 auto;
}
/* One height for the field and its buttons: Bootstrap 4 sizes .form-control
   in em, so the smaller .vf-mono text would leave the field 1.5px short. */
.vf-module .vf-secret-result .vf-inline-field {
    align-items: stretch;
}
.vf-module .vf-secret-result .vf-inline-field > .form-control {
    height: auto;
}
.vf-module .vf-secret-note {
    margin: 6px 0 0;
}
/* Mask Sensitive (vfApplyIpMask toggles body.vf-mask-active) hides one-time
   secrets completely instead of blurring them, so hovering cannot reveal
   them in a screenshot. */
.vf-module .vf-show-when-masked {
    display: none;
}
body.vf-mask-active .vf-module .vf-hide-when-masked {
    display: none !important;
}
body.vf-mask-active .vf-module .vf-show-when-masked {
    display: block;
}

/* =========================================================================
   Rebuild panel — form spacing, OS search, keyboard-operable OS gallery
   ========================================================================= */
.vf-module .vf-rebuild-warning {
    margin-bottom: 15px;
}
.vf-module .vf-rebuild-field {
    margin-bottom: 15px;
}
.vf-module .vf-rebuild-field > label {
    display: block;
    font-weight: 600;
    margin: 0 0 5px;
}
.vf-module .vf-os-search {
    margin-bottom: 0;
}
.vf-module #vf-os-no-match {
    margin: 0 0 15px;
}
.vf-module .vf-rebuild-ssh-paste {
    margin-top: 8px;
}
.vf-module .vf-rebuild-ssh-help {
    margin: 6px 0 0;
}
.vf-module .vf-rebuild-selected {
    margin-bottom: 10px;
}
.vf-module .vf-rebuild-selected-desc {
    display: block;
}
.vf-module .vf-rebuild-actions {
    align-items: center;
}
/* Stay beside the button on a phone: take the rest of the row and wrap
   inside it rather than dropping below the button. */
.vf-module .vf-rebuild-progress {
    flex: 1 1 0;
    min-width: 0;
}
.vf-module #vf-rebuild-alert {
    margin: 12px 0 0;
}
/* In the client area the OS category headers and cards are <button>s (the
   checkout gallery in hooks.php still builds <div>s and uses the shared
   rules above). Reset the browser's button look, then restyle. */
.vf-module button.vf-os-category-header {
    width: 100%;
    background: transparent;
    color: inherit;
    font: inherit;
    font-weight: 600;
    text-align: left;
    line-height: 1.4;
}
.vf-module button.vf-os-category-header:hover {
    background: rgba(0, 0, 0, 0.03);
}
.vf-module button.vf-os-card {
    background: transparent;
    color: inherit;
    font: inherit;
    line-height: 1.3;
    vertical-align: top;
}
.vf-module button.vf-os-card .vf-os-label,
.vf-module button.vf-os-card .vf-os-version {
    display: block;
}
.vf-module .vf-os-label {
    font-size: max(12px, .875em);
}
.vf-module .vf-os-version {
    font-size: max(11px, .8125em);
    color: var(--vf-muted);
}
.vf-module .vf-os-eol-badge {
    font-size: 11px;
}
.vf-module .vf-os-category-arrow {
    font-size: 11px;
    color: var(--vf-muted);
}
.vf-module .vf-os-card:hover,
.vf-module .vf-os-card-selected {
    border-color: var(--vf-primary);
}
.vf-module .vf-os-card-selected {
    background: var(--vf-surface);
    box-shadow: 0 0 0 1px var(--vf-primary);
}

/* =========================================================================
   Panel shell additions (the panel margin and title reset live in T5's
   "Panel shell" section)
   ========================================================================= */
/* A closing alert (the Suspended, Pending and other status notices) sits on
   the panel padding instead of adding Bootstrap's 20px alert margin under it.
   Never put .vf-stack or .vf-row-between on .panel-body itself: Bootstrap 3
   gives it clearfix ::before/::after boxes, which become flex items and add a
   gap at both ends. */
.vf-module .vf-body > .alert:last-child,
.vf-module .vf-stack > .alert {
    margin-bottom: 0;
}
/* Right-aligned figures, e.g. a table's cost column. */
.vf-module .vf-num {
    text-align: right;
    font-variant-numeric: tabular-nums;
}

/* =========================================================================
   Billing & Usage panel (self-service)
   ========================================================================= */
.vf-module .vf-ss-credit {
    align-self: flex-start;
    min-width: 180px;
}
/* Bootstrap 3 gives .table-responsive a border and a bottom margin on phones. */
.vf-module .vf-ss-table-wrap {
    margin-bottom: 0;
    border: 0;
}
.vf-module .vf-usage-table {
    margin-bottom: 0;
}
/* Compact rows in every version (table-sm is Bootstrap 4+ only). */
.vf-module .vf-usage-table > thead > tr > th,
.vf-module .vf-usage-table > tbody > tr > td {
    padding: 6px 8px;
}
