@charset "UTF-8";

/**
 * Main entry point to the website's stylesheet.
 *
 * The stylesheet is split into layers, imported in order of increasing
 * specificity and reach. Earlier layers set far-reaching defaults. Later
 * layers narrow to to specific elements, components, and one-off helpers.
 *
 * Keeping the cascade flowing downward avoids specificity battles.
 *
 *   fonts       @font-face declarations.
 *   properties  Design tokens.
 *   resets      Cross-browser normalization.
 *   typography  Bare-element text styling.
 *   layout      Page-level structure.
 *   components  Reusable UI components, eg. NavBar.
 *   utilities   Single-purpose helpers; highest specificity, may use !important.
 */

/*
 * FONTS
 *
 * Files live in ../font/ relative to this stylesheet's published location
 * (_/css/site.css -> _/font/*.woff2).
 */

@font-face {
  font-family: "JetBrains Mono";
  src: url("../font/jetbrains-mono/thin.woff2") format("woff2");
  font-weight: 100;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "JetBrains Mono";
  src: url("../font/jetbrains-mono/thin-italic.woff2") format("woff2");
  font-weight: 100;
  font-style: italic;
  font-display: swap;
}

@font-face {
  font-family: "JetBrains Mono";
  src: url("../font/jetbrains-mono/extralight.woff2") format("woff2");
  font-weight: 200;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "JetBrains Mono";
  src: url("../font/jetbrains-mono/extralight-italic.woff2") format("woff2");
  font-weight: 200;
  font-style: italic;
  font-display: swap;
}

@font-face {
  font-family: "JetBrains Mono";
  src: url("../font/jetbrains-mono/light.woff2") format("woff2");
  font-weight: 300;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "JetBrains Mono";
  src: url("../font/jetbrains-mono/light-italic.woff2") format("woff2");
  font-weight: 300;
  font-style: italic;
  font-display: swap;
}

