@charset "UTF-8";
/* DejaVu Sans Mono cut down to ASCII and the block and box characters, with its license in the font's name table.
   Android's monospace fonts lack the block characters, and the ones it borrows are a different width. */
@font-face {
    font-family: 'ASCII Art';
    src: url(/fonts/ascii-art.woff) format('woff');
    font-display: block;
}

/* The same font's own bold and oblique, in ASCII only. Their characters are the same width, so they keep to the grid. */
@font-face {
    font-family: 'ASCII Art';
    src: url(/fonts/ascii-art-bold.woff) format('woff');
    font-weight: bold;
    font-display: block;
}

@font-face {
    font-family: 'ASCII Art';
    src: url(/fonts/ascii-art-oblique.woff) format('woff');
    font-style: italic;
    font-display: block;
}

/* A terminal window. Every border is CSS content, so the HTML stays a plain document. Sizes are in ch and lh, to keep to
   a character grid. Each string below is longer than it needs to be, and is clipped to the box it decorates. */
:root {
    --fg: #92ff00;
    --bg: #000;
    --rule: #5a9900;
    --gutter: 4ch;
    --tildes: "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~";
    --quotes: ">\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>\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";
    /* Double lines would make h2 as heavy as h1, so h1 takes them and h2 keeps a single line. */
    --double: "════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════";
    --single: "────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────";
    --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║\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║\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║\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║\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║\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║\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║\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║\A║\A║\A║\A║\A║\A║\A║\A║\A║\A║\A║\A║\A║\A║\A║\A║\A║\A║\A║\A";
}

/* Hides the borders from screen readers. In its own property because a var() in content can't fall back to an earlier
   declaration: a browser without this syntax would lose the borders entirely. */
@supports (content: "x" / "") {
    :root {
        --alt: / "";
    }
}

html {
    background: var(--bg);
    color: var(--fg);
    /* Whole-pixel rows just shorter than the characters, so the border characters join up. */
    font: 16px/18px 'ASCII Art', monospace;
    font-synthesis: none;
    /* Otherwise Chrome can round a character's width to whole pixels, which breaks the grid. */
    text-rendering: geometricPrecision;
    -webkit-text-size-adjust: 100%;
    text-size-adjust: 100%;
}

/* The frame. header and main stay unpositioned, so their pseudo-elements are placed against the body. */
body {
    position: relative;
    box-sizing: border-box;
    width: calc(100% - 2ch);
    max-width: 100ch;
    min-height: calc(100dvh - 2lh);
    min-height: round(down, 100dvh - 2lh, 1lh);
    margin: 1lh auto;
    padding: 2lh 3ch;
}

.framed::before,
.framed::after {
    position: absolute;
    left: 0;
    right: 0;
    height: 1lh;
    overflow: hidden;
    white-space: nowrap;
    color: var(--rule);
}

.framed::before {
    content: "╔" var(--double) var(--alt,);
    top: 0;
}

.framed::after {
    content: "╚" var(--double) var(--alt,);
    bottom: 0;
}

.framed main::before,
.framed main::after {
    content: var(--bars) var(--alt,);
    position: absolute;
    top: 1lh;
    bottom: 1lh;
    width: 1ch;
    overflow: hidden;
    white-space: pre;
    color: var(--rule);
}

.framed main::before {
    left: 0;
}

.framed main::after {
    right: 0;
}

header::before,
header::after {
    position: absolute;
    /* Over the end of body's rules, which come later in the page. */
    z-index: 1;
    right: 0;
    width: 1ch;
    background: var(--bg);
    color: var(--rule);
}

header::before {
    content: "╗" var(--alt,);
    top: 0;
}

header::after {
    content: "╝" var(--alt,);
    bottom: 0;
}

/* Plain, unlike other links, because it sits on the frame's top rule. */
header a {
    position: absolute;
    top: 0;
    left: 2ch;
    padding: 0 1ch;
    background: var(--bg);
    color: var(--fg);
}

header a::before,
header a::after {
    content: none;
}

/* The same rule, at its other end. A normal link again, on a background that cuts through the rule. */
.account {
    position: absolute;
    z-index: 2;
    top: 0;
    right: 2ch;
    padding: 0 1ch;
    background: var(--bg);
}

header .account a {
    position: static;
    padding: 0;
    background: var(--fg);
    color: var(--bg);
}

header .account a::before {
    content: "[" var(--alt,);
}

header .account a::after {
    content: "]" var(--alt,);
}

header .account a:focus-visible {
    background: var(--bg);
    color: var(--fg);
}

