/* ===========================================================================
   nether.css
   ---------------------------------------------------------------------------
   There is no build step and no framework. This file says what things are made
   of; site/tokens.css says what the materials are, and site/design.py makes
   that. If you are about to write a `#` in here, the value belongs there.

   The system is three scales.

   Colour is Oklch. Indigo and rose form the dark room; porcelain and plum
   form its light companion. Both are generated from semantic roles, not
   inverted RGB values. Depth follows the same violet-to-rose path in each.

   Space follows a ten-pixel grid, independent of the font's advance. There are
   two spacing systems here and that is a fact rather than a plan: the pages
   are written in `rem` off the root size and the necropolis is written in the
   cell. Both came down together, which is what makes the site smaller.

   Type follows the eight-pixel drawing cell. There are four sizes, because a face
   drawn on an eight-pixel grid has exactly four at which a pixel of it is a
   whole number of the screen's. It does not come down with the space, and it
   is why the page gets denser rather than daintier.

   tests/contrast/run checks semantic text, raised surfaces, depth labels and
   the colour tables in the shipped GIFs. The two rooms share roles, not RGB
   complements.
   =========================================================================== */

:root {
  /* Colour, space and type are generated into tokens.css by site/design.py,
     which is the only place on this site where a colour is a number. If you
     are about to write a `#` below this line, the value belongs there. */
  /* Ninety-six cells rather than eighty, which is the same nine hundred and
     sixty pixels the column has always been. The cell came down to ten and the
     measure did not follow it: the face still advances fourteen pixels at the
     body size, so this is sixty-eight characters of it, and the specification
     writes code samples up to seventy-eight. A narrower column would not make
     the page smaller, it would make `pre` scroll sideways. */
  --col: calc(96 * var(--cell));
  --bevel-hi: var(--dim);
  --bevel-lo: var(--dimmer);
}

/* --------------------------------------------------------------------------
   The page is capped at eighty spacing cells. The font keeps its own fixed
   advance; reading width does not depend on squeezing the drawings.
   -------------------------------------------------------------------------- */

* { box-sizing: border-box; margin: 0; padding: 0; }

/* Straight to the text, for anyone arriving by keyboard. */
a.skip {
  position: absolute;
  left: -9999px;
  padding: .3rem .8rem;
  background: var(--accent);
  color: var(--ground);
  text-decoration: none;
}
a.skip:focus {
  left: .5rem;
  top: .5rem;
  z-index: 10;
}

/* The root size is the other half of the scale, and it is the half that
   moves most of this file. Every margin, padding and gap below is written in
   `rem`; every `font-size` is written in `px`, on the eight-pixel grid the
   face is drawn on. So this takes fourteen sixteenths of the air out of the
   page and leaves every glyph landing exactly where it did.

   It is the only way a design whose type has four sizes gets smaller. The
   cell in site/design.py is the same move on the other spacing system, the
   one the necropolis uses. */
html {
  font-size: 14px;
  background: var(--ground) url("gfx/bg.gif") repeat;
}
html[data-lamp="lit"] { background-image: url("gfx/bg-lit.gif"); }

/* One font, drawn in this repository, so the site reads the same on a machine
   with nothing installed. site/font.py makes it; there is no font library here
   for the same reason there is no image library. The fallback is named after
   it rather than instead of it: if the face does not load, a monospace stack
   keeps the columns, and nothing else here depends on the letterforms. */
@font-face {
  font-family: "Nether 8";
  src: url("nether.woff") format("woff");
  font-weight: normal;
  font-style: normal;
  font-display: block;
}

/* The bold is drawn, not derived. Seventeen rules below ask for one, and a
   browser with only the regular makes its own by smearing each glyph sideways
   and compositing it over itself -- on a face drawn as 8x8 pixels that turns
   every one-pixel stem into one pixel and a fraction, the grid stops lining
   up, and the letterform stops being the letterform. site/font.py draws the
   second weight instead and refuses to ship one that is wider, lighter, or
   short of a counter the regular has. */
@font-face {
  font-family: "Nether 8";
  src: url("nether-bold.woff") format("woff");
  font-weight: bold;
  font-style: normal;
  font-display: block;
}

/* The elements the user agent gives a font-family of its own.
   `font-family` inherits, but only where nothing else sets it -- and a browser
   sets it on every one of these before the page is read. So `body` naming the
   face reaches the prose and not one code listing, not the sign, and not the
   lamp. It is the whole page on a site made of listings.

   Every element here has a user-agent default. If a new one appears in the
   markup it belongs in this list, and tests/css/run says so. */
