/*
 * The command palette (ADO #336): the small bar, and the dialog it becomes.
 *
 * WHY THIS IS ITS OWN STYLESHEET AND NOT A <style> BLOCK. The dashboard
 * scopes its own styles inline, and that is right for styles only the
 * dashboard has. This is a component meant to be dropped onto any page with
 * one include, and a component whose CSS is copied into each page is a
 * component with a different bug on every page.
 *
 * NOT assets/css/main.css. That file is compiled output from assets/sass/,
 * which is not deployed, so an edit there silently diverges the next time
 * anybody rebuilds it. Same convention as dashboard.php and all-services.php.
 *
 * EVERY COLOUR IS STATED. The theme's page ground is dark navy (#242943) with
 * WHITE default text, so anything drawn here has to set its own colour or
 * inherit white onto whatever it happens to sit on -- and the theme colours
 * strong/b and .button white specifically, which beats a colour set on a
 * parent. Three separate invisible-white-on-white bugs were shipped on the
 * dashboard before that was written down. The panel is therefore deliberately
 * DARK rather than a white card: it sits over a dark page, and a dark surface
 * is the one where the theme's own defaults are already readable.
 *
 * Every selector is .vg-cp-*, so nothing here can reach the rest of the page.
 */

/* -- the collapsed bar: a pill in the header ----------------------------- */

/* Nothing of the component is in the page's flow any more: the pill is
   positioned in the header strip and the dialog is fixed. The wrapper is only
   where the call site put the markup, so it takes no room. */
.vg-cp {
	margin: 0;
}

/*
 * THE SAME PLACE ON EVERY PAGE. The script moves the pill into #header (and
 * adds .is-docked), which is fixed on most console pages and absolute at the
 * top of the document on the ones with the theme's `alt` class -- positioned
 * either way, so this rule centres the pill in it. Before the script runs, or
 * without it, the same rule places the pill in the same strip: no ancestor of
 * the call site is positioned, so `absolute` resolves against the document,
 * whose top is where the header is.
 *
 * Sizes are in the header's own em. The pill inherits the body's font size
 * exactly as #header does (main.css sets it on body and nowhere between), so
 * 3.25em here is the header's height at every breakpoint, and the pill sits
 * centred in it without a pixel figure that is right for one screen.
 *
 * It is an <a>, so main.css gives it an underline and a dotted border-bottom
 * that have to be removed by hand; and #header is uppercase, letter-spaced
 * and 3.25em in line-height, all inherited, so those are reset too.
 */
.vg-cp-bar {
	position: absolute;
	z-index: 10001;
	top: calc(var(--vg-safe-top, 0px) + .675em);
	left: 50%;
	transform: translateX(-50%);
	display: flex;
	align-items: center;
	box-sizing: border-box;
	height: 1.9em;
	padding: 0 .7em;
	border: 1px solid rgba(255, 255, 255, .18);
	border-bottom: 1px solid rgba(255, 255, 255, .18);
	border-radius: 999px;
	background: rgba(255, 255, 255, .06);
	color: rgba(255, 255, 255, .75);
	font-size: 1em;
	font-weight: 400;
	letter-spacing: 0;
	line-height: 1;
	text-transform: none;
	text-decoration: none;
	white-space: nowrap;
	cursor: text;
	transition: background-color .15s ease-in-out, border-color .15s ease-in-out, color .15s ease-in-out;
}

/* Inside the header the safe-area inset is already the header's own offset
   (app-shell.css moves the whole header down), so it must not count twice. */
.vg-cp-bar.is-docked {
	top: .675em;
}

.vg-cp-bar:hover,
.vg-cp-bar:focus,
.vg-cp-bar:focus-visible {
	background: rgba(255, 255, 255, .12);
	border-color: rgba(255, 255, 255, .45);
	color: #fff;
	text-decoration: none;
	outline: none;
}

