/* hnet.sh stylesheet. Order: tokens, base, page layout, top bar, sidebar, table of contents, text,
 * code blocks, notices, tables, section listings, and last the shared look of every ASCII line. */

/* Tokens */

:root {
    --bg: #000;
    --fg: #ccc;
    --strong: #eee;
    --dim: #777;
    /* Konsole BackgroundIntense */
    --code-bg: #151515;
    --blue: #28a1c5;
    --red: #b52c27;
    --orange: #df8a13;
    /* The logo's white, a touch off pure white like in the original artwork. */
    --white: #fefefc;
    /* Code blocks (from the design pass for highlighting/hnet.json): line number of a highlighted line,
     * and the selection background. */
    --hl-number: #9a9a9a;
    --selection: #222c38;
    --mono: ui-monospace, "DejaVu Sans Mono", "Liberation Mono", Menlo, Consolas, monospace;
    --sans: system-ui, -apple-system, "Segoe UI", "Noto Sans", "DejaVu Sans", sans-serif;
    /* Side margin of the page; shrinks with the window in the wide layout. */
    --side: clamp(1rem, 2vw, 2rem);
    /* Height of the fixed top bar band in the wide layout; everything sticky starts below it. */
    --top: 4.5rem;
    /* Long enough for any width; ASCII rules are clipped to their box. */
    --dashes: "------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------";
}

/* Base */

*, *::before, *::after {
    box-sizing: border-box;
}

html {
    font-family: var(--sans);
    font-size: 100%;
    line-height: 1.6;
    color: var(--fg);
    background: var(--bg);
    -webkit-text-size-adjust: 100%;
    text-size-adjust: 100%;
}

body {
    margin: 0;
    padding: 2rem 1.25rem;
}

/* Prose is proportional; everything that frames it stays monospace. */
.topbar,
.sidebar,
h1, h2, h3, h4,
code {
    font-family: var(--mono);
}

/* Page layout: on narrow screens everything is one column, menu above the text; from 64em on there are
 * three columns, menu | text | contents. The menu shrinks with the window down to the ~11rem the logo
 * needs. The text column is filled first, up to its 42rem reading width (full at 1280px, ~35rem at
 * 1024px); the contents column then takes everything left up to the right margin, never less than
 * 12rem, so titles only get an ellipsis when space really runs out. Pages without a table of contents
 * simply leave the third column empty.
 * Breakpoints use the range syntax, (width < 64em) and (width >= 64em): unlike max-width: 63.99em they
 * leave no gap between the two layouts at fractional widths (zoom, high-DPI scaling). */

.content {
    max-width: 42rem;
}

@media (width >= 64em) {
    html {
        scroll-padding-top: var(--top);
    }
    body {
        display: grid;
        grid-template-columns: clamp(11rem, 15vw, 18rem) minmax(0, 42rem) minmax(12rem, 1fr);
        column-gap: clamp(1.5rem, 2.5vw, 4rem);
        padding: var(--top) var(--side) 3rem;
    }
    .sidebar,
    .toc {
        position: sticky;
        top: var(--top);
        align-self: start;
    }
}

/* Top bar: the site description on the left, links to other HNet services on the right, an ASCII rule
 * below. On narrow screens it sits above the logo and scrolls with the page. On wide screens it stays in
 * view like the sidebar: fixed in the body's top padding, on a band of page background that ends with a
 * rule across the whole page between the side margins; the page scrolls underneath the band. */

.topbar {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: baseline;
    column-gap: 3ch;
    margin-bottom: 1.5rem;
    color: var(--dim);
}
/* Narrow screens: the rule is a full-width flex item that always wraps onto its own line. */
.topbar::after {
    content: var(--dashes);
    flex-basis: 100%;
    margin-top: .25rem;
}

/* The description comes from attributes and is drawn by CSS on wide screens only, so phones and text
 * browsers (which ignore CSS) don't show it at all. */
.tagline {
    display: none;
}

