/* VirtFusion Direct Provisioning Module Styles */ /* Typography */ .vf-bold { font-weight: 800; } .vf-small { font-size: 0.9rem; } /* Buttons */ .vf-spinner-margin { margin-right: 7px; } /* Status Badges */ .vf-badge { font-size: 0.75rem; padding: 0.35rem 0.75rem; text-transform: uppercase; font-weight: 700; border-radius: 6px; display: inline-block; } .vf-badge-active { background-color: rgba(32, 177, 0, 0.12); color: #276900; } .vf-badge-awaiting { background-color: rgba(177, 89, 0, 0.12); color: #692000; } .vf-badge-suspended { background-color: rgba(220, 53, 69, 0.12); color: #721c24; } /* Power Management */ .vf-power-buttons { display: flex; flex-wrap: wrap; gap: 8px; } .vf-btn-power { min-width: 100px; font-weight: 600; text-transform: uppercase; font-size: 0.8rem; padding: 0.5rem 1rem; display: inline-flex; align-items: center; justify-content: center; gap: 5px; } /* Hidden elements (initial state) */ #vf-login-button-spinner { display: none; } #vf-password-reset-button-spinner { display: none; } #vf-password-reset-error { display: none; } #vf-password-reset-success { display: none; } #vf-login-error { display: none; } #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; } } /* Action Progress Banner */ #vf-action-progress { background: #337ab7; color: #fff; padding: 8px 16px; border-radius: 6px; margin-bottom: 12px; display: flex; align-items: center; gap: 10px; font-size: 0.85rem; } #vf-action-progress .spinner-border { width: 16px; height: 16px; border-width: 2px; } /* 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; } .vf-ip-address { font-family: monospace; font-size: 0.9rem; } /* 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: #28a745; } .vf-timeline-dot-pending { background: #ffc107; } .vf-timeline-content { font-size: 0.85rem; } /* Server Name Dropdown */ #vf-name-dropdown { position: relative; background: #fff; border: 1px solid #dee2e6; border-radius: 6px; margin-top: 4px; max-width: 250px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); z-index: 10; } .vf-name-option { padding: 6px 12px; cursor: pointer; font-family: monospace; font-size: 0.85rem; border-bottom: 1px solid #f0f0f0; } .vf-name-option:last-child { border-bottom: none; } .vf-name-option:hover { background: rgba(51,122,183,0.06); } /* Copy to Clipboard */ .vf-ip-copy { padding: 2px 5px; line-height: 1; color: #6c757d; background: none; border: 1px solid transparent; border-radius: 3px; cursor: pointer; vertical-align: middle; } .vf-ip-copy:hover { color: #337ab7; background: rgba(51,122,183,0.08); border-color: rgba(51,122,183,0.2); } .vf-copy-tooltip { position: absolute; margin-left: 4px; padding: 2px 8px; font-size: 0.75rem; color: #fff; background: #28a745; border-radius: 3px; white-space: nowrap; animation: vf-fade-in 0.2s ease; } @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: 0.9rem; 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: 0.85rem; 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: 0.7rem; 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.1rem; 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: 10px; color: #888; line-height: 1.2; } .vf-os-eol-badge { display: inline-block; background: #dc3545; color: #fff; font-size: 9px; font-weight: 700; padding: 1px 5px; border-radius: 3px; margin-top: 3px; } #vf-os-details { border-top: 1px solid #dee2e6; padding-top: 10px; } .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; } } /* Resource panel */ .vf-resource-item .progress { background-color: rgba(0,0,0,0.08); border-radius: 4px; } /* Order form slider UI */ .vf-slider-container { padding: 8px 0; } .vf-slider-value { font-weight: 600; font-size: 0.95rem; 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-power-buttons { flex-direction: column; } .vf-btn-power { width: 100%; } .vf-ip-row { flex-wrap: wrap; } } /* ========================================================================= Reverse DNS panel ========================================================================= */ .vf-rdns-row { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; padding: 8px 0; border-bottom: 1px solid rgba(0,0,0,.06); } .vf-rdns-row:last-child { border-bottom: none; } .vf-rdns-ip { font-family: monospace; font-size: 13px; min-width: 180px; font-weight: 600; } .vf-rdns-edit { display: flex; flex: 1 1 auto; gap: 6px; align-items: center; min-width: 240px; } .vf-rdns-input { flex: 1 1 auto; min-width: 180px; max-width: 420px; font-family: monospace; font-size: 13px; } .vf-rdns-badge { display: inline-block; padding: 2px 8px; border-radius: 10px; font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: .02em; line-height: 1.4; white-space: nowrap; } .vf-rdns-msg { flex-basis: 100%; font-size: 12px; display: none; padding-left: 180px; } .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; } @media (max-width: 768px) { .vf-rdns-row { flex-direction: column; align-items: stretch; } .vf-rdns-edit { flex-direction: column; align-items: stretch; } .vf-rdns-msg { padding-left: 0; } } /* Subnet-only rows (IPv6 /64 allocations). Distinct visual treatment so customers see "this is a subnet, not a host" without reading the badge. */ .vf-rdns-subnet-row { background: rgba(23, 162, 184, 0.04); border-left: 3px solid #17a2b8; padding-left: 8px; } .vf-rdns-subnet-form { flex-basis: 100%; padding: 10px 0 0 180px; display: flex; flex-direction: column; gap: 6px; } .vf-rdns-subnet-inputs { display: flex; gap: 6px; flex-wrap: wrap; } .vf-rdns-subnet-actions { display: flex; gap: 6px; align-items: center; } @media (max-width: 768px) { .vf-rdns-subnet-form { padding-left: 0; } .vf-rdns-subnet-inputs { flex-direction: column; } } /* ---------------- In-page Section Nav ---------------- */ .vf-section-nav-body { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; } .vf-section-nav-body::before { content: "Jump to:"; font-weight: 600; color: #555; margin-right: 4px; font-size: 13px; } .vf-nav-link { display: inline-block; padding: 4px 10px; border: 1px solid #d6d8db; border-radius: 4px; background: #f8f9fa; color: #333; text-decoration: none; font-size: 13px; line-height: 1.4; transition: background-color 0.12s ease, border-color 0.12s ease, color 0.12s ease; } .vf-nav-link:hover, .vf-nav-link:focus { background: #e9ecef; border-color: #adb5bd; color: #000; text-decoration: none; outline: none; } @media (max-width: 576px) { .vf-section-nav-body::before { display: block; width: 100%; margin-bottom: 4px; } } /* ---------------- Server Overview meta bar ---------------- */ .vf-overview-meta { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; padding: 8px 12px; background: #f8f9fa; border: 1px solid #e6e8eb; border-radius: 4px; } .vf-meta-chip { display: inline-block; padding: 3px 10px; background: #fff; border: 1px solid #d6d8db; border-radius: 12px; font-size: 12px; color: #333; line-height: 1.5; } .vf-meta-chip-muted { color: #6c757d; font-style: italic; background: transparent; border: none; padding: 3px 4px; } .vf-mask-ips-btn { margin-left: auto; font-size: 12px; padding: 3px 10px; } @media (max-width: 576px) { .vf-mask-ips-btn { margin-left: 0; width: 100%; } } /* ---------------- Live Stats panel ---------------- */ .vf-live-bar { width: 100%; height: 14px; background: #e9ecef; border-radius: 7px; overflow: hidden; position: relative; } .vf-live-bar-fill { height: 100%; background: linear-gradient(90deg, #28a745, #20c997); transition: width 0.5s ease, background 0.3s ease; } .vf-live-bar-fill.bg-warning { background: linear-gradient(90deg, #ffc107, #fd7e14); } .vf-live-bar-fill.bg-danger { background: linear-gradient(90deg, #dc3545, #c82333); } .vf-livestats-updated { color: #6c757d; } /* ---------------- Filesystem rows ---------------- */ .vf-fs-row .progress { background-color: #e9ecef; } .vf-fs-row .progress-bar { background-color: #337ab7; transition: width 0.5s ease; } .vf-fs-row .progress-bar.bg-warning { background-color: #ffc107 !important; } .vf-fs-row .progress-bar.bg-danger { background-color: #dc3545 !important; } /* ---------------- 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: 1rem; } .vf-panel-grid > .panel, .vf-panel-grid > .card { margin-bottom: 0 !important; height: 100%; } /* ---------------- Server Overview rename row ---------------- */ /* * Was previously a single flex row that squished the Save button on * narrower viewports. Wrap-on-overflow + min-widths keep buttons readable * regardless of cell width. */ .vf-rename-row { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; } .vf-rename-input-field { flex: 1 1 160px; min-width: 140px; max-width: 240px; } .vf-rename-btn-randomise, .vf-rename-btn-save { flex: 0 0 auto; white-space: nowrap; min-width: 38px; } .vf-rename-btn-save { min-width: 56px; } /* ---------------- IP cell rows (Server Overview) ---------------- */ /* * Each IPv4/IPv6 address renders as a compact row: address span + copy * button. Replaces the standalone Network panel; the per-address copy * affordance moved here. */ .vf-ip-cell-row { display: flex; align-items: center; gap: 6px; margin-bottom: 2px; line-height: 1.5; } .vf-ip-cell-row .vf-ip-address { word-break: break-all; } .vf-ip-cell-row:last-child { margin-bottom: 0; } /* ---------------- 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; }