@font-face {
  font-family: "JetBrains Mono";
  src: url("../font/jetbrains-mono/regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "JetBrains Mono";
  src: url("../font/jetbrains-mono/regular-italic.woff2") format("woff2");
  font-weight: 400;
  font-style: italic;
  font-display: swap;
}

@font-face {
  font-family: "JetBrains Mono";
  src: url("../font/jetbrains-mono/medium.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "JetBrains Mono";
  src: url("../font/jetbrains-mono/medium-italic.woff2") format("woff2");
  font-weight: 500;
  font-style: italic;
  font-display: swap;
}

@font-face {
  font-family: "JetBrains Mono";
  src: url("../font/jetbrains-mono/semibold.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "JetBrains Mono";
  src: url("../font/jetbrains-mono/semibold-italic.woff2") format("woff2");
  font-weight: 600;
  font-style: italic;
  font-display: swap;
}

@font-face {
  font-family: "JetBrains Mono";
  src: url("../font/jetbrains-mono/bold.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "JetBrains Mono";
  src: url("../font/jetbrains-mono/bold-italic.woff2") format("woff2");
  font-weight: 700;
  font-style: italic;
  font-display: swap;
}

@font-face {
  font-family: "JetBrains Mono";
  src: url("../font/jetbrains-mono/extrabold.woff2") format("woff2");
  font-weight: 800;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "JetBrains Mono";
  src: url("../font/jetbrains-mono/extrabold-italic.woff2") format("woff2");
  font-weight: 800;
  font-style: italic;
  font-display: swap;
}

/**
 * CUSTOM PROPERTIES (DESIGN TOKENS)
 *
 * The single source of truth for the theme's colors, fonts, and spacing.
 * Other CSS layers consume these via `var()` and should not hard-code
 * equivalent literals.
 *
 * Naming convention: tokens read as `--<group>-<name>-<part>`, all parts
 * hyphen-separated (eg. `--color-text-light`, `--font-weight-medium`). A
 * trailing `-<bp>` denotes a breakpoint-specific value (eg. `--font-size-root-sm`).
 * Tokens are grouped by their leading segment (`--color-*`, `--font-size-*`)
 * and ordered alphabetically.
 */

:root {

  /*
  Font-rendering default required to give JetBrains Mono its
  intended appearance.
  */

  font-optical-sizing: auto;
  font-variant-numeric: tabular-nums lining-nums;

  /*
  Honour the user's light/dark preference. Let browser-rendered
  chrome (form controls, scrollbars) follow it.
  */

  color-scheme: light dark;

  /*
  BASE PALETTE - light mode.

  Color is built in two tiers. A small set of base palette tokens (`--base-*`)
  hold the only literal color definitions in the theme (with a few exceptions).
  The main base colors are an ink, a muted ink, a faint ink, a page, and a 
  muted page tone, and an accent color. Only the base colors are flipped between 
  light and dark modes – nothing else. (Dark mode is defined at the bottom of 
  this file).

  Every semantic color token (`--color-*`) derives from the base palette. Only
  these tokens are references elsewhere in the theme – the base colors are 
  never referenced directly.

  The accent is a subtle signature color used for link underlines, footnote
  markers, and a few other things.

  The text selection background/foreground are NOT flipped between
  light and dark modes. The highlight text (`<mark>`) is a softer,
  translucent version of the same yellow. The alpha lets it tint over
  any background, to the marked text can keep its inherited color and
  stay legible between light and dark modes.

  Everything else is monochrome.
  */

  --base-accent: hsl(176, 100%, 36%);    /* signature color */
  --base-ink: hsl(0, 0%, 15%);           /* primary text, borders, bullets */
  --base-ink-muted: hsl(0, 0%, 50%);     /* secondary/light text */
  --base-ink-faint: hsl(0, 0%, 75%);     /* placeholder text */
  --base-page: hsl(0, 0%, 100%);         /* page background */
  --base-page-muted: hsl(0, 0%, 96%);    /* tinted surfaces: header, code */
  --base-highlight: hsl(50, 100%, 50%);  /* selected text background */
  --base-highlight-ink: hsl(0, 0%, 15%); /* selected text foreground */
  --base-highlight-soft: hsl(50, 100%, 50%, 35%); /* <mark> background */

  /*
  ROLES
  These variables name *roles* and derive their values
  from the base palette, so they invert automatically
  in dark mode.
  */

  --color-accent: var(--base-accent);
  --color-header-background: var(--base-page-muted);
  --color-page-background: var(--base-page);
  --color-text-default: var(--base-ink);
  --color-text-light: var(--base-ink-muted);
  --color-text-placeholder: var(--base-ink-faint);
  --color-border: var(--base-ink);
  --color-bullet: var(--base-ink);
  --color-text-pre-background: var(--base-page-muted);
  --color-text-pre-foreground: inherit;
  --color-text-code-background: var(--base-page-muted);
  --color-text-code-foreground: inherit;
  --color-text-selection: var(--base-highlight);
  --color-text-selection-foreground: var(--base-highlight-ink);
  --color-mark-background: var(--base-highlight-soft);

  /*
  LINKS + OUTLINES
  Ink-colored text with an accent underline and outline.
  */

  --color-hyperlink-active: inherit;
  --color-hyperlink-default: inherit;
  --color-hyperlink-focus: inherit;
  --color-hyperlink-hover: inherit;
  --color-hyperlink-underline: var(--color-accent);
  --color-hyperlink-visited: inherit;
  --color-outline: var(--color-accent);

  /*
  VIDEO BACKGROUND
  The background color for video letter-boxing is always
  black – this is NOT flipped between light and dark mode,
  hence we're not reusing a variable here.
  */

  --color-video: hsl(0, 0%, 15%);

  /*
  FONTS
  Monospace throughout.
  */

  --font-family-default: 'JetBrains Mono', ui-monospace, monospace;
  --font-family-monospace: 'JetBrains Mono', ui-monospace, monospace;

  /*
  FONT WEIGHTS
  */

  --font-weight-bold: 800;
  --font-weight-medium: 600;
  --font-weight-normal: 500;

  /*
  ROOT FONT SIZES
  The root font size scales up at various breakpoints.
  */

  --font-size-root: 9px;
  --font-size-root-xs: 9.25px;   /* screen width ≥ 400px */
  --font-size-root-sm: 9.5px;    /* screen width ≥ 600px */
  --font-size-root-md: 9.75px;   /* screen width ≥ 800px */
  --font-size-root-lg: 10px;     /* screen width ≥ 1000px */
  --font-size-root-xl: 10.5px;   /* screen width ≥ 1200px */
  --font-size-root-xxl: 11px;    /* screen width ≥ 1400px */

  /*
  FONT SIZES
  Six scales, defined relative to the root font size.
  */

  --font-size-lg:  1.6rem;
  --font-size-md:  1.6rem; /* default */
  --font-size-sm:  1.4rem;
  --font-size-xl:  2.2rem;
  --font-size-xs:  1.2rem;
  --font-size-xxl: 3rem;

  /*
  MONOSPACE FONT SIZES
  */

  --font-size-monospace-block: 1.6rem;
  --font-size-monospace-inline: 100%;

  /*
  GRID RHYTHM

  Vertical and horizontal rhythms are established around the base font size.

  All vertical spacing is based on the `--line-height` value, which sets
  the box height for lines of text. All vertical spacing is a multiple of
  this value: 1x, 1.5x, 2x… The line height value is expressed in rem, so 
  it scales with the root font size ladder, keeping the vertical rhythm 
  proportional to everything else that scales with font size. Code blocks 
  get their own, tighter leading.

  Because all text is rendered in a monospace font, we can establish a
  horizontal grid around the width of a single character – expressed by
  the `ch` unit. Indents, padding, and other horizontal spacing align to
  whole character units.

  The `--border-thickness` value is the grid's hairline, used for
  rulers, tables, and form controls.
  */

  --border-thickness: 2px;
  --line-height: 2.5rem;
  --line-height-code: 2rem;

  /*
  SPACING
  */

  --spacing: 4rem;
  --spacing-lg: 8rem;
  --spacing-sm: 6rem;

}

/*
DARK MODE
Color inversions happen here. The four base palette tones
are flipped, and every semantic `--color-*` token follows.
The accent is also brightened a little to keep it punch
against the near-black backdrop.
*/

@media (prefers-color-scheme: dark) {
  :root {
    --base-accent: hsl(176, 70%, 50%);  /* brighter teal for dark bg */
    --base-ink: hsl(0, 0%, 90%);        /* primary text, borders, bullets */
    --base-ink-muted: hsl(0, 0%, 60%);  /* secondary/light text */
    --base-ink-faint: hsl(0, 0%, 35%);  /* placeholder text */
    --base-page: hsl(0, 0%, 8%);        /* page background */
    --base-page-muted: hsl(0, 0%, 14%); /* tinted surfaces: header, code */
  }
}

/**
 * RESETS
 *
 * Normalizes browser defaults to a clean, predictable baseline, so the layers
 * that follow can style from a known starting point. Inspired by the classic
 * resets (Meyer, normalize.css, sanitize.css) but trimmed to what this theme
 * actually uses, and wired to the design tokens in `_properties.css`.
 *
 * BROWSER SUPPORT: Internet Explorer is NOT supported at all. There are no
 * `-ms-` vendor prefixes or IE-specific hacks here. The theme targets modern,
 * evergreen browsers only.
 */

/*
Zero the default margins/padding on every element, so spacing
is owned entirely by the layout and typography layers.
*/

* {
  margin: 0;
  padding: 0;
}

/*
Border-box everywhere – it's easier to work with.
*/

*,
*::after,
*::before {
  box-sizing: border-box;
}

/*
Respect a user's request for less motion. All-but-extinguish
animations, transitions, and smooth scrolling for everyone who
has set this preference. Enforced through high (`!important`)
specificity. Applies globally.
*/

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    scroll-behavior: auto !important;
    transition-duration: 0.01ms !important;
  }
}

/*
Applying page background to the <html> element is
more reliable than <body>. Don't allow the layout
to collapse below the narrowest supported viewpoint.
*/

html {
  background: var(--color-page-background);
  min-width: 320px;
}

/*
Always reserve the vertical scrollbar gutter so centered
content does not shift sideways when navigating between
short and tall pages.
*/

body {
  overflow-x: auto;
  overflow-y: scroll;
}

/*
Drop the grey flash that mobile browsers
paint over a tapped element.
*/

body {
  -webkit-tap-highlight-color: transparent;
}

/*
Force font inheritance through every element. Effects form controls,
which would otherwise ship with their own font family and weight.
This makes it easier to manage the font cascade – everything is
inherited from the root font.
*/

body * {
  font-family: inherit;
  font-weight: inherit;
}

/*
Switch `<var>` from italic to upright text. See also
abbr/dfn/cite/address.
*/

var {
  font-style: normal;
}

/*
Let only `<em>`/`<i>` be italic by default.
*/

em, i {
  font-style: italic;
}

/*
RESPONSIVE ROOT FONT SIZE
The root font size is set in pixels and stepped up over a ladder
of breakpoints.

Because virtually everything else in the theme is sized relative to
the root em size (`rem`), the whole UI scales proportionally to
font size. Increasing the font size at a breakpoint therefore
scales the whole UI – no need to maintain lots of per-element
media queries.

The breakpoints are defined in pixels. Using `rem` units for media query
breakpoints would resolve against the initial root size, which is fixed
at 16px. So we might as well define absolute pixels for the breakpoints.
*/

html {
  font-size: var(--font-size-root);
}

@media screen and (min-width: 400px) {
  html {
    font-size: var(--font-size-root-xs);
  }
}

@media screen and (min-width: 600px) {
  html {
    font-size: var(--font-size-root-sm);
  }
}

@media screen and (min-width: 800px) {
  html {
    font-size: var(--font-size-root-md);
  }
}

@media screen and (min-width: 1000px) {
  html {
    font-size: var(--font-size-root-lg);
  }
}

@media screen and (min-width: 1200px) {
  html {
    font-size: var(--font-size-root-xl);
  }
}

@media screen and (min-width: 1400px) {
  html {
    font-size: var(--font-size-root-xxl);
  }
}

/*
Neutralize the browser's built-in font-size shrinking:
headings, small, nested lists, etc. all reset to 100% (inherit),
so the type scale is set only by the explicit tokens in the
typography layer, not by browser defaults.
*/

html * {
  font-size: 100%;
}

ul ul,
ol ol,
ul ol,
ol ul {
  font-size: 100%;
}

/*
The document's base size – the rem-based type scale keys off this.
*/

body {
  font-size: var(--font-size-md);
}

/*
Font sizes for monospace text can be fine-tuned independently.
*/

pre {
  display: block;
  font-size: var(--font-size-monospace-block);
}

code, kbd, samp, var {
  display: inline;
  font-size: var(--font-size-monospace-inline);
}

/*
Start from a single line-height. The typography layer
sets the real grid rhythm on `body`. Forcing `inherit`
on descendants stops controls and other elements from
reintroducing their own leading.
*/

body {
  line-height: 1;
}

body * {
  line-height: inherit;
}

pre {
  line-height: 1;
}

/*
Hint legibility-priority shaping, and stop iOS inflating
text after an orientation change. `scroll-padding-top`
keeps a heading jumped to via a TOC / in-page anchor
off the very top edge.
*/

html {
  scroll-padding-top: var(--line-height);
  text-rendering: optimizeLegibility;
  -webkit-text-size-adjust: 100%;
     -moz-text-size-adjust: 100%;
          text-size-adjust: 100%;
}

/*
Typographic line-breaking polish. Balance headings so
their lines are evened out rather than left ragged, and
set body copy to avoid orphans (awkward last lines).
Both degrade gracefully where unsupported.
*/

h1, h2, h3, h4, h5, h6 {
  text-wrap: balance;
}

p {
  text-wrap: pretty;
}

/*
Single source of text color, inherited by everything,
so dark mode flips it in one place via the token. A global
`overflow-wrap` is a safety net so a long unbroken string
(eg. a URL) breaks rather than overflowing a narrow column.
*/

body {
  color: var(--color-text-default);
  overflow-wrap: break-word;
}

body * {
  color: inherit;
}

/*
SVGs paint nothing until a layer opts in. This avoids
browsers' default black fill bleeding through. Text
inside an SVG does take the current text color,
however.
*/

svg {
  fill: none;
  stroke: none;
}

svg text {
  fill: currentColor;
}

/*
Markers sit inside the content box (the typography
layer builds the hanging indent on top of this). List
markers are removed here and re-added where required.
*/

ol,
ul {
  list-style-position: inside;
}

ul {
  list-style-type: none;
}

li {
  list-style: inherit;
}

/*
Strip the default 3D groove rule down to nothing.
The typography layer draws its own ruler styles.
*/

hr {
  border: 0;
  border-top: 1px solid var(--color-text-default);
  height: 0;
}

/*
Let long tokens in inline code break rather
than overflow a column.
*/

code {
  overflow-wrap: break-word;
  white-space: pre-line;
  word-break: normal;
}

/*
Preformatted blocks preserve whitespace but wrap,
and scroll horizontally only when a line genuinely
cannot wrap (eg. a long unbroken string).
*/

pre {
  overflow: hidden;
  overflow-x: auto;
  white-space: pre-wrap;
  word-wrap: normal;
}

/*
Clear any browser decoration on abbr/dfn, then give
an abbreviation that carries a `title` a consistent
dotted underline (browsers are inconsistent here)
plus a help cursor, so the expansion is discoverable.
*/

abbr,
dfn {
  text-decoration: none;
}

abbr[title] {
  -webkit-text-decoration: underline dotted;
          text-decoration: underline dotted;
}

abbr[title],
dfn[title] {
  cursor: help;
}

abbr,
dfn {
  font-style: normal;
}

/*
Suppress the browser's automatic quotation marks
around blockquote/q. Quoting is handled explicitly
by the Asciidoctor quote styles.
*/

blockquote,
q {
  quotes: none;
}

blockquote::before, blockquote::after,
q::before, q::after {
  content: '';
}

/*
The `<cite>` element is italic by default. Keep upright.
*/

cite {
  font-style: normal;
}

/*
Remove default decorations from edit/underline elements.
Semantics are conveyed by the typography layer, not
browser defaults.
*/

del,
ins {
  text-decoration: none;
}

s,
u {
  text-decoration: none;
}

/*
Highlight text. A little horizontal padding lifts
the tint off the glyph edges.
*/

mark {
  background: var(--color-mark-background);
  color: inherit;
  padding: 0 0.25ch;
}

/*
Size sub/sup down and zero their line-height so they
don't open up the line box and disturb the baseline grid.
Each is then nudged to its position.
*/

sub,
sup {
  font-size: 75%;
  line-height: 0;
  position: relative;
  vertical-align: baseline;
}

sup {
  top: -0.5em;
}

sub {
  bottom: -0.25em;
}

/*
`<small>` is sized by the typography layer.
Remove default italic styling of `<address>`.
*/

small {
  font-size: 100%;
}

address {
  font-style: normal;
}

/*
Generated content inherits the decoration/alignment
of its originating element rather than resetting, so
`::before`/`::after` glyphs line up.
*/

::before,
::after {
  text-decoration: inherit;
  vertical-align: inherit;
}

/*
Text selection: a fixed highlight with a contrasting
ink, and no text-shadow bleeding through the
highlight.
*/

::-moz-selection {
  background: var(--color-text-selection);
  color: var(--color-text-selection-foreground);
  text-shadow: none;
}

::selection {
  background: var(--color-text-selection);
  color: var(--color-text-selection-foreground);
  text-shadow: none;
}

/*
Collapse the double-border model to single shared borders,
drop cell spacing, and start tables full-width and left-aligned.
The typography layer styles the actual borders/padding onto
this clean base.
*/

table {
  border: 0;
  border-collapse: collapse;
  border-spacing: 0;
  empty-cells: show;
  table-layout: auto;
  text-align: left;
  vertical-align: middle;
  width: 100%;
}

*[dir="rtl"] table {
  text-align: right;
}

/*
Make every table part transparent and inheriting, so
cells take their look from the table rather than browser
defaults.
*/

tbody,
td,
tfoot,
th,
thead,
tr {
  background: inherit;
  border: inherit;
  font-weight: inherit;
  margin: inherit;
  padding: inherit;
  text-align: inherit;
  vertical-align: inherit;
}

caption {
  caption-side: top;
}

/*
Form controls don't inherit font properties by default.
Force them to, so inputs/buttons/selects use the monospace
face and the theme's weights/sizes.
*/

button,
input,
select,
textarea {
  font-family: inherit;
  font-size: inherit;
  font-weight: inherit;
}

optgroup {
  font-style: normal;
}

/*
Strip links back to plain inherited text (no browser
blue/underline). The typography layer re-applies custom
presentation The decoration defaults here mean any later
`text-decoration: underline` starts from a known style.
*/

a {
  color: inherit;
  outline: none;
  text-decoration: none;

  /* Defaults for when text-decoration is re-applied: */
  text-decoration-color: currentColor;
  text-decoration-style: solid;
  text-decoration-thickness: 1px;
  text-underline-offset: 0;
}

/*
A single, visible focus ring in the accent color for
every focusable element, offset off the element so it
reads clearly (accessibility).
*/

*:focus {
  outline-color: var(--color-outline);
  outline-offset: 3px;
  outline-style: solid;
  outline-width: 2px;
}

/*
Show the ring only for keyboard / programmatic focus,
not for mouse clicks. When the browser judges focus not
to warrant a visible indicator (`:not(:focus-visible)`),
hide it.
*/

*:focus:not(:focus-visible) {
  outline: none;
}

/*
Programmatically-focusable-only elements (tabindex=-1)
should never show a ring.
*/

*[tabindex="-1"],
*[tabindex="-1"]:focus {
  outline: none;
}

/*
Pointer cursor on everything interactive (some,
like `details`, don't get it by default).
*/

a,
button,
details,
input[type="button"],
input[type="color"],
input[type="image"],
input[type="range"],
input[type="reset"],
input[type="submit"] {
  cursor: pointer;
}

button[disabled],
input[disabled],
select[disabled],
textarea[disabled] {
  cursor: default;
}

/*
Surface an element's access key as a hint, eg. " [s]".
*/

*[accesskey]::after {
  content: ' [' attr(accesskey) ']';
}

/*
Remove the default fieldset border.
Forms are styled by the controls layer.
*/

fieldset {
  border: 0;
}

/*
Labels stack above their controls by default.
*/

label {
  display: block;
}

/*
Flatten controls to a blank slate (no browser chrome,
transparent, full-width block), so the controls layer can
style them from scratch. The exceptions below opt specific
control types back out of full-width/block.
*/

button,
input,
select,
textarea {
  background: transparent;
  border: 0;
  color: inherit;
  display: block;
  width: 100%;
}

select[multiple],
select[size] {
  height: auto;
}

/*
Color and image inputs are intrinsically sized,
not full-width.
*/

input[type="color"] {
  display: inline-block;
  width: 60px;
}

input[type="image"] {
  display: inline-block;
  width: auto;
}

/*
Give textareas a sane minimum height and disable
the drag-resize handle (which would break the grid).
*/

textarea {
  min-height: 10em;
  overflow: auto;
  resize: none;
}

/*
Checkboxes/radios are small inline toggles, not
full-width blocks. The controls layer draws the
custom square.
*/

input[type="checkbox"],
input[type="radio"] {
  box-sizing: border-box;
  display: inline-block;
  padding: 0;
  vertical-align: baseline;
  width: auto;
}

/*
Keep the native button appearance as the base to restyle.
*/

button {
  -webkit-appearance: button;
     -moz-appearance: button;
          appearance: button;
}

/*
Treat search inputs like plain text fields and
strip WebKit's search decorations/cancel button.
*/

input[type="search"] {
  -webkit-appearance: textfield;
     -moz-appearance: textfield;
          appearance: textfield;
}

input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-decoration {
  -webkit-appearance: none;
          appearance: none;
}

/*
Firefox: remove the inner focus border/padding so the
theme's own focus ring is the only one shown.
*/

button::-moz-focus-inner,
input::-moz-focus-inner {
  border-width: 0;
  padding: 0;
}

/*
Firefox: restore a visible selected-option text by
faking it with a zero-blur text-shadow (works around the
transparent-text focusring quirk).
*/

select:-moz-focusring,
select::-moz-focus-inner {
  color: transparent;
  text-shadow: 0 0 0 white;
}

input[type="range"]::-moz-focus-outer {
  border: 0;
}

/*
Placeholder text uses the muted token at full opacity
(Firefox dims it).
*/

::-moz-placeholder {
  color: var(--color-text-placeholder);
  opacity: 1;
}

::placeholder {
  color: var(--color-text-placeholder);
  opacity: 1;
}

/*
Media elements are block-level. A controls-less
audio element is hidden entirely.
*/

audio,
video {
  display: block;
}

audio:not([controls]) {
  display: none;
}

/*
Images are block-level and never overflow the column.
`height: auto` preserves the aspect ratio. (Inline images
opt back into their attribute size in the asciidoctor layer.)
*/

img {
  border: 0;
  display: block;
  height: auto;
  max-width: 100%;
}

/*
Video letter-boxing shows the fixed video background
token (always black).
*/

video {
  background: var(--color-video);
  max-width: 100%;
}

/*
Embedded content is block-level and capped
to the column width.
*/

iframe,
embed,
object {
  display: block;
  max-width: 100%;
}

iframe {
  border: 0;
}

canvas {
  display: block;
  height: auto;
  max-width: 100%;
}

svg {
  display: block;

  /* Fills container. Height scales proportionally. */
  width: 100%;
  height: auto;
}

/*
Clip a nested SVG's overflow (a non-root SVG can
otherwise paint outside its box in some engines).
*/

svg:not(:root) {
  overflow: hidden;
}

/*
Ensure HTML5 sectioning/semantic elements are block-level in
very, very old browsers that default them to inline.
*/

address,
article,
aside,
details,
footer,
header,
main,
nav,
section,
summary {
  display: block;
}

meter,
progress {
  display: inline-block;
}

/*
Strip the browser chrome off `<dialog>` and popovers
(default border, padding, and the centred/inset positioning)
back to a blank slate. The backdrop's default dim is also
cleared. Both stay hidden until opened.
*/

dialog {
  background: var(--color-page-background);
  border: 0;
  color: inherit;
  margin: auto;
  padding: 0;
}

[popover] {
  background: var(--color-page-background);
  border: 0;
  color: inherit;
  margin: 0;
  padding: 0;
}

::backdrop {
  background: transparent;
}

/* Honour the non-standard `unselectable` attribute. */

*[unselectable] {
  -webkit-user-select: none;
     -moz-user-select: none;
          user-select: none;
}

/*
`[hidden]`/`<template>` must always stay hidden,
even against later display rules — hence `!important`.
*/

*[hidden],
template {
  display: none !important;
}

/*
@deprecated
CLEARFIX: A legacy hack to keep floated children inside
their parent containers. No longer required if modern
layout techniques are used, and the ghost content added by
the hack to pseudo elements cna create layout issue.
Kept here for reference.
*/

/*
:where(
  address, article, aside, blockquote, details, div, dl, fieldset, figure,
  footer, form, header, main, nav, ol, section, ul
)::after {
  clear: both;
  content: '';
  display: table;
}
*/

/**
 * TYPOGRAPHY
 *
 * A minimal typography layer, just setting some global defaults on bare
 * elements. Most typographic styles are set vie components.
 */

body {
  font-family: var(--font-family-default);
  font-weight: var(--font-weight-normal);
  line-height: var(--line-height);
}

strong, b, dfn {
  font-weight: var(--font-weight-bold);
}

small {
  color: var(--color-text-light);
}

/**
 * CONTROLS
 *
 * A minimal baseline of interactive controls.
 *
 * Buttons, text inputs, checkboxes, radios, selects, and textareas are
 * styled through the Form component.
 */

/*
The horizontal scrollbar is given the
grid's line height.
*/

::-webkit-scrollbar {
  height: var(--line-height);
}

/*
Placeholder text. Reset opacity.
*/

::-moz-placeholder {
  color: var(--color-text-light);
  opacity: 1;
}

::placeholder {
  color: var(--color-text-light);
  opacity: 1;
}

/*
DISCLOSURE (details / summary)
The summary is the always-visible toggle. Its marker is a triangle that
points right when closed and down when open.
*/

details {
  border: var(--border-thickness) solid var(--color-border);
  margin-bottom: var(--line-height);
  padding: calc(var(--line-height) - var(--border-thickness)) 1ch;
}

/*
Restore `list-item` so the disclosure triangle
can render.
*/

summary {
  cursor: pointer;
  display: list-item;
  font-weight: var(--font-weight-bold);
}

details[open] summary {
  margin-bottom: var(--line-height);
}

details ::marker {
  content: "▶ ";
}

details[open] ::marker {
  content: "▼ ";
}

/*
The last revealed block sits flush
with the box's bottom padding.
*/

details :last-child {
  margin-bottom: 0;
}

/**
 * LAYOUT
 */

/*
PAGE CENTERING
`round(down, 100%, 1ch)` snaps the column to a whole number
of character cells, so content aligns to the monospace grid
*/

body {
  align-items: center;
  display: flex;
  flex-direction: column;
  width: 100%;
}

.MAIN {
  max-width: calc(min(80ch, round(down, 100%, 1ch)));
  overflow-x: hidden;
  /* padding: calc(var(--line-height) / 2) 2ch var(--line-height) 2ch; */
  padding: 0 2ch;
  position: relative;
  width: 100%;
}

.HEADER {
  border-bottom: var(--border-thickness) solid var(--color-border);
  width: 100%;
}

/*
Breadcrumb section always fills its space even when
there is no nested Breadcrumb component to render.
*/

.BREADCRUMBS {
  margin: 0;
  min-height: calc(var(--line-height) * 2);
}

.FOOTER {
  border-top: var(--border-thickness) solid var(--color-border);
  margin: calc(var(--line-height) * 2) 0 0;
  padding: var(--line-height) 0;
}

/**
 * ASCIIDOCTOR-SPECIFIC STYLES
 *
 * Add typographic elements, compiled from AsciiDoc sources, are encapsulated
 * in an `AsciiDoc` component. This component styles naked typographic elements,
 * and also classes applied by the `asciidoctor` processor.
 *
 * Only a subset of AsciiDoctor-generated markup is covered here – just enough
 * for styling the output generated for this website. The default Asciidoctor
 * v2 style sheet is here – this is our reference:
 * https://cdn.jsdelivr.net/gh/asciidoctor/asciidoctor@2.0/data/stylesheets/asciidoctor-default.css
 */

/*
HEADINGS
Uppercase, bold, and spaced in whole lines.
h1 occupies a double line box, so it still lands on the
grid at its larger size.
*/

.AsciiDoc h1,
.AsciiDoc h2,
.AsciiDoc h3,
.AsciiDoc h4,
.AsciiDoc h5,
.AsciiDoc h6 {
  font-weight: var(--font-weight-bold);
  line-height: var(--line-height);
  margin: calc(var(--line-height) * 2) 0 var(--line-height);
}

.AsciiDoc h1 {
  font-size: var(--font-size-xxl);
  letter-spacing: -0.05rem;
  margin-bottom: calc(var(--line-height) * 2);
  margin-top: calc(var(--line-height) * 4);
  text-transform: uppercase;
}

.AsciiDoc h2 {
  font-size: var(--font-size-xl);
  text-transform: uppercase;
}

.AsciiDoc h3 {
  font-size: var(--font-size-lg);
  text-transform: uppercase;
}

/*
TITLES
Asciidoctor labels many blocks with a `.title`,
which serves as a heading for images, listings, tables, etc.
*/

.AsciiDoc .title {
  color: var(--color-text-default);
  font-weight: var(--font-weight-bold);
  margin: calc(var(--line-height) * 0.5) 0;
  text-transform: uppercase;
}

/*
PARAGRAPHS
*/

.AsciiDoc p {
  hyphens: auto;
  margin: var(--line-height) 0;
  overflow-wrap: break-word;
  word-wrap: break-word;
}

/*
LISTS - BASELINE STYLES
Square bullets for ul. Dotted decimal counters for ol.
A hanging indent is applied: the markers sits flush with the
left margin with the first line and wrapped lines of text indented
at the same level.
*/

.AsciiDoc ul,
.AsciiDoc ol {
  margin: 0 0 var(--line-height);
}

.AsciiDoc ul {
  list-style-type: square;
}

.AsciiDoc ol {
  counter-reset: item;
  list-style-type: none;
}

.AsciiDoc ul li {
  padding-left: 2.75ch;
  text-indent: -2.75ch;
}

.AsciiDoc ol ul,
.AsciiDoc ol ol,
.AsciiDoc ul ol,
.AsciiDoc ul ul {
  margin: 0;
  padding-left: 2.75ch;
  text-indent: 0;
}

/*
The muted tone tints the number/bullet.
The item text stays ink.
*/

.AsciiDoc li::marker {
  color: var(--color-text-default);
  line-height: 0;
}

.AsciiDoc ol li::before {
  color: var(--color-text-default);
  content: counters(item, ".") ". ";
  counter-increment: item;
  font-weight: var(--font-weight-medium);
}

.AsciiDoc ol > li {
  color: var(--color-text-default);
}

/*
LISTS - EXTENDED MARKUP
The Asciidoctor processor wraps every list item's text in a `<p>`
(always, even for a single line), and wraps each list in a
`<div class="ulist">` / `<div class="olist">`.
*/

.AsciiDoc .ulist li > p:first-child,
.AsciiDoc .olist li > p:first-child {
  display: inline;
  margin: 0;
}

/*
DESCRIPTION LISTS
Bold the term and indent the description by whole character units.
*/

.AsciiDoc .dlist dl {
  margin: 0 0 var(--line-height);
}

.AsciiDoc .dlist dt {
  font-weight: var(--font-weight-bold);
}

.AsciiDoc .dlist dd {
  margin: 0 0 var(--line-height) 2ch;
}

.AsciiDoc .dlist dd > p:first-child {
  margin-top: 0;
}

/*
QUESTION & ANSWER
Number the questions and keep answers flush under them.
*/

.AsciiDoc .qlist.qanda ol {
  counter-reset: question;
  list-style-type: none;
  padding-left: 0;
}

.AsciiDoc .qlist.qanda > ol > li::before {
  content: none;
  counter-increment: none;
}

.AsciiDoc .qlist.qanda > ol > li {
  counter-increment: question;
}

.AsciiDoc .qlist.qanda > ol > li > p:first-child::before {
  content: counter(question) ". ";
  font-weight: var(--font-weight-bold);
}

/*
CALLOUT LISTS (colist) & CALLOUT NUMBERS (conum)
A conum is an inline reference marker, shown as an inverted,
bordered box holding its number. The colist below the
code pairs each number with its explanation in a
borderless table.
*/

.AsciiDoc .conum[data-value] {
  background: var(--color-text-default);
  border: var(--border-thickness) solid var(--color-border);
  color: var(--color-page-background);
  display: inline-block;
  font-style: normal;
  font-weight: var(--font-weight-bold);
  height: 2ch;
  line-height: calc(2ch - var(--border-thickness) * 2);
  text-align: center;
  width: 2ch;
}

.AsciiDoc .conum[data-value]::after {
  content: attr(data-value);
}

.AsciiDoc .conum[data-value] + b {
  display: none;
}

.AsciiDoc .colist table {
  margin: 0 0 var(--line-height);
  position: static;
  top: 0;
  width: auto;
}

.AsciiDoc .colist td {
  border: none;
  padding: 0 1ch 0 0;
  vertical-align: top;
}

/*
PREFORMATTED TEXT
Baseline styles for preformatted text blocks, which
are used in several contexts in `asciidoctor` rendering.
By default, preformatted text blocks have a tighter vertical
grid rhythm than body text – this is sometimes overridden
again, eg. for verse blocks.
*/

.AsciiDoc pre {
  font-family: var(--font-family-monospace);
  line-height: var(--line-height-code);
  margin: 0;
  overflow-x: auto;
  overflow-y: hidden;
  white-space: pre;
}

/*
INLINE CODE
A tinted box with hairline border and grid-aligned padding, so
a code span stands out within prose. Block code (inside `<pre>`)
opts back out – see blow.
*/

.AsciiDoc code {
  background: var(--color-text-code-background);
  border: var(--border-thickness) solid var(--color-border);
  color: var(--color-text-code-foreground);
  font-weight: var(--font-weight-medium);
  padding: 0 0.5ch;
}

.AsciiDoc pre code {
  background: none;
  border: 0;
  padding: 0;
  white-space: inherit;
}

/*
RULERS
Applied through pseudo element in a way that does not disturb
the vertical rhythm.
*/

.AsciiDoc hr {
  border: none;
  color: var(--color-border);
  display: block;
  height: var(--line-height);
  margin: calc(var(--line-height) * 1) 0;
  position: relative;
}

.AsciiDoc hr::after {
  border-top: calc(var(--border-thickness) * 1) solid currentColor;
  content: "";
  display: block;
  height: 0;
  left: 0;
  position: absolute;
  top: calc(var(--line-height) / 2 - var(--border-thickness));
  width: 100%;
}

/*
IMAGES & FIGURES
Videos and bare/figure images fill the content column.
Images are NOT given a blanket `width: 100%` here – that would
override the HTML `width`/`height` attributes on inline images,
forcing them to the intrinsic size. Inline images are left to set
their own rendering via width/height attributes.
*/

.AsciiDoc video {
  display: block;
  -o-object-fit: contain;
     object-fit: contain;
  overflow: hidden;
  width: 100%;
}

/*
Text color is set on the images because, if an image fails
to load, its alt text will be rendered in its place.
*/

.AsciiDoc img {
  color: var(--color-text-default);
}

/*
FIGURES
Images within <figure> elements are rendered as blocks
filling the full width of their container.
*/

.AsciiDoc figure {
  margin: calc(var(--line-height) * 2) 4ch;
  overflow-x: auto;
  overflow-y: hidden;
}

.AsciiDoc figcaption {
  display: block;
  text-align: center;
}

.AsciiDoc figure > img {
  display: block;
  -o-object-fit: contain;
     object-fit: contain;
  overflow: hidden;
  width: 100%;
}

/*
TABLES
Full-width, snapped to whole cells, with the grid's
border thickness on every edge and padding computed
so cell text stays on the line grid.
*/

.AsciiDoc table {
  border-collapse: collapse;
  margin: 0 0 calc(var(--line-height) * 2);
  position: relative;
  top: calc(var(--line-height) / 2);
  width: calc(round(down, 100%, 1ch));
}

.AsciiDoc th,
.AsciiDoc td {
  border: var(--border-thickness) solid var(--color-border);
  line-height: var(--line-height);
  padding:
    calc(var(--line-height) / 2)
    calc(1ch - var(--border-thickness) / 2)
    calc(var(--line-height) / 2 - var(--border-thickness));
  text-align: left;
  vertical-align: top;
}

/*
Cell content sits flush: strip the margins off any element nested
in a cell so block children (paragraphs, lists, etc.) don't push
the cell open beyond its padding.
*/

.AsciiDoc th > *,
.AsciiDoc td > * {
  margin: 0;
}

.AsciiDoc th {
  font-weight: var(--font-weight-bold);
}

/*
ADMONITIONS (note, tip, important, caution, warning)
Rather than icons, we use a left rule plus the admonition's name as
an uppercase label — drawn from the icon's `title` attribute via `attr()`.
*/

.AsciiDoc .admonitionblock {
  margin: var(--line-height) 0;
}

.AsciiDoc .admonitionblock > table {
  border-collapse: collapse;
  width: 100%;
}

.AsciiDoc .admonitionblock td {
  border: none;
  padding: 0;
  vertical-align: top;
}

.AsciiDoc .admonitionblock td.icon {
  padding-right: 2ch;
  width: 12ch;
}

.AsciiDoc .admonitionblock td.icon .fa {
  font-style: normal;
  font-weight: var(--font-weight-bold);
  text-transform: uppercase;
}

.AsciiDoc .admonitionblock td.icon .fa::before {
  content: attr(title);
}

.AsciiDoc .admonitionblock td.content {
  border-left: var(--border-thickness) solid var(--color-border);
  padding-left: 2ch;
}

.AsciiDoc .admonitionblock td.content > :first-child,
.AsciiDoc .admonitionblock td.content > :first-child > :first-child {
  margin-top: 0;
}

.AsciiDoc .admonitionblock td.content > :last-child,
.AsciiDoc .admonitionblock td.content > :last-child > :last-child {
  margin-bottom: 0;
}

/*
QUOTE & VERSE BLOCKS
Quoteblock wraps a real `<blockquote>`.
Verseblock keeps line breaks in a `<pre class="content">`.
Both may carry an attribution.
*/

.AsciiDoc .quoteblock,
.AsciiDoc .verseblock {
  border-left: var(--border-thickness) solid var(--color-text-default);
  margin: var(--line-height) 0;
  padding-left: 2ch;
}

.AsciiDoc .verseblock pre.content {
  line-height: var(--line-height);
}

.AsciiDoc .attribution {
  color: var(--color-text-default);
  margin-top: calc(var(--line-height) * 0.5);
}

.AsciiDoc .attribution cite {
  display: block;
}

/*
SIDEBAR & EXAMPLE BLOCKS
 */

.AsciiDoc .sidebarblock,
.AsciiDoc .exampleblock {
  border: var(--border-thickness) solid var(--color-border);
  margin: var(--line-height) 0;
  padding: calc(var(--line-height) * 0.5) 2ch;
}

.AsciiDoc .sidebarblock .title,
.AsciiDoc .exampleblock .title {
  margin-top: 0;
}

.AsciiDoc .sidebarblock .content > :last-child,
.AsciiDoc .sidebarblock .content > :last-child > :last-child,
.AsciiDoc .sidebarblock .content > :last-child > :last-child > :last-child {
    margin-bottom: 0;
}

.AsciiDoc .exampleblock .content > :last-child,
.AsciiDoc .exampleblock .content > :last-child > :last-child,
.AsciiDoc .exampleblock .content > :last-child > :last-child > :last-child {
  margin-bottom: 0;
}

/*
OPEN BLOCK
A bare grouping block with no chrome of its own.
*/

.AsciiDoc .openblock {
  margin: var(--line-height) 0;
}

/*
CODE & LITERAL BLOCKS
*/

.AsciiDoc .listingblock > .content,
.AsciiDoc .literalblock > .content {
  background: var(--color-text-pre-background);
  border: var(--border-thickness) solid var(--color-border);
  margin: var(--line-height) 0;
  padding: var(--line-height) 2ch;
}

.AsciiDoc .listingblock > .content > pre,
.AsciiDoc .literalblock > .content > pre {
  margin: 0;
}

/*
IMAGE BLOCKS & INLINE IMAGES
*/

.AsciiDoc .imageblock {
  margin: calc(var(--line-height) * 2) 0;
}

.AsciiDoc .imageblock img {
  display: block;
  -o-object-fit: contain;
     object-fit: contain;
  width: 100%;
}

.AsciiDoc .imageblock > .title {
  text-align: center;
}

/*
An inline image flows within the text. No width/height is set, so its HTML
`width`/`height` attributes size it.
*/

.AsciiDoc .image {
  display: inline;
}

.AsciiDoc .image > img {
  display: inline;
  max-width: 100%;
  vertical-align: baseline;
}

/*
LINKS
*/

.AsciiDoc a {
  color: var(--color-hyperlink-default);
  text-decoration: underline;
  text-decoration-color: var(--color-hyperlink-underline);
  text-decoration-thickness: var(--border-thickness);
  text-underline-offset: 0.3em;
}

.AsciiDoc a:visited { color: var(--color-hyperlink-visited); }

.AsciiDoc a:hover   { color: var(--color-hyperlink-hover); }

.AsciiDoc a:focus   { color: var(--color-hyperlink-focus); }

.AsciiDoc a:active  { color: var(--color-hyperlink-active); }

/*
FOOTNOTES
In-text reference markers are rendered inline – required resetting
`sup` defaults. Tint the marker link with the accent (the `[ ]` brackets
stay ink).
*/

.AsciiDoc sup.footnote,
.AsciiDoc sup.footnoteref {
  font-size: 100%;
  top: 0;
}

.AsciiDoc sup.footnote > a,
.AsciiDoc sup.footnoteref > a {
  color: var(--color-accent);
}

/*
The endnote list at the page foot.
Separated by a rule, normal body size.
*/

.AsciiDoc #footnotes {
  margin-top: calc(var(--line-height) * 2);
}

.AsciiDoc #footnotes hr {
  margin-bottom: var(--line-height);
}