.services {
    margin-left: auto;
    text-align: right;
}
.services .service {
    display: inline-block;
    white-space: nowrap;
}
.services .name {
    color: var(--strong);
}
/* Separators exist for text browsers, which ignore CSS; graphical browsers space services by margin. */
.services .sep {
    display: none;
}
.services .sep + .service {
    margin-left: 3ch;
}
.services a {
    color: var(--blue);
    text-decoration: none;
}
.services a:hover,
.services a:focus {
    text-decoration: underline;
}

@media (width >= 64em) {
    .topbar {
        position: fixed;
        z-index: 11;
        top: .9rem;
        left: var(--side);
        right: var(--side);
        margin: 0;
    }
    .topbar::after {
        content: none;
    }
    body::before {
        content: var(--dashes);
        position: fixed;
        z-index: 10;
        top: 0;
        left: 0;
        right: 0;
        /* A border, not padding: overflow clips at the padding edge, so the dashes stop at the side margins. */
        border: solid var(--bg);
        border-width: 2.5rem var(--side) 0;
        background: var(--bg);
    }
    /* "HNet - HKr's space": the title in the colour of the service names, the description dimmed. */
    .tagline {
        display: block;
    }
    .tagline::before {
        content: attr(data-title);
        color: var(--strong);
    }
    .tagline::after {
        content: " - " attr(data-text);
    }
}

/* Sidebar */

.logo {
    display: inline-block;
    text-decoration: none;
}
/* Undo the code block look: the logo is a <pre>, but not code. */
.logo pre {
    margin: 0 0 1.5rem;
    padding: 0;
    background: none;
    overflow: visible;
    font-size: 1.6rem;
    font-weight: bold;
    line-height: 1.15;
}
.logo .b { color: var(--blue); }
.logo .r { color: var(--red); }
.logo .w { color: var(--white); }

/* The menu is a list so text browsers put each item on its own line. */
.sidebar nav ul {
    list-style: none;
    margin: 0;
    padding: 0;
}
.sidebar nav li {
    margin: 0;
}
.sidebar nav a {
    display: block;
    color: var(--strong);
    text-decoration: none;
    white-space: pre;
}
.sidebar nav a::before {
    content: "  ";
}
.sidebar nav a.active::before {
    content: "> ";
    color: var(--blue);
}
.sidebar nav a:hover,
.sidebar nav a:focus {
    text-decoration: underline;
}

.sidebar footer {
    margin-top: 1.5rem;
    color: var(--dim);
    font-size: .9rem;
}

/* Narrow screens: a rule between the menu and the text. */
@media (width < 64em) {
    .sidebar {
        margin-bottom: 2.5rem;
    }
    .sidebar::after {
        content: var(--dashes);
        display: block;
        margin-top: 1.5rem;
    }
}

/* Table of contents of an article, drawn like the output of `tree`, in the third column of the wide layout.
 * It scrolls on its own when it's taller than the window. Hidden on phones. Everything visible in it is
 * generated from data attributes (see templates/page.html), so text browsers show nothing. */

.toc {
    display: none;
}
@media (width >= 64em) {
    .toc {
        display: block;
        max-height: calc(100vh - var(--top) - 1.5rem);
        overflow-y: auto;
        font-family: var(--mono);
        font-size: .9rem;
        line-height: 1.4;
    }
    .toc::before {
        content: attr(data-title);
        display: block;
        margin-bottom: .5rem;
        color: var(--strong);
        font-weight: bold;
    }
    .toc-row {
        display: flex;
    }
    /* Tree prefix; the "/ """ form keeps screen readers from reading out the pipes and dashes where supported. */
    .toc-row::before {
        content: attr(data-tree);
        content: attr(data-tree) / "";
        flex: none;
        white-space: pre;
        color: var(--dim);
    }
    /* One line per entry; titles that don't fit end in an ellipsis (the full title is in the tooltip).
     * Chapters in the bright colour of headings in the text, subsections dimmed like the tree lines. */
    .toc-row a {
        min-width: 0;
        overflow: hidden;
        white-space: nowrap;
        text-overflow: ellipsis;
        color: var(--dim);
        text-decoration: none;
    }
    .toc-row a::before {
        content: attr(data-title);
    }
    .toc .chapter a {
        color: var(--strong);
    }
    .toc-row a:hover,
    .toc-row a:focus {
        color: var(--blue);
        text-decoration: underline;
    }
}

