:root {
--mbr-icon-search: url("data:image/svg+xml,%20%20%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%221.2em%22%20height%3D%221.2em%22%20viewBox%3D%220%200%20512%20512%22%3E%3Cpath%20fill%3D%22currentColor%22%20d%3D%22M416%20208c0%2045.9-14.9%2088.3-40%20122.7l126.6%20126.7c12.5%2012.5%2012.5%2032.8%200%2045.3s-32.8%2012.5-45.3%200L330.7%20376c-34.4%2025.2-76.8%2040-122.7%2040C93.1%20416%200%20322.9%200%20208S93.1%200%20208%200s208%2093.1%20208%20208M208%20352a144%20144%200%201%200%200-288a144%20144%200%201%200%200%20288%22%2F%3E%3C%2Fsvg%3E");
/* Sidebar Navigation Variables (for mbr-browse-single) */
--mbr-sidebar-width: 280px;
--mbr-hide-nav-bp: 1024px;
--mbr-show-tags: block; /* Set to 'none' to hide tags in sidebar */
/* Pull Quote Styling Variables */
--mbr-pullquote-bg: var(--pico-muted-border-color);
--mbr-pullquote-border: var(--pico-primary);
--mbr-pullquote-color: var(--pico-color);
/* Marginalia Styling Variables */
--mbr-marginalia-bg: var(--pico-secondary-background);
/* --mbr-marginalia-border: var(--pico-muted-border-color); */
--mbr-marginalia-border: var(--pico-secondary-hover-background);
--mbr-marginalia-color: var(--pico-muted-color);
/* GitHub Alert: Note (Blue) */
--mbr-alert-note-bg: rgba(227, 242, 253, 0.4);
--mbr-alert-note-border: #1976d2;
--mbr-alert-note-icon-color: #1976d2;
/* GitHub Alert: Tip (Green) */
--mbr-alert-tip-bg: rgba(232, 245, 233, 0.4);
--mbr-alert-tip-border: #388e3c;
--mbr-alert-tip-icon-color: #388e3c;
/* GitHub Alert: Important (Purple) */
--mbr-alert-important-bg: rgba(243, 229, 245, 0.4);
--mbr-alert-important-border: #7b1fa2;
--mbr-alert-important-icon-color: #7b1fa2;
/* GitHub Alert: Warning (Orange) */
--mbr-alert-warning-bg: rgba(255, 243, 224, 0.4);
--mbr-alert-warning-border: #f57c00;
--mbr-alert-warning-icon-color: #f57c00;
/* GitHub Alert: Caution (Red) */
--mbr-alert-caution-bg: rgba(255, 235, 238, 0.4);
--mbr-alert-caution-border: #c62828;
--mbr-alert-caution-icon-color: #c62828;
/* Incomplete marker (TK/TODO/FIXME/XXX) — a wash only, no underline. */
--mbr-incomplete-bg: rgba(255, 235, 59, 0.18);
/* Task annotations (!! / !!! priority, #tag, @due, @done, [-] canceled) */
--mbr-task-pri-high-color: #f57c00;
--mbr-task-pri-urgent-color: #c62828;
--mbr-task-pri-size: 0.55em;
--mbr-task-tag-bg: rgba(115, 130, 140, 0.16);
--mbr-task-tag-color: var(--pico-muted-color, #5c6b73);
--mbr-task-chip-bg: rgba(115, 130, 140, 0.1);
--mbr-task-chip-color: var(--pico-muted-color, #5c6b73);
--mbr-task-chip-radius: 0.5em;
--mbr-task-canceled-color: var(--pico-muted-color, #5c6b73);
/* Arrival flash for a #mbr-task-N deep link. */
--mbr-task-flash-color: rgba(255, 213, 79, 0.55);
/* Paper margins. Applied as padding on the content box rather than as an
* `@page` margin -- see the "Print Styles" section for the Safari reason. */
--mbr-print-margin-block: 0.5in;
--mbr-print-margin-inline: 1in;
/* Definition Lists (FAQ-style disclosure) Variables.
* All colors resolve through Pico custom properties, so light/dark mode and
* every color theme follow automatically -- override these, not the rules. */
--mbr-dl-question-color: var(--pico-color);
--mbr-dl-question-hover-color: var(--pico-primary-hover);
--mbr-dl-question-weight: 600;
--mbr-dl-answer-color: var(--pico-muted-color);
--mbr-dl-separator-color: var(--pico-muted-border-color);
--mbr-dl-marker-color: var(--pico-primary);
--mbr-dl-marker-size: 0.62em;
--mbr-dl-marker-gap: 0.55em;
/* Vertical breathing room above/below each question and under each answer. */
--mbr-dl-item-spacing: var(--pico-spacing);
/* How far the answer is indented from the question. */
--mbr-dl-answer-indent: calc(var(--pico-spacing) * 1.5);
--mbr-dl-transition-duration: 0.25s;
--mbr-dl-transition-easing: ease;
/* Alert Icons (SVG Data URIs) */
--mbr-icon-note: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='16' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='8' x2='12.01' y2='8'%3E%3C/line%3E%3C/svg%3E");
--mbr-icon-tip: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 2a7 7 0 0 0-7 7c0 2.38 1.19 4.47 3 5.74V17a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1v-2.26c1.81-1.27 3-3.36 3-5.74a7 7 0 0 0-7-7z'%3E%3C/path%3E%3Cpath d='M9 21h6'%3E%3C/path%3E%3C/svg%3E");
--mbr-icon-important: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z'%3E%3C/path%3E%3Cline x1='12' y1='8' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='16' x2='12.01' y2='16'%3E%3C/line%3E%3C/svg%3E");
--mbr-icon-warning: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z'%3E%3C/path%3E%3Cline x1='12' y1='9' x2='12' y2='13'%3E%3C/line%3E%3Cline x1='12' y1='17' x2='12.01' y2='17'%3E%3C/line%3E%3C/svg%3E");
--mbr-icon-caution: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolygon points='7.86 2 16.14 2 22 7.86 22 16.14 16.14 22 7.86 22 2 16.14 2 7.86 7.86 2'%3E%3C/polygon%3E%3Cline x1='12' y1='8' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='16' x2='12.01' y2='16'%3E%3C/line%3E%3C/svg%3E");
/* tie reveal.js slides styles to our pico styles and theme */
--r-background-color: var(--pico-background-color);
--r-main-font: var(--pico-font-family);
--r-main-font-size: calc(var(--pico-font-size) * 1.25);
--r-main-color: var(--pico-color);
--r-block-margin: calc(var(--pico-spacing) * 1.2);
--r-heading-margin: var(--r-block-margin);
--r-heading-font: var(--pico-font-family);
--r-heading-color: var(--pico-primary);
--r-heading-line-height: 1.2;
--r-heading-letter-spacing: normal;
--r-heading-text-transform: uppercase;
--r-heading-text-shadow: none;
--r-heading-font-weight: 700;
--r-heading1-text-shadow: none;
--r-heading1-size: calc(var(--pico-font-size) * 3.1);
--r-heading2-size: calc(var(--pico-font-size) * 1.8);
--r-heading3-size: calc(var(--pico-font-size) * 1.6);
--r-heading4-size: calc(var(--pico-font-size) * 1.3);
--r-code-font: var(--pico-font-family-monospace);
--r-link-color: var(--pico-primary);
/* not sure on this one; could do lch(from var(--pico-primary) calc(l - 20) c h) to darken */
--r-link-color-dark: var(--pico-primary);
--r-link-color-hover: var(--pico-primary-hover);
--r-selection-background-color: var(--pico-text-selection-color);
--r-selection-color: var(--pico-color);
--r-overlay-element-bg-color: var(--pico-modal-overlay-background-color);
--r-overlay-element-fg-color: var(--pico-color);
}
main > section[data-theme="light"] {
background-color: rgba(255, 255, 255, 0.85);
padding: var(--pico-block-spacing-vertical) 0;
}
main > section[data-theme="dark"] {
background-color: rgba(0, 0, 0, 0.85);
padding: var(--pico-block-spacing-vertical) 0;
}
.mbr-search-button {
width: 1.2em;
height: 1.2em;
mask-size: cover;
mask: var(--mbr-icon-search) no-repeat 100% 100%;
background-color: var(--pico-color);
border: none;
outline: none;
}
body > header {
background-color: var(--pico-background-color);
border-bottom: 2px solid var(--pico-secondary-border);
position: sticky;
top: 0;
padding-block: 0;
z-index: 999;
}
/* Offset anchor jumps (including `:target` and permalink clicks) so the
* linked heading isn't hidden under the sticky header above (nav ul is
* 2.4em + 2px border). */
html {
scroll-padding-top: 3em;
}
body > header > nav {
padding-block: 0;
margin-block: 0;
}
body > header > nav > ul {
height: 2.4em;
}
body > header nav details[class="dropdown"] summary {
border-color: transparent;
background-color: transparent;
margin-right: -14px;
}
body > header nav details[class="dropdown"] summary::after {
background: none;
}
nav[aria-label="breadcrumb"] ul li {
padding-top: 0;
font-style: italic;
}
body > footer {
border-top: 1px solid var(--pico-secondary-border);
}
/* ==================== Sidebar Navigation Grid Layout ==================== */
/*
* CSS Grid layout for body when mbr-browse-single sidebar is active.
* The component adds 'mbr-has-sidebar' class to body when in desktop mode (>1024px).
* On mobile (<1024px), the sidebar is an overlay drawer - no grid layout needed.
*/
/* Desktop: sidebar visible inline via CSS grid.
*
* `screen and` is load-bearing, not decoration. Per CSS 2.1 a width query in
* paged media resolves against the page box (a Letter sheet is ~816px, so this
* block should never match when printing) -- but WebKit evaluates width and
* viewport units against the on-screen window instead
* (https://bugs.webkit.org/show_bug.cgi?id=250685, open since 2023;
* https://bugs.webkit.org/show_bug.cgi?id=126591 for `vw`). Unqualified, this
* block therefore applies while printing from any Safari window wider than
* 1024px, dropping a `min-height: 100vh` grid and two sticky children into the
* printed layout. Qualifying the media type sidesteps the bug entirely.
*
* Pico's own breakpoints are unqualified and have the same exposure; the print
* block's `main.container { max-width: none }` neutralises the consequence we
* can actually reach. */
@media screen and (min-width: 1024px) {
body.mbr-has-sidebar {
display: grid;
grid-template-columns: var(--mbr-sidebar-width) 1fr;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"sidebar header"
"sidebar main"
"sidebar footer";
min-height: 100vh;
}
body.mbr-has-sidebar > mbr-browse-single {
grid-area: sidebar;
position: sticky;
top: 0;
height: 100vh;
overflow-y: auto;
border-right: 1px solid var(--pico-muted-border-color);
z-index: 100;
}
body.mbr-has-sidebar > header {
grid-area: header;
position: sticky;
top: 0;
}
body.mbr-has-sidebar > main {
grid-area: main;
}
body.mbr-has-sidebar > footer {
grid-area: footer;
}
}
/* Mobile: no grid layout, sidebar is overlay drawer handled by component.
* `screen and` for the same reason as the desktop block above. */
@media screen and (max-width: 1023px) {
body.mbr-has-sidebar {
display: block;
}
}
figure > video {
width: 100%;
height: auto;
max-height: calc(100vh - 50px);
max-width: 100%;
align-items: center;
/* display: inline-flex; */
user-select: none;
}
figure > figcaption {
display: flex;
justify-content: space-between;
flex-direction: row-reverse;
flex-wrap: wrap-reverse;
}
figure > figcaption > * {
flex-grow: 1;
}
figure > figcaption > mbr-video-extras {
flex-grow: 2;
}
figure {
margin-bottom: var(--pico-block-spacing-vertical);
}
/* ==================== Video Theater Mode ==================== */
figure.theater {
/* Break out of parent container to fill viewport width */
width: 100vw;
margin-left: calc(-50vw + 50%);
margin-right: calc(-50vw + 50%);
/* Dark background for cinematic feel */
background: #000;
/* Flex column to stack video + controls, cap to viewport */
display: flex;
flex-direction: column;
align-items: center;
max-height: 95vh;
/* Sit above sibling content but below sticky header (z-index: 999) */
position: relative;
z-index: 100;
padding: 0;
}
figure.theater > video {
flex: 1 1 auto;
min-height: 0; /* allow flex shrink below intrinsic size */
width: 100%;
max-height: 80vh;
object-fit: contain; /* maintain aspect ratio, letterbox if needed */
}
figure.theater > figcaption {
flex: 0 0 auto;
width: 100%;
max-width: 1200px;
padding: 0.5rem 1rem;
color: var(--pico-muted-color);
}
/* figure > video::cue { */
/* font-size: 0.875em; */
/* margin: 1em; */
/* padding: 0.5em; */
/* } */
/* media-provider > video::cue { */
/* display: none; */
/* } */
ol > li {
list-style: decimal;
}
li::marker {
color: var(--pico-muted-color);
}
/* ==================== Dark Mode Overrides ==================== */
@media only screen and (prefers-color-scheme: dark) {
:root:not([data-theme]) {
/* Marginalia - Dark Mode */
--mbr-marginalia-bg: rgba(32, 38, 50, 0.6);
/* GitHub Alerts - Dark Mode */
--mbr-alert-note-bg: rgba(13, 71, 161, 0.2);
--mbr-alert-note-border: #42a5f5;
--mbr-alert-note-icon-color: #42a5f5;
--mbr-alert-tip-bg: rgba(27, 94, 32, 0.2);
--mbr-alert-tip-border: #66bb6a;
--mbr-alert-tip-icon-color: #66bb6a;
--mbr-alert-important-bg: rgba(74, 20, 140, 0.2);
--mbr-alert-important-border: #ab47bc;
--mbr-alert-important-icon-color: #ab47bc;
--mbr-alert-warning-bg: rgba(230, 81, 0, 0.2);
--mbr-alert-warning-border: #ffa726;
--mbr-alert-warning-icon-color: #ffa726;
--mbr-alert-caution-bg: rgba(183, 28, 28, 0.2);
--mbr-alert-caution-border: #ef5350;
--mbr-alert-caution-icon-color: #ef5350;
/* Task annotations - Dark Mode */
--mbr-task-pri-high-color: #ffa726;
--mbr-task-pri-urgent-color: #ef5350;
--mbr-task-tag-bg: rgba(148, 163, 184, 0.2);
--mbr-task-chip-bg: rgba(148, 163, 184, 0.14);
--mbr-task-flash-color: rgba(255, 213, 79, 0.28);
}
}
[data-theme="dark"] {
/* Pull Quote - Dark Mode */
--mbr-pullquote-bg: rgba(42, 49, 64, 0.4);
--mbr-pullquote-border: var(--pico-primary-hover);
/* Marginalia - Dark Mode */
--mbr-marginalia-bg: rgba(32, 38, 50, 0.6);
/* GitHub Alerts - Dark Mode */
--mbr-alert-note-bg: rgba(13, 71, 161, 0.2);
--mbr-alert-note-border: #42a5f5;
--mbr-alert-note-icon-color: #42a5f5;
--mbr-alert-tip-bg: rgba(27, 94, 32, 0.2);
--mbr-alert-tip-border: #66bb6a;
--mbr-alert-tip-icon-color: #66bb6a;
--mbr-alert-important-bg: rgba(74, 20, 140, 0.2);
--mbr-alert-important-border: #ab47bc;
--mbr-alert-important-icon-color: #ab47bc;
--mbr-alert-warning-bg: rgba(230, 81, 0, 0.2);
--mbr-alert-warning-border: #ffa726;
--mbr-alert-warning-icon-color: #ffa726;
--mbr-alert-caution-bg: rgba(183, 28, 28, 0.2);
--mbr-alert-caution-border: #ef5350;
--mbr-alert-caution-icon-color: #ef5350;
/* Task annotations - Dark Mode */
--mbr-task-pri-high-color: #ffa726;
--mbr-task-pri-urgent-color: #ef5350;
--mbr-task-tag-bg: rgba(148, 163, 184, 0.2);
--mbr-task-chip-bg: rgba(148, 163, 184, 0.14);
--mbr-task-flash-color: rgba(255, 213, 79, 0.28);
}
/* ==================== Standard Block Quotes (> - Level 1 Nesting) ==================== */
blockquote {
/* avoid awkward indents when we nest blockquotes by clearing some defaults */
padding: 0;
border: none;
}
blockquote > p:last-child {
/* this will remove the double padding from the blockquote element and the p for all of these */
margin-bottom: 0;
}
:not(blockquote) > blockquote:not(:has(> blockquote)) {
padding: var(--pico-spacing);
border-left: 0.25rem solid var(--pico-blockquote-border-color);
}
blockquote:not(:has(blockquote)) p {
font-style: italic;
}
blockquote > p {
font-size: var(--pico-font-size);
}
/* ==================== Pull Quotes (>> - Level 2 Nesting) ==================== */
/*
* Pull quotes are created with double blockquote nesting (>>).
* Styled like magazine pull quotes: larger text, bold border, italic styling.
*
* Example markdown:
* >> This is a pull quote with larger, emphasized text
*/
:not(blockquote) > blockquote > blockquote:not(:has(> blockquote)) {
--pico-font-size: 1.5rem;
--pico-font-weight: 500;
font-style: italic;
background-color: var(--mbr-pullquote-bg);
border-left: 0.5rem solid var(--mbr-pullquote-border);
color: var(--mbr-pullquote-color);
padding: calc(var(--pico-spacing) * 2);
}
/* ==================== GitHub-Style Alerts ==================== */
/*
* GitHub-style alert blockquotes with semantic colors and icons.
* Classes are automatically added by pulldown-cmark for markdown like:
*
* > [!NOTE]
* > This is a note alert
*/
/* Base alert styling */
blockquote.markdown-alert-note,
blockquote.markdown-alert-tip,
blockquote.markdown-alert-important,
blockquote.markdown-alert-warning,
blockquote.markdown-alert-caution {
position: relative;
padding: var(--pico-spacing);
padding-left: calc(var(--pico-spacing) * 2.5);
margin: var(--pico-typography-spacing-vertical) 0;
border-left: 0.5rem solid;
border-radius: var(--pico-border-radius);
}
/* Icon positioning */
blockquote.markdown-alert-note::before,
blockquote.markdown-alert-tip::before,
blockquote.markdown-alert-important::before,
blockquote.markdown-alert-warning::before,
blockquote.markdown-alert-caution::before {
content: "";
position: absolute;
left: calc(var(--pico-spacing) * 0.75);
top: calc(var(--pico-spacing) * 1.5);
width: 22px;
height: 22px;
mask-size: contain;
mask-repeat: no-repeat;
mask-position: center;
}
/* Alert title styling */
blockquote.markdown-alert-note > p:first-of-type::before,
blockquote.markdown-alert-tip > p:first-of-type::before,
blockquote.markdown-alert-important > p:first-of-type::before,
blockquote.markdown-alert-warning > p:first-of-type::before,
blockquote.markdown-alert-caution > p:first-of-type::before {
--pico-font-weight: 700;
display: block;
margin-bottom: 0.25rem;
}
/* Note Alert (Blue) */
blockquote.markdown-alert-note {
background-color: var(--mbr-alert-note-bg);
border-color: var(--mbr-alert-note-border);
}
blockquote.markdown-alert-note::before {
mask-image: var(--mbr-icon-note);
background-color: var(--mbr-alert-note-icon-color);
}
blockquote.markdown-alert-note > p:first-of-type::before {
content: "Note";
color: var(--mbr-alert-note-icon-color);
}
/* Tip Alert (Green) */
blockquote.markdown-alert-tip {
background-color: var(--mbr-alert-tip-bg);
border-color: var(--mbr-alert-tip-border);
}
blockquote.markdown-alert-tip::before {
background-color: var(--mbr-alert-tip-icon-color);
mask-image: var(--mbr-icon-tip);
}
blockquote.markdown-alert-tip > p:first-of-type::before {
content: "Tip";
color: var(--mbr-alert-tip-icon-color);
}
/* Important Alert (Purple) */
blockquote.markdown-alert-important {
background-color: var(--mbr-alert-important-bg);
border-color: var(--mbr-alert-important-border);
}
blockquote.markdown-alert-important::before {
mask: var(--mbr-icon-important);
background-color: var(--mbr-alert-important-icon-color);
}
blockquote.markdown-alert-important > p:first-of-type::before {
content: "Important";
color: var(--mbr-alert-important-icon-color);
}
/* Warning Alert (Orange) */
blockquote.markdown-alert-warning {
background-color: var(--mbr-alert-warning-bg);
border-color: var(--mbr-alert-warning-border);
}
blockquote.markdown-alert-warning::before {
background-color: var(--mbr-alert-warning-icon-color);
mask-image: var(--mbr-icon-warning);
}
blockquote.markdown-alert-warning > p:first-of-type::before {
content: "Warning";
color: var(--mbr-alert-warning-icon-color);
}
/* Caution Alert (Red) */
blockquote.markdown-alert-caution {
background-color: var(--mbr-alert-caution-bg);
border-color: var(--mbr-alert-caution-border);
}
blockquote.markdown-alert-caution::before {
mask-image: var(--mbr-icon-caution);
background-color: var(--mbr-alert-caution-icon-color);
}
blockquote.markdown-alert-caution > p:first-of-type::before {
content: "Caution";
color: var(--mbr-alert-caution-icon-color);
}
/* Incomplete marker — TK/TODO/FIXME/XXX, or whatever incomplete_markers
* configures. A block whose first text starts with a marker is wrapped whole;
* every other occurrence has just the marker word wrapped. The first wrapper on
* a source line also carries an id="mbr-marker-{line}" deep-link anchor.
* Highlights drafts in server/GUI mode; off by default in static builds. */
.mbr-incomplete {
background: var(--mbr-incomplete-bg);
padding: 0 0.15rem;
border-radius: 2px;
}
/* A block-initial wrap containing a later inline wrap would otherwise stack two
* translucent washes on the same word. The outer span already says "this block
* is incomplete"; the inner one has nothing left to add. */
.mbr-incomplete .mbr-incomplete {
background: none;
padding: 0;
}
/* ==================== Task Lists ==================== */
/*
* Markup emitted by `markdown::collect_events_and_headings` for `- [ ]`,
* `- [x]`, `- [-]` (canceled) and `- [>]` (moved), with the `@due` / `@done` /
* `#tag` / `!!` annotations lifted out of the text and rendered as chips:
*
* <li><input type="checkbox" class="mbr-task-check" id="mbr-task-12"
* data-mbr-task-line="12" data-mbr-task-status="open" disabled>
* <span class="mbr-task-text">write the report</span>
* <span class="mbr-task-pri mbr-task-pri-urgent" …></span>
* <span class="mbr-task-tag">#work</span>
* <time class="mbr-task-due" datetime="2026-08-05">Aug 5</time></li>
*
* The `<li>` carries no class of its own -- pulldown-cmark gives the HTML
* writer no attribute channel for list items -- so the bullet is suppressed by
* matching on the checkbox instead. The second selector covers a loose list,
* where the item's content is wrapped in a paragraph.
*/
li:has(> .mbr-task-check),
li:has(> p > .mbr-task-check) {
list-style: none;
}
.mbr-task-check {
/* Vertically centre against the text rather than sitting on the baseline. */
vertical-align: middle;
margin-inline-end: 0.4em;
}
/* Only when editing is on does `mbr-task-doc.ts` drop `disabled` and add this
* class -- a box that cannot be written to must not invite a click. */
.mbr-task-check.mbr-task-editable {
cursor: pointer;
}
/*
* Arrival flash for a `#mbr-task-42` deep link, applied to the task's <li> by
* `mbr-task-doc.ts` on load and on every hashchange.
*
* A fading background rather than a border or an outline, so nothing in the
* line moves: a layout shift landing at the same moment as the fragment jump
* would scroll the task the user just followed a link to back off screen.
*/
@keyframes mbr-task-flash {
from {
background-color: var(--mbr-task-flash-color, rgba(255, 213, 79, 0.55));
}
to {
background-color: transparent;
}
}
li.mbr-task-flash,
.mbr-task-flash {
border-radius: 4px;
animation: mbr-task-flash 1.6s ease-out 1;
}
/* Respect a reduced-motion preference by holding the highlight steady and
* letting the cleanup timeout remove it, rather than animating it away. */
@media (prefers-reduced-motion: reduce) {
li.mbr-task-flash,
.mbr-task-flash {
animation: none;
background-color: var(--mbr-task-flash-color, rgba(255, 213, 79, 0.55));
}
}
/* Canceled (`[-]`) and moved (`[>]`) tasks. Replaces the bare <s> the old
* renderer emitted, so the strikethrough now stops at the task's own text and
* leaves its subtasks and chips legible. */
.mbr-task-canceled {
text-decoration: line-through;
color: var(--mbr-task-canceled-color);
}
/* Priority dot. Empty by design: the element is a swatch, and its meaning
* reaches assistive tech through `role="img"` + `aria-label`. */
.mbr-task-pri {
display: inline-block;
width: var(--mbr-task-pri-size);
height: var(--mbr-task-pri-size);
border-radius: 50%;
vertical-align: baseline;
}
.mbr-task-pri-high {
background: var(--mbr-task-pri-high-color);
}
.mbr-task-pri-urgent {
background: var(--mbr-task-pri-urgent-color);
}
.mbr-task-tag {
background: var(--mbr-task-tag-bg);
color: var(--mbr-task-tag-color);
border-radius: var(--mbr-task-chip-radius);
padding: 0.05em 0.5em;
font-size: 0.85em;
white-space: nowrap;
}
/*
* Date chips. Styled neutrally on purpose: whether a due date is overdue
* depends on today's date, and this HTML is cached by the server and frozen
* outright by a static build, so an "overdue" class baked in at render time
* would be wrong by the next morning. The frontend adds one at runtime; the
* machine-readable value it needs is already in each chip's `datetime`.
*/
.mbr-task-due,
.mbr-task-completed,
.mbr-task-moved {
background: var(--mbr-task-chip-bg);
color: var(--mbr-task-chip-color);
border-radius: var(--mbr-task-chip-radius);
padding: 0.05em 0.5em;
font-size: 0.85em;
white-space: nowrap;
}
/*
* Chip icons. The gap is a margin rather than a space inside `content`,
* because CSS consumes one whitespace character as the terminator of a hex
* escape -- `content: "\2713 "` renders the tick with no space after it.
*/
.mbr-task-due::before,
.mbr-task-completed::before,
.mbr-task-moved::before {
margin-inline-end: 0.3em;
}
.mbr-task-due::before {
content: "\1F5D3\FE0E"; /* 🗓 calendar, text presentation */
}
.mbr-task-completed::before {
content: "\2713"; /* ✓ */
}
.mbr-task-moved::before {
content: "\2192"; /* → */
}
/* ==================== Marginalia (>>> - Level 3+ Nesting) ==================== */
/*
* Marginalia are created with triple blockquote nesting (>>>).
* Uses a hover/click indicator to reveal sidenote content when there aren't margins.
*
* Example markdown:
* >>> This is a margin note shown in gutter or via indicator
*/
/* Marginalia container - inline indicator approach */
blockquote blockquote:has(blockquote) {
position: relative;
}
blockquote blockquote blockquote {
display: block;
position: absolute;
left: 100%;
top: -3rem;
font-size: 0.75em;
}
/* Indicator marker */
blockquote blockquote blockquote::before {
content: "†";
display: inline-block;
color: var(--pico-primary);
font-weight: 700;
font-size: 1.5em;
cursor: pointer;
padding: 0 4px;
border-radius: var(--pico-border-radius);
}
blockquote blockquote blockquote:hover::before,
blockquote blockquote blockquote:focus-within::before {
background-color: var(--mbr-marginalia-bg);
}
/* Hide marginalia content by default if screen is less than x pixels; media queries below override */
blockquote blockquote blockquote p {
position: absolute;
display: none;
z-index: 1000;
/* Popover styling */
background-color: var(--pico-background-color);
border: 1px solid var(--mbr-marginalia-border);
border-left: 3px solid var(--pico-primary);
border-radius: var(--pico-border-radius);
box-shadow: var(--pico-box-shadow);
padding: calc(var(--pico-spacing) * 0.75);
margin: 0;
/* Sizing and positioning */
min-width: 280px;
max-width: 90vw;
transform: translateX(-100%) translateY(-50%);
/* Text styling */
--pico-font-size: 0.875em;
--pico-line-height: 1.15;
}
/* Show marginalia on hover */
blockquote blockquote blockquote:hover p,
blockquote blockquote blockquote:focus-within p {
display: block;
}
/* Popover arrow - points right toward the † indicator */
blockquote blockquote blockquote p::before {
content: "";
position: absolute;
left: 100%;
top: 12px;
border: 8px solid transparent;
border-left-color: var(--mbr-marginalia-border);
}
blockquote blockquote blockquote p::after {
content: "";
position: absolute;
left: 100%;
top: 13px;
border: 7px solid transparent;
border-left-color: var(--pico-background-color);
margin-left: -1px;
}
/* Show marginalia fixed in margin when screen is wide enough.
*
* `screen and` for the same WebKit reason as the sidebar block above, and here
* it changes printed output: the print block resets these paragraphs' position,
* transform and max-width but NOT their `width`, so on a Safari window ≥2000px
* an unqualified query left `width: calc(100vw - 40px)` -- a *window*-relative
* width in WebKit -- applied to every margin note on paper. */
@media screen and (min-width: 2000px) {
blockquote blockquote blockquote::before {
content: "";
}
blockquote blockquote blockquote p {
left: calc(100% + 5px);
width: calc(100vw - 40px);
transform: translateY(-50%);
max-width: 250px;
display: block;
border: none;
box-shadow: none;
background: none;
border-radius: 0;
}
blockquote blockquote blockquote p::before,
blockquote blockquote blockquote p::after {
left: auto;
right: 20px;
border: none;
transform: none;
}
}
/* Multiple paragraphs in marginalia */
blockquote blockquote blockquote p + p {
position: static;
visibility: visible;
opacity: 1;
display: none;
margin-top: calc(var(--pico-typography-spacing-vertical) * 0.5);
padding: 0;
border: none;
box-shadow: none;
background: none;
width: auto;
max-width: none;
}
blockquote blockquote blockquote:hover p + p,
blockquote blockquote blockquote:focus-within p + p {
display: block;
}
/* Touch device support - keep visible longer after tap */
@media (hover: none) {
blockquote blockquote blockquote:focus p,
blockquote blockquote blockquote:active p {
visibility: visible;
display: block;
opacity: 1;
}
}
pre.mermaid {
padding: var(--pico-typography-spacing-vertical);
}
/* ==================== Link Enhancement Tooltips (GUI Mode) ==================== */
/*
* Subtle tooltip styling for links enhanced by mbr-link-enhancement component.
* Only active in GUI mode where browser URL and status bar is not visible.
* Users can override these styles in their own theme.css. And can disable by removing
* the component that adds them or by using display: none; on this selector.
*/
a.mbr-link-enhanced[data-tooltip]::before {
font-size: 0.65em;
background-color: rgb(from var(--pico-tooltip-background-color) r g b / 0.75);
}
a.mbr-link-enhanced[data-tooltip]::after {
color: rgb(from var(--pico-tooltip-background-color) r g b / 0.75);
}
/* ==================== Collapsible Headings + Permalinks ==================== */
/* Hidden sibling content when a heading is collapsed */
.sectionhidden {
display: none;
}
/* Collapsible heading affordance */
.mbr-collapsible {
cursor: pointer;
user-select: none;
}
.mbr-collapsible:focus-visible {
outline: 2px solid var(--pico-primary-focus, var(--pico-primary));
outline-offset: 2px;
}
/* "+" prefix when collapsed */
.mbr-section-collapsed::before {
content: "+ ";
color: var(--pico-muted-color);
font-weight: normal;
}
/* Permalink anchor — hidden by default, revealed on heading hover/focus */
/*
* The "#" is generated content, not a text node, so that selecting a heading
* does not copy it and print/find-in-page never see it. mbr-heading-enhancer.ts
* deliberately leaves the element empty; do not move this back into the markup.
*/
.mbr-heading-anchor::after {
content: "#";
}
.mbr-heading-anchor {
margin-left: 0.4em;
color: var(--pico-muted-color);
text-decoration: none;
font-weight: normal;
opacity: 0;
font-size: 0.85em;
transition: opacity 0.15s ease-in-out;
}
:is(h1, h2, h3, h4, h5, h6):hover .mbr-heading-anchor,
:is(h1, h2, h3, h4, h5, h6):focus-within .mbr-heading-anchor {
opacity: 0.5;
}
.mbr-heading-anchor:hover,
.mbr-heading-anchor:focus {
opacity: 1;
color: var(--pico-primary);
text-decoration: underline;
}
/* ==================== Screen Reader Only (Accessibility) ==================== */
/*
* Visually hidden but accessible to screen readers and search indexers.
* Used for high-weight search content (titles, filenames) that should
* be indexed by Pagefind with maximum weight but not visible on page.
*/
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
/* ==================== Find in Page (GUI mode) ==================== */
/*
* <mbr-find-bar> registers its match ranges in CSS.highlights, which is a
* DOCUMENT-scoped registry, and the ranges point into the light DOM under
* main#wrapper. A ::highlight() rule inside the element's shadow root would
* therefore match nothing at all -- these have to live here, in a sheet linked
* from _head.html on every page and overridable via user.css.
*
* Only color, background-color, text-decoration*, text-shadow and
* -webkit-text-stroke are honoured inside ::highlight(); borders and outlines
* are ignored. An engine without the Custom Highlight API drops just these two
* rules, and the bar falls back to a plain Selection on the active match.
*/
::highlight(mbr-find) {
background-color: rgba(255, 214, 0, 0.4);
color: inherit;
}
::highlight(mbr-find-active) {
background-color: #ff9632;
color: #000;
}
/* ==================== Footnotes (GitHub-Flavored Markdown) ==================== */
/*
* Footnotes are created with [^1] syntax in markdown.
* The footnote definitions appear at the bottom of the document.
*
* Example markdown:
* Here is some text with a footnote[^1].
*
* [^1]: This is the footnote content.
*/
/* Footnote reference links (the superscript numbers in the text) */
sup.footnote-reference {
font-size: 0.75em;
vertical-align: super;
line-height: 0;
text-decoration: none;
font-weight: 600;
top: -0.2em;
}
/* Footnote definitions container - all footnotes at bottom */
.footnote-definition {
font-size: 0.875em;
line-height: 1.5;
margin: 0 0 0.75rem 0;
padding-left: 2.5rem;
color: var(--pico-muted-color);
}
/* Add a subtle divider before the first footnote */
.footnote-definition:first-of-type {
margin-top: var(--pico-spacing);
padding-top: var(--pico-spacing);
border-top: 1px solid var(--pico-muted-border-color);
}
/* Footnote label (the number) */
.footnote-definition-label {
font-weight: 700;
color: var(--pico-primary);
min-width: 2rem;
text-align: right;
padding-right: 0.5rem;
display: inline;
margin: 0;
}
.footnote-definition sup {
vertical-align: baseline;
font-size: 1em;
margin-block-start: 1em;
display: inline;
position: static;
}
.footnote-definition-label::after {
content: ".";
}
/* Footnote content paragraphs */
.footnote-definition p {
margin: 0;
display: inline;
}
/* Back-reference link (↩) */
.footnote-definition a[href^="#fnref"] {
margin-left: 0.25em;
text-decoration: none;
opacity: 0.6;
font-size: 0.9em;
}
.footnote-definition a[href^="#fnref"]:hover {
opacity: 1;
}
/*
* Hover preview card (desktop only), injected by <mbr-footnote-preview>.
* Shows the footnote's content in a floating card when the reader hovers or
* focuses a footnote reference. Positioned via inline left/top by the component.
*/
.mbr-footnote-popover {
position: fixed;
z-index: 1000;
max-width: min(360px, 90vw);
max-height: 50vh;
overflow-y: auto;
padding: 0.5rem 0.75rem;
font-size: 0.875em;
line-height: 1.5;
color: var(--pico-color);
background: var(--pico-background-color);
border: 1px solid var(--pico-muted-border-color);
border-radius: var(--pico-border-radius);
box-shadow: var(--pico-box-shadow, 0 4px 16px rgba(0, 0, 0, 0.18));
}
/* Collapse the definition's inline-flow margins inside the card. */
.mbr-footnote-popover p {
margin: 0;
}
.mbr-footnote-popover p + p {
margin-top: 0.5rem;
}
/* ==================== Definition Lists (FAQ-style disclosure) ==================== */
/*
* Markdown definition lists render as an FAQ: each `<dt>` is a question, and
* its `<dd>` answer is collapsed until the question is activated.
*
* Example markdown:
* What is mbr?
* : A markdown browser, previewer and static site generator.
*
* This is deliberately JavaScript-free. The only hook is `tabindex="0"` on
* every `<dt>` (emitted by `src/html.rs`), which makes the question focusable
* so `:focus` can stand in for "open".
*
* ACCEPTED LIMITATION -- clicking an already-open question does NOT close it,
* because the click just re-focuses a `<dt>` that already has focus and CSS
* has no way to toggle. Clicking a different question, or anywhere off the
* list, does close it. The same mechanic means clicking *inside* an open
* answer (to select its text, say) moves focus to the body and collapses it;
* select from the question end, or print, to work around that. A real toggle
* needs `<details>` markup or JavaScript, and neither is on the table here.
*
* Scoped to `main` so it only ever touches rendered markdown -- `<dl>`s built
* by templates or components stay untouched. (`<mbr-keys>` also renders a
* `<dl>`, but it lives in a shadow root this sheet cannot reach anyway.)
*/
main dl {
margin-block: calc(var(--pico-spacing) * 1.5);
/* Each `dt` draws the separator above itself; this closes off the last
* answer so the list reads as a bounded block. */
border-bottom: 1px solid var(--mbr-dl-separator-color);
}
main dl > dt {
cursor: pointer;
-webkit-user-select: none;
user-select: none;
color: var(--mbr-dl-question-color);
font-weight: var(--mbr-dl-question-weight);
border-top: 1px solid var(--mbr-dl-separator-color);
padding-block: var(--mbr-dl-item-spacing);
/* Hanging indent: the marker sits in the gutter and the second line of a
* long question lines up under the first line's text, not under the marker. */
padding-inline-start: calc(
var(--mbr-dl-marker-size) + var(--mbr-dl-marker-gap)
);
text-indent: calc(
-1 * (var(--mbr-dl-marker-size) + var(--mbr-dl-marker-gap))
);
border-radius: var(--pico-border-radius);
transition: color var(--mbr-dl-transition-duration)
var(--mbr-dl-transition-easing);
}
main dl > dt:hover {
color: var(--mbr-dl-question-hover-color);
}
/* Suppress the ring on mouse activation, then put a real one back for keyboard
* users below -- same idiom as `.mbr-collapsible` above. */
main dl > dt:focus {
outline: none;
}
main dl > dt:focus-visible {
outline: 2px solid var(--pico-primary-focus, var(--pico-primary));
outline-offset: 2px;
}
/* Disclosure marker. A square box clipped to a triangle, rather than the
* classic zero-size border trick, so `rotate()` pivots about the box's centre
* instead of drifting as it turns. */
main dl > dt::before {
content: "";
display: inline-block;
inline-size: var(--mbr-dl-marker-size);
block-size: var(--mbr-dl-marker-size);
margin-inline-end: var(--mbr-dl-marker-gap);
vertical-align: -0.04em;
background-color: var(--mbr-dl-marker-color);
clip-path: polygon(25% 0%, 25% 100%, 90% 50%);
transition: transform var(--mbr-dl-transition-duration)
var(--mbr-dl-transition-easing);
}
/* Rotate the marker while this question's answers are open. The second
* selector reads "the nearest preceding question of the answer holding focus":
* it has a later answer with focus inside, and no *other* question stands
* between the two. Without the `:not()` every question above the open one
* would point down as well. */
main dl > dt:focus::before,
main dl > dt:has(~ dd:focus-within):not(:has(~ dt ~ dd:focus-within))::before {
transform: rotate(90deg);
}
/* Collapsed answer.
*
* `visibility: hidden` is doing more work than it looks. `height: 0;
* overflow: hidden` alone hides the answer visually but leaves any links
* inside it in the tab order, so a keyboard user tabs into content they cannot
* see. `visibility: hidden` removes descendants from both the tab order and
* the accessibility tree, which fixes that.
*
* It has to be `visibility` specifically: `display: none` would kill the
* height transition, and `content-visibility: hidden` / `interactivity: inert`
* would make the answer permanently unfocusable, breaking the focus handoff in
* the rule below. */
main dl > dd {
visibility: hidden;
height: 0;
overflow: hidden;
/* Zeroed so a collapsed answer contributes no height at all. Margins stay 0
* in both states; only padding is restored on open, which keeps the
* separator lines evenly placed. `overflow: hidden` also establishes a block
* formatting context, so a loose definition's `<p>` margins cannot collapse
* out through this box and reopen a gap. */
margin-block: 0;
padding-block: 0;
margin-inline-start: var(--mbr-dl-answer-indent);
color: var(--mbr-dl-answer-color);
}
/* Open answer.
*
* The combinator is `~`, not `+`, because one question may legitimately own
* several answers -- markdown's `Term` / `: one` / `: two` emits a `<dt>`
* followed by two sibling `<dd>`s, and so does any tight list whose entries
* are not blank-line separated. With `+` only the first answer would ever
* open, and since a closed answer is `visibility: hidden` the rest would be
* both invisible and untabbable, i.e. unreachable content.
*
* The `dd:focus-within` selectors are what make tabbing from a question into a
* link inside its answer work. At the instant focus leaves the `dt`,
* `dt:focus ~ dd` still matches, so the answers are visible and their links
* are focusable and can be reached; the moment focus lands inside,
* `dd:focus-within` takes over. Style recalculation happens after the focus
* move, so there is no frame in which neither selector matches and the answer
* flickers shut. `dd:focus-within ~ dd` keeps the *other* answers of a
* multi-answer question open too, so tabbing reaches every one of them.
*
* `dd:focus-within` can never open a *closed* answer on its own: `visibility:
* hidden` makes its descendants unfocusable, so focus can only ever get inside
* by way of the question. */
main dl > dt:focus ~ dd,
main dl > dd:focus-within,
main dl > dd:focus-within ~ dd {
visibility: visible;
height: auto;
padding-block: 0 var(--mbr-dl-item-spacing);
}
/* `~` reaches every later sibling, including the answers belonging to the NEXT
* question, so shut those again. CSS has no "until" combinator; interposing a
* `dt` is how we say "past the end of this entry". These win on specificity
* (one extra type selector) as well as source order, and they are inert
* whenever nothing is focused -- which is why they do not fight the print
* rules below. */
main dl > dt:focus ~ dt ~ dd,
main dl > dd:focus-within ~ dt ~ dd {
visibility: hidden;
height: 0;
padding-block: 0;
}
/* Height only animates where the intrinsic-size keywords can be interpolated.
* Everything is gated together so browsers without it (Safari, at time of
* writing) snap the answer open cleanly rather than animating the padding
* against a height that jumps. No `max-height` magic numbers. */
@supports (interpolate-size: allow-keywords) {
:root {
/* Inherited, so it is set at the root as the feature intends. */
interpolate-size: allow-keywords;
}
main dl > dd {
transition:
height var(--mbr-dl-transition-duration) var(--mbr-dl-transition-easing),
padding-block var(--mbr-dl-transition-duration)
var(--mbr-dl-transition-easing),
visibility var(--mbr-dl-transition-duration);
/* `visibility` interpolates by its own rule -- any value strictly between
* the endpoints resolves to `visible` -- so a closing answer stays on
* screen for the whole duration and only vanishes at the end, which is
* what lets the collapse animate instead of blinking out. `allow-discrete`
* is a no-op for `visibility` itself; it is here so that a genuinely
* discrete property added to this list by an override behaves too. */
transition-behavior: allow-discrete;
}
}
/* Must follow the @supports block: equal specificity, so source order decides. */
@media (prefers-reduced-motion: reduce) {
main dl > dt,
main dl > dt::before,
main dl > dd {
transition: none;
}
}
/* ==================== Print Styles ==================== */
@media print {
/* PAGE MARGINS ARE ZERO ON PURPOSE -- the sheet's margins come from
* `main.container`'s padding below. Do not "restore" a margin here.
*
* A non-zero `@page` margin makes Safari (and WKWebView, i.e. GUI mode) lay
* out a large empty band at the top of EVERY page; Chrome is unaffected.
* Zeroing the page box and moving the whitespace into the content box
* removes it. This was arrived at empirically -- printing is the only way to
* observe it -- so treat the pairing as load-bearing and re-test on Safari
* before changing either half.
*
* The mechanism is NOT the WebKit `@page`-vs-print-media rule-collection
* ordering, which was the obvious suspect: that would predict a band here
* too, since this rule is itself nested inside `@media print`. Whatever the
* true cause, the trigger is the non-zero value, not the nesting. Consistent
* with that, the band could also be cleared at print time by changing any
* print-dialog setting (in either direction) or by enabling print-media
* emulation in devtools -- both of which force a re-layout. GUI mode exposes
* no dialog controls, so there it was unavoidable. */
@page {
margin: 0;
}
/* Hide chrome with an ALLOWLIST, not a denylist.
*
* `<main>` is the content; every other child of `<body>` is chrome. Listing
* the chrome by tag name instead does not survive contact with this
* codebase, because which components are emitted depends on the mode:
* `_display_enhancements.html` adds six elements to every page, `_footer.html`
* adds `<mbr-keys>` and `<mbr-fuzzy-nav>` always, `<mbr-live-reload>` in
* server mode and `<mbr-find-bar>` + `<mbr-link-enhancement>` in GUI mode,
* and the sidebar layout prepends `<mbr-browse-single>`. A denylist silently
* rots every time a component is added, and the failure is invisible until
* someone prints -- a missed element that is `position: fixed` paints on the
* FIRST page only, and one that is `display: block` with height pushes the
* content down. Inverting the test makes new components correct by default.
*
* This also covers the overlays components append straight to `<body>` at
* runtime -- the editor backdrop (`editor-crepe.ts`), the picker backdrop
* (`editor-picker-shared.ts`) and the footnote hover card
* (`mbr-footnote-preview.ts`) -- all of which are `position: fixed` and would
* otherwise paint over page one.
*
* Two carve-outs:
* - `<mbr-genealogy>` sits outside `<main>` but is generated *content*: the
* family chart on `type: person` pages. It printed before this rule
* existed and it still has to.
* - `.mbr-print-keep` is the opt-in for repositories that put real content
* in `.mbr/_footer_custom.html`. Without it their content would vanish
* from the page with no clue why. */
body > *:not(main, mbr-genealogy, .mbr-print-keep) {
display: none !important;
}
/* Reset grid layout for printing */
body.mbr-has-sidebar {
display: block;
}
/* Reduce font size (~40% smaller than base) */
:root {
--pico-font-size: 62.5%;
}
/* The paper margins live HERE, not on `@page` -- see the note by the `@page`
* rule above for why. `--mbr-print-margin-*` are the knobs to override.
*
* Known trade-off of moving the vertical margin into the content box: the
* padding applies at the start and end of the box, so a document that runs
* past one sheet gets its top margin on page 1 and its bottom margin on the
* last page, while continuation pages fall back to the printer's own
* unprintable area. The horizontal padding is unaffected and applies to
* every page. A non-zero `@page` margin is what would give uniform vertical
* margins, and that is exactly what triggers the Safari band. */
main.container {
margin: 0;
padding: var(--mbr-print-margin-block) var(--mbr-print-margin-inline);
max-width: none;
}
/* ---------- Nothing is collapsed or clipped on paper ----------
*
* Every collapse, clamp and clip in this sheet is an affordance for *reading
* on a screen*: it trades content for skimmability, on the understanding
* that the reader can always open the thing back up. Paper takes that
* bargain away. A section the reader collapsed before hitting Print does not
* come back -- it is simply missing from the page, with nothing to indicate
* that anything was there. So print undoes all of it.
*
* The one deliberate exception is `.sr-only`; see the end of this block. */
/* Sibling content hidden by a collapsed heading (`<mbr-heading-enhancer>`).
* This is the one that bites: collapsing is a transient reading gesture, not
* an instruction about the document, and the reader has no reason to expect
* it to follow them onto the paper.
*
* `revert` and not `block`, because the class is applied to whatever
* siblings happen to follow the heading -- `<p>`, `<ul>`, `<table>`,
* `<figure>`, `<pre>` -- and each has its own correct display. `revert`
* hands each element back its user-agent value. */
.sectionhidden {
display: revert;
}
/* The "+" marker announces hidden content. Nothing is hidden here. */
.mbr-section-collapsed::before {
content: none;
}
/* Permalink anchors only exist to be hovered. */
.mbr-heading-anchor {
display: none;
}
/* Raw `<details>` blocks. GFM passes literal `<details><summary>` straight
* through, and `docs/markdown/index.md` actively recommends it as the way to
* get a real toggle -- so a block the reader left closed prints with its body
* missing.
*
* CSS cannot set the `open` attribute, so the only lever is the user agent's
* own `::details-content` box, which carries `content-visibility: hidden`
* while the element is closed. Overriding that is the technique the CSSWG
* settled on when it finally closed csswg-drafts#2084, "Ability to style
* <details>/<summary> to be open (e.g. for print styles)", in August 2025.
*
* BROWSER SUPPORT, PLAINLY: `::details-content` is Chrome/Edge 131+, Safari
* 18.4+, Firefox 143+ (Baseline newly-available, September 2025); GUI mode
* uses the system WebKit, so it tracks the installed Safari. Anywhere older
* this rule is simply dropped as an unknown selector, a closed `<details>`
* still prints closed, and there is NO CSS-only alternative -- no shipping
* engine ever exposed a light-DOM hook for the closed content (Firefox 49-102
* suppressed frame construction outright in C++; everything since, in all
* three engines, hides a shadow slot), which is precisely why that CSSWG
* issue sat open for eight years. Do not add `details > *:not(summary) {
* display: block }` as a "fallback": the selector *matches*, so it looks
* applied in devtools, but the flat-tree slot above it is hidden and nothing
* happens -- in every engine. The real fallback is a `beforeprint` listener
* flipping the `open` attribute, which is JavaScript, and so deliberately
* not done here.
*
* `content-visibility` alone is what defeats the user agent; it does not
* need `!important`, because both Blink and WebKit deliberately let author
* rules outrank the inline style they put on that shadow slot. The
* `!important`s are aimed at *user.css*, which `_head.html` links after this
* sheet: a repository that copied MDN's accordion pattern
* (`details::details-content { block-size: 0; overflow: clip }`) matches this
* selector exactly, and `@media print` adds no specificity, so without them
* source order would re-collapse the block on paper. */
details::details-content {
content-visibility: visible !important;
block-size: auto !important;
overflow: visible !important;
}
/* The marker is drawn from the `open` attribute, which is still absent -- so
* without this the triangle points "closed" beside content that is plainly
* open. `disclosure-open` is the same keyword the UA stylesheet uses for
* `details[open]`, so it is available wherever the marker renders at all. */
details > summary:first-of-type {
list-style-type: disclosure-open;
}
/* Oembed link cards clamp the description to 200px and clip what does not
* fit. There is nothing to clip *for* on paper. */
.mbr-social-link-box {
max-height: none;
overflow: visible;
}
/* Kanban boards lose cards on paper twice over: `height: 85vh` cuts off
* everything below one screenful, and the columns scroll horizontally past
* the width of the sheet. Flattening to a single column is the only shape
* that guarantees every card reaches the page -- the board reads as a run of
* headed lists rather than side-by-side columns, which is the right trade
* when the alternative is dropping cards silently.
*
* `break-after` has to be reset too: `always` is a *page* break once there
* is no multicol context to consume it, so each list would otherwise eject
* the rest of the board onto a fresh sheet.
*
* Unscoped on purpose -- `.kanban` lands on `<section>` for `--- {.kanban}`
* and on `<body>` itself when a note sets `style: kanban` in frontmatter. */
.kanban {
height: auto;
max-height: none;
columns: auto;
overflow: visible;
}
.kanban > ul,
.kanban > ol,
.kanban ul:last-child,
.kanban ol:last-child {
break-before: auto;
break-after: auto;
}
/* Theater figures size themselves against the viewport and bleed to its full
* width. The video is dropped below, but the caption is content and must not
* be squeezed by a viewport-relative height. */
figure.theater {
max-height: none;
width: auto;
margin-inline: 0;
background: none;
}
/* Prevent awkward page breaks */
pre,
code,
figure,
blockquote,
table,
ul,
ol {
page-break-inside: avoid;
}
/* style inline katex the same as inline code by default */
.math-inline {
border-radius: var(--pico-border-radius);
background: var(--pico-code-background-color);
color: var(--pico-code-color);
font-weight: var(--pico-font-weight);
line-height: initial;
font-size: 0.875em;
}
/* Marginalia: display inline for print (not absolute positioned) */
blockquote blockquote:has(blockquote) {
position: static;
}
blockquote blockquote blockquote {
position: static;
display: block;
font-size: 0.85em;
margin: var(--pico-spacing) 0;
padding: var(--pico-spacing);
background-color: var(--mbr-marginalia-bg);
border-left: 3px solid var(--pico-primary);
}
/* Hide the indicator marker in print */
blockquote blockquote blockquote::before {
content: none;
}
/* Show marginalia content normally in print */
blockquote blockquote blockquote p {
position: static;
display: block;
transform: none;
min-width: auto;
max-width: none;
background: none;
border: none;
box-shadow: none;
padding: 0;
margin: 0;
}
/* Hide popover arrows in print */
blockquote blockquote blockquote p::before,
blockquote blockquote blockquote p::after {
content: none;
}
/* Show additional paragraphs in marginalia */
blockquote blockquote blockquote p + p {
display: block;
}
/* Video/media elements: use auto height, hide player controls */
figure > video,
media-player {
max-height: none;
height: auto;
}
/* Hide video player (videos cannot be printed meaningfully) */
media-player,
video {
display: none;
}
/* Show a placeholder message for videos */
figure:has(media-player)::after,
figure:has(video)::after {
content: "[Video content - see digital version]";
display: block;
font-style: italic;
color: var(--pico-muted-color);
padding: var(--pico-spacing);
border: 1px dashed var(--pico-muted-border-color);
text-align: center;
}
/* Reduce GitHub alert icon size for print */
blockquote.markdown-alert-note::before,
blockquote.markdown-alert-tip::before,
blockquote.markdown-alert-important::before,
blockquote.markdown-alert-warning::before,
blockquote.markdown-alert-caution::before {
width: 14px;
height: 14px;
top: calc(var(--pico-spacing) * 1.25);
}
/* Footnotes: ensure they stay together and print cleanly */
.footnote-definition {
page-break-inside: avoid;
color: inherit;
}
.footnote-definition:first-of-type {
break-before: avoid;
}
/* Definition lists: force every answer open. A printed FAQ showing only the
* questions would be useless.
*
* All three selectors are needed. Printing does NOT clear focus -- someone
* who opens a question and then hits Print still has a focused `<dt>` -- so
* the two re-collapse rules would otherwise keep matching and, at one extra
* type selector, outrank a bare `main dl > dd` here. Repeating them verbatim
* makes this an equal-specificity tie that source order settles our way,
* which is why the "Definition Lists" section has to stay above this block. */
main dl > dd,
main dl > dt:focus ~ dt ~ dd,
main dl > dd:focus-within ~ dt ~ dd {
visibility: visible;
height: auto;
overflow: visible;
padding-block: 0 var(--mbr-dl-item-spacing);
}
/* The disclosure chevron means nothing on paper. Dropping the marker box
* also means the question's hanging indent has to be undone, or the first
* line would hang out into the margin. */
main dl > dt::before {
content: none;
}
main dl > dt {
padding-inline-start: 0;
text-indent: 0;
/* Keep a question with the answer it introduces. */
break-after: avoid;
}
main dl > dt,
main dl > dd {
page-break-inside: avoid;
}
/* ---------- DELIBERATE EXCEPTION: `.sr-only` stays hidden ----------
*
* Do not add `.sr-only` to the "nothing is collapsed on paper" rules above.
* It is not collapsed content. `index.html` (and `home`/`section`/`tag`)
* emit a visually hidden *duplicate* of the page title purely so Pagefind
* can weight it (`<span class="sr-only" data-pagefind-weight="10">`) --
* revealing it would print the title twice, once as a stray line and once as
* the real `<h1>` directly beneath it.
*
* Nothing is lost by leaving it: the visible heading carries the same text.
* `aria-hidden` needs no print rule either -- it hides content from the
* accessibility tree, never visually -- and `[hidden]` is deliberately left
* alone, because unlike a collapsed section it is an explicit statement by
* the author that the content does not apply. */
}
/* ==================== Enhanced Oembed Social Link Boxes ==================== */
.mbr-social-link-box {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: 1fr;
grid-column-gap: 1em;
max-width: 900px;
max-height: 200px;
overflow: hidden;
}
.mbr-social-link {
grid-column: span 2;
text-decoration: none;
}
.mbr-social-link header {
font-size: 1rem;
font-weight: bold;
margin-bottom: var(--pico-typography-spacing-vertical);
}
.mbr-social-link p {
font-size: 0.75rem;
margin: 0;
color: var(--pico-secondary);
}
/*
* PRINT TIP: For best results when printing:
* 1. Use light mode (not dark mode)
* 2. Enable "Print backgrounds" in your browser's print dialog
*/
/* ============================= Kanban Display ========================= */
/*
* just use `--- {.kanban}` or put style: kanban in the frontmatter as appropriate
*/
.kanban {
columns: 18rem; /* needs to be fixed since we don't know how many columns */
column-gap: 2rem;
column-fill: auto; /* should avoid balancing and just fill left first */
/* column-rule: 1px solid var(--pico-muted-border-color); */
overflow-x: auto; /* allow horizontal scroll */
overflow-y: visible;
max-width: 100%;
height: 85vh;
}
.kanban h1,
.kanban h2,
.kanban h3,
.kanban h4,
.kanban h5,
.kanban h6 {
margin-top: 0;
break-after: avoid;
-webkit-column-break-after: avoid;
break-inside: avoid;
-webkit-column-break-inside: avoid;
}
.kanban h1:has(+ ul),
.kanban h1:has(+ ol),
.kanban h2:has(+ ul),
.kanban h2:has(+ ol),
.kanban h3:has(+ ul),
.kanban h3:has(+ ol),
.kanban h4:has(+ ul),
.kanban h4:has(+ ol),
.kanban h5:has(+ ul),
.kanban h5:has(+ ol),
.kanban h6:has(+ ul),
.kanban h6:has(+ ol) {
break-after: avoid;
-webkit-column-break-after: avoid;
break-inside: avoid;
-webkit-column-break-inside: avoid;
}
.kanban > ul,
.kanban > ol {
margin-left: 0;
padding-left: 0;
break-after: column;
break-inside: avoid;
-webkit-column-break-inside: avoid;
-webkit-column-break-before: avoid;
break-before: avoid;
}
.kanban > ul > li,
.kanban > ol > li {
margin-bottom: var(--pico-block-spacing-vertical);
padding: var(--pico-block-spacing-vertical)
var(--pico-block-spacing-horizontal);
border-radius: var(--pico-border-radius);
background: var(--pico-card-background-color);
box-shadow: var(--pico-card-box-shadow);
display: block;
/* background-color: var(--pico-card-sectioning-background-color); */
font-weight: bold;
break-inside: avoid;
-webkit-column-break-inside: avoid;
}
.kanban ul > li ul,
.kanban ol > li ol {
font-weight: normal;
margin-top: 1em;
}
.kanban ul:last-child,
.kanban ol:last-child {
break-after: always;
}
/************ OUTLINE **********************/
.outline main {
font-size: 16px;
line-height: 1.6;
}
.outline main h1,
.outline main h2,
.outline main h3,
.outline main h4,
.outline main h5,
.outline main h6 {
font-weight: 600;
line-height: 1.1;
margin: 36px 24px 16px 0;
padding: 0;
}
.outline main h1,
.outline main h2 {
border-bottom: 1px solid #eaecef;
}
.outline main h1 {
font-size: 32px;
line-height: 40px;
margin: 0 0 16px;
padding: 0 0 9.600000381469727px;
}
.outline main h2 {
font-size: 24px;
line-height: 30px;
padding: 0 0 7.199999809265137px;
}
.outline main h3 {
font-size: 20px;
line-height: 25px;
}
.outline main h4 {
font-size: 16px;
line-height: 20px;
margin: 24px 0 16px;
padding: 0;
}
.outline main h5 {
font-size: 14px;
line-height: 17px;
}
.outline main h6 {
font-size: 13.600000381469727px;
line-height: 17px;
}
.outline main {
line-height: 1.6;
padding: 3px;
}
.outline main p {
margin: 1em 0;
}
.outline main > *:first-child {
margin-top: 0 !important;
}
.outline main > *:last-child {
margin-bottom: 0 !important;
}
.outline main p,
.outline main blockquote,
.outline main ul,
.outline main ol,
.outline main dl,
.outline main table,
.outline main pre {
margin-bottom: 16px;
}
.outline main ol,
.outline main ul {
padding-left: 2.6ch;
}
.outline main ul > li {
list-style-type: disc;
}
.outline main ol > li {
list-style-type: upper-alpha;
}
.outline main ol ol > li {
list-style-type: decimal;
}
.outline main ol ol ol > li {
list-style-type: lower-alpha;
}
.outline main ol ol ol ol > li {
list-style-type: lower-roman;
}
.outline main ol ol,
.outline main ol ul,
.outline main ul ul,
.outline main ul ol {
margin-top: 0;
margin-bottom: 0;
}
.outline main li > p {
margin-bottom: 0;
}
.outline main li p + p {
margin-top: 16px;
}
.outline main dl {
padding: 0;
}
.outline main dl dt {
padding: 0;
margin-top: 16px;
font-size: 1em;
font-style: italic;
font-weight: 700;
}
.outline main dl dd {
padding: 0 16px;
margin-bottom: 16px;
}
.outline main blockquote {
padding: 0 15px;
margin-left: 0;
color: #777;
border-left: 4px solid #ddd;
}
.outline main blockquote > :first-child {
margin-top: 0;
}
.outline main blockquote > :last-child {
margin-bottom: 0;
}
@media print {
body.outline {
background: #fff;
}
.outline main img,
.outline main table,
.outline main figure {
page-break-inside: avoid;
}
.outline main {
background: #fff;
border: none !important;
font-size: 12px;
}
.outline main pre code {
overflow: visible;
}
}
.outline main {
counter-reset: H2;
}
.outline main h2 {
counter-reset: H3;
}
.outline main h2:before {
content: counter(H2) ". ";
counter-increment: H2;
counter-reset: H3;
counter-reset: H4;
counter-reset: H5;
}
.outline main h3 {
counter-reset: H4;
}
.outline main h3:before {
content: counter(H2) "." counter(H3) ". ";
counter-increment: H3;
counter-reset: H4;
counter-reset: H5;
}
.outline main h4 {
counter-reset: H5;
}
.outline main h4:before {
content: counter(H2) "." counter(H3) "." counter(H4) ". ";
counter-increment: H4;
counter-reset: H5;
}
.outline main h5:before {
content: counter(H2) "." counter(H3) "." counter(H4) "." counter(H5) ". ";
counter-increment: H5;
}