<div id="root"></div>
$light: #fff;
$dark: #222;
$blue: #2196f3;
$red: #fb3838;

body {
	box-sizing: border-box;
	height: 100%;
}

/* Form
----------------------------*/
form {
	overflow: hidden;
	width: 300px;
	margin: 1em auto;
	select,
	input {
		font-weight: 500;
		font-size: 1em;
		line-height: 1em;
		width: calc(100% / 3 - 0.4em);
		height: 2.5em;
		float: left;
		padding: 0.5em;
		margin: 0 0.2em;
		border: 1px solid lighten($dark, 80%);
		border-width: 0 0 2px 0;
		background: transparent;
		color: $dark;
		outline: none;
		transition: all 500ms ease-in-out;
		&:hover,
		&:focus {
			cursor: pointer;
			outline: none;
			transition: all 500ms ease-in-out;
		}
	}
	input[type="submit"] {
		border: 1px solid $blue;
		background: $blue;
		color: $light;
		&:hover,
		&:focus {
			border-color: lighten($blue, 20%);
			background: lighten($blue, 20%);
		}
	}
	option {
		color: $dark;
	}
	option:disabled {
		color: lighten($dark, 60%);
	}
}

/* Grid
----------------------------*/
%equal-heights {
	display: flex;
	flex-wrap: wrap;
}
.boxes {
	@extend %equal-heights;
}
.box {
	margin:1em 0.5em;
	width: calc(100% / 4 - 1em);
	@media (max-width: 960px) {
		width: calc(100% / 3 - 1em);
	}
	@media (max-width: 767px) {
		width: calc(100% / 2 - 1em);
	}
	@media (max-width: 600px) {
		width: calc(100% - 1em);
	}
}