/*
UI MACROS
The experimental UI macros (`kbd:[]`, `btn:[]`, `menu:[]`)
need the document attribute `:experimental:` to be processed.
*/

.AsciiDoc kbd {
  background: var(--color-header-background);
  border: var(--border-thickness) solid var(--color-border);
  display: inline-block;
  font-family: var(--font-family-monospace);
  line-height: calc(var(--line-height) - var(--border-thickness) * 2);
  margin: 0 0.2ch;
  padding: 0 0.5ch;
  white-space: nowrap;
}

.AsciiDoc .keyseq kbd:first-child {
  margin-left: 0;
}

.AsciiDoc .keyseq kbd:last-child {
  margin-right: 0;
}

.AsciiDoc b.button::before {
  content: "[";
  padding-right: 0.25ch;
}

.AsciiDoc b.button::after {
  content: "]";
  padding-left: 0.25ch;
}

.AsciiDoc .menuseq b {
  font-weight: var(--font-weight-bold);
}

.AsciiDoc .menuseq .caret {
  font-style: normal;
}

.AsciiDoc .menuseq .caret::before {
  content: "›";
  font-weight: var(--font-weight-normal);
  margin: 0 0.5ch;
}

/*
INLINE TEXT ROLES
Built-in Asciidoctor text roles: `[.underline]#...#`,
`[.line-through]#...#`, and alignment roles on paragraphs.
*/