/* Phones keep the frame, but at the screen's edges, to save columns. */
@media (max-width: 40rem) {
    :root {
        --gutter: 1ch;
    }

    body {
        width: 100%;
        min-height: 100dvh;
        min-height: round(down, 100dvh, 1lh);
        margin: 0;
        padding: 2lh 1ch;
    }

    .framed {
        min-height: calc(100dvh - 1lh);
        min-height: round(down, 100dvh - 1lh, 1lh);
        margin-block: .5lh;
        padding-inline: 2ch;
    }
}

h1,
h2,
h3,
p,
ul,
ol,
pre,
blockquote,
table,
form,
hr {
    margin: 0 0 1lh;
}

h1,
h2,
h3 {
    position: relative;
    width: fit-content;
    max-width: 100%;
    margin-bottom: 2lh;
    font: inherit;
}

h1 {
    text-transform: uppercase;
}

h1::after,
h2::after,
h3::after {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    height: 1lh;
    overflow: hidden;
    white-space: nowrap;
    color: var(--rule);
}

h1::after {
    content: var(--double) var(--alt,);
}

h2::after {
    content: var(--single) var(--alt,);
}

h3::after {
    content: var(--tildes) var(--alt,);
}

hr {
    height: 1lh;
    overflow: hidden;
    border: 0;
    color: var(--rule);
}

hr::before {
    content: var(--double) var(--alt,);
    display: block;
    white-space: nowrap;
}

/* Links and buttons are inverted, so they stand out from the text around them, and go plain to show hover and focus. */
a {
    background: var(--fg);
    color: var(--bg);
    text-decoration: none;
}

a:focus-visible,
button:focus-visible {
    outline: 1px dotted var(--fg);
    background: var(--bg);
    color: var(--fg);
}

/* Not on touchscreens, where hover stays on after a tap. */
@media (hover: hover) {
    a:hover,
    button:hover,
    .file:hover span {
        background: var(--bg);
        color: var(--fg);
    }

    input[type=checkbox]:hover {
        background: var(--fg);
        color: var(--bg);
    }

    header a:hover {
        background: var(--fg);
        color: var(--bg);
    }

    header .account a:hover {
        background: var(--bg);
        color: var(--fg);
    }
}

a::before {
    content: "[" var(--alt,);
}

a::after {
    content: "]" var(--alt,);
}

code {
    font: inherit;
}

code::before,
code::after {
    content: "`" var(--alt,);
}

ul,
ol {
    padding: 0;
    list-style: none;
}

ol {
    counter-reset: item;
}

li {
    padding-left: 2ch;
    text-indent: -2ch;
}

ol > li {
    padding-left: 3ch;
    text-indent: -3ch;
    counter-increment: item;
}

ul > li::before {
    content: "- " var(--alt,);
}

ol > li::before {
    content: counter(item) ". " var(--alt,);
}

li > ul,
li > ol {
    margin-bottom: 0;
    text-indent: 0;
}

blockquote {
    position: relative;
    margin-inline: 0;
    padding-left: 2ch;
}

blockquote::before {
    content: var(--quotes) var(--alt,);
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    width: 1ch;
    overflow: hidden;
    white-space: pre;
    color: var(--rule);
}

blockquote > :last-child {
    margin-bottom: 0;
}

pre {
    position: relative;
    overflow-x: auto;
    padding-block: 1lh;
    font: inherit;
}

pre::before,
pre::after {
    content: var(--double) var(--alt,);
    position: absolute;
    left: 0;
    right: 0;
    height: 1lh;
    overflow: hidden;
    white-space: nowrap;
    color: var(--rule);
}

pre::before {
    top: 0;
}

pre::after {
    bottom: 0;
}

pre code::before,
pre code::after {
    content: none;
}

/* Each cell draws its own edges from its left side, so the borders line up even if a column isn't a whole number of
   characters wide. A table needs a one-row thead, and th doesn't wrap, because the right edge counts on that row being
   one line. */
table {
    position: relative;
    max-width: 100%;
    padding: 0 1ch 1lh 0;
    border-collapse: separate;
    border-spacing: 0;
}

table::before,
table::after,
th::before,
td::before,
tbody tr:last-child td::after {
    position: absolute;
    overflow: hidden;
    white-space: pre;
    color: var(--rule);
    pointer-events: none;
}

table::before {
    content: "╗\A║\A╣\A" var(--bars) var(--alt,);
    top: 0;
    right: 0;
    bottom: 1lh;
    width: 1ch;
}

table::after {
    content: "╝" var(--alt,);
    right: 0;
    bottom: 0;
}

th,
td {
    position: relative;
    padding: 0 1ch 0 2ch;
    font: inherit;
    text-align: left;
    vertical-align: top;
    overflow-wrap: break-word;
}

/* Lets the table fit a narrow screen by squeezing its last column, without splitting a short word in the others. */
td:last-child {
    overflow-wrap: anywhere;
}

th {
    padding-block: 1lh;
    white-space: nowrap;
}

