/* The sign-in page of VPN Client, in Material Design 3: the consoles' Bleu Marseille tokens
   (vpn-manager _tokens.scss), outlined text fields, radio buttons, filled, tonal and text buttons. */

:root {
	--typo-font-family: 'Exo 2', system-ui, sans-serif;
	--color-primary: rgb(6 96 171);
	--color-on-primary: rgb(255 255 255);
	--color-surface: rgb(255 255 255);
	--color-on-surface: rgb(25 28 33);
	--color-on-surface-variant: rgb(65 71 81);
	--color-surface-container-low: rgb(245 246 253);
	--color-outline: rgb(114 119 130);
	--color-outline-variant: rgb(193 199 211);
	--color-secondary-container: rgb(212 227 255);
	--color-on-secondary-container: rgb(0 30 61);
	--color-error: rgb(186 26 26);
	--color-success: rgb(46 158 82);
	--color-shadow-ink: rgb(19 22 27);
	--shadow-card: 0 1px 2px color-mix(in srgb, var(--color-shadow-ink) 6%, transparent),
		0 2px 8px color-mix(in srgb, var(--color-shadow-ink) 5%, transparent);
	--brand-vpn-color: #4486d3;
	--brand-manager-color: #003564;
	--radius-md: 12px;
	--radius-lg: 16px;
	--radius-full: 999px;
	--space-xs: 4px;
	--space-sm: 8px;
	--space-md: 12px;
	--space-lg: 16px;
	--space-xl: 24px;
	--sl-opacity-hovered: 0.08;
	--sl-opacity-pressed: 0.12;
	--duration-fast: 150ms;
	/* MD3 extra-small corner of the outlined text field, its height, the button's */
	--field-radius: 4px;
	--field-height: 56px;
	--field-label-inset: 12px;
	/* a field beside its button: narrower, the button goes under it */
	--inline-field-min-width: 200px;
	--button-height: 40px;
	/* MD3 radio button: its icon, and the state layer around it */
	--radio-size: 20px;
	--radio-target: 40px;
	--label-line-height: 20px;
	--qr-size: 168px;
	--brand-height: 32px;
	--card-max-width: 400px;
	color-scheme: light;
}

* {
	box-sizing: border-box;
}

body {
	margin: 0;
	min-height: 100vh;
	background: var(--color-surface-container-low);
	color: var(--color-on-surface);
	font: 400 14px/20px var(--typo-font-family);
}

.sign-in {
	display: flex;
	align-items: center;
	justify-content: center;
	min-height: 100vh;
	padding: var(--space-lg);
}

.card {
	width: 100%;
	max-width: var(--card-max-width);
	padding: var(--space-xl);
	border-radius: var(--radius-lg);
	background: var(--color-surface);
	box-shadow: var(--shadow-card);
	/* the brand's folded letters keep their width while hidden: never a sideways scroll on a phone */
	overflow-x: clip;
}

/* VPN Client folds into its mark as in the consoles: beats and easing copied from vpn-manager
   Brand.scss, geometry from BrandClientLockup.tsx and brandPaths.ts (no build shares them) */
.brand {
	--brand-easing: cubic-bezier(0.4, 0, 0.2, 1);
	--brand-client-morph-duration: 900ms;
	--brand-client-emerge-duration: 600ms;
	/* the cap appears while the letter C still covers it, then the letter fades off it: the shape never thins */
	--brand-client-crossfade-duration: calc(var(--brand-client-morph-duration) / 2);
	--brand-client-ratio: calc(1210.85 / 176);
	--brand-mark-ratio: calc(228.4489 / 176);
	--brand-cap-overhang: calc(74.9426 / 176);
	/* the letter C's box and the cap's by their centres, the C turned a quarter onto the cap */
	--brand-letter-c-origin: 648.5977px 88px;
	--brand-letter-c-onto-cap: translate(-534.3732px, -135.3466px) rotate(0.25turn) scale(calc(228.4489 / 176));
	--brand-cap-origin: 114.2245px -47.3466px;
	--brand-cap-onto-letter-c: translate(534.3732px, 135.3466px) rotate(-0.25turn) scale(calc(176 / 228.4489));
	--brand-lient-tuck: -54.663px;
	--brand-wave-duration: calc(2 * var(--brand-client-morph-duration));
	--brand-wave-start: calc(var(--brand-client-emerge-duration) + var(--brand-client-morph-duration));
	--brand-wave-opacity: 0.5;
	--brand-wave-held-opacity: 0.4;
	--brand-wave-rise: -100px;
	--brand-wave-start-scale: 0.99;
	--brand-wave-shrink: 0.7;
	/* the cap's crown: half the mark's width, the cap's top */
	--brand-wave-origin: 114.2245px -74.9426px;
	display: flex;
	align-items: center;
	justify-content: center;
	/* the folded mark's box, held so the form never moves when the name folds */
	min-height: calc(var(--brand-height) * (1 + var(--brand-cap-overhang)));
	margin-bottom: var(--space-xl);
}

