/* Built by coppice from its styles/*.css and the site's, in the order of their names: edit those. */

/* --- styles/01-colors.css --- */

/* ==========================================================================
   The site's stylesheet, in parts: main.go joins styles/*.css, in the order
   of their names, into css/site.css. A new part sorts in by its number.

   Fonts: --font-text and --font-mono, with their @font-face rules, come from
   css/fonts.css, which fonts.go writes from Google Fonts at build time.
   ========================================================================== */


/* ==========================================================================
   Colors, picked by theme in config.toml (data-theme on <html>). Each theme
   has a light and a dark side, from its own palette:
     paper        warm paper and ink, after darioamodei.com
     catppuccin   Latte / Mocha
     gruvbox      light / dark, medium contrast
     solarized    light / dark
     nord         Snow Storm / Polar Night
     rose-pine    Dawn / main
     tokyo-night  Day / Night
     everforest   light / dark, medium contrast
     dracula      Alucard / Dracula
     clrs         clrs.cc: white / navy
     spinney      spinney.dev's: white and olive / black and green
   Dark mode follows the OS; there is no toggle.
   ========================================================================== */

:root {
  --bg: #f0eee6; /* ivory paper */
  --fg: #1f1e1d; /* slate ink */
  --muted: #5e5d59; /* dates, notes, hover */
  --border: #d1cfc5; /* rules, quote bar */
  --tint: #00000014; /* code and note-marker backgrounds */
  --tint-hover: #00000026;
  --accent: var(--fg); /* links and the animation */
  color-scheme: light;
}

:root[data-theme="catppuccin"] {
  --bg: #eff1f5; /* base */
  --fg: #4c4f69; /* text */
  --muted: #686b80; /* subtext0, darkened from #6c6f85 to 4.5:1 */
  --border: #bcc0cc; /* surface1 */
  --tint: #dce0e8; /* crust */
  --tint-hover: #ccd0da; /* surface0 */
  --accent: #8839ef; /* mauve */
}

:root[data-theme="gruvbox"] {
  --bg: #fbf1c7; /* bg0 */
  --fg: #3c3836; /* fg1 */
  --muted: #76695f; /* fg4, darkened from #7c6f64 to 4.5:1 */
  --border: #d5c4a1; /* bg2 */
  --tint: #ebdbb2; /* bg1 */
  --tint-hover: #d5c4a1; /* bg2 */
  --accent: #af3a03; /* orange */
}

:root[data-theme="solarized"] {
  --bg: #fdf6e3; /* base3 */
  --fg: #5e727a; /* base00, darkened from #657b83 to 4.5:1 */
  --muted: #677171; /* base1, darkened from #93a1a1 to 4.5:1 */
  --border: #93a1a1; /* base1 */
  --tint: #eee8d5; /* base2 */
  --tint-hover: #93a1a14d;
  --accent: #2073ae; /* blue, darkened from #268bd2 to 4.5:1 */
}

:root[data-theme="nord"] {
  --bg: #eceff4; /* nord6 */
  --fg: #2e3440; /* nord0 */
  --muted: #4c566a; /* nord3 */
  --border: #d8dee9; /* nord4 */
  --tint: #e5e9f0; /* nord5 */
  --tint-hover: #d8dee9; /* nord4 */
  --accent: #4f6c90; /* nord10, darkened from #5e81ac to 4.5:1 */
}

:root[data-theme="rose-pine"] {
  --bg: #faf4ed; /* base */
  --fg: #575279; /* text */
  --muted: #6f6c87; /* subtle, darkened from #797593 to 4.5:1 */
  --border: #dfdad9; /* highlight med */
  --tint: #f2e9e1; /* overlay */
  --tint-hover: #dfdad9; /* highlight med */
  --accent: #79668e; /* iris, darkened from #907aa9 to 4.5:1 */
}

:root[data-theme="tokyo-night"] {
  --bg: #e1e2e7; /* bg */
  --fg: #3760bf; /* fg */
  --muted: #526196; /* fg_dark, darkened from #6172b0 to 4.5:1 */
  --border: #a8aecb; /* fg_gutter */
  --tint: #d0d5e3; /* bg_dark */
  --tint-hover: #c4c8da; /* bg_highlight */
  --accent: #7b44c3; /* magenta, darkened from #9854f1 to 4.5:1 */
}

:root[data-theme="everforest"] {
  --bg: #fdf6e3; /* bg0 */
  --fg: #5c6a72; /* fg */
  --muted: #677366; /* grey2, darkened from #829181 to 4.5:1 */
  --border: #e0dcc7; /* bg4 */
  --tint: #f4f0d9; /* bg1 */
  --tint-hover: #e6e2cc; /* bg3 */
  --accent: #687701; /* green, darkened from #8da101 to 4.5:1 */
}

:root[data-theme="dracula"] {
  --bg: #fffbeb; /* background */
  --fg: #1f1f1f; /* foreground */
  --muted: #635d97; /* comment */
  --border: #cfcfde; /* selection */
  --tint: #cfcfde80;
  --tint-hover: #cfcfde; /* selection */
  --accent: #644ac9; /* purple */
}