.vg-cp-bar:focus-visible {
	box-shadow: 0 0 0 2px rgba(155, 241, 255, .6);
}

.vg-cp-bar-icon:before,
.vg-cp-field-icon:before,
.vg-cp-tip-icon:before,
.vg-cp-icon:before {
	/* The theme ships Font Awesome 5. FA6 renamed a lot of icons and an
	   unknown name draws nothing at all, silently -- which is why
	   command-palette-test.php checks every icon name against the
	   stylesheet the site actually ships. */
	font-family: 'Font Awesome 5 Free';
	font-weight: 900;
}

.vg-cp-bar-icon {
	font-size: .7em;
	opacity: .8;
}

/* Folded to nothing until the pill is hovered or focused, then opened just
   wide enough to say what it is. In the DOM throughout, so it is the link's
   accessible name either way. max-width rather than width because width
   cannot be animated to "as wide as the words". */
.vg-cp-bar-text {
	max-width: 0;
	overflow: hidden;
	opacity: 0;
	font-size: .62em;
	letter-spacing: .04em;
	transition: max-width .2s ease, margin-left .2s ease, opacity .15s ease;
}

/* Margins, not a flex gap: a gap is spent beside the folded label too, and
   left a hole in the middle of the pill. */
.vg-cp-bar:hover .vg-cp-bar-text,
.vg-cp-bar:focus-visible .vg-cp-bar-text {
	max-width: 14em;
	margin-left: .6em;
	opacity: 1;
}

.vg-cp-bar-keys {
	flex: 0 0 auto;
	display: flex;
	margin-left: .55em;
	opacity: .8;
}

/* -- keys ---------------------------------------------------------------- */

/* .vg-cp-bar is listed on its own because the pill leaves .vg-cp when the
   script docks it in the header. */
.vg-cp kbd,
.vg-cp-bar kbd {
	display: inline-block;
	min-width: 1.5em;
	padding: .1em .4em;
	border: 1px solid rgba(255, 255, 255, .3);
	border-radius: 3px;
	background: rgba(255, 255, 255, .07);
	color: rgba(255, 255, 255, .85);
	font-family: inherit;
	font-size: .8em;
	line-height: 1.5;
	text-align: center;
}

/* After the rule above, which it narrows: the pill's key has to fit a pill. */
.vg-cp-bar kbd {
	min-width: 0;
	padding: .15em .45em;
	border-color: rgba(255, 255, 255, .22);
	font-size: .55em;
	line-height: 1.4;
}

/* -- the dialog ---------------------------------------------------------- */

/*
 * MEASURED, NOT GUESSED. The theme's #header is `position: fixed` at z-index
 * 10000 and its #menu overlay is 10002; the dashboard's floating jumper is
 * 9000. The first version of this sat at 9500 and the VPS GB logo drew
 * straight over the open panel -- visible in a screenshot, invisible in the
 * code. Anything added above these has to clear 10002.
 */
.vg-cp-scrim {
	position: fixed;
	inset: 0;
	z-index: 10010;
	background: rgba(12, 14, 24, .55);
	-webkit-backdrop-filter: blur(3px);
	backdrop-filter: blur(3px);
}

/*
 * AS LARGE AS THE SCREEN ALLOWS, AND A FIXED SIZE WHILE IT IS OPEN. The pill
 * is as small as it can be because it is on every page; the panel is the
 * opposite, because when somebody opens it the panel is the only thing they
 * are looking at. Its height does not follow its contents: a panel that
 * shrinks and grows with every keystroke moves the row under the pointer, and
 * a list that jumps is a list where Enter lands on the wrong thing.
 *
 * The top edge is level with the pill, so it reads as the pill opening rather
 * than as a second thing appearing; --vg-safe-top is app-shell.css's status
 * bar inset in the installed app and 0px everywhere else.
 */