/* Thumbs
----------------------------*/
.thumb {
	padding: 1em;
	text-align: center;
	position: relative;
	width: calc(100% - 2em);
	max-width: 12em;
	margin: auto;
	border: 1px solid darken($light, 10%);
	background: $light;
	box-shadow: 0px 4px 4px -4px $dark;
	border-radius: 4px;
	transition: background 800ms ease;
	opacity: 1;
	transform: scale(1);
	animation: show 500ms 1 ease-in-out;
	@keyframes show {
		from {
			transform:scale(0.5);
			opacity: 0;
		}
	}
	img {
		max-width: 100%;
		padding: 1em;
		width: calc(100% - 2em);
	}
	.img-loading {
    width: 100%;
    margin: auto;
    text-align:center;
    position:relative;
    color: $blue;
    div{
      display: block;
      width: 100%;
      min-height: 190px;
      margin: auto;
      background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+PCEtLSBHZW5lcmF0b3I6IEdyYXZpdC5pbyAtLT48c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHN0eWxlPSJpc29sYXRpb246aXNvbGF0ZSIgdmlld0JveD0iMCAwIDg0IDE1MCIgd2lkdGg9Ijg0cHQiIGhlaWdodD0iMTUwcHQiPjxtYXNrIGlkPSJfbWFza194dWZtVmJjR1hRUTY3cTIweEpvZlNPZnVDajdNclZ3YiIgeD0iLTIwMCUiIHk9Ii0yMDAlIiB3aWR0aD0iNDAwJSIgaGVpZ2h0PSI0MDAlIj48cmVjdCB4PSItMjAwJSIgeT0iLTIwMCUiIHdpZHRoPSI0MDAlIiBoZWlnaHQ9IjQwMCUiIHN0eWxlPSJmaWxsOndoaXRlOyIvPjxsaW5lIHgxPSI4LjU3MyIgeTE9IjE3LjUiIHgyPSI3NC41NzMiIHkyPSIxNy41IiBmaWxsPSJibGFjayIgc3Ryb2tlPSJub25lIi8+PC9tYXNrPjxsaW5lIHgxPSI4LjU3MyIgeTE9IjE3LjUiIHgyPSI3NC41NzMiIHkyPSIxNy41IiBtYXNrPSJ1cmwoI19tYXNrX3h1Zm1WYmNHWFFRNjdxMjB4Sm9mU09mdUNqN01yVndiKSIgdmVjdG9yLWVmZmVjdD0ibm9uLXNjYWxpbmctc3Ryb2tlIiBzdHJva2Utd2lkdGg9IjEwIiBzdHJva2U9InJnYigzNCwzNCwzNCkiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLW1pdGVybGltaXQ9IjQiLz48bWFzayBpZD0iX21hc2tfa2xIUU5OQ2xZNGpUeVhtdUR0cEVqdnJ0OWlPUnFvbmQiIHg9Ii0yMDAlIiB5PSItMjAwJSIgd2lkdGg9IjQwMCUiIGhlaWdodD0iNDAwJSI+PHJlY3QgeD0iLTIwMCUiIHk9Ii0yMDAlIiB3aWR0aD0iNDAwJSIgaGVpZ2h0PSI0MDAlIiBzdHlsZT0iZmlsbDp3aGl0ZTsiLz48cGF0aCBkPSIgTSA4LjU3MyA0OC4wMzMgTCA3NC41NzMgNDguMDMzIE0gOC41NzMgNzQuNjY1IEwgNzQuNTczIDc0LjY2NSBNIDguNTczIDk5Ljk2NSBMIDc0LjU3MyA5OS45NjUgTSA4LjU3MyAxMjQgTCA3NC41NzMgMTI0IE0gOC41NzMgMjAgTCA4LjU3MyAxMjkgTSAzMC41NzMgMjAgTCAzMC41NzMgMTI5IE0gNTIuNTczIDIwIEwgNTIuNTczIDEyOSBNIDc0LjU3MyAyMCBMIDc0LjU3MyAxMjkiIGZpbGwtcnVsZT0iZXZlbm9kZCIgZmlsbD0iYmxhY2siIHN0cm9rZT0ibm9uZSIvPjwvbWFzaz48cGF0aCBkPSIgTSA4LjU3MyA0OC4wMzMgTCA3NC41NzMgNDguMDMzIE0gOC41NzMgNzQuNjY1IEwgNzQuNTczIDc0LjY2NSBNIDguNTczIDk5Ljk2NSBMIDc0LjU3MyA5OS45NjUgTSA4LjU3MyAxMjQgTCA3NC41NzMgMTI0IE0gOC41NzMgMjAgTCA4LjU3MyAxMjkgTSAzMC41NzMgMjAgTCAzMC41NzMgMTI5IE0gNTIuNTczIDIwIEwgNTIuNTczIDEyOSBNIDc0LjU3MyAyMCBMIDc0LjU3MyAxMjkiIGZpbGwtcnVsZT0iZXZlbm9kZCIgZmlsbD0icmdiKDAsMCwwKSIgbWFzaz0idXJsKCNfbWFza19rbEhRTk5DbFk0alR5WG11RHRwRWp2cnQ5aU9ScW9uZCkiIHZlY3Rvci1lZmZlY3Q9Im5vbi1zY2FsaW5nLXN0cm9rZSIgc3Ryb2tlLXdpZHRoPSI0IiBzdHJva2U9InJnYigzNCwzNCwzNCkiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLW1pdGVybGltaXQ9IjQiLz48cGF0aCBkPSIgTSA4LjU3MyA0OC4wMzMgTCA3NC41NzMgNDguMDMzIE0gOC41NzMgNzQuNjY1IEwgNzQuNTczIDc0LjY2NSBNIDguNTczIDk5Ljk2NSBMIDc0LjU3MyA5OS45NjUgTSA4LjU3MyAxMjQgTCA3NC41NzMgMTI0IE0gOC41NzMgMjAgTCA4LjU3MyAxMjkgTSAzMC41NzMgMjAgTCAzMC41NzMgMTI5IE0gNTIuNTczIDIwIEwgNTIuNTczIDEyOSBNIDc0LjU3MyAyMCBMIDc0LjU3MyAxMjkiIGZpbGwtcnVsZT0iZXZlbm9kZCIgZmlsbD0icmdiKDAsMCwwKSIvPjxwYXRoIGQ9IiBNIDQ5LjU3MyA4IEMgNDkuNTczIDYuMzQ0IDUwLjkxNyA1IDUyLjU3MyA1IEMgNTQuMjI5IDUgNTUuNTczIDYuMzQ0IDU1LjU3MyA4IEMgNTUuNTczIDkuNjU2IDU0LjIyOSAxMSA1Mi41NzMgMTEgQyA1MC45MTcgMTEgNDkuNTczIDkuNjU2IDQ5LjU3MyA4IFogIE0gMjcuNTczIDggQyAyNy41NzMgNi4zNDQgMjguOTE3IDUgMzAuNTczIDUgQyAzMi4yMjkgNSAzMy41NzMgNi4zNDQgMzMuNTczIDggQyAzMy41NzMgOS42NTYgMzIuMjI5IDExIDMwLjU3MyAxMSBDIDI4LjkxNyAxMSAyNy41NzMgOS42NTYgMjcuNTczIDggWiAgTSA2LjA3MyA4IEMgNi4wNzMgNi4zNDQgNy40MTcgNSA5LjA3MyA1IEMgMTAuNzI5IDUgMTIuMDczIDYuMzQ0IDEyLjA3MyA4IEMgMTIuMDczIDkuNjU2IDEwLjcyOSAxMSA5LjA3MyAxMSBDIDcuNDE3IDExIDYuMDczIDkuNjU2IDYuMDczIDggWiAgTSA3MS41NzMgOCBDIDcxLjU3MyA2LjM0NCA3Mi45MTcgNSA3NC41NzMgNSBDIDc2LjIyOSA1IDc3LjU3MyA2LjM0NCA3Ny41NzMgOCBDIDc3LjU3MyA5LjY1NiA3Ni4yMjkgMTEgNzQuNTczIDExIEMgNzIuOTE3IDExIDcxLjU3MyA5LjY1NiA3MS41NzMgOCBaICIgZmlsbC1ydWxlPSJldmVub2RkIiBmaWxsPSJub25lIiB2ZWN0b3ItZWZmZWN0PSJub24tc2NhbGluZy1zdHJva2UiIHN0cm9rZS13aWR0aD0iMSIgc3Ryb2tlPSJyZ2IoMCwwLDApIiBzdHJva2UtbGluZWpvaW49Im1pdGVyIiBzdHJva2UtbGluZWNhcD0iYnV0dCIgc3Ryb2tlLW1pdGVybGltaXQ9IjQiLz48cGF0aCBkPSIgTSAxMC42OTggMTM5LjI3OSBMIDEwLjY5OCAxMzkuMjc5IEwgMTAuNjk4IDEzOS4yNzkgUSAxMC42OTggMTQwLjk0NCAxMC4xNzMgMTQxLjc2NiBMIDEwLjE3MyAxNDEuNzY2IEwgMTAuMTczIDE0MS43NjYgUSA5LjY0NyAxNDIuNTg4IDguNTY2IDE0Mi41ODggTCA4LjU2NiAxNDIuNTg4IEwgOC41NjYgMTQyLjU4OCBRIDcuNTI5IDE0Mi41ODggNi45ODkgMTQxLjc0NiBMIDYuOTg5IDE0MS43NDYgTCA2Ljk4OSAxNDEuNzQ2IFEgNi40NDggMTQwLjkwNSA2LjQ0OCAxMzkuMjc5IEwgNi40NDggMTM5LjI3OSBMIDYuNDQ4IDEzOS4yNzkgUSA2LjQ0OCAxMzcuNiA2Ljk3MSAxMzYuNzg3IEwgNi45NzEgMTM2Ljc4NyBMIDYuOTcxIDEzNi43ODcgUSA3LjQ5NCAxMzUuOTc0IDguNTY2IDEzNS45NzQgTCA4LjU2NiAxMzUuOTc0IEwgOC41NjYgMTM1Ljk3NCBRIDkuNjEyIDEzNS45NzQgMTAuMTU1IDEzNi44MjIgTCAxMC4xNTUgMTM2LjgyMiBMIDEwLjE1NSAxMzYuODIyIFEgMTAuNjk4IDEzNy42NyAxMC42OTggMTM5LjI3OSBaICBNIDcuMTg3IDEzOS4yNzkgTCA3LjE4NyAxMzkuMjc5IEwgNy4xODcgMTM5LjI3OSBRIDcuMTg3IDE0MC42ODEgNy41MTYgMTQxLjMyIEwgNy41MTYgMTQxLjMyIEwgNy41MTYgMTQxLjMyIFEgNy44NDYgMTQxLjk1OSA4LjU2NiAxNDEuOTU5IEwgOC41NjYgMTQxLjk1OSBMIDguNTY2IDE0MS45NTkgUSA5LjI5NiAxNDEuOTU5IDkuNjIzIDE0MS4zMTEgTCA5LjYyMyAxNDEuMzExIEwgOS42MjMgMTQxLjMxMSBRIDkuOTUxIDE0MC42NjMgOS45NTEgMTM5LjI3OSBMIDkuOTUxIDEzOS4yNzkgTCA5Ljk1MSAxMzkuMjc5IFEgOS45NTEgMTM3Ljg5NSA5LjYyMyAxMzcuMjUxIEwgOS42MjMgMTM3LjI1MSBMIDkuNjIzIDEzNy4yNTEgUSA5LjI5NiAxMzYuNjA3IDguNTY2IDEzNi42MDcgTCA4LjU2NiAxMzYuNjA3IEwgOC41NjYgMTM2LjYwNyBRIDcuODQ2IDEzNi42MDcgNy41MTYgMTM3LjI0MiBMIDcuNTE2IDEzNy4yNDIgTCA3LjUxNiAxMzcuMjQyIFEgNy4xODcgMTM3Ljg3NyA3LjE4NyAxMzkuMjc5IFogIE0gMzIuNjk4IDEzOS4yNzkgTCAzMi42OTggMTM5LjI3OSBMIDMyLjY5OCAxMzkuMjc5IFEgMzIuNjk4IDE0MC45NDQgMzIuMTczIDE0MS43NjYgTCAzMi4xNzMgMTQxLjc2NiBMIDMyLjE3MyAxNDEuNzY2IFEgMzEuNjQ3IDE0Mi41ODggMzAuNTY2IDE0Mi41ODggTCAzMC41NjYgMTQyLjU4OCBMIDMwLjU2NiAxNDIuNTg4IFEgMjkuNTI5IDE0Mi41ODggMjguOTg5IDE0MS43NDYgTCAyOC45ODkgMTQxLjc0NiBMIDI4Ljk4OSAxNDEuNzQ2IFEgMjguNDQ4IDE0MC45MDUgMjguNDQ4IDEzOS4yNzkgTCAyOC40NDggMTM5LjI3OSBMIDI4LjQ0OCAxMzkuMjc5IFEgMjguNDQ4IDEzNy42IDI4Ljk3MSAxMzYuNzg3IEwgMjguOTcxIDEzNi43ODcgTCAyOC45NzEgMTM2Ljc4NyBRIDI5LjQ5NCAxMzUuOTc0IDMwLjU2NiAxMzUuOTc0IEwgMzAuNTY2IDEzNS45NzQgTCAzMC41NjYgMTM1Ljk3NCBRIDMxLjYxMiAxMzUuOTc0IDMyLjE1NSAxMzYuODIyIEwgMzIuMTU1IDEzNi44MjIgTCAzMi4xNTUgMTM2LjgyMiBRIDMyLjY5OCAxMzcuNjcgMzIuNjk4IDEzOS4yNzkgWiAgTSAyOS4xODcgMTM5LjI3OSBMIDI5LjE4NyAxMzkuMjc5IEwgMjkuMTg3IDEzOS4yNzkgUSAyOS4xODcgMTQwLjY4MSAyOS41MTYgMTQxLjMyIEwgMjkuNTE2IDE0MS4zMiBMIDI5LjUxNiAxNDEuMzIgUSAyOS44NDYgMTQxLjk1OSAzMC41NjYgMTQxLjk1OSBMIDMwLjU2NiAxNDEuOTU5IEwgMzAuNTY2IDE0MS45NTkgUSAzMS4yOTYgMTQxLjk1OSAzMS42MjMgMTQxLjMxMSBMIDMxLjYyMyAxNDEuMzExIEwgMzEuNjIzIDE0MS4zMTEgUSAzMS45NTEgMTQwLjY2MyAzMS45NTEgMTM5LjI3OSBMIDMxLjk1MSAxMzkuMjc5IEwgMzEuOTUxIDEzOS4yNzkgUSAzMS45NTEgMTM3Ljg5NSAzMS42MjMgMTM3LjI1MSBMIDMxLjYyMyAxMzcuMjUxIEwgMzEuNjIzIDEzNy4yNTEgUSAzMS4yOTYgMTM2LjYwNyAzMC41NjYgMTM2LjYwNyBMIDMwLjU2NiAxMzYuNjA3IEwgMzAuNTY2IDEzNi42MDcgUSAyOS44NDYgMTM2LjYwNyAyOS41MTYgMTM3LjI0MiBMIDI5LjUxNiAxMzcuMjQyIEwgMjkuNTE2IDEzNy4yNDIgUSAyOS4xODcgMTM3Ljg3NyAyOS4xODcgMTM5LjI3OSBaICBNIDU0LjY5OCAxMzkuMjc5IEwgNTQuNjk4IDEzOS4yNzkgTCA1NC42OTggMTM5LjI3OSBRIDU0LjY5OCAxNDAuOTQ0IDU0LjE3MyAxNDEuNzY2IEwgNTQuMTczIDE0MS43NjYgTCA1NC4xNzMgMTQxLjc2NiBRIDUzLjY0NyAxNDIuNTg4IDUyLjU2NiAxNDIuNTg4IEwgNTIuNTY2IDE0Mi41ODggTCA1Mi41NjYgMTQyLjU4OCBRIDUxLjUyOSAxNDIuNTg4IDUwLjk4OSAxNDEuNzQ2IEwgNTAuOTg5IDE0MS43NDYgTCA1MC45ODkgMTQxLjc0NiBRIDUwLjQ0OCAxNDAuOTA1IDUwLjQ0OCAxMzkuMjc5IEwgNTAuNDQ4IDEzOS4yNzkgTCA1MC40NDggMTM5LjI3OSBRIDUwLjQ0OCAxMzcuNiA1MC45NzEgMTM2Ljc4NyBMIDUwLjk3MSAxMzYuNzg3IEwgNTAuOTcxIDEzNi43ODcgUSA1MS40OTQgMTM1Ljk3NCA1Mi41NjYgMTM1Ljk3NCBMIDUyLjU2NiAxMzUuOTc0IEwgNTIuNTY2IDEzNS45NzQgUSA1My42MTIgMTM1Ljk3NCA1NC4xNTUgMTM2LjgyMiBMIDU0LjE1NSAxMzYuODIyIEwgNTQuMTU1IDEzNi44MjIgUSA1NC42OTggMTM3LjY3IDU0LjY5OCAxMzkuMjc5IFogIE0gNTEuMTg3IDEzOS4yNzkgTCA1MS4xODcgMTM5LjI3OSBMIDUxLjE4NyAxMzkuMjc5IFEgNTEuMTg3IDE0MC42ODEgNTEuNTE2IDE0MS4zMiBMIDUxLjUxNiAxNDEuMzIgTCA1MS41MTYgMTQxLjMyIFEgNTEuODQ2IDE0MS45NTkgNTIuNTY2IDE0MS45NTkgTCA1Mi41NjYgMTQxLjk1OSBMIDUyLjU2NiAxNDEuOTU5IFEgNTMuMjk2IDE0MS45NTkgNTMuNjIzIDE0MS4zMTEgTCA1My42MjMgMTQxLjMxMSBMIDUzLjYyMyAxNDEuMzExIFEgNTMuOTUxIDE0MC42NjMgNTMuOTUxIDEzOS4yNzkgTCA1My45NTEgMTM5LjI3OSBMIDUzLjk1MSAxMzkuMjc5IFEgNTMuOTUxIDEzNy44OTUgNTMuNjIzIDEzNy4yNTEgTCA1My42MjMgMTM3LjI1MSBMIDUzLjYyMyAxMzcuMjUxIFEgNTMuMjk2IDEzNi42MDcgNTIuNTY2IDEzNi42MDcgTCA1Mi41NjYgMTM2LjYwNyBMIDUyLjU2NiAxMzYuNjA3IFEgNTEuODQ2IDEzNi42MDcgNTEuNTE2IDEzNy4yNDIgTCA1MS41MTYgMTM3LjI0MiBMIDUxLjUxNiAxMzcuMjQyIFEgNTEuMTg3IDEzNy44NzcgNTEuMTg3IDEzOS4yNzkgWiAgTSA3Ni42OTggMTM5LjI3OSBMIDc2LjY5OCAxMzkuMjc5IEwgNzYuNjk4IDEzOS4yNzkgUSA3Ni42OTggMTQwLjk0NCA3Ni4xNzMgMTQxLjc2NiBMIDc2LjE3MyAxNDEuNzY2IEwgNzYuMTczIDE0MS43NjYgUSA3NS42NDcgMTQyLjU4OCA3NC41NjYgMTQyLjU4OCBMIDc0LjU2NiAxNDIuNTg4IEwgNzQuNTY2IDE0Mi41ODggUSA3My41MjkgMTQyLjU4OCA3Mi45ODkgMTQxLjc0NiBMIDcyLjk4OSAxNDEuNzQ2IEwgNzIuOTg5IDE0MS43NDYgUSA3Mi40NDggMTQwLjkwNSA3Mi40NDggMTM5LjI3OSBMIDcyLjQ0OCAxMzkuMjc5IEwgNzIuNDQ4IDEzOS4yNzkgUSA3Mi40NDggMTM3LjYgNzIuOTcxIDEzNi43ODcgTCA3Mi45NzEgMTM2Ljc4NyBMIDcyLjk3MSAxMzYuNzg3IFEgNzMuNDk0IDEzNS45NzQgNzQuNTY2IDEzNS45NzQgTCA3NC41NjYgMTM1Ljk3NCBMIDc0LjU2NiAxMzUuOTc0IFEgNzUuNjEyIDEzNS45NzQgNzYuMTU1IDEzNi44MjIgTCA3Ni4xNTUgMTM2LjgyMiBMIDc2LjE1NSAxMzYuODIyIFEgNzYuNjk4IDEzNy42NyA3Ni42OTggMTM5LjI3OSBaICBNIDczLjE4NyAxMzkuMjc5IEwgNzMuMTg3IDEzOS4yNzkgTCA3My4xODcgMTM5LjI3OSBRIDczLjE4NyAxNDAuNjgxIDczLjUxNiAxNDEuMzIgTCA3My41MTYgMTQxLjMyIEwgNzMuNTE2IDE0MS4zMiBRIDczLjg0NiAxNDEuOTU5IDc0LjU2NiAxNDEuOTU5IEwgNzQuNTY2IDE0MS45NTkgTCA3NC41NjYgMTQxLjk1OSBRIDc1LjI5NiAxNDEuOTU5IDc1LjYyMyAxNDEuMzExIEwgNzUuNjIzIDE0MS4zMTEgTCA3NS42MjMgMTQxLjMxMSBRIDc1Ljk1MSAxNDAuNjYzIDc1Ljk1MSAxMzkuMjc5IEwgNzUuOTUxIDEzOS4yNzkgTCA3NS45NTEgMTM5LjI3OSBRIDc1Ljk1MSAxMzcuODk1IDc1LjYyMyAxMzcuMjUxIEwgNzUuNjIzIDEzNy4yNTEgTCA3NS42MjMgMTM3LjI1MSBRIDc1LjI5NiAxMzYuNjA3IDc0LjU2NiAxMzYuNjA3IEwgNzQuNTY2IDEzNi42MDcgTCA3NC41NjYgMTM2LjYwNyBRIDczLjg0NiAxMzYuNjA3IDczLjUxNiAxMzcuMjQyIEwgNzMuNTE2IDEzNy4yNDIgTCA3My41MTYgMTM3LjI0MiBRIDczLjE4NyAxMzcuODc3IDczLjE4NyAxMzkuMjc5IFogIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGZpbGw9InJnYigwLDAsMCkiLz48L3N2Zz4=)
        no-repeat center center transparent;
      animation: flash 800ms infinite ease-in-out;
      @keyframes flash {
        from {
          opacity: 0;
        }
      }
    }
  }
	figcaption {
		margin-top: 0.2em;
		font-size: 12px;
		font-weight: 700;
		color: darken($light, 30%);
	}
	&.hide {
		opacity: 0;
		transform: scale(0.2);
		animation: hideElement 200ms 1 ease-in-out;
		@keyframes hideElement {
			from {
				transform:scale(1);
				opacity: 1;
			}
		}
	}
	.img-close {
		position: absolute;
		top: -8px;
		right: -8px;
		width: 30px;
		height: 30px;
		line-height: 1.2;
		font-size: 25px;
		font-weight: bold;
		border-radius: 100%;
		cursor: pointer;
		background: $red;
		border: 1px solid darken($red, 20%);
		color: $light;
	}
}
.exists{
	border:1px solid $red;
	background:lighten($red,20%);
	transition: background 800ms ease;
	figcaption{
		color:$light;
	}
}
/* layout
----------------------------*/
.header {
	text-align: center;
	h3 {
		margin: 0;
		font-size: 2em;
		color: darken($light, 50%);
	}
}