/* clrs.cc's gray (#aaa) is too faint for text on white, so quiet text is navy. */
:root[data-theme="clrs"] {
  --bg: #ffffff; /* white */
  --fg: #111111; /* black */
  --muted: #001f3f; /* navy */
  --border: #dddddd; /* silver */
  --tint: #dddddd; /* silver */
  --tint-hover: #aaaaaa; /* gray */
  --accent: #0074d9; /* blue */
}

/* spinney.dev's: clrs.cc's black, silver and white, olive and green, its
   quiet text black mixed into the white. */
:root[data-theme="spinney"] {
  --bg: #ffffff; /* white */
  --fg: #111111; /* black */
  --muted: #6b6b6b; /* black, 62% into white */
  --border: #dddddd; /* silver */
  --tint: #0000000d;
  --tint-hover: #0000001a;
  --accent: #2e7d58; /* olive, darkened from #3d9970 to 4.5:1 */
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #1f1e1d;
    --fg: #f0eee6;
    --muted: #b0aea5;
    --border: #5e5d59;
    --tint: #ffffff1a;
    --tint-hover: #ffffff2e;
    color-scheme: dark;
  }

  :root[data-theme="catppuccin"] {
    --bg: #1e1e2e; /* base */
    --fg: #cdd6f4; /* text */
    --muted: #a6adc8; /* subtext0 */
    --border: #45475a; /* surface1 */
    --tint: #313244; /* surface0 */
    --tint-hover: #45475a; /* surface1 */
    --accent: #cba6f7; /* mauve */
  }

  :root[data-theme="gruvbox"] {
    --bg: #282828; /* bg0 */
    --fg: #ebdbb2; /* fg1 */
    --muted: #a89984; /* fg4 */
    --border: #504945; /* bg2 */
    --tint: #3c3836; /* bg1 */
    --tint-hover: #504945; /* bg2 */
    --accent: #fe8019; /* orange */
  }

  :root[data-theme="solarized"] {
    --bg: #002b36; /* base03 */
    --fg: #839496; /* base0 */
    --muted: #829298; /* base01, lightened from #586e75 to 4.5:1 */
    --border: #586e75; /* base01 */
    --tint: #073642; /* base02 */
    --tint-hover: #586e754d;
    --accent: #3a95d6; /* blue, lightened from #268bd2 to 4.5:1 */
  }

  :root[data-theme="nord"] {
    --bg: #2e3440; /* nord0 */
    --fg: #eceff4; /* nord6 */
    --muted: #d8dee9; /* nord4 */
    --border: #4c566a; /* nord3 */
    --tint: #3b4252; /* nord1 */
    --tint-hover: #434c5e; /* nord2 */
    --accent: #88c0d0; /* nord8 */
  }

  :root[data-theme="rose-pine"] {
    --bg: #191724; /* base */
    --fg: #e0def4; /* text */
    --muted: #908caa; /* subtle */
    --border: #403d52; /* highlight med */
    --tint: #26233a; /* overlay */
    --tint-hover: #403d52; /* highlight med */
    --accent: #c4a7e7; /* iris */
  }

  :root[data-theme="tokyo-night"] {
    --bg: #1a1b26; /* bg */
    --fg: #c0caf5; /* fg */
    --muted: #7d83a9; /* dark5, lightened from #737aa2 to 4.5:1 */
    --border: #3b4261; /* fg_gutter */
    --tint: #292e42; /* bg_highlight */
    --tint-hover: #3b4261; /* fg_gutter */
    --accent: #7aa2f7; /* blue */
  }

  :root[data-theme="everforest"] {
    --bg: #2d353b; /* bg0 */
    --fg: #d3c6aa; /* fg */
    --muted: #9da9a0; /* grey2 */
    --border: #475258; /* bg3 */
    --tint: #343f44; /* bg1 */
    --tint-hover: #3d484d; /* bg2 */
    --accent: #a7c080; /* green */
  }

  :root[data-theme="dracula"] {
    --bg: #282a36; /* background */
    --fg: #f8f8f2; /* foreground */
    --muted: #8692b9; /* comment, lightened from #6272a4 to 4.5:1 */
    --border: #44475a; /* current line */
    --tint: #44475a; /* current line */
    --tint-hover: #6272a4; /* comment */
    --accent: #bd93f9; /* purple */
  }

  :root[data-theme="clrs"] {
    --bg: #001f3f; /* navy */
    --fg: #ffffff; /* white */
    --muted: #dddddd; /* silver */
    --border: #0074d9; /* blue */
    --tint: #111111; /* black */
    --tint-hover: #0074d9; /* blue */
    --accent: #7fdbff; /* aqua */
  }

  :root[data-theme="spinney"] {
    --bg: #111111; /* black */
    --fg: #dddddd; /* silver */
    --muted: #aaaaaa; /* gray */
    --border: #313131; /* silver, 16% into black */
    --tint: #ffffff0f;
    --tint-hover: #ffffff1f;
    --accent: #2ecc40; /* green */
  }

  /* Light text on dark reads heavier; thin the variable weight to match. */
  body {
    font-weight: 370;
  }

  /* SVGs loaded via <img> can't inherit currentColor, so flip them. */
  img[src$=".svg"] {
    filter: invert(1);
  }
}

/* --- styles/02-base.css --- */

/* ==========================================================================
   Base: page, type, links, lists.
   ========================================================================== */

* {
  box-sizing: border-box;
}

/* Keep room for the scrollbar on every page, so pages that scroll and pages
   that don't line up: the animation holds still from home to contact. */