.AsciiDoc .underline {
  text-decoration: underline;
}

.AsciiDoc .line-through {
  text-decoration: line-through;
}

.AsciiDoc .text-center {
  text-align: center;
}

/*
The `[.lead]` role marks an introductory paragraph.
*/

.AsciiDoc .paragraph.lead > p {
  font-size: var(--font-size-lg);
}

/**
 * BREADCRUMBS COMPONENT.
 */

.Breadcrumbs {
  color: var(--color-text-light);
  font-size: var(--font-size-sm);
}

.Breadcrumbs ul {
  -moz-column-gap: 1ch;
       column-gap: 1ch;
  display: flex;
  flex-wrap: wrap;
  list-style: none;
  margin: 0;
  padding: calc(var(--line-height) / 2) 0;
}

.Breadcrumbs li {
  margin: 0;
}

.Breadcrumbs li + li::before,
.Breadcrumbs li:last-child::after {
  color: var(--color-text-light);
  content: "›";
}

.Breadcrumbs li + li::before {
  margin-right: 1ch;
}

.Breadcrumbs li:last-child::after {
  margin-left: 1ch;
}

.Breadcrumbs a:hover,
.Breadcrumbs a:focus {
  text-decoration: underline;
  text-decoration-color: var(--color-hyperlink-underline);
  text-decoration-thickness: var(--border-thickness);
  text-underline-offset: 0.3em;
}