/* Text */

h1, h2, h3, h4 {
    color: var(--strong);
    line-height: 1.3;
    margin: 2rem 0 1rem;
}
h1 { font-size: 1.5rem; margin-top: 0; }
h2 { font-size: 1.25rem; }
h3, h4 { font-size: 1rem; }

strong { color: var(--strong); }

a {
    color: var(--blue);
}
a:hover,
a:focus {
    color: var(--strong);
}

code {
    font-size: .9em;
    color: var(--orange);
}

blockquote {
    margin: 1rem 0 1rem 2ch;
    color: var(--dim);
}

ol, ul {
    padding-left: 2.5em;
}
li + li {
    margin-top: .4rem;
}

/* Code blocks: framed by text rules, labelled with the block's name, on a shaded background.
 * +-- config ----------
 * ...
 * +--------------------
 * Colours of the syntax come from highlighting/hnet.json, through the giallo.css Zola generates from it
 * (including the highlighted line background and line number colour). */

pre {
    margin: 1.25rem 0;
    padding: .5rem .75rem;
    background: var(--code-bg);
    overflow-x: auto;
    line-height: 1.4;
}
pre code {
    display: block;
    color: var(--fg);
    font-size: .9rem;
}
pre code::before,
pre code::after {
    display: block;
}
pre code::before {
    content: "+-- " attr(data-name) " " var(--dashes);
}
pre code::after {
    content: "+" var(--dashes);
}

/* One span per line, so lines can be highlighted and numbered. */
pre.giallo .giallo-l {
    display: inline-block;
    min-height: 1lh;
    min-width: 100%;
    position: relative;
    vertical-align: top;
}
/* The 2ch gutter for the ">" marker only where a block has highlighted lines (hl_lines),
 * so ordinary blocks stay aligned with their ASCII frame. */
pre.giallo:has(.z-hl) .giallo-l {
    padding-left: 2ch;
}
pre.giallo .giallo-l.z-hl::after {
    content: ">";
    position: absolute;
    top: 0;
    left: 0;
    color: var(--orange);
}
/* Line numbers (linenos): not selectable, so copying a block never picks them up. */
pre.giallo .giallo-ln {
    display: inline-block;
    min-width: 3ch;
    margin-right: 2ch;
    text-align: right;
    -webkit-user-select: none;
    user-select: none;
}
pre.giallo .giallo-l.z-hl > .giallo-ln {
    color: var(--hl-number);
}
pre.giallo ::selection {
    background-color: var(--selection);
}

/* Shell prompt for command blocks; added by CSS so it isn't copied with the command.
 * Blank lines separate groups of commands and get no prompt. */
code[data-name="command"] .giallo-l::before {
    content: "$ ";
    color: var(--dim);
}
code[data-name="command"] .giallo-l:empty::before {
    content: none;
}

/* Notices: framed like code blocks, in the notice's colour. */

.notice {
    margin: 1.5rem 0;
}
.notice p {
    margin: .5rem 0;
}
.notice.info { color: var(--blue); }
.notice.warn { color: var(--orange); }
.notice a { color: inherit; }
.notice::before,
.notice::after {
    display: block;
}
.notice.info::before { content: "+-- [i] " var(--dashes); }
.notice.warn::before { content: "+-- [!] " var(--dashes); }
.notice::after { content: "+" var(--dashes); }

/* Tables drawn as a full ASCII grid:
 * +----------+----------+
 * | Header   | Header   |
 * +----------+----------+
 * | cell     | cell     |
 * +----------+----------+
 * Wide tables scroll sideways, so the table is a scroll container, and anything positioned against it
 * only spans its visible part. The whole grid is therefore drawn by rows and cells, which span the full
 * content and scroll with it (table sections are avoided too: Safari won't position against tbody):
 * - every cell draws its own stretch of the rule above it, "+-----", and the "|" column on its left;
 * - cells of the last row also draw their stretch of the closing rule below them;
 * - every row draws the right edge, and the last row the bottom right corner.
 * Each column's stretches start at the same place in every row, so the dashes line up throughout.
 * Rows sit on a fixed line grid (no other vertical padding) so the bars join up between rows. */