pre, code, kbd, samp, tt,
button, input, optgroup, select, textarea {
  font-family: inherit;
  font-size: inherit;
}

body {
  max-width: var(--col);
  margin: 0 auto;
  padding: 1.5rem 1rem 6rem;
  background: transparent;
  color: var(--ink);
  font-family: "Nether 8", ui-monospace, monospace;
  /* Twice the drawing cell, so every pixel of the face lands on two of the
     screen's and nothing is ever asked to draw half of one. The face advances
     seven pixels per cell: six for ink and one blank metric bearing. The
     scale is 8, 16, 24, 32 and there is nothing in between it. */
  font-size: 16px;
  /* Twenty-two pixels, not twenty-four. Leading is the largest vertical
     measure on the page by a long way -- margins are a minority of it -- so it
     is the only number that makes the page denser rather than marginally
     tidier. It has to land on a whole pixel: the face draws a one-pixel stem
     and a line box that ends on a half puts the next row's baseline half a
     pixel out. 1.375 of sixteen is twenty-two, and 1.4 is twenty-two and two
     fifths. */
  line-height: 1.375;
  /* A weight or a style this face does not have must fail visibly rather than
     be invented. A missing bold that looks wrong is a bug report; a smeared
     one is a thing people assume was intended. There is no italic and there
     is not going to be one. */
  font-synthesis: none;
  -webkit-font-smoothing: none;
  font-smooth: never;
}

::selection { background: var(--accent); color: var(--ground); }

/* The public terminal: directory and document, not a simulated shell. */
body.terminal { max-width: 1320px; padding: 1rem 1rem 3rem; }
.terminal-title, .pane-title, .terminal-status {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: .5ch 2ch;
  padding: .5rem .75rem;
}
.terminal-title { background: var(--accent); color: var(--ground); }
.terminal-header {
  padding: 1.5rem .75rem;
  border: 1px solid var(--dim);
  border-top: 0;
  background: var(--ground);
}
.terminal-workspace {
  display: grid;
  grid-template-columns: 252px minmax(0, 1fr);
  border: 1px solid var(--dim);
  border-top: 0;
  background: var(--ground);
}
.directory { padding: 1rem .75rem; border-right: 1px solid var(--dim); }
.directory-drawer {
  position: sticky;
  top: 1rem;
  max-height: calc(100vh - 2rem);
  overflow-x: hidden;
  overflow-y: auto;
}
.directory summary { color: var(--accent); cursor: pointer; padding: .5rem 0; }
.directory nav.contents { border: 0; padding: 0; margin: .5rem 0; }
.directory nav.contents ol { display: block; }
.directory nav.contents li { margin: 0; }
.directory a, .directory li[aria-current] {
  display: block;
  padding: .5rem .25rem;
  overflow-wrap: anywhere;
  text-decoration: none;
}
.directory a:hover, .directory a:focus-visible {
  background: var(--accent);
  color: var(--ground);
}
.directory li[aria-current] { border-left: 3px solid var(--accent); background: var(--raised); }
.desk-directory span { color: var(--dim); }
.directory-note { margin: 2rem 0 0; color: var(--dim); }
.reading-pane { min-width: 0; }
.pane-title { border-bottom: 1px solid var(--dim); color: var(--dim); overflow-wrap: anywhere; }
.terminal main { padding: 1.25rem; }
.terminal main :is(h1, h2, h3, h4) { scroll-margin-top: 1rem; }
.terminal nav.bar { border: 1px solid var(--dim); gap: .25rem; padding: .35rem; }
.terminal nav.bar a { display: inline-block; padding: .5rem .75rem; text-decoration: none; }
.terminal .lamp { min-height: 40px; }
.terminal-status { border: 1px solid var(--dim); border-top: 0; color: var(--dim); }
.arrival { border: 1px solid var(--dim); text-align: center; margin-bottom: 1rem; }
.arrival .panel-label { padding: .5rem; background: var(--raised); color: var(--dim); text-align: left; }
.arrival h1 { margin: 0 0 1rem; }
.arrival h1::before { content: none; }
.arrival > p:not(.panel-label) { padding: 0 .75rem; }
.arrival-actions { display: flex; flex-wrap: wrap; justify-content: center; gap: .75rem; }
.arrival-actions a { padding: .5rem 0; }
.desk-notice { color: var(--dim); }
.complaints { border: 1px dashed var(--dim); padding: .75rem; margin: 1rem 0 2rem; }
.complaints summary { cursor: pointer; color: var(--alt); }
.complaints[open] summary { margin-bottom: 1rem; }
.complaints p:last-child { margin-bottom: 0; }
summary:focus-visible, button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
@media (max-width: 1050px) {
  .terminal-workspace { grid-template-columns: minmax(0, 1fr); }
  .directory { border-right: 0; border-bottom: 1px solid var(--dim); padding: .5rem .75rem; }
  .directory-drawer { position: static; max-height: none; }
  .directory-note { display: none; }
  .desk-directory, .directory nav.contents ol { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }
}
@media (max-width: 500px) {
  body.terminal { padding: .5rem; }
  .terminal main { padding: .75rem; }
  .terminal nav.bar a { padding: .5rem; }
  .terminal-title, .pane-title, .terminal-status { padding: .5rem; }
  .arrival .panel-label { overflow-wrap: anywhere; }
}