html {
  scrollbar-gutter: stable;
}

/* The column's width and the font sizes. These are the defaults; width
   and [sizes] in config.toml set any of them, as typed, in a <style> after
   this file (base.html). The em sizes are relative to the text around
   them, so they follow text. */
:root {
  --width: 44rem; /* the text's column, on every page */
  --size-text: 1.25rem; /* the body text; a tenth smaller on phones */
  --size-title: 2.6em; /* a page's or post's title, h1 */
  --size-subtitle: 1.1em; /* a post's description, under its title */
  --size-heading: 1.5em; /* ## */
  --size-subheading: 1.25em; /* ### */
  --size-minor: 1.1em; /* #### */
  --size-date: 0.9em; /* dates */
  --size-notes: 0.85em; /* sidenotes and margin notes */
  --size-references: 1em; /* everything after a "## References" heading */
  --size-code: 0.9em; /* code, inline and in blocks */
  --size-captions: 0.9em; /* under pictures and in galleries */
  --size-tables: 0.9em;
  --size-quotes: 1em; /* blockquotes */
  --size-contents: 1em; /* a post's contents list */
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font: 400 var(--size-text)/1.6 var(--font-text);
  font-optical-sizing: auto;
  -webkit-font-smoothing: antialiased;
  counter-reset: sn; /* sidenote numbers */
}

/* Read by screen readers, not shown: the heading of a page whose design
   has none (home, compact pages). */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

::selection {
  background: var(--fg);
  color: var(--bg);
}

/* --- Page column ---------------------------------------------------------- */

/* One column for every page, centred. */
.page {
  max-width: var(--width);
  margin: 0 auto;
  padding: 3rem 20px 6rem;
}

/* The site's own text, everywhere but in posts and the writings list
   (.cased), is set in one case whatever case it's typed in: case in
   config.toml's [fonts] sets --case and --caps (lowercase by default).
   Inside posts and writings, the site's own words (.ui: dates, the back
   link, "Contents") follow it too. Code keeps its case. */
.page:not(.cased),
.cased .ui {
  text-transform: var(--case, lowercase);
  font-variant-caps: var(--caps, normal);
}

.page:not(.cased) :is(code, pre) {
  text-transform: none;
  font-variant-caps: normal;
}

/* --- Headings ------------------------------------------------------------- */

h1,
h2,
h3,
h4 {
  margin: 0;
  line-height: 1.2;
  text-wrap: balance;
}

h1 {
  margin-bottom: 0.2em;
  font-size: var(--size-title);
  font-weight: 700;
  line-height: 1.1;
}

h2 {
  margin: 1em 0 0.5em;
  font-size: var(--size-heading);
  font-weight: 600;
  scroll-margin-top: 5rem;
}

h3 {
  margin: 1em 0 0.7em;
  font-size: var(--size-subheading);
  font-weight: 600;
  scroll-margin-top: 5rem;
}

h4 {
  margin: 1em 0 0.5em;
  font-size: var(--size-minor);
  font-weight: 600;
  scroll-margin-top: 5rem;
}

/* Page and post title, with the italic subtitle and date under it. */
h1.title {
  margin: 0.6em 0 0.1em;
}

.subtitle {
  margin: 0;
  font-size: var(--size-subtitle);
  font-style: italic;
}

.date {
  color: var(--muted);
  font-size: var(--size-date);
  font-variant-numeric: tabular-nums;
}

p.date {
  margin: 2em 0 1em;
}

/* --- Text ----------------------------------------------------------------- */

p {
  margin: 0 0 1em;
}

.body {
  text-wrap: pretty;
}

/* A post's references: everything after its "## References" heading but
   the headings themselves, picture credits included. */
.body #references ~ :not(h2, h3, h4) {
  font-size: var(--size-references);
}

a {
  color: var(--accent);
  text-decoration: underline;
  text-decoration-thickness: 0.08em;
  text-underline-offset: 0.1em;
  transition: color 0.2s linear;
}

a:hover {
  color: var(--muted);
}

a:focus-visible {
  outline: 2px solid var(--fg);
  outline-offset: 2px;
}

ul,
ol {
  margin: 0 0 1em;
  padding-left: 2em;
}

li {
  margin-bottom: 0.3em;
}

@media (max-width: 47.99rem) {
  h1 {
    font-size: calc(var(--size-title) * 0.8);
  }
}

/* Phones: text a tenth smaller, so lines aren't cut too short. */
@media (max-width: 30rem) {
  body {
    font-size: calc(var(--size-text) * 0.9);
  }

  .page {
    padding: 2rem 16px 4rem;
  }
}

/* --- styles/03-content.css --- */

/* ==========================================================================
   Content: quotes, callouts, code, tables, images, rules, math.
   ========================================================================== */

blockquote {
  margin: 2em 0;
  padding: 0.25em 0 0.1em 1.25em;
  border-left: 1px solid var(--border);
  font-size: var(--size-quotes);
  font-style: italic;
  line-height: 1.5;
}

blockquote p {
  margin-bottom: 0.5em;
}

blockquote footer {
  color: var(--muted);
  font-size: 0.9em;
  font-style: normal;
}

/* --- Callouts: > [!NOTE], [!TIP], [!IMPORTANT], [!WARNING], [!CAUTION] ---- */

