You know. Lexy colors. Seems to make sense. Also fixed several places I just hated the color scheme, such as the hover color in popup menus and the title bar in dialogs. Woohoo.
2602 lines
62 KiB
CSS
2602 lines
62 KiB
CSS
html {
|
|
font-size: 16px;
|
|
height: 100%;
|
|
}
|
|
body {
|
|
height: 100%;
|
|
margin: 0;
|
|
box-sizing: border-box;
|
|
|
|
display: flex;
|
|
flex-direction: column;
|
|
|
|
font-family: Ubuntu, Source Sans Pro, DejaVu Sans, sans-serif;
|
|
line-height: 1.33;
|
|
background: hsl(var(--main-hue), 5%, 5%);
|
|
background-image: url(background.svg);
|
|
background-size: 12em;
|
|
color: #ececec;
|
|
|
|
--main-hue: 350;
|
|
--hover-hue: 5;
|
|
--selected-hue: 10;
|
|
--panel-bg-color: hsl(var(--main-hue), 10%, 10%);
|
|
--button-bg-color: hsl(var(--main-hue), 40%, 20%);
|
|
--button-bg-gradient: linear-gradient(to bottom, var(--button-bg-shadow-color), transparent 75%);
|
|
--button-bg-shadow-color: #fff1;
|
|
--button-bg-hover-color: hsl(var(--hover-hue), 50%, 35%);
|
|
--generic-bg-hover-on-white: hsl(var(--hover-hue), 60%, 90%);
|
|
--generic-bg-selected-on-white: hsl(var(--selected-hue), 75%, 90%);
|
|
--generic-border-selected-on-white: hsl(var(--selected-hue), 60%, 75%);
|
|
}
|
|
|
|
/* Generic element styling */
|
|
main[hidden] {
|
|
display: none !important;
|
|
}
|
|
input[type=radio],
|
|
input[type=checkbox],
|
|
input[type=range] {
|
|
font-size: inherit;
|
|
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-color: var(--button-bg-color);
|
|
background-image: var(--button-bg-gradient);
|
|
border: 1px solid hsl(var(--main-hue), 10%, 7.5%);
|
|
box-shadow:
|
|
inset 0 0 1px 1px #fff2,
|
|
0 1px 1px hsl(var(--main-hue), 10%, 7.5%);
|
|
border-radius: 0.25em;
|
|
text-shadow: 0 1px 0 #0004;
|
|
text-transform: lowercase;
|
|
cursor: pointer;
|
|
}
|
|
button:hover,
|
|
.radio-faux-button-set > label:hover > input + span {
|
|
background-color: 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:enabled.button-bright {
|
|
background-color: hsl(var(--main-hue), 60%, 30%);
|
|
}
|
|
button:enabled.button-bright:hover {
|
|
background-color: hsl(var(--hover-hue), 65%, 40%);
|
|
}
|
|
button:disabled {
|
|
color: #606060;
|
|
background-color: #202020;
|
|
cursor: auto;
|
|
}
|
|
button.button-big {
|
|
display: block;
|
|
width: 100%;
|
|
margin: 0.5em 0;
|
|
padding: 1em;
|
|
}
|
|
button.--button-glow-ok {
|
|
background: hsl(var(--main-hue), 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;
|
|
}
|
|
select {
|
|
font-size: inherit;
|
|
}
|
|
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(var(--main-hue), 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;
|
|
}
|
|
button.--pressed,
|
|
.radio-faux-button-set > label > input:checked + span {
|
|
background: hsl(var(--main-hue), 80%, 50%);
|
|
box-shadow:
|
|
inset 0 1px 3px 1px hsl(var(--main-hue), 50%, 15%),
|
|
inset 0 0.25em 1em 0.5em hsl(var(--main-hue), 50%, 30%),
|
|
0 1px 1px hsl(var(--main-hue), 10%, 10%)
|
|
}
|
|
|
|
.button-row {
|
|
display: grid;
|
|
/* Put the buttons in a row most of the time, but change to a column when out of space */
|
|
grid: auto-flow auto / repeat(auto-fit, minmax(10em, 1fr));
|
|
gap: 0.5em;
|
|
align-items: stretch;
|
|
margin: 0.5em 0;
|
|
}
|
|
.button-row > button {
|
|
margin: 0;
|
|
}
|
|
|
|
/* Overlay styling */
|
|
.overlay {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
|
|
isolation: isolate;
|
|
z-index: 1;
|
|
position: fixed;
|
|
top: 0;
|
|
bottom: 0;
|
|
left: 0;
|
|
right: 0;
|
|
background: #fff4;
|
|
}
|
|
.overlay.--transient {
|
|
align-items: start;
|
|
justify-content: start;
|
|
background: none;
|
|
}
|
|
.popup-menu {
|
|
position: absolute;
|
|
min-width: 10vw;
|
|
border: 1px solid #444;
|
|
color: black;
|
|
background: hsl(var(--main-hue), 20%, 95%);
|
|
box-shadow: 0 1px 3px 1px #0009;
|
|
}
|
|
.popup-menu > li {
|
|
padding: 0.375em 0.625em;
|
|
cursor: pointer;
|
|
}
|
|
.popup-menu > li:hover {
|
|
color: hsl(var(--hover-hue), 90%, 10%);
|
|
background: hsl(var(--hover-hue), 90%, 85%);
|
|
}
|
|
.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 6px #000c;
|
|
}
|
|
.dialog > header {
|
|
padding: 0.5em;
|
|
line-height: 1;
|
|
background: linear-gradient(
|
|
hsl(var(--main-hue), 40%, 50%),
|
|
hsl(var(--main-hue), 50%, 45%));
|
|
border-bottom: 1px solid hsl(var(--main-hue), 60%, 30%);
|
|
color: white;
|
|
text-shadow: 0 2px 0 #0006;
|
|
}
|
|
.dialog > header h1 {
|
|
font-size: 1.25em;
|
|
}
|
|
.dialog > footer {
|
|
display: flex;
|
|
justify-content: flex-end;
|
|
gap: 0.5em;
|
|
|
|
padding: 0.5em;
|
|
background: #d0d0d0;
|
|
}
|
|
.dialog > footer > .-spacer {
|
|
flex: 1;
|
|
}
|
|
.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(var(--main-hue), 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;
|
|
text-align: right;
|
|
color: hsl(var(--main-hue), 50%, 25%);
|
|
}
|
|
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;
|
|
}
|
|
dl.formgrid > dd.-one-field {
|
|
display: flex;
|
|
}
|
|
dl.formgrid > dd.-textarea {
|
|
display: flex;
|
|
align-self: end; /* make the <dt> align to the top */
|
|
}
|
|
dl.formgrid > dd.-one-field > *,
|
|
dl.formgrid > dd.-textarea > * {
|
|
flex: auto;
|
|
}
|
|
dl.formgrid > dd.-with-buttons {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
}
|
|
|
|
/* 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(var(--main-hue), 20%, 60%);
|
|
}
|
|
table.level-browser tfoot {
|
|
position: sticky;
|
|
bottom: -1em;
|
|
background: #f4f4f4; /* match dialog background */
|
|
}
|
|
table.level-browser tfoot tr th {
|
|
border-top: 2px solid hsl(var(--main-hue), 20%, 60%);
|
|
text-align: right;
|
|
}
|
|
table.level-browser th,
|
|
table.level-browser td {
|
|
padding: 0.25em;
|
|
}
|
|
table.level-browser td.-number {
|
|
color: #404040;
|
|
text-align: right;
|
|
}
|
|
table.level-browser th.-time,
|
|
table.level-browser th.-score,
|
|
table.level-browser td.-time,
|
|
table.level-browser td.-score {
|
|
text-align: right;
|
|
}
|
|
table.level-browser button {
|
|
font-size: 0.833em;
|
|
}
|
|
table.level-browser tr.--current {
|
|
background: var(--generic-bg-selected-on-white);
|
|
outline: 1px solid var(--generic-border-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(var(--main-hue), 20%, 80%);
|
|
}
|
|
@media (max-width: 600px) {
|
|
/* Unique media query: this is only necessary for VERY narrow screens */
|
|
/* In order to wrap the rows, turn the table markup into a stack of grids */
|
|
table.level-browser {
|
|
display: block;
|
|
}
|
|
table.level-browser tr {
|
|
display: grid;
|
|
grid:
|
|
"number star name name forget"
|
|
"number . clock time score"
|
|
/ 3em 1em 1fr 1fr 1fr
|
|
;
|
|
}
|
|
table.level-browser td,
|
|
table.level-browser th {
|
|
display: block;
|
|
}
|
|
table.level-browser thead .-title,
|
|
table.level-browser tfoot .-title {
|
|
/* "Level" and "Total" column headers are not useful and eat a lot of space */
|
|
display: none;
|
|
}
|
|
table.level-browser thead th:empty,
|
|
table.level-browser tfoot th:empty {
|
|
/* These are filler for table layout purposes */
|
|
display: none;
|
|
}
|
|
table.level-browser .-number {
|
|
grid-area: number;
|
|
}
|
|
table.level-browser .-title {
|
|
grid-area: name;
|
|
}
|
|
table.level-browser .-time {
|
|
grid-area: clock;
|
|
}
|
|
table.level-browser .-time + .-time {
|
|
grid-area: time;
|
|
}
|
|
table.level-browser .-score {
|
|
grid-area: score;
|
|
}
|
|
table.level-browser .-aid {
|
|
grid-area: star;
|
|
/* We overflow a bit because of our padding, so just leak into it */
|
|
justify-self: center;
|
|
}
|
|
table.level-browser .-button {
|
|
grid-area: forget;
|
|
justify-self: end;
|
|
}
|
|
/* Move borders off cells and onto rows */
|
|
table.level-browser thead tr th {
|
|
border: none;
|
|
}
|
|
table.level-browser tfoot tr th {
|
|
border: none;
|
|
}
|
|
table.level-browser tbody tr:nth-child(10n) td {
|
|
border: none;
|
|
}
|
|
table.level-browser thead tr {
|
|
border-bottom: 2px solid hsl(var(--main-hue), 20%, 60%);
|
|
}
|
|
table.level-browser tfoot tr {
|
|
border-top: 2px solid hsl(var(--main-hue), 20%, 60%);
|
|
}
|
|
table.level-browser tbody tr {
|
|
border-bottom: 1px solid #ddd;
|
|
}
|
|
table.level-browser tbody tr.--current {
|
|
border: none;
|
|
}
|
|
table.level-browser tbody tr:nth-child(10n) {
|
|
border-bottom: 2px solid hsl(var(--main-hue), 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;
|
|
}
|
|
|
|
@media (max-width: 800px) {
|
|
/* Stack the formgrid, it doesn't fit very well as columns */
|
|
.dialog dl.formgrid {
|
|
display: block;
|
|
}
|
|
.dialog dl.formgrid > dt {
|
|
margin: 0.5em 0;
|
|
text-align: left;
|
|
}
|
|
.dialog dl.formgrid > dt:first-child {
|
|
margin-top: 0;
|
|
}
|
|
.dialog dl.formgrid > * + dt {
|
|
border-top: 1px solid #ccc;
|
|
padding-top: 0.5em;
|
|
}
|
|
.dialog dl.formgrid > * + dt:empty {
|
|
padding-top: 0;
|
|
}
|
|
.dialog dl.formgrid > dd {
|
|
margin: 0.5em 0;
|
|
}
|
|
|
|
.dialog-compat .radio-faux-button-set {
|
|
font-size: 0.83em;
|
|
flex-wrap: wrap;
|
|
}
|
|
.dialog-compat .radio-faux-button-set > * {
|
|
flex: 1 0 30%;
|
|
}
|
|
.dialog-compat .radio-faux-button-set .-button {
|
|
border-radius: 0;
|
|
}
|
|
ul.compat-flags img.compat-icon,
|
|
ul.compat-flags span.compat-icon-gap {
|
|
width: 16px;
|
|
height: 16px;
|
|
}
|
|
}
|
|
|
|
|
|
/* 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%;
|
|
}
|
|
.dialog-options {
|
|
}
|
|
}
|
|
|
|
|
|
/**************************************************************************************************/
|
|
/* Main page structure */
|
|
|
|
body > header {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5em;
|
|
|
|
padding: 0.25em 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 {
|
|
white-space: nowrap;
|
|
}
|
|
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;
|
|
}
|
|
#failed .-with-error {
|
|
display: none;
|
|
}
|
|
#failed.--got-error .-with-error {
|
|
display: revert;
|
|
}
|
|
#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;
|
|
--mask: linear-gradient(to right, transparent 0, #ffffff40 10%, white 20%, white 80%, #ffffff40 90%, transparent 100%);
|
|
-webkit-mask-image: var(--mask);
|
|
mask-image: var(--mask);
|
|
}
|
|
.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;
|
|
}
|
|
#header-icon {
|
|
image-rendering: crisp-edges;
|
|
image-rendering: pixelated;
|
|
}
|
|
|
|
@media (orientation: portrait) and (max-width: 800px), (orientation: landscape) and (max-height: 600px) {
|
|
body > header {
|
|
padding: 1px;
|
|
}
|
|
/* All these headings are way too big on phones */
|
|
body > header h1 {
|
|
font-size: 1.125em;
|
|
}
|
|
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;
|
|
}
|
|
|
|
/* Hide the top/bottom nav while playing entirely */
|
|
body[data-mode=player] #header-pack,
|
|
body[data-mode=player] #header-level {
|
|
display: none;
|
|
}
|
|
}
|
|
|
|
/**************************************************************************************************/
|
|
/* Splash (intro part) */
|
|
|
|
#splash {
|
|
display: grid;
|
|
grid:
|
|
"header header"
|
|
"links links"
|
|
"disclaimer disclaimer"
|
|
"stock yours"
|
|
/ 3fr minmax(18em, 1fr)
|
|
;
|
|
gap: 1em;
|
|
|
|
position: relative;
|
|
padding: 1em 7.5%;
|
|
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 fullscreen" 2fr
|
|
"image tagline fullscreen" 1fr
|
|
/ min-content 1fr min-content
|
|
;
|
|
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-fullscreen {
|
|
/* FIXME this makes the title SLIGHTLY offcenter bc of grid gap */
|
|
display: none;
|
|
grid-area: fullscreen;
|
|
align-self: center;
|
|
}
|
|
#splash-fullscreen svg {
|
|
width: 2em;
|
|
height: auto;
|
|
}
|
|
#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;
|
|
}
|
|
#splash > #splash-disclaimer {
|
|
grid-area: disclaimer;
|
|
font-size: 0.83em;
|
|
margin: 0;
|
|
text-align: center;
|
|
color: #c0c0c0;
|
|
}
|
|
|
|
@media (max-width: 800px) {
|
|
#splash {
|
|
/* Grid layout doesn't fit, just stack everything */
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.5em;
|
|
/* 10% padding is way way too much */
|
|
padding: 0.5em;
|
|
}
|
|
#splash::after {
|
|
/* This needs different handling in a flex container */
|
|
flex: 0 0 0.5em;
|
|
height: auto;
|
|
}
|
|
/* Shrink logo and title, and left-align both */
|
|
#splash > header {
|
|
grid-template-rows: auto auto;
|
|
grid-template-columns: min-content 1fr;
|
|
column-gap: 0.5em;
|
|
margin: 0;
|
|
}
|
|
#splash > header img {
|
|
width: 48px;
|
|
}
|
|
#splash > header h1 {
|
|
font-size: 1.5em;
|
|
}
|
|
#splash > header p {
|
|
font-size: 0.9em;
|
|
}
|
|
/* No need to boost the font size here */
|
|
#splash > #splash-links {
|
|
font-size: inherit;
|
|
column-gap: 1em;
|
|
}
|
|
#splash > section {
|
|
padding: 0.5em;
|
|
}
|
|
/* This takes up an incredible amount of space on a phone; push it down, they have to scroll to
|
|
* see much of anything anyway. TODO possibly revert if i can find a way to shorten wording */
|
|
#splash > #splash-disclaimer {
|
|
order: 99;
|
|
}
|
|
}
|
|
|
|
.played-pack-list {
|
|
|
|
}
|
|
#splash-stock-levels .played-pack-list {
|
|
display: grid;
|
|
grid: auto-flow auto / repeat(auto-fill, minmax(320px, 1fr)); /* 10x10 */
|
|
gap: 1em;
|
|
margin: 1em 0;
|
|
}
|
|
.played-pack-list .-preview {
|
|
display: block;
|
|
height: 320px;
|
|
margin: auto;
|
|
object-fit: none;
|
|
}
|
|
.played-pack-list > li > button {
|
|
font-size: 1.25em;
|
|
padding: 0.5em;
|
|
margin: 0.25em 0;
|
|
text-transform: none;
|
|
text-align: left;
|
|
/* this also forces the button to be 1 line of text high even for empty title */
|
|
white-space: pre-wrap;
|
|
}
|
|
.played-pack-list p {
|
|
color: #c0c0c0;
|
|
font-style: italic;
|
|
}
|
|
.played-pack-list .-progress {
|
|
display: grid;
|
|
grid:
|
|
"levels levels levels"
|
|
"score time button"
|
|
/ 2fr 2fr 1fr
|
|
;
|
|
gap: 0.5em;
|
|
margin: 0.5em 0;
|
|
align-items: center;
|
|
}
|
|
.played-pack-list > li.--unplayed .-progress {
|
|
display: none;
|
|
}
|
|
.played-pack-list .-progress > .-levels {
|
|
grid-area: levels;
|
|
|
|
position: relative;
|
|
z-index: 1;
|
|
padding: 0.25em;
|
|
border: 1px solid hsl(var(--main-hue), 25%, 40%);
|
|
text-shadow: 0 1px 1px black;
|
|
text-align: center;
|
|
}
|
|
.played-pack-list .-progress > .-levels::before,
|
|
.played-pack-list .-progress > .-levels::after {
|
|
content: '';
|
|
position: absolute;
|
|
z-index: -1;
|
|
top: 0;
|
|
bottom: 0;
|
|
left: 0;
|
|
}
|
|
.played-pack-list .-progress > .-levels::before {
|
|
width: calc(var(--cleared) * 100%);
|
|
background: hsl(var(--main-hue), 25%, 30%);
|
|
}
|
|
.played-pack-list .-progress > .-levels::after {
|
|
width: calc(var(--aidless) * 100%);
|
|
background: hsl(var(--main-hue), 25%, 40%);
|
|
}
|
|
.played-pack-list .-progress > .-score {
|
|
grid-area: score;
|
|
}
|
|
.played-pack-list .-progress > .-time {
|
|
grid-area: time;
|
|
}
|
|
.played-pack-list .-progress > .-levels {
|
|
grid-area: levels;
|
|
}
|
|
.played-pack-list .-progress > .-score::before {
|
|
content: "Score: ";
|
|
color: #909090;
|
|
}
|
|
.played-pack-list .-progress > .-time::before {
|
|
content: "Time: ";
|
|
color: #909090;
|
|
}
|
|
.played-pack-list .-editor-status {
|
|
display: flex;
|
|
gap: 0.5em;
|
|
margin: 0.5em 0 1em;
|
|
}
|
|
.played-pack-list .-editor-status > .-level-count {
|
|
flex: auto;
|
|
}
|
|
.played-pack-list .-editor-status > .-timestamp {
|
|
flex: auto;
|
|
text-align: right;
|
|
}
|
|
|
|
/* "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(var(--main-hue), 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!) */
|
|
/* It does also make auto-sizing easier! */
|
|
/* Default to a landscape layout, with the buttons on the left */
|
|
display: grid;
|
|
grid:
|
|
"buttons game actions"
|
|
"buttons game actions"
|
|
". music music"
|
|
/ 1fr auto 1fr
|
|
;
|
|
justify-content: stretch;
|
|
gap: 0.5em;
|
|
margin: auto; /* center in both directions baby */
|
|
}
|
|
#player-controls,
|
|
#player-actions {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: stretch;
|
|
gap: 0.25em;
|
|
}
|
|
#player-controls {
|
|
grid-area: buttons;
|
|
align-self: start;
|
|
}
|
|
#player-controls button,
|
|
#player-actions button {
|
|
padding: 0.5em;
|
|
line-height: 1;
|
|
}
|
|
#player-controls button svg,
|
|
#player-actions button svg {
|
|
font-size: 1.5em;
|
|
display: block;
|
|
margin: 0.125em auto;
|
|
}
|
|
#player-controls .radio-faux-button-set {
|
|
margin: 0;
|
|
}
|
|
#player-actions {
|
|
grid-area: actions;
|
|
align-self: end;
|
|
}
|
|
#player-music {
|
|
grid-area: music;
|
|
margin: 0 calc(var(--tile-width) * var(--scale) / 4);
|
|
text-transform: lowercase;
|
|
color: #909090;
|
|
}
|
|
/* Key hints are placed on the sides */
|
|
#player button {
|
|
position: relative;
|
|
}
|
|
#player button .keyhint {
|
|
font-size: 1rem;
|
|
position: absolute;
|
|
top: 1.25em;
|
|
margin: auto;
|
|
color: #404040;
|
|
}
|
|
#player-controls button .keyhint {
|
|
left: -2em;
|
|
}
|
|
#player-actions button .keyhint {
|
|
right: -2em;
|
|
}
|
|
#player button:disabled .keyhint {
|
|
display: none;
|
|
}
|
|
#player-controls button:enabled.control-restart {
|
|
/* Special shenanigans for holding R to restart */
|
|
--restart-progress: 0;
|
|
background-image: var(--button-bg-gradient), conic-gradient(
|
|
hsl(345, 60%, 40%) 0deg calc(var(--restart-progress) * 360deg),
|
|
transparent calc(var(--restart-progress) * 360deg) 360deg)
|
|
}
|
|
@media (orientation: portrait) {
|
|
/* On a portrait screen, put the controls on top */
|
|
#player-main {
|
|
grid:
|
|
"buttons actions"
|
|
"game game"
|
|
"music music"
|
|
;
|
|
}
|
|
#player-controls,
|
|
#player-actions {
|
|
flex-direction: row;
|
|
white-space: nowrap;
|
|
}
|
|
#player-controls button svg,
|
|
#player-actions button svg {
|
|
font-size: 1em;
|
|
}
|
|
#player-controls button {
|
|
padding: 0.25em 0.5em;
|
|
line-height: 1.33;
|
|
}
|
|
#player-actions {
|
|
justify-content: end;
|
|
}
|
|
#player button .keyhint {
|
|
top: -2em;
|
|
left: 0;
|
|
right: 0;
|
|
}
|
|
}
|
|
@media (orientation: portrait) and (max-width: 800px) {
|
|
/* On a /small/ portrait screen, put the controls on their own bottom row */
|
|
#player-main {
|
|
grid:
|
|
"buttons"
|
|
"game"
|
|
"actions"
|
|
;
|
|
}
|
|
#player-controls,
|
|
#player-actions {
|
|
/* Not much in these rows so make them a bit bigger for hittability */
|
|
font-size: 1.33em;
|
|
justify-content: center;
|
|
}
|
|
#player-controls button,
|
|
#player-actions button {
|
|
flex: auto;
|
|
padding: 0.25em 0.5em;
|
|
}
|
|
#player-controls .control-restart {
|
|
/* This is a dedicated pause-menu button */
|
|
display: none;
|
|
}
|
|
#player .keyhint {
|
|
/* Hide key hints; there's nowhere to put them and they take up surprisingly a lot of space */
|
|
display: none;
|
|
}
|
|
#player-controls .radio-faux-button-set span {
|
|
/* "step mode" is real big */
|
|
font-size: 0.75em;
|
|
}
|
|
}
|
|
@media (orientation: landscape) and (max-height: 600px) {
|
|
/* On a small landscape screen, remove the music row (it matters!) */
|
|
#player-main {
|
|
grid:
|
|
"buttons game actions"
|
|
"buttons game actions"
|
|
/ 1fr auto 1fr
|
|
;
|
|
}
|
|
}
|
|
@media (orientation: portrait) and (max-width: 800px), (orientation: landscape) and (max-height: 600px) {
|
|
#player-controls .-optional-label {
|
|
display: none;
|
|
}
|
|
#splash-fullscreen {
|
|
display: revert;
|
|
}
|
|
#player-music {
|
|
/* TODO :( */
|
|
display: none;
|
|
}
|
|
}
|
|
|
|
#player-game-area {
|
|
grid-area: game;
|
|
/* don't stretch if the buttons or music blow out somehow */
|
|
justify-self: center;
|
|
align-self: center;
|
|
|
|
isolation: isolate;
|
|
display: grid;
|
|
align-items: center;
|
|
grid:
|
|
"level chips" min-content
|
|
"level time" min-content
|
|
"level bonus" min-content
|
|
"level rules" 1fr
|
|
"level inventory" min-content
|
|
/* Need explicit min-content to force the hint to wrap */
|
|
/ min-content min-content
|
|
;
|
|
column-gap: calc(var(--tile-width) * var(--scale) / 4);
|
|
row-gap: calc(var(--tile-height) * var(--scale) / 4);
|
|
|
|
padding: calc(var(--tile-height) * var(--scale) / 4) calc(var(--tile-width) * var(--scale) / 4);
|
|
background: hsl(var(--main-hue), 10%, 15%);
|
|
box-shadow: 0 0.25em 1em black;
|
|
}
|
|
|
|
.level {
|
|
grid-area: level;
|
|
|
|
position: relative;
|
|
outline: 1px solid hsl(var(--main-hue), 10%, 5%);
|
|
}
|
|
.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:
|
|
"pack" calc(1em * 1.25 * 1)
|
|
"level" calc(1.333em * 1.25 * 2)
|
|
"author" calc(1em * 1.25 * 1)
|
|
"space" 1fr
|
|
"score" 1.5em
|
|
"controls" 1.5em
|
|
;
|
|
align-items: center;
|
|
gap: 0.25em;
|
|
/* Prevent blowout; force using the canvas's size */
|
|
height: 0;
|
|
min-height: 100%;
|
|
width: 0;
|
|
min-width: 100%;
|
|
box-sizing: border-box;
|
|
|
|
z-index: 2;
|
|
font-size: calc(0.5 * var(--tile-width) * var(--scale));
|
|
line-height: 1.25;
|
|
background: #0009;
|
|
color: white;
|
|
text-align: center;
|
|
text-shadow: 0 1px 1px black;
|
|
}
|
|
/* Allow clicking through the overlay in debug mode */
|
|
body.--debug .player-overlay-message {
|
|
pointer-events: none;
|
|
}
|
|
.player-overlay-message > * {
|
|
padding: 0 0.25em;
|
|
}
|
|
.player-overlay-message h1 {
|
|
/* Pack title, doesn't need to be too big */
|
|
grid-area: pack;
|
|
font-size: 0.833em;
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
color: hsl(var(--main-hue), 25%, 75%);
|
|
}
|
|
.player-overlay-message > h2 {
|
|
grid-area: level;
|
|
font-size: 2em;
|
|
}
|
|
.player-overlay-message[data-reason='waiting'] > h2 {
|
|
/* For 'waiting' this is a level name, so make it two lines of smaller text */
|
|
font-size: 1.333em;
|
|
}
|
|
.player-overlay-message > h3 {
|
|
grid-area: author;
|
|
font-size: 1em;
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
color: hsl(var(--main-hue), 10%, 90%);
|
|
}
|
|
.player-overlay-message > .-best-score {
|
|
grid-area: score;
|
|
align-self: flex-end;
|
|
}
|
|
.player-overlay-message > .scoreboard {
|
|
grid-row: author / score;
|
|
}
|
|
.player-overlay-message .-controls-hint {
|
|
grid-area: controls;
|
|
font-size: 0.75em;
|
|
color: #c0c0c0;
|
|
}
|
|
.player-overlay-message .mobile-pause-menu {
|
|
grid-area: space;
|
|
}
|
|
.mobile-pause-menu {
|
|
font-size: 1.25em;
|
|
display: none; /* flex */
|
|
flex-direction: column;
|
|
align-items: stretch;
|
|
gap: 0.33em;
|
|
width: 80%;
|
|
margin: auto;
|
|
}
|
|
.mobile-pause-menu button {
|
|
padding: 0.33em;
|
|
}
|
|
.mobile-pause-menu > p {
|
|
display: flex;
|
|
flex-direction: row;
|
|
align-items: stretch;
|
|
justify-content: stretch;
|
|
margin: 0;
|
|
gap: 0.33em;
|
|
}
|
|
.mobile-pause-menu > p > button {
|
|
flex: 1;
|
|
line-height: 1;
|
|
}
|
|
.mobile-pause-menu > p > button.-narrow {
|
|
flex: initial;
|
|
}
|
|
.mobile-pause-menu .-only-waiting,
|
|
.mobile-pause-menu .-only-paused,
|
|
.mobile-pause-menu .-only-failure,
|
|
.mobile-pause-menu .-only-success,
|
|
.mobile-pause-menu .-only-ended {
|
|
display: none;
|
|
}
|
|
.player-overlay-message[data-reason=waiting] .mobile-pause-menu .-only-waiting,
|
|
.player-overlay-message[data-reason=paused] .mobile-pause-menu .-only-paused,
|
|
.player-overlay-message[data-reason=failure] .mobile-pause-menu .-only-failure,
|
|
.player-overlay-message[data-reason=success] .mobile-pause-menu .-only-success,
|
|
.player-overlay-message[data-reason=ended] .mobile-pause-menu .-only-ended {
|
|
display: initial;
|
|
}
|
|
.player-overlay-message[data-reason=paused] .mobile-pause-menu p.-only-paused {
|
|
display: flex;
|
|
}
|
|
.player-overlay-message[data-reason=""] {
|
|
display: none;
|
|
}
|
|
.player-overlay-message[data-reason=waiting] {
|
|
background: linear-gradient(to bottom, #000d, #0008 40%, #0008 60%, #000d);
|
|
}
|
|
.player-overlay-message[data-reason=failure] {
|
|
background: hsla(330, 20%, 10%, 0.5);
|
|
background: radial-gradient(#0004, hsla(330, 10%, 10%, 0.5) 40%, hsl(330, 20%, 10%));
|
|
}
|
|
.player-overlay-message[data-reason=success] {
|
|
background: radial-gradient(hsla(var(--main-hue), 60%, 5%, 0.75), 60%, hsla(var(--main-hue), 60%, 25%, 0.75));
|
|
}
|
|
.player-overlay-message[data-reason=ended] {
|
|
/* Rearrange this entirely, to fit the ending image in */
|
|
grid:
|
|
"congrats" min-content
|
|
"." 0.5em
|
|
"menu" 1fr
|
|
"." 0.5em
|
|
"score" min-content
|
|
;
|
|
overflow: hidden;
|
|
background: url(ending.png) no-repeat center center / cover;
|
|
box-shadow: inset 0 0 calc(4 * var(--tile-width)) hsl(var(--main-hue), 50%, 25%);
|
|
}
|
|
.player-overlay-message[data-reason=ended] .mobile-pause-menu {
|
|
grid-area: menu;
|
|
}
|
|
.player-overlay-message[data-reason=ended] > .-congrats {
|
|
grid-area: congrats;
|
|
margin: 0;
|
|
padding: 0.25em;
|
|
background: #0009;
|
|
}
|
|
.player-overlay-message[data-reason=ended] > .-score {
|
|
grid-area: score;
|
|
margin: 0;
|
|
padding: 0.25em;
|
|
background: #0006;
|
|
}
|
|
.player-overlay-message[data-reason=ended] > .-score output {
|
|
font-size: 2em;
|
|
display: block;
|
|
}
|
|
@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);
|
|
/* Alas, the spinning part apparently eats a lot of CPU */
|
|
/* animation: ending-spinner 10s linear infinite; */
|
|
-webkit-mask-image: radial-gradient(at center, #0000 0%, #000c 50%);
|
|
mask-image: radial-gradient(at center, #0000 0%, #000c 50%);
|
|
}
|
|
}
|
|
@keyframes ending-spinner {
|
|
0% {
|
|
transform: rotate(0turn);
|
|
}
|
|
100% {
|
|
transform: rotate(1turn);
|
|
}
|
|
}
|
|
.scoreboard {
|
|
display: grid;
|
|
grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr;
|
|
grid-auto-rows: min-content;
|
|
align-items: center;
|
|
row-gap: 0.75em;
|
|
margin: auto 5%;
|
|
font-weight: normal;
|
|
text-align: center;
|
|
/* this is a lot of stuff crammed into a small space, so prefer having more space between rows
|
|
* and less space between labels+values (which makes them more clearly related anyway) */
|
|
line-height: 1.1;
|
|
}
|
|
.scoreboard .-subscore {
|
|
grid-column: span 2;
|
|
color: #f4f4f4;
|
|
}
|
|
.scoreboard .-level-score {
|
|
grid-column: span 3;
|
|
}
|
|
.scoreboard .-improvement {
|
|
grid-column: span 3;
|
|
}
|
|
.scoreboard .-improvement.--same h4 {
|
|
color: hsl(240, 50%, 60%);
|
|
}
|
|
.scoreboard .-improvement.--same p {
|
|
color: hsl(240, 50%, 80%);
|
|
}
|
|
.scoreboard .-improvement.--worse h4 {
|
|
color: hsl(330, 50%, 60%);
|
|
}
|
|
.scoreboard .-improvement.--worse p {
|
|
color: hsl(330, 50%, 80%);
|
|
}
|
|
.scoreboard .-improvement.--better h4 {
|
|
color: hsl(210, 50%, 60%);
|
|
}
|
|
.scoreboard .-improvement.--better p {
|
|
color: hsl(210, 50%, 80%);
|
|
}
|
|
.scoreboard .-total-score {
|
|
grid-column: span 3;
|
|
color: hsl(45, 100%, 75%);
|
|
}
|
|
.scoreboard h4 {
|
|
font-size: 0.75em;
|
|
color: hsl(var(--main-hue), 10%, 60%);
|
|
}
|
|
.scoreboard .-total-score h4 {
|
|
color: hsl(30, 50%, 60%);
|
|
}
|
|
.scoreboard p {
|
|
margin: 0;
|
|
}
|
|
.scoreboard .-total-score p {
|
|
font-size: 1.333em;
|
|
}
|
|
|
|
/* Transparent container for displaying captions for captions */
|
|
.player-overlay-captions {
|
|
grid-area: level;
|
|
place-self: stretch;
|
|
position: relative;
|
|
/* above the message layer */
|
|
z-index: 3;
|
|
|
|
font-size: calc(0.75em * var(--scale));
|
|
pointer-events: none;
|
|
}
|
|
.player-overlay-captions > span.-caption {
|
|
position: absolute;
|
|
left: calc(var(--x-offset) * var(--tile-width) * var(--scale));
|
|
top: calc(var(--y-offset) * var(--tile-height) * var(--scale));
|
|
animation: 1s ease-in 1 forwards caption-fade;
|
|
|
|
font-weight: bold;
|
|
color: white;
|
|
/* Lol this sucks, please save me Tab */
|
|
/* TODO use an svg element for these instead? would also avoid overflow issues */
|
|
text-shadow:
|
|
-1px -1px black,
|
|
1px -1px black,
|
|
-1px 2px black,
|
|
1px 2px black,
|
|
/* one more to fix lowercase k! */
|
|
1px 0 black;
|
|
|
|
white-space: nowrap;
|
|
/* Anchor these to their absolute centers */
|
|
transform: translate(-50%, -50%);
|
|
}
|
|
@keyframes caption-fade {
|
|
0% {
|
|
opacity: 1;
|
|
}
|
|
75% {
|
|
opacity: 1;
|
|
}
|
|
100% {
|
|
opacity: 0;
|
|
}
|
|
}
|
|
|
|
.player-level-number {
|
|
grid-area: number;
|
|
/* This is only for portrait, and mostly to fill space */
|
|
display: none;
|
|
line-height: 1;
|
|
}
|
|
.chips {
|
|
grid-area: chips;
|
|
}
|
|
.time {
|
|
grid-area: time;
|
|
}
|
|
.bonus {
|
|
grid-area: bonus;
|
|
}
|
|
.chips,
|
|
.time,
|
|
.bonus {
|
|
font-size: calc(var(--tile-height) * var(--scale) * 3/4);
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.25em;
|
|
}
|
|
.chips h3,
|
|
.time h3,
|
|
.bonus h3 {
|
|
flex: 0;
|
|
order: 2;
|
|
font-size: 0.75em;
|
|
line-height: 1;
|
|
color: hsl(var(--main-hue), 20%, 80%);
|
|
}
|
|
.chips output,
|
|
.time output,
|
|
.bonus output {
|
|
flex: 1;
|
|
min-width: 2em;
|
|
min-height: 1em;
|
|
line-height: 1;
|
|
text-align: right;
|
|
font-family: monospace;
|
|
color: hsl(var(--main-hue), 20%, 60%);
|
|
}
|
|
/* nb: the hex colors are all taken from the lexy palette */
|
|
.chips output {
|
|
color: #feafc9;
|
|
}
|
|
.time output {
|
|
color: #6ca2a7;
|
|
}
|
|
.time output.--warning {
|
|
color: #f48457;
|
|
}
|
|
.time output.--danger {
|
|
color: #e1565f;
|
|
/* 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);
|
|
}
|
|
}
|
|
.chips output.--done,
|
|
.time output.--frozen,
|
|
.bonus output {
|
|
color: hsl(var(--main-hue), 10%, 30%);
|
|
}
|
|
#player.--bonus-visible .bonus output {
|
|
color: #e2c9ff;
|
|
}
|
|
.player-rules {
|
|
font-size: calc(var(--tile-height) * var(--scale) / 4);
|
|
grid-area: rules;
|
|
align-self: end;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.5em;
|
|
color: hsl(var(--main-hue), 20%, 80%);
|
|
}
|
|
.player-rules p {
|
|
display: none;
|
|
margin: 0;
|
|
}
|
|
#player.--hide-logic .player-rules #player-rule-logic-hidden {
|
|
display: revert;
|
|
}
|
|
#player.--cc1-boots .player-rules #player-rule-cc1-boots {
|
|
display: revert;
|
|
}
|
|
|
|
/* 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: rules;
|
|
align-self: stretch;
|
|
|
|
display: none;
|
|
position: relative;
|
|
overflow: hidden;
|
|
font-size: calc(var(--tile-height) * var(--scale) / 4);
|
|
font-family: serif;
|
|
color: hsl(var(--main-hue), 20%, 80%);
|
|
background: url(#svg-icon-hint) hsl(var(--main-hue), 10%, 10%);
|
|
border: 3px double hsl(var(--main-hue), 10%, 15%);
|
|
}
|
|
#player-game-area > .player-hint-wrapper > .player-hint-bg-icon {
|
|
position: absolute;
|
|
width: 8em;
|
|
height: auto;
|
|
bottom: -2em;
|
|
right: -2em;
|
|
opacity: 0.05;
|
|
transform: rotate(-30deg);
|
|
}
|
|
#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! */
|
|
box-sizing: border-box;
|
|
height: 0;
|
|
min-height: 100%;
|
|
width: 0;
|
|
min-width: 100%;
|
|
padding: 0.5em 0.625em;
|
|
line-height: 1.5;
|
|
white-space: pre-wrap;
|
|
}
|
|
#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;
|
|
}
|
|
|
|
@media (orientation: portrait) {
|
|
#player-game-area {
|
|
/* Rearrange the grid to be vertical */
|
|
grid:
|
|
"inventory chips chips time" min-content
|
|
"inventory rules bonus bonus" min-content
|
|
"level level level level" min-content
|
|
/ min-content 1fr 1fr 2fr
|
|
;
|
|
}
|
|
.player-level-number {
|
|
/* TODO this makes us too big on my phone, damn */
|
|
/*display: initial;*/
|
|
}
|
|
.chips,
|
|
.time,
|
|
.bonus {
|
|
/* These numbers need to be sliiightly smaller */
|
|
font-size: calc(var(--tile-height) * var(--scale) * 2/3);
|
|
}
|
|
#player .inventory {
|
|
/* stick me in the center left */
|
|
place-self: center start;
|
|
}
|
|
#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-game-area > .player-hint-wrapper > .player-hint {
|
|
padding: 0.33em 0.5em;
|
|
line-height: 1.33;
|
|
}
|
|
.player-rules {
|
|
align-self: center;
|
|
flex-direction: row;
|
|
}
|
|
.player-rules p span {
|
|
/* There's only room for the icons, since there's no dedicated hint space */
|
|
display: none;
|
|
}
|
|
}
|
|
@media (orientation: portrait) and (max-width: 800px), (orientation: landscape) and (max-height: 600px) {
|
|
/* Overlay is a bit different on what I assume is a touchscreen */
|
|
.player-overlay-message[data-reason='waiting'] > p {
|
|
/* Hide the "Ready!" and controls, since there's a menu */
|
|
display: none;
|
|
}
|
|
.mobile-pause-menu {
|
|
display: flex;
|
|
}
|
|
}
|
|
@media (orientation: portrait) and (max-width: 800px) {
|
|
#player-game-area {
|
|
padding: 0;
|
|
background: none;
|
|
box-shadow: none;
|
|
}
|
|
.level {
|
|
outline: 1px solid black;
|
|
}
|
|
}
|
|
|
|
/* 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-flow min-content / repeat(8, min-content);
|
|
gap: 2px;
|
|
}
|
|
#player-debug > .-inventory > button {
|
|
padding: 0;
|
|
}
|
|
#player-debug > .-inventory > button > img {
|
|
display: block;
|
|
}
|
|
#player-debug > .-inventory > button.-wide {
|
|
grid-column: span 5;
|
|
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;
|
|
}
|
|
|
|
.player-debug-actor-tooltip {
|
|
position: absolute;
|
|
display: none;
|
|
|
|
/* similar to editor tooltip */
|
|
padding: 0.33em 0.75em;
|
|
border: 1px solid black;
|
|
color: #d8d8d8;
|
|
background: hsl(var(--main-hue), 10%, 20%);
|
|
box-shadow: 0 1px 2px 1px #0004;
|
|
|
|
opacity: 0.9;
|
|
font-family: monospace;
|
|
pointer-events: none;
|
|
}
|
|
.player-debug-actor-tooltip.--visible {
|
|
display: block;
|
|
}
|
|
.player-debug-actor-tooltip h3 {
|
|
font-size: 1.25em;
|
|
margin-bottom: 0.25rem;
|
|
border-bottom: 1px solid currentColor;
|
|
color: white;
|
|
}
|
|
.player-debug-actor-tooltip dl {
|
|
display: grid;
|
|
grid: auto-flow min-content / auto auto;
|
|
align-items: baseline;
|
|
gap: 0.25em 1em;
|
|
margin: 0;
|
|
}
|
|
.player-debug-actor-tooltip dl > dt {
|
|
grid-column: 1;
|
|
}
|
|
.player-debug-actor-tooltip dl > dd {
|
|
grid-column: 2;
|
|
margin: 0;
|
|
}
|
|
|
|
|
|
/**************************************************************************************************/
|
|
/* Editor */
|
|
|
|
#editor {
|
|
flex: 1 1 auto;
|
|
display: grid;
|
|
grid:
|
|
"controls controls" min-content
|
|
"palette level" 1fr
|
|
"palette status" min-content
|
|
/ min-content 1fr
|
|
;
|
|
gap: 0.5em;
|
|
|
|
min-height: 0;
|
|
margin: auto 1em;
|
|
}
|
|
|
|
#editor .editor-canvas {
|
|
grid-area: level;
|
|
overflow: auto;
|
|
position: relative;
|
|
background: #101010;
|
|
border: 0.125em solid black;
|
|
}
|
|
#editor .editor-canvas::before {
|
|
/* Clever abuse of sticky positioning to draw a box shadow on top of the container and inside
|
|
* the scrollbars (thanks, leafo!) */
|
|
content: '';
|
|
display: block;
|
|
position: sticky;
|
|
top: 0;
|
|
left: 0;
|
|
height: 100%;
|
|
box-shadow: inset 0 0 0.5em black;
|
|
z-index: 1;
|
|
pointer-events: none;
|
|
}
|
|
#editor .editor-canvas.--crispy {
|
|
image-rendering: crisp-edges;
|
|
image-rendering: pixelated;
|
|
}
|
|
#editor .editor-canvas .-container {
|
|
/* The shadow overlay is sticky-positioned, meaning it defaults to being in-flow, so this
|
|
* container needs to compensate by absolutely positioning itself back up top. It'll still
|
|
* create scrollbars, so this shouldn't cause any issues. */
|
|
position: absolute;
|
|
top: 0;
|
|
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. It's 75vmin because that /ROUGHLY/ allows panning the level to the edge of
|
|
* the viewport but not completely off of it. */
|
|
/* NOTE: This MUST be large enough to guarantee being bigger than the viewport; we aren't in a
|
|
* flex container, so if the canvas + border aren't sufficiently tall, we won't even fill the
|
|
* viewport and the canvas will be off-center. Also, with no border at all, a mysterious
|
|
* interaction with the sticky box-shadow causes the top of the canvas to go off the top of the
|
|
* viewport entirely! So, twiddle this with care. */
|
|
/* TODO probably a better way to measure this; i really want relative to parent size, but
|
|
* percentage padding and margins are specifically relative to our width */
|
|
border: 50vmax solid transparent;
|
|
/* This is necessary to force us to be as wide as the canvas; without it, we have an auto width,
|
|
* and there's technically no space left after our border, so we become zero width and the
|
|
* canvas is entirely overflow, which fucks up positioning of the SVG overlay */
|
|
width: -moz-fit-content;
|
|
width: fit-content;
|
|
}
|
|
#editor .editor-canvas canvas {
|
|
display: block;
|
|
width: calc(var(--viewport-width) * var(--tile-width) * var(--scale));
|
|
--viewport-width: 9;
|
|
--viewport-height: 9;
|
|
--scale: 1;
|
|
}
|
|
/* SVG overlays */
|
|
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;
|
|
}
|
|
svg.level-editor-overlay .overlay-transient {
|
|
display: none;
|
|
}
|
|
svg.level-editor-overlay .overlay-transient.--visible {
|
|
display: initial;
|
|
}
|
|
svg.level-editor-overlay rect.overlay-cursor {
|
|
x-stroke: hsla(220, 100%, 60%, 0.5);
|
|
fill: hsla(220, 100%, 75%, 0.25);
|
|
}
|
|
svg.level-editor-overlay rect.overlay-pending-selection {
|
|
stroke: hsla(220, 100%, 60%, 0.5);
|
|
fill: hsla(220, 100%, 75%, 0.25);
|
|
}
|
|
svg.level-editor-overlay rect.overlay-selection {
|
|
stroke: #000c;
|
|
fill: hsla(220, 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;
|
|
}
|
|
}
|
|
#overlay-arrowhead {
|
|
fill: white;
|
|
}
|
|
svg.level-editor-overlay g.overlay-connection {
|
|
stroke: white;
|
|
filter: url(#overlay-filter-outline);
|
|
}
|
|
svg.level-editor-overlay g.overlay-connection line.-arrow {
|
|
marker-end: url(#overlay-arrowhead);
|
|
}
|
|
svg.level-editor-overlay rect.overlay-camera {
|
|
stroke: #808080;
|
|
fill: #80808040;
|
|
pointer-events: auto;
|
|
}
|
|
svg.level-editor-overlay text {
|
|
/* Each cell is one "pixel", so text needs to be real small */
|
|
font-size: 1px;
|
|
}
|
|
svg.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(220, 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(var(--main-hue), 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 #editor-statusbar {
|
|
grid-area: status;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5em;
|
|
/* Try very hard to minimize reflow, since this is updated frequently */
|
|
height: 1.25em;
|
|
line-height: 1.25;
|
|
overflow: hidden;
|
|
}
|
|
#editor #editor-statusbar > .-zoom {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.25em;
|
|
width: 11.5em;
|
|
}
|
|
#editor #editor-statusbar > .-zoom > input {
|
|
width: 6em;
|
|
margin: 0;
|
|
}
|
|
#editor #editor-statusbar > .-zoom > output {
|
|
width: 4em;
|
|
}
|
|
#editor #editor-statusbar > .-cursor {
|
|
width: 5em;
|
|
}
|
|
|
|
.editor-level-browser {
|
|
display: grid;
|
|
grid: auto-flow auto / repeat(auto-fill, minmax(13em, 1fr)); /* 12em preview width + 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.--selected {
|
|
background: var(--generic-bg-selected-on-white);
|
|
outline: 1px solid var(--generic-border-selected-on-white);
|
|
}
|
|
.editor-level-browser li:hover {
|
|
background: var(--generic-bg-hover-on-white);
|
|
}
|
|
.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(var(--main-hue), 75%, 90%);
|
|
outline: 2px solid hsl(var(--main-hue), 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(var(--main-hue), 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%);
|
|
}
|