/* --- the sign over the door ---------------------------------------------- */

pre.sign {
  /* Both axes, on purpose. `overflow-x: auto` alone computes `overflow-y` to
     `auto` as well -- CSS says a `visible` axis beside a non-`visible` one
     becomes `auto` -- so a horizontal scroll container has a vertical one it
     never asked for. The face's ascent and descent are exactly one em, so at
     `line-height: 1` the line boxes are exactly the content height and a
     fraction of a pixel of rounding is enough to show it. 0181. */
  overflow-x: auto;
  overflow-y: hidden;
  color: var(--accent);
  font-size: 8px;
  line-height: 1;
  white-space: pre;
  /* `pre` is a block, so it is as wide as the column and the art sits at the
     left of it while everything around it is centred. `fit-content` shrinks
     the box to the art, and then the margins can centre it. */
  width: fit-content;
  max-width: 100%;
  margin: 0 auto;
}
pre.sign b { color: var(--alt); font-weight: normal; }

p.tagline {
  margin: .75rem 0 0;
  color: var(--ink);
  text-align: center;
}
p.tagline em { color: var(--accent); font-style: normal; }

/* --- rules ---------------------------------------------------------------- */

hr {
  height: 0;
  margin: 1.25rem 0;
  border: 0;
  border-top: 3px double var(--dim);
}
hr.thin  { border-top: 1px solid var(--dim); }
hr.heavy { border-top: 3px double var(--accent); }

/* --- depth, as the site's own colour --------------------------------------

   The ramp from sulphur to magenta is the one piece of colour this project
   invented rather than inherited, and for a long time it only appeared inside
   code samples. Every page of the specification now carries the deepest
   stratum it describes, computed from the page rather than written down, and
   anything that has a depth is stained by it.
   -------------------------------------------------------------------------- */

.gauge { display: flex; gap: 2px; margin: 0 0 1.25rem; }
.gauge span {
  flex: 1 1 0;
  height: 4px;
  background: currentColor;
  opacity: .16;
}
.gauge span.lit { opacity: 1; }

/* The specification is a reference, not a chapter book. Every section keeps
   the whole contents list at its head so a reader can move directly to the
   rule they need. */
nav.contents {
  margin: 0 0 1.25rem;
  padding: .45rem .7rem;
  border: 1px solid var(--dim);
}
nav.contents p { margin: 0 0 .3rem; color: var(--dim); }
nav.contents ol {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(18ch, 1fr));
  gap: .2rem 1.25rem;
  margin: 0;
  padding: 0;
  list-style: none;
}
nav.contents li[aria-current="page"] { color: var(--ink); font-weight: bold; }

td.shaft { min-width: 12ch; }
td.shaft span {
  display: inline-block;
  min-width: 2ch;
  padding: 0 .4ch;
  background: currentColor;
  color: var(--ground);
  text-align: right;
}
td.shaft span.d0 { background: var(--d0); }
td.shaft span.d1 { background: var(--d1); }
td.shaft span.d2 { background: var(--d2); }
td.shaft span.d3 { background: var(--d3); }
td.shaft span.d4 { background: var(--d4); }
td.shaft span.d5 { background: var(--d5); }
td.shaft span.d6 { background: var(--d6); }
td.shaft span.d7 { background: var(--d7); }
td.shaft span.d8 { background: var(--d8); }

/* --- navigation ----------------------------------------------------------- */