/**
 * FOOTER COMPONENT
 */

.Footer {
  color: var(--color-text-light);
  font-size: var(--font-size-sm);
}

/**
 * FORM CONTROLS
 */

/*
Shared styles for input fields.
`appearance: none` strips native chrome.
*/

.Form input,
.Form button,
.Form select,
.Form textarea {
  -moz-osx-font-smoothing: inherit;
  -webkit-font-smoothing: inherit;

  -webkit-appearance: none;

     -moz-appearance: none;

          appearance: none;
  background: var(--color-page-background);
  border: var(--border-thickness) solid var(--color-text-default);
  color: var(--color-text-default);
  font: inherit;
  font-weight: inherit;
  height: calc(var(--line-height) * 2);
  line-height: normal;
  margin: 0;
  overflow: visible;
  padding:
    calc(var(--line-height) / 2 - var(--border-thickness))
    calc(1ch - var(--border-thickness));
  width: auto;
}

/*
Allow textareas to be resized vertically only.
Horizontal resizing can break layout.
*/

.Form textarea {
  height: auto;
  min-height: calc(var(--line-height) * 4);
  resize: vertical;
}

/*
Text-like inputs fill the available width,
snapped to whole characters.
*/

.Form input,
.Form select,
.Form textarea {
  width: calc(round(down, 100%, 1ch));
}