/* main.go makes them from GitHub's alerts. Their title says which kind,
   not their colour; a warning and a caution have a heavier rule. */
.callout {
  margin: 1.5em 0;
  padding: 0.75em 1em;
  border-left: 3px solid var(--accent);
  border-radius: 0 0.5rem 0.5rem 0;
  background: var(--tint);
}

.callout:is(.warning, .caution) {
  border-left-width: 6px;
}

.callout > :last-child {
  margin-bottom: 0;
}

.callout-title {
  margin: 0 0 0.3em;
  font-size: 0.9em;
  font-weight: 600;
}

/* --- Code ----------------------------------------------------------------- */

/* Monospace looks large next to the text font, so it runs a size down.
   No ligatures: code reads exactly as typed. */
code,
pre {
  font-family: var(--font-mono);
  font-size: var(--size-code);
  line-height: 1.55;
  font-variant-ligatures: none;
  font-feature-settings:
    "liga" 0,
    "calt" 0;
  tab-size: 4;
}

code {
  padding: 0.1em 0.3em;
  border-radius: 4px;
  background: var(--tint);
}

pre {
  margin: 0 0 1em;
  padding: 0.9em 1.1em;
  border-radius: 0.5rem;
  background: var(--tint);
  overflow-x: auto;
}

pre code {
  padding: 0;
  background: none;
  font-size: 1em;
}

/* The copy button js/copy.js puts on each code block: shown when the block
   is pointed at or the button reached by keyboard, and always on touch
   screens, which can't point. */
.code-block {
  position: relative;
  margin: 0 0 1em;
}

.code-block > pre {
  margin: 0;
}

.code-block .copy {
  position: absolute;
  top: 0.45em;
  right: 0.45em;
  padding: 0.1em 0.6em;
  border: 1px solid var(--border);
  border-radius: 4px;
  background: var(--bg);
  color: var(--muted);
  font: inherit;
  font-size: calc(var(--size-code) * 0.85);
  cursor: pointer;
  opacity: 0;
  transition: opacity 0.2s ease;
}

.code-block:hover .copy,
.code-block .copy:focus-visible {
  opacity: 1;
}

.code-block .copy:hover {
  color: var(--fg);
}

.code-block .copy:focus-visible {
  outline: 2px solid var(--fg);
  outline-offset: 2px;
}

@media (hover: none) {
  .code-block .copy {
    opacity: 1;
  }
}

/* --- Tables --------------------------------------------------------------- */

table {
  width: 100%;
  margin: 0 0 1em;
  border-collapse: collapse;
  font-size: var(--size-tables);
  font-variant-numeric: tabular-nums;
}

th,
td {
  padding: 0.3em 0.6em 0.3em 0;
  border-bottom: 1px solid var(--border);
  text-align: left;
}

th {
  border-bottom-color: var(--fg);
  font-weight: 600;
}

/* Narrow screens: a table too wide for the column scrolls sideways
   instead of widening the page. */
@media (max-width: 47.99rem) {
  table {
    display: block;
    overflow-x: auto;
  }
}

/* --- Images and rules ----------------------------------------------------- */

img,
svg {
  display: block;
  max-width: 100%;
  height: auto;
}

.body img {
  border-radius: 0.5rem;
}

figure {
  margin: 2.5em 0;
}

figcaption {
  margin-top: 1em;
  color: var(--muted);
  font-size: var(--size-captions);
}

hr {
  margin: 2em 0;
  border: 0;
  border-top: 1px solid var(--border);
}

/* --- Math ----------------------------------------------------------------- */

/* Display math (MathML, <math display="block">), spaced like a paragraph.
   Too wide for a narrow screen, it scrolls sideways instead of widening
   the page. */
math[display="block"] {
  margin: 1em 0 1.25em;
  overflow-x: auto;
  overflow-y: hidden;
}

/* --- styles/04-galleries.css --- */

/* ==========================================================================
   Galleries: <div class="gallery"> around Markdown images. main.go turns
   each image into a <figure>, its title the caption, and adds a viewer for
   it (below).
   ========================================================================== */

/* Tiles of one shape in a grid, like a game library's covers: each picture
   cropped to 3:4, its caption over its foot when pointed at. The more
   pictures, the smaller the tiles; main.go's tileSide sizes their
   thumbnails to match, from the same 25 and 61. */
.gallery {
  --tile: 10rem;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(var(--tile), 1fr));
  gap: 0.75rem;
  margin: 2em 0;
}

.gallery:has(> figure:nth-child(25)) {
  --tile: 8rem;
}

.gallery:has(> figure:nth-child(61)) {
  --tile: 6.5rem;
}

/* On wide screens the gallery spreads past the text's column, centred on
   it, unless a contents sidebar needs the room. The 6rem spare keeps it
   clear of the scrollbar and the window's edges. */
@media (min-width: 50rem) {
  .page:not(:has(.toc)) .gallery {
    --wide: min(max(72rem, 100%), 100vw - 6rem);
    width: var(--wide);
    margin-left: calc((100% - var(--wide)) / 2);
  }
}

.gallery figure {
  position: relative;
  margin: 0;
  overflow: hidden;
  border-radius: 0.25rem;
  transition:
    transform 0.2s ease,
    box-shadow 0.2s ease;
}

