/* 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; } /* 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?cache=b3-445487d5"); } @font-face { font-family: "RecVarMono"; src: url("../font/Recursive_VF_1.085.woff2?cache=b3-445487d5"); font-variation-settings: "MONO" 1; } body, pre, code, kbd, button { font-family: "RecVar", sans-serif; line-height: 1.5; } body { font-size: 87.5%; } pre, code, kbd, button { font-size: 100%; } :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-slnt: 0; --recursive-casl: 0; --recursive-wght: 900; font-size: 3.5rem; font-feature-settings: var(--recursive-simplified-r) 0; } h2 { --recursive-slnt: 0; --recursive-casl: 0.5; --recursive-wght: 800; font-size: 2rem; } h3 { --recursive-slnt: 0; --recursive-casl: 0.5; --recursive-wght: 700; font-size: 1.5rem; } h4 { --recursive-slnt: 0; --recursive-casl: 0.5; --recursive-wght: 700; font-size: 1rem; } pre, code, kbd, th-literate-program { --recursive-mono: 1; --recursive-casl: 0; --recursive-slnt: 0; --recursive-wght: 450; } 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: 1rem; margin-bottom: 1rem; 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 the `new` link on the homepage */ a[data-cast~="new"] { flex-shrink: 0; color: var(--text-color); opacity: 50%; &.has-news { opacity: 100%; text-decoration: none; & .new-text { text-decoration: underline; } } & .badge { margin-left: var(--8px); text-decoration: none; } } /* Style new badges */ span.badge { --recursive-wght: 800; --recursive-slnt: 0; --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; & #version-info { flex-grow: 1; } & #footer-icon { flex-shrink: 0; } & #version-info { display: flex; flex-direction: row; align-items: center; justify-content: end; opacity: 50%; transition: var(--transition-duration) opacity; & .icon-history { display: inline-block; width: 32px; height: 32px; margin-right: 0.5rem; background-image: var(--icon-history); background-repeat: no-repeat; background-position: 50% 50%; } & > ul { display: flex; flex-direction: row; flex-wrap: wrap; justify-content: flex-end; margin: 0; padding-left: 0; list-style: none; opacity: 0%; transition: var(--transition-duration) opacity; } & > ul > li { flex-shrink: 0; } & > ul > li:not(:first-child)::before { content: "ยท"; text-decoration: none; display: inline-block; padding-left: 0.75em; padding-right: 0.75em; } & a { display: inline-block; color: var(--text-color); } &:hover > ul { opacity: 100%; } } & #footer-icon { & > a { display: block; } & > a > svg { display: block; color: var(--text-color); opacity: 40%; } } } @media (hover: none) { footer > #version-info { & > ul { opacity: 100%; } } } /* 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; } /* Funny joke */ @keyframes hello-there { 0% { opacity: 0%; } 70% { opacity: 0%; } 100% { opacity: 70%; } } .oops-you-seem-to-have-gotten-stuck { margin-top: 16px; display: none; position: absolute; opacity: 0%; } #index\:treehouse > details:not([open]) > summary .oops-you-seem-to-have-gotten-stuck { display: inline; animation: 4s hello-there forwards; } /* 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; }