/*
Checkboxes and radios are compact toggles drawn from the box
itself: a 2ch square (or circle), filled with a solid block when
checked. The height is pinned to the 2ch width (rather than the
line height) so the box stays square regardless of line height,
and centred on the text line via margin.
*/

.Form input[type="checkbox"],
.Form input[type="radio"] {
  cursor: pointer;
  display: inline-grid;
  height: 2ch;
  margin-top: calc((var(--line-height) - 2ch) / 2);
  place-content: center;
  vertical-align: top;
  width: 2ch;
}

/*
The checked mark is a solid block (a dot, for radios)
filling half the box.
*/

.Form input[type="checkbox"]:checked::before,
.Form input[type="radio"]:checked::before {
  background: var(--color-text-default);
  content: "";
  height: 1ch;
  width: 1ch;
}

.Form input[type="radio"],
.Form input[type="radio"]::before {
  border-radius: 100%;
}

/*
Disable outline.
*/

.Form button:focus,
.Form input:focus,
.Form select:focus,
.Form textarea:focus {
  outline: none;
}

/*
Buttons read as uppercase actions and depress slightly when
activated. Unlike the full-width text inputs, a button shrinks to
its label and sits inline, so adjacent buttons line up in a row.
*/

.Form button {
  cursor: pointer;
  display: inline-block;
  font-weight: var(--font-weight-bold);
  text-transform: uppercase;
  vertical-align: top;
  width: auto;
}