nav.bar {
  display: flex;
  flex-wrap: wrap;
  gap: 0 .5ch;
  align-items: baseline;
  padding: .3rem .6rem;
  border: 2px solid;
  border-color: var(--bevel-hi) var(--bevel-lo) var(--bevel-lo) var(--bevel-hi);
  background: var(--ground);
}
nav.bar .sep { color: var(--dim); }
nav.bar a { color: var(--ink); }
nav.bar a:hover { background: var(--accent); color: var(--ground); }
nav.bar a[aria-current] { background: var(--accent); color: var(--ground); }
nav.bar .spacer { flex: 1 1 auto; }

/* --- headings: DOS window title bars -------------------------------------- */

h1 {
  margin: 1.5rem 0 .75rem;
  color: var(--accent);
  font-size: 24px;
  font-weight: bold;
  letter-spacing: .125em;
  text-transform: uppercase;
}
h1::before { content: "\2588\2588 "; }
h1::before, h2::before, h3::before { margin-right: .5ch; }

h2 {
  margin: 2.25rem 0 .75rem;
  padding: .15rem .6rem;
  background: var(--accent);
  color: var(--ground);
  font-size: 24px;
  font-weight: bold;
}
h2::before { content: "\25A0 "; }

h3 {
  margin: 1.6rem 0 .5rem;
  color: var(--alt);
  font-size: 16px;
  font-weight: bold;
}
h3::before { content: "\25B8 "; color: var(--dim); }

h4 {
  margin: 1.2rem 0 .4rem;
  color: var(--quote);
  font-size: 16px;
  font-weight: bold;
}

h1 a, h2 a, h3 a, h4 a { color: inherit; text-decoration: none; }
h2 a:hover, h3 a:hover, h4 a:hover { text-decoration: underline; }

/* --- text ----------------------------------------------------------------- */

p { margin: 0 0 .9rem; }
strong { color: var(--accent); font-weight: bold; }
em { color: var(--alt); font-style: normal; text-decoration: underline; }

a { color: var(--alt); text-decoration: underline; }
a:hover { background: var(--alt); color: var(--ground); text-decoration: none; }
a:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

ul, ol { margin: 0 0 .9rem; padding-left: 3ch; }
li { margin: 0 0 .2rem; }
ul { list-style: none; }
ul > li::before { content: "\2022 "; margin-left: -2ch; color: var(--accent); }
ol { list-style-position: outside; }
ol > li::marker { color: var(--accent); }

blockquote {
  margin: 0 0 .9rem;
  padding: .5rem .9rem;
  border-left: 4px solid var(--quote);
  background: var(--ground);
  color: var(--dim);
}
blockquote strong { color: var(--alt); }
blockquote p:last-child { margin-bottom: 0; }

/* --- code ----------------------------------------------------------------- */

code {
  color: var(--code);
  font-family: inherit;
  white-space: pre-wrap;
}
a code { color: inherit; }

figure.listing {
  margin: 0 0 1.1rem;
  border: 2px solid;
  border-color: var(--bevel-lo) var(--bevel-hi) var(--bevel-hi) var(--bevel-lo);
}
figure.listing figcaption {
  padding: .1rem .6rem;
  background: var(--dim);
  color: var(--ground);
  font-size: 8px;
  letter-spacing: .125em;
  text-transform: uppercase;
}
figure.listing pre {
  overflow-x: auto;
  overflow-y: hidden;
  padding: .7rem .9rem;
  /* Was 1.45, which is twenty-three and a fifth. The body's leading, for the
     reason written beside it. */
  line-height: 1.375;
  tab-size: 2;
}
figure.listing pre code { color: var(--ink); white-space: pre; }

/* the syntax colours, such as they are */
.k  { color: var(--accent); font-weight: bold; }  /* keyword     */
.t  { color: var(--alt); }                        /* type        */
.c  { color: var(--dim); }                        /* comment     */
.s  { color: var(--good); }                       /* string      */
.n  { color: var(--alt); }                      /* number      */
.p  { color: var(--dim); }                        /* prompt      */
.h  { color: var(--quote); }                        /* cairn       */
.e  { color: var(--warn); font-weight: bold; }    /* error       */
.d0 { color: var(--d0); font-weight: bold; }
.d1 { color: var(--d1); font-weight: bold; }
.d2 { color: var(--d2); font-weight: bold; }
.d3 { color: var(--d3); font-weight: bold; }
.d4 { color: var(--d4); font-weight: bold; }
.d5 { color: var(--d5); font-weight: bold; }
.d6 { color: var(--d6); font-weight: bold; }
.d7 { color: var(--d7); font-weight: bold; }
.d8 { color: var(--d8); font-weight: bold; }

/* --- tables --------------------------------------------------------------- */