table {
    --bars: "|\A|\A|\A|\A|\A|\A|\A|\A|\A|\A|\A|\A|\A|\A|\A|\A|\A|\A|\A|\A|\A|\A|\A|\A|\A|\A|\A|\A|\A|\A|\A|\A|\A|\A|\A|\A|\A|\A|\A|\A|\A|\A|\A|\A|\A|\A|\A|\A|\A|\A|\A|\A|\A|\A|\A|\A|\A|\A|\A|\A";
    --rule: 1.3em;
    --cell-bg: var(--bg);
    display: block;
    width: max-content;
    max-width: 100%;
    overflow-x: auto;
    border-collapse: collapse;
    margin: 1.5rem 0;
    padding-bottom: var(--rule);
    font-family: var(--mono);
    font-size: .9rem;
    line-height: 1.3;
}
tr {
    position: relative;
}
th, td {
    position: relative;
    padding: var(--rule) 1ch 0 2ch;
    text-align: left;
    vertical-align: top;
}
th:last-child,
td:last-child {
    padding-right: 2ch;
}
th {
    color: var(--strong);
    background: var(--code-bg);
}
/* The rule between header and body belongs to the first body row; shade it like the header. */
thead tr,
tbody tr:first-child {
    --cell-bg: var(--code-bg);
}
tbody tr:first-child > td {
    background: linear-gradient(var(--code-bg), var(--code-bg)) top / 100% var(--rule) no-repeat;
}

tr::before,
tr::after,
th::before,
td::before,
tbody tr:last-child > td::after {
    position: absolute;
    overflow: hidden;
}
/* Each cell: its stretch of the rule above ("+" at the left joint, then dashes) and its left "|" column. */
th::before,
td::before {
    content: "+" var(--dashes) "\A" var(--bars);
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    white-space: pre;
}
/* Last row: each cell's stretch of the closing rule, one line below the cell. */
tbody tr:last-child > td::after {
    content: "+" var(--dashes);
    left: 0;
    right: 0;
    bottom: calc(-1 * var(--rule));
    white-space: nowrap;
}
/* Right edge of every row: "+" at the top joint, hiding the last dash under it, "|" below. */
tr::after {
    content: "+\A" var(--bars);
    top: 0;
    bottom: 0;
    right: 0;
    width: 1ch;
    white-space: pre;
    background: linear-gradient(var(--cell-bg), var(--cell-bg)) top / 100% var(--rule) no-repeat;
}
/* Last row: the right edge runs down to the closing rule, where the row's ::before makes the corner. */
tbody tr:last-child::after {
    bottom: calc(-1 * var(--rule));
}
/* Browsers turn a row's ::before into an extra leading table cell, even when it's absolutely positioned
 * (empty, so zero width). Every row must have one, or the row that does shifts one column to the right. */
tr::before {
    content: "";
}
tbody tr:last-child::before {
    content: "+";
    z-index: 1;
    right: 0;
    bottom: calc(-1 * var(--rule));
    width: 1ch;
    background: var(--bg);
}

/* Section listings */

.posts li p {
    margin: .25rem 0 0;
    color: var(--dim);
}

/* Every ASCII line on the page shares one look: separators, code block and notice frames, the table grid.
 * Horizontal rules are a long run of dashes clipped to their box. */

body::before,
.topbar::after,
.sidebar::after,
pre code::before,
pre code::after,
.notice::before,
.notice::after,
tr::before,
tr::after,
th::before,
td::before,
td::after {
    font-family: var(--mono);
    font-size: .9rem;
    font-weight: normal;
    color: var(--dim);
}
body::before,
.topbar::after,
.sidebar::after,
pre code::before,
pre code::after,
.notice::before,
.notice::after {
    overflow: hidden;
    white-space: nowrap;
}

/* Exception: notice frames keep the notice's colour, so the kind of notice reads from the frame too. */
.notice::before,
.notice::after {
    color: inherit;
}