.brand__vpn {
	fill: var(--brand-vpn-color);
}

.brand__manager {
	fill: var(--brand-manager-color);
}

.brand__client {
	display: block;
	flex-shrink: 0;
	width: calc(var(--brand-height) * var(--brand-client-ratio));
	height: var(--brand-height);
	margin-top: 0;
	transition:
		width calc(var(--brand-client-morph-duration) + var(--brand-client-emerge-duration)) var(--brand-easing),
		margin-top var(--brand-client-morph-duration) var(--brand-easing);
}

.brand__client svg {
	display: block;
	height: 100%;
	overflow: visible;
}

.brand__client--collapsed {
	width: calc(var(--brand-height) * var(--brand-mark-ratio));
	/* room for the cap above the cap height */
	margin-top: calc(var(--brand-height) * var(--brand-cap-overhang));
	transition:
		width calc(var(--brand-client-emerge-duration) + var(--brand-client-morph-duration)) var(--brand-easing),
		margin-top var(--brand-client-morph-duration) var(--brand-easing) var(--brand-client-emerge-duration);
}

/* the letter C and the cap move as one shape, each element on the other's place */
.brand__client-c,
.brand__client-cap {
	transform-box: view-box;
}

.brand__client-c {
	transform-origin: var(--brand-letter-c-origin);
	transition:
		transform var(--brand-client-morph-duration) var(--brand-easing),
		opacity var(--brand-client-crossfade-duration) ease;
}

.brand__client-cap {
	opacity: 0;
	transform: var(--brand-cap-onto-letter-c);
	transform-origin: var(--brand-cap-origin);
	transition:
		transform var(--brand-client-morph-duration) var(--brand-easing),
		opacity var(--brand-client-crossfade-duration) ease var(--brand-client-crossfade-duration);
}

.brand__fading {
	transition: opacity var(--brand-client-emerge-duration) ease var(--brand-client-morph-duration);
}

.brand__client-emerging {
	transition:
		transform var(--brand-client-emerge-duration) var(--brand-easing) var(--brand-client-morph-duration),
		opacity var(--brand-client-emerge-duration) ease var(--brand-client-morph-duration);
}

/* folding: the letters fade and "lient" tucks into the C, then the C becomes the cap */
.brand__client--collapsed .brand__client-c {
	opacity: 0;
	transform: var(--brand-letter-c-onto-cap);
	transition:
		transform var(--brand-client-morph-duration) var(--brand-easing) var(--brand-client-emerge-duration),
		opacity var(--brand-client-crossfade-duration) ease
			calc(var(--brand-client-emerge-duration) + var(--brand-client-crossfade-duration));
}

.brand__client--collapsed .brand__client-cap {
	opacity: 1;
	transform: none;
	transition:
		transform var(--brand-client-morph-duration) var(--brand-easing) var(--brand-client-emerge-duration),
		opacity var(--brand-client-crossfade-duration) ease var(--brand-client-emerge-duration);
}

.brand__client--collapsed .brand__fading,
.brand__client--collapsed .brand__client-emerging {
	opacity: 0;
	transition:
		transform var(--brand-client-emerge-duration) var(--brand-easing),
		opacity var(--brand-client-emerge-duration) ease-in;
}

.brand__client--collapsed .brand__client-emerging {
	transform: translateX(var(--brand-lient-tuck));
}

/* once folded, the cap sends waves: copies of it rise from its crown, shrinking as they fade */
.brand__wave {
	opacity: 0;
	transform-origin: var(--brand-wave-origin);
}

.brand__client--collapsed .brand__wave {
	animation: brand-wave var(--brand-wave-duration) linear var(--brand-wave-start) infinite;
}

.brand__client--collapsed .brand__wave--later {
	animation-delay: calc(var(--brand-wave-start) + var(--brand-wave-duration) / 2);
}

/* both waves stay readable above the cap, three arcs like a Wi-Fi sign; they fade out at the top */
@keyframes brand-wave {
	from {
		opacity: var(--brand-wave-opacity);
		transform: translateY(0) scale(var(--brand-wave-start-scale));
	}
	50% {
		opacity: var(--brand-wave-held-opacity);
	}
	to {
		opacity: 0;
		transform: translateY(var(--brand-wave-rise)) scale(var(--brand-wave-shrink));
	}
}

/* MD3 headline small */
.title {
	margin: 0 0 var(--space-sm);
	font-size: 24px;
	font-weight: 400;
	line-height: 32px;
	text-align: center;
}