View Compiled
const {useState, useEffect, Fragment } = React;

const assetsUrl = "http://ukulala.surge.sh/chords";
/**
 * Storage theme settings
 *
 * set Storage.val = {color: 'blue'}
 * get Storage.val
 */
const Storage = {
	get val() {
		this.data = window.localStorage.getItem("demo_data");
		return JSON.parse(this.data);
	},
	set val(value) {
		this.data = JSON.stringify(value);
		window.localStorage.setItem("demo_data", this.data);
	}
};

// check array duplicates
const hasDuplicates = array => {
	return (new Set(array)).size !== array.length;
}


/* Notes
-----------------------------*/
const Notes = {
	C: "Do",
	Db: "Reb/Do#",
	D: "Re",
	Eb: "Mib/Re#",
	E: "Mi",
	F: "Fa",
	Gb: "Solb/Fa#",
	G: "Sol",
	Ab: "Lab/Sol#",
	A: "La",
	Bb: "Sib/La#",
	B: "Si"
};
/* Tonalityes
-----------------------------*/
const Tonalityes = {
	"": "",
	m: "m",
	_: "+",
	"5": "5",
	"6": "6",
	maj7: "maj7",
	m7: "m7",
	m6: "m6",
	m7_b5_: "m7(b5)",
	dim7: "dim7",
	"7": "7",
	"9": "9",
	"7_b9_": "7(b9)",
	"7__5_": "7(#5)"
};
/* Simple forms component
-----------------------------*/
const Form = (props) => <form onSubmit={props.fn}>{props.children}</form>;
const Select = (props) => {
	let data = props.data;
	let notes = {};
	if (props.sort) notes = Object.entries(data).sort();
	else notes = Object.entries(data);
	return (
		<select onChange={props.fn}>
			{notes.map(([key, value]) => (
				<option key={key} value={key}>
					{value}
				</option>
			))}
		</select>
	);
};
const Submit = (props) => <input type="submit" value={props.val || "Get"} />;