.gallery figure:is(:hover, :focus-within) {
  z-index: 1;
  transform: translateY(-3px) scale(1.04);
  box-shadow: 0 0.5rem 1.25rem #0000004d;
}

.gallery figure > a {
  display: block;
}

.gallery figure > a:focus-visible {
  outline-offset: -2px;
}

.gallery img {
  width: 100%;
  aspect-ratio: 3 / 4;
  object-fit: cover;
}

/* White on a shade dark enough for 4.5:1 over any picture behind it. */
.gallery figcaption {
  position: absolute;
  inset: auto 0 0;
  padding: 2.5em 0.6em 0.5em;
  background: linear-gradient(#0000, #000000d9 2.25em);
  color: #fff;
  font-size: calc(var(--size-captions) * 0.85);
  line-height: 1.3;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease;
}

.gallery figure:is(:hover, :focus-within) figcaption {
  opacity: 1;
}

/* <div class="gallery columns">: columns instead, each picture whole and
   in its own shape, its caption under it, filled top to bottom. Pointed
   at, the picture lifts off the page and its caption darkens, as a tile
   does, but the caption stays put. */
.gallery.columns {
  display: block;
  columns: 4 13rem;
  column-gap: 1.25rem;
}

.gallery.columns figure {
  margin: 0 0 1.5rem;
  overflow: visible;
  break-inside: avoid;
}

.gallery.columns figure:is(:hover, :focus-within) {
  transform: none;
  box-shadow: none;
}

.gallery.columns img {
  aspect-ratio: auto;
  border-radius: 0.25rem;
  transition:
    transform 0.2s ease,
    box-shadow 0.2s ease;
}

.gallery.columns figure:is(:hover, :focus-within) img {
  transform: translateY(-3px) scale(1.02);
  box-shadow: 0 0.5rem 1.25rem #0000004d;
}

.gallery.columns figcaption {
  position: static;
  margin-top: 0.5em;
  padding: 0;
  background: none;
  color: var(--muted);
  font-size: var(--size-captions);
  line-height: 1.4;
  opacity: 1;
  transition: color 0.2s ease;
}

.gallery.columns figure:is(:hover, :focus-within) figcaption {
  color: var(--fg);
}

/* <div class="gallery squares">: square tiles, captions only in the
   viewer. */
.gallery.squares img {
  aspect-ratio: 1;
}

.gallery.squares figcaption {
  display: none;
}

@media (prefers-reduced-motion: reduce) {
  .gallery figure,
  .gallery.columns img {
    transition: none;
  }

  .gallery figure:is(:hover, :focus-within),
  .gallery.columns figure:is(:hover, :focus-within) img {
    transform: none;
  }
}

/* The viewer: one picture at a time, as large as the window allows, over
   the page in its own colours. It shows while the address ends in its id
   (#view-<name>); the backdrop and "close" go back to the tile. */
.viewer {
  display: none;
}

/* Focused when it opens (static/js/gallery.js); the links inside show
   focus themselves. */
.viewer:focus {
  outline: none;
}

.viewer:target {
  position: fixed;
  inset: 0;
  z-index: 10;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 1.5rem 16px;
  background: var(--bg);
}

body:has(.viewer:target) {
  overflow: hidden;
}

.viewer .backdrop {
  position: absolute;
  inset: 0;
}

/* Above the backdrop, so clicks on the picture and links don't close it. */
.viewer figure,
.viewer-nav {
  position: relative;
  margin: 0;
  text-align: center;
}

.viewer img {
  width: auto;
  max-height: calc(100vh - 8rem);
  max-height: calc(100dvh - 8rem);
  margin: 0 auto;
  border-radius: 0;
}

.viewer figcaption {
  margin-top: 0.75em;
}

.viewer-nav {
  display: flex;
  gap: 2em;
  margin-top: 0.5em;
  font-size: 0.9em;
}

/* --- styles/05-sidenotes.css --- */

/* ==========================================================================
   Sidenotes, from {sn|text} and {mn|text} in Markdown (see main.go).
   Wide screens: in the right margin. Narrow: click the number to open inline.
   The number is a small pill, like a footnote marker.
   ========================================================================== */

/* The checkbox each note opens with: out of sight but focusable, so a
   keyboard can open notes too; its label shows the focus. */
input.margin-toggle {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
}

label.margin-toggle:has(+ input:focus-visible) {
  outline: 2px solid var(--fg);
  outline-offset: 2px;
  border-radius: 4px;
}

label.margin-toggle {
  cursor: pointer;
}

.sidenote,
.marginnote {
  display: none;
  color: var(--muted);
  font-size: var(--size-notes);
  line-height: 1.45;
}

/* The number in the text. */
label.sidenote-number::after {
  counter-increment: sn;
  content: counter(sn);
  margin: 0 2px;
  padding: 3px 4px 1px;
  border-radius: 4px;
  background: var(--tint);
  font-size: 0.7em;
  font-weight: 500;
  vertical-align: 0.15em;
}

label.sidenote-number:hover::after {
  background: var(--tint-hover);
}

/* The number in front of the note. */
.sidenote::before {
  content: counter(sn) ". ";
  font-weight: 500;
}

/* Narrow: opened inline under the line. */
input.margin-toggle:checked + .sidenote,
input.margin-toggle:checked + .marginnote {
  display: block;
  margin: 0.5em 0 1em 1em;
}

/* Wide: always shown, floated into the right margin, 2rem off the column.
   A page with notes or a contents sidebar keeps 18rem free on each side for
   them, narrowing its column if width in config.toml leaves less. */
@media (min-width: 76rem) {
  .page:has(.toc, .sidenote, .marginnote) {
    max-width: min(var(--width), 100vw - 36rem);
  }

  .sidenote,
  .marginnote,
  input.margin-toggle:checked + .sidenote,
  input.margin-toggle:checked + .marginnote {
    display: block;
    float: right;
    clear: right;
    width: 14rem;
    margin: 0 -16rem 0 0;
  }

  label.margin-toggle:not(.sidenote-number),
  input.margin-toggle {
    display: none;
  }
}

/* --- styles/06-contents.css --- */

/* ==========================================================================
   Contents (table of contents) for posts with 2+ "##" headings, and the
   docs' sidebar. No JS.
   Narrow screens: a plain numbered list under the date.
   From 60rem: fixed on the left. The ×/☰ button is a <label> for a hidden
   checkbox (.toc-state); checked means closed.
   ========================================================================== */

.toc-state {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.toc {
  margin: 0 0 2em;
  font-size: var(--size-contents);
}

.toc h2 {
  margin: 0 0 0.5em;
  font-size: 1.2em;
}

.toc ol {
  margin: 0;
  padding-left: 1.4em;
}

.toc li {
  margin-bottom: 0.3em;
}

.toc-toggle {
  display: none;
}

/* From 60rem to 76rem the column moves right, clear of the sidebar; with
   the sidebar closed, it's centred again. From 76rem there's room for the
   sidebar on the left and notes on the right of a centred column
   (05-sidenotes.css). */
@media (min-width: 60rem) and (max-width: 75.99rem) {
  .toc-state:not(:checked) ~ .page:has(.toc) {
    max-width: min(var(--width), 78vw - 3rem);
    margin-left: max(22vw + 1rem, (100vw - var(--width)) / 2);
  }
}

@media (min-width: 60rem) {
  /* --- Sidebar ------------------------------------------------------------ */

  .toc {
    position: fixed;
    inset: 0 auto 0 0;
    z-index: 4;
    width: min(22%, 23rem, max((100vw - var(--width)) / 2, 18rem) - 1rem);
    margin: 0;
    padding: 130px 25px 25px;
    overflow-y: auto;
    background: var(--bg);
    /* Fade both ways: allow-discrete keeps it displayed until the fade-out
       ends; @starting-style below fades it in from 0. */
    transition:
      opacity 0.25s ease-out,
      display 0.25s allow-discrete;
  }

  @starting-style {
    .toc {
      opacity: 0;
    }
  }

  .toc-state:checked ~ .page .toc {
    display: none;
    opacity: 0;
  }

  .toc ol {
    margin-top: 30px;
    padding: 0;
    list-style: none;
  }

  .toc li {
    margin-bottom: 0.6em;
    line-height: 1.6;
  }

  /* Quiet but readable (muted is 4.5:1 in every theme); the section being
     read is also bold, so colour isn't the only sign. */
  .toc a {
    color: var(--muted);
    text-decoration: none;
    transition: color 0.2s;
  }

  /* .current marks the section being read (static/js/toc.js). */
  .toc a:hover,
  .toc a.current {
    color: var(--fg);
  }

  .toc a.current {
    font-weight: 600;
  }

  /* --- ×/☰ button --------------------------------------------------------- */

  .toc-toggle {
    position: fixed;
    top: 22px;
    left: 12px;
    z-index: 5;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    border-radius: 4px;
    cursor: pointer;
  }

  .toc-toggle svg {
    width: 24px;
    height: 24px;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.5;
  }

  /* Open shows ×, closed shows ☰. */
  .toc-toggle .menu,
  .toc-state:checked ~ .page .toc-toggle .close {
    display: none;
  }

  .toc-state:checked ~ .page .toc-toggle .menu {
    display: block;
  }

  .toc-state:focus-visible ~ .page .toc-toggle {
    outline: 2px solid var(--fg);
    outline-offset: 2px;
  }
}

/* --- styles/07-pages.css --- */

/* ==========================================================================
   Page-specific bits: the animations, home, writings, 404, the licence and
   the back link.
   ========================================================================== */

/* --- Spinning shapes, home and contact (static/js/shapes.js) -------------- */

/* ASCII art, wider than the text column and centered on the page. The script
   fills in as many characters as fit the box. Hidden without JavaScript. */
pre.shapes {
  width: min(calc(100vw - 32px), 60rem);
  height: min(60vh, 34rem);
  margin: 0 0 1.5rem 50%;
  padding: 0;
  translate: -50%;
  overflow: hidden;
  background: none;
  border-radius: 0;
  font-size: 0.75rem;
  line-height: 1;
  user-select: none;
}

@media (max-width: 30rem) {
  pre.shapes {
    height: min(48vh, 22rem);
    font-size: 0.5625rem;
  }
}

/* A page's description, under its title, before its text or its date. */
.page:not(.cased) .subtitle + .body {
  margin-top: 1.5em;
}

/* 404: the code, small, over the heading. */
p.code {
  margin: 0;
  color: var(--muted);
  font-size: 1.25em;
  font-variant-numeric: tabular-nums;
}

p.code + h1.title {
  margin-top: 0.1em;
}

/* --- Line animations: curve, cycloid, mandelbrot (static/js/) ------------- */

svg.curve,
pre.shapes {
  color: var(--accent);
}

svg.curve {
  width: min(100%, 20rem);
  margin: 0 auto 2.5rem;
}

svg.curve[hidden] {
  display: none;
}

svg.curve path,
svg.curve circle {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.2px; /* the scripts keep their starting dot's 1.2 in step */
  stroke-linecap: round; /* so the starting dot shows */
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}

/* Cycloid on a line and the medley: wide, not square. */
svg#cycloid-horizontal,
svg#sine {
  width: min(100%, 34rem);
}

svg#medley,
svg#ford,
svg#golden,
svg#nautilus,
svg#newton {
  width: min(100%, 30rem);
}

