/* one stylesheet for the whole site.
   sections: colors / font / page / gehenna / boxes / tags / front page / blog /
   posts / windows / snapshot / code / footnotes */


/* ---- colors ----
   from the xemacs emacs theme (tmp/xemacs-theme.el) */

:root {
  --bg: #cccccc;           /* default background: gray80 */
  --fg: #000000;           /* default foreground: black */
  --link: #8b8b00;         /* yellow4, same as --yellow below */
  --link-visited: #8b8b00; /* same: visited links look no different */
  --link-active: #8b8b00;  /* same again: nor do links being clicked */
  --selection: #a6a6a6;    /* region: gray65 */
  --field: #d9d9d9;        /* widget-field-face: gray85. the search box. */
  --dim: #696969;          /* widget-inactive-face: dim gray. line numbers. */
  --hover: #bfbfbf;        /* gui-button-face: grey75. the line of code under the mouse. */
  --footnote: #8b8b00;     /* yellow4, like links. everything of a footnote. */
  --wire: #000000;         /* black. the grid in the background. */
  --ground: none;          /* the squares of that grid: none, empty. */

  /* the theme's darker primary colors, the ones it uses for code.
     box borders are drawn in these.
     (its plain "red", "green" and "blue" are #ff0000, #00ff00, #0000ff:
     full brightness, too loud here.) */
  --red: #cd0000;       /* red3 */
  --green: #008b00;     /* green4 */
  --blue: #0000cd;      /* blue3 */
  --purple: #8b008b;    /* magenta4 */
  --brown: #8b2323;     /* brown4 */
  --steelblue: #4682b4; /* steelblue */
  --seagreen: #2e8b57;  /* seagreen */
  --pink: #db7093;      /* palevioletred */
  --yellow: #8b8b00;    /* yellow4. not in the theme: its only yellow is
                           plain "yellow" (#ffff00), which can't be seen
                           on gray. this is the dark shade of the same. */

  /* the colors of code, from the theme's font-lock faces */
  --code-keyword: #8b0000;      /* font-lock-keyword-face: red4 */
  --code-string: #008b00;       /* font-lock-string-face: green4 */
  --code-comment: #00008b;      /* font-lock-comment-face: blue4 */
  --code-function: #8b2323;     /* font-lock-function-name-face: brown4 */
  --code-type: #4682b4;         /* font-lock-type-face: steelblue */
  --code-variable: #8b008b;     /* font-lock-variable-name-face: magenta4 */
  --code-constant: #cd0000;     /* font-lock-constant-face and -builtin-face: red3 */
  --code-preprocessor: #0000cd; /* font-lock-preprocessor-face: blue3 */
}

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

a { color: var(--link); }
a:visited { color: var(--link-visited); }
a:active { color: var(--link-active); }

/* a link's underline: 1px thick, a pixel of the pixel font. left to
   itself the font asks for 1.5px, which a sharper screen draws 3 dots
   thick under letters whose strokes are 2. */
a { text-decoration-thickness: 1px; }

::selection { background: var(--selection); }


/* ---- font ----
   Sperry PC 8x16, see font/README.txt. (to try one of the runners-up,
   swap which font-family line under "html" below is commented out.)
   it is a pixel font: each character is 8px wide and 16px tall, and it
   only looks crisp at 16px, 32px, 48px... so the base size is 16px and
   every other size is a whole multiple of it: 1rem is the base size,
   2rem twice that.

   it only has the characters of the original pc. the few it lacks (the
   dash in page titles, the trademark sign) are drawn in the second font,
   IBM VGA 8x16, which has many more. */

@font-face {
  font-family: "Sperry PC 8x16";
  src: url("font/Px437_SperryPC_8x16.ttf");
}

/* the two runners-up. a font that no rule uses is never downloaded. */
@font-face {
  font-family: "FM Towns 8x16";
  src: url("font/Px437_FMTowns_re_8x16.ttf");
}

@font-face {
  font-family: "DOS/V JPN16";
  src: url("font/Px437_DOS-V_re_JPN16.ttf");
}

@font-face {
  font-family: "IBM VGA 8x16";
  src: url("font/PxPlus_IBM_VGA_8x16.ttf");
}

/* the small print. the same family as the site's font, but each character
   is 8px tall instead of 16px (and just as wide): crisp at 8px, 16px... */
@font-face {
  font-family: "Sperry PC 8x8";
  src: url("font/Px437_SperryPC_CGA.ttf");
}

html {
  font-family: "Sperry PC 8x16", "IBM VGA 8x16", monospace;
  /* font-family: "FM Towns 8x16", "IBM VGA 8x16", monospace; */
  /* font-family: "DOS/V JPN16", "IBM VGA 8x16", monospace; */
  font-size: 16px;
  /* how tall a line is: 1.2 times the size of the font. firefox does
     that by itself for these fonts, which don't say how much room to
     leave between lines; chrome and safari leave none, and every line
     of text sits right on the one above it. so it is said outright.
     (times new roman does say, but every browser rounds what it says
     differently, so where it is used its lines are given in pixels:
     the ones firefox makes of it. see "times new roman's lines".) */
  line-height: 1.2;
}

h1 { font-size: 2rem; }
h2, h3 { font-size: 1rem; }

/* no bold version of the font exists, a faked one looks smeared */
h1, h2, h3 { font-weight: normal; }

/* code is in the second font, IBM VGA 8x16, at the same size */
pre, code {
  font-family: "IBM VGA 8x16", monospace;
  font-size: 16px;
}

/* how many characters wide a tab is in code */
pre { tab-size: 2; }


/* ---- page ----
   one column, 80 characters wide, in the middle of the window.
   (does nothing to the front page, its links are placed by hand.) */

body {
  max-width: 80ch;
  margin: 16px auto;
  padding: 0 16px;
}

/* "release: <where>", the last line of every page (lib/release.html.ejs):
   where the site was built into, in the small gray font, in the very
   bottom right corner of the page: of the window, when the page is no
   taller than it. it is placed against <html>, which is at least as tall
   as the window, so it is out of every page's own layout. */
html {
  position: relative;
  min-height: 100%;
}
.release {
  position: absolute;
  right: 4px;
  bottom: 2px;
  max-width: calc(100% - 8px);
  margin: 0;
  font-family: "Sperry PC 8x8", "IBM VGA 8x16", monospace;
  font-size: 8px;
  line-height: 8px;
  color: var(--dim);
  text-align: right;
  overflow-wrap: anywhere;
}

/* in "test" (see config.js), a post that is not public says which it is,
   next to its date: "draft", "private" */
.visibility {
  font-family: "Sperry PC 8x8", "IBM VGA 8x16", monospace;
  font-size: 8px;
  color: var(--dim);
  text-transform: uppercase;
}

/* pictures, code and tables never stick out of the column: pictures
   shrink, long lines of code and long words in a table wrap */
img { max-width: 100%; }
td, th { overflow-wrap: anywhere; }


/* ---- gehenna ----
   the world in the background of every page, a grid and stars.
   <gehenna> puts this <canvas> in a page, and gehenna.js draws on
   it. it fills the window, stays put when the page scrolls, and is behind everything: it shows wherever nothing is in
   front of it, so around the boxes, not through them. */

#gehenna {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: -1;
  color: var(--wire); /* the color of the lines */
  pointer-events: none;
}