.lead {
	margin: 0 0 var(--space-xl);
	color: var(--color-on-surface-variant);
	text-align: center;
}

.step[hidden] {
	display: none;
}

/* MD3 outlined text field: the label rests in the field and floats onto its outline */
.field {
	position: relative;
}

.field input {
	width: 100%;
	height: var(--field-height);
	padding: 0 52px 0 15px;
	border: 1px solid var(--color-outline);
	border-radius: var(--field-radius);
	background: transparent;
	color: var(--color-on-surface);
	font: 400 16px/24px var(--typo-font-family);
	outline: none;
}

.field input:hover {
	border-color: var(--color-on-surface);
}

.field input:focus {
	border: 2px solid var(--color-primary);
	padding-left: 14px;
}

.field label {
	position: absolute;
	top: 50%;
	left: var(--field-label-inset);
	padding: 0 var(--space-xs);
	background: var(--color-surface);
	color: var(--color-on-surface-variant);
	font: 400 16px/24px var(--typo-font-family);
	max-width: calc(100% - 2 * var(--field-label-inset));
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
	transform: translateY(-50%);
	transition: top var(--duration-fast), font-size var(--duration-fast), line-height var(--duration-fast);
	pointer-events: none;
}

.field input:focus + label,
.field input:not(:placeholder-shown) + label {
	top: 0;
	font-size: 12px;
	line-height: 16px;
}

.field input:focus + label {
	color: var(--color-primary);
}

.field--error input,
.field--error input:hover,
.field--error input:focus {
	border-color: var(--color-error);
}

.field--error label,
.field--error input:focus + label {
	color: var(--color-error);
}

/* the request runs: a spinner at the right of the field */
.spinner {
	display: none;
	position: absolute;
	top: 50%;
	right: var(--space-lg);
	width: 20px;
	height: 20px;
	margin-top: -10px;
	border: 2px solid var(--color-primary);
	border-right-color: transparent;
	border-radius: 50%;
	animation: spin 800ms linear infinite;
}

.field--busy .spinner {
	display: block;
}

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

/* MD3 supporting text */
.supporting {
	min-height: 16px;
	margin: var(--space-xs) 0 0;
	padding: 0 var(--space-lg);
	color: var(--color-on-surface-variant);
	font-size: 12px;
	line-height: 16px;
}

.supporting--error {
	color: var(--color-error);
}

.supporting--success {
	color: var(--color-success);
}

.actions {
	display: flex;
	flex-wrap: wrap;
	justify-content: flex-end;
	gap: var(--space-sm);
	margin-top: var(--space-lg);
}

/* MD3 buttons: full-rounded, a state layer on hover and press */
.button {
	position: relative;
	height: var(--button-height);
	padding: 0 var(--space-xl);
	overflow: hidden;
	border: none;
	border-radius: var(--radius-full);
	font: 500 14px/20px var(--typo-font-family);
	letter-spacing: 0.1px;
	cursor: pointer;
}

.button::after {
	content: '';
	position: absolute;
	inset: 0;
	background: currentColor;
	opacity: 0;
	transition: opacity var(--duration-fast);
}

.button:hover::after {
	opacity: var(--sl-opacity-hovered);
}

.button:active::after {
	opacity: var(--sl-opacity-pressed);
}

/* aria-disabled: drawn disabled, still told it is clicked (the download page's systems coming soon) */
.button:disabled,
.button[aria-disabled='true'] {
	cursor: default;
}

.button:disabled::after,
.button[aria-disabled='true']::after {
	opacity: 0;
}

.button:focus-visible {
	outline: 2px solid var(--color-primary);
	outline-offset: 2px;
}

.button--filled {
	background: var(--color-primary);
	color: var(--color-on-primary);
}

.button--filled:disabled,
.button--filled[aria-disabled='true'] {
	background: color-mix(in srgb, var(--color-on-surface) 12%, transparent);
	color: color-mix(in srgb, var(--color-on-surface) 38%, transparent);
}

.button--text {
	padding: 0 12px;
	background: transparent;
	color: var(--color-primary);
}

.button--text:disabled {
	color: color-mix(in srgb, var(--color-on-surface) 38%, transparent);
}

/* MD3 filled tonal button: a secondary action beside the form's filled one */
.button--tonal {
	background: var(--color-secondary-container);
	color: var(--color-on-secondary-container);
}

.button--tonal:disabled {
	background: color-mix(in srgb, var(--color-on-surface) 12%, transparent);
	color: color-mix(in srgb, var(--color-on-surface) 38%, transparent);
}

.button[hidden] {
	display: none;
}

