@font-face {
    font-family: 'Berkeley Mono';
    src: url('/berkeley-mono-vf.v2.woff2') format('woff2');
    font-weight: 100 900;
    font-stretch: 60% 100%;
    font-style: oblique 0deg 16deg;
    font-display: swap;
}

:root {
    --ink: #000000;
    --paper: #ffffff;
    --ground: #f0f0f0;
    --frame: #d4d4d4;
    --muted: #666666;
    --accent: #0b3d91;
    /* Current-page marker only */
    --mark: #c00000;

    --edge: #7a7a7a;

    /* A surface for inline code. */
    --wash: #ececec;

    --sidenote-width: 13rem;
    --sidenote-gap: 1.25rem;

    /* Rail spacing is a token because dark mode needs more of it. */
    --nav-gap: 0.35rem;

    color-scheme: light;

    /* Berkeley Mono advances 0.6em, so 1ch is exactly 0.6em. */
    --measure: 78ch;
    --rail: 11rem;
    --gap: 2.5rem;

    --pad-x: 2.25rem;
    --pad-y: 2rem;
}


/* Disabled for now. Not the look I'm going for */
/*
@media (prefers-color-scheme: dark) {
    :root {
        --ink: #eaeaea;
        --paper: #000000;
        --ground: #1a1a1a;
        --frame: #33353a;
        --muted: #9a9a9a;
        --accent: #7ea8e8;

        --nav-gap: 0.6rem;
    }
}
*/


* {
    box-sizing: border-box;
}

::selection {
    background: var(--ink);
    color: var(--paper);
}

html {
    background: var(--ground);
    color: var(--ink);
    font-family: 'Berkeley Mono', ui-monospace, Consolas, monospace;
    /* 17px floor, but yield to a larger browser default. The plain
       declaration is a fallback for browsers without max(). */
    font-size: 17px;
    font-size: max(17px, 100%);
    line-height: 1.65;
}

body {
    margin: 0;
    padding: 3rem 1rem;
}

/* ---- Shell ------------------------------------------------------------- */
/* Three columns with equal gutters, so the sheet is centred on the viewport.
   The rail sits at the inner edge of the left gutter, so --gap is the visible
   separation at any width. Flooring both gutters at the rail width means the
   sheet yields space before the rail can be overrun. */

.shell {
    display: grid;
    grid-template-columns:
        minmax(var(--rail), 1fr) minmax(0, var(--measure)) minmax(var(--rail), 1fr);
    align-items: start;
}

/* ---- Masthead and rail ------------------------------------------------- */

.masthead {
    grid-column: 1;
    justify-self: end;
    width: var(--rail);
    padding-right: var(--gap);
    position: sticky;
    top: 3rem;
}

.sheet {
    grid-column: 2;
}

.wordmark {
    display: block;
    text-decoration: none;
    color: var(--ink);
}

.callsign {
    display: block;
    font-size: 1.5rem;
    font-weight: 800;
    letter-spacing: 0.18em;
    line-height: 1.2;
}

.realname {
    display: block;
    font-size: 0.75rem;
    font-stretch: 90%;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--muted);
}

.masthead nav {
    margin-top: 2rem;
    display: flex;
    flex-direction: column;
    gap: var(--nav-gap);
}

/* Nav items carry .btn. Only the scale and the marker alignment differ. */
.masthead nav a {
    font-size: 0.8rem;
    gap: 1ch;
    justify-content: flex-start;
}

/* The current page is marked by a filled square. */
.masthead nav a::before {
    content: "";
    flex: 0 0 auto;
    width: 0.5em;
    height: 0.5em;
    background: transparent;
}

.masthead nav a[aria-current]::before {
    background: var(--mark);
}

@media (forced-colors: active) {
    .masthead nav a[aria-current]::before {
        background: CanvasText;
        forced-color-adjust: none;
    }
}

/* A notebook entry hangs under its section as an indented child. Wrapping is
   allowed because the indented rail leaves room for about ten characters on
   one line. */
.masthead nav .sub {
    margin-left: 2ch;
    min-width: 0;
    white-space: normal;
}

/* ---- Sheet ------------------------------------------------------------- */

.sheet {
    background: var(--paper);
    border: 1px solid var(--frame);
    border-radius: 4px;
    padding: var(--pad-y) var(--pad-x);
    min-width: 0;
}