/* while the background is dragged to look around (see gehenna.js) */
html.looking, html.looking * {
  cursor: grabbing;
}


/* ---- boxes ----
   put class="box" on something to draw a line around it. (in a template,
   <box> does: see bin/box.js.)

   a box has a black border, and under it colored copies of that border,
   the layers, each pushed a few pixels further out than the one above
   it. usually there is one layer, pushed down and to the right, and the
   black border is filled in with the color of the page, so of the layer
   only the two sides that peek out show: below and to the right.

   the settings of a box. a box that wants something else sets them in
   its style: style="--layers: 3; --dx: -1". <box layers="3"
   direction="left"> writes exactly that.

     --layers   how many layers
     --shift    how far each layer is pushed from the one above it
     --dx       which way it is pushed: 1 right, -1 left, 0 neither
     --dy       the same for down (1) and up (-1)
     --fill     what a border is filled with. the color of the page:
                it hides what is under it. transparent: every border
                shows whole.
     --colors   the colors of the layers, topmost first: "red blue".
                "random" for one dealt at random by script.js, and so
                is every layer the list doesn't reach.
     --clickable  "no" for a box that can not be pressed. unlike the
                others this one is handed down: the boxes inside such
                a box can not be pressed either, unless they say "yes".
                (that is why it has no line in the rule below, which
                would set it afresh for every box. a box nobody told
                anything can be pressed.)

   script.js makes the layers: a <span class="layer"> for each, inside
   the box, with the number of the layer in --n (1 is the topmost) and
   its color in --line-2. it marks the box class="layered" when it has.

   --line-1 is the color of the border in front, always black.
   --line-2 is the color of a layer. the one here is used when script.js
   doesn't run. */

.box {
  --line-1: var(--fg);
  --line-2: var(--red);
  --layers: 1;
  --shift: 3px;
  --dx: 1;
  --dy: 1;
  --fill: var(--bg);
  --colors: random;

  position: relative;
  margin: 0 0 16px 0;
  padding: 0 16px;
  border: 1px solid transparent; /* the room the black border takes.
                                    ::before, below, draws it. */
  background: var(--bg);         /* hides what is behind the box: the
                                    wireframe. the borders are drawn on
                                    top of this. */
  isolation: isolate;            /* keeps the borders, which are drawn
                                    under the box's contents, from going
                                    under anything outside the box as well */
}

/* the black border, and the fill that hides the layers under it */
.box::before {
  content: "";
  position: absolute;
  inset: -1px;                    /* right on the box's own (invisible) border */
  border: 1px solid var(--line-1);
  background: var(--fill);
  pointer-events: none;           /* clicks go through it */
  z-index: -1;                    /* under the box's contents */
}

/* a layer: a colored border. (the second line is the one layer a box
   has when script.js doesn't run.) */
.box > .layer,
.box:not(.layered)::after {
  content: "";
  position: absolute;
  inset: -1px;                    /* same size as the black one */
  transform: translate(calc(var(--dx) * var(--n) * var(--shift)),
                       calc(var(--dy) * var(--n) * var(--shift))); /* pushed out, n steps */
  border: 1px solid var(--line-2);
  background: var(--fill);
  pointer-events: none;
  z-index: calc(-1 - var(--n));   /* under the black one, and under the
                                     layers above it */
}

.box:not(.layered)::after { --n: 1; }

/* a box is pressed down while the mouse button is held on it (script.js
   gives it class="pressed" for as long, if the box is --clickable): it
   sits where its bottom layer was, and the layers are gone. */