div.scroll { overflow-x: auto; overflow-y: hidden; margin: 0 0 1.1rem; }

table {
  width: 100%;
  border-collapse: collapse;
  border: 2px solid var(--dim);
}
caption {
  padding: .2rem 0;
  color: var(--dim);
  text-align: left;
}
th {
  padding: .2rem .7rem;
  border: 1px solid var(--dim);
  background: var(--dim);
  color: var(--ground);
  text-align: left;
  white-space: nowrap;
}
td {
  padding: .25rem .7rem;
  border: 1px solid var(--dim);
  vertical-align: top;
}
/* Full inversion on hover. Twenty-one to one, and period-appropriate. */
tbody tr:hover td { background: var(--ink); color: var(--ground); }
tbody tr:hover td a { color: var(--ground); }

/* --- boxes ---------------------------------------------------------------- */

div.box {
  margin: 0 0 1.1rem;
  padding: .7rem .9rem;
  border: 2px solid;
  border-color: var(--bevel-hi) var(--bevel-lo) var(--bevel-lo) var(--bevel-hi);
}
div.box > :last-child { margin-bottom: 0; }
div.box.shout { border-color: var(--warn); color: var(--warn); }
/* The one sentence everything else follows from. It gets the room. */
div.box.covenant { border-color: var(--accent); color: var(--accent); margin: 1.5rem 0; }
div.box.covenant strong { font-size: 24px; letter-spacing: .125em; }
div.box.covenant p + p { color: var(--dim); margin-top: .5rem; }

p.small { color: var(--dim); }
div.box.shout strong { color: var(--warn); }

dl.swatches { display: grid; grid-template-columns: repeat(auto-fit, minmax(14ch, 1fr)); gap: .75rem; margin: 1rem 0; }
dl.swatches div { padding: .75rem; color: var(--ink); background: var(--raised); border: 1px solid var(--dim); }
dl.swatches div::before { content: ""; display: block; height: 2rem; margin-bottom: .75rem; background: var(--swatch); border: 1px solid var(--dim); }
dl.swatches dt { font-weight: bold; }
dl.swatches dd { color: var(--dim); }

/* --- the lamp ------------------------------------------------------------- */

button.lamp {
  padding: 0 .6ch;
  border: 2px solid;
  border-color: var(--bevel-hi) var(--bevel-lo) var(--bevel-lo) var(--bevel-hi);
  background: var(--ground);
  color: var(--ink);
  font: inherit;
  cursor: pointer;
}
button.lamp:hover { background: var(--accent); color: var(--ground); }
button.lamp:active { border-color: var(--bevel-lo) var(--bevel-hi) var(--bevel-hi) var(--bevel-lo); }

/* --- the cursor ----------------------------------------------------------- */

span.cursor { animation: blink 1.06s step-end infinite; color: var(--accent); }
@keyframes blink { 50% { opacity: 0; } }

/* --- footer --------------------------------------------------------------- */

footer {
  margin-top: 2.5rem;
  color: var(--dim);
  font-size: 8px;
}
footer a { color: var(--dim); }
footer .badge {
  display: inline-block;
  margin: .5rem .4ch 0 0;
  padding: 0 .5ch;
  border: 1px solid var(--dim);
  color: var(--dim);
  font-size: 8px;
  text-transform: uppercase;
}

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

@media (max-width: 640px) {
  /* The size does not move. Eight and sixteen are the only body sizes at
     which a pixel of the face is a whole number of the screen's, and a
     narrow screen is the last place to start drawing half of one. */
  body { padding: 1rem .6rem 4rem; }
  pre.sign { font-size: 8px; }
}

/* ===========================================================================
   THE DATED PART
   ---------------------------------------------------------------------------
   Everything below here is on purpose. Every graphic on this site was written
   by site/gfx.py, which contains a GIF89a encoder, an LZW compressor
   and a 5x7 bitmap font, because there is no image library in this repository
   and there is not going to be one.
   =========================================================================== */

img { image-rendering: pixelated; image-rendering: crisp-edges; }

.center { text-align: center; }

img.banner { width: 100%; max-width: 396px; margin: 0 auto; }
/* The mark. Drawn at three times the cell and shown at exactly that, because
   a bitmap resampled to 1.4 pixels per pixel is an argument against itself. */