.sheet h1 {
    margin: 0;
    font-size: 1.3rem;
    font-weight: 800;
    letter-spacing: 0.16em;
    text-transform: uppercase;
}

/* One hairline, same bleed. The double stroke opens a document; this only
   closes a header block, and matches the rule above the series navigation. */
.rule-thin {
    height: 0;
    border-top: 1px solid var(--frame);
    margin: 0.9rem calc(var(--pad-x) * -1) 1.75rem;
}

/* Against a title block the heavy rule does not need its full clearance. */
.rule:has(+ .note-head) {
    margin-bottom: 0.9rem;
}

/* Two equal strokes bled to both edges of the sheet. */
.rule {
    height: 7px;
    border-top: 2px solid var(--ink);
    border-bottom: 2px solid var(--ink);
    margin: 1.25rem calc(var(--pad-x) * -1) 2rem;
}

/* ---- Prose ------------------------------------------------------------- */

strong {
    font-weight: 800;
}

:where(.sheet) p {
    margin: 0 0 1.5rem;
    hyphens: auto;
    -webkit-hyphens: auto;
}

.sheet p:last-child {
    margin-bottom: 0;
}

/* :where() zeroes this rule's specificity so a .btn placed in the sheet keeps
   its own colour and loses the prose underline. */
:where(.sheet) a {
    color: var(--accent);
    text-decoration: underline;
    text-underline-offset: 0.2em;
    text-decoration-thickness: 1px;
}

/* ---- Portrait ---------------------------------------------------------- */

.portrait {
    float: right;
    width: 13rem;
    max-width: 40%;
    margin: 0.35rem 0 1.25rem 2.5ch;
    border: 1px solid var(--edge);
    line-height: 0;
}

.portrait picture {
    display: contents;
}

.portrait img {
    display: block;
    width: 100%;
    height: auto;
}

/* ---- Contact ----------------------------------------------------------- */

.contact {
    clear: both;
    margin-top: 2.5rem;
    padding-top: 1.25rem;
    border-top: 1px solid var(--frame);
    font-size: 0.85rem;
}

.contact .label {
    font-weight: 700;
    font-stretch: 90%;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--muted);
    margin-right: 2ch;
}

/* ---- Button ------------------------------------------------------------ */

.btn {
    --btn-drop: 2px;

    position: relative;
    top: 0;
    left: 0;

    display: inline-flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.25em 2ch;
    min-width: 16ch;
    max-width: 100%;

    padding: 0.3rem 1.25ch;
    border: 1px solid var(--ink);
    background: var(--paper);
    color: var(--ink);
    box-shadow: var(--btn-drop) var(--btn-drop) 0 var(--ink);

    font: inherit;
    /* A control does not want prose leading. Most of the height a button
       looked padded with came from inheriting 1.65. */
    line-height: 1.2;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-decoration: none;
    white-space: nowrap;
}

/* The label never breaks. A marker too long for the plate drops under the
   label and breaks anywhere, which only happens where the plate would
   otherwise overflow its column. */
.btn> :first-child {
    flex: 0 0 auto;
}

.btn .marker {
    font-weight: 400;
    min-width: 0;
    white-space: normal;
    overflow-wrap: anywhere;
}

/* Displace with position, never transform: a composited layer would drop the
   label from subpixel to grayscale antialiasing on hover. */
.btn:hover,
.btn:active {
    background: var(--ink);
    color: var(--paper);
    box-shadow: 0 0 0 var(--ink);
    top: var(--btn-drop);
    left: var(--btn-drop);
}

.btn:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 3px;
}

/* Disabled: same plate, printed rather than raised. The shadow stays so it
   still reads as a button, but in edge grey so there is nothing to press.
   An anchor with no href is a placeholder link: not focusable, not a link. */
.btn[aria-disabled="true"],
a.btn:not([href]) {
    border-color: var(--edge);
    color: var(--muted);
    box-shadow: var(--btn-drop) var(--btn-drop) 0 var(--edge);
    cursor: default;
}

.btn[aria-disabled="true"]:hover,
.btn[aria-disabled="true"]:active,
a.btn:not([href]):hover,
a.btn:not([href]):active {
    top: 0;
    left: 0;
    background: var(--paper);
    color: var(--muted);
    box-shadow: var(--btn-drop) var(--btn-drop) 0 var(--edge);
}