.box.pressed {
  transform: translate(calc(var(--dx) * var(--layers) * var(--shift)),
                       calc(var(--dy) * var(--layers) * var(--shift)));
}

.box.pressed > .layer { display: none; }

/* while a press that did not start on text lasts, script.js gives the
   whole page class="pressing": dragging the mouse selects no text then.
   (the second line of each pair is the same thing for safari.) */
html.pressing {
  user-select: none;
  -webkit-user-select: none;
}


/* ---- tags ----
   <a class="box tag" href="search.html?tag=nix">nix</a> is a tag: a little box
   around one or two words. clicking it lists the posts with that tag.
   put a row of them inside <p class="tags">. */

.tag {
  --shift: 2px;

  display: inline-block;
  margin: 0 8px 8px 0;
  padding: 0 1ch;
  text-decoration: none;
  user-select: none;         /* a tag is a button: its word is not for
                                selecting, pressing it never selects */
  -webkit-user-select: none;
}

/* tags are links, but stay black */
a.tag,
a.tag:visited { color: var(--fg); }


/* ---- staircases (<staircase>, see bin/staircase.js) ----
   a grid with a single cell that every step sits in, at the top left,
   pushed right by --x and down by --y. bin/staircase.js works those out,
   or www/staircase.js, on the page, for steps that touch. */

.staircase {
  display: grid;
  justify-items: start;
  align-items: start;
  margin: 0;
  padding: 0;
  list-style: none;
}

.staircase > * {
  grid-area: 1 / 1;
  margin: var(--y, 0px) 0 0 var(--x, 0px);
}


/* ---- front page (index.html) ----
   a staircase of links a bit up and left of the middle of the window,
   each line a little further left than the one above it. */

.home {
  position: absolute;
  top: 30%;
  left: 40%;
  line-height: 24px;
}


/* ---- blog (blog/index.html, blog/all.html, search.html) ----
   <body class="blog"> lays the page out like this:

     header   header
     sidebar  main

   <header> is the header, <div class="sidebar"> the sidebar (its boxes
   are <aside>s), <main> the rest. */

.blog {
  max-width: 100ch;
  display: grid;
  grid-template-columns: 24ch 1fr; /* sidebar width, main gets the rest */
  grid-template-areas:
    "header  header"
    "sidebar main";
  column-gap: 16px;
  align-items: start;
}

.blog > header { grid-area: header; }
/* the sidebar is as tall as what is beside it, not just as tall as its
   boxes, so that the contents of a post can stay in the window all the
   way down (see "the contents of a post", below) */
.blog > .sidebar { grid-area: sidebar; align-self: stretch; }

/* the thin gray line in the sidebar, between the posts and the tags */
.sidebar hr {
  border: none;
  border-top: 1px solid var(--dim);
  margin: 0 0 16px 0; /* the posts leave 16px above it already */
}
.blog > main { grid-area: main; }

/* the list of all posts (blog/all.html): a table with two lines to a
   post, the second its subtitles, in gray. a black line between posts. */
.all-posts { border-collapse: collapse; }
.all-posts td {
  padding: 0 1ch 0 0;
  vertical-align: top;
}
.all-posts tr:not(.byline) td { padding-top: 8px; }
.all-posts .byline td { color: var(--dim); padding-bottom: 8px; }
/* its tags: a row of tags in the cell, without the room a row of them
   leaves under itself elsewhere */
.all-posts .tags { margin: 0; }
.all-posts .tag { margin-bottom: 0; }
.all-posts tr:not(.byline):not(:first-child) td { border-top: 1px solid var(--fg); }

/* without this, something wide in a post (a table, a long line of code)
   pushes the whole column wider than the window instead of staying inside */
.blog > main { min-width: 0; }

/* narrow windows (phones): everything in one column, sidebar first */
@media (max-width: 640px) {
  .blog {
    grid-template-columns: 1fr;
    grid-template-areas:
      "header"
      "sidebar"
      "main";
  }
}

/* header picture: a strip cut out of asset/header.jpg.
   height = how tall the strip is.
   object-position = which part of the picture shows (0% top, 100% bottom). */
header img {
  display: block;
  width: 100%;
  height: 200px;
  margin-top: 16px;
  object-fit: cover;
  object-position: center 30%;
}

/* list of posts: no bullets, date on one line, title under it */
.posts {
  padding: 0;
  list-style: none;
}

.posts li { margin-bottom: 16px; }
.sidebar h2 + .posts { margin-top: 0; } /* under "recent": see below */
.posts time { display: block; }

/* the contents of a post, a box of its own in the sidebar, under the
   one with the search box. headed "contents": a short line for each
   section, in Times New Roman and black, subsections further in. its
   numeral is underlined in the color of the line under that section's
   heading (script.js copies it over).

   the box stays in the window while the post scrolls: it goes up with
   the page until it is 16px from the top of the window, the same as the
   page is from it, and stays there. a long list scrolls inside the box,
   so that the box is never taller than the window. (on a phone, with
   the sidebar over the post, it scrolls away with the page.) */
.sidebar > .contents {
  position: sticky;
  top: 16px;
}

/* "contents" over it, in the small font and gray, like the ai disclaimer.
   (and "recent" over the list of posts, in the other sidebar box.) */