img.mark { display: block; width: 96px; height: 120px; margin: 0 auto 1rem; image-rendering: pixelated; }
img.descent { display: block; width: 320px; max-width: 100%; height: auto; margin: 1rem auto; }
img.hero { display: block; width: 100%; max-width: 600px; height: auto; margin: 0 auto 1.25rem; image-rendering: pixelated; }
img.rule   { width: 100%; max-width: 396px; margin: 1rem auto; }
/* The specimen is drawn at three times the cell and must not be resampled to
   anything else: a bitmap face shown at 1.4 pixels per pixel is an argument
   against itself. */
img.specimen { width: 100%; max-width: 435px; margin: 1rem auto; image-rendering: pixelated; }

/* the marquee, which we are not sorry about */
.marquee {
  overflow: hidden;
  margin: 0 0 1rem;
  padding: .2rem 0;
  border-top: 1px solid var(--dim);
  border-bottom: 1px solid var(--dim);
  white-space: nowrap;
}
.marquee > span {
  display: inline-block;
  padding-left: 100%;
  color: var(--accent);
  animation: crawl 24s linear infinite;
}
@keyframes crawl { to { transform: translateX(-100%); } }

.blink { animation: blink 1.2s step-end infinite; }

/* a plaque: a bevelled box with a DOS title bar on it */
.plaque { margin: 0 0 1.2rem; border: 2px solid; border-color: var(--bevel-hi) var(--bevel-lo) var(--bevel-lo) var(--bevel-hi); }
.plaque > h3 {
  margin: 0;
  padding: .15rem .6rem;
  background: var(--dim);
  color: var(--ground);
  font-size: 8px;
  letter-spacing: .125em;
}
.plaque > h3::before { content: none; }
.plaque > div { padding: .7rem .9rem; }
.plaque > div > :last-child { margin-bottom: 0; }

/* the doctrine */
ol.doctrine { margin: 0 0 1.2rem; padding: 0; list-style: none; counter-reset: doctrine; }
ol.doctrine > li {
  position: relative;
  margin: 0 0 .8rem;
  padding: 0 0 0 5ch;
  counter-increment: doctrine;
}
ol.doctrine > li::before {
  content: counter(doctrine, decimal-leading-zero) ".";
  position: absolute;
  left: 0;
  color: var(--accent);
  font-weight: bold;
}
ol.doctrine > li b { display: block; color: var(--ink); text-transform: uppercase; letter-spacing: .125em; }
ol.doctrine > li span { color: var(--dim); }

/* A diagram that carries labels is drawn small and shown at an exact 2x.
   The 5x7 face has no more detail to give, so drawing it larger would cost
   four times the bytes for the same pixels; an integer upscale of pixel art
   is exact, and `image-rendering: pixelated` above keeps it that way. Below
   600px it scales down instead of overflowing, and stays blocky doing it. */
.diagram { display: block; width: 600px; max-width: 100%; height: auto; margin: 1.5rem auto; }


/* the badge shelf */
.badges { display: flex; flex-wrap: wrap; gap: 4px; justify-content: center; margin: 1rem 0; }
.badges img { width: 88px; height: 31px; }

.counter { display: flex; align-items: center; justify-content: center; gap: 1ch; margin: 1rem 0; color: var(--dim); font-size: 8px; }

hr.gfx { height: 0; margin: 1.2rem 0; border: 0; }

/* The necropolis: a neighbourhood of records, not a moving constellation.
   All controls remain ordinary HTML. The SVG only connects their boxes. */