/* External: the plate is drawn in link colour, so a reader who knows what
   blue means in prose knows where this goes. Keyed on rel, which already
   states the fact, rather than on a second class saying the same thing. */
.btn[rel~="external"] {
    border-color: var(--accent);
    box-shadow: var(--btn-drop) var(--btn-drop) 0 var(--accent);
}

.btn[rel~="external"] .marker {
    color: var(--muted);
}

.btn[rel~="external"]:hover,
.btn[rel~="external"]:active {
    background: var(--accent);
    color: var(--paper);
    box-shadow: 0 0 0 var(--accent);
}

.btn[rel~="external"]:hover .marker,
.btn[rel~="external"]:active .marker {
    color: var(--paper);
}

/* ---- Embed ------------------------------------------------------------- */

.embed {
    display: block;
    width: 100%;
    aspect-ratio: 16 / 9;
    margin: 0 0 1.5rem;
    border: 1px solid var(--edge);
}

/* ---- Album index ------------------------------------------------------- */
/* auto-fill rather than auto-fit: with a single album, auto-fit collapses the
   empty tracks and stretches the lone card across the whole sheet. */

.album-index {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
    gap: 1.5rem;
}

.album-card {
    display: flex;
    flex-direction: column;
    border: 1px solid var(--ink);
    background: var(--paper);
    color: var(--ink);
    text-decoration: none;
}

/* A fixed ratio and a crop, so a portrait cover cannot make its row ragged. */
.album-card img {
    display: block;
    width: 100%;
    height: auto;
    aspect-ratio: 6 / 7;
    object-fit: cover;
    border-bottom: 1px solid var(--edge);
}

/* margin-top pins the label to the bottom when a long title makes one card
   taller than its neighbours. */
.card-label {
    margin-top: auto;
    padding: 0.5rem 1.25ch 0.6rem;
}

.card-title {
    display: block;
    font-weight: 700;
    letter-spacing: 0.04em;
}

.card-meta {
    display: block;
    font-size: 0.72rem;
    color: var(--muted);
    font-variant-numeric: tabular-nums;
}

/* The label inverts and the plate does not. A grid of cards displacing into
   drop shadows the way buttons do would read as clutter. */
.album-card:hover .card-label,
.album-card:focus-visible .card-label {
    background: var(--ink);
    color: var(--paper);
}

.album-card:hover .card-meta,
.album-card:focus-visible .card-meta {
    color: var(--frame);
}

.album-card:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 3px;
}

/* ---- Index entries ----------------------------------------------------- */
/* Kind left, title and note centre, year right. The uppercase left column and
   the tabular year reuse the .datasheet and .album-head treatments. Every cell is
   placed explicitly, so an entry may omit the year or the note. */

.entry {
    display: grid;
    grid-template-columns: 7ch 1fr auto;
    align-items: baseline;
    gap: 0.6rem 1.5ch;
    padding: 1.1rem 0;
    border-top: 1px solid var(--frame);
}

.entry:last-child {
    border-bottom: 1px solid var(--frame);
}

.entry-kind {
    grid-column: 1;
    grid-row: 1;
    font-weight: 700;
    font-stretch: 90%;
    letter-spacing: 0.12em;
    text-transform: uppercase;
}