.sidebar h2 {
  margin: 16px 0 4px 0;
  font-family: "Sperry PC 8x8", "IBM VGA 8x16", monospace;
  font-size: 8px;
  color: var(--dim);
}
.contents ul {
  margin: 0 0 16px 0;
  max-height: calc(100vh - 92px); /* the window, less the 16px over and
                                     under the box and what else is in
                                     it: "contents", and the space around */
  overflow-y: auto;
  position: relative; /* script.js measures the sections against the list,
                         to keep the one being read in sight */
  padding: 0;
  list-style: none;
  font-family: "Times New Roman", Times, serif;
  line-height: 19px; /* see "times new roman's lines" */
}
.contents li {
  --line-2: var(--link); /* its underline's color when script.js doesn't run */
}
/* the numeral, then the title beside it. a title too long for one line
   wraps, and its next lines start where it does, not under the numeral. */
.contents a,
.contents a:visited {
  display: flex;
  align-items: baseline; /* the numeral's underline stays on the first line */
  color: var(--fg);
  text-decoration: none;
}

/* a title runs to two lines at most: past that it is cut off, the
   second line ending in "…". (the link's tooltip has all of it.) */
.contents .title {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
}

/* only the numeral is underlined, its full stop included, an ordinary
   underline in its heading's color. the gap between it and the title is
   not underlined. there are two levels: a top level section, and
   everything inside one, moved in by --indent. (the sidebar gives
   --level as 1 or 2, never deeper.) */
.contents { --indent: 1ch; }
.contents .numeral {
  flex: none;
  margin-left: calc((var(--level) - 1) * var(--indent));
  margin-right: 0.25em; /* the gap before the title: about a space */
  line-height: inherit; /* the list's, not a heading numeral's (see .numeral):
                          a section with no title has only the numeral to
                          set how tall its line is, and the underline
                          that runs across is placed on a line that tall */
  text-decoration: underline;
  text-decoration-color: var(--line-2);
}

/* the section being read: its underline runs on past the numeral, under
   the title, all the way across the box. script.js says which section
   that is, with class="current".
   the line is more underline: a row of spaces laid under the title,
   underlined the same way as the numeral, so that it is where the
   numeral's is and as thick. */
.contents a {
  position: relative; /* the row of spaces is placed against the link */
  isolation: isolate; /* and drawn under the title, not under the box */
}
.contents li.current > a::after {
  content: "\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0\a0";
                         /* more than the box is wide */
  position: absolute;
  top: 0;                /* on the first line, with the numeral */
  left: calc((var(--level) - 1) * var(--indent)); /* from where it starts */
  right: 0;              /* to the edge of the box */
  overflow: hidden;      /* the spaces past the edge are cut off */
  white-space: pre;
  text-decoration: underline;
  text-decoration-color: var(--line-2);
  z-index: -1;
  pointer-events: none;
}

/* where that underline is and how thick: firefox's, said outright. the
   font says, but each browser rounds it its own way: firefox draws it
   1px thick, 2px under the letters, chrome and safari 1px higher, and
   on a sharper screen chrome draws it three times as thick. firefox's
   on a sharper screen (2 pixels to a px) is the second rule. */
.contents .numeral,
.contents li.current > a::after {
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
}
@media (min-resolution: 2dppx) {
  .contents .numeral,
  .contents li.current > a::after {
    text-decoration-thickness: 0.5px;
    text-underline-offset: 1.5px;
  }
}

/* room under the search box: on a post it is the last thing in its box
   (and on the blog's front page the posts' list leaves the same room
   over itself already, so there it changes nothing) */
.sidebar form { margin-bottom: 16px; }

/* search box */
input[type="search"] {
  appearance: none; /* no browser decorations, just the box */
  box-sizing: border-box;
  width: 100%;
  padding: 3px 1ch;
  border: 1px solid var(--fg);
  border-radius: 0;
  background: var(--field);
  color: var(--fg);
  font: inherit;
}

/* the gray "search" in it while it's empty. firefox makes it black, a
   little more than half see-through, which comes out as this gray on the
   box's. chrome and safari have grays of their own, darker and lighter,
   so it is said outright. */
input[type="search"]::placeholder {
  color: #646464;
  opacity: 1;
}


/* ---- posts (post/some-post.html) ---- */

/* the top of a post, and of a preview of one on the blog's front page:
   the date on a line of its own, the title right under it, then the tags */
article > header { margin: 16px 0; }
article > header time { display: block; }
article > header h1,
article > header h3 { margin: 0 0 16px 0; }

/* the title of a post, on the post's own page: in Times New Roman, like
   the section headings further down */
article > header h1 {
  font-family: "Times New Roman", Times, serif;
  line-height: 36px; /* see "times new roman's lines" */
}

/* it is a link to the post itself, but looks like a heading: black, not
   underlined */
article > header h1 > a,
article > header h1 > a:visited,
article > header h1 > a:active {
  color: var(--fg);
  text-decoration: none;
}

/* the disclaimer under a post's tags, about what an ai did and did not
   do: small and gray, to stay out of the way. it is in the small font,
   at that font's real size. */
.disclaimer {
  margin-top: -16px;  /* the space between it and the tags. less than
                         nothing, because the tags leave 24px under
                         themselves: this takes 16px of it back. */
  margin-bottom: 0;   /* the space under it is the header's (16px, above) */
  font-family: "Sperry PC 8x8", "IBM VGA 8x16", monospace;
  font-size: 8px;
  color: var(--dim);
}

/* section headings: big, with a roman numeral in front. a post makes one
   with <section title="The Title">, which numbers it.
   only the <h2> directly inside <article> are like this.

   sections can have sections inside them, as deep as you like: an
   <section> inside another. the headings of those are smaller:
   <h3>, <h4>, <h5>, and <h6> for level 5 and deeper.

   they are in Times New Roman, not the pixel font. that is a font the
   reader's own computer has to have; one without it uses its nearest
   lookalike (Times, or whatever serif font it has). */