.vg-cp-panel {
	position: fixed;
	z-index: 10011;
	top: calc(var(--vg-safe-top, 0px) + .6em);
	left: 50%;
	transform: translateX(-50%);
	transform-origin: 50% 0;
	display: flex;
	flex-direction: column;
	box-sizing: border-box;
	width: min(64rem, calc(100vw - 2em));
	height: min(46rem, calc(100vh - var(--vg-safe-top, 0px) - 2em));
	border: 1px solid rgba(255, 255, 255, .16);
	border-radius: 14px;
	background: rgba(34, 38, 62, .94);
	-webkit-backdrop-filter: blur(18px) saturate(140%);
	backdrop-filter: blur(18px) saturate(140%);
	box-shadow: 0 2em 4em rgba(0, 0, 0, .5), 0 0 0 1px rgba(0, 0, 0, .25);
	color: #fff;
	overflow: hidden;
	animation: vg-cp-grow .18s cubic-bezier(.2, .9, .3, 1);
}

/* Out of the pill: from its size at the top centre to the panel's. Restarts
   on every open, because [hidden] takes the panel out of rendering and an
   animation replays when an element is rendered again. */
@keyframes vg-cp-grow {
	from {
		opacity: 0;
		transform: translateX(-50%) scale(.12, .06);
	}
	to {
		opacity: 1;
		transform: translateX(-50%) scale(1, 1);
	}
}

@media (prefers-reduced-motion: reduce) {
	.vg-cp-panel {
		animation: none;
	}

	.vg-cp-bar-text {
		transition: none;
	}
}

.vg-cp-field {
	display: flex;
	align-items: center;
	gap: .8em;
	padding: 1em 1.25em;
	border-bottom: 1px solid rgba(255, 255, 255, .1);
}

.vg-cp-field-icon {
	font-size: 1.05em;
	opacity: .55;
}

/* The theme styles inputs for its own forms -- a bottom border, a fixed
   height and a margin. All three have to go, or the field sits half out of
   its own row. */
/* Two classes, not one, and that is the fix rather than a style choice:
   main.css's `input[type="text"]` is 0,1,1 and beat a lone .vg-cp-input, so
   the field kept the theme's border, height and focus ring. Worse, the row
   changed height when the field lost focus, which moved the tip below it out
   from under the pointer between mousedown and mouseup, so "Don't show
   again" never received its click. Found in a browser, as these always are. */
.vg-cp-field .vg-cp-input,
.vg-cp-field .vg-cp-input:focus {
	flex: 1 1 auto;
	margin: 0;
	padding: 0;
	height: auto;
	border: 0;
	box-shadow: none;
	background: transparent;
	color: #fff;
	font-size: 1.2em;
	line-height: 1.6;
}

.vg-cp-input::placeholder {
	color: rgba(255, 255, 255, .45);
	opacity: 1;
}

/* "Esc" with a keyboard, "Close" without one: the media query at the bottom
   swaps the words. A key cap for a key the reader has, and a word otherwise. */
.vg-cp-dismiss {
	flex: 0 0 auto;
	appearance: none;
	-webkit-appearance: none;
	height: auto;
	font-family: inherit;
	margin: 0;
	padding: .25em .6em;
	border: 1px solid rgba(255, 255, 255, .2);
	border-radius: 5px;
	box-shadow: none;
	background: rgba(255, 255, 255, .05);
	color: rgba(255, 255, 255, .7);
	font-size: .65em;
	font-weight: 600;
	letter-spacing: .06em;
	text-transform: none;
	line-height: 1.6;
	cursor: pointer;
}

.vg-cp-dismiss:hover {
	border-color: rgba(255, 255, 255, .5);
	color: #fff;
}

.vg-cp-dismiss-word {
	display: none;
}

/* -- the tip ------------------------------------------------------------- */

.vg-cp-tip {
	display: flex;
	align-items: center;
	gap: .9em;
	margin: .75em 1em 0;
	padding: .65em .9em;
	border: 1px solid rgba(155, 241, 255, .22);
	border-radius: 8px;
	background: rgba(155, 241, 255, .06);
	color: rgba(255, 255, 255, .82);
	font-size: .78em;
	line-height: 1.55;
}