/* Columns
-----------------------------*/
const Boxes = (props) => <div className="boxes">{props.children}</div>;
const Box = (props) => <div className="box">{props.children}</div>;
const ImgLoader = () => <div className="img-loading"><div></div></div>

/* Image
-----------------------------*/
const Image = (props) => {
	const [src, setSrc] = useState("");
	// use timeout and show image
	useEffect(() => {
		let timerid = false;
		if (timerid) {
			clearTimeout(timerid);
		}
		timerid = setTimeout(() => {
			setSrc(`${assetsUrl}/${props.data}.svg`);
		}, 100);
	}, [props.data]);

	return (
		<figure className={`thumb ${props.data}`}>
			<span className="img-close" onClick={props.fn}>&times;</span>
			{/* check if exists src */}
			{src ? <img src={src} /> : <ImgLoader/>}
			<figcaption>
        {props.data.substring(0, 2).charAt(1) === "b"
          ? Notes[props.data.substring(0, 2)] +
            " " +
            Tonalityes[props.data.substring(2, props.data.length)]
          : Notes[props.data.substring(0, 1)] +
            " " +
            Tonalityes[props.data.substring(1, props.data.length)]}
			</figcaption>
		</figure>
	);
};

const Header = (props) => (
	<header className="header">
		<h3>{props.children}</h3>
	</header>
);