.entry-year {
    grid-column: 3;
    grid-row: 1;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.entry-kind,
.entry-year {
    font-size: 0.68rem;
    color: var(--muted);
}

/* Ink, not accent. A column of blue titles would put more blue on the front
   page than the rest of the site carries. */
.entry-title {
    grid-column: 2;
    grid-row: 1;
    font-weight: 700;
    letter-spacing: 0.04em;
    color: var(--ink);
}

/* The action sits under the note rather than around the title. Every title
   then reads as a title, and an entry with no destination simply omits this
   instead of changing typeface. */
.entry>.btn {
    grid-column: 2;
    grid-row: 3;
    justify-self: start;
}

.entry-note {
    grid-column: 2 / -1;
    grid-row: 2;
    margin: 0;
    font-size: 0.92rem;
}

/* In the document, off the screen: for a heading the masthead already shows.
   display: none would also remove it from the accessibility tree. */
.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

.standfirst {
    margin-bottom: 2.25rem;
    hyphens: none;
    -webkit-hyphens: none;
}

/* ---- Resume ------------------------------------------------------------ */
/* Section heads borrow the plate-head stroke: an uppercase label over 2px of
   ink. */

.sheet h2 {
    margin: 2.75rem 0 1.25rem;
    padding-bottom: 0.3rem;
    border-bottom: 2px solid var(--ink);
    font-size: 1rem;
    font-weight: 800;
    letter-spacing: 0.1em;
    text-transform: uppercase;
}

.sheet h3 {
    margin: 2.75rem 0 1.25rem;
    border-bottom: 1px solid var(--frame);
    font-size: 1rem;
    font-weight: 800;
    letter-spacing: 0.1em;
    text-transform: uppercase;
}

/* Name left, dates right, sharing a baseline. */
.dated {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: baseline;
    gap: 0.25rem 2ch;
}

.when {
    flex: 0 0 auto;
    font-size: 0.68rem;
    color: var(--muted);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* An employer, school, or project: a section the generator builds from an H3
   and everything under it. */
.job {
    margin-bottom: 1.75rem;
}

.job h3 {
    margin: 0;
    font-size: 1rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: none;
    border-bottom: 0;
}

/* A paragraph directly under the job, with no role heading of its own, takes
   the role treatment so it does not read as a second subtitle. */
.job>p {
    margin: 0 0 0.9rem 3ch;
    font-size: 0.92rem;
}

/* .place is the block subtitle: title and location. .note is an aside about an
   anomaly in the record, and takes the same treatment. */
.job .place,
.job .note {
    margin: 0 0 0.9rem;
    font-size: 0.85rem;
    color: var(--muted);
}

/* A project inside a job: the section built from an H4. The indent puts it
   under the employer it belongs to without needing a second rule or a bullet. */
.role {
    margin: 0 0 0.9rem 3ch;
}

.role h4 {
    margin: 0;
    font-size: 0.92rem;
    font-weight: 700;
    letter-spacing: 0.04em;
}

.role p {
    margin: 0.15rem 0 0;
    font-size: 0.92rem;
}

/* Label and value rows: contact, papers, awards. max-content sizes the label
   column to the longest label in each list rather than to a guess. */
.pairs {
    display: grid;
    grid-template-columns: max-content minmax(0, 1fr);
    align-items: baseline;
    gap: 0.55rem 2ch;
    margin: 0;
}

.pairs dt {
    font-size: 0.68rem;
    font-weight: 700;
    font-stretch: 90%;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    font-variant-numeric: tabular-nums;
    color: var(--muted);
}

.pairs dd {
    margin: 0;
    min-width: 0;
    font-size: 0.92rem;
    overflow-wrap: anywhere;
}

/* A paper is three paragraphs, title, authors, venue, styled by position. Run
   together as one paragraph the title stops carrying, which is the only part
   most readers scan for. Four-line entries need more room between them than
   one-line pairs do. */
.papers {
    row-gap: 1.6rem;
}

.papers dd>p {
    margin: 0;
}

.papers dd>p:nth-child(1) {
    font-weight: 700;
    letter-spacing: 0.04em;
}

.papers dd>p:nth-child(2) {
    margin-top: 0.25rem;
}

.papers dd>p:nth-child(3) {
    color: var(--muted);
}

/* The only button in a paper entry is the DOI plate, on its own line. */
.papers .btn {
    display: flex;
    width: max-content;
    margin-top: 0.6rem;
}

/* Titles held within a single position. Tighter leading and row gap than the
   prose pairs, so the rows read as one table rather than four statements. */
.positions {
    line-height: 1.4;
    row-gap: 0.2rem;
    margin-bottom: 0.9rem;
}

/* Dates, not labels. Match .when in the block header above rather than the
   uppercase treatment .pairs gives a real label. */
.positions dt {
    font-weight: 400;
    font-stretch: 100%;
    letter-spacing: 0;
    text-transform: none;
}

/* Key over value, flowing into columns, the way a plate datasheet does. The
   only list whose rows need a box each; the generator wraps them in a div. */
.skills {
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 16rem), 1fr));
    gap: 1.3rem 2.5ch;
}

.skills>div {
    min-width: 0;
}

/* ---- Datasheet --------------------------------------------------------- */
/* Key over value, flowing horizontally. Reads as a datasheet under a wide
   image rather than a tall list beside it. */

