/* Every literal colour is a token; changes land in one place. */
:root { color-scheme: light dark;
  --font-body: ui-serif, Georgia, "Times New Roman", serif;
  --font-mono: ui-monospace, SFMono-Regular, Menlo, monospace;
  --fg: #111;      --dim: #555;
  --bg: #fdfdfc;   --line: #e3e3e0;
  --code-bg: #f4f4f1;
  --accent: #00e;
  --veil: rgb(253 253 252 / 0%);
}
@media (prefers-color-scheme: dark) {
  :root { --fg: #e8e8e6; --dim: #a0a09b; --bg: #16161a;
          --line: #2c2c31; --code-bg: #1e1e23; --accent: #8ab4f8;
          --veil: rgb(8 8 10 / 78%); }
}
* { box-sizing: border-box; }
body { margin: 0; background: var(--bg); color: var(--fg);
       font: 16px/1.65 var(--font-body); }
.wrap { max-width: 68rem; margin: 0 auto; padding: 2.5rem 1.25rem 3rem;
        display: grid; grid-template-columns: 14rem minmax(0, 1fr); gap: 2.75rem;
        align-items: start; }
.wrap.solo { grid-template-columns: minmax(0, 1fr); max-width: 46rem; }
main { max-width: 46rem; }
@media (width <= 56rem) {
  .wrap, .wrap.solo { grid-template-columns: minmax(0, 1fr); gap: 1.5rem; }
  nav.tree ul ul { display: none; }

  /* The column head on a narrow screen: the name on one side, the button on
     the other, the index beneath them both when it is asked for. */
  .side { display: grid; grid-template-columns: minmax(0, 1fr) auto;
          align-items: center; gap: 1rem; }
  .side .brand { margin: 0; }
  .side .find, .side nav.tree { grid-column: 1 / -1; }

  /* Where the script runs, the index waits behind the button; where it does
     not, the button is never shown and the index stays where it was. The
     search box waits behind the same button as the index it searches. */
  .js .burger { display: inline-flex; }
  .js .side .find { display: none; }
  .js .burger[aria-expanded="true"] ~ .find { display: block; }
  .js nav.tree { position: static; display: none; }
  .js nav.tree.open { display: block; }
  /* Asked for in full, given in full: an open index shows its sub-lists,
     which the always-there one has no room for. */
  .js nav.tree.open ul ul { display: block; }
}

/* The index list on the left: the whole tree, all the time, in the body
   voice. Groups are bold; where you are is underlined. */
nav.tree { position: sticky; top: 2rem; font-size: .95rem; }
nav.tree ul { list-style: none; margin: 0; padding: 0; }
nav.tree ul ul { padding-left: 1rem; }
nav.tree a { color: var(--fg); text-decoration: none; display: block;
             position: relative; padding: .18rem 0 .18rem 1.45em; }
nav.tree a:hover { text-decoration: underline; text-underline-offset: 3px; }
nav.tree a.current { font-weight: 700; text-decoration: underline;
                     text-underline-offset: 3px; }
nav.tree li.group > a { font-weight: 700; }

/* The search box, above the index it searches; the stylesheet reveals it only
   where scripts run, for the same reason it reveals the button. Results stand
   where the tree stood, in its column and its voice, with the match set bold
   rather than highlit: a page of yellow smears is hazard tape, not type. */
.find { display: none; margin: 0 0 1.1rem; }
.js .find { display: block; }
.find input { width: 100%; padding: .4rem .6rem; font: inherit;
              font-size: .95rem; color: var(--fg); background: var(--bg);
              border: 1px solid var(--line); border-radius: 4px; }
nav.tree .found { margin: 0 0 .8rem; }
nav.tree .results li { margin: 0 0 .9rem; }
nav.tree .results a { display: inline; padding: 0; font-weight: 700; }
nav.tree .results .dim { display: block; margin-top: .15rem; }
.results mark { background: none; color: var(--fg); font-weight: 700; }

.crumbs { font-size: .9rem; line-height: 1.65; min-height: 1.65em;
          margin-bottom: .75rem; }

/* Previous and next, in sidebar order. */
.pager { display: flex; justify-content: space-between; gap: 1.5rem;
         margin-top: 3rem; padding-top: 1rem; border-top: 1px solid var(--line);
         font-size: .95rem; }
.pager .next { margin-left: auto; text-align: right; }

h1 { font-size: 2rem; letter-spacing: -.02em; line-height: 1.15;
     margin: 0 0 .4rem; }
h2 { font-size: 1.15rem; letter-spacing: -.01em; margin: 2.25rem 0 .6rem;
     clear: both; }

/* A heading links to itself. The mark keeps its space while invisible, so
   hovering a heading does not nudge the line it sits on. */
.anchor { margin-left: .35rem; font-weight: 400; text-decoration: none;
          color: var(--dim); opacity: 0; }
h2:hover .anchor, h3:hover .anchor, h4:hover .anchor,
h5:hover .anchor, h6:hover .anchor, .anchor:focus { opacity: 1; }
/* The line under the landing's name, which the site states once and the page
   is handed rather than repeating. */