/* Cycloids: the circles, the spoke and the ground, behind the curve. */
svg.curve .faint {
  stroke-opacity: 0.35;
}

/* Cycloid: the pen. */
svg.curve .pen {
  fill: currentColor;
  stroke: none;
}

/* --- Section headings and link lists (writings, 404) ---------------------- */

h2.section {
  margin: 1.5em 0 0.7em;
  font-size: 1.2em;
}

ul.links {
  padding-left: 1em;
}

ul.links li {
  margin-bottom: 0.8em;
}

ul.links .date {
  margin-left: 0.4em;
}

/* --- Centered pages: home and contact (those with an animation) ----------- */

/* Text centered. The animation sits at the same height on both pages, its
   middle at 42% of the window, so it holds still between them; the text
   follows below it. --art is the animation's height. */
.page.centered {
  --art: min(calc(100vw - 32px), 20rem); /* svg.curve, square */
  padding-top: max(2rem, calc(42svh - var(--art) / 2));
  text-align: center;
}

/* No animation (animation = "" in config.toml): the text starts a third of
   the way down instead, still at the same height on both pages. */
.page.centered:not(:has(svg.curve, pre.shapes)) {
  padding-top: max(2rem, 33svh);
}

.page.centered:has(pre.shapes:not([hidden])) {
  --art: min(60vh, 34rem);
}