.vg-cp-tip-icon {
	flex: 0 0 auto;
	color: #9bf1ff;
	opacity: .85;
}

.vg-cp-tip-text {
	flex: 1 1 auto;
	margin: 0;
	padding: 0;
}

/* The theme gives <code> a box and a monospace face sized for body copy; here
   it is a command name in a sentence, so it is told to fit the line. */
.vg-cp-tip code {
	margin: 0;
	padding: .05em .35em;
	border: 1px solid rgba(255, 255, 255, .2);
	border-radius: 3px;
	background: rgba(255, 255, 255, .06);
	color: #fff;
	font-size: .95em;
}

.vg-cp-tip-hide {
	flex: 0 0 auto;
	appearance: none;
	-webkit-appearance: none;
	height: auto;
	margin: 0;
	padding: .2em .1em;
	border: 0;
	box-shadow: none;
	background: transparent;
	color: rgba(255, 255, 255, .6);
	font-family: inherit;
	font-size: .92em;
	font-weight: 600;
	letter-spacing: 0;
	line-height: 1.5;
	text-transform: none;
	text-decoration: underline;
	text-decoration-color: rgba(255, 255, 255, .3);
	text-underline-offset: .2em;
	white-space: nowrap;
	cursor: pointer;
}

.vg-cp-tip-hide:hover {
	color: #fff;
}

/* -- the key list in /help ----------------------------------------------- */

.vg-cp-keys {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(18em, 1fr));
	gap: .45em 1.5em;
	padding: .3em .55em 1em;
	color: rgba(255, 255, 255, .7);
	font-size: .8em;
}

.vg-cp-keys-row {
	display: flex;
	align-items: center;
	gap: .7em;
}

.vg-cp-keys-row kbd {
	flex: 0 0 auto;
	min-width: 3.4em;
}

.vg-cp-status {
	margin: 0;
	padding: .6em 1.15em 0;
	color: rgba(255, 255, 255, .55);
	font-size: .75em;
	letter-spacing: .06em;
}

.vg-cp-status:empty {
	display: none;
}

/* -- results ------------------------------------------------------------- */

.vg-cp-results {
	flex: 1 1 auto;
	margin: 0;
	padding: .5em .6em .8em;
	list-style: none;
	overflow-y: auto;
}

.vg-cp-results li {
	margin: 0;
	padding: 0;
}

.vg-cp-group {
	padding: .9em .55em .35em;
	color: rgba(255, 255, 255, .5);
	font-size: .65em;
	font-weight: 600;
	letter-spacing: .2em;
	text-transform: uppercase;
}

/*
 * HALF THESE RULES EXIST TO UNDO THE THEME'S <button>, and they are not
 * padding. A row that opens a confirm has to be a button rather than a link,
 * and main.css styles every button as a call to action: 2.75em tall,
 * uppercase, letter-spaced, centred, its own font-weight and an inset
 * box-shadow border. Seen in a browser, the first version of this rendered
 * "RESTART VM1" in spaced capitals across its own second line while the
 * <a> rows next to it looked perfect -- because the anchors were never
 * styled that way. text-transform and letter-spacing are INHERITED too, so
 * resetting the row fixes its children with it.
 */
.vg-cp-row {
	display: flex;
	align-items: center;
	gap: .85em;
	width: 100%;
	min-width: 0;
	height: auto;
	margin: 0;
	padding: .6em .55em;
	appearance: none;
	-webkit-appearance: none;
	border: 1px solid transparent;
	border-radius: 5px;
	box-shadow: none;
	background: transparent;
	color: #fff;
	font-family: inherit;
	font-size: 1em;
	font-weight: 400;
	letter-spacing: 0;
	line-height: 1.5;
	text-align: left;
	text-transform: none;
	text-decoration: none;
	white-space: normal;
	cursor: pointer;
}