.datasheet {
    display: flex;
    flex-wrap: wrap;
    gap: 1.4rem 4.5ch;
    margin: 0;
    flex: 1 1 auto;
    min-width: 0;
    font-size: 0.68rem;
    line-height: 1.5;
}

.datasheet div {
    min-width: 0;
}

.datasheet dt {
    font-weight: 700;
    font-stretch: 90%;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--muted);
}

.datasheet dd {
    margin: 0;
    color: var(--muted);
    font-variant-numeric: tabular-nums;
}

/* ---- Notebook ---------------------------------------------------------- */
/* An engineering note is a document with a title block, numbered figures, and
   room for code and tables. */

.note-head {
    margin: 0;
}

.sheet {
    counter-reset: figure sidenote;
}

/* ---- Sidenotes --------------------------------------------------------- */
/* Floated into the right gutter so vertical position follows document order
   with no script. clear keeps consecutive notes from stacking on each other. */

/* Written at its marker, so the margin placement is level with the sentence
   that raised it. */
.sidenote {
    float: right;
    clear: right;
    width: var(--sidenote-width);
    margin-right: calc(-1 * (var(--sidenote-width) + var(--sidenote-gap) + var(--pad-x)));
    margin-bottom: 1rem;
    /* Padding is permanent so the hover fill cannot reflow the note. */
    padding: 0.35rem 1ch;
    font-size: 0.8rem;
    line-height: 1.5;
    color: var(--muted);
}

/* The number on the note. aria-hidden on a real element suppresses its
   generated content, which no ARIA on a pseudo-element can. */
.sn-num::before {
    content: counter(sidenote);
    margin-right: 1ch;
    font-weight: 700;
    color: var(--ink);
}

/* ---- Toggled sidenote -------------------------------------------------- */
/* The other arrangement. The note stays at its marker in the source, so the
   margin placement is exact on a wide screen, and a narrow screen hides it
   behind a tap rather than letting it interrupt the paragraph unasked. */

/* Inert above the gutter breakpoint, and out of the tab order with it, since
   the note is on screen either way and the label controls nothing. */
.sn-toggle {
    display: none;
}

/* A plain superscript number above the gutter breakpoint, where the note is
   already in the margin and the marker only refers to it. A label carries no
   superscript default, so it matches <sup> by hand. */
.sn-mark {
    counter-increment: sidenote;
    position: relative;
    top: 0;
    left: 0;
    vertical-align: super;
    font-size: 0.7em;
    font-weight: 700;
    padding: 0 0.3ch;
}

.sn-mark::after {
    content: counter(sidenote);
}

/* The input is off-screen but still focusable, so the ring has to be drawn on
   the label the reader can actually see. */
.sn-toggle:focus-visible+.sn-mark {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

/* Hovering either end lights the other, so the marker does something and the
   pairing is visible without a script. :has supplies the reverse direction. */
.sn-mark:hover,
.sn-mark:has(~ .sidenote:hover) {
    background: var(--wash);
}

.sn-mark:hover~.sidenote,
.sidenote:hover {
    background: var(--wash);
    color: var(--ink);
}

.sheet>picture {
    display: block;
    margin: 0 0 1.5rem;
}

.sheet>picture img {
    display: block;
    width: 100%;
    height: auto;
    border: 1px solid var(--edge);
}

.figure {
    counter-increment: figure;
    counter-reset: subfigure;
    margin: 0 0 1.75rem;
}

/* Panels side by side, stacking on their own when the column cannot hold two.
   Equal heights so the captions line up even though the photographs do not. */
.figure-row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
    gap: 1rem 1.5ch;
}

.subfigure {
    counter-increment: subfigure;
    display: flex;
    flex-direction: column;
    margin: 0;
}

/* The panels are equal height and the photographs are not, so the slack goes
   above the shorter image. Bottom edges line up and each caption sits directly
   under its own panel. picture is display:contents, so the img is the item. */
.subfigure img {
    margin-top: auto;
}

.subfigure figcaption {
    padding-top: 0.4rem;
    font-size: 0.75rem;
    color: var(--muted);
}

.subfigure figcaption::before {
    content: "(" counter(subfigure, lower-alpha) ") ";
    font-weight: 700;
    color: var(--ink);
}

/* Remove <picture> from the box tree so block layout reaches the img. */
.figure picture {
    display: contents;
}

.figure img {
    display: block;
    width: 100%;
    height: auto;
    border: 1px solid var(--edge);
}

