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%, 20%); --button-bg-color: hsl(225, 10%, 25%); --button-bg-hover-color: hsl(225, 15%, 30%); } /* Generic element styling */ main[hidden] { display: none !important; } input[type=radio], input[type=checkbox], input[type=range] { margin: 0.125em; vertical-align: middle; } button { font-size: inherit; padding: 0.25em 0.5em; font-family: inherit; color: white; background: var(--button-bg-color); border: 1px solid hsl(225, 10%, 15%); box-shadow: inset 0 0 2px 1px hsl(225, 10%, 33%), 0 1px 0 hsl(225, 10%, 10%); border-radius: 0.25em; text-transform: lowercase; cursor: pointer; } button:hover { background: var(--button-bg-hover-color); } button:active { box-shadow: inset 0 0 2px 1px hsl(225, 10%, 33%); transform: translateY(1px); } 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; } 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; } a { color: #c0c0c0; } a:link, a:visited { text-decoration: underline dotted; } a:link { color: hsl(225, 50%, 60%); } a:visited { color: hsl(300, 50%, 60%); } a:link:hover, a:visited:hover { text-decoration: underline; } a:active { color: hsl(0, 50%, 60%); } svg.svg-icon { width: 1em; height: 1em; vertical-align: middle; stroke: none; fill: currentColor; } /* Overlay styling */ .overlay { display: flex; align-items: center; justify-content: center; position: fixed; top: 0; bottom: 0; left: 0; right: 0; background: #fff4; } .dialog { display: flex; flex-direction: column; min-width: 33%; max-width: 75%; max-height: 75%; 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 { overflow: auto; padding: 1em; } .dialog pre.error { color: #400000; background: #f0d0d0; padding: 0.5em 1em; } /* 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.--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: hsl(225, 60%, 85%); } table.level-browser tbody tr:nth-child(10n) td { border-bottom: 2px solid hsl(225, 20%, 80%); } /* Options dialog */ .dialog-options { height: 60%; width: 75%; } .dialog-options > section { flex: 1; } nav.tabstrip { display: flex; border-bottom: 1px solid #d0d0d0; } nav.tabstrip > a { margin: 0 0.5em; padding: 0.5em 1em; color: inherit; text-decoration: none; border-top-left-radius: 0.5em; border-top-right-radius: 0.5em; } nav.tabstrip > a:hover { background: #e8e8e8; } nav.tabstrip > a.--selected { background: #d0d0d0; } .dialog section.tabblock { display: none; overflow: auto; margin: 0.25em 0.5em; } .dialog section.tabblock.--selected { display: initial; } label.option { display: flex; align-items: center; padding: 0.25em; } label.option:hover { outline: 2px solid #d0d0d0; outline-radius: 2px; } 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%; } } /* Bits and pieces */ img.compat-icon { margin: 0 0.25em 0.125em; vertical-align: middle; } .compat-lynx, .compat-ms { font-size: 0.75em; display: inline-block; margin: 0 0.25em; padding: 0.25em; line-height: 1; vertical-align: middle; color: white; background: gray; border-radius: 0.25em; } /**************************************************************************************************/ /* 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[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; } #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 header" "intro intro intro" "stock upload yours" / 1fr 1fr 1fr ; gap: 1em; position: relative; padding: 1em 10%; margin: auto; overflow: auto; } #splash > .drag-overlay { display: none; justify-content: center; align-items: center; font-size: 10vmin; position: absolute; top: 0; bottom: 0; left: 1rem; right: 1rem; background: #fff2; border: 0.25rem dashed white; border-radius: 1rem; text-shadow: 0 1px 5px black; text-align: center; } #splash.--drag-hover > .drag-overlay { display: flex; } #splash > header { grid-area: header; text-align: center; } #splash > header img { display: block; margin: auto; } #splash > header h1 { font-size: 3em; } #splash h2 { border-bottom: 1px solid #404040; color: #909090; text-shadow: 0 1px #0004; } #splash > section { padding: 1em; background: var(--panel-bg-color); box-shadow: 0 0.25em 1em black; } #splash > #splash-intro { grid-area: intro; font-size: 18px; } #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; } /* Shrink logo and title */ #splash > header img { width: 48px; } #splash > header h1 { font-size: 2em; } } button.level-pack-button { display: grid; grid: "title score" "desc desc" / 1fr min-content ; padding: 0.5em; text-align: left; } 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; } /**************************************************************************************************/ /* Player */ #player { flex: 0; display: flex; flex-direction: column; justify-content: stretch; gap: 0.5em; margin: auto; /* center in both directions baby */ image-rendering: crisp-edges; image-rendering: pixelated; --tile-width: 32px; --tile-height: 32px; --scale: 1; } #player > .-main-area { isolation: isolate; display: grid; align-items: center; grid: "level chips" min-content "level time" min-content "level bonus" min-content "level message" 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: 0.125em solid black; } .level canvas { display: block; width: calc(var(--viewport-width) * var(--tile-width) * var(--scale)); --viewport-width: 9; --viewport-height: 9; } #player .overlay-message { grid-area: level; place-self: stretch; display: grid; grid-template-rows: 2fr 6fr 2fr 1fr; justify-content: center; align-items: center; z-index: 2; font-size: calc(0.5 * var(--tile-width) * var(--scale)); padding: 2%; background: #0009; color: white; text-align: center; text-shadow: 0 2px 1px black; } #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%); } 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: initial; } .message { grid-area: message; align-self: stretch; 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; /* FIXME find a way to enforce that the message never makes the grid get bigger */ overflow: auto; } .message:empty { display: none; } #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-music { grid-area: music; display: flex; gap: 1em; margin: 0 1em; text-transform: lowercase; color: #909090; } #player-music #player-music-left { /* allow me to wrap if need be */ flex: 1 0 0px; } #player-music #player-music-right { text-align: right; } #player-music #player-music-volume { width: 8em; } #player .controls { grid-area: controls; display: flex; } .play-controls, .demo-controls { display: flex; align-items: center; gap: 0.25em; } .play-controls { align-self: start; } .demo-controls { display: none; flex: 1; justify-content: flex-end; } main.--has-demo .demo-controls { display: flex; } /* Debug stuff */ #player-debug { display: none; background-image: repeating-linear-gradient(135deg, hsl(0, 0%, 12.5%) 0em, hsl(0, 0%, 12.5%) 1em, hsl(45, 25%, 12.5%) 1em, hsl(45, 25%, 12.5%) 2em); } .input { display: grid; display: none; grid: "drop up cycle" 1.5em "left swap right" 1.5em ". down . " 1.5em / 1.5em 1.5em 1.5em ; gap: 0.5em; } .input-action { padding: 0.25em; line-height: 1; color: #fff4; background: #202020; } .input-action[data-action=up] { grid-area: up; } .input-action[data-action=down] { grid-area: down; } .input-action[data-action=left] { grid-area: left; } .input-action[data-action=right] { grid-area: right; } .input-action[data-action=swap] { grid-area: swap; } .input-action[data-action=cycle] { grid-area: cycle; } .input-action[data-action=drop] { grid-area: drop; } .input-action.--pressed { color: white; background: hsl(225, 75%, 25%); } @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 > .-main-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) / 1fr 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 .message { /* 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 .controls .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 / calc((32px + 4px) * 8) 1fr ; gap: 0.5em; min-height: 0; margin: auto 1em; } #editor .level { grid-area: level; position: relative; overflow: auto; /* Padding and background make it easier to tell when we're at the edge of the map */ /* TODO padding should be half a cell, and svg should respect it too */ /* padding: 1em; */ background: #202020; } /* SVG overlays */ #editor svg.level-editor-overlay { position: absolute; top: 0; left: 0; /* FIXME get real size */ width: 1024px; height: 1024px; /* allow clicks to go through us! */ pointer-events: none; /* default svg properties */ stroke-width: 0.0625; fill: none; } #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 .controls { grid-area: controls; display: grid; grid: "toolbar layer direction menu" auto "hint hint hint hint" 1.5em ; } #editor .controls #editor-toolbar { grid-area: toolbar; } #editor .controls .-buttons { grid-area: menu; } #editor .controls #editor-tool-help { grid-area: hint; } .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; } .icon-button-set button.-selected { background-image: url(icons/tool-bg-selected.png); } .icon-button-set button img { display: block; } #editor .palette { grid-area: palette; min-width: 20vw; padding-right: 0.25em; /* in case of scrollbar */ 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; grid: auto-flow 32px / repeat(auto-fit, 32px); gap: 4px; } .palette-entry { margin: 0.25em; } .palette-entry.--selected { box-shadow: 0 0 0 1px black, 0 0 0 2px white; }