1868 lines
42 KiB
CSS
1868 lines
42 KiB
CSS
html {
|
|
font-size: 16px;
|
|
height: 100%;
|
|
}
|
|
body {
|
|
height: 100%;
|
|
margin: 0;
|
|
|
|
display: flex;
|
|
flex-direction: column;
|
|
|
|
font-family: Ubuntu, Source Sans Pro, DejaVu Sans, sans-serif;
|
|
line-height: 1.33;
|
|
background: #080808;
|
|
background-image: url(background.svg);
|
|
background-size: 10%;
|
|
color: #ececec;
|
|
|
|
--panel-bg-color: hsl(225, 10%, 15%);
|
|
--button-bg-color: hsl(225, 10%, 25%);
|
|
--button-bg-hover-color: hsl(225, 15%, 30%);
|
|
--generic-bg-hover-on-white: hsl(225, 60%, 85%);
|
|
--generic-bg-selected-on-white: hsl(225, 60%, 90%);
|
|
}
|
|
|
|
/* Generic element styling */
|
|
main[hidden] {
|
|
display: none !important;
|
|
}
|
|
input[type=radio],
|
|
input[type=checkbox],
|
|
input[type=range] {
|
|
margin: 0.125em;
|
|
vertical-align: middle;
|
|
}
|
|
input[type=number] {
|
|
font-size: inherit;
|
|
width: 4em;
|
|
width: 8ch;
|
|
text-align: right;
|
|
}
|
|
button,
|
|
.radio-faux-button-set > label > input + span {
|
|
font-size: inherit;
|
|
padding: 0.25em 0.5em;
|
|
font-family: inherit;
|
|
color: white;
|
|
background: var(--button-bg-color);
|
|
border: 1px solid hsl(225, 10%, 10%);
|
|
box-shadow:
|
|
inset 0 0 0 1px hsl(225, 10%, 33%),
|
|
0 1px 1px hsl(225, 10%, 10%);
|
|
border-radius: 0.25em;
|
|
text-transform: lowercase;
|
|
cursor: pointer;
|
|
}
|
|
button:hover,
|
|
.radio-faux-button-set > label:hover > input + span {
|
|
background: var(--button-bg-hover-color);
|
|
}
|
|
button:active,
|
|
.radio-faux-button-set > label:active > input + span {
|
|
transform: translateY(1px);
|
|
/* Need this for the editor's tool help things and i'm not questioning it */
|
|
z-index: 1;
|
|
}
|
|
button:disabled {
|
|
color: #606060;
|
|
background: #202020;
|
|
box-shadow:
|
|
inset 0 0 2px 1px hsl(225, 0%, 10%),
|
|
0 1px 0 hsl(225, 10%, 10%);
|
|
cursor: auto;
|
|
}
|
|
button.button-big {
|
|
display: block;
|
|
width: 100%;
|
|
margin: 0.5em 0;
|
|
padding: 1em;
|
|
}
|
|
button.--button-glow-ok {
|
|
background: hsl(225, 100%, 50%);
|
|
}
|
|
button.--button-glow {
|
|
transition: background-color 0.5s ease-out;
|
|
}
|
|
button.--image {
|
|
padding: 0;
|
|
border: none;
|
|
background: none;
|
|
box-shadow: none;
|
|
}
|
|
button.--image img {
|
|
display: block;
|
|
}
|
|
h1, h2, h3, h4, h5, h6 {
|
|
font-weight: normal;
|
|
margin: 0;
|
|
}
|
|
ul, ol {
|
|
margin: 0;
|
|
padding: 0;
|
|
list-style: none;
|
|
}
|
|
ul.normal-list {
|
|
margin-left: 1em;
|
|
list-style: disc;
|
|
}
|
|
ol.normal-list {
|
|
margin-left: 1.5em;
|
|
list-style: decimal;
|
|
}
|
|
p {
|
|
margin: 0.5em 0;
|
|
}
|
|
p:first-child {
|
|
margin-top: 0;
|
|
}
|
|
p:last-child {
|
|
margin-bottom: 0;
|
|
}
|
|
pre {
|
|
white-space: pre-wrap;
|
|
}
|
|
code {
|
|
color: #c0c0e0;
|
|
}
|
|
kbd {
|
|
padding: 0 0.25em;
|
|
border: 1px solid currentColor;
|
|
border-radius: 0.25em;
|
|
box-shadow: 0 2px 0 currentColor;
|
|
text-align: center;
|
|
text-transform: uppercase;
|
|
}
|
|
|
|
a {
|
|
color: #c0c0c0;
|
|
}
|
|
a:link,
|
|
a:visited {
|
|
text-decoration: underline dotted;
|
|
}
|
|
a:link {
|
|
color: hsl(225, 50%, 75%);
|
|
}
|
|
a:visited {
|
|
color: hsl(255, 50%, 75%);
|
|
}
|
|
a:link:hover,
|
|
a:visited:hover {
|
|
text-decoration: underline;
|
|
}
|
|
a:active {
|
|
color: hsl(0, 50%, 60%);
|
|
}
|
|
|
|
svg#svg-iconsheet {
|
|
/* This is a collection of SVG icons to be re-<use>d */
|
|
display: none;
|
|
}
|
|
svg.svg-icon {
|
|
width: 1em;
|
|
height: 1em;
|
|
vertical-align: middle;
|
|
|
|
stroke: none;
|
|
fill: currentColor;
|
|
fill-rule: evenodd;
|
|
}
|
|
|
|
/* Set of radio buttons in a row, styled like buttons */
|
|
/* (you know, like /actual/ radio buttons) */
|
|
/* Button-esque styling is shared with the button definition above */
|
|
.radio-faux-button-set {
|
|
display: flex;
|
|
align-items: stretch;
|
|
margin: 0.5em 0;
|
|
}
|
|
.radio-faux-button-set > label {
|
|
flex: 1;
|
|
}
|
|
.radio-faux-button-set > label > input {
|
|
display: none;
|
|
}
|
|
.radio-faux-button-set > label > input + span {
|
|
display: block;
|
|
box-sizing: border-box;
|
|
height: 100%;
|
|
border-radius: 0;
|
|
text-align: center;
|
|
}
|
|
.radio-faux-button-set > label:first-child > input + span {
|
|
border-top-left-radius: 0.25em;
|
|
border-bottom-left-radius: 0.25em;
|
|
}
|
|
.radio-faux-button-set > label:last-child > input + span {
|
|
border-top-right-radius: 0.25em;
|
|
border-bottom-right-radius: 0.25em;
|
|
}
|
|
.radio-faux-button-set > label > input:checked + span {
|
|
background: hsl(225, 80%, 50%);
|
|
box-shadow:
|
|
inset 0 1px 0 1px hsl(225, 10%, 20%),
|
|
inset 0 -0em 2em 0.5em hsl(225, 50%, 30%),
|
|
0 1px 1px hsl(225, 10%, 10%);
|
|
}
|
|
|
|
.button-row {
|
|
display: flex;
|
|
gap: 0.5em;
|
|
align-items: stretch;
|
|
}
|
|
.button-row > button {
|
|
flex: 1;
|
|
}
|
|
|
|
/* Overlay styling */
|
|
.overlay {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
|
|
position: fixed;
|
|
top: 0;
|
|
bottom: 0;
|
|
left: 0;
|
|
right: 0;
|
|
background: #fff4;
|
|
}
|
|
.overlay.--transient {
|
|
align-items: start;
|
|
justify-content: start;
|
|
background: none;
|
|
}
|
|
.dialog {
|
|
display: flex;
|
|
flex-direction: column;
|
|
|
|
min-width: 33vw;
|
|
max-width: 75vw;
|
|
max-height: 75vh;
|
|
border: 1px solid black;
|
|
color: black;
|
|
background: #f4f4f4;
|
|
box-shadow: 0 1px 3px #000c;
|
|
}
|
|
.dialog > header {
|
|
padding: 0.5em;
|
|
line-height: 1;
|
|
background: hsl(225, 20%, 40%);
|
|
color: white;
|
|
}
|
|
.dialog > header h1 {
|
|
font-size: 1em;
|
|
}
|
|
.dialog > footer {
|
|
display: flex;
|
|
justify-content: flex-end;
|
|
gap: 0.5em;
|
|
|
|
padding: 0.5em;
|
|
background: #d0d0d0;
|
|
}
|
|
.dialog > header:empty,
|
|
.dialog > footer:empty {
|
|
display: none;
|
|
}
|
|
.dialog > section {
|
|
flex: auto;
|
|
overflow: auto;
|
|
padding: 1em;
|
|
}
|
|
.dialog pre.error {
|
|
color: #400000;
|
|
background: #f0d0d0;
|
|
padding: 0.5em 1em;
|
|
}
|
|
.dialog a:link {
|
|
color: hsl(225, 50%, 50%);
|
|
}
|
|
.dialog a:visited {
|
|
color: hsl(255, 50%, 50%);
|
|
}
|
|
dl.formgrid {
|
|
display: grid;
|
|
grid: auto-flow min-content / 1fr 4fr;
|
|
align-items: baseline;
|
|
gap: 1em;
|
|
margin: 0;
|
|
}
|
|
dl.formgrid > dt {
|
|
grid-column: 1;
|
|
}
|
|
dl.formgrid > dd {
|
|
grid-column: 2;
|
|
margin: 0;
|
|
}
|
|
dl.formgrid > dd button {
|
|
margin: 0.25em 0;
|
|
}
|
|
dl.formgrid > dd button + button {
|
|
margin-left: 0.25em;
|
|
}
|
|
|
|
/* Individual overlays */
|
|
table.level-browser {
|
|
width: 100%;
|
|
/* for some reason the table ignores the bottom padding when it overflows */
|
|
margin-bottom: 1em;
|
|
line-height: 1.25;
|
|
border-spacing: 0;
|
|
}
|
|
table.level-browser thead {
|
|
position: sticky;
|
|
top: -1em; /* counteract padding so cells don't appear above us */
|
|
background: #f4f4f4; /* match dialog background */
|
|
}
|
|
table.level-browser thead tr th {
|
|
border-bottom: 2px solid hsl(225, 20%, 60%);
|
|
}
|
|
table.level-browser td {
|
|
padding: 0.25em;
|
|
}
|
|
table.level-browser td.-number {
|
|
color: #404040;
|
|
text-align: right;
|
|
}
|
|
table.level-browser td.-time {
|
|
text-align: right;
|
|
}
|
|
table.level-browser td.-score {
|
|
text-align: right;
|
|
}
|
|
table.level-browser tr.--current {
|
|
background: var(--generic-bg-selected-on-white);
|
|
}
|
|
table.level-browser tr.--unvisited {
|
|
color: #606060;
|
|
font-style: italic;
|
|
}
|
|
table.level-browser tr.--error {
|
|
color: #600000;
|
|
font-style: italic;
|
|
}
|
|
table.level-browser tbody tr {
|
|
cursor: pointer;
|
|
}
|
|
table.level-browser tbody tr:hover {
|
|
background: var(--generic-bg-hover-on-white);
|
|
}
|
|
table.level-browser tbody tr:nth-child(10n) td {
|
|
border-bottom: 2px solid hsl(225, 20%, 80%);
|
|
}
|
|
|
|
/* Compat dialog */
|
|
.dialog-compat {
|
|
max-width: 60em;
|
|
}
|
|
ul.compat-flags > li {
|
|
padding: 0.125em;
|
|
}
|
|
ul.compat-flags > li.-checked {
|
|
background: var(--generic-bg-selected-on-white);
|
|
}
|
|
ul.compat-flags > li:hover {
|
|
background: var(--generic-bg-hover-on-white);
|
|
}
|
|
ul.compat-flags > li > label {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.25em;
|
|
}
|
|
ul.compat-flags > li > label > span.-desc {
|
|
flex: 1;
|
|
}
|
|
img.compat-icon,
|
|
.compat-icon-gap {
|
|
display: inline-block;
|
|
width: 32px;
|
|
height: 32px;
|
|
vertical-align: middle;
|
|
}
|
|
|
|
|
|
/* Options dialog */
|
|
.dialog-options {
|
|
}
|
|
.option-volume {
|
|
display: flex;
|
|
gap: 1em;
|
|
}
|
|
.option-volume > input[type=range] {
|
|
flex: auto;
|
|
}
|
|
.option-tileset canvas {
|
|
vertical-align: middle;
|
|
}
|
|
label.option {
|
|
display: flex;
|
|
align-items: center;
|
|
padding: 0.25em;
|
|
}
|
|
label.option:hover {
|
|
outline: 2px solid #d0d0d0;
|
|
}
|
|
label.option .option-label {
|
|
flex: 1;
|
|
}
|
|
.option-help {
|
|
display: none;
|
|
background: #e8e8e8;
|
|
padding: 0.5em 0.75em;
|
|
border-radius: 0.5em;
|
|
}
|
|
.option-help.--visible {
|
|
/* TODO */
|
|
}
|
|
|
|
@media (max-width: 800px) {
|
|
.dialog {
|
|
max-width: 90%;
|
|
max-height: 90%;
|
|
}
|
|
}
|
|
|
|
|
|
/**************************************************************************************************/
|
|
/* Main page structure */
|
|
|
|
body > header {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5em;
|
|
|
|
padding: 0.5em;
|
|
line-height: 1.125;
|
|
}
|
|
body > header h1 {
|
|
font-size: 1.66em;
|
|
}
|
|
body > header h2 {
|
|
font-size: 1.33em;
|
|
}
|
|
body > header h3 {
|
|
font-size: 1.75em;
|
|
}
|
|
body > header > nav {
|
|
flex: 1;
|
|
display: flex;
|
|
justify-content: flex-end;
|
|
gap: 0.5em;
|
|
}
|
|
body > header button {
|
|
font-size: 0.75em;
|
|
}
|
|
body > header h1 a {
|
|
color: inherit !important;
|
|
text-decoration: none !important;
|
|
}
|
|
|
|
body[data-mode=failed] #header-pack,
|
|
body[data-mode=failed] #header-level,
|
|
body[data-mode=failed] #header-main > nav,
|
|
body[data-mode=loading] #header-pack,
|
|
body[data-mode=loading] #header-level,
|
|
body[data-mode=loading] #header-main > nav {
|
|
display: none;
|
|
}
|
|
body[data-mode=splash] #header-pack,
|
|
body[data-mode=splash] #header-level {
|
|
display: none;
|
|
}
|
|
body[data-mode=editor] #player-edit,
|
|
body[data-mode=player] #editor-play {
|
|
display: none;
|
|
}
|
|
#failed,
|
|
#loading {
|
|
margin: auto;
|
|
text-align: center;
|
|
}
|
|
#loading {
|
|
font-size: 2em;
|
|
}
|
|
.scrolling-sidewalk {
|
|
height: 32px;
|
|
width: 50vw;
|
|
margin: auto;
|
|
background: url(icons/tool-bg-selected.png) repeat;
|
|
animation: scrolling-sidewalk linear 0.4s infinite;
|
|
/*
|
|
box-shadow:
|
|
inset 5vw 0 5vw -5vw black,
|
|
inset -5vw 0 5vw -5vw black;
|
|
*/
|
|
mask: linear-gradient(to right, transparent 0, #ffffff40 10%, white 20%, white 80%, #ffffff40 90%, transparent 100%);
|
|
}
|
|
.scrolling-sidewalk > img {
|
|
display: block;
|
|
margin: auto;
|
|
}
|
|
@keyframes scrolling-sidewalk {
|
|
0% {
|
|
background-position: 0px 0px;
|
|
}
|
|
100% {
|
|
background-position: -32px 0px;
|
|
}
|
|
}
|
|
pre.stack-trace {
|
|
overflow: auto;
|
|
width: 90vw;
|
|
max-width: 50em;
|
|
padding: 0.5em;
|
|
margin: 1em auto;
|
|
white-space: pre;
|
|
text-align: left;
|
|
background: hsl(345, 20%, 10%);
|
|
border: 3px double hsl(345, 75%, 20%);
|
|
}
|
|
|
|
#header-main {
|
|
order: 3;
|
|
color: #606060;
|
|
}
|
|
|
|
@media (max-width: 800px) {
|
|
body > header {
|
|
padding: 0.25em;
|
|
}
|
|
/* All these headings are way too big on phones */
|
|
body > header h1 {
|
|
font-size: 1.25em;
|
|
}
|
|
body > header h2 {
|
|
font-size: 1.125em;
|
|
}
|
|
body > header h3 {
|
|
font-size: 1.0625em;
|
|
}
|
|
body > header p {
|
|
/* "a game by eevee" takes up too much space :( */
|
|
display: none;
|
|
}
|
|
}
|
|
|
|
/**************************************************************************************************/
|
|
/* Splash (intro part) */
|
|
|
|
#splash {
|
|
display: grid;
|
|
grid:
|
|
"header header"
|
|
"links links"
|
|
"stock yours"
|
|
/ 1fr 1fr
|
|
;
|
|
gap: 1em;
|
|
|
|
position: relative;
|
|
padding: 1em 10%;
|
|
margin: auto 0;
|
|
overflow: auto;
|
|
}
|
|
#splash::after {
|
|
/* Force some breathing room at the bottom of the scroll */
|
|
content: '';
|
|
display: block;
|
|
height: 2em;
|
|
}
|
|
#splash > .drag-overlay {
|
|
display: none;
|
|
justify-content: center;
|
|
align-items: center;
|
|
|
|
font-size: 10vmin;
|
|
position: fixed;
|
|
top: 0.5rem;
|
|
bottom: 0.5rem;
|
|
left: 0.5rem;
|
|
right: 0.5rem;
|
|
background: #0004;
|
|
border: 0.125rem dashed white;
|
|
border-radius: 0.25rem;
|
|
text-shadow: 0 1px 5px black;
|
|
text-align: center;
|
|
}
|
|
#splash > .drag-overlay::before {
|
|
content: "drop levels here";
|
|
}
|
|
#splash.--drag-hover > .drag-overlay {
|
|
display: flex;
|
|
}
|
|
|
|
#splash > header {
|
|
grid-area: header;
|
|
display: grid;
|
|
grid:
|
|
"image title" 2fr
|
|
"image tagline" 1fr
|
|
;
|
|
gap: 0 2em;
|
|
|
|
margin: auto;
|
|
}
|
|
#splash > header img {
|
|
grid-area: image;
|
|
align-self: center;
|
|
}
|
|
#splash > header h1 {
|
|
grid-area: title;
|
|
align-self: end;
|
|
font-size: 4em;
|
|
margin: 0;
|
|
}
|
|
#splash > header p {
|
|
grid-area: tagline;
|
|
align-self: start;
|
|
font-size: 1.5em;
|
|
margin: 0;
|
|
font-style: italic;
|
|
color: #909090;
|
|
}
|
|
#splash h2 {
|
|
border-bottom: 1px solid #404040;
|
|
color: #909090;
|
|
text-shadow: 0 1px #0004;
|
|
}
|
|
#splash * + h2 {
|
|
margin-top: 1rem;
|
|
}
|
|
#splash > section {
|
|
padding: 1em;
|
|
background: var(--panel-bg-color);
|
|
box-shadow: 0 0.25em 1em black;
|
|
}
|
|
#splash-links {
|
|
grid-area: links;
|
|
font-size: 1.5em;
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
justify-content: center;
|
|
gap: 0 2em;
|
|
}
|
|
#splash > #splash-intro {
|
|
grid-area: intro;
|
|
font-size: 20px;
|
|
}
|
|
#splash > #splash-stock-levels {
|
|
grid-area: stock;
|
|
}
|
|
#splash > #splash-upload-levels {
|
|
grid-area: upload;
|
|
}
|
|
#splash-upload-file,
|
|
#splash-upload-dir {
|
|
/* Hide the file upload control, which is ugly */
|
|
display: none;
|
|
}
|
|
#splash > #splash-your-levels {
|
|
grid-area: yours;
|
|
}
|
|
|
|
@media (max-width: 800px) {
|
|
#splash {
|
|
/* Grid layout doesn't fit, just stack everything */
|
|
display: flex;
|
|
flex-direction: column;
|
|
/* 10% padding is way way too much */
|
|
padding: 1em;
|
|
}
|
|
#splash::after {
|
|
/* This needs different handling in a flex container */
|
|
flex: 0 0 0.5em;
|
|
height: auto;
|
|
}
|
|
/* Shrink logo and title */
|
|
#splash > header {
|
|
grid-template-rows: auto auto;
|
|
column-gap: 0.5em;
|
|
}
|
|
#splash > header img {
|
|
width: 48px;
|
|
}
|
|
#splash > header h1 {
|
|
font-size: 2em;
|
|
}
|
|
#splash > header p {
|
|
font-size: 1em;
|
|
}
|
|
/* No need to boost the font size here */
|
|
#splash > #splash-links {
|
|
font-size: inherit;
|
|
column-gap: 1em;
|
|
}
|
|
}
|
|
|
|
.played-pack-list {
|
|
|
|
}
|
|
.played-pack-list > li {
|
|
margin-bottom: 1em;
|
|
}
|
|
.played-pack-list p {
|
|
color: #e8e8e8;
|
|
}
|
|
.played-pack-list .-progress {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5em;
|
|
text-align: right;
|
|
}
|
|
.played-pack-list > li.--unplayed .-progress {
|
|
display: none;
|
|
}
|
|
.played-pack-list .-progress > .-score,
|
|
.played-pack-list .-progress > .-time,
|
|
.played-pack-list .-progress > .-levels {
|
|
flex: 2;
|
|
}
|
|
.played-pack-list .-progress > button {
|
|
flex: 1;
|
|
}
|
|
button.level-pack-button {
|
|
display: grid;
|
|
grid:
|
|
"title score"
|
|
"desc desc"
|
|
/ 1fr min-content
|
|
;
|
|
|
|
padding: 0.5em;
|
|
text-align: left;
|
|
}
|
|
button.level-pack-button:enabled {
|
|
background: hsl(225, 30%, 25%);
|
|
box-shadow:
|
|
inset 0 0 0 1px hsl(225, 30%, 33%),
|
|
0 1px 1px hsl(225, 10%, 10%);
|
|
}
|
|
button.level-pack-button:enabled:hover {
|
|
background: hsl(225, 40%, 30%);
|
|
}
|
|
button.level-pack-button h3 {
|
|
grid-area: title;
|
|
}
|
|
button.level-pack-button .-score {
|
|
grid-area: score;
|
|
font-style: italic;
|
|
color: #c0c0c0;
|
|
text-align: right;
|
|
}
|
|
button.level-pack-button p {
|
|
grid-area: desc;
|
|
font-size: 0.833em;
|
|
font-style: italic;
|
|
color: #c0c0c0;
|
|
}
|
|
|
|
/* "Bulk test" button, only available in debug mode */
|
|
#main-test-pack {
|
|
display: none;
|
|
}
|
|
body.--debug #main-test-pack {
|
|
display: initial;
|
|
}
|
|
.packtest-dialog {
|
|
width: 75vw;
|
|
height: 75vh;
|
|
}
|
|
ol.packtest-summary {
|
|
display: flex;
|
|
align-items: stretch;
|
|
height: 1em;
|
|
border: 1px solid #606060;
|
|
}
|
|
ol.packtest-summary > li {
|
|
/* Give a meaty flex-basis; the dialog has a max-width so it won't blow out, and these will
|
|
* simply shrink if necessary */
|
|
flex: 1 1 1em;
|
|
background: white;
|
|
}
|
|
.packtest-row {
|
|
display: flex;
|
|
gap: 0.5em;
|
|
align-items: center;
|
|
margin: 0.5em 0;
|
|
}
|
|
.packtest-row > p {
|
|
flex: 9;
|
|
margin: 0;
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
.packtest-row > button {
|
|
flex: 1;
|
|
}
|
|
.packtest-results {
|
|
width: 100%;
|
|
table-layout: fixed;
|
|
border-collapse: collapse;
|
|
margin-bottom: 1em;
|
|
}
|
|
.packtest-results th {
|
|
font-weight: normal;
|
|
}
|
|
.packtest-results tbody {
|
|
cursor: pointer;
|
|
border-top: 1px solid #0004;
|
|
}
|
|
.packtest-results tbody:hover {
|
|
outline: 2px solid #000;
|
|
}
|
|
.packtest-results td {
|
|
padding: 0.25em;
|
|
}
|
|
.packtest-results .-level {
|
|
text-align: left;
|
|
}
|
|
.packtest-results .-result {
|
|
width: 8em;
|
|
text-align: center;
|
|
}
|
|
.packtest-results .-clock {
|
|
width: 6em;
|
|
text-align: right;
|
|
}
|
|
.packtest-results .-delta {
|
|
width: 8em;
|
|
text-align: right;
|
|
}
|
|
.packtest-results .-speed {
|
|
width: 8em;
|
|
text-align: right;
|
|
}
|
|
.packtest-results canvas {
|
|
display: block;
|
|
margin: 0.5em auto;
|
|
}
|
|
.packtest-colorcoded [data-status=no-replay] {
|
|
background: hsl(0, 0%, 25%);
|
|
}
|
|
.packtest-colorcoded [data-status=running] {
|
|
background: hsl(30, 100%, 75%);
|
|
}
|
|
.packtest-colorcoded [data-status=success] {
|
|
background: hsl(120, 60%, 75%);
|
|
}
|
|
.packtest-colorcoded [data-status=early] {
|
|
background: hsl(75, 60%, 75%);
|
|
}
|
|
.packtest-colorcoded [data-status=failure] {
|
|
background: hsl(0, 60%, 60%);
|
|
}
|
|
.packtest-colorcoded [data-status=short] {
|
|
background: hsl(330, 60%, 75%);
|
|
}
|
|
.packtest-colorcoded [data-status=error] {
|
|
background: black;
|
|
color: white;
|
|
}
|
|
.packtest-dialog .grade-A {
|
|
color: hsl(120, 60%, 45%);
|
|
font-weight: bold;
|
|
}
|
|
.packtest-dialog .grade-B {
|
|
color: hsl(210, 60%, 45%);
|
|
font-weight: bold;
|
|
}
|
|
.packtest-dialog .grade-C {
|
|
color: hsl(270, 60%, 45%);
|
|
font-weight: bold;
|
|
}
|
|
.packtest-dialog .grade-D {
|
|
color: hsl(36, 60%, 60%);
|
|
font-weight: bold;
|
|
}
|
|
.packtest-dialog .grade-F {
|
|
color: hsl(0, 60%, 60%);
|
|
font-weight: bold;
|
|
}
|
|
|
|
|
|
/**************************************************************************************************/
|
|
/* Player */
|
|
|
|
#player {
|
|
flex: 1;
|
|
position: relative;
|
|
display: flex;
|
|
|
|
image-rendering: crisp-edges;
|
|
image-rendering: pixelated;
|
|
|
|
--tile-width: 32px;
|
|
--tile-height: 32px;
|
|
--scale: 1;
|
|
}
|
|
#player-main {
|
|
/* This element basically just exists so that #player can have relative positioning and the
|
|
* debug panel can use that to sit against the right edge; absolute positioning excludes
|
|
* margins, so if it were positioned as a child of THIS element, it would be stuffed into the
|
|
* game area (oops!) */
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: stretch;
|
|
gap: 0.5em;
|
|
margin: auto; /* center in both directions baby */
|
|
}
|
|
#player-game-area {
|
|
isolation: isolate;
|
|
align-self: center; /* don't stretch if the buttons or music blow out somehow */
|
|
display: grid;
|
|
align-items: center;
|
|
grid:
|
|
"level chips" min-content
|
|
"level time" min-content
|
|
"level bonus" min-content
|
|
"level hint" 1fr
|
|
"level inventory" min-content
|
|
/* Need explicit min-content to force the hint to wrap */
|
|
/ min-content min-content
|
|
;
|
|
column-gap: 2em;
|
|
row-gap: 0.5em;
|
|
|
|
padding: 1em;
|
|
background: hsl(225, 10%, 20%);
|
|
box-shadow: 0 0.25em 1em black;
|
|
}
|
|
#player > .controls {
|
|
order: -1;
|
|
}
|
|
|
|
.level {
|
|
grid-area: level;
|
|
|
|
position: relative;
|
|
border: 2px solid black;
|
|
}
|
|
.level canvas {
|
|
display: block;
|
|
width: calc(var(--viewport-width) * var(--tile-width) * var(--scale));
|
|
height: calc(var(--viewport-height) * var(--tile-height) * var(--scale));
|
|
--viewport-width: 9;
|
|
--viewport-height: 9;
|
|
}
|
|
#player .overlay-message {
|
|
grid-area: level;
|
|
place-self: stretch;
|
|
|
|
position: relative;
|
|
display: grid;
|
|
grid-template-rows: 2fr 6fr 2fr 1fr;
|
|
justify-content: center;
|
|
align-items: center;
|
|
/* Prevent blowout; force using the canvas's height */
|
|
height: 0;
|
|
min-height: 100%;
|
|
box-sizing: border-box;
|
|
/* Copy the canvas's border width too */
|
|
border: 2px solid transparent;
|
|
|
|
z-index: 2;
|
|
font-size: calc(0.5 * var(--tile-width) * var(--scale));
|
|
padding: 2% 5%;
|
|
background: #0009;
|
|
color: white;
|
|
text-align: center;
|
|
text-shadow: 0 2px 1px black;
|
|
}
|
|
/* Allow clicking through the overlay in debug mode */
|
|
body.--debug .overlay-message {
|
|
pointer-events: none;
|
|
}
|
|
#player .overlay-message p {
|
|
margin: 0;
|
|
}
|
|
#player .overlay-message .-top {
|
|
font-size: 1.5em;
|
|
}
|
|
#player .overlay-message .-middle {
|
|
}
|
|
#player .overlay-message .-bottom {
|
|
}
|
|
#player .overlay-message .-keyhint {
|
|
align-self: end;
|
|
font-size: 0.5em;
|
|
color: #c0c0c0;
|
|
}
|
|
#player .overlay-message[data-reason=""] {
|
|
display: none;
|
|
}
|
|
#player .overlay-message[data-reason=failure] {
|
|
box-shadow: inset 0 0 calc(4 * var(--tile-width)) var(--tile-width) black;
|
|
}
|
|
#player .overlay-message[data-reason=success] {
|
|
background: hsla(225, 50%, 25%, 0.5);
|
|
box-shadow: inset 0 0 calc(4 * var(--tile-width)) hsl(225, 50%, 25%);
|
|
}
|
|
#player .overlay-message[data-reason=ended] {
|
|
/* Shove the middle + bottom parts down so they don't overlay the busiest part of the ending image */
|
|
grid-template-rows: 8fr 4fr 2fr 0;
|
|
overflow: hidden;
|
|
color: black;
|
|
background: url(ending.png) no-repeat center center / cover;
|
|
box-shadow: inset 0 0 calc(4 * var(--tile-width)) hsl(225, 50%, 25%);
|
|
text-shadow: 0 0 2px white, 0 2px 2px white;
|
|
}
|
|
#player .overlay-message[data-reason=ended] .-top,
|
|
#player .overlay-message[data-reason=ended] .-bottom {
|
|
font-size: 1.5em;
|
|
}
|
|
@supports (mask-image: none) or (-webkit-mask-image: none) {
|
|
/* Do this complicated rotating sunburst thing only if masks work */
|
|
#player .overlay-message[data-reason=ended]::before {
|
|
content: '';
|
|
position: absolute;
|
|
z-index: -1;
|
|
top: -50%;
|
|
bottom: -50%;
|
|
left: -50%;
|
|
right: -50%;
|
|
background: repeating-conic-gradient(at center, #fbf8ad 0turn 0.025turn, #f6d87e 0.025turn 0.075turn, #fbf8ad 0.075turn 0.1turn);
|
|
animation: ending-spinner 10s linear infinite;
|
|
-webkit-mask-image: radial-gradient(at center, #0000 0%, #0006 50%);
|
|
mask-image: radial-gradient(at center, #0000 0%, #0006 50%);
|
|
}
|
|
}
|
|
@keyframes ending-spinner {
|
|
0% {
|
|
transform: rotate(0turn);
|
|
}
|
|
100% {
|
|
transform: rotate(1turn);
|
|
}
|
|
}
|
|
dl.score-chart {
|
|
display: grid;
|
|
grid-auto-columns: 1fr 1fr;
|
|
margin: auto;
|
|
font-weight: normal;
|
|
}
|
|
dl.score-chart dt {
|
|
grid-column: 1;
|
|
text-align: left;
|
|
}
|
|
dl.score-chart dd {
|
|
grid-column: 2;
|
|
margin: 0;
|
|
text-align: right;
|
|
}
|
|
dl.score-chart .-sum {
|
|
margin-bottom: 0.5em;
|
|
border-top: 1px solid white;
|
|
color: hsl(40, 75%, 80%);
|
|
}
|
|
|
|
.chips {
|
|
grid-area: chips;
|
|
}
|
|
.time {
|
|
grid-area: time;
|
|
}
|
|
.bonus {
|
|
grid-area: bonus;
|
|
}
|
|
.chips,
|
|
.time,
|
|
.bonus {
|
|
font-size: calc(var(--tile-height) * var(--scale) / 3);
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
.chips h3,
|
|
.time h3,
|
|
.bonus h3 {
|
|
flex: 1;
|
|
font-size: 1.25em;
|
|
line-height: 1;
|
|
color: hsl(225, 20%, 90%);
|
|
}
|
|
.chips output,
|
|
.time output,
|
|
.bonus output {
|
|
flex: 1;
|
|
font-size: 2em;
|
|
min-width: 2em;
|
|
min-height: 1em;
|
|
line-height: 1;
|
|
text-align: right;
|
|
font-family: monospace;
|
|
color: hsl(225, 20%, 60%);
|
|
}
|
|
.chips output.--done {
|
|
color: hsl(225, 10%, 30%);
|
|
}
|
|
.time output.--warning {
|
|
color: hsl(345, 60%, 60%);
|
|
}
|
|
.time output.--danger {
|
|
color: hsl(330, 60%, 60%);
|
|
/* TODO this can get out of sync and keeps going at 0, but is a neat idea */
|
|
/* animation: time-pulse 1s linear infinite; */
|
|
}
|
|
@keyframes time-pulse {
|
|
0% {
|
|
transform: scale(1.1);
|
|
}
|
|
100% {
|
|
transform: scale(1);
|
|
}
|
|
}
|
|
.time output.--frozen {
|
|
color: hsl(225, 10%, 30%);
|
|
}
|
|
#player .bonus {
|
|
visibility: hidden;
|
|
display: none;
|
|
}
|
|
#player.--bonus-visible .bonus {
|
|
visibility: initial;
|
|
display: flex;
|
|
}
|
|
|
|
/* This has a wrapper because scrollables don't work too well as the direct child of a grid or flex
|
|
* parent; they really want to expand to their natural size, and I do not want that */
|
|
#player-game-area > .player-hint-wrapper {
|
|
grid-area: hint;
|
|
align-self: stretch;
|
|
|
|
display: none;
|
|
font-size: calc(var(--tile-height) * var(--scale) / 3);
|
|
padding: 0.25em 0.5em;
|
|
font-family: serif;
|
|
font-style: italic;
|
|
color: hsl(45, 100%, 60%);
|
|
background: #080808;
|
|
border: 1px inset #202020;
|
|
}
|
|
#player-game-area > .player-hint-wrapper > .player-hint {
|
|
overflow: auto;
|
|
/* Set our inherent height or whatever to zero, but then force us to expand to whatever size our
|
|
* parent happens to be. Magic! */
|
|
height: 0;
|
|
min-height: 100%;
|
|
}
|
|
#player-game-area > .player-hint-wrapper.--visible {
|
|
display: initial;
|
|
}
|
|
|
|
#player .inventory {
|
|
grid-area: inventory;
|
|
justify-self: center;
|
|
display: grid;
|
|
grid: auto-flow calc(var(--tile-height) * var(--scale)) / repeat(4, calc(var(--tile-width) * var(--scale)));
|
|
|
|
background-size: calc(var(--tile-width) * var(--scale)) calc(var(--tile-height) * var(--scale));
|
|
width: calc(4 * var(--tile-width) * var(--scale));
|
|
height: calc(2 * var(--tile-height) * var(--scale));
|
|
}
|
|
#player .inventory img {
|
|
width: calc(var(--tile-width) * var(--scale));
|
|
}
|
|
#player .inventory .--hidden {
|
|
visibility: hidden;
|
|
pointer-events: none;
|
|
}
|
|
#player .inventory > span {
|
|
position: relative;
|
|
}
|
|
#player .inventory .-count {
|
|
font-size: calc(0.25 * var(--tile-height) * var(--scale));
|
|
position: absolute;
|
|
top: 0;
|
|
right: 0;
|
|
padding: 0.25em 0.5em;
|
|
margin: 0.25em; /* 2px, for a 32px tileset */
|
|
line-height: 1;
|
|
border-radius: 0.25em;
|
|
background: #0009;
|
|
color: white;
|
|
}
|
|
#player .actions {
|
|
display: flex;
|
|
gap: 0.5em;
|
|
}
|
|
#player .actions button {
|
|
flex: 1;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
#player-music {
|
|
grid-area: music;
|
|
margin: 0 1em;
|
|
text-transform: lowercase;
|
|
color: #909090;
|
|
}
|
|
|
|
#player .controls {
|
|
grid-area: controls;
|
|
display: flex;
|
|
gap: 0.25em;
|
|
justify-content: space-between;
|
|
}
|
|
#player button {
|
|
position: relative;
|
|
}
|
|
#player button .keyhint {
|
|
position: absolute;
|
|
left: 0;
|
|
right: 0;
|
|
top: -2em;
|
|
margin: auto;
|
|
color: #404040;
|
|
}
|
|
#player button:disabled .keyhint {
|
|
display: none;
|
|
}
|
|
|
|
.play-controls {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.25em;
|
|
}
|
|
.play-controls {
|
|
align-self: start;
|
|
}
|
|
|
|
/* Debug stuff */
|
|
body.--debug #player-debug {
|
|
display: flex;
|
|
}
|
|
#player-debug {
|
|
flex: none;
|
|
align-self: center;
|
|
display: none;
|
|
/* FIXME this blows out the height instead of scrolling and i cannot figure out how to make it
|
|
* stop, so here is an arbitrary max height on it which i extremely hate */
|
|
overflow: auto;
|
|
max-height: 75vh;
|
|
flex-direction: column;
|
|
justify-content: start;
|
|
gap: 0.25em;
|
|
padding: 0.5em;
|
|
background-image: repeating-linear-gradient(135deg,
|
|
hsl(0, 0%, 4%) 0px,
|
|
hsl(0, 0%, 4%) 16px,
|
|
hsl(30, 25%, 8%) 16px,
|
|
hsl(30, 25%, 8%) 32px);
|
|
border: 0.25em solid hsl(30, 75%, 50%);
|
|
border-right-width: 0;
|
|
box-shadow: inset 0 0 0.25em 0.25em #0004;
|
|
}
|
|
#player-debug > h3 {
|
|
margin: -0.25em -0.25em 0.25em;
|
|
padding: 0 0.5em;
|
|
background: hsl(30, 60%, 20%);
|
|
color: black;
|
|
}
|
|
#player-debug > * + h3 {
|
|
margin-top: 0.5em;
|
|
}
|
|
#player-debug hr {
|
|
border: none;
|
|
margin: 0.25em 10%;
|
|
border-bottom: 1px solid #404040;
|
|
}
|
|
#player-debug table.-time-controls {
|
|
border-collapse: collapse;
|
|
width: 100%;
|
|
margin-bottom: 0.5em;
|
|
}
|
|
#player-debug table.-time-controls button {
|
|
width: 100%;
|
|
text-align: inherit;
|
|
}
|
|
#player-debug table.-time-controls td:nth-child(1) {
|
|
/* go backwards button */
|
|
text-align: left;
|
|
}
|
|
#player-debug table.-time-controls td:nth-child(2) {
|
|
/* value */
|
|
width: 4em;
|
|
text-align: right;
|
|
}
|
|
#player-debug table.-time-controls td:nth-child(3) {
|
|
/* label */
|
|
}
|
|
#player-debug table.-time-controls td:nth-child(4) {
|
|
/* go forward button */
|
|
text-align: right;
|
|
}
|
|
#player-debug .-inventory {
|
|
display: grid;
|
|
margin: 0 auto;
|
|
grid: auto-fill var(--tile-height) / repeat(8, var(--tile-width));
|
|
gap: 2px;
|
|
}
|
|
#player-debug > .-inventory > button {
|
|
padding: 0;
|
|
}
|
|
#player-debug > .-inventory > button > img {
|
|
display: block;
|
|
}
|
|
#player-debug > .-inventory > button.-wide {
|
|
grid-column: span 8;
|
|
padding: 0.25em;
|
|
}
|
|
#player-debug .-buttons {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
gap: 0.25em;
|
|
}
|
|
#player-debug .-buttons button {
|
|
flex: auto;
|
|
}
|
|
|
|
#player-debug .-replay-columns {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
gap: 0.5em;
|
|
}
|
|
#player-debug .-replay-columns .-buttons {
|
|
flex-direction: column;
|
|
}
|
|
#player-debug-input {
|
|
flex: none;
|
|
display: grid;
|
|
grid:
|
|
"drop up cycle" 1em
|
|
"left . right" 1em
|
|
". down swap" 1em
|
|
/ 1em 1em 1em
|
|
;
|
|
gap: 0.5em;
|
|
}
|
|
#player-debug-input > svg {
|
|
fill: #404040;
|
|
}
|
|
#player-debug-input > svg.--held {
|
|
fill: white;
|
|
}
|
|
#player-debug > .-replay-available {
|
|
display: flex;
|
|
gap: 0.5em;
|
|
}
|
|
#player-debug > .-replay-available > h4 {
|
|
flex: 1 0 0;
|
|
}
|
|
#player-debug > .-replay-available > p {
|
|
flex: 2 0 0;
|
|
margin: 0;
|
|
}
|
|
#player-debug .-replay-status {
|
|
flex: 1;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
height: 4em;
|
|
}
|
|
#player-debug .-replay-status > .-none {
|
|
}
|
|
#player.--replay-playback #player-debug .-replay-status > .-none,
|
|
#player.--replay-recording #player-debug .-replay-status > .-none {
|
|
display: none;
|
|
}
|
|
#player-debug .-replay-status > .-playback {
|
|
flex: 1;
|
|
display: none;
|
|
grid:
|
|
"duration percent" 1em
|
|
"progress progress" 0.5em
|
|
"button button" 2em
|
|
/ 3fr 1fr
|
|
;
|
|
gap: 0.25em;
|
|
align-items: center;
|
|
}
|
|
#player.--replay-playback #player-debug .-replay-status > .-playback {
|
|
display: grid;
|
|
}
|
|
#player-debug .-replay-status > .-playback > progress {
|
|
grid-area: progress;
|
|
width: 100%;
|
|
height: 100%;
|
|
}
|
|
#player-debug .-replay-status > .-playback > output {
|
|
grid-area: percent;
|
|
min-width: 0;
|
|
text-align: right;
|
|
}
|
|
#player-debug .-replay-status > .-playback > span {
|
|
grid-area: duration;
|
|
min-width: 0;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
#player-debug .-replay-status > .-playback > button {
|
|
grid-area: button;
|
|
}
|
|
#player-debug .-replay-status > .-recording {
|
|
display: none;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
#player.--replay-recording #player-debug .-replay-status > .-recording {
|
|
display: flex;
|
|
}
|
|
|
|
|
|
@media (max-width: 800px) {
|
|
#player {
|
|
/* sentinel for js */
|
|
--is-portrait: 1;
|
|
/* The play area isn't necessarily the biggest thing any more, and it's ugly when stretched */
|
|
align-items: center;
|
|
}
|
|
#player .controls {
|
|
flex-direction: column;
|
|
}
|
|
#player-game-area {
|
|
/* Rearrange the grid to be vertical */
|
|
grid:
|
|
"level level"
|
|
"chips inventory" calc((var(--tile-height) * var(--scale) * 2 - 1em) / 3)
|
|
"time inventory" calc((var(--tile-height) * var(--scale) * 2 - 1em) / 3)
|
|
"bonus inventory" calc((var(--tile-height) * var(--scale) * 2 - 1em) / 3)
|
|
/* FIXME ideally the first column would be 1fr so the hearts/time have space, but that
|
|
* allows hints to grow to the entire width of the window, which incredibly sucks. i
|
|
* don't know how to get around this except by giving the grid a fixed width, which i
|
|
* guess wouldn't be that hard */
|
|
/ min-content min-content
|
|
;
|
|
row-gap: 0.5em;
|
|
column-gap: 1em;
|
|
|
|
padding: 0.5em;
|
|
}
|
|
#player .inventory {
|
|
/* stick me in the center right */
|
|
place-self: center end;
|
|
}
|
|
#player-game-area > .player-hint-wrapper {
|
|
/* Overlay hints on the inventory area */
|
|
grid-row: chips / bonus;
|
|
grid-column: level;
|
|
z-index: 1;
|
|
font-size: calc(var(--tile-height) * var(--scale) / 2.5);
|
|
}
|
|
#player .keyhint {
|
|
/* Hide key hints, they take up surprisingly a lot of space */
|
|
display: none;
|
|
}
|
|
#player-music {
|
|
/* Stack the title/artist on the volume, since they don't fit well side by side */
|
|
font-size: 0.875em;
|
|
}
|
|
}
|
|
|
|
|
|
/**************************************************************************************************/
|
|
/* Editor */
|
|
|
|
#editor {
|
|
flex: 1 1 auto;
|
|
display: grid;
|
|
grid:
|
|
"controls controls" min-content
|
|
"palette level" 1fr
|
|
/ min-content 1fr
|
|
;
|
|
gap: 0.5em;
|
|
|
|
min-height: 0;
|
|
margin: auto 1em;
|
|
}
|
|
|
|
#editor .editor-canvas {
|
|
grid-area: level;
|
|
overflow: auto;
|
|
/* Flex layout to center the canvas and overlay together */
|
|
display: flex;
|
|
/* This isn't supported in Chrome (still!!), so use auto margins on the child instead
|
|
align-items: safe center;
|
|
justify-content: safe center;
|
|
*/
|
|
background: #202020;
|
|
border: 0.125em solid black;
|
|
}
|
|
#editor .editor-canvas .-container {
|
|
position: relative;
|
|
margin: auto;
|
|
/* Give the canvas/overlay a bit of a margin; it has to be a border because, due to some quirk
|
|
* of overflowing flexboxes I guess, padding and margins won't extend the scroll area on the
|
|
* right and bottom */
|
|
/* TODO padding should be half a cell? */
|
|
border: 2em solid transparent;
|
|
}
|
|
#editor .editor-canvas canvas {
|
|
display: block;
|
|
width: calc(var(--viewport-width) * var(--tile-width) * var(--scale));
|
|
--viewport-width: 9;
|
|
--viewport-height: 9;
|
|
}
|
|
/* SVG overlays */
|
|
#editor svg.level-editor-overlay {
|
|
position: absolute;
|
|
top: 0;
|
|
bottom: 0;
|
|
left: 0;
|
|
right: 0;
|
|
/* allow clicks to go through us! */
|
|
pointer-events: none;
|
|
|
|
/* default svg properties */
|
|
stroke-width: 0.0625;
|
|
fill: none;
|
|
}
|
|
#editor .level-editor-overlay .overlay-transient {
|
|
display: none;
|
|
}
|
|
#editor .level-editor-overlay .overlay-transient.--visible {
|
|
display: initial;
|
|
}
|
|
#editor .level-editor-overlay rect.overlay-cursor {
|
|
x-stroke: hsla(225, 100%, 60%, 0.5);
|
|
fill: hsla(225, 100%, 75%, 0.25);
|
|
}
|
|
#editor .level-editor-overlay rect.overlay-pending-selection {
|
|
stroke: hsla(225, 100%, 60%, 0.5);
|
|
fill: hsla(225, 100%, 75%, 0.25);
|
|
}
|
|
#editor .level-editor-overlay rect.overlay-selection {
|
|
stroke: #000c;
|
|
fill: hsla(225, 0%, 75%, 0.25);
|
|
stroke-dasharray: 0.125, 0.125;
|
|
animation: marching-ants 1s linear infinite;
|
|
pointer-events: auto;
|
|
cursor: move;
|
|
}
|
|
@keyframes marching-ants {
|
|
0% {
|
|
stroke-dashoffset: 0.25;
|
|
}
|
|
100% {
|
|
stroke-dashoffset: 0;
|
|
}
|
|
}
|
|
#editor .level-editor-overlay rect.overlay-cxn {
|
|
stroke: red;
|
|
}
|
|
#editor .level-editor-overlay line.overlay-cxn {
|
|
stroke: red;
|
|
}
|
|
#editor .level-editor-overlay rect.overlay-camera {
|
|
stroke: #808080;
|
|
fill: #80808040;
|
|
pointer-events: auto;
|
|
}
|
|
#editor .level-editor-overlay text {
|
|
/* Each cell is one "pixel", so text needs to be real small */
|
|
font-size: 1px;
|
|
}
|
|
#editor .level-editor-overlay text.overlay-edit-tip {
|
|
stroke: none;
|
|
fill: black;
|
|
}
|
|
|
|
.editor-big-tooltip {
|
|
/* shared between toolbar and palette tooltips */
|
|
opacity: 0;
|
|
visibility: hidden;
|
|
z-index: 1;
|
|
position: absolute;
|
|
padding: 0.33em 0.75em;
|
|
pointer-events: none;
|
|
|
|
transition-property: margin, opacity, visibility;
|
|
transition-timing-function: ease-out;
|
|
transition-duration: 0.125s, 0.125s, 0s;
|
|
transition-delay: 0s, 0s, 0.125s;
|
|
|
|
border: 1px solid black;
|
|
white-space: pre-wrap;
|
|
line-height: 1.5;
|
|
text-transform: none;
|
|
text-align: left;
|
|
color: #d8d8d8;
|
|
background: hsl(225, 10%, 20%);
|
|
box-shadow: 0 1px 2px 1px #0004;
|
|
}
|
|
.editor-big-tooltip h3 {
|
|
font-size: 1.25em;
|
|
margin-bottom: 0.25rem;
|
|
border-bottom: 1px solid currentColor;
|
|
color: white;
|
|
}
|
|
#editor .controls {
|
|
/* TODO with the hint area gone i don't think this needs to be a grid? could just flex */
|
|
grid-area: controls;
|
|
display: grid;
|
|
grid:
|
|
"tile toolbar layer direction . menu" auto
|
|
/ auto auto auto auto 1fr auto
|
|
;
|
|
align-items: center;
|
|
column-gap: 1em;
|
|
}
|
|
#editor .controls .editor-tile-controls {
|
|
grid-area: tile;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.25em;
|
|
}
|
|
#editor .controls #editor-tile canvas {
|
|
display: block;
|
|
}
|
|
#editor .controls #editor-toolbar {
|
|
grid-area: toolbar;
|
|
}
|
|
#editor-toolbar .-help {
|
|
width: max-content;
|
|
margin-top: -0.25em;
|
|
margin-left: -0.5em;
|
|
}
|
|
#editor-toolbar button:hover .-help {
|
|
opacity: 1;
|
|
z-index: 2; /* show above any that are in mid-fade */
|
|
visibility: visible;
|
|
margin-top: 0.25em;
|
|
transition-delay: 0.5s;
|
|
transition-timing-function: ease-in;
|
|
}
|
|
#editor .controls .-buttons {
|
|
grid-area: menu;
|
|
}
|
|
.icon-button-set {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
}
|
|
.icon-button-set button {
|
|
width: auto;
|
|
height: auto;
|
|
padding: 0;
|
|
margin: 0;
|
|
line-height: 1;
|
|
background: url(icons/tool-bg-unselected.png) no-repeat;
|
|
border: none;
|
|
border-radius: 0;
|
|
box-shadow: none;
|
|
}
|
|
.icon-button-set button.-selected {
|
|
background-image: url(icons/tool-bg-selected.png);
|
|
}
|
|
.icon-button-set button img {
|
|
display: block;
|
|
}
|
|
|
|
#editor .palette {
|
|
isolation: isolate;
|
|
grid-area: palette;
|
|
width: calc(32px * 8 + 4px * 9);
|
|
padding-right: 1em; /* make room for scrollbar so we don't get a horizontal one */
|
|
/* TODO when there IS a scrollbar, the h2s are slightly narrower. think this is an
|
|
* unexpected consequence of using min-content, which i guess does not take the
|
|
* possibility of a scrollbar into account */
|
|
overflow-y: auto;
|
|
}
|
|
#editor .palette h2 {
|
|
font-size: 1em;
|
|
margin-top: 1em;
|
|
border-bottom: 1px solid currentColor;
|
|
color: #909090;
|
|
}
|
|
#editor .palette h2:first-child {
|
|
margin-top: 0;
|
|
}
|
|
#editor .palette section {
|
|
display: grid;
|
|
margin: 0.33em 4px; /* matches gap */
|
|
grid: auto-flow 32px / repeat(8, 32px);
|
|
gap: 4px;
|
|
}
|
|
.palette-entry {
|
|
}
|
|
.palette-entry:hover {
|
|
box-shadow: 0 0 0 1px black, 0 0 0 3px hsl(225, 100%, 75%);
|
|
}
|
|
.palette-entry.--selected {
|
|
z-index: 1;
|
|
box-shadow: 0 0 0 1px black, 0 0 0 3px white;
|
|
}
|
|
.editor-palette-tooltip {
|
|
width: 20em;
|
|
|
|
/* Don't immediately hide me when mousing between entries */
|
|
/* FIXME if it's in mid-fade and you mouse over an entry again, it stays frozen in mid-fade
|
|
* for 0.5s :( */
|
|
transition-delay: 0.5s, 0.5s, 0.625s;
|
|
}
|
|
.editor-palette-tooltip.--visible {
|
|
opacity: 1;
|
|
z-index: 2; /* show above any that are in mid-fade */
|
|
visibility: visible;
|
|
margin-left: 1em;
|
|
transition-delay: 0.5s;
|
|
transition-timing-function: ease-in;
|
|
}
|
|
|
|
.editor-level-browser {
|
|
display: grid;
|
|
grid: auto-flow auto / repeat(auto-fill, minmax(13em, 1fr)); /* 12em preview wdith + padding */
|
|
gap: 0.5em;
|
|
width: 70vw;
|
|
/* seems to go into the parent's right padding fsr, i guess because the scrollbar is there */
|
|
margin-right: 1em;
|
|
list-style: none;
|
|
}
|
|
.editor-level-browser li {
|
|
display: grid;
|
|
grid:
|
|
"preview preview"
|
|
"number title"
|
|
/ min-content 1fr
|
|
;
|
|
gap: 0.25em;
|
|
padding: 0.5em;
|
|
}
|
|
.editor-level-browser li:hover {
|
|
background: hsl(225, 60%, 85%);
|
|
}
|
|
.editor-level-browser li > .-preview {
|
|
grid-area: preview;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
width: 12em;
|
|
height: 12em;
|
|
margin: auto;
|
|
}
|
|
.editor-level-browser li > .-preview:empty::before {
|
|
content: '···';
|
|
display: block;
|
|
font-size: 5em;
|
|
color: #c0c0c0;
|
|
}
|
|
.editor-level-browser li > .-preview canvas {
|
|
display: block;
|
|
max-width: 100%;
|
|
max-height: 100%;
|
|
}
|
|
.editor-level-browser li > .-number {
|
|
grid-area: number;
|
|
font-size: 2em;
|
|
}
|
|
.editor-level-browser li > .-title {
|
|
grid-area: title;
|
|
align-self: center;
|
|
}
|
|
|
|
/* Mini editors for specific tiles with complex properties */
|
|
/* FIXME should this stuff be on an overlay container class? */
|
|
form.editor-popup-tile-editor {
|
|
position: relative;
|
|
padding: 0.5em;
|
|
color: black;
|
|
background: white;
|
|
border: 1px solid black;
|
|
box-shadow: 0 2px 4px #0004;
|
|
|
|
margin-top: 1em;
|
|
|
|
--chevron-offset: 0px;
|
|
}
|
|
form.editor-popup-tile-editor.--above {
|
|
margin-top: -1em;
|
|
}
|
|
form.editor-popup-tile-editor h3 {
|
|
border-bottom: 1px dotted #606060;
|
|
}
|
|
form.editor-popup-tile-editor * + h3 {
|
|
margin-top: 0.25em;
|
|
}
|
|
/* Use ::before for a chevron pointing at the tile in question */
|
|
form.editor-popup-tile-editor::before {
|
|
content: '';
|
|
display: block;
|
|
position: absolute;
|
|
border: 1em solid transparent;
|
|
left: var(--chevron-offset);
|
|
margin-left: -1em;
|
|
|
|
top: -1em;
|
|
border-top: none;
|
|
border-bottom-color: white;
|
|
filter: drop-shadow(0 -1px 0 black);
|
|
}
|
|
form.editor-popup-tile-editor.--above::before {
|
|
top: auto;
|
|
bottom: -1em;
|
|
border: 1em solid transparent;
|
|
border-bottom: none;
|
|
border-top-color: white;
|
|
filter: drop-shadow(0 1px 0 black);
|
|
}
|
|
/* Letter floor tiles, which let you pick the character to use; show them as a grid. Note the
|
|
* characters are preceded by radio buttons, which we hide for simplicity */
|
|
ol.editor-letter-tile-picker {
|
|
display: grid;
|
|
grid: auto-flow 1.5em / repeat(17, 1.5em);
|
|
text-align: center;
|
|
font-family: monospace;
|
|
}
|
|
ol.editor-letter-tile-picker label,
|
|
ol.editor-letter-tile-picker .-glyph {
|
|
display: block;
|
|
height: 100%;
|
|
}
|
|
ol.editor-letter-tile-picker input[type=radio] {
|
|
display: none;
|
|
}
|
|
ol.editor-letter-tile-picker input[type=radio]:checked + .-glyph {
|
|
background: hsl(225, 75%, 90%);
|
|
outline: 2px solid hsl(225, 75%, 80%);
|
|
}
|
|
/* Hint tiles accept prose */
|
|
textarea.editor-hint-tile-text {
|
|
font-size: 1.5em;
|
|
width: 20vw;
|
|
height: 20vh;
|
|
min-width: 15rem;
|
|
min-height: 5rem;
|
|
border: none;
|
|
font-family: serif;
|
|
}
|
|
/* Class for a list that uses hidden inputs with svg icons, shared by directional blocks and
|
|
* railroad tracks */
|
|
.editor-tile-editor-svg-parts input {
|
|
display: none;
|
|
}
|
|
.editor-tile-editor-svg-parts svg {
|
|
display: block;
|
|
width: 3em;
|
|
fill: none;
|
|
stroke: #c0c0c0;
|
|
stroke-width: 2;
|
|
}
|
|
.editor-tile-editor-svg-parts input:checked + svg {
|
|
stroke: hsl(225, 90%, 50%);
|
|
}
|
|
/* Directional blocks have arrows */
|
|
ol.editor-directional-block-tile-arrows {
|
|
display: grid;
|
|
grid: auto-flow 3em / repeat(3, 3em);
|
|
}
|
|
/* Railroad tracks are... complicated */
|
|
ul.editor-railroad-tile-tracks {
|
|
display: grid;
|
|
grid: auto-flow 3em / repeat(3, 3em);
|
|
gap: 0.25em;
|
|
}
|
|
ul.editor-railroad-tile-tracks.--switch input:checked + svg {
|
|
stroke: hsl(15, 90%, 50%);
|
|
}
|