const App = () => {
	// last array
	let lastSaved = Storage.val ? Storage.val : ["C"];
	// data of chords
	const [data, setData] = useState(["C"]);

	// note & tonality
	const [note, setNote] = useState("C");
	const [tonality, setTonality] = useState("");

	// on init get last data saved
	useEffect(() => setData(lastSaved), []);
	
	// Add submit
	const handleSubmit = (e) => {
    e.preventDefault();
    let arr = note + tonality;
    let newArr = [...data, arr];
    if (hasDuplicates(newArr)) {
      // if chord exists show red color
      let img = document.querySelector(`.${arr}`);
      img.classList.add("exists");
      let w = setTimeout(() => {
        img.classList.remove("exists");
        clearTimeout(w);
      }, 800);
    }
    // update array of unique elements
    setData([...new Set(newArr)]);
    Storage.val = [...new Set(newArr)];
		return false;
	};

	// delete data
	const removeData = (evt, index) => {
		let element = evt.target.parentNode;
		element.classList.add("hide");

		let w = setTimeout(() => {
			// remove array by index
			let arr = [...data];
			arr.splice(index, 1);
			// remove duplicates
			let savedArr = [...new Set(arr)];
			// update
			setData(savedArr);
			// storage saved
			Storage.val = savedArr;
			clearTimeout(w);
		}, 500);

	};

	return (
		<Fragment>
			<Header>Ukelele Componser</Header>
			<Form fn={handleSubmit}>
				<Select 
					sort={false} 
					fn={(e) => setNote(e.target.value)} 
					data={Notes} />
				<Select
					sort={true}
					fn={(e) => setTonality(e.target.value)}
					data={Tonalityes}
				/>
				<Submit val="+" />
			</Form>
			<Boxes>
				{data.map((item, index) => (
					<Box key={index}>
						<Image 
							fn={(evt) => removeData(evt, index)} 
							data={item} />
					</Box>
				))}
			</Boxes>
		</Fragment>
	);
};

ReactDOM.render(<App />, window.root);
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/react/16.13.0/umd/react.production.min.js
  2. https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.0/umd/react-dom.production.min.js