body.necropolis { max-width: 1248px; padding: var(--step) var(--tight) var(--gap); }
.necropolis [hidden] { display: none !important; }
.necropolis h1 { font-size: 32px; line-height: 1.25; margin: var(--tight) 0; }
.necropolis h2 { background: none; color: var(--ink); padding: 0; margin: 0 0 var(--hair); font-size: 24px; border: 0; }
.necropolis h3 { color: var(--dim); font-size: 16px; margin: 0 0 var(--tight); }
.necropolis h1::before, .necropolis h2::before, .necropolis h3::before { content: none; }
.necropolis p { margin: 0 0 var(--hair); }
.necropolis button { font: inherit; color: var(--ink); background: var(--raised); border: 1px solid var(--dimmer); padding: 10px 16px; min-height: 44px; cursor: pointer; text-align: left; }
.necropolis button:hover:not(:disabled) { border-color: var(--accent); background: var(--sunk); }
.necropolis button:disabled { color: var(--dim); cursor: default; border-style: dotted; }
.necropolis :focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; }
.necropolis pre { white-space: pre-wrap; overflow-wrap: anywhere; overflow-x: auto; overflow-y: hidden; max-width: 100%; margin: var(--hair) 0; padding: var(--tight); background: var(--sunk); border: 1px solid var(--dimmer); }
.necropolis code { background: transparent; padding: 0; }
.nc-header { border-bottom: 1px solid var(--dimmer); padding-bottom: var(--tight); margin-bottom: var(--tight); }
.nc-eyebrow, .nc-private, .nc-caption, .nc-footer { color: var(--dim); }
.necropolis .nc-eyebrow { font-size: 16px; letter-spacing: .125em; }
.nc-header h1 { color: var(--accent); }
.nc-private { margin-top: var(--tight) !important; }
.nc-source { border: 1px solid var(--dimmer); padding: var(--hair) var(--tight); background: var(--sunk); }
.nc-source summary { cursor: pointer; min-height: 32px; color: var(--code); }
.nc-source label { display: block; margin-top: var(--hair); }
.nc-source textarea { display: block; width: 100%; min-height: 240px; resize: vertical; margin: var(--hair) 0; padding: var(--hair); border: 1px solid var(--dimmer); background: var(--ground); color: var(--ink); font: inherit; line-height: 1.5; }
.nc-state { display: flex; align-items: center; justify-content: space-between; gap: var(--hair); padding: var(--tight) 0; color: var(--dim); }
.nc-state p { margin: 0; }
.nc-overview { display: flex; align-items: center; justify-content: space-between; gap: var(--tight); padding: var(--tight); border: 1px solid var(--dimmer); border-top: 3px solid var(--accent); background: var(--sunk); }
.nc-overview h2 { overflow-wrap: anywhere; }
.nc-roots { display: flex; flex-wrap: wrap; gap: var(--hair); max-width: 50%; }
.necropolis .nc-root-hole { border-style: dashed; color: var(--accent); }
.necropolis .nc-root-deposit { color: var(--code); }
.nc-navigation { display: flex; flex-wrap: wrap; align-items: center; gap: var(--hair); margin: var(--tight) 0; padding: 0; border: 0; background: none; }
.nc-navigation span { margin-left: auto; color: var(--dim); }
.nc-neighbourhood { position: relative; display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr) minmax(0, 1fr); gap: var(--step); align-items: center; min-height: 300px; padding: var(--tight) 0 var(--step); }
.nc-neighbourhood > section { position: relative; z-index: 1; min-width: 0; }
.nc-neighbours h3 { text-transform: uppercase; letter-spacing: .125em; }
.nc-object { display: grid; grid-template-columns: 1fr auto; gap: 6px 12px; width: 100%; margin-bottom: var(--hair); }
.nc-object .nc-edge-label { grid-column: 1 / -1; color: var(--dim); font-size: 16px; }
.nc-object strong { color: var(--ink); }
.nc-object code { color: var(--dim); }
.nc-preview { grid-column: 1 / -1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-size: 16px; }
.nc-empty { color: var(--dim); border-top: 1px dotted var(--dimmer); padding-top: var(--hair); }
.nc-selected { padding: var(--tight); border: 2px solid var(--accent); background: var(--sunk); box-shadow: 6px 6px 0 var(--raised); overflow-wrap: anywhere; }
.nc-selected h2 { font-size: 32px; color: var(--accent); }
.nc-selected .nc-eyebrow { font-size: 16px; }
.necropolis [data-kind="Hole"] { border-style: dashed; border-color: var(--accent); }
.necropolis [data-kind="Deposit"] { border-color: var(--code); }
.necropolis [data-kind="Missing"], .necropolis [data-kind="Unavailable"] { border-style: dotted; border-color: var(--warn); }
.nc-wires { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; z-index: 0; }
.nc-wire { fill: none; stroke: var(--dimmer); stroke-width: 1.5; }
.nc-wire[data-kind="Hole"] { stroke: var(--accent); stroke-dasharray: 5 5; }
.nc-wire[data-kind="Deposit"] { stroke: var(--code); }
.nc-inspector { padding: var(--tight); border: 1px solid var(--dimmer); background: var(--raised); }
.nc-inspector-heading { display: flex; justify-content: space-between; align-items: center; gap: var(--hair); margin-bottom: var(--hair); }
.nc-inspector-heading h2 { margin: 0; }
.nc-inspector > code { display: block; color: var(--dim); overflow-wrap: anywhere; margin-bottom: var(--tight); user-select: all; }
.nc-inspector h3 { margin-top: var(--tight); margin-bottom: var(--hair); }
.nc-inspector button + button { margin-left: var(--hair); }
.nc-excerpt mark { background: var(--accent); color: var(--sunk); padding: 2px 0; }
.nc-caption { margin-top: var(--tight) !important; }
.nc-footer { margin-top: var(--step); padding-top: var(--tight); border-top: 1px solid var(--dimmer); font-size: 16px; }
@media (max-width: 760px) {
  body.necropolis { padding: var(--tight) var(--hair) var(--step); }
  .necropolis h1 { font-size: 32px; }
  .nc-neighbourhood { grid-template-columns: minmax(0, 1fr); gap: var(--tight); }
  .nc-selected { order: -1; }
  .nc-wires { display: none; }
  .nc-overview, .nc-inspector-heading { align-items: flex-start; flex-direction: column; }
  .nc-roots { max-width: 100%; }
  .nc-inspector, .nc-overview { padding: var(--hair); }
  .nc-navigation { gap: 8px; }
  .nc-navigation button { padding: 8px; }
  .nc-navigation span { width: 100%; margin: 0; }
}