/* Drawings get numbered, so figures do too, and the number comes from the
   document order rather than from being typed. */
.figure>figcaption {
    margin-top: 0.5rem;
    font-size: 0.8rem;
    color: var(--muted);
}

.figure>figcaption::before {
    content: "Fig. " counter(figure) ". ";
    font-weight: 700;
    color: var(--ink);
}

/* Code scrolls rather than wrapping. A wrapped line number or a broken string
   literal is worse than a scrollbar. */
pre {
    overflow-x: auto;
    margin: 0 0 1.5rem;
    padding: 0.9rem 1.25ch;
    border: 1px solid var(--frame);
    background: var(--ground);
    font-size: 0.85rem;
    line-height: 1.5;
}

/* The whole site is monospace, so inline code needs a ground rather than a
   typeface to separate it from prose. */
/* Everything here is already monospace, so a ground alone is too quiet to
   separate an identifier from the prose around it. Weight does the rest. */
code {
    background: var(--wash);
    padding: 0 0.4ch;
    font-weight: 700;
}

pre code {
    background: none;
    padding: 0;
    font-weight: 400;
}

table {
    width: 100%;
    border-collapse: collapse;
    margin: 0 0 1.75rem;
    font-size: 0.92rem;
}

th {
    text-align: left;
    padding: 0 2ch 0.35rem 0;
    border-bottom: 2px solid var(--ink);
    font-size: 0.68rem;
    font-weight: 700;
    font-stretch: 90%;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--muted);
}

td {
    padding: 0.4rem 2ch 0.4rem 0;
    border-bottom: 1px solid var(--frame);
    vertical-align: top;
}

td:last-child,
th:last-child {
    padding-right: 0;
}

/* Column alignment from the markdown table syntax. Left is the default. */
.align-center {
    text-align: center;
}

.align-right {
    text-align: right;
}

/* Previous left, next right, so a part in the middle of a series reads as a
   spread rather than a stack. */
.series {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: 0.6rem 2ch;
    margin-top: 2.5rem;
    padding-top: 1.5rem;
    border-top: 1px solid var(--frame);
}

.series .btn:only-child {
    margin-left: auto;
}

/* ---- Diagrams ---------------------------------------------------------- */
/* Block diagrams are inline SVG so they set in the site font and follow the
   tokens. The rules live here because style-src 'self' forbids a style
   element in the page. The standalone .svg carries a hex copy for preview;
   keep the two in step. Marker references stay on the paths as attributes so
   this sheet names no ids. */

.figure svg {
    display: block;
    width: 100%;
    height: auto;
    border: 1px solid var(--edge);
    background: var(--paper);
    forced-color-adjust: none;
}

.dg-board {
    fill: var(--ground);
    stroke: var(--edge);
    stroke-width: 1.4;
}

.dg-block {
    fill: var(--paper);
    stroke: var(--ink);
    stroke-width: 1.6;
}

.dg-tube {
    fill: var(--wash);
    stroke: var(--ink);
    stroke-width: 1.6;
}

.dg-board-title {
    font-size: 15px;
    font-weight: 700;
    fill: var(--ink);
}

.dg-label {
    font-size: 13.5px;
    font-weight: 700;
    fill: var(--ink);
}

.dg-line-label {
    font-size: 11.5px;
    fill: var(--ink);
}

.dg-small,
.dg-note {
    font-size: 11.5px;
    fill: var(--muted);
}

/* Net class is carried by weight alone; the legend in the drawing is the key. */
.dg-signal,
.dg-power,
.dg-hv,
.dg-wireless {
    fill: none;
    stroke: var(--ink);
}

.dg-signal {
    stroke-width: 1.4;
}

.dg-power {
    stroke-width: 2.6;
}

.dg-hv {
    stroke-width: 4;
}

.dg-wireless {
    stroke-width: 1.4;
    stroke-dasharray: 6 5;
}

.dg-junction,
.dg-arrowhead {
    fill: var(--ink);
}

/* ---- Footer ------------------------------------------------------------ */
/* Sits below the sheet in the grid, and below the album on photography pages,
   where album.css gives it the same width. */

.sitefoot {
    grid-column: 2;
    display: grid;
    grid-template-columns: 1fr auto;
    align-items: baseline;
    gap: 0.4rem 2ch;
    margin-top: 1.25rem;
    font-size: 0.72rem;
    color: var(--muted);
}