/* the address the steps after the first are about, and the way back to it */
.identity {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: var(--space-sm);
	margin-bottom: var(--space-lg);
}

.identity[hidden] {
	display: none;
}

.identity__email {
	min-width: 0;
	overflow-wrap: anywhere;
	font-weight: 500;
}

.hint {
	margin: 0 0 var(--space-md);
	color: var(--color-on-surface-variant);
}

/* stacked fields keep the supporting text's room between them */
.field + .field,
.rules + .field,
.supporting + .field,
.protections + .field {
	margin-top: var(--space-lg);
}

/* under a new password: each rule, ticked once kept, an error once a typed password breaks it (the consoles' PasswordRules) */
.rules {
	margin: var(--space-xs) 0 0;
	padding: 0 var(--space-lg);
	list-style: none;
	color: var(--color-on-surface-variant);
	font-size: 12px;
	line-height: 16px;
}

.rules__rule::before {
	content: '✕';
	display: inline-block;
	width: var(--space-lg);
}

.rules__rule--broken {
	color: var(--color-error);
}

.rules__rule--kept {
	color: var(--color-primary);
}

.rules__rule--kept::before {
	content: '✓';
	color: var(--color-primary);
}

/* the protections, as MD3 radio buttons with a label and its supporting line */
.protections {
	margin: var(--space-lg) 0 0;
	padding: 0;
	border: none;
}

.protections__legend {
	margin-bottom: var(--space-sm);
	padding: 0;
	font-weight: 500;
}

.protection {
	display: flex;
	align-items: flex-start;
	gap: var(--space-xs);
	padding: var(--space-xs) 0;
	cursor: pointer;
}

.protection input {
	flex-shrink: 0;
	width: var(--radio-size);
	height: var(--radio-size);
	margin: calc((var(--radio-target) - var(--radio-size)) / 2);
	accent-color: var(--color-primary);
	cursor: pointer;
}

.protection__text {
	display: flex;
	flex-direction: column;
	padding-top: calc((var(--radio-target) - var(--label-line-height)) / 2);
}

.protection[hidden] {
	display: none;
}

.protection__supporting {
	color: var(--color-on-surface-variant);
	font-size: 12px;
	line-height: 16px;
}

.protection__panel {
	margin: 0 0 var(--space-sm) var(--radio-target);
	padding: var(--space-lg);
	border: 1px solid var(--color-outline-variant);
	border-radius: var(--radius-md);
}

.protection__panel[hidden] {
	display: none;
}

/* the app's QR code, dark modules on white whatever the theme, its quiet zone drawn */
.authenticator__qr svg {
	display: block;
	width: var(--qr-size);
	height: var(--qr-size);
	margin: 0 auto var(--space-sm);
	background: rgb(255 255 255);
	fill: rgb(0 0 0);
}

.authenticator__key {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: center;
	gap: var(--space-sm);
}

.authenticator__secret {
	font: 500 14px/20px ui-monospace, monospace;
	letter-spacing: 0.5px;
	overflow-wrap: anywhere;
	user-select: all;
}

/* a phone holds its authenticator app: the link opens it; a computer scans the QR code instead */
.authenticator__open {
	display: none;
	align-items: center;
	margin: var(--space-sm) auto 0;
	text-decoration: none;
	width: fit-content;
}

@media (pointer: coarse) {
	.authenticator__open {
		display: flex;
	}
}

.inline-field {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: flex-end;
	gap: var(--space-sm);
	margin-top: var(--space-lg);
}

.inline-field .field {
	flex: 1 1 var(--inline-field-min-width);
	min-width: 0;
}

/* the code typed into the client running elsewhere: large, spaced, every character apart (MD3 display small) */
.completion-code {
	margin: 0 0 var(--space-lg);
	font: 500 36px/44px ui-monospace, monospace;
	letter-spacing: 0.15em;
	text-align: center;
	user-select: all;
}

.completion-code[hidden],
.hint[hidden] {
	display: none;
}

.organizations {
	margin: 0 0 var(--space-sm);
}

.organizations:empty {
	display: none;
}

.organizations--ambiguous {
	color: var(--color-error);
}

@media (prefers-reduced-motion: reduce) {
	.spinner {
		animation-duration: 2400ms;
	}
	.field label,
	.button::after,
	.brand__client,
	.brand__client--collapsed,
	.brand__client-c,
	.brand__client-cap,
	.brand__client--collapsed .brand__client-c,
	.brand__client--collapsed .brand__client-cap,
	.brand__client-emerging,
	.brand__fading,
	.brand__client--collapsed .brand__fading,
	.brand__client--collapsed .brand__client-emerging {
		transition: none;
	}
	.brand__client--collapsed .brand__wave {
		animation: none;
	}
}
