Added contextual navigation palette

This commit is contained in:
2026-02-28 10:24:43 +01:00
parent ee099346db
commit b8544011d4
16 changed files with 871 additions and 670 deletions

View File

@@ -16,6 +16,7 @@ const TYPE_LABELS: Record<ContentType, string> = {
article: 'Article',
element: 'Element',
page: 'Page',
section: 'Section',
};
/* INDEX ENTRY */
@@ -82,8 +83,12 @@ const buildRows = (entries: PaletteEntry[]): RenderRow[] => {
return rows;
};
interface Props {
currentPath?: string;
}
/* COMPONENT */
export default function CommandPalette() {
export default function CommandPalette({ currentPath = '/' }) {
const [isOpen, setIsOpen] = useState(false);
const [query, setQuery] = useState('');
const [index, setIndex] = useState<IndexedEntry[]>([]);
@@ -150,9 +155,7 @@ export default function CommandPalette() {
/* FILTERED ENTRIES -> RENDER ROWS */
const filtered = useMemo(() => {
if (!query.trim()) {
return index.filter((e) => e.depth <= 2).slice(0, MAX_DEFAULT);
}
if (query.trim()) {
const q = normalize(query);
return index
.map((entry) => ({ entry, score: scoreEntry(entry, q) }))
@@ -160,7 +163,41 @@ export default function CommandPalette() {
.sort((a, b) => b.score - a.score)
.slice(0, MAX_SEARCH)
.map((r) => r.entry);
}, [index, query]);
}
if (currentPath === '/') {
return index.filter((e) => e.depth === 1);
}
const segments = currentPath.replace(/\/$/, '').split('/').filter(Boolean);
const parentPath = '/' + segments.slice(0, -1).join('/');
const normalizedCurrent = currentPath.replace(/\/$/, '');
const siblings = index.filter((e) => {
const ePath = e.path.replace(/\/$/, '');
return (
ePath !== normalizedCurrent &&
ePath.startsWith(parentPath) &&
e.depth === segments.length
);
});
const children = index.filter((e) => {
const ePath = e.path.replace(/\/$/, '');
return (
ePath.startsWith(normalizedCurrent) && e.depth === segments.length + 1
);
});
const parent = index.filter((e) => {
const ePath = e.path.replace(/\/$/, '');
return ePath === parentPath;
});
const contextual = [...parent, ...siblings, ...children];
return contextual;
}, [index, query, currentPath]);
const rows = useMemo(() => buildRows(filtered), [filtered]);

View File

@@ -13,13 +13,13 @@ import CommandPalette from "./CMDPalette"
<span class="bracket">]</span>
</span>
</a>
<CommandPalette client:load />
<CommandPalette client:load currentPath={Astro.url.pathname} />
</div>
</header>
<style>
.site-header {
@mixin py var(--el-masthead-paddingY);
@mixin py var(--ui-masthead-paddingY);
position: sticky;
z-index: 9;
@@ -41,8 +41,8 @@ import CommandPalette from "./CMDPalette"
align-items: center;
justify-content: flex-start;
font-size: var(--el-masthead-font-size);
line-height: var(--el-masthead-line-height);
font-size: var(--ui-masthead-font-size);
line-height: var(--ui-masthead-line-height);
}
.site-logo {

View File

@@ -19,20 +19,19 @@ console.log(subtitle);
@mixin layout-wrapper;
@mixin py var(--spacing-relaxed);
}
.title {
font-size: var(--el-h1-color);
font-family: var(--el-h1-font-family);
font-size: var(--el-h1-font-size);
line-height: var(--typo-leading-tight);
letter-spacing: -0.025em;
@mixin heading-1;
}
.subtitle {
@mixin mt var(--spacing-snug);
font-family: var(--font-header);
font-size: var(--typo-size-lg);
font-weight: 300;
letter-spacing: 0.075em;
text-transform: uppercase;
letter-spacing: 0.075em;
}
</style>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 155 KiB

View File

@@ -3,10 +3,7 @@ title: Alchemical Materialism
subtitle: A Systematic Framework for Worldbuilding Through Elemental Combination
summary: A Systematic Framework for Worldbuilding Through Elemental Combination
cover:
src: /content/articles/alchemical-materialism/cover/src.png
alt: Man approach a volcano
caption: The Eshian God-Alchemists claimed this was the face of Monad
showInHeader: true
showInHeader: false
publishDate: 2026-02-20T11:17:00.000Z
status: published
isFeatured: false

View File

@@ -10,6 +10,9 @@ export const createContentField = (
) =>
fields.markdoc({
label: 'Body',
options: {
heading: [2, 3, 4, 5, 6],
},
components: {
...sharedComponents,
...additionalComponents,

View File

@@ -15,6 +15,7 @@ const { entry, collectionName } = Astro.props;
const { Content } = await render(entry);
const { title, summary, subtitle, updateDate, publishDate, tags, seo } =
entry.data;
const hasMargin = Astro.slots.has('margin')
const breadcrumbs = await getBreadcrumbs(
entry.data.parent ?? null,
@@ -48,11 +49,41 @@ const headerCover =
tags={tags}
subtitle={subtitle}
/>
<div class="content">
<div class="frame">
<div class="body content">
<slot name="before-content" />
<Content />
<slot name="after-content" />
</div>
{hasMargin &&(
<aside class="margin">
<slot name="margin" />
</aside>
)}
</div>
</article>
</main>
</Base>
<style>
.frame {
@mixin layout-wrapper;
font-size: var(--typo-size-responsive);
@media (--bp-desktop) {
position: relative;
display: grid;
grid-template-columns: var(--ui-content-width) var(--ui-margin-width);
}
}
.body {
min-width: 0;
}
.margin {
position: relative;
min-width: 0;
}
</style>

View File

@@ -1,7 +1,7 @@
import type { CollectionEntry } from 'astro:content';
/** Registered Content Type identifiers **/
export type ContentType = 'article' | 'page' | 'element';
export type ContentType = 'article' | 'page' | 'element' | 'section';
/**
* Minimal common shape for everything that participates in path resoltution and parent chain walking.

View File

@@ -174,7 +174,7 @@ export const buildPaletteIndex = (
return {
label: r.entry.data.title,
path: `/${r.path}`,
type: r.type,
type: r.type === 'article' && depth <= 1 ? 'section' : r.type,
parent: parentTitle,
depth,
};

View File

@@ -0,0 +1,651 @@
.content {
@mixin responsive-wrapper;
font-family: var(--font-body);
/* === Headings === */
& h1 {
margin-block: var(--el-h1-vspace-top) var(--el-h1-vspace-bottom);
padding-bottom: var(--spacing-snug);
border-bottom: var(--size-4) solid var(--el-h1-color);
font-family: var(--el-h1-font-family), serif;
font-size: var(--el-h1-font-size);
font-weight: 400;
line-height: var(--typo-leading-tight);
color: var(--el-h1-color);
text-transform: uppercase;
letter-spacing: -0.0137em;
& + p,
& + ul,
& + ol,
& + blockquote {
margin-block: calc(1em * var(--typo-leading-normal) * var(--vspace-tight))
calc(1em * var(--typo-leading-normal) * var(--vspace-snug));
}
& + h2 {
margin-block: calc(1em * 1.125 * var(--vspace-snug))
calc(1em * 1.125 * var(--vspace-normal));
}
}
& h2 {
margin-block: var(--el-h2-vspace-top) var(--el-h2-vspace-bottom);
padding-left: var(--spacing-snug);
border-left: var(--size-4) solid var(--el-h2-color);
font-family: var(--el-h2-font-family), serif;
font-size: var(--el-h2-font-size);
font-weight: 900;
line-height: 1.1765;
color: var(--el-h2-color);
text-transform: uppercase;
letter-spacing: -0.0096em;
& + p,
& + ul,
& + ol,
& + blockquote {
margin-block: calc(1em * var(--typo-leading-normal) * var(--vspace-tight))
calc(1em * var(--typo-leading-normal) * var(--vspace-snug));
}
& + h3 {
margin-block: calc(1em * 1.125 * var(--vspace-compressed))
calc(1em * 1.125 * var(--vspace-snug));
}
}
& h3 {
margin-block: var(--el-h3-vspace-top) var(--el-h3-vspace-bottom);
padding: var(--spacing-tight) var(--spacing-snug);
font-family: var(--el-h3-font-family), serif;
font-size: var(--el-h3-font-size);
font-weight: 800;
line-height: 1.2;
color: var(--color-surface-base);
text-transform: uppercase;
letter-spacing: -0.004em;
background: var(--el-h3-color);
}
& h4 {
margin-block: var(--el-h4-vspace-top) var(--el-h4-vspace-bottom);
padding: var(--spacing-tight) var(--spacing-snug);
border-top: var(--size-3) solid var(--el-h4-color);
border-bottom: var(--size-3) solid var(--el-h4-color);
font-family: var(--el-h4-font-family), serif;
font-size: var(--el-h4-font-size);
font-weight: 800;
line-height: 1.125;
text-transform: uppercase;
letter-spacing: 0.0025em;
}
& h5 {
margin-block: var(--el-h5-vspace-top) var(--el-h5-vspace-bottom);
padding: var(--spacing-tight) var(--spacing-snug);
font-family: var(--el-h5-font-family), serif;
font-size: var(--el-h5-font-size);
font-weight: 800;
line-height: 1.28;
color: var(--el-h5-color);
text-transform: uppercase;
letter-spacing: 0.05em;
&::before,
&::after {
content: '';
padding-right: var(--spacing-tight);
line-height: 1;
}
&::before {
content: '⭑';
}
&::after {
content: '';
}
}
& h6 {
margin-block: var(--el-h6-vspace-top) var(--el-h6-vspace-bottom);
font-family: var(--el-h6-font-family), serif;
font-size: var(--el-h6-font-size);
font-weight: 900;
line-height: 1.4;
color: var(--el-h6-color);
text-transform: uppercase;
letter-spacing: 0.035em;
}
& h3,
& h4,
& h5,
& h6 {
& + p,
& + ul,
& + ol,
& + blockquote {
margin-block: calc(
1em * var(--typo-leading-normal) * var(--vspace-compressed)
)
calc(1em * var(--typo-leading-normal) * var(--vspace-snug));
}
}
/* === Body Text === */
& p {
margin-block: var(--el-p-vspace-top) var(--el-p-vspace-bottom);
font-family: var(--el-p-font-family), sans-serif;
font-size: var(--el-p-font-size);
font-weight: 400;
line-height: var(--typo-leading-normal);
color: var(--el-p-color);
text-align: justify;
}
& blockquote {
margin-block: var(--el-p-vspace-top) var(--el-p-vspace-bottom);
padding: var(--spacing-snug) 0 var(--spacing-snug)
var(--spacing-comfortable);
border-left: var(--size-4) solid var(--color-text-tertiary);
font-family: var(--el-blockquote-font-family), serif;
font-size: var(--el-blockquote-font-size);
font-weight: 500;
font-style: normal;
line-height: var(--typo-leading-comfortable);
color: var(--el-blockquote-color);
}
/* === Code === */
pre {
margin-block: var(--el-pre-vspace-top) var(--el-pre-vspace-bottom);
padding: var(--spacing-comfortable);
font-family: var(--el-pre-font-family), monospace;
font-size: var(--el-pre-font-size);
line-height: 1.5385;
color: var(--el-pre-color);
background: var(--el-pre-background);
}
code {
padding: 0.1em 0.3em;
font-family: var(--font-mono), monospace;
font-size: var(--typo-size-sm);
color: var(--color-text-inverse);
background: var(--color-surface-inverse);
}
kbd {
padding: 0.1em 0.3em;
border: 1px solid var(--color-text-primary);
border-radius: 2px;
font-family: var(--font-mono), monospace;
font-size: var(--typo-size-xs);
color: var(--color-text-inverse);
text-transform: uppercase;
background: var(--color-surface-inverse);
}
samp {
padding: 0.1em 0.3em;
border-left: var(--size-1) solid var(--color-text-tertiary);
font-family: var(--font-mono), monospace;
font-size: var(--typo-size-sm);
color: var(--color-text-primary);
background: var(--color-surface-elevated-2);
}
var {
font-family: var(--font-mono), monospace;
font-weight: 600;
font-style: normal;
color: var(--color-text-secondary);
}
/* === Lists === */
ul,
ol {
margin-block: var(--el-list-vspace-top) var(--el-list-vspace-bottom);
font-size: var(--el-list-font-size);
line-height: var(--typo-leading-normal);
color: var(--el-list-color);
}
ul ul,
ul ol,
ol ul,
ol ol {
margin-block: var(--el-list-nested-vspace-top)
var(--el-list-nested-vspace-bottom);
}
li {
margin-block: var(--el-li-vspace-top) var(--el-li-vspace-bottom);
li {
margin-block: var(--el-li-nested-vspace-top)
var(--el-li-nested-vspace-bottom);
}
}
ul {
padding-left: var(--spacing-cozy);
list-style: none;
li {
padding-left: var(--spacing-cozy);
&::marker {
content: '⎊';
color: var(--color-text-primary);
}
}
ul,
ol {
padding-left: var(--spacing-cozy);
}
ul li::marker {
content: '⋊';
color: var(--color-text-primary);
}
ul ul,
ul ol,
ol ul,
ol ol {
padding-left: var(--spacing-cozy);
}
ul ul li::marker,
ol ul li::marker {
content: '◆';
color: var(--color-text-primary);
}
ul ul ul,
ul ul ol,
ul ol ul,
ul ol ol,
ol ul ul,
ol ul ol,
ol ol ul,
ol ol ol {
padding-left: var(--spacing-cozy);
}
ul ul ul li::marker,
ul ol ul li::marker,
ol ul ul li::marker,
ol ol ul li::marker {
content: '⯀';
color: var(--color-text-primary);
}
}
ol {
counter-reset: ol-l1;
contain: style;
padding-left: var(--spacing-cozy);
list-style: none;
& > li {
counter-increment: ol-l1;
margin-left: 1.5em;
padding-left: var(--spacing-cozy);
&::marker {
content: counter(ol-l1, decimal-leading-zero) '.)';
color: var(--color-text-primary);
}
}
}
ol > li > ol {
counter-reset: ol-l2;
padding-left: var(--spacing-cozy);
& > li {
counter-increment: ol-l2;
margin-left: 0.825em;
&::marker {
content: counter(ol-l2, lower-alpha) '.)';
color: var(--color-text-primary);
}
}
}
ol > li > ul {
padding-left: var(--spacing-cozy);
}
ol > li > ol > li > ol,
ol > li > ul > li > ol {
counter-reset: ol-l3;
margin-left: 0;
padding-left: var(--spacing-cozy);
& > li {
counter-increment: ol-l3;
&::marker {
content: counter(ol-l3, upper-roman) '.)';
color: var(--color-text-primary);
}
}
}
ol > li > ol > li > ul,
ol > li > ul > li > ul {
padding-left: var(--spacing-cozy);
}
ol > li > ol > li > ol > li > ol,
ol > li > ol > li > ul > li > ol,
ol > li > ul > li > ol > li > ol,
ol > li > ul > li > ul > li > ol {
counter-reset: ol-l4;
margin-left: 0;
padding-left: var(--spacing-cozy);
& > li {
counter-increment: ol-l4;
&::marker {
content: counter(ol-l4, lower-greek) '.)';
color: var(--color-text-primary);
}
}
}
ol > li > ol > li > ol > li > ul,
ol > li > ol > li > ul > li > ul,
ol > li > ul > li > ol > li > ul,
ol > li > ul > li > ul > li > ul {
padding-left: var(--spacing-cozy);
}
ol li,
ul li {
list-style-position: outside;
}
.list-inside ol li,
.list-inside ul li {
list-style-position: inside;
}
/* === Tables === */
table {
border-collapse: collapse;
width: 100%;
margin-block: var(--spacing-tight) var(--spacing-tight);
border: var(--size-2) solid var(--color-text-primary);
font-size: var(--typo-size-md);
line-height: 1.2;
& thead th,
& th {
padding: 0 var(--spacing-snug) var(--spacing-snug);
font-family: var(--el-th-font-family), serif;
font-size: var(--typo-size-sm);
font-weight: 900;
line-height: 1.2;
color: var(--el-th-color);
text-transform: uppercase;
background: var(--el-th-background);
}
& tbody td,
& td {
padding: var(--spacing-snug);
border: var(--size-1) solid var(--color-text-secondary);
font-family: var(--el-td-font-family), monospace;
font-size: var(--typo-size-sm);
line-height: 1.2;
color: var(--el-td-color);
text-align: center;
}
}
/* === DL / DT / DD === */
dl {
margin-block: calc(1em * var(--typo-leading-normal) * var(--vspace-snug))
calc(1em * var(--typo-leading-normal) * var(--vspace-compressed));
font-size: var(--typo-size-md);
line-height: var(--typo-leading-normal);
}
dt {
margin-block: calc(1em * 1.4 * var(--vspace-snug))
calc(1em * 1.4 * var(--vspace-compressed));
padding: var(--spacing-snug);
font-family: var(--el-dt-font-family), serif;
font-size: var(--typo-size-lg);
font-weight: 700;
line-height: 1.4;
color: var(--el-dt-color);
text-transform: uppercase;
letter-spacing: 0.035em;
background: var(--el-dt-background);
}
dd {
margin-block: calc(
1em * var(--typo-leading-normal) * var(--vspace-compressed)
)
calc(1em * var(--typo-leading-normal) * var(--vspace-tight));
padding: 0 var(--spacing-comfortable);
font-family: var(--el-dd-font-family), sans-serif;
font-size: var(--typo-size-md);
line-height: var(--typo-leading-normal);
color: var(--el-dd-color);
}
/* === HR === */
hr {
position: relative;
overflow: visible;
height: var(--size-3);
margin-block: var(--spacing-relaxed) 0;
border: none;
background: var(--hr-color);
&::after {
content: '▼';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
padding: 0 0.25em;
font-size: var(--typo-size-4xl);
line-height: var(--typo-leading-compressed);
color: var(--hr-symbol-color);
background: var(--hr-symbol-background);
}
}
/* === Inline Elements === */
em,
i {
font-style: italic;
letter-spacing: 0.025em;
}
strong,
b {
font-weight: 900;
letter-spacing: 0.025em;
}
a {
position: relative;
padding: 0.1em 0.2em;
font-weight: 600;
color: var(--color-text-primary);
text-decoration: underline;
text-decoration-thickness: var(--size-1);
text-underline-offset: 2px;
transition:
color 0.5s ease-in-out,
background 0.5s ease-in-out;
&:hover {
cursor: pointer;
color: var(--color-surface-base);
text-decoration: none;
background: var(--color-text-primary);
}
&:visited,
&:active {
color: var(--color-primary-emphasis);
}
}
small {
font-size: var(--typo-size-xs);
color: var(--color-text-tertiary);
}
sub,
sup {
font-size: 0.5625em;
font-weight: 600;
color: var(--color-text-secondary);
}
del,
s {
color: var(--color-text-tertiary);
text-decoration: line-through;
text-decoration-thickness: var(--size-1);
}
ins {
font-weight: 600;
color: var(--color-text-primary);
text-decoration: underline;
text-decoration-color: var(--color-primary);
text-decoration-thickness: var(--size-1);
background: transparent;
}
abbr {
cursor: help;
text-decoration: underline dotted;
text-underline-offset: var(--size-1);
}
dfn {
font-weight: 700;
font-style: normal;
color: var(--color-text-primary);
}
cite {
font-weight: 600;
font-style: normal;
color: var(--color-text-secondary);
}
q {
font-style: normal;
&::before {
content: '»';
}
&::after {
content: '«';
}
}
time {
font-family: var(--font-mono), monospace;
font-size: var(--typo-size-sm);
color: var(--color-text-secondary);
}
/* === Article Lead Paragraph === */
& article {
& > p:first-of-type {
font-size: var(--typo-size-xl);
font-weight: 700;
line-height: 1.4;
letter-spacing: 0.022em;
&::first-letter {
float: left;
margin: 0.1em 0.1em 0 0;
padding: 0;
font-family: var(--font-display), serif;
font-size: 4em;
font-weight: bold;
line-height: 1;
color: var(--color-primary);
@supports (initial-letter: 4) {
float: none;
margin: 0;
padding-right: var(--spacing-snug);
font-size: inherit;
line-height: inherit;
initial-letter: 3;
}
}
}
}
}

View File

@@ -1,46 +1,11 @@
.content {
@mixin responsive-wrapper;
font-family: var(--font-body);
/* === Headings === */
& h1 {
margin-block: var(--el-h1-vspace-top) var(--el-h1-vspace-bottom);
padding-bottom: var(--spacing-snug);
border-bottom: var(--size-4) solid var(--el-h1-color);
font-family: var(--el-h1-font-family), serif;
font-size: var(--el-h1-font-size);
font-weight: 400;
line-height: var(--typo-leading-tight);
color: var(--el-h1-color);
text-transform: uppercase;
letter-spacing: -0.0137em;
& + p,
& + ul,
& + ol,
& + blockquote {
margin-block: calc(1em * var(--typo-leading-normal) * var(--vspace-tight))
calc(1em * var(--typo-leading-normal) * var(--vspace-snug));
}
& + h2 {
margin-block: calc(1em * 1.125 * var(--vspace-snug))
calc(1em * 1.125 * var(--vspace-normal));
}
}
font-size: var(--typo-size-responsive);
& h2 {
margin-block: var(--el-h2-vspace-top) var(--el-h2-vspace-bottom);
padding-left: var(--spacing-snug);
border-left: var(--size-4) solid var(--el-h2-color);
font-family: var(--el-h2-font-family), serif;
font-size: var(--el-h2-font-size);
font-weight: 900;
line-height: 1.1765;
color: var(--el-h2-color);
text-transform: uppercase;
letter-spacing: -0.0096em;
@mixin heading-2;
@mixin pl var(--spacing-snug);
@mixin border-l var(--size-4), solid, var(--el-h2-color);
& + p,
& + ul,
@@ -57,595 +22,47 @@
}
& h3 {
margin-block: var(--el-h3-vspace-top) var(--el-h3-vspace-bottom);
padding: var(--spacing-tight) var(--spacing-snug);
@mixin heading-3;
@mixin py var(--spacing-tight);
@mixin px var(--spacing-snug);
font-family: var(--el-h3-font-family), serif;
font-size: var(--el-h3-font-size);
font-weight: 800;
line-height: 1.2;
color: var(--color-surface-base);
text-transform: uppercase;
letter-spacing: -0.004em;
background: var(--el-h3-color);
color: var(--color-text-inverse);
background: var(--color-surface-inverse);
}
& h4 {
margin-block: var(--el-h4-vspace-top) var(--el-h4-vspace-bottom);
padding: var(--spacing-tight) var(--spacing-snug);
border-top: var(--size-3) solid var(--el-h4-color);
border-bottom: var(--size-3) solid var(--el-h4-color);
@mixin heading-4;
@mixin py var(--spacing-tight);
@mixin px var(--spacing-snug);
@mixin border-t var(--size-3), solid, var(--el-h4-color);
@mixin border-b var(--size-3), solid, var(--el-h4-color);
font-family: var(--el-h4-font-family), serif;
font-size: var(--el-h4-font-size);
font-weight: 800;
line-height: 1.125;
text-transform: uppercase;
letter-spacing: 0.0025em;
color: var(--el-h4-color);
}
& h5 {
margin-block: var(--el-h5-vspace-top) var(--el-h5-vspace-bottom);
padding: var(--spacing-tight) var(--spacing-snug);
@mixin heading-5;
@mixin py var(--spacing-tight);
@mixin px var(--spacing-snug);
font-family: var(--el-h5-font-family), serif;
font-size: var(--el-h5-font-size);
font-weight: 800;
line-height: 1.28;
color: var(--el-h5-color);
text-transform: uppercase;
letter-spacing: 0.05em;
&::before,
&::after {
content: '';
padding-right: var(--spacing-tight);
line-height: 1;
}
@mixin pr var(--spacing-tight);
&::before {
content: '⭑';
}
&::after {
content: '';
}
}
& h6 {
margin-block: var(--el-h6-vspace-top) var(--el-h6-vspace-bottom);
font-family: var(--el-h6-font-family), serif;
font-size: var(--el-h6-font-size);
font-weight: 900;
line-height: 1.4;
color: var(--el-h6-color);
text-transform: uppercase;
letter-spacing: 0.035em;
}
& h3,
& h4,
& h5,
& h6 {
& + p,
& + ul,
& + ol,
& + blockquote {
margin-block: calc(
1em * var(--typo-leading-normal) * var(--vspace-compressed)
)
calc(1em * var(--typo-leading-normal) * var(--vspace-snug));
}
}
/* === Body Text === */
& p {
margin-block: var(--el-p-vspace-top) var(--el-p-vspace-bottom);
font-family: var(--el-p-font-family), sans-serif;
font-size: var(--el-p-font-size);
font-weight: 400;
line-height: var(--typo-leading-normal);
color: var(--el-p-color);
text-align: justify;
}
& blockquote {
margin-block: var(--el-p-vspace-top) var(--el-p-vspace-bottom);
padding: var(--spacing-snug) 0 var(--spacing-snug)
var(--spacing-comfortable);
border-left: var(--size-4) solid var(--color-text-tertiary);
font-family: var(--el-blockquote-font-family), serif;
font-size: var(--el-blockquote-font-size);
font-weight: 500;
font-style: normal;
line-height: var(--typo-leading-comfortable);
color: var(--el-blockquote-color);
}
/* === Code === */
pre {
margin-block: var(--el-pre-vspace-top) var(--el-pre-vspace-bottom);
padding: var(--spacing-comfortable);
font-family: var(--el-pre-font-family), monospace;
font-size: var(--el-pre-font-size);
line-height: 1.5385;
color: var(--el-pre-color);
background: var(--el-pre-background);
}
code {
padding: 0.1em 0.3em;
font-family: var(--font-mono), monospace;
font-size: var(--typo-size-sm);
color: var(--color-text-inverse);
background: var(--color-surface-inverse);
}
kbd {
padding: 0.1em 0.3em;
border: 1px solid var(--color-text-primary);
border-radius: 2px;
font-family: var(--font-mono), monospace;
font-size: var(--typo-size-xs);
color: var(--color-text-inverse);
text-transform: uppercase;
background: var(--color-surface-inverse);
}
samp {
padding: 0.1em 0.3em;
border-left: var(--size-1) solid var(--color-text-tertiary);
font-family: var(--font-mono), monospace;
font-size: var(--typo-size-sm);
color: var(--color-text-primary);
background: var(--color-surface-elevated-2);
}
var {
font-family: var(--font-mono), monospace;
font-weight: 600;
font-style: normal;
color: var(--color-text-secondary);
}
/* === Lists === */
ul,
ol {
margin-block: var(--el-list-vspace-top) var(--el-list-vspace-bottom);
font-size: var(--el-list-font-size);
line-height: var(--typo-leading-normal);
color: var(--el-list-color);
}
ul ul,
ul ol,
ol ul,
ol ol {
margin-block: var(--el-list-nested-vspace-top)
var(--el-list-nested-vspace-bottom);
}
li {
margin-block: var(--el-li-vspace-top) var(--el-li-vspace-bottom);
li {
margin-block: var(--el-li-nested-vspace-top)
var(--el-li-nested-vspace-bottom);
}
}
ul {
padding-left: var(--spacing-cozy);
list-style: none;
li {
padding-left: var(--spacing-cozy);
&::marker {
content: '⎊';
color: var(--color-text-primary);
}
}
ul,
ol {
padding-left: var(--spacing-cozy);
}
ul li::marker {
content: '⋊';
color: var(--color-text-primary);
}
ul ul,
ul ol,
ol ul,
ol ol {
padding-left: var(--spacing-cozy);
}
ul ul li::marker,
ol ul li::marker {
content: '◆';
color: var(--color-text-primary);
}
ul ul ul,
ul ul ol,
ul ol ul,
ul ol ol,
ol ul ul,
ol ul ol,
ol ol ul,
ol ol ol {
padding-left: var(--spacing-cozy);
}
ul ul ul li::marker,
ul ol ul li::marker,
ol ul ul li::marker,
ol ol ul li::marker {
content: '⯀';
color: var(--color-text-primary);
}
}
ol {
counter-reset: ol-l1;
contain: style;
padding-left: var(--spacing-cozy);
list-style: none;
& > li {
counter-increment: ol-l1;
margin-left: 1.5em;
padding-left: var(--spacing-cozy);
&::marker {
content: counter(ol-l1, decimal-leading-zero) '.)';
color: var(--color-text-primary);
}
}
}
ol > li > ol {
counter-reset: ol-l2;
padding-left: var(--spacing-cozy);
& > li {
counter-increment: ol-l2;
margin-left: 0.825em;
&::marker {
content: counter(ol-l2, lower-alpha) '.)';
color: var(--color-text-primary);
}
}
}
ol > li > ul {
padding-left: var(--spacing-cozy);
}
ol > li > ol > li > ol,
ol > li > ul > li > ol {
counter-reset: ol-l3;
margin-left: 0;
padding-left: var(--spacing-cozy);
& > li {
counter-increment: ol-l3;
&::marker {
content: counter(ol-l3, upper-roman) '.)';
color: var(--color-text-primary);
}
}
}
ol > li > ol > li > ul,
ol > li > ul > li > ul {
padding-left: var(--spacing-cozy);
}
ol > li > ol > li > ol > li > ol,
ol > li > ol > li > ul > li > ol,
ol > li > ul > li > ol > li > ol,
ol > li > ul > li > ul > li > ol {
counter-reset: ol-l4;
margin-left: 0;
padding-left: var(--spacing-cozy);
& > li {
counter-increment: ol-l4;
&::marker {
content: counter(ol-l4, lower-greek) '.)';
color: var(--color-text-primary);
}
}
}
ol > li > ol > li > ol > li > ul,
ol > li > ol > li > ul > li > ul,
ol > li > ul > li > ol > li > ul,
ol > li > ul > li > ul > li > ul {
padding-left: var(--spacing-cozy);
}
ol li,
ul li {
list-style-position: outside;
}
.list-inside ol li,
.list-inside ul li {
list-style-position: inside;
}
/* === Tables === */
table {
border-collapse: collapse;
width: 100%;
margin-block: var(--spacing-tight) var(--spacing-tight);
border: var(--size-2) solid var(--color-text-primary);
font-size: var(--typo-size-md);
line-height: 1.2;
& thead th,
& th {
padding: 0 var(--spacing-snug) var(--spacing-snug);
font-family: var(--el-th-font-family), serif;
font-size: var(--typo-size-sm);
font-weight: 900;
line-height: 1.2;
color: var(--el-th-color);
text-transform: uppercase;
background: var(--el-th-background);
}
& tbody td,
& td {
padding: var(--spacing-snug);
border: var(--size-1) solid var(--color-text-secondary);
font-family: var(--el-td-font-family), monospace;
font-size: var(--typo-size-sm);
line-height: 1.2;
color: var(--el-td-color);
text-align: center;
}
}
/* === DL / DT / DD === */
dl {
margin-block: calc(1em * var(--typo-leading-normal) * var(--vspace-snug))
calc(1em * var(--typo-leading-normal) * var(--vspace-compressed));
font-size: var(--typo-size-md);
line-height: var(--typo-leading-normal);
}
dt {
margin-block: calc(1em * 1.4 * var(--vspace-snug))
calc(1em * 1.4 * var(--vspace-compressed));
padding: var(--spacing-snug);
font-family: var(--el-dt-font-family), serif;
font-size: var(--typo-size-lg);
font-weight: 700;
line-height: 1.4;
color: var(--el-dt-color);
text-transform: uppercase;
letter-spacing: 0.035em;
background: var(--el-dt-background);
}
dd {
margin-block: calc(
1em * var(--typo-leading-normal) * var(--vspace-compressed)
)
calc(1em * var(--typo-leading-normal) * var(--vspace-tight));
padding: 0 var(--spacing-comfortable);
font-family: var(--el-dd-font-family), sans-serif;
font-size: var(--typo-size-md);
line-height: var(--typo-leading-normal);
color: var(--el-dd-color);
}
/* === HR === */
hr {
position: relative;
overflow: visible;
height: var(--size-3);
margin-block: var(--spacing-relaxed) 0;
border: none;
background: var(--hr-color);
&::after {
content: '▼';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
padding: 0 0.25em;
font-size: var(--typo-size-4xl);
content: "";
line-height: var(--typo-leading-compressed);
color: var(--hr-symbol-color);
background: var(--hr-symbol-background);
}
}
/* === Inline Elements === */
em,
i {
font-style: italic;
letter-spacing: 0.025em;
}
strong,
b {
font-weight: 900;
letter-spacing: 0.025em;
}
a {
position: relative;
padding: 0.1em 0.2em;
font-weight: 600;
color: var(--color-text-primary);
text-decoration: underline;
text-decoration-thickness: var(--size-1);
text-underline-offset: 2px;
transition:
color 0.5s ease-in-out,
background 0.5s ease-in-out;
&:hover {
cursor: pointer;
color: var(--color-surface-base);
text-decoration: none;
background: var(--color-text-primary);
}
&:visited,
&:active {
color: var(--color-primary-emphasis);
}
}
small {
font-size: var(--typo-size-xs);
color: var(--color-text-tertiary);
}
sub,
sup {
font-size: 0.5625em;
font-weight: 600;
color: var(--color-text-secondary);
}
del,
s {
color: var(--color-text-tertiary);
text-decoration: line-through;
text-decoration-thickness: var(--size-1);
}
ins {
font-weight: 600;
color: var(--color-text-primary);
text-decoration: underline;
text-decoration-color: var(--color-primary);
text-decoration-thickness: var(--size-1);
background: transparent;
}
abbr {
cursor: help;
text-decoration: underline dotted;
text-underline-offset: var(--size-1);
}
dfn {
font-weight: 700;
font-style: normal;
color: var(--color-text-primary);
}
cite {
font-weight: 600;
font-style: normal;
color: var(--color-text-secondary);
}
q {
font-style: normal;
&::before {
content: '»';
}
&::after {
content: '«';
content: '';
}
}
time {
font-family: var(--font-mono), monospace;
font-size: var(--typo-size-sm);
color: var(--color-text-secondary);
}
& h6 {
@mixin heading-6;
/* === Article Lead Paragraph === */
& article {
& > p:first-of-type {
font-size: var(--typo-size-xl);
font-weight: 700;
line-height: 1.4;
letter-spacing: 0.022em;
&::first-letter {
float: left;
margin: 0.1em 0.1em 0 0;
padding: 0;
font-family: var(--font-display), serif;
font-size: 4em;
font-weight: bold;
line-height: 1;
color: var(--color-primary);
@supports (initial-letter: 4) {
float: none;
margin: 0;
padding-right: var(--spacing-snug);
font-size: inherit;
line-height: inherit;
initial-letter: 3;
}
}
}
color: var(--el-h6-color);
}
}

View File

@@ -91,9 +91,5 @@
--spacing-generous: var(--size-16);
--spacing-luxurious: var(--size-24);
--spacing-expansive: var(--size-32);
/* == Responsive Content Dimensions */
--layout-max-width: 90rem;
--content-max-width: 75ch;
}
}

View File

@@ -4,43 +4,49 @@
--el-h1-color: var(--color-text-primary);
--el-h1-font-family: var(--font-display);
--el-h1-font-size: var(--typo-size-7xl);
--el-h1-leading: 1.125;
--el-h2-color: var(--color-text-primary);
--el-h2-font-family: var(--font-header);
--el-h2-font-size: var(--typo-size-5xl);
--el-h2-leading: 1.1765;
--el-h3-color: var(--color-text-secondary);
--el-h3-font-family: var(--font-header);
--el-h3-font-size: var(--typo-size-4xl);
--el-h3-leading: 1.2;
--el-h4-color: var(--color-text-secondary);
--el-h4-font-family: var(--font-header);
--el-h4-font-size: var(--typo-size-3xl);
--el-h4-leading: 1.125;
--el-h5-color: var(--color-text-secondary);
--el-h5-font-family: var(--font-header);
--el-h5-font-size: var(--typo-size-2xl);
--el-h5-leading: 1.28;
--el-h6-color: var(--color-text-secondary);
--el-h6-font-family: var(--font-header);
--el-h6-font-size: var(--typo-size-xl);
--el-h6-leading: 1.4;
/* === Heading Vertical Spacing === */
--el-h1-vspace-base: calc(1em * 1.125);
--el-h1-vspace-base: calc(1em * var(--el-h1-leading));
--el-h1-vspace-top: calc(var(--el-h1-vspace-base) * var(--vspace-snug));
--el-h1-vspace-bottom: calc(
var(--el-h1-vspace-base) * var(--vspace-compressed)
);
--el-h2-vspace-base: calc(1em * 1.1765);
--el-h2-vspace-base: calc(1em * var(--el-h2-leading));
--el-h2-vspace-top: calc(var(--el-h2-vspace-base) * var(--vspace-snug));
--el-h2-vspace-bottom: calc(
var(--el-h2-vspace-base) * var(--vspace-compressed)
);
--el-h3-vspace-base: calc(1em * 1.2);
--el-h3-vspace-base: calc(1em * var(--el-h3-leading));
--el-h3-vspace-top: calc(var(--el-h3-vspace-base) * var(--vspace-cozy));
--el-h3-vspace-bottom: calc(var(--el-h3-vspace-base) * var(--vspace-snug));
--el-h4-vspace-base: calc(1em * 1.125);
--el-h4-vspace-base: calc(1em * var(--el-h4-leading));
--el-h4-vspace-top: calc(var(--el-h4-vspace-base) * var(--vspace-normal));
--el-h4-vspace-bottom: calc(var(--el-h4-vspace-base) * var(--vspace-tight));
--el-h5-vspace-base: calc(1em * 1.28);
--el-h5-vspace-base: calc(1em * var(--el-h5-leading));
--el-h5-vspace-top: calc(var(--el-h5-vspace-base) * var(--vspace-cozy));
--el-h5-vspace-bottom: calc(var(--el-h5-vspace-base) * var(--vspace-tight));
--el-h6-vspace-base: calc(1em * 1.4);
--el-h6-vspace-base: calc(1em * var(--el-h6-leading));
--el-h6-vspace-top: calc(var(--el-h6-vspace-base) * var(--vspace-snug));
--el-h6-vspace-bottom: calc(
var(--el-h6-vspace-base) * var(--vspace-compressed)
@@ -119,18 +125,3 @@
--hr-symbol-color: var(--color-text-tertiary);
--hr-symbol-background: var(--color-surface-base);
}
.responsivewrapper {
max-width: clamp(60ch, 90vw, 90ch);
margin-inline: auto;
padding: 0 var(--spacing-cozy);
}
.layoutwrapper {
width: 100%;
margin-inline: auto;
@media screen and (--max-layout) {
padding-inline: var(--spacing-comfortable);
}
}

View File

@@ -25,11 +25,16 @@
--ui-typo-size-5xl: 2rem;
/* === MastHead === */
--el-masthead-font-size: var(--ui-font-size-xl);
--el-masthead-line-height: var(--typo-leading-snug);
--el-masthead-paddingY: var(--ui-spacing-relaxed);
--el-masthead-height: calc(
(var(--el-masthead-font-size) * var(--el-masthead-line-height)) +
(var(--el-masthead-paddingY) * 2)
--ui-masthead-font-size: var(--ui-font-size-xl);
--ui-masthead-line-height: var(--typo-leading-snug);
--ui-masthead-paddingY: var(--ui-spacing-relaxed);
--ui-masthead-height: calc(
(var(--ui-masthead-font-size) * var(--ui-masthead-line-height)) +
(var(--ui-masthead-paddingY) * 2)
);
/* === Content/Marginalia === */
--ui-content-width: minmax(0, 72ch);
--ui-margin-width: minmax(18ch, 1fr);
--ui-layout-width: 90rem;
}

View File

@@ -11,8 +11,9 @@
@define-mixin layout-wrapper {
@mixin mx auto;
@mixin px var(--spacing-comfortable);
width: 100%;
max-width: var(--layout-max-width);
max-width: var(--ui-layout-width);
@media screen and (--max-layout) {
@mixin px var(--spacing-comfortable);

View File

@@ -0,0 +1,73 @@
@define-mixin heading-1 {
@mixin mt var(--el-h1-vspace-top);
@mixin mb var(--el-h1-vspace-bottom);
@mixin pb var(--spacing-snug);
font-family: var(--el-h1-font-family);
font-size: var(--el-h1-font-size);
font-weight: 400;
line-height: var(--el-h1-leading);
color: var(--el-h1-color);
text-transform: uppercase;
letter-spacing: -0.0137em;
}
@define-mixin heading-2 {
@mixin mt var(--el-h2-vspace-top);
@mixin mb var(--el-h2-vspace-bottom);
font-family: var(--el-h2-font-family);
font-size: var(--el-h2-font-size);
font-weight: 900;
line-height: var(--el-h2-leading);
text-transform: uppercase;
letter-spacing: -0.0096em;
}
@define-mixin heading-3 {
@mixin mt var(--el-h3-vspace-top);
@mixin mb var(--el-h3-vspace-bottom);
font-family: var(--el-h3-font-family);
font-size: var(--el-h3-font-size);
font-weight: 800;
line-height: var(--el-h3-leading);
text-transform: uppercase;
letter-spacing: -0.004em;
}
@define-mixin heading-4 {
@mixin mt var(--el-h4-vspace-top);
@mixin mb var(--el-h4-vspace-bottom);
font-family: var(--el-h4-font-family);
font-size: var(--el-h4-font-size);
font-weight: 800;
line-height: var(--el-h4-leading);
text-transform: uppercase;
letter-spacing: 0.0025em;
}
@define-mixin heading-5 {
@mixin mt var(--el-h5-vspace-top);
@mixin mb var(--el-h5-vspace-bottom);
font-family: var(--el-h5-font-family);
font-size: var(--el-h5-font-size);
font-weight: 800;
line-height: var(--el-h5-leading);
text-transform: uppercase;
letter-spacing: 0.05em;
}
@define-mixin heading-6 {
@mixin mt var(--el-h6-vspace-top);
@mixin mb var(--el-h6-vspace-bottom);
font-family: var(--el-h6-font-family);
font-size: var(--el-h6-font-size);
font-weight: 900;
line-height: var(--el-h6-leading);
text-transform: uppercase;
letter-spacing: 0.035em;
}