/* Accent here would shout across a line that is deliberately quiet. Plates
   keep their own treatment. */
.sitefoot a:not(.btn) {
    color: var(--muted);
    text-decoration: underline;
    text-underline-offset: 0.2em;
    text-decoration-thickness: 1px;
}

.sitefoot a:not(.btn):hover {
    color: var(--ink);
}

/* The feed plate takes a row of its own under the copyright line. */
#feed {
    grid-column: 1 / -1;
    justify-self: start;
}

.sitefoot a:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 3px;
}

/* ---- Below the sidenote gutter ----------------------------------------- */
/* The gutter holds a sidenote only above 1314px. Below that the note falls
   back into the flow, and because it is the last child of its paragraph it
   lands after the prose instead of splitting it. */

@media (max-width: 82rem) {

    /* Closed by default. Opening it inline rather than as a block means even
       the reader who asks for it does not get the paragraph cut in half. */
    .sidenote {
        display: none;
        float: none;
        width: auto;
        margin: 0;
    }

    .sn-toggle:checked~.sidenote {
        display: inline;
        background: var(--wash);
        color: var(--ink);
    }

    /* Opened inline the note sits directly against its own marker, so its
       number would be the same digit twice in a row. */
    .sidenote .sn-num {
        display: none;
    }

    /* Off screen but focusable, so the control exists for the keyboard. */
    .sn-toggle {
        display: inline;
        position: absolute;
        width: 1px;
        height: 1px;
        opacity: 0;
        pointer-events: none;
    }

    /* Below the gutter the marker stops being a reference and becomes the only
       route to the note, so it takes the button treatment: a box with a hard
       offset behind it, which is what this site uses for anything you press.
       1px rather than the button's 2px, since it is a fifth of the height. */
    .sn-mark {
        font-size: 0.85em;
        padding: 0.1rem 0.5ch;
        border: 1px solid var(--ink);
        box-shadow: 1px 1px 0 var(--ink);
        cursor: pointer;
    }

    /* The visible marker is smaller than a finger. WCAG exempts inline targets
       from the 24px minimum, which is a reason it is allowed rather than a
       reason it is usable, so the hit area grows without moving the layout. */
    .sn-mark::before {
        content: "";
        position: absolute;
        inset: -0.7rem -0.5rem;
    }

    /* Held down while the note is open. Hover keeps the wash instead, so
       pointing at a marker and having opened one stay distinguishable. */
    .sn-toggle:checked+.sn-mark {
        box-shadow: 0 0 0 var(--ink);
        top: 1px;
        left: 1px;
    }
}

/* ---- Narrow screens ---------------------------------------------------- */
/* Below the rail plus measure, the nav moves above the sheet and runs
   horizontally. */

@media (max-width: 76rem) {
    body {
        padding: 1.5rem 0.75rem;
    }

    .shell {
        grid-template-columns: minmax(0, var(--measure));
        justify-content: center;
        gap: 1.5rem;
    }

    .masthead {
        grid-column: 1;
        justify-self: stretch;
        width: auto;
        padding-right: 0;
        position: static;
    }

    .sheet {
        --pad-x: 1.25rem;
        --pad-y: 1.25rem;
        grid-column: 1;
    }

    .sitefoot {
        grid-column: 1;
    }

    .masthead nav {
        margin-top: 1.25rem;
        flex-direction: row;
        flex-wrap: wrap;
        gap: var(--nav-gap) 2.5ch;
    }

    .masthead nav .sub {
        margin-left: 0;
    }
}

/* ---- Phones ------------------------------------------------------------ */
/* Below this the float leaves under 40ch beside the portrait, too narrow for
   hyphenated prose. */

@media (max-width: 45rem) {
    .portrait {
        float: none;
        width: 13rem;
        max-width: 55%;
        margin: 0 0 1.75rem;
    }

    .entry {
        grid-template-columns: 1fr auto;
    }

    .entry-title,
    .entry-note {
        grid-column: 1 / -1;
    }

    .entry-title {
        grid-row: 2;
    }

    .entry-note {
        grid-row: 3;
    }

    .entry>.btn {
        grid-column: 1 / -1;
        grid-row: 4;
    }

    .entry-year {
        grid-column: 2;
    }
}