/*
Space consecutive inline buttons by one character cell. Cancel
any inherited margin, so a row of buttons stay on one line. Separate
inline buttons with left margin only.
*/

.Form button + button {
  margin-left: 1ch;
  margin-top: 0;
}

.Form button::-moz-focus-inner {
  border: 0;
  padding: 0;
}

.Form button:active {
  transform: translate(2px, 2px);
}

/*
Labels are block-level and grid-wide, so stacked
label/control pairs align.
*/

.Form label {
  display: block;
  font-weight: var(--font-weight-bold);
  height: auto;
  line-height: var(--line-height);
  margin: 0;
  width: calc(round(down, 100%, 1ch));
}

/*
Separate stacked label rows (eg. lists of radios or checkboxes) by one
grid line, so consecutive toggles aren't scrunched together. Adjacent-
sibling only, so the first label in a group keeps its leading flush.
*/

.Form label + label {
  margin-top: var(--line-height);
}

/*
A control nested inside its label fills the
label's width.
*/

.Form label input,
.Form label select,
.Form label textarea {
  width: 100%;
}

/**
 * NAVBAR COMPONENT
 *
 * The primary site navigation. The brand sits on the left and the menu
 * inline on the right. On narrow viewports the menu collapses behind a
 * burger button, and drops down as a full-width list beneath the bar
 * (the `is-open` state is toggled by `40-navbar.js`).
 */

/*
Center-align so everything lines up.
*/

/*
No vertical padding here – the bar's height is set entirely by its tallest
child. The toggle and menu carry their own vertical padding (below) to hold
their normal line-height size and spacing from the bar's edges; the brand
carries none, so it can stretch (via `align-self: stretch` below) to the
bar's complete height.
*/

.NavBar {
  align-items: center;
  display: flex;
  flex-wrap: wrap;
  margin: 0 auto;
  max-width: calc(min(80ch, round(down, 100%, 1ch)));
  padding: 0 2ch;
  row-gap: calc(var(--line-height) / 2);
  width: 100%;
}

/*
A fixed height (matching the toggle/menu's own line-height + padding box,
below) rather than `align-self: stretch` – stretch would resolve against
the flex line's cross-size, which an oversized source image (eg. a 1000px
square PNG dropped in as the logo) would otherwise inflate, growing the
whole bar to match it. `overflow: hidden` then clips the image to this
fixed box no matter its intrinsic size.
*/

.NavBar__Brand {
  display: inline-flex;
  height: calc(var(--line-height) * 2);
  overflow: hidden;
  text-decoration: none;
}

/*
`object-fit: contain` scales the image down (never up) to fit within this
fixed box, preserving its aspect ratio, however large or differently-shaped
the source file is.
*/

.NavBar__BrandImage {
  display: block;
  height: calc(100% - 4px);
  margin: 2px 0;
  -o-object-fit: contain;
     object-fit: contain;
  width: auto;
}