article > h2,
article > hgroup > h2,
article > hgroup > h3,
article > hgroup > h4,
article > hgroup > h5,
article > hgroup > h6 {
  font-family: "Times New Roman", Times, serif;
  font-weight: normal;
}

/* how big each level is */
article > h2,
article > hgroup > h2 { font-size: 2rem; }    /* IV.      */
article > hgroup > h3 { font-size: 1.5rem; }  /* iv.i     */
article > hgroup > h4 { font-size: 1.25rem; } /* iv.i.a   */
article > hgroup > h5 { font-size: 1rem; }    /* iv.i.a.i */
article > hgroup > h6 { font-size: 1rem; }    /* iv.i.a.i.a and deeper */

/* times new roman's lines: how tall a line of it is at each size. the
   font says how much room to leave, but every browser rounds that its
   own way: at 16px firefox makes a line 19px, chrome 20px, safari 18px,
   and everything under it moves. so it is said outright, in whole
   pixels, firefox's. (the sidebar's contents, 16px, and a post's
   title, 32px, have theirs where their font is set.) */
article > h2,
article > hgroup > h2 { line-height: 36px; }  /* 32px */
article > hgroup > h3 { line-height: 28px; }  /* 24px */
article > hgroup > h4 { line-height: 23px; }  /* 20px */
article > hgroup > h5,
article > hgroup > h6 { line-height: 19px; }  /* 16px */

/* a section's title and its subheadings are kept together in an <hgroup>:
   the subheadings sit right under the title, small and gray, one to a line.

   every space around them is a line of its own below. a space can be
   less than nothing, to pull two things closer than they naturally sit:
   -4px */

article > hgroup {
  /* the color of the line under the heading. script.js changes it to a
     random color for each heading; the one here, the color of links, is
     used when it doesn't run. */
  --line-2: var(--link);

  margin-top: 12px;    /* above the whole heading */
  margin-bottom: 0px; /* between the heading and the text after it */
}

article > hgroup > h2,
article > hgroup > h3,
article > hgroup > h4,
article > hgroup > h5,
article > hgroup > h6 {
  margin-top: 12px;
  margin-bottom: 12px; /* under the title: before the text, or before the
                          first subheading (which then takes some of it
                          back, see below) */
}

/* whatever follows a heading starts right after it, with no space of its
   own on top (a paragraph would otherwise add 16px) */
article > hgroup + * { margin-top: 0; }

/* a subheading. a thin gray line runs down its left side.
   (a section can have it in the heading's color instead, and in other
   places: see "other looks for a heading", below.) */
.subheading {
  margin-top: 0;      /* between one subheading and the next... */
  margin-bottom: 0;   /* ...these two add up */
  margin-left: 2ch;                  /* from the edge of the text to the line */
  border-left: 1px solid var(--subheading-line-color, var(--dim)); /* the line */
  padding-left: 2ch;                 /* from the line to the subheading's text */
  color: var(--dim);
}

/* the first subheading of a heading sits closer to the line under the
   heading than the text of a section does. this is how much closer:
   0 for not at all, -12px for as close as it goes. */
article > hgroup > .subheading:nth-child(2) { margin-top: -8px; }

/* the last subheading of a heading: the space between it and the text
   that comes after */
article > hgroup > .subheading:last-child { margin-bottom: 4px; }

/* the numeral, "II.": black like the rest of the heading. it is a link
   (to its own section, to copy the address of), but not underlined: the
   line under the whole heading, below, starts from it. */
.numeral {
  position: relative;  /* the line under the heading is placed against it */
  display: inline-block;
  line-height: 0.8;    /* how tall the numeral's box is. smaller brings
                          the line under the heading closer to the letters */
  text-decoration: none;
}

/* the line under a heading, in the heading's color. every level has one.
   a top level section's goes all the way across the post, deeper ones
   less far, along a curve, down to just under the numeral at level 6
   and deeper. (for the top level only, keep just the h2 lines of the
   rules below.) */
article > hgroup > h2,
article > hgroup > h3,
article > hgroup > h4,
article > hgroup > h5,
article > hgroup > h6 {
  container-type: inline-size; /* lets the line be measured against the
                                  heading: 100cqw is all its width */
  isolation: isolate;          /* keeps the line, which is drawn under
                                  the title's letters, from going under
                                  anything outside the heading as well */
}

article > hgroup > h2 > .numeral::after,
article > hgroup > h3 > .numeral::after,
article > hgroup > h4 > .numeral::after,
article > hgroup > h5 > .numeral::after,
article > hgroup > h6 > .numeral::after {
  content: "";
  position: absolute;
  left: -2px;            /* starts a little left of the numeral... */
  top: calc(100% + 1px); /* ...just under it... */
  width: calc(100cqw + 4px); /* ...and ends a little right of the text:
                                the whole post, and 2px more each side.
                                (the top level's. the rule below makes
                                it shorter for the others.) */
  border-top: 1px solid var(--line-2);
  z-index: -1;           /* under the letters: the tails of p, g and y
                            are drawn over the line, not cut by it */
}