/* --- the manual's chapter list -------------------------------------------- */

/* Nine doors, numbered, in the order they are meant to be opened. A grid
   rather than a table because there is nothing to compare between rows: the
   only fact about a chapter here is which one comes next. */
.chapters {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: .4rem;
  margin: 1.5rem 0;
}
a.chapter {
  display: flex;
  gap: .75rem;
  align-items: baseline;
  padding: .6rem .8rem;
  border: 2px solid;
  border-color: var(--bevel-hi) var(--bevel-lo) var(--bevel-lo) var(--bevel-hi);
  text-decoration: none;
  color: var(--ink);
}
a.chapter .n { color: var(--dimmer); }
a.chapter:hover, a.chapter:focus-visible { background: var(--accent); color: var(--ground); }
a.chapter:hover .n, a.chapter:focus-visible .n { color: var(--ground); }

/* --- the face specimen ---------------------------------------------------- */

.s8  { font-size: var(--type-fine); line-height: 1; white-space: pre; }
.s16 { font-size: var(--type-body); line-height: 1; white-space: pre; }
.s24 { font-size: var(--type-head); line-height: 1; white-space: pre; }
.s32 { font-size: var(--type-sign); line-height: 1; white-space: pre; }

.specimen-scale { margin: 1rem 0 1.5rem; }
.scale-row {
  overflow-x: auto;
  overflow-y: hidden;
  margin: 0 0 .75rem;
  padding: .7rem .9rem;
  background: var(--raised);
  border: 1px solid var(--dim);
}
.scale-row p.c { margin: 0 0 .4rem; font-size: var(--type-fine); }
.scale-sample { margin: 0 0 .25rem; }
.scale-sample:last-child { margin-bottom: 0; }

.glyph-catalogue {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: .75rem;
  margin: 1rem 0 2rem;
}
.glyph-card {
  display: flex;
  flex-direction: column;
  gap: .6rem;
  min-width: 0;
  padding: .75rem;
  background: var(--raised);
  border: 1px solid var(--dim);
}
.glyph-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: .25rem .75rem;
  padding-bottom: .35rem;
  border-bottom: 1px solid var(--dimmer);
}
.glyph-meta {
  font-size: var(--type-fine);
  color: var(--dim);
  letter-spacing: .125em;
  text-transform: uppercase;
}
.glyph-name {
  flex-basis: 100%;
  font-size: var(--type-fine);
  color: var(--dim);
  overflow-wrap: anywhere;
}
.glyph-grids {
  display: flex;
  gap: .75rem;
  align-items: flex-start;
}
.glyph-cell { margin: 0; }
.glyph-cell figcaption {
  margin-bottom: .2rem;
  font-size: var(--type-fine);
  color: var(--dim);
}
pre.glyph-grid {
  overflow-x: hidden;
  overflow-y: hidden;
  padding: .35rem;
  background: var(--ground);
  color: var(--ink);
  border: 1px solid var(--dimmer);
  font-size: var(--type-fine);
  line-height: 1;
  white-space: pre;
}
pre.glyph-grid[data-weight="bold"] { color: var(--accent); }
.glyph-sizes {
  display: flex;
  flex-wrap: wrap;
  gap: .4rem;
  align-items: flex-end;
  padding-top: .35rem;
  border-top: 1px solid var(--dimmer);
}
.glyph-size {
  display: inline-flex;
  align-items: baseline;
  gap: .25rem;
  padding: .25rem .35rem;
  background: var(--ground);
  border: 1px solid var(--dimmer);
}
.glyph-px {
  margin-right: .1rem;
  font-size: var(--type-fine);
  color: var(--dim);
}
