treehouse/static/css/main.css
liquidex 6d3037791a make the command line a bit more accessible by including a :| icon at the bottom
also add a few extra commands for navigating around the house
2024-12-10 20:41:14 +01:00

986 lines
17 KiB
CSS

/* Lay out the main containers. */
body {
--top-min-spacing: 40px;
margin: 0;
display: grid;
grid-template-columns:
[left] minmax(
0,
clamp(80px, calc(100vw - (1920px - 360px - 160px)), 160px)
)
[center] minmax(0, auto)
[right] minmax(0, calc(100vw - (1920px - 360px)));
grid-template-rows:
[top] minmax(
clamp(
var(--top-min-spacing),
calc(100vw - (1920px - 360px - 160px)),
128px
),
min-content
)
[title] minmax(6rem, min-content)
[main] 1fr
[bottom] min-content;
}
html {
/* Try to always leave a bunch of empty space at the bottom, but don't overdo it.
It's kind of awkward when you scroll to the bottom and your page just turns blank. */
--virtual-space-ratio: 1.75;
height: calc(100% * var(--virtual-space-ratio));
}
body {
min-height: calc(100% / var(--virtual-space-ratio));
}
.noscript {
grid-row: top;
grid-column: center;
}
#nav-logo {
grid-row: title;
grid-column: left;
align-self: center;
justify-self: end;
}
section.page-header {
grid-row: title;
grid-column: center;
align-self: center;
}
main {
grid-row: main;
grid-column: center / center;
margin-right: 8px;
}
footer {
grid-row: bottom;
grid-column: center / center;
}
@media (max-width: 1200px) {
main {
grid-column: left / -1;
}
footer {
grid-column: 1 / -1;
}
}
@media (max-width: 450px) {
body {
--top-min-spacing: 0px;
}
section.page-header {
grid-column: 1 / -1;
}
nav#nav-logo {
display: none;
}
}
/* Choose more pretty colors than vanilla HTML */
body {
background-color: var(--background-color);
color: var(--text-color);
}
:root {
scrollbar-color: var(--border-2) var(--shaded-background);
scrollbar-width: auto;
scrollbar-gutter: stable;
}
:focus-visible {
outline: 1px solid var(--liquidex-brand-blue);
outline-offset: 2px;
}
/* Set up typography */
@font-face {
font-family: "RecVar";
/* NOTE: I put the hash in here manually instead of adding the complexity of piping CSS through
Handlebars because I don't really think it's worth it for this single asset.
Other assets are referenced rarely enough that caching probably isn't gonna make too much of
an impact.
It's unlikely I'll ever update the font anyways, so eh, whatever. */
src: url("../font/Recursive_VF_1.085.woff2?v=b3-445487d5");
}
@font-face {
font-family: "RecVarMono";
src: url("../font/Recursive_VF_1.085.woff2?v=b3-445487d5");
font-variation-settings: "MONO" 1;
}
body,
pre,
code,
kbd,
button,
select,
input,
dfn {
font-family: "RecVar", sans-serif;
font-style: normal;
line-height: 1.5;
}
body {
font-size: 87.5%;
}
pre,
code,
kbd,
button,
select,
input {
font-size: inherit;
}
:root {
--recursive-mono: 0;
--recursive-casl: 1;
--recursive-wght: 400;
--recursive-slnt: 0;
--recursive-crsv: 0.5;
--recursive-simplified-f: "ss03";
--recursive-simplified-g: "ss04";
--recursive-simplified-l: "ss05";
--recursive-simplified-r: "ss06";
--recursive-no-serif-L-Z: "ss08";
}
*,
*:before,
*:after {
font-variation-settings:
"MONO" var(--recursive-mono),
"CASL" var(--recursive-casl),
"wght" var(--recursive-wght),
"slnt" var(--recursive-slnt),
"CRSV" var(--recursive-crsv);
font-feature-settings: var(--recursive-simplified-f),
var(--recursive-simplified-g), var(--recursive-simplified-l),
var(--recursive-simplified-r), var(--recursive-no-serif-L-Z);
}
h1 {
--recursive-casl: 0;
--recursive-wght: 900;
font-size: 3.5rem;
font-feature-settings: var(--recursive-simplified-r) 0;
}
h2 {
--recursive-casl: 0.5;
--recursive-wght: 800;
font-size: 2rem;
}
h3 {
--recursive-casl: 0.5;
--recursive-wght: 700;
font-size: 1.5rem;
}
h4 {
--recursive-casl: 0.5;
--recursive-wght: 700;
font-size: 1rem;
}
pre,
code,
kbd,
th-literate-program {
--recursive-mono: 1;
--recursive-casl: 0;
--recursive-wght: 450;
}
strong code {
--recursive-wght: 800;
}
b,
strong {
--recursive-wght: 700;
}
i,
em {
--recursive-slnt: -16;
font-style: normal;
}
h1,
h2,
h3,
h4,
h5,
h6 {
text-wrap: balance;
}
/* Lay out elements a bit more compactly */
p,
pre {
margin: 0 0;
}
h1,
h2,
h3,
h4,
h5,
h6 {
margin: var(--4px) 0;
}
/* Make code examples a little prettier by giving them visual separation from the rest of the page */
code,
th-literate-program {
padding: var(--3px) var(--4px);
background-color: var(--shaded-background);
border-radius: 0.4em;
}
th-literate-program,
th-literate-output {
display: block;
}
kbd {
padding: var(--3px) var(--6px);
border: var(--1px) solid var(--border-1);
border-radius: 0.4em;
}
pre,
th-literate-program {
padding: var(--8px) var(--12px);
margin: var(--12px) 0;
background-color: var(--shaded-background);
border-radius: 0.5em;
transition: background-color var(--transition-duration);
}
@media (prefers-color-scheme: light) {
pre,
th-literate-program {
background-color: transparent;
border: var(--1px) solid var(--border-1);
}
}
pre > code,
th-literate-program > code {
padding: 0;
background: none;
border-radius: 0;
}
th-literate-program {
white-space: pre;
}
/* And don't let code examples fly off and overflow the window */
pre,
th-literate-program {
min-width: 0;
width: auto;
overflow: auto;
}
/* Also don't let images get out of hand */
img {
max-width: 100%;
}
/* Also regarding images - make them look a bit more pretty by default */
img.pic {
border-radius: var(--6px);
margin: var(--8px) 0;
}
/* Image hints for tweaking rendering */
img {
&[src*="+pixel"] {
image-rendering: pixelated;
border-radius: 0;
}
/* TODO: These could be autogenerated! */
&[src*="+width72"] {
width: 72px;
height: auto;
}
&[src*="+width160"] {
width: 160px;
height: auto;
}
&[src*="+width640"] {
width: 640px;
height: auto;
}
&[src*="+width752"] {
width: 752px;
height: auto;
}
/* Resources for use in JavaScript. */
&.resource {
display: none;
}
}
/* Fix the default blue and ugly purple links normally have */
a {
color: var(--link-color);
}
a:visited {
color: var(--link-color-visited);
}
/* Allow for some secret links */
a.secret {
color: var(--text-color);
text-decoration: none;
}
/* Make blockquotes a bit prettier */
blockquote {
margin: 0;
padding: var(--4px) var(--12px);
margin: var(--4px) 0;
border-left: var(--4px) solid var(--border-1);
}
/* And tables. */
table {
margin: var(--8px) 0;
}
table,
th,
td {
border: var(--1px) solid var(--border-2);
border-collapse: collapse;
padding: var(--4px) var(--10px);
}
th {
background-color: var(--shaded-background);
--recursive-wght: 700;
--recursive-casl: 0.5;
}
/* Horizontal rules */
hr {
width: 100%;
border: none;
border-top: var(--1px) solid var(--border-1);
margin-top: 2em;
margin-bottom: 2em;
}
/* Style the noscript box a little more prettily. */
.noscript {
padding: var(--16px);
background-color: #fde748;
color: var(--text-color-light);
border: var(--1px) solid #6c581c;
border-radius: var(--8px);
width: fit-content;
margin-left: auto;
margin-right: auto;
margin-top: 16px;
margin-bottom: 16px;
}
.noscript:empty {
display: none;
}
.noscript p {
margin-top: 0;
margin-bottom: var(--16px);
}
.noscript p:last-child {
margin-bottom: 0;
}
.noscript a {
color: var(--link-color-light);
}
.noscript a:visited {
color: var(--link-color-visited-light);
}
/* Navigation button */
#nav-logo {
width: min-content;
height: min-content;
}
#nav-logo .logo {
width: 64px;
height: 64px;
display: block;
opacity: 100%;
color: var(--text-color);
}
/* Navigation header (contains page title & breadcrumbs) */
h1.page-title {
--recursive-wght: 850;
margin-top: 0.2rem;
margin-bottom: 0.2rem;
margin-left: 2.25rem;
font-size: 2.5rem;
& a {
color: var(--text-color);
text-decoration: underline;
text-decoration-color: transparent;
transition: var(--transition-duration) text-decoration-color;
&:hover {
text-decoration-color: var(--text-color);
}
}
}
@media (hover: none) {
h1.page-title a {
text-decoration: underline;
}
}
/* Style badges */
span.badge {
--recursive-wght: 800;
--recursive-mono: 1;
--recursive-casl: 0;
border-radius: 999px;
padding: var(--2px) var(--6px);
font-size: 0.9em;
&.red {
color: white;
background-color: #d01243;
}
&.blue {
color: white;
background-color: #058ef0;
}
&.before-content {
margin-right: var(--6px);
}
}
/* Style the footer */
footer {
padding-left: 1rem;
padding-right: 1rem;
margin-top: 4rem;
padding-bottom: 4rem;
display: flex;
flex-direction: row;
& > .left {
flex-grow: 1;
}
& > .right {
flex-shrink: 0;
}
& #footer-icon {
display: block;
& > svg {
display: block;
color: var(--text-color);
opacity: 40%;
}
}
& #open-command-line {
width: 32px;
height: 32px;
background: none;
border: none;
padding: 0;
background-image: var(--icon-cmd);
background-repeat: no-repeat;
background-position: 50% 50%;
opacity: 50%;
transition: var(--transition-duration) opacity;
&:hover {
opacity: 100%;
}
&:active {
opacity: 75%;
}
}
}
@media (hover: none) {
footer > #version-info {
& > ul {
opacity: 100%;
}
}
}
/* Style dialogues */
dialog[open] {
position: fixed;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
color: var(--text-color);
background-color: var(--background-color);
border: 1px solid var(--border-1);
border-radius: 12px;
}
/* Style emojis to be readable */
img[data-cast~="emoji"] {
max-width: 1.5em;
max-height: 1.5em;
vertical-align: bottom;
object-fit: contain;
}
/* And also style emoji tooltips. */
th-emoji-tooltip {
display: flex;
flex-direction: column;
align-items: center;
position: fixed;
transform: translateX(-50%) translateY(-10%) scale(0.8);
width: max-content;
z-index: 100;
background-color: var(--background-color-tooltip);
padding: var(--8px);
margin-top: var(--8px);
border-radius: var(--6px);
transition:
opacity var(--transition-duration) cubic-bezier(0.22, 1, 0.36, 1),
filter var(--transition-duration) cubic-bezier(0.22, 1, 0.36, 1),
transform var(--transition-duration) cubic-bezier(0.22, 1, 0.36, 1);
opacity: 0%;
filter: blur(var(--3px));
pointer-events: none;
}
th-emoji-tooltip.transitioned-in {
opacity: 100%;
filter: blur(0);
transform: translateX(-50%) scale(1);
}
th-emoji-tooltip img {
display: block;
max-width: 4.5rem;
max-height: 4.5rem;
}
th-emoji-tooltip p {
--recursive-wght: 550;
color: var(--text-color);
font-size: 0.9em;
margin: 0;
padding-top: 6px;
line-height: 1;
}
.th-emoji-unknown {
text-decoration: 1px underline var(--error-color);
cursor: help;
}
/* Command line */
th-command-line {
--recursive-mono: 1;
--recursive-casl: 0;
display: none;
flex-direction: column;
background-color: var(--background-color-tooltip);
font-size: 87.5%;
&.visible {
display: flex;
position: fixed;
left: 0;
bottom: 0;
width: 100%;
}
& > .input-wrapper {
display: flex;
flex-direction: row;
align-items: center;
padding: 0 4px;
width: 100%;
&::before {
content: ":";
padding-right: 2px;
opacity: 50%;
}
& > input {
background: none;
color: var(--text-color);
border: none;
flex-grow: 1;
padding: 2px 0;
&:focus {
outline: none;
}
}
}
& > ul.suggestions {
list-style: none;
display: flex;
flex-direction: column;
margin: 0;
padding: 0;
max-height: 25vh;
overflow: auto;
& > li {
padding: 2px 8px;
cursor: default;
& > dfn {
--recursive-crsv: 0;
--recursive-wght: 700;
margin-right: 2ch;
}
&:hover,
&.tabbed {
background-color: var(--liquidex-brand-blue);
color: white;
}
&.immediate {
cursor: pointer;
}
}
}
}
@media (hover: none) {
th-command-line {
& > ul.suggestions > li {
border-bottom: 1px solid var(--border-1);
}
}
}
@media (pointer: coarse) {
th-command-line {
& > .input-wrapper > input {
padding: 8px 0;
}
& > ul.suggestions > li {
padding: 8px 8px;
}
}
}
/* Literate programming support */
:root {
--error-color: #d94141;
}
@media (prefers-color-scheme: dark) {
:root {
--error-color: #e39393;
}
}
th-literate-program[data-mode="input"] {
/* Override the cursor with an I-beam, because the editor captures clicks and does not bubble
them back up to the caller */
cursor: text;
}
th-literate-program[data-mode="output"] {
padding: 0;
background: none;
border: none;
border-radius: 0;
& iframe,
& img.placeholder-image {
border-style: none;
border-radius: 4px;
display: block;
}
& iframe {
width: 100%;
}
& img.placeholder-image.js {
transition: opacity var(--transition-duration);
}
& iframe,
& img.placeholder-image.loading {
opacity: 50%;
}
& iframe.loaded {
opacity: 100%;
}
/* The inner iframe is hidden until something requests display. */
& iframe.hidden {
display: none;
}
& pre > code {
display: block;
}
& pre.error {
color: var(--error-color);
position: relative;
&:empty {
display: none;
}
&::after {
content: "Error";
padding: var(--8px);
position: absolute;
right: 0;
top: 0;
color: var(--text-color);
opacity: 50%;
}
}
& pre.console,
& pre.placeholder-console {
position: relative;
margin-top: 0;
margin-bottom: 0;
&:empty {
display: none;
}
&::after {
content: "Console";
padding: var(--8px);
position: absolute;
right: 0;
top: 0;
color: var(--text-color);
opacity: 50%;
}
}
}
/* Syntax highlighting */
:root {
--syntax-comment: #9b8580;
--syntax-identifier: var(--text-color);
--syntax-keyword1: #e15e2b;
--syntax-keyword2: #199aca;
--syntax-operator: #e3755b;
--syntax-function: #d57b07;
--syntax-literal: #a64fb3;
--syntax-string: #79ac3b;
--syntax-punct: #a28680;
}
@media (prefers-color-scheme: dark) {
:root {
--syntax-comment: #aca8a4;
--syntax-identifier: var(--text-color);
--syntax-keyword1: #ffb06a;
--syntax-keyword2: #8ad4f9;
--syntax-operator: #ec9f8d;
--syntax-function: #fbd283;
--syntax-literal: #e9b9f0;
--syntax-string: #b0dd7a;
--syntax-punct: #9d9a96;
}
}
.th-syntax-highlighting span {
&.comment {
--recursive-slnt: -16;
color: var(--syntax-comment);
}
&.identifier {
color: var(--syntax-identifier);
}
&.keyword1 {
color: var(--syntax-keyword1);
}
&.keyword2 {
color: var(--syntax-keyword2);
}
&.operator {
color: var(--syntax-operator);
}
&.function {
color: var(--syntax-function);
}
&.literal {
color: var(--syntax-literal);
}
&.string {
color: var(--syntax-string);
}
&.punct {
color: var(--syntax-punct);
}
&.error {
color: var(--error-color);
text-decoration: wavy underline;
}
&.hidden {
display: none;
}
&.type-hint {
color: var(--syntax-comment);
font-size: 80%;
}
}
.th-syntax-highlighting {
& .export {
text-decoration: underline dotted;
cursor: help;
text-decoration-color: transparent;
transition: text-decoration-color var(--transition-duration);
}
&:hover,
&:focus {
& .export {
text-decoration-color: var(--syntax-keyword1);
}
}
}
/* Style settings sections */
section[data-cast~="settings"] {
/* Don't display settings when JavaScript is disabled.
JS overrides this value on the element itself. */
display: none;
}