/* how far the line goes at each level, by way of a curve.

   the curve is drawn by experiment/line-curve.html: across is how deep
   a section is, from the top level to level 6; up is how far its line
   goes, from all the way across down to just the numeral. the one in
   use has its handles at a (0.2, 1) and b (0.2, 0), which gives
     level  1     2     3     4     5     6 and deeper
            1     0.67  0.3   0.11  0.02  0

   css can't work out a curve by itself, but its animations can: their
   timing is a curve, cubic-bezier(). so the line gets an animation from
   all the way across to just the numeral that never plays (paused),
   and each level is parked at its own moment of it (animation-delay):
   level 1 at the start, level 6 at the end, the ones between evenly in
   between. where the curve has got to by then is how long the line is.

   the curve, as cubic-bezier(a across, 1 - a up, b across, 1 - b up):
   the numbers of the experiment's handles, with up turned over, as an
   animation's curve runs from bottom left to top right and ours from
   top left to bottom right.
   the depth: the 5 in the delay is how many steps there are from level
   1 to the level where the line is just under the numeral (6). */
@keyframes heading-line {
  from { width: calc(100cqw + 4px); } /* all the way across */
  to   { width: calc(100% + 4px); }   /* just the numeral (100% is its width) */
}

article > hgroup > h2 > .numeral::after,
article > hgroup > h3 > .numeral::after,
article > hgroup > h4 > .numeral::after,
article > hgroup > h5 > .numeral::after,
article > hgroup > h6 > .numeral::after {
  animation: heading-line 1s cubic-bezier(0.2, 0, 0.2, 1) paused both;
  /* level 1 waits 0s, level 2 is 0.2s in, ... level 6 is 1s in, the end.
     (a delay below zero starts the animation that far along.) */
  animation-delay: calc(max(min((var(--level, 1) - 1) / 5, 1), 0) * -1s);
}

/* other looks for a heading. a section can ask for them (see
   bin/section.js), and the heading widget can try them out on a whole
   post. each is a data-... attribute on the heading's <hgroup>; without
   them a heading looks as above. */

/* line-width="1/3": the line goes that share of the way, which is in
   --share: 0 just under the numeral, 1 all the way across. no curve. */
article > hgroup[data-line-width] > * > .numeral::after {
  animation: none;
  width: calc(100% + var(--share, 1) * (100cqw - 100%) + 4px);
}

/* box="yes": a thin box around the numeral, in the line's color. its
   bottom side is right where the line under the heading is. */
article > hgroup[data-box="yes"] > * > .numeral {
  outline: 1px solid var(--line-2);
  outline-offset: 1px; /* the gap between the letters and the box */
}

/* subheading-line-color="heading": the line beside the subheadings in
   the heading's color, not gray */
article > hgroup[data-subheading-line-color="heading"] {
  --subheading-line-color: var(--line-2);
}

/* subheading-line-justify="left": the line beside the subheadings at
   the very left, under where the line under the heading starts */
article > hgroup[data-subheading-line-justify="left"] > .subheading {
  margin-left: -2px;
}

/* subheading-line-justify="numeral": the line beside the subheadings
   just right of the numeral, where a box around it has its right side.
   the numeral is not the same width in every heading ("I." is narrow,
   "VIII." wide), so the heading is laid out in two columns: the first
   as wide as the numeral, the second everything else. the title and the
   subheadings are both in the second. */
article > hgroup:has(> h2) { --heading-size: 2rem; }    /* the sizes of */
article > hgroup:has(> h3) { --heading-size: 1.5rem; }  /* the headings, */
article > hgroup:has(> h4) { --heading-size: 1.25rem; } /* from above */
article > hgroup:has(> h5) { --heading-size: 1rem; }
article > hgroup:has(> h6) { --heading-size: 1rem; }

article > hgroup[data-subheading-line-justify="numeral"] {
  display: grid;
  grid-template-columns: auto 1fr;
  container-type: inline-size; /* the line under the heading is measured
                                  against this, not the title (below) */
}
/* the title's own row uses those same two columns: numeral, then title.
   it can't do that and be what the line is measured against as well,
   so the whole heading is that instead: it is just as wide.
   (in a grid, the space above the title no longer runs together with the
   space above the whole heading, so it is left out.) */
article > hgroup[data-subheading-line-justify="numeral"] > :is(h2, h3, h4, h5, h6) {
  container-type: normal;
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: subgrid;
  align-items: baseline;
  margin-top: 0;
}
article > hgroup[data-subheading-line-justify="numeral"] > * > .numeral {
  margin-right: 0.25em; /* the space between the numeral and the title */
}
article > hgroup[data-subheading-line-justify="numeral"] > .subheading {
  grid-column: 2;
  /* back over that space, to 1px right of the numeral */
  margin-left: calc(1px - 0.25 * var(--heading-size));
}

/* subheading-line="joined": the line beside the subheadings goes up to
   meet the line under the heading. it is drawn from there, under the
   numeral, instead of beside each subheading (whose own line is still
   there, taking up its 1px, but not drawn). it is made much too long,
   and the clip-path cuts it off at the bottom of the last subheading.
   (the other three numbers of the clip-path let the heading stick out
   at the top and the sides.) */
article > hgroup[data-subheading-line="joined"]:has(> .subheading) {
  clip-path: inset(-100px -100px 0 -100px);
}
article > hgroup[data-subheading-line="joined"] > .subheading {
  border-left-color: transparent;
}
article > hgroup[data-subheading-line="joined"]:has(> .subheading) > * > .numeral::before {
  content: "";
  position: absolute;
  left: 16px;            /* where the line usually is: 2ch of the
                            subheadings' font in from the left */
  top: calc(100% + 1px); /* from the line under the heading on down */
  height: 100vh;
  border-left: 1px solid var(--subheading-line-color, var(--dim));
}
article > hgroup[data-subheading-line="joined"][data-subheading-line-justify="left"] > * > .numeral::before {
  left: -2px;
}
article > hgroup[data-subheading-line="joined"][data-subheading-line-justify="numeral"] > * > .numeral::before {
  left: calc(100% + 1px);
}