/*
BURGER BUTTON
Shown only on mobile (hidden at >=800px, below).
Pin to the right edge of the bar. `margin-left: auto` keeps the
button hard right whether the menu is hidden (closed) or wrapped
onto its own full-width row (open). Vertical padding holds it at its
normal line-height size and spacing from the bar's top/bottom edges, now
that `.NavBar` itself carries none.
*/

.NavBar__Toggle {
  align-items: center;
  background: transparent;
  border: 0;
  cursor: pointer;
  display: flex;
  height: var(--line-height);
  justify-content: center;
  margin-left: auto;
  padding: calc(var(--line-height) / 2) 0;
  width: auto;
}

/*
The hamburger icon. `flex: none` stops the SVG from
collapsing the icon inside the flex button.
*/

svg.NavBar__ToggleIcon {
  flex: none;
  height: var(--line-height);
  stroke: currentColor;
  stroke-linecap: square;
  stroke-width: var(--border-thickness);
  width: var(--line-height);
}

/*
The menu is a bullet-less list. It takes a full row
of the wrapping flex bar (`flex-basis: 100%`) so it sits
beneath the brand and button, and stacks its items
vertically.
*/

.NavBar__Menu {
  flex-basis: 100%;
  list-style: none;
  margin: 0;
  padding: 0;
}

.NavBar__Menu:not(.is-open) {
  display: none;
}

/*
Right-align the stacked items, under the burger button. `.NavBar` no longer
carries its own vertical padding (see above), so this wrapped second row
supplies its own top spacing (margin-top, as before) and bottom spacing
(padding-bottom) to match.
*/

.NavBar__Menu.is-open {
  align-items: flex-end;
  display: flex;
  flex-direction: column;
  margin-top: calc(var(--line-height) / 2);
  padding-bottom: calc(var(--line-height) / 2);
  row-gap: calc(var(--line-height) / 2);
}

.NavBar__Menu a {
  text-transform: uppercase;
}

/*
On hover/focus, the text menu items show the same accent underline as
links inside `.AsciiDoc`. (The social icon item is excluded, and the brand
is an icon too — it dims instead, like the social icon below.)
*/

.NavBar__Menu > li:not(.NavBar__Social) > a:hover,
.NavBar__Menu > li:not(.NavBar__Social) > a:focus {
  text-decoration: underline;
  text-decoration-color: var(--color-hyperlink-underline);
  text-decoration-thickness: var(--border-thickness);
  text-underline-offset: 0.3em;
}

/*
The social (GitHub) item carries an inline SVG icon rather than
a text label The icon has no text baseline, so on the baseline-aligned
desktop menu it would sit misaligned with the text items. `align-self: center`
centers this one item on the menu line instead.
*/

.NavBar__Social a {
  align-items: center;
  display: inline-flex;
  text-decoration: none;
}

/*
Collapse the inherited line-height so the item box hugs the icon; otherwise
the icon floats at the top of a tall line box and reads as elevated.
*/

@media screen and (min-width: 800px) {
  .NavBar__Social {
    line-height: 0;
  }
}

/*
The icon inherits the link's ink color (overriding the `fill: none` reset)
and brightens to the accent on hover/focus, matching the link behavior. The
glyph is nudged onto the text baseline of the adjacent menu items.
It is sized in `em` so it scales with the adjacent menu text rather than the
(small) root font-size that `--line-height` is based on. `flex: none` stops
the SVG from collapsing inside the shrink-wrapped inline-flex link.
*/

.NavBar__Icon {
  fill: currentColor;
  flex: none;
  width: 1em;
}

.NavBar__Social a:hover .NavBar__Icon,
.NavBar__Social a:focus .NavBar__Icon {
  fill: var(--color-accent);
}

/*
DESKTOP
At >=800px the burger is hidden and the menu is always shown as an
inline horizontal list on the right, regardless of the `is-open` state.
Push the whole menu to the right edge of the bar (the brand stays left),
and right-align the items within it. Vertical padding holds it at its
normal line-height size and spacing from the bar's top/bottom edges, now
that `.NavBar` itself carries none – matching the toggle's mobile padding,
so the bar is the same total height on both breakpoints, and the brand
(stretched to fill it) doesn't jump size when the layout switches.
*/

@media screen and (min-width: 800px) {
  .NavBar__Toggle {
    display: none;
  }

  .NavBar__Menu,
  .NavBar__Menu:not(.is-open),
  .NavBar__Menu.is-open {
    align-items: baseline;
    -moz-column-gap: 2ch;
         column-gap: 2ch;
    display: flex;
    flex-basis: auto;
    flex-direction: row;
    flex-wrap: wrap;
    justify-content: flex-end;
    margin-left: auto;
    margin-top: 0;
    padding: calc(var(--line-height) / 2) 0;
    row-gap: 0;
  }

  /*
  On the baseline-aligned horizontal menu the icon (no text baseline) would
  sit low. Center just this item on the line. (On the mobile dropdown it instead
  follows the column's right-alignment, so this is desktop-only.)
  */

  .NavBar__Social {
    align-self: center;
  }
}

/**
 * FLOATING TABLE OF CONTENTS
 *
 * An on-page contents list with scrollspy – implemented in `50-toc.js`, which
 * reads the rendered page contents and fills the empty `<aside class="TOC">`
 * rendered by `toc.hbs`.
 */

.TOC {
  display: none;
}

/*
Reveal the TOC only on screens where there is enough
empty space in the gutter – between the content and the
right edge of the page.
*/

@media screen and (min-width: 1440px) {

  /*
  Reveal only when the page actually has a contents list.
  The JS leaves the TOC empty on pages with too few headings.
  */

  .TOC:not(:empty) {
    border-left: var(--border-thickness) solid var(--color-border);
    display: block;
    font-size: var(--font-size-sm);
    line-height: var(--line-height);
    max-height: calc(100vh - var(--line-height) * 2);

    /*
    Cap the width of the TOC. Entries longer than this
    are clipped – see `.TOC__List a`.
    */

    max-width: 36ch;
    overflow-y: auto;
    padding-left: 2ch;
    padding-bottom: 1ch;

    /*
    Pinned to the far right of the viewport,
    just inside the scrollbar.
    */

    position: fixed;
    right: 2ch;
    top: calc(var(--line-height) * 2);
  }
}

/*
The small-caps label above the list.
*/

.TOC__Title {
  color: var(--color-text-light);
  font-weight: var(--font-weight-bold);
  margin-bottom: calc(var(--line-height) / 2);
  margin-top: calc(var(--line-height) / 2);
  text-transform: uppercase;
}

/*
The list is bullet-less.
*/

.TOC__List,
.TOC__List ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

/*
Nested (h3) entries indent two cells under
their parent section.
*/

.TOC__List ul {
  padding-left: 2ch;
}

/*
Reset any inherited margins on list items.
*/

.TOC__List li {
  margin: 0;
}

/*
At rest, entries are quiet, ink-light
text with no underline.
*/

.TOC__List a {
  color: var(--color-text-light);
  display: block;
  overflow: hidden;
  text-decoration: none;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/*
On hover, reveal underline.
*/

.TOC__List a:hover {
  text-decoration: underline;
  text-decoration-color: var(--color-accent);
  text-decoration-thickness: var(--border-thickness);
  text-underline-offset: 0.3em;
}

/*
Active item is full-ink text.
*/

.TOC__List .is-active > a {
  color: var(--color-text-default);
}

/**
 * UTILITIES
 */

.left {
  float: left !important
}

.right {
  float: right !important
}

.text-left {
  text-align: left !important
}

.text-right {
  text-align: right !important
}

.text-center {
  text-align: center !important
}

.text-justify {
  text-align: justify !important
}

.hide {
  display: none
}