/* Hover and keyboard selection are the SAME state deliberately: two different
   highlights, one following the mouse and one the arrow keys, is how somebody
   presses Enter and gets the other one. */
.vg-cp-row.is-active,
.vg-cp-row:hover {
	background: rgba(255, 255, 255, .09);
	border-color: rgba(255, 255, 255, .22);
	text-decoration: none;
}

/* ...and while the pointer is inside the list, the keyboard's highlight gives
   way to it, so there is never more than one. Two appear otherwise in one
   real case: the panel opens directly under a stationary cursor, which
   hovers a row without ever firing a mousemove for the script to follow. */
.vg-cp-results:hover .vg-cp-row.is-active:not(:hover) {
	background: transparent;
	border-color: transparent;
}

.vg-cp-icon {
	flex: 0 0 1.4em;
	opacity: .65;
	text-align: center;
}

.vg-cp-body {
	flex: 1 1 auto;
	min-width: 0;
}

.vg-cp-name {
	display: block;
	overflow: hidden;
	color: #fff;
	font-size: .9em;
	font-weight: 600;
	white-space: nowrap;
	text-overflow: ellipsis;
}

.vg-cp-meta {
	display: block;
	overflow: hidden;
	margin-top: .15em;
	color: rgba(255, 255, 255, .55);
	font-size: .75em;
	white-space: nowrap;
	text-overflow: ellipsis;
}

.vg-cp-tail {
	flex: 0 0 auto;
	color: rgba(255, 255, 255, .5);
	font-size: .7em;
	letter-spacing: .1em;
	text-transform: uppercase;
	white-space: nowrap;
}

/* A status worth noticing: a resource that is not live yet carries it, so
   "why can I not restart this" is answered in the row rather than by a
   refusal after pressing Enter. */
.vg-cp-tag {
	display: inline-block;
	margin-left: .5em;
	padding: .1em .6em;
	border-radius: 999px;
	background: rgba(255, 193, 7, .16);
	color: #ffd75e;
	font-size: .68em;
	font-weight: 700;
	letter-spacing: .08em;
	text-transform: uppercase;
	vertical-align: .1em;
}

/* -- the confirm step ---------------------------------------------------- */

/*
 * This is the important state in the whole component. A command is never run
 * by the keystroke that selects it: selecting turns the row into this, which
 * names the target and says what will happen, and only a second, deliberate
 * Enter posts anything. Amber rather than red -- nothing the palette can run
 * is destructive (no rebuild, no resize, no delete) and a red panel for
 * "restart PHP" trains people to click through red panels.
 */
.vg-cp-confirm {
	margin: .5em .55em;
	padding: .9em 1em;
	border: 1px solid rgba(255, 193, 7, .5);
	border-radius: 6px;
	background: rgba(255, 193, 7, .1);
	color: #fff;
}

.vg-cp-confirm-title {
	display: block;
	color: #fff;
	font-size: .95em;
	font-weight: 700;
}

.vg-cp-confirm-note {
	display: block;
	margin-top: .35em;
	color: rgba(255, 255, 255, .78);
	font-size: .8em;
	line-height: 1.5;
}

.vg-cp-confirm-actions {
	display: flex;
	align-items: center;
	gap: .6em;
	margin-top: .9em;
}

/* The theme's .button is white text on a white inset box-shadow, which
   vanishes on a light surface and reads as a ghost on this one. Both buttons
   here are painted from scratch rather than borrowed. */
.vg-cp-go,
.vg-cp-cancel {
	appearance: none;
	-webkit-appearance: none;
	height: auto;
	font-family: inherit;
	margin: 0;
	padding: .45em 1.1em;
	border: 0;
	border-radius: 4px;
	font-size: .75em;
	font-weight: 700;
	letter-spacing: .12em;
	text-transform: uppercase;
	line-height: 2;
	cursor: pointer;
}