a.numeral,
a.numeral:visited,
a.numeral:active { color: var(--fg); }

/* figures: a picture (or a block of code) with a caption under it.
   in a post, this makes one:
     <figure src="img/post/picture.png"><caption>the caption</caption></figure>
   the box is the usual black + color pair.
   width is how wide a figure is unless it says otherwise:
     <figure src="img/post/picture.png" style="width: 50%"> */
figure.box {
  width: 92%;
  box-sizing: border-box;
  margin: 24px auto;
  padding: 0;
}

figure img {
  display: block;
  margin: 16px auto;
  max-width: calc(100% - 32px);
}

figure pre { margin: 16px; }

/* the line between the picture and the caption: black, like the box's
   own border, and drawn over the colored one where they cross. */
figcaption {
  border-top: 1px solid var(--line-1);
  padding: 12px 16px;
}

/* the footnotes at the bottom of a post, set off from the post by the
   same kind of line. the negative margins take the line out to the edges
   of the post's box. */
article > footer {
  border-top: 1px solid var(--line-1);
  margin: 32px -16px 0 -16px;
  padding: 8px 16px;
}


/* ---- windows (<window>, see bin/window.js) ----
   a box with a bar along its top: its title, and three buttons. */

/* a <span>, half as wide as a figure (see "figures"), in a line with
   whatever is written beside it. the first of a line starts where a
   figure would. */
.window {
  display: inline-block;
  width: 46%;
  box-sizing: border-box;
  margin: 24px 0 24px 4%;
  padding: 8px 1ch;
  vertical-align: top;   /* two of them line up by their tops */
}
/* two fit in a line: the second of them starts right after the first,
   with only a space between. a third goes on the next line, and starts
   where a figure would again, and so on. */
.window + .window { margin-left: 0; }
.window + .window + .window { margin-left: 4%; }
.window + .window + .window + .window { margin-left: 0; }

/* windows written inside a <span> of their own are as tall as each other,
   the shorter one stretched to the taller one's height:
     <span><window> ... </window> <window> ... </window></span>
   and when there is no room for two side by side (30 characters each),
   they go one over the other, each as wide as a figure. the span is as
   wide as a figure, and they share it. */
span:has(> .window) {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  gap: 24px 1ch;  /* one over the other, as far apart as a figure from what
                     is around it; side by side, a space between them */
  width: 92%;
  margin: 24px auto;
}
span:has(> .window) > .window:not(.floating) {
  flex: 1 1 30ch;
  width: auto;
  min-width: 0;  /* how wide it is comes from the 30ch, not what is in it */
  margin: 0;
}

.window > .bar,
.window > .body { display: block; }
.window > .bar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1ch;
  margin: 0 0 4px 0;
}
.window > .bar > .buttons { display: flex; gap: 4px; }
/* a button is its icon, 11 pixels, with a pixel of room around it */
.window > .bar button,
.window-place button {
  display: block;
  padding: 2px;
  border: 1px solid var(--fg);
  background: var(--bg);
  color: var(--fg);
  line-height: 0;
  cursor: pointer;
}
.window > .bar button:disabled { color: var(--dim); border-color: var(--dim); cursor: default; }
.window > .bar button[hidden] { display: none; }
.window > .bar button.done { background: var(--fg); color: var(--bg); } /* copied */
.window .icon {
  display: block;
  fill: currentColor;
  shape-rendering: crispEdges;
}

/* the line under the bar, across the whole window, the color of the
   box's own line. the tabs sit on it, if there are any: the one showing
   is a little box of the same line around its name, open at the bottom,
   where it covers the line, so it looks like it is lifted out of what is
   under it. the others are only their names, in gray. */
.window > .tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 0 1ch;
  margin: 0 -1ch 8px -1ch;  /* out to the window's sides, past its padding */
  padding: 0 1ch;
  border-bottom: 1px solid var(--line-1);
}
.window > .tabs button {
  font: inherit;
  margin: 0 0 -1px 0;       /* down over the line */
  padding: 0 1ch;
  border: 1px solid transparent;
  border-bottom: none;
  background: none;
  color: var(--dim);
  cursor: pointer;
}
.window > .tabs button.on {
  border-color: var(--line-1);
  background: var(--fill, var(--bg)); /* hides the line under it */
  color: var(--fg);
  cursor: default;
}
.window > .body > .tab[hidden] { display: none; }
.window > .body > .tab { display: block; }

/* taken out of the page: it floats over it, where script.js puts it, and
   is dragged about by its bar. where it was, a window-place: a little
   box with a button to put it back (see "windows" in script.js). */
.window.floating {
  position: fixed;
  margin: 0;
  z-index: 3;
  max-width: calc(100vw - 16px);
  background: var(--bg); /* the page doesn't show through it */
}
.window.floating > .bar { cursor: move; touch-action: none; user-select: none; -webkit-user-select: none; }
.window-place { display: inline-block; vertical-align: top; margin: 24px 0 24px 4%; }
span:has(> .window) > .window-place { flex: none; margin: 0; }
.window-place > .box { display: inline-block; padding: 4px; margin: 0; }