.page.centered:has(#cycloid-horizontal:not([hidden])) {
  --art: calc(min(100vw - 32px, 34rem) * 1.8 / 4.4); /* its viewBox's shape */
}

.page.centered:has(#medley:not([hidden])) {
  --art: calc(min(100vw - 32px, 30rem) * 2.16 / 3.2);
}

.page.centered:has(#ford:not([hidden])) {
  --art: calc(min(100vw - 32px, 30rem) * 1.08 / 2.08);
}

.page.centered:has(#golden:not([hidden])) {
  --art: calc(min(100vw - 32px, 30rem) * 1.4 / 2.16);
}

.page.centered:has(#nautilus:not([hidden])) {
  --art: calc(min(100vw - 32px, 30rem) * 1.64 / 2.16);
}

.page.centered:has(#sine:not([hidden])) {
  --art: calc(min(100vw - 32px, 34rem) * 1.36 / 4.16);
}

.page.centered:has(#newton:not([hidden])) {
  --art: calc(min(100vw - 32px, 30rem) * 1.5 / 3.2);
}

@media (max-width: 30rem) {
  .page.centered:has(pre.shapes:not([hidden])) {
    --art: min(48vh, 22rem);
  }
}

.page.centered ul {
  padding: 0;
  list-style: none;
}

/* --- Home: contact and writings, side by side ----------------------------- */

.home-links {
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: 0.5em 1.5em;
}

/* On a compact page, the link to the page itself. */
.home-links a[aria-current] {
  color: var(--muted);
  text-decoration: none;
}

/* --- The content license, under each post --------------------------------- */

p.license {
  margin: 3em 0 0;
  color: var(--muted);
  font-size: var(--size-date);
}

p.license a {
  color: inherit;
}

/* --- "← Back to …", one level up, above most pages ------------------------ */

nav.back {
  margin: 0 0 1.5em;
  font-size: var(--size-date);
}

nav.back a {
  text-decoration: none;
}

nav.back a:hover {
  text-decoration: underline;
}

/* --- styles/08-docs.css --- */

/* ==========================================================================
   Docs: the list at /docs/, the docs menu and its search, the link on each
   heading, previous and next.
   ========================================================================== */

.docs-list {
  padding-left: 1.6em;
}

.docs-list li {
  margin-bottom: 1em;
}

.docs-list p {
  margin: 0.2em 0 0;
  color: var(--muted);
  font-size: var(--size-date);
}

/* A doc has no date under its description to space it from what follows. */
.page:has(.docs-nav) .subtitle {
  margin-bottom: 1.5em;
}

/* The docs menu (base.html) holds the sidebar's nav. On narrow screens it's
   a <details> under the title, closed until asked, so the text comes first;
   its summary names it, so the nav's own heading goes. */
.docs-menu {
  margin: 0 0 2em;
}

.docs-menu > summary {
  display: flex;
  align-items: center;
  gap: 0.3em;
  padding: 0.3em 0;
  color: var(--muted);
  font-size: var(--size-contents);
  list-style: none;
  cursor: pointer;
}

.docs-menu > summary::-webkit-details-marker {
  display: none;
}