.vg-cp-go {
	background: #ffc107;
	color: #35301c;
}

.vg-cp-go:hover {
	background: #ffcf3d;
	color: #35301c;
}

.vg-cp-cancel {
	background: transparent;
	box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .35);
	color: rgba(255, 255, 255, .85);
}

.vg-cp-cancel:hover {
	box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .7);
	color: #fff;
}

/* -- empty, error, footer ------------------------------------------------ */

.vg-cp-empty {
	padding: 1.4em .8em;
	color: rgba(255, 255, 255, .6);
	font-size: .85em;
	line-height: 1.6;
}

.vg-cp-empty a {
	color: #fff;
}

.vg-cp-foot {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: 1.1em;
	padding: .7em 1.15em;
	border-top: 1px solid rgba(255, 255, 255, .14);
	background: rgba(0, 0, 0, .14);
	color: rgba(255, 255, 255, .55);
	font-size: .7em;
	letter-spacing: .06em;
}

.vg-cp-foot-link {
	margin-left: auto;
	border-bottom: 0;
	color: rgba(255, 255, 255, .8);
	text-decoration: none;
}

.vg-cp-foot-link:hover {
	color: #fff;
}

/* -- small screens ------------------------------------------------------- */

@media screen and (max-width: 736px) {
	/* NOT CENTRED ON A PHONE. The logo is 165px wide at its 44px height, so
	   on a 360px screen the middle of the header is inside it. Docked, the
	   pill joins the header's own row, pushed right against Menu: the nav
	   gives up the flex-grow it uses to reach the right edge, and the pill's
	   auto margin takes that space instead. Undocked (no script), it is
	   placed at the same spot by offset from the right. */
	.vg-cp-bar {
		left: auto;
		right: 4em;
		transform: none;
		width: 2.1em;
		height: 2.1em;
		padding: 0;
		justify-content: center;
	}

	.vg-cp-bar.is-docked {
		position: relative;
		top: auto;
		right: auto;
		flex: 0 0 auto;
		align-self: center;
		margin-left: auto;
	}

	#header .vg-cp-bar.is-docked + nav {
		flex-grow: 0;
	}

	/* An icon on a phone: no key to advertise, and no hover to unfold the
	   label on. The label stays in the DOM as the link's name. */
	.vg-cp-bar-keys,
	.vg-cp-bar:hover .vg-cp-bar-text,
	.vg-cp-bar:focus-visible .vg-cp-bar-text,
	.vg-cp-bar-text {
		position: absolute;
		width: 1px;
		height: 1px;
		max-width: none;
		overflow: hidden;
		clip: rect(0 0 0 0);
		white-space: nowrap;
	}

	.vg-cp-bar-icon {
		font-size: .8em;
	}

	/* Full screen, not a floating card: on a phone the keyboard takes half
	   the viewport, and a centred panel ends up as a two-row list. */
	.vg-cp-panel {
		top: 0;
		width: 100%;
		max-width: none;
		height: 100%;
		max-height: none;
		padding-top: var(--vg-safe-top, 0px);
		border: 0;
		border-radius: 0;
	}

	.vg-cp-dismiss-key {
		display: none;
	}

	.vg-cp-dismiss-word {
		display: inline;
	}

	/* The words get the width; a bulb alone on its own line said nothing. */
	.vg-cp-tip {
		flex-wrap: wrap;
	}

	.vg-cp-tip-icon {
		display: none;
	}

	/* Every hint in the footer is a key a phone does not have. */
	.vg-cp-foot span {
		display: none;
	}

	.vg-cp-foot-link {
		margin-left: 0;
	}
}

/* [hidden] has to win over the display rules above, because the panel and the
   scrim are rendered hidden and toggled by the attribute rather than by a
   class -- the same reason all-services.php restates it. */
.vg-cp [hidden],
.vg-cp-bar [hidden] {
	display: none !important;
}