th::before {
    content: "╦" var(--double) "\A║\A╬" var(--double) var(--alt,);
    inset: 0;
}

th:first-child::before {
    content: "╔" var(--double) "\A║\A╠" var(--double) var(--alt,);
}

td::before {
    content: var(--bars) var(--alt,);
    top: 0;
    bottom: 0;
    left: 0;
    width: 1ch;
}

tbody tr:last-child td::after {
    content: "╩" var(--double) var(--alt,);
    top: 100%;
    left: 0;
    right: 0;
    height: 1lh;
}

tbody tr:last-child td:first-child::after {
    content: "╚" var(--double) var(--alt,);
}

label {
    display: block;
    margin-bottom: 1lh;
}

input {
    box-sizing: border-box;
    width: min(30ch, 100%);
    padding: 0;
    border: 0;
    /* An input can't have pseudo-elements, so this is the one line that isn't made of characters. */
    border-bottom: 1px dotted var(--rule);
    outline: 0;
    background: none;
    color: inherit;
    font: inherit;
}

input:focus {
    border-bottom-color: var(--fg);
}

button {
    padding: 0;
    border: 0;
    background: var(--fg);
    color: var(--bg);
    font: inherit;
    cursor: pointer;
}

button::before {
    content: "[ " var(--alt,);
}

button::after {
    content: " ]" var(--alt,);
}

.logo {
    display: flex;
    justify-content: center;
    margin-top: 3lh;
}

/* Drawn as text, like the frame. Unlike a text input, a checkbox without its appearance can have pseudo-elements. */
input[type=checkbox] {
    appearance: none;
    width: 3ch;
    height: 1lh;
    margin: 0;
    border: 0;
    vertical-align: top;
    cursor: pointer;
}

input[type=checkbox]::before {
    content: "[ ]" var(--alt,);
}

input[type=checkbox]:checked::before {
    content: "[x]" var(--alt,);
}

input[type=checkbox]:focus-visible {
    outline: 1px dotted var(--fg);
}

/* The browser's own button can't take the brackets, so a span in the label stands in for it. A click on the label
   opens the file picker, and the input still shows the file's name. */
input[type=file] {
    border: 0;
    cursor: pointer;
}

input[type=file]::file-selector-button {
    display: none;
}

.file span {
    background: var(--fg);
    color: var(--bg);
    cursor: pointer;
}

.file span::before {
    content: "[ " var(--alt,);
}

.file span::after {
    content: " ]" var(--alt,);
}

.file:has(input:focus-visible) span {
    outline: 1px dotted var(--fg);
    background: var(--bg);
    color: var(--fg);
}

nav {
    margin-bottom: 2lh;
}

/* The widest table: a username can be one long word, and four columns don't fit a phone. */
.users td:first-child {
    overflow-wrap: anywhere;
}

.users td:not(:first-child) {
    overflow-wrap: break-word;
}

.users a {
    white-space: nowrap;
}

@media (max-width: 40rem) {
    .users .email {
        display: none;
    }
}

@media (max-width: 22rem) {
    .users td:not(:first-child) {
        overflow-wrap: anywhere;
    }
}

/* Only the name wraps: it can be one long word, and five columns don't fit a phone. */
.torrents td:first-child {
    overflow-wrap: anywhere;
}

.torrents td:not(:first-child) {
    white-space: nowrap;
}

/* Too many columns for a phone, and none can go: a log needs all of them. So the table scrolls inside the frame. */
.logs {
    overflow-x: auto;
}

.logs table {
    max-width: none;
}

.logs td {
    white-space: nowrap;
}

/* Only names and addresses wrap: they can be one long word. An IPv4 address still fits on one line. */
.logs .wrap,
.logs td:last-child {
    min-width: 16ch;
    overflow-wrap: anywhere;
    white-space: normal;
}

/* One box, not one per line: lines are shorter than the characters, so each line's background would cover the
   underscores on the line above. */
.torrents a,
.logs a {
    display: inline-block;
    vertical-align: top;
}

@media (max-width: 40rem) {
    .torrents .uploader,
    .torrents .size,
    .torrents .completed {
        display: none;
    }
}

@media (max-width: 30rem) {
    .torrents .leechers {
        display: none;
    }
}

/* Torrent and file names can be one long word, which would otherwise run out of the frame. */
main {
    overflow-wrap: anywhere;
}

pre[style*="--cols"] {
    /* Fits the widest line on a narrow screen: a character is just under 0.603em. */
    font-size: min(13px, (100vw - 2 * var(--gutter)) / (var(--cols) * 0.603));
    /* The font's own line height, at which the block characters join up. */
    line-height: normal;
    overflow-x: visible;
    margin: 0;
    padding: 0;
}

pre[style*="--cols"]::before,
pre[style*="--cols"]::after {
    content: none;
}