.docs-menu > summary:hover {
  color: var(--fg);
}

.docs-menu > summary:focus-visible {
  outline: 2px solid var(--fg);
  outline-offset: 2px;
  border-radius: 4px;
}

/* The chevron turns down while the menu is open. */
.docs-menu > summary svg {
  width: 1em;
  height: 1em;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: rotate 0.2s ease;
}

.docs-menu[open] > summary svg {
  rotate: 90deg;
}

.docs-menu .toc {
  margin: 0.75em 0 0;
}

.docs-menu .toc h2 {
  display: none;
}

/* The sidebar's heading goes to /docs/. */
.docs-nav h2 a {
  color: inherit;
  text-decoration: none;
}

.docs-nav h2 a:hover {
  text-decoration: underline;
}

/* The doc being read, in the sidebar, with its sections under it. */
.docs-nav a[aria-current] {
  color: var(--fg);
  font-weight: 600;
  text-decoration: none;
}

.docs-nav ol ol {
  margin: 0.4em 0 0.6em;
  padding-left: 1em;
  font-size: 0.92em;
}

/* From 60rem the menu is the sidebar, always open (06-contents.css): the
   summary goes and the nav's heading returns. The <details> shows its
   content while closed, which takes ::details-content (Chrome 131, Safari
   18.4, Firefox 143). A browser without it keeps the summary under the
   title, and opens the sidebar from there. */
@media (min-width: 60rem) {
  .docs-menu,
  .docs-menu .toc {
    margin: 0;
  }

  .docs-menu .toc h2 {
    display: block;
  }

  @supports selector(::details-content) {
    .docs-menu > summary {
      display: none;
    }

    .docs-menu::details-content {
      content-visibility: visible;
    }
  }
}

/* --- Search (js/docs-search.js), at the top of the sidebar ---------------- */

.docs-search {
  margin: 0.75em 0 0;
}

.docs-search input {
  width: 100%;
  padding: 0.35em 0.6em;
  border: 1px solid var(--border);
  border-radius: 4px;
  background: var(--bg);
  color: var(--fg);
  font: inherit;
  font-size: 0.9em;
}

.docs-search input::placeholder {
  color: var(--muted);
  opacity: 1;
}

.docs-search input:focus-visible {
  outline: 2px solid var(--fg);
  outline-offset: 1px;
}

.docs-search-status {
  margin: 0.5em 0 0;
  color: var(--muted);
  font-size: 0.9em;
}

.docs-search-status:empty {
  display: none;
}

.docs-search .docs-results {
  margin: 0.75em 0 0;
  padding: 0;
  list-style: none;
}

.docs-search .docs-results li {
  margin-bottom: 0.8em;
  line-height: 1.4;
}

.docs-results a {
  display: block;
  text-decoration: none;
}

.docs-results strong {
  font-weight: 600;
}

.docs-results .where {
  display: block;
  font-size: 0.85em;
}

.docs-results p {
  margin: 0.2em 0 0;
  color: var(--muted);
  font-size: 0.85em;
}

.docs-results mark {
  border-radius: 2px;
  background: var(--tint-hover);
  color: inherit;
}

/* While searching, the results take the place of the list of docs. */
.docs-search.searching ~ ol {
  display: none;
}

/* --- The link each heading of a doc has to itself (main.go) --------------- */

/* Shown when the heading is pointed at, or when a keyboard reaches it. */
.anchor {
  margin-left: 0.3em;
  color: var(--muted);
  text-decoration: none;
  opacity: 0;
}

:is(h2, h3, h4):hover > .anchor,
.anchor:focus-visible {
  opacity: 1;
}

/* --- A doc from [docs] pages: the link to its source ---------------------- */

.source {
  margin: 3em 0 0;
  color: var(--muted);
  font-size: var(--size-date);
}

.source a {
  color: inherit;
}

.source + .pager {
  margin-top: 1em;
}

/* --- Previous and next, at the end of a doc ------------------------------- */

/* A small word over each doc's name, which is what's underlined. */
.pager {
  display: flex;
  justify-content: space-between;
  gap: 1em 2em;
  margin-top: 3em;
  padding-top: 1em;
  border-top: 1px solid var(--border);
}

.pager a {
  display: flex;
  flex-direction: column;
  text-decoration: none;
}

.pager a[rel="next"] {
  margin-left: auto;
  text-align: right;
}

.pager .label {
  color: var(--muted);
  font-size: var(--size-date);
}

.pager .name {
  text-decoration: underline;
  text-decoration-thickness: 0.08em;
  text-underline-offset: 0.1em;
}

/* --- styles/09-motion.css --- */

/* ==========================================================================
   Moving between pages: a short crossfade, where the browser supports it
   (Chrome, Safari). The animation is its own layer and swaps over at once:
   the new page has already picked up its time, so it doesn't jump.
   ========================================================================== */

@media (prefers-reduced-motion: no-preference) {
  @view-transition {
    navigation: auto;
  }
}

pre.shapes,
svg.curve {
  view-transition-name: art;
}

::view-transition-old(art) {
  display: none;
}

::view-transition-new(art) {
  animation: none;
}


/* ==========================================================================
   Respect the OS setting for less motion: no fades or transitions.
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    transition-duration: 0s !important;
    transition-delay: 0s !important;
    animation: none !important;
  }
}