.lede { font-weight: 700; font-size: 1.05rem; margin: 0 0 1rem; }
p, li { margin: .6rem 0; }

a { color: var(--accent); }

/* A name, set in its own face; the face itself arrives per site, as
   .wordmark-1 and so on. Display faces run small against a serif at the same
   size, so they are nudged up to sit level with the words either side, and the
   weight is pinned because one-weight faces get smeared by a bold heading. */
.wordmark { font-weight: 400; font-size: 1.06em; letter-spacing: .01em; }
.dim { color: var(--dim); font-size: .9rem; }
hr { border: 0; border-top: 1px solid var(--line); margin: 2.5rem 0; }
blockquote { color: var(--dim); border-left: 2px solid var(--line);
             margin: 1rem 0; padding-left: 1rem; }

/* A backdrop: a picture behind everything, distinct from the hero above, which
   is the masthead. The page then reads off a panel rather than off the picture,
   which is the only way the words stay words.
   Fixed, so the artwork holds still while the column scrolls over it.
   
   The veil is what makes that work in the dark. These pictures are drawn on
   white, and a near-black panel floating in a bright field is the wrong way
   round: the surround should be darker than the thing being read, not
   brighter. In the light the veil is clear and the artwork is itself. */
body.has-backdrop {
  background-image: linear-gradient(var(--veil), var(--veil)), var(--backdrop);
  background-position: center;
  background-size: cover;
  background-attachment: fixed;
  background-repeat: no-repeat;
}
body.has-backdrop .wrap { margin: 2.5rem auto; padding: 2.75rem 2.5rem 3rem;
                      background: var(--bg); border: 1px solid var(--line);
                      border-radius: 8px; }
@media (width <= 46rem) {
  body.has-backdrop { background-attachment: scroll; }
  body.has-backdrop .wrap { margin: 0 auto; border: 0; border-radius: 0; }
}

/* The roster: every other site in the registry, with its own mark. */
.fleet { list-style: none; padding: 0; margin: 1.5rem 0; }
.fleet li { display: flex; gap: .9rem; margin: 0 0 1.4rem; }
.fleet-mark { flex: 0 0 auto; width: 2.3rem; height: 2.3rem; margin-top: .2rem;
              object-fit: contain; }
.fleet-head { display: block; }
.fleet-name { font-weight: 700; }
/* Where to go, beside the name rather than on it. */
.fleet-link { margin-left: .7rem; font-size: .85em; }
.fleet .dim { display: block; }

/* The tree of indexes: a section page is a listing of its children. */
ul.index { list-style: none; padding: 0; margin: 1.5rem 0; }
ul.index li { margin: 0 0 1rem; padding-bottom: 1rem; border-bottom: 1px solid var(--line); }
ul.index li:last-child { border-bottom: 0; }
ul.index span.dim { display: block; margin-top: .15rem; }

/* The copy button the one emitted script builds, sitting over its block.
   flow-root because the block it wraps is a formatting context of its own and
   steps aside for a float, while a plain div would run on underneath one and
   take the button out over the image with it. */
.codeblock { position: relative; display: flow-root; }
.codeblock pre { padding-right: 2.9rem; }
.copy { position: absolute; top: .4rem; right: .4rem; cursor: pointer;
        display: inline-flex; align-items: center; justify-content: center;
        width: 1.7rem; height: 1.7rem; padding: 0; color: var(--dim);
        background: var(--bg); border: 1px solid var(--line);
        border-radius: 4px; }
.copy:hover { color: var(--fg); }

/* The menu button: the copy button's box, at the size a thumb needs. It is
   hidden wherever the index is already on the page -- every wide screen, and
   any screen at all without the script that would open it. */
.burger { display: none; align-items: center; justify-content: center;
          width: 2.75rem; height: 2.75rem; padding: 0; cursor: pointer;
          color: var(--fg); background: var(--bg);
          border: 1px solid var(--line); border-radius: 4px; }
.burger .ex, .burger[aria-expanded="true"] .bars { display: none; }
.burger[aria-expanded="true"] .ex { display: block; }

code, pre { font-family: var(--font-mono); font-size: .875rem; }
pre { background: var(--code-bg); border: 1px solid var(--line); border-radius: 6px;
      padding: .85rem 1rem; overflow-x: auto; line-height: 1.5; }
code:not(pre code) { background: var(--code-bg); padding: .1rem .3rem; border-radius: 3px; }

table { border-collapse: collapse; width: 100%; margin: 1rem 0; font-size: .92em; }
th, td { border: 1px solid var(--line); padding: .45rem .7rem; text-align: left; vertical-align: top; }
th { background: var(--code-bg); }

footer { margin-top: 3rem; padding-top: 1rem; border-top: 1px solid var(--line);
         color: var(--dim); font-size: .9rem; text-align: right; }

/* The name is the loudest thing in the column, because it is the one thing
   there that is not navigation. */
