/* * noVNC base CSS * Copyright (C) 2019 The noVNC authors * noVNC is licensed under the MPL 2.0 (see LICENSE.txt) * This file is licensed under the 2-Clause BSD license (see LICENSE.txt). */ /* * Z index layers: * * 0: Main screen * 10: Control bar * 50: Transition blocker * 60: Connection popups * 100: Status bar * ... * 1000: Javascript crash * ... * 10000: Max (used for polyfills) */ /* * State variables (set on :root): * * noVNC_loading: Page is still loading * noVNC_connecting: Connecting to server * noVNC_reconnecting: Re-establishing a connection * noVNC_connected: Connected to server (most common state) * noVNC_disconnecting: Disconnecting from server */ :root { font-family: sans-serif; line-height: 1.6; } body { margin:0; padding:0; /*Background image with light grey curve.*/ background-color:#494949; background-repeat:no-repeat; background-position:right bottom; height:100%; touch-action: none; } html { height:100%; } .noVNC_only_touch.noVNC_hidden { display: none; } .noVNC_disabled { color: var(--novnc-grey); } /* ---------------------------------------- * Spinner * ---------------------------------------- */ .noVNC_spinner { position: relative; } .noVNC_spinner, .noVNC_spinner::before, .noVNC_spinner::after { width: 10px; height: 10px; border-radius: 2px; box-shadow: -60px 10px 0 rgba(255, 255, 255, 0); animation: noVNC_spinner 1.0s linear infinite; } .noVNC_spinner::before { content: ""; position: absolute; left: 0px; top: 0px; animation-delay: -0.1s; } .noVNC_spinner::after { content: ""; position: absolute; top: 0px; left: 0px; animation-delay: 0.1s; } @keyframes noVNC_spinner { 0% { box-shadow: -60px 10px 0 rgba(255, 255, 255, 0); width: 20px; } 25% { box-shadow: 20px 10px 0 rgba(255, 255, 255, 1); width: 10px; } 50% { box-shadow: 60px 10px 0 rgba(255, 255, 255, 0); width: 10px; } } /* ---------------------------------------- * WebKit centering hacks * ---------------------------------------- */ .noVNC_center { /* * This is a workaround because webkit misrenders transforms and * uses non-integer coordinates, resulting in blurry content. * Ideally we'd use "top: 50%; transform: translateY(-50%);" on * the objects instead. */ display: flex; align-items: center; justify-content: center; position: fixed; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; } .noVNC_center > * { pointer-events: auto; } .noVNC_crosscenter { display: flex !important; flex-direction: column; justify-content: center; position: fixed; top: 0; left: 0; height: 100%; margin: 0 !important; padding: 0 !important; pointer-events: none; } .noVNC_crosscenter > * { pointer-events: auto; } .noVNC_right .noVNC_crosscenter { left: auto; right: 0; } .noVNC_top.noVNC_crosscenter, .noVNC_top .noVNC_crosscenter { flex-direction: row; width: 100%; height: auto; } .noVNC_bottom.noVNC_crosscenter, .noVNC_bottom .noVNC_crosscenter { flex-direction: row; width: 100%; height: auto; } .noVNC_bottom .noVNC_crosscenter { top: auto; bottom: 0; } /* ---------------------------------------- * Layering * ---------------------------------------- */ .noVNC_connect_layer { z-index: 60; } /* ---------------------------------------- * Fallback error * ---------------------------------------- */ #noVNC_fallback_error { z-index: 1000; visibility: hidden; /* Put a dark background in front of everything but the error, and don't let mouse events pass through */ background: rgba(0, 0, 0, 0.8); pointer-events: all; } #noVNC_fallback_error.noVNC_open { visibility: visible; } #noVNC_fallback_error > div { max-width: calc(100vw - 30px - 30px); max-height: calc(100vh - 30px - 30px); overflow: auto; padding: 15px; transition: 0.5s ease-in-out; transform: translateY(-50px); opacity: 0; text-align: center; font-weight: bold; color: #fff; border-radius: 12px; box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5); background: rgba(200,55,55,0.8); } #noVNC_fallback_error.noVNC_open > div { transform: translateY(0); opacity: 1; } #noVNC_fallback_errormsg { font-weight: normal; } #noVNC_fallback_errormsg .noVNC_message { display: inline-block; text-align: left; font-family: monospace; white-space: pre-wrap; } #noVNC_fallback_error .noVNC_location { font-style: italic; font-size: 0.8em; color: rgba(255, 255, 255, 0.8); } #noVNC_fallback_error .noVNC_stack { padding: 10px; margin: 10px; font-size: 0.8em; text-align: left; font-family: monospace; white-space: pre; border: 1px solid rgba(0, 0, 0, 0.5); background: rgba(0, 0, 0, 0.2); overflow: auto; } /* ---------------------------------------- * Control bar * ---------------------------------------- */ #noVNC_control_bar_anchor { /* The anchor is needed to get z-stacking to work */ position: fixed; z-index: 10; transition: 0.5s ease-in-out; /* Edge misrenders animations wihthout this */ transform: translateX(0); } :root.noVNC_connected #noVNC_control_bar_anchor.noVNC_idle { opacity: 0.8; } #noVNC_control_bar_anchor:is(.noVNC_top, .noVNC_bottom) { /* Edge misrenders animations wihthout this */ transform: translateY(0); } #noVNC_control_bar_anchor.noVNC_right { left: auto; right: 0; } #noVNC_control_bar_anchor.noVNC_bottom { top: auto; bottom: 0; } #noVNC_control_bar { position: relative; left: -100%; transition: 0.5s ease-in-out; background-color: var(--novnc-blue); border-radius: 0 12px 12px 0; user-select: none; -webkit-user-select: none; -webkit-touch-callout: none; /* Disable iOS image long-press popup */ } .noVNC_right #noVNC_control_bar { left: 100%; border-radius: 12px 0 0 12px; } .noVNC_top #noVNC_control_bar { left: auto; /* FIXME: We want to mirror the left and right modes here and use a relative top offset (-100%), but it doesn't resolve correctly against the anchor height reference */ top: -55px; border-radius: 0 0 12px 12px; } .noVNC_bottom #noVNC_control_bar { left: auto; /* FIXME: We want to mirror the left and right modes here and use a relative top offset (100%), but it doesn't resolve correctly against the anchor height reference */ top: 55px; border-radius: 12px 12px 0 0; } #noVNC_control_bar.noVNC_open { box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5); left: 0; } :is(.noVNC_top, .noVNC_bottom) #noVNC_control_bar.noVNC_open { left: auto; top: 0; } #noVNC_control_bar::before { /* This extra element is to get a proper shadow */ content: ""; position: absolute; z-index: -1; height: 100%; width: 30px; left: -30px; transition: box-shadow 0.5s ease-in-out; } .noVNC_right #noVNC_control_bar::before { visibility: hidden; } .noVNC_top #noVNC_control_bar::before { height: 30px; width: 100%; top: -30px; bottom: auto; } .noVNC_bottom #noVNC_control_bar::before { visibility: hidden; } #noVNC_control_bar.noVNC_open::before { box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5); } #noVNC_control_bar_handle { position: absolute; left: -15px; top: 0; transform: translateY(35px); width: calc(100% + 30px); height: 50px; z-index: -1; cursor: pointer; border-radius: 6px; background-color: var(--novnc-darkblue); box-shadow: 3px 3px 0px rgba(0, 0, 0, 0.5); } :root:not(.noVNC_connected) #noVNC_control_bar_handle { display: none; } :is(.noVNC_top, .noVNC_bottom) #noVNC_control_bar_handle { transform: translateX(35px); top: -15px; left: 0; width: 50px; height: calc(100% + 30px); } #noVNC_control_bar_handle::before { content: ""; background: url("../images/handle_bg.svg"); background-repeat: no-repeat; position: absolute; top: 0; right: 0; width: 15px; height: 50px; } .noVNC_right #noVNC_control_bar_handle::before { left: 0; right: auto; } .noVNC_top #noVNC_control_bar_handle::before { left: 0; right: auto; transform-origin: bottom left; transform: rotate(90deg) translateX(20px); } .noVNC_bottom #noVNC_control_bar_handle::before { left: 0; right: auto; transform-origin: bottom left; transform: rotate(90deg) translateX(-50px); } #noVNC_control_bar_handle:after { content: ""; transition: transform 0.5s ease-in-out; background: url("../images/handle.svg") no-repeat center; background-size: 5px 6px; position: absolute; top: 20px; /* (50px-10px)/2 */ right: 3px; transform: none; width: 10px; height: 10px; transform-origin: center; } .noVNC_right #noVNC_control_bar_handle:after { left: 3px; right: auto; transform: rotate(180deg); } .noVNC_top #noVNC_control_bar_handle:after { left: 20px; right: auto; top: auto; bottom: 3px; transform: rotate(90deg); } .noVNC_bottom #noVNC_control_bar_handle:after { left: 20px; right: auto; top: 3px; bottom: auto; transform: rotate(-90deg); } #noVNC_control_bar.noVNC_open #noVNC_control_bar_handle:after { transform: translateX(1px) rotate(180deg); } .noVNC_right #noVNC_control_bar.noVNC_open #noVNC_control_bar_handle:after { transform: translateX(-1px); } .noVNC_top #noVNC_control_bar.noVNC_open #noVNC_control_bar_handle:after { transform: translateY(1px) rotate(-90deg); } .noVNC_bottom #noVNC_control_bar.noVNC_open #noVNC_control_bar_handle:after { transform: translateY(-1px) rotate(90deg); } /* Larger touch area for the handle, used when a touch screen is available */ #noVNC_control_bar_handle div { position: absolute; left: auto; right: -35px; top: 0; width: 50px; height: 100%; display: none; } @media (any-pointer: coarse) { #noVNC_control_bar_handle div { display: initial; } } .noVNC_right #noVNC_control_bar_handle div { left: -35px; right: auto; } .noVNC_top #noVNC_control_bar_handle div { left: 0; right: auto; top: auto; bottom: -35px; width: 100%; height: 50px; } .noVNC_bottom #noVNC_control_bar_handle div { left: 0; right: auto; top: -35px; bottom: auto; width: 100%; height: 50px; } #noVNC_control_bar > .noVNC_scroll { max-height: 100vh; /* Chrome is buggy with 100% */ overflow-x: hidden; overflow-y: auto; padding: 10px; display: flex; flex-direction: column; justify-content: flex-start; align-items: center; gap: 10px 0; } :is(.noVNC_top, .noVNC_bottom) > #noVNC_control_bar > .noVNC_scroll { max-width: 100vw; /* Chrome is buggy with 100% */ overflow-x: auto; overflow-y: hidden; flex-direction: row; gap: 0 10px; } /* Control bar hint */ .noVNC_hint_anchor { position: fixed; left: -50px; } .noVNC_hint_anchor.noVNC_right { left: auto; right: -50px; } .noVNC_hint_anchor.noVNC_top { left: auto; top: -50px; } .noVNC_hint_anchor.noVNC_bottom { left: auto; top: auto; bottom: -50px; } .noVNC_control_bar_hint { width: 100px; height: 50%; max-height: 600px; position: relative; transform: scale(0); visibility: hidden; opacity: 0; transition: 0.2s ease-in-out; background: transparent; box-shadow: 0 0 10px black, inset 0 0 10px 10px var(--novnc-darkblue); border-radius: 12px; transition-delay: 0s; } :is(.noVNC_top, .noVNC_bottom) .noVNC_control_bar_hint { width: 50%; height: 100px; max-width: 600px; max-height: none; } .noVNC_control_bar_hint.noVNC_active { visibility: visible; opacity: 1; transition-delay: 0.2s; transform: scale(1); } .noVNC_control_bar_hint.noVNC_notransition { transition: none !important; } /* Control bar buttons */ #noVNC_control_bar .noVNC_button { min-width: unset; padding: 4px 4px; border:1px solid rgba(255, 255, 255, 0.2); border-radius: 6px; background-color: transparent; } #noVNC_control_bar .noVNC_button.noVNC_selected { border-color: rgba(0, 0, 0, 0.8); background-color: rgba(0, 0, 0, 0.5); } #noVNC_control_bar .noVNC_button.noVNC_hidden { display: none !important; } /* Panels */ .noVNC_panel { transform: translateX(25px); transition: 0.5s ease-in-out; box-sizing: border-box; /* so max-width don't have to care about padding */ max-width: calc(100vw - 75px - 25px); /* minus left and right margins */ max-height: calc(100vh - 75px - 25px); /* minus top and bottom margins */ overflow-x: hidden; overflow-y: auto; visibility: hidden; opacity: 0; padding: 15px; background: #fff; border-radius: 12px; color: #000; border: 2px solid #E0E0E0; box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5); } .noVNC_panel.noVNC_open { visibility: visible; opacity: 1; transform: translateX(75px); } .noVNC_right .noVNC_panel { transform: translateX(-25px); } .noVNC_right .noVNC_panel.noVNC_open { transform: translateX(-75px); } .noVNC_top .noVNC_panel { transform: translateY(25px); } .noVNC_top .noVNC_panel.noVNC_open { transform: translateY(75px); } .noVNC_bottom .noVNC_panel { transform: translateY(-25px); } .noVNC_bottom .noVNC_panel.noVNC_open { transform: translateY(-75px); } .noVNC_panel > * { display: block; margin: 10px auto; } .noVNC_panel > *:first-child { margin-top: 0 !important; } .noVNC_panel > *:last-child { margin-bottom: 0 !important; } .noVNC_panel hr { border: none; border-top: 1px solid var(--novnc-lightgrey); width: 100%; /*
inside a flexbox will otherwise be 0px wide */ } .noVNC_panel label { display: block; white-space: nowrap; margin: 5px; } @media (max-width: 540px) { /* Allow wrapping on small screens */ .noVNC_panel label { white-space: unset; } } .noVNC_panel li { margin: 5px; } .noVNC_panel .noVNC_heading { background-color: var(--novnc-blue); border-radius: 6px; padding: 5px 8px; /* Compensate for padding in image */ padding-right: 11px; display: flex; align-items: center; gap: 6px; color: white; font-size: 20px; font-weight: bold; white-space: nowrap; } .noVNC_panel .noVNC_heading img { vertical-align: bottom; } .noVNC_panel form { display: flex; flex-direction: column; gap: 12px } .noVNC_panel .button_row { margin-top: 10px; display: flex; gap: 10px; justify-content: space-between; } .noVNC_panel .button_row *:only-child { margin-left: auto; /* Align single buttons to the right */ } /* Expanders */ .noVNC_expander { cursor: pointer; } .noVNC_expander::before { content: url("../images/expander.svg"); display: inline-block; margin-right: 5px; transition: 0.2s ease-in-out; } .noVNC_expander.noVNC_open::before { transform: rotateZ(90deg); } .noVNC_expander ~ * { margin: 5px; margin-left: 10px; padding: 5px; background: rgba(0, 0, 0, 0.04); border-radius: 6px; } .noVNC_expander:not(.noVNC_open) ~ * { display: none; } /* Control bar content */ #noVNC_control_bar .noVNC_logo { display: block; max-width: 35px; max-height: 35px; object-fit: contain; } .noVNC_logo + hr { /* Remove all but top border */ border: none; border-top: 1px solid rgba(255, 255, 255, 0.2); width: 35px; height: 1px; margin: 0; } :is(.noVNC_top, .noVNC_bottom) .noVNC_logo + hr { /* Remove all but left border */ border-left: 1px solid rgba(255, 255, 255, 0.2); border-top: none; width: 1px; height: 35px; } :root:not(.noVNC_connected) #noVNC_view_drag_button { display: none; } /* noVNC Touch Device only buttons */ :root:not(.noVNC_connected) #noVNC_keyboard_button { display: none; } @media not all and (any-pointer: coarse) { /* FIXME: It is bad to assume that no touch devices have physical keyboards available. Hopefully we can get a media query for this: https://github.com/w3c/csswg-drafts/issues/3871 */ :root.noVNC_connected #noVNC_keyboard_button { display: none; } } /* Extra manual keys */ :root:not(.noVNC_connected) #noVNC_toggle_extra_keys_button { display: none; } #noVNC_modifiers { background-color: var(--novnc-darkgrey); border: none; padding: 10px; display: flex; flex-direction: column; justify-content: flex-start; align-items: center; gap: 10px 0; } #noVNC_modifiers > * { margin: 0; } :is(.noVNC_top, .noVNC_bottom) #noVNC_modifiers { flex-direction: row; gap: 0 10px; } /* Shutdown/Reboot */ :root:not(.noVNC_connected) #noVNC_power_button { display: none; } #noVNC_power { } #noVNC_power_buttons { display: none; } #noVNC_power input[type=button] { width: 100%; } /* Clipboard */ :root:not(.noVNC_connected) #noVNC_clipboard_button { display: none; } #noVNC_clipboard_text { width: 360px; min-width: 150px; height: 160px; min-height: 70px; box-sizing: border-box; max-width: 100%; /* minus approximate height of title, height of subtitle, and margin */ max-height: calc(100vh - 10em - 25px); } /* Settings */ #noVNC_settings { } #noVNC_settings ul { list-style: none; padding: 0px; } #noVNC_settings button, #noVNC_settings select, #noVNC_settings textarea, #noVNC_settings input:not([type=checkbox]):not([type=radio]) { margin-left: 6px; /* Prevent inputs in settings from being too wide */ max-width: calc(100% - 6px - var(--input-xpadding) * 2); } #noVNC_setting_port { width: 80px; } #noVNC_setting_path { width: 100px; } /* Version */ .noVNC_version_wrapper { font-size: small; } .noVNC_version { margin-left: 1rem; } /* Connection controls */ :root:not(.noVNC_connected) #noVNC_disconnect_button { display: none; } /* ---------------------------------------- * Status dialog * ---------------------------------------- */ #noVNC_status { position: fixed; top: 0; left: 0; width: 100%; z-index: 100; transform: translateY(-100%); cursor: pointer; transition: 0.5s ease-in-out; visibility: hidden; opacity: 0; padding: 5px; display: flex; flex-direction: row; justify-content: center; align-content: center; line-height: 1.6; word-wrap: break-word; color: #fff; border-bottom: 1px solid rgba(0, 0, 0, 0.9); } #noVNC_status.noVNC_open { transform: translateY(0); visibility: visible; opacity: 1; } #noVNC_status::before { content: ""; display: inline-block; width: 25px; height: 25px; margin-right: 5px; } #noVNC_status.noVNC_status_normal { background: rgba(128,128,128,0.9); } #noVNC_status.noVNC_status_normal::before { content: url("../images/info.svg") " "; } #noVNC_status.noVNC_status_error { background: rgba(200,55,55,0.9); } #noVNC_status.noVNC_status_error::before { content: url("../images/error.svg") " "; } #noVNC_status.noVNC_status_warn { background: rgba(180,180,30,0.9); } #noVNC_status.noVNC_status_warn::before { content: url("../images/warning.svg") " "; } /* ---------------------------------------- * Connect dialog * ---------------------------------------- */ #noVNC_connect_dlg { transition: 0.5s ease-in-out; transform: scale(0, 0); visibility: hidden; opacity: 0; } #noVNC_connect_dlg.noVNC_open { transform: scale(1, 1); visibility: visible; opacity: 1; } #noVNC_connect_dlg .noVNC_logo { transition: 0.5s ease-in-out; padding: 10px; margin-bottom: 10px; font-size: 80px; text-align: center; border-radius: 6px; } @media (max-width: 440px) { #noVNC_connect_dlg { max-width: calc(100vw - 100px); } #noVNC_connect_dlg .noVNC_logo { font-size: calc(25vw - 30px); } } #noVNC_connect_dlg div { padding: 18px; background-color: var(--novnc-darkgrey); border-radius: 12px; text-align: center; font-size: 20px; box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5); } #noVNC_connect_button { width: 100%; padding: 6px 30px; cursor: pointer; border-color: transparent; border-radius: 12px; background-color: var(--novnc-blue); color: white; display: flex; justify-content: center; place-items: center; gap: 4px; } #noVNC_connect_button img { vertical-align: bottom; height: 1.3em; } /* ---------------------------------------- * Server verification dialog * ---------------------------------------- */ #noVNC_verify_server_dlg { position: relative; transform: translateY(-50px); } #noVNC_verify_server_dlg.noVNC_open { transform: translateY(0); } #noVNC_fingerprint_block { margin: 10px; } /* ---------------------------------------- * Password dialog * ---------------------------------------- */ #noVNC_credentials_dlg { position: relative; transform: translateY(-50px); } #noVNC_credentials_dlg.noVNC_open { transform: translateY(0); } #noVNC_username_block.noVNC_hidden, #noVNC_password_block.noVNC_hidden { display: none; } /* ---------------------------------------- * Main area * ---------------------------------------- */ /* Transition screen */ #noVNC_transition { transition: 0.5s ease-in-out; display: flex; opacity: 0; visibility: hidden; position: fixed; top: 0; left: 0; bottom: 0; right: 0; color: white; background: rgba(0, 0, 0, 0.5); z-index: 50; /*display: flex;*/ align-items: center; justify-content: center; flex-direction: column; } :root.noVNC_loading #noVNC_transition, :root.noVNC_connecting #noVNC_transition, :root.noVNC_disconnecting #noVNC_transition, :root.noVNC_reconnecting #noVNC_transition { opacity: 1; visibility: visible; } :root:not(.noVNC_reconnecting) #noVNC_cancel_reconnect_button { display: none; } #noVNC_transition_text { font-size: 1.5em; } /* Main container */ #noVNC_container { width: 100%; height: 100%; background-color: #313131; border-bottom-right-radius: 800px 600px; /*border-top-left-radius: 800px 600px;*/ /* If selection isn't disabled, long-pressing stuff in the sidebar can accidentally select the container or the canvas. This can happen when attempting to move the handle. */ user-select: none; -webkit-user-select: none; } #noVNC_keyboardinput { width: 1px; height: 1px; background-color: #fff; color: #fff; border: 0; position: absolute; left: -40px; z-index: -1; ime-mode: disabled; } /*Default noVNC logo.*/ /* From: http://fonts.googleapis.com/css?family=Orbitron:700 */ @font-face { font-family: 'Orbitron'; font-style: normal; font-weight: 700; src: local('?'), url('Orbitron700.woff') format('woff'), url('Orbitron700.ttf') format('truetype'); } .noVNC_logo { color: var(--novnc-yellow); font-family: 'Orbitron', 'OrbitronTTF', sans-serif; line-height: 0.9; text-shadow: 0.1em 0.1em 0 black; } .noVNC_logo span{ color: var(--novnc-green); } #noVNC_bell { display: none; } /* ---------------------------------------- * Media sizing * ---------------------------------------- */ @media screen and (max-width: 640px){ #noVNC_logo { font-size: 150px; } } @media screen and (min-width: 321px) and (max-width: 480px) { #noVNC_logo { font-size: 110px; } } @media screen and (max-width: 320px) { #noVNC_logo { font-size: 90px; } }