// ================================ // GLOBAL PAGE STYLES AND VARIABLES // ================================ :root { --color-black: #000000; --color-white: #ffffff; --color-fog: #eeeeee; --color-parchment: #faefe2; --color-cloud: #d9e1e4; --color-mustard: #e5c299; --color-navy: #16323f; --color-walnut: #473a3a; --color-slate: #3a4047; --color-crimson: #803847; --color-lilac: #cabdc8; // --color-lime: #c5e0af; --color-lemon: #efe2b2; --color-peach: #ebb29f; --color-ale: #cd8f7a; // --color-flamingo: #d2697c; --color-seaside: #b0d6cb; --color-seaside-rgb: 176, 214, 203; // --color-cove: #83c0b9; --color-sage: #91b99a; --color-storm: #627088; --max-width: 1200px; --max-width-plus-padding: calc(var(--max-width) + 40px * 2); --max-extended-width: 1600px; --max-width-reading-material: 800px; --variable-px: Min(1px, 0.15vw); --page-edge-padding: 40px; --border-thickness: 2px; --font-size-link: calc(1rem * 4 / 3); } html, body { color: var(--color-navy); background: var(--color-white); font-family: "Inter", sans-serif; line-height: 1.5; font-weight: 500; font-size: 18px; tab-size: 4; width: 100%; height: 100%; margin: 0; } @media screen and (max-width: 780px) { :root { --font-size-link: calc(1rem * 24 / 18); --page-edge-padding: 28px; --border-thickness: 1px; } html, body { font-size: 16px; } } @media print, screen and (max-width: 500px) { :root { --page-edge-padding: 20px; } } // ================== // GLOBAL PAGE LAYOUT // ================== body > .page { box-sizing: border-box; min-width: 320px; header { padding: 0 var(--page-edge-padding); color: var(--color-walnut); position: relative; z-index: 1000; nav { margin: auto; max-width: var(--max-width); .row { display: flex; justify-content: space-between; --nav-padding-above-below: 30px; padding-top: var(--nav-padding-above-below); padding-bottom: calc(var(--nav-padding-above-below) - 16px); margin-bottom: calc(var(--nav-padding-above-below) - 16px); // Covers up content that extends up underneath the header background: white; @media screen and (max-width: 780px) { --nav-padding-above-below: 24px; } .left, .right { z-index: 1; display: flex; align-items: center; gap: 40px; a { font-family: "Bona Nova", Palatino, serif; font-feature-settings: "lnum"; line-height: 1.25; font-weight: 700; text-decoration: none; --height: 60px; --button-padding: 24px; --nav-font-size: 28px; // Keep up to date with `NAV_BUTTON_INITIAL_FONT_SIZE` in navbar.js font-size: var(--nav-font-size); &.button { min-height: 0; height: var(--height); padding-left: var(--button-padding); padding-right: var(--button-padding); line-height: calc(var(--height) - 2 * var(--border-thickness)); font-size: var(--nav-font-size); &::before { content: none; } } &:not(.button) { color: inherit; } img { display: block; width: var(--height); height: var(--height); } } &.left img { // Don't show the alt text if the image doesn't load font-size: 0; } @media screen and (max-width: 1200px) { gap: 30px; a { --height: 50px; --button-padding: 16px; --nav-font-size: 24px; } } @media screen and (max-width: 1000px) { gap: 30px; a { --button-padding: 14px; --nav-font-size: 20px; } } @media print, screen and (max-width: 900px) { gap: 20px; a { --height: 40px; --button-padding: 13px; --nav-font-size: 18px; } } @media print, screen and (max-width: 780px) { gap: 20px; a { --button-padding: 12px; --nav-font-size: 16px; } } @media screen and (max-width: 680px) { gap: 16px; a { --height: 30px; --button-padding: 8px; --nav-font-size: 14px; } } @media screen and (max-width: 580px) { gap: 12px; a { --height: 24px; --nav-font-size: 13px; } } @media screen and (max-width: 520px) { gap: 10px; a { --height: 22px; --button-padding: 6px; --nav-font-size: 12px; } } @media screen and (max-width: 460px) { gap: 8px; a { --height: 20px; --button-padding: 4px; --nav-font-size: 11px; } } @media screen and (max-width: 420px) { gap: 6px; a { --nav-font-size: 10px; } } @media screen and (max-width: 380px) { gap: 6px; a { --nav-font-size: 9px; } } @media screen and (max-width: 350px) { gap: 6px; a { --nav-font-size: 8px; } } } } } .ripple { display: block; background: none; // Covers up content that extends up underneath the header fill: white; stroke: currentColor; --ripple-height: 16px; height: var(--ripple-height); margin-top: calc(-1 * var(--ripple-height) + var(--border-thickness)); margin-bottom: calc(-1 * var(--border-thickness)); stroke-width: var(--border-thickness); &::before, &::after { content: none; } } hr { background: none; } @media screen and (max-width: 1400px) { .ripple { width: calc(100% + (var(--page-edge-padding) * 2)); margin-left: calc(-1 * var(--page-edge-padding)); margin-right: calc(-1 * var(--page-edge-padding)); } hr { display: none; } } } main { padding: calc(120 * var(--variable-px)) var(--page-edge-padding); > section { max-width: var(--max-width); margin-left: auto; margin-right: auto; // Puts the content in front of the hexagon decoration position: relative; z-index: 1; ~ section { margin-top: calc(120 * var(--variable-px)); } p img { max-width: 100%; } pre { box-sizing: border-box; overflow: auto; } details { width: 100%; } } } footer { display: flex; flex-direction: column; align-items: center; padding: 40px; padding-top: 0; color: var(--color-walnut); @media screen and (max-width: 1400px) { hr { width: 100%; &::before, &::after { border: none; background: currentColor; width: calc(var(--page-edge-padding) + 40px); height: var(--border-thickness); } } } nav { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px 40px; margin-top: 40px; a { color: var(--color-walnut); } @media screen and (max-width: 900px) { max-width: 500px; } @media screen and (max-width: 780px) { max-width: 440px; } @media screen and (max-width: 400px) { gap: 6px 20px; } } span { text-align: center; margin-top: 40px; } } } // ===================== // ELEMENT SPACING RULES // ===================== :is(h1, h2, h3, h4, article > :first-child) ~ :is(p, ul, ol, ol li p, img, a:has(> img:only-child)), :is(h1, h2, h3, h4, article > :first-child) ~ :is(ul, ol) li p + img, :is(h1, h2, h3, h4, p) ~ .feature-icons, p ~ :is(h1, h2, h3, h4, details summary, blockquote, .image-comparison, .video-background, .video-embed), .video-embed + :is(p, .link, .button), p + p > .button, p + :is(.link, section), img + .link, article { margin-top: 20px; } * { min-width: 0; min-height: 0; } // ================================== // HEADER AND TEXT ELEMENT TAG STYLES // ================================== h1 { font-size: calc(1rem * 8 / 3); font-family: "Bona Nova", Palatino, serif; font-feature-settings: "lnum"; line-height: 1.25; font-weight: 700; display: inline-block; margin: 0; ~ h2 { margin-top: 40px; } ~ hr { margin-top: 40px; margin-bottom: 20px; } } h2, h3, h4, h5, h6 { font-family: "Inter", sans-serif; line-height: 1.5; font-weight: 800; display: inline-block; margin: 0; } h2 { font-size: calc(1rem * 16 / 9); font-weight: 700; } h3 { font-size: calc(1rem * 4 / 3); } h4, h5, h6 { font-size: 1rem; } p { margin: 0; text-align: justify; text-justify: inter-character; // Only supported in Firefox -webkit-hyphens: auto; hyphens: auto; code { text-justify: auto; } } h1, h2, h3, h4, h5, h6, p { ~ img, ~ iframe, ~ a > img:only-child { width: 100%; height: auto; } } a { color: var(--color-crimson); } // ======================== // OTHER ELEMENT TAG STYLES // ======================== img { vertical-align: top; } table { margin: 20px -20px; width: calc(100% + 40px); th, td { border: 20px solid transparent; vertical-align: top; margin: 0; padding: 0; } th:not(:first-child) img, td:not(:first-child) img { max-width: 100%; } th:empty { border: none; } } ul, ol { margin: 0; + p { margin-top: 0; } li { margin-top: 0.5em; } } hr { // Reset Firefox user agent style that is overriding `currentColor` that we set color: unset; } code { color: var(--color-black); background: var(--color-fog); padding: 0 4px; overflow-wrap: anywhere; -webkit-hyphens: none; hyphens: none; a & { color: var(--color-crimson); } } pre { display: flex; max-width: 100%; color: var(--color-fog); // This zero transform sets this element as the root for `position: fixed` transform: translate(0); // Color overrides &, &.z-code { background: var(--color-navy); .z-path { color: #679f70; span { color: #e6e1dc; } } } // Container for the element (span or table) containing the lines of code code { background: initial; color: inherit; display: block; overflow-x: auto; padding: 20px; width: 0; flex: 1 1 auto; } // Language name in top right corner &[data-lang] { padding-top: 28px; &::before { content: attr(data-lang); color: rgba(var(--color-seaside-rgb), 0.5); text-transform: lowercase; font-family: "Inter", sans-serif; font-size: 0.75em; font-weight: 700; font-style: italic; -webkit-user-select: none; user-select: none; pointer-events: none; position: fixed; top: 0; line-height: 28px; display: block; width: 100%; text-indent: 20px; background: rgba(0, 0, 0, 0.25); &[data-lang="sh"] { content: "Shell"; } &[data-lang="rs"] { content: "Rust"; } &[data-lang="js"] { content: "JavaScript"; } &[data-lang="ts"] { content: "TypeScript"; } } } // Code blocks with line numbers &[data-linenos] table { border-spacing: 0; margin: -20px; tr { &:first-child td { padding-top: 20px; } &:last-child td { padding-bottom: 20px; } td { &:first-child { padding-left: 20px; padding-right: 10px; -webkit-user-select: none; user-select: none; vertical-align: top; text-align: right; background: rgba(0, 0, 0, 0.25); } &:last-child { padding-left: 10px; padding-right: 20px; } } } } } kbd { outline: calc(var(--border-thickness) / 2) solid var(--color-navy); padding: 0 8px; margin: 0 4px; color: inherit; font-family: inherit; } summary { cursor: pointer; } hr { overflow: visible; } hr, .ripple { width: calc(100% - 32px * 2); height: var(--border-thickness); margin: 0 32px; background: currentColor; position: relative; border: none; &::before { left: -40px; border-width: 0 0 var(--border-thickness) 40px; } &::after { right: -40px; border-width: 0 40px var(--border-thickness) 0; } &::before, &::after { content: ""; display: block; width: 0; height: 0; position: absolute; border-color: transparent transparent currentColor transparent; border-style: solid; } } // Using this requires adding this line to the page's frontmatter: // css_external = ["https://fonts.googleapis.com/css2?family=Noto+Color+Emoji&display=swap"] .emoji { font-family: "Noto Color Emoji", sans-serif; font-style: normal; } // ======= // LAYOUTS // ======= .reading-material.reading-material { max-width: var(--max-width-reading-material); article { width: 100%; h2 { margin-top: 80px; } h3 { margin-top: 40px; } h4 { margin-top: 20px; } h1, h2, h3, h4, h5, h6 { display: block; &:first-child { margin-top: 0; } } // Captions below images in blog posts p:has(> img) + center:has(> em) { margin-top: 10px; } p ~ img { width: auto; max-width: 100%; } hr { margin-top: 40px; margin-bottom: 40px; } + hr { margin-top: calc(80 * var(--variable-px)); margin-bottom: calc(40 * var(--variable-px)); } } } // .graphic { // max-width: 200px; // flex: 1 1 100%; // display: flex; // img { // display: block; // width: 100%; // object-fit: contain; // @media screen and (max-width: 800px) { // width: auto; // height: 120px; // } // } // } .block { display: flex; flex-direction: column; align-items: flex-start; width: 100%; &.centered { align-items: center; } } :not(.diptych, .triptych) > :is(.block, .diptych, .triptych) + :is(.block, .diptych, .triptych) { margin-top: calc(120 * var(--variable-px)); } .feature-box-narrow, .feature-box-outer { padding: calc(80 * var(--variable-px)); background-image: url("https://static.graphite.rs/textures/noise.png"); background-blend-mode: overlay; background-position: center; } :where(h1, h2, h3, h4, p) + .feature-box-narrow { margin-top: calc(40 * var(--variable-px)); } .feature-box-full-image { width: calc(100% + 2 * 80 * var(--variable-px)); height: auto; margin-left: calc(-80 * var(--variable-px)); margin-top: calc(-80 * var(--variable-px)); margin-bottom: calc(40 * var(--variable-px)); display: block; } .feature-box-outer { @media screen and (max-width: 1000px) { &.feature-box-outer { margin-left: calc(-1 * var(--page-edge-padding)); margin-right: calc(-1 * var(--page-edge-padding)); padding-left: var(--page-edge-padding); padding-right: var(--page-edge-padding); } } &.feature-box-outer { max-width: unset; } .feature-box-inner { max-width: var(--max-width); margin: 0 auto; } } h1.feature-box-header.feature-box-header { &, & a { font-family: "Inter", sans-serif; line-height: 1.5; font-weight: 800; text-transform: uppercase; font-size: calc(1rem * 14 / 9); } span { white-space: pre; } ~ hr { margin-top: 20px; margin-bottom: 40px; + p { margin-top: 0; } } } .diptych, .triptych { display: flex; flex-wrap: wrap; gap: calc(80 * var(--variable-px)); .block { flex: 1 1 0; } img[alt=""] { display: block; &::after { content: ""; display: block; width: 100%; height: 240px; background: var(--color-crimson); } } } .diptych .block { min-width: 320px; } .triptych .block { min-width: 280px; } @media screen and (max-width: 520px) { .diptych .block { min-width: 200px; } .triptych .block { min-width: 280px; } } // ======================== // COMMON SIMPLE COMPONENTS // ======================== .link { display: inline-block; font-size: var(--font-size-link); font-weight: 800; text-decoration: none; color: var(--color-crimson); white-space: nowrap; &:not(.not-uppercase) { text-transform: uppercase; } } .button { display: inline-block; border: var(--border-thickness) solid currentColor; min-height: calc(var(--font-size-link) * 2); font-size: var(--font-size-link); padding: 0 var(--font-size-link); box-sizing: border-box; text-align: left; text-decoration: none; font-weight: 800; color: var(--color-crimson); &::before { content: ""; line-height: calc(var(--font-size-link) * 2 - 2 * var(--border-thickness)); } img { height: calc(var(--font-size-link) * 1.5); margin-right: calc(var(--font-size-link) / 2); } img, span { vertical-align: middle; } } .arrow::after { content: " ยป"; font-family: "Inter", sans-serif; } .demo-artwork { display: flex; align-items: center; justify-content: center; margin-top: 20px; > a { flex: 0 0 auto; img { height: 128px; border: 12px solid var(--color-walnut); vertical-align: top; flex: 0 0 auto; } } p { display: flex; flex-direction: column; max-width: 300px; margin-left: 40px; text-align: left; } } .video-embed { position: relative; width: 100%; &.aspect-16x9 { padding-top: calc(100% / (16 / 9)); } img, iframe { position: absolute; width: 100%; height: 100%; top: 0; left: 0; } img { cursor: pointer; } } .video-background { position: relative; font-size: 0; video { max-width: Min(100%, 1280px); } // Uses a white border over the video to cover up the edges of the video which, due to a Chrome rendering bug, displays black edges sometimes when scrolling &::after { content: ""; position: absolute; inset: 0; border: 2px solid white; pointer-events: none; } } // blockquote { // padding: 32px 80px; // background: rgba(0, 0, 0, 0.0625); // position: relative; // border-left: 4px solid var(--color-navy); // &::before, // &::after { // content: ""; // position: absolute; // width: 52px; // height: 40px; // background-image: url('data:image/svg+xml;utf8,\ // \ // '); // } // &::before { // top: 16px; // left: 16px; // } // &::after { // transform: rotate(180deg); // bottom: 16px; // right: 16px; // } // } // ========================= // COMMON COMPLEX COMPONENTS // ========================= .image-comparison { position: relative; touch-action: pan-y pinch-zoom; max-width: Min(100%, 512px); .crop-container { height: 100%; &:nth-child(2) { overflow: hidden; width: calc(100% - var(--comparison-percent)); &, img { position: absolute; top: 0; right: 0; } } &.crop-container.crop-container { img { display: block; width: auto; height: 100%; } &:first-child img { width: 100%; } } } .slide-bar { position: absolute; background: var(--color-navy); margin-left: -2px; width: 4px; height: 100%; top: 0; left: var(--comparison-percent); box-shadow: 0 0 2px rgba(255, 255, 255, 0.5); .arrows { position: absolute; top: calc(50% - (40px / 2)); left: calc(4px / 2); width: 0; height: 0; opacity: 1; transition: opacity 0.25s; svg { position: absolute; width: 6.5px; height: 11px; top: calc(-11px / 2); fill: var(--color-white); @keyframes pulse-left { from { transform: translateX(3px); } to { transform: translateX(-3px); } } @keyframes pulse-right { from { transform: scaleX(-1) translateX(3px); } to { transform: scaleX(-1) translateX(-3px); } } @keyframes pulse-opacity { 0% { opacity: 0; } 40% { opacity: 1; } 90% { opacity: 1; } 100% { opacity: 0; } } &:nth-of-type(1) { right: 6px; animation: 3s infinite ease-out pulse-left, 3s infinite ease-out pulse-opacity; } &:nth-of-type(2) { left: 6px; animation: 3s infinite ease-out pulse-right, 3s infinite ease-out pulse-opacity; } } div { content: ""; position: absolute; background: var(--color-navy); top: 0; left: 0; width: 32px; height: 32px; transform: translate(-50%, -50%) rotate(45deg); box-shadow: 0 0 2px rgba(255, 255, 255, 0.5); } // Cover up the box-shadow at the top and bottom of the circle so it connects to the vertical line &::after { content: ""; position: absolute; background: var(--color-navy); left: -2px; top: -24px; width: 4px; height: 48px; } } } &:hover .slide-bar .arrows { opacity: 0; } } .carousel { margin-top: calc(80 * var(--variable-px)); transform: translate(0); .carousel-slide { display: flex; white-space: nowrap; touch-action: pan-y pinch-zoom; cursor: grab; img { position: relative; display: inline-block; user-select: none; flex: 0 0 auto; padding: 0 20px; &:first-child, &:last-child { --fade-factor: Min(calc(var(--over-slide-factor, 0) / 1.5 + 0.5), 1); // Fade to white (combining invert and brightness, see ) and desaturate filter: Invert(calc(var(--fade-factor) / 2)) Brightness(calc(1 + var(--fade-factor))) Grayscale(var(--fade-factor)); } &:first-child { margin-left: -20px; } &:last-child { margin-right: -20px; } } } &:not(.dragging, .jostling) .carousel-slide img { transition: transform 500ms; } .carousel-slide:not(.torn) { overflow: hidden; } .carousel-slide.torn { position: fixed; top: 0; z-index: -1; // Torn edge mask -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat; -webkit-mask-size: contain; mask-size: contain; &.left { padding-left: 160px; margin-left: -160px; -webkit-mask-image: url("https://static.graphite.rs/textures/torn-edge-left.png"); // TODO: Switch PNG to AVIF when Edge support has rolled out mask-image: url("https://static.graphite.rs/textures/torn-edge-left.png"); -webkit-mask-position: top left; mask-position: top left; } &.right { padding-right: 160px; margin-right: -160px; -webkit-mask-image: url("https://static.graphite.rs/textures/torn-edge-right.png"); // TODO: Switch PNG to AVIF when Edge support has rolled out mask-image: url("https://static.graphite.rs/textures/torn-edge-right.png"); -webkit-mask-position: top right; mask-position: top right; } } .screenshot-details { display: flex; margin: 20px 0; gap: 20px 40px; @media screen and (max-width: 800px) { flex-wrap: wrap; justify-content: center; } .carousel-controls { display: flex; align-items: center; flex: 0 0 auto; button { outline: none; background: none; border: none; padding: 0; color: inherit; cursor: pointer; svg { display: block; } + button { margin-left: 20px; } } .direction { fill: currentColor; } .dot { width: 16px; height: 16px; box-sizing: border-box; border-radius: 50%; border: 2px solid currentColor; &.active { border: none; background: var(--color-crimson); } } } .screenshot-description { display: flex; align-items: center; min-height: calc(2em * 1.5); p + p { margin: 0; } p:not(.active) { display: none; } } } &.center { .screenshot-details { justify-content: center; } } &.window-size-1 .carousel-slide img { width: 100%; } &.window-size-2 .carousel-slide img { width: calc((100% / 2) - 10px); padding: 0 10px; &:first-child { margin-left: -10px; } &:last-child { margin-right: -10px; } } &.window-size-3 .carousel-slide img { width: calc((100% / 3) - 10px * (4 / 3)); padding: 0 10px; &:first-child { margin-left: -10px; } &:last-child { margin-right: -10px; } } @media screen and (max-width: 1000px) { margin-left: calc(-1 * var(--page-edge-padding)); margin-right: calc(-1 * var(--page-edge-padding)); .screenshot-details { margin-left: var(--page-edge-padding); margin-right: var(--page-edge-padding); } } @media screen and (max-width: /* The value of --max-width-plus-padding: */ 1280px) { .carousel-slide.torn { display: none; } } } .atlas { object-fit: cover; object-position: calc(-48px * var(--atlas-index)) 0; width: 48px; height: 48px; } .feature-icons { display: flex; flex-wrap: wrap; margin-bottom: 20px; width: 100%; gap: 16px; .feature-icon { display: flex; align-items: center; img { flex: 0 0 auto; } } &:not(.stacked) .feature-icon { padding: 16px; gap: 16px; // Half width, minus own padding on both sides, minus half a gap flex: 1 0 calc(50% - (16px * 2) - (16px / 2)); @media screen and (max-width: 1100px) { // Quarter width, minus own padding on both sides flex: 1 0 calc(100% - (16px * 2)); } } &:not(.no-background) .feature-icon { background: rgba(0, 0, 0, 0.0625); } &.four-wide .feature-icon { flex: 1 0 calc(25% - (16px * 4) - (16px / 4)); @media screen and (max-width: 1200px) { // Half width, minus own padding on both sides, minus half a gap flex: 1 0 calc(50% - (16px * 2) - (16px / 2)); } @media screen and (max-width: 840px) { // Quarter width, minus own padding on both sides flex: 1 0 calc(100% - (16px * 2)); } } &.stacked { justify-content: space-between; margin: 0 -10px; width: calc(100% + 20px); gap: 0; .feature-icon { flex-direction: column; flex: 0 1 auto; margin: 0 10px; @media screen and (max-width: 1100px) { width: calc(100% / 3 - 40px); } @media screen and (max-width: 400px) { width: calc(100% / 2 - 20px); } img { width: 72px; height: 72px; object-position: calc(-72px * var(--atlas-index)) 0; margin-bottom: 8px; } span { text-align: center; } } } } p + .feature-icons .feature-icon.feature-icon { margin-top: calc(40 * var(--variable-px)); }