/* the controls the experiments put in their windows: a row to a line, a
   name on the left */
.window .row { display: flex; align-items: center; gap: 1ch; margin: 0 0 8px 0; }
.window .row.wrap { flex-wrap: wrap; gap: 4px 1ch; }
.window .name { flex: none; width: 9ch; }
.window input[type=range] { flex: 1; min-width: 0; margin: 0; }
.window input[type=number],
.window input[type=text] { flex: none; width: 8ch; font: inherit; }
.window select,
.window .body button { font: inherit; }
.window .count { flex: none; width: 5ch; }
/* the line at the bottom: what the window would copy */
.window .now { margin: 0; color: var(--dim); user-select: all; -webkit-user-select: all; overflow-wrap: anywhere; }

/* ---- snapshot (make image, see bin/snapshot.sh) ----
   a page opened as page.html?snapshot is dressed for a picture: <html>
   gets class="snapshot" before anything is drawn. so anything only for
   pictures goes here, written as html.snapshot ...

   the picture is taken in a window as tall as the whole page, so what
   stays put while the page scrolls has nothing to do: the contents box
   is at the top of the sidebar, where it starts, and shows every
   section. */
html.snapshot .sidebar > .contents { position: relative; } /* not sticky, but
                                     still a box (see "boxes") */
html.snapshot .contents ul { max-height: none; overflow: visible; }
/* a picture can't be clicked: no buttons in the windows' bars */
html.snapshot .window > .bar > .buttons { display: none; }

/* ---- code ----
   the build turns every block of code into numbered lines (see "code
   blocks" in bin/libgehenna.js). here a block is laid out as a table: a row
   per line, with the line's number and then its text. */

pre > code {
  display: table;
  width: 100%;
}

.line { display: table-row; }

/* the number of a line. it is a link to that line, but a quiet one: gray,
   not underlined, and left out when the code is selected and copied. */
.line-number {
  display: table-cell;
  padding-right: 2ch;
  text-align: right;
  text-decoration: none;
  user-select: none;
}

a.line-number,
a.line-number:visited,
a.line-number:active { color: var(--dim); }

/* the text of a line. a line too long for the box wraps, and what wraps
   stays to the right of the numbers. */
.line-text {
  display: table-cell;
  width: 100%;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  line-break: strict; /* "--dport" stays whole when it wraps, as in
                         firefox; safari would otherwise split it
                         between the two dashes. (chrome still does,
                         and nothing here can stop it.) */
}

/* the line under the mouse is marked lightly. the line whose address is
   in the address bar (after clicking its number, or following a link to
   it) is marked like selected text, and stays so. */
.line:hover { background: var(--hover); }
.line:target { background: var(--selection); }

/* the build also marks the pieces of the code with these classes. the
   colors are at the top of this file. anything not listed here stays
   black: plain variables, operators, brackets. */

.hl-keyword { color: var(--code-keyword); }
.hl-string { color: var(--code-string); }
.hl-comment { color: var(--code-comment); }
.hl-function { color: var(--code-function); }
.hl-type, .hl-constructor, .hl-module { color: var(--code-type); }
.hl-property { color: var(--code-variable); }
.hl-number, .hl-constant, .hl-escape { color: var(--code-constant); }
.hl-attribute { color: var(--code-preprocessor); }

/* names the language itself provides: len, long, true... */
.hl-builtin { color: var(--code-constant); }

/* the "$ " in front of a command in a terminal session: gray, and left
   out when the command is selected and copied */
.hl-prompt {
  color: var(--dim);
  user-select: none;
}

/* code sitting inside a string, like the ${x} in "a ${x}", is not string colored */
.hl-embedded { color: var(--fg); }


/* ---- footnotes ----
   a footnote mark in the text is a raised * or dagger (which mark is
   decided in bin/libgehenna.js, see footnoteMarks). the footnote's text sits
   inside the mark, hidden, and shows in a little window under that line
   while the mouse is over the mark (or the mark is reached with tab).

   everything of a footnote is one color, --footnote at the top of this
   file: the marks, the arrows back up from the list, the window's border. */

.footnote {
  /* not shrunk like a normal <sup>: this font is only crisp at its real
     size. and not raised here either, that is done just below. */
  font-size: 1rem;
  vertical-align: baseline;
}

/* the mark. it is moved up without the line it is in getting any taller. */
.footnote > a {
  position: relative;
  top: -5px; /* how far up */
  text-decoration: none;
}

.footnote > a,
.footnote > a:visited,
.footnote > a:active,
.footnote-mark,
.footnote-back,
.footnote-back:visited,
.footnote-back:active { color: var(--footnote); }

.footnote-popup {
  display: none;
  position: absolute;
  left: 16px;   /* as wide as the text of the post */
  right: 16px;
  z-index: 1;
  padding: 8px 1ch;
  border: 1px solid var(--footnote);
  background: var(--bg);
  overflow-wrap: anywhere; /* long links wrap instead of sticking out */
}

.footnote:hover .footnote-popup,
.footnote:focus-within .footnote-popup { display: block; }

/* the list at the bottom. the marks are written out in the html (so
   that the arrow can come before them), so the list makes none itself.
   long links wrap here too. */
.footnotes {
  margin: 8px 0;  /* with the footer's 8px, 16px under the line over them */
  padding: 0;
  list-style: none;
}

.footnotes li {
  margin-bottom: 8px;
  overflow-wrap: anywhere;
}