.brand { margin: 0 0 1.1rem; font-size: 1.5rem; line-height: 1.2; }
.brand a { color: var(--fg); text-decoration: none; position: relative;
           display: inline-block; padding-left: 1.25em; }

/* The mark sits in a gutter every link reserves, so the list does not shift
   as it moves from one entry to the next. */
.tree-mark { position: absolute; left: 0; top: 50%; width: 1.05em;
             height: auto; transform: translateY(-50%); }
/* The cover engraving sits beside the opening paragraph, not above it, so the
   page opens on words. It unfloats where a column that narrow would leave the
   text in a gutter. */
.cover { float: right; max-width: 45%; margin: .2rem 0 1rem 1.75rem; }
.cover img { display: block; margin-left: auto; max-width: 16rem; width: 100%;
             height: auto; border-radius: 6px; border: 1px solid var(--line); }
.cover .credit, .hero-art figcaption { display: block; margin-top: .5rem;
                 font-size: .78rem; line-height: 1.45; color: var(--dim); }

/* The masthead: the name at the size a name deserves, its line beneath, and
   the picture beside them rather than floated into the paragraph after. The
   two sit on one baseline grid so the block reads as one thing. */
.hero { display: grid; grid-template-columns: minmax(0, 1fr) auto;
        gap: 2.75rem; align-items: center; margin: 0 0 2.5rem; }
.hero h1 { font-size: 3.1rem; line-height: 1.05; margin: 0 0 .55rem; }
.hero .lede { font-size: 1.2rem; margin: 0 0 1.1rem; }
.hero-words > p:last-child { margin-bottom: 0; }
.hero-art { margin: 0; }
.hero-art img { display: block; width: 15rem; max-width: 100%; height: auto;
                border: 1px solid var(--line); border-radius: 6px; }
@media (width <= 46rem) {
  .hero { grid-template-columns: minmax(0, 1fr); gap: 1.5rem; }
  .hero h1 { font-size: 2.4rem; }
  .hero-art img { width: 12rem; }
}

/* Something served from elsewhere, framed like a code block so it reads as
   part of the page rather than as a hole punched through it. */
.embed { display: block; width: 100%; height: 20rem; margin: 1.5rem 0;
         border: 1px solid var(--line); border-radius: 6px; background: var(--bg); }
@media (width <= 40rem) {
  .cover { float: none; max-width: none; margin: .5rem 0 1.25rem;
           text-align: center; }
}

/* Syntax highlighting, applied at build time by highlight.js. Six colours
   rather than the thirty a full theme defines: a code block should read as
   prose with structure, not as a christmas tree, and the eye only needs to
   separate what a thing IS from what it is CALLED. Anything unmapped inherits
   the body colour, which is the right default for the parts of a program that
   are just names. */
:root {
  --hl-keyword: #8250df;   /* keyword, operator, the language's own words */
  --hl-string:  #0a6847;   /* string, char, regex */
  --hl-comment: #6a737d;   /* comment, and anything else that is not code */
  --hl-name:    #0550ae;   /* function and type names at their definition */
  --hl-literal: #953800;   /* number, boolean, null */
  --hl-attr:    #24292f;   /* attribute, property, punctuation-ish */
}
@media (prefers-color-scheme: dark) {
  :root {
    --hl-keyword: #d2a8ff;
    --hl-string:  #7ee787;
    --hl-comment: #8b949e;
    --hl-name:    #79c0ff;
    --hl-literal: #ffa657;
    --hl-attr:    #c9d1d9;
  }
}

.hljs-keyword, .hljs-operator, .hljs-literal.hljs-keyword,
.hljs-selector-tag, .hljs-built_in, .hljs-meta { color: var(--hl-keyword); }
.hljs-string, .hljs-char, .hljs-regexp, .hljs-symbol,
.hljs-template-string, .hljs-quote { color: var(--hl-string); }
.hljs-comment { color: var(--hl-comment); font-style: italic; }
.hljs-title, .hljs-title.function_, .hljs-title.class_,
.hljs-section, .hljs-name { color: var(--hl-name); }
.hljs-number, .hljs-literal { color: var(--hl-literal); }
.hljs-attr, .hljs-attribute, .hljs-property,
.hljs-variable, .hljs-params { color: var(--hl-attr); }
/* A diff or a shell prompt should not be louder than the code it sits in. */
.hljs-addition { color: var(--hl-string); }
.hljs-deletion { color: var(--hl-literal); }

@font-face { font-family: "Fredoka"; font-style: normal;
  font-weight: 400; font-display: block;
  src: url("/fredoka-latin.woff2") format("woff2"); }
.wordmark-1 { font-family: "Fredoka", var(--font-body); }

@font-face { font-family: "IM Fell English SC"; font-style: normal;
  font-weight: 400; font-display: block;
  src: url("/im-fell-english-sc-latin.woff2") format("woff2"); }
.wordmark-2 { font-family: "IM Fell English SC", var(--font-body); }

.wordmark-3 { font-family: "IM Fell English SC", var(--font-body); }
