The mark is fill="currentColor" inside an anchor, so an unstyled paint renders it in the UA link blue. That is what the flash is: the document painted before the stylesheet applies, not a theme switch. Without a color-scheme declaration the browser treats the document as light, so the canvas it paints between documents, and the scrollbar, are white. Gecko paints a pending stylesheet's document far more readily than Blink does, which is why it shows there and not in Chromium. Dark on flux and bbs, which are dark only; all three branches on raayoni. The other half of this is a Caddy change in bucur: every response currently carries no Cache-Control, no ETag and no Last-Modified, so the stylesheet is refetched on every navigation and the window keeps reopening. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
194 lines
9.7 KiB
CSS
194 lines
9.7 KiB
CSS
/* randogoth BBS
|
|
*
|
|
* An ANSI bulletin board, not a DOS application. The distinction is the whole
|
|
* point: Turbo Vision is grey chrome, dialogs and a menu bar, which is what the
|
|
* previous theme gave. A BBS is 80 columns of CP437 on black, the 16 colour
|
|
* EGA palette, numbered areas with hotkeys, and a status line at the bottom.
|
|
*
|
|
* Everything is sized in `ch` so the screen stays exactly 80 columns wide at
|
|
* any font size, the way a terminal does.
|
|
*/
|
|
|
|
@font-face {
|
|
font-family: 'Classic Console';
|
|
src: url('clacon2.woff2') format('woff2');
|
|
font-display: block;
|
|
}
|
|
|
|
/* the IBM EGA/VGA text palette, unaltered */
|
|
:root {
|
|
/* A board is black by definition; tell the browser so the canvas between
|
|
documents and the scrollbar match instead of flashing light. */
|
|
color-scheme: dark;
|
|
--black: #000000; --blue: #0000aa; --green: #00aa00; --cyan: #00aaaa;
|
|
--red: #aa0000; --magenta: #aa00aa; --brown: #aa5500; --grey: #aaaaaa;
|
|
--dgrey: #555555; --lblue: #5555ff; --lgreen: #55ff55; --lcyan: #55ffff;
|
|
--lred: #ff5555; --lmagenta: #ff55ff; --yellow: #ffff55; --white: #ffffff;
|
|
}
|
|
|
|
html { background: var(--black); }
|
|
body {
|
|
margin: 0; padding: 0;
|
|
background: var(--black);
|
|
color: var(--grey);
|
|
font-family: 'Classic Console', ui-monospace, monospace;
|
|
/* clamp so 80ch always fits the viewport, phone to desktop */
|
|
font-size: clamp(7px, 2.32vw, 17px);
|
|
/* Exactly one cell per row. Each box row is its own <pre>, so any leading at
|
|
all opens a gap between them and the vertical box-drawing characters stop
|
|
meeting. Prose gets its leading back on .msgbody below. */
|
|
line-height: 1;
|
|
-webkit-font-smoothing: none;
|
|
font-smooth: never;
|
|
}
|
|
|
|
#screen { width: 80ch; margin: 0 auto; padding: 1.2em 0 2.4em; }
|
|
|
|
pre, .row { margin: 0; font: inherit; white-space: pre; }
|
|
|
|
/* ── the masthead ──────────────────────────────────────────────────────── */
|
|
/* The masthead is TheDraw's "Syndicate", an ANSI font from the board era, baked
|
|
in as static text. It uses exactly three colour levels, so the ramp is three
|
|
custom properties and recolouring costs nothing. See bbs.js: the ramp is drawn
|
|
at random once per session, which is the one piece of decoration on this site
|
|
that is also its subject. */
|
|
.logo { margin: 0 0 .2em; }
|
|
/* Both planes carry tone. ANSI paints solid areas as a space with a background,
|
|
so mapping only the foreground drops most of the mass: the first attempt at
|
|
this lost 247 of 355 inked cells and the letters came out hollow. */
|
|
.logo .f1 { color: var(--l1, #0000aa); }
|
|
.logo .f2 { color: var(--l2, #00aa00); }
|
|
.logo .f3 { color: var(--l3, #ffff55); }
|
|
.logo .b1 { background: var(--l1, #0000aa); }
|
|
.logo .b2 { background: var(--l2, #00aa00); }
|
|
.logo .b3 { background: var(--l3, #ffff55); }
|
|
.rule { color: var(--blue); }
|
|
.sysline { color: var(--dgrey); }
|
|
.sysline b { color: var(--grey); font-weight: normal; }
|
|
|
|
/* ── links behave like a lightbar: inverse on hover, as a BBS selection ─── */
|
|
a { color: var(--lcyan); text-decoration: none; }
|
|
a:hover, a:focus { background: var(--lcyan); color: var(--black); outline: none; }
|
|
/* A lightbar inverts the whole cell. Spans inside a link carry their own colour
|
|
(.area is cyan, .key is yellow) and would otherwise keep it against the cyan
|
|
highlight, which left the area names cyan on cyan and invisible. */
|
|
a:hover *, a:focus * { color: inherit; background: transparent; }
|
|
a:visited { color: var(--lcyan); }
|
|
|
|
/* ── hotkeys ───────────────────────────────────────────────────────────── */
|
|
.key { color: var(--yellow); }
|
|
.key b { color: var(--white); font-weight: normal; }
|
|
|
|
/* ── area / message listings ───────────────────────────────────────────── */
|
|
.box { color: var(--blue); }
|
|
.boxtitle { color: var(--yellow); }
|
|
.area { color: var(--lcyan); }
|
|
.desc { color: var(--grey); }
|
|
.count { color: var(--lgreen); }
|
|
.date { color: var(--dgrey); }
|
|
.sect { color: var(--brown); }
|
|
.num { color: var(--dgrey); }
|
|
.new { color: var(--lred); }
|
|
|
|
/* ── a message ─────────────────────────────────────────────────────────── */
|
|
.msghdr { color: var(--dgrey); }
|
|
.msghdr b { color: var(--lcyan); font-weight: normal; }
|
|
.msghdr .subj { color: var(--yellow); }
|
|
|
|
.msgbody { color: var(--grey); margin: 1em 0 0; line-height: 1.4; }
|
|
.msgbody p { margin: 0 0 1em; }
|
|
.msgbody h1, .msgbody h2, .msgbody h3 {
|
|
color: var(--yellow); font-size: 1em; font-weight: normal;
|
|
text-transform: uppercase; margin: 1.6em 0 .6em; }
|
|
.msgbody h1::before, .msgbody h2::before, .msgbody h3::before { content: "── "; color: var(--blue); }
|
|
.msgbody ul, .msgbody ol { margin: 0 0 1em; padding-left: 3ch; }
|
|
.msgbody li { margin: 0; }
|
|
.msgbody ul { list-style: none; }
|
|
.msgbody ul > li::before { content: "\00B7 "; color: var(--cyan); }
|
|
/* Pictures keep the scanlines the page gave up: on a board, an image was a
|
|
monitor showing it. See plugins/crtimages.py for the wrapper. */
|
|
.msgbody .crt { position: relative; display: block; margin: 1em 0; line-height: 0;
|
|
border: 1px solid var(--blue); }
|
|
/* Everything fills the column, including images smaller than it. Upscaling is
|
|
nearest-neighbour, so a 320 wide DOS screenshot comes out as bigger pixels
|
|
rather than a blurred one, which is the right answer for this material. */
|
|
.msgbody .crt img { display: block; width: 100%; height: auto; margin: 0;
|
|
border: 0; image-rendering: pixelated; }
|
|
/* The scanlines are the monitor it is being shown on. Look straight at it and
|
|
they go, which is also the only way to see the picture clean. */
|
|
.msgbody .crt::after { content: ""; position: absolute; inset: 0; pointer-events: none;
|
|
background: repeating-linear-gradient(to bottom,
|
|
rgba(0,0,0,0) 0 2px, rgba(0,0,0,.38) 2px 3px);
|
|
opacity: 1; transition: opacity .12s linear; }
|
|
.msgbody .crt:hover::after,
|
|
.msgbody .crt:focus-within::after { opacity: 0; }
|
|
@media (prefers-reduced-motion: reduce) {
|
|
.msgbody .crt::after { transition: none; }
|
|
}
|
|
/* Embeds fill the column like everything else. The ratio is injected per
|
|
element by plugins/crtimages.py from each embed's own attributes. */
|
|
.msgbody iframe { display: block; width: 100%; height: auto; margin: 1em 0;
|
|
border: 1px solid var(--blue); }
|
|
.msgbody blockquote { margin: 0 0 1em; padding-left: 2ch; color: var(--lgreen);
|
|
border-left: 1px solid var(--green); }
|
|
/* Code blocks only. A bare :not() would have been enough until a page put box
|
|
drawing in the body: the frames are <pre> too, and were being wrapped, boxed
|
|
and turned green as if they were source. */
|
|
.msgbody code { color: var(--lgreen); font: inherit; }
|
|
.msgbody pre:not([class]), .msgbody pre.highlight {
|
|
color: var(--lgreen); font: inherit; white-space: pre-wrap;
|
|
border: 1px solid var(--blue); padding: .4em 1ch; margin: 0 0 1em;
|
|
overflow-x: auto; }
|
|
.msgbody strong { color: var(--white); font-weight: normal; }
|
|
.msgbody em { color: var(--lcyan); font-style: normal; }
|
|
.msgbody hr { border: 0; border-top: 1px solid var(--blue); margin: 1.4em 0; }
|
|
.msgbody a { text-decoration: underline; }
|
|
|
|
/* the Fidonet tagline that closed every message */
|
|
.tagline { color: var(--dgrey); margin-top: 1.6em; }
|
|
.tagline .origin { color: var(--green); }
|
|
|
|
/* ── the prompt. A BBS always leaves you at one. ───────────────────────── */
|
|
.prompt { color: var(--grey); margin-top: 1.4em; }
|
|
.prompt .cursor {
|
|
background: var(--grey); color: var(--grey);
|
|
animation: blink 1.06s steps(1) infinite; }
|
|
@keyframes blink { 50% { background: transparent; } }
|
|
@media (prefers-reduced-motion: reduce) { .prompt .cursor { animation: none; } }
|
|
|
|
|
|
/* the keyword cloud is the one thing that cannot hold an 80 column frame */
|
|
.cloud { color: var(--grey); padding: .4em 2ch .6em; line-height: 1.6; }
|
|
.cloud a { margin-right: .4ch; }
|
|
.cloud .num { margin-right: 1.4ch; }
|
|
|
|
/* pages */
|
|
.bigmail { margin: 0 0 1.4em; }
|
|
.bigmail a, .mail { color: var(--yellow); }
|
|
.bigmail a:hover { background: var(--yellow); color: var(--black); }
|
|
.prompt .hint { color: var(--dgrey); }
|
|
|
|
|
|
/* guestbook */
|
|
.gb-rule { margin: 1.5em 0 0; }
|
|
/* Box drawing is on the grid wherever it appears, including inside a page body,
|
|
which otherwise hands it the 1.4 leading that prose wants. */
|
|
.msgbody .box, .msgbody .gb-rule, .msgbody .rule { line-height: 1; }
|
|
.gb-body { color: var(--grey); line-height: 1.4; padding: .5em 0 0 4ch; }
|
|
|
|
/* The form does not try to close each line with a vertical: a text input is not
|
|
a character cell and will not line up with one. Top and bottom rules only. */
|
|
.gb-form { margin: 0; padding: .8em 0 .4em; }
|
|
.gb-row { margin: 0 0 .7em; padding-left: 2ch; line-height: 1.6; }
|
|
.gb-row label { display: inline-block; width: 10ch; color: var(--dgrey); }
|
|
.gb-row label.second { width: auto; padding: 0 1ch 0 3ch; }
|
|
.gb-form input, .gb-form textarea {
|
|
font: inherit; background: #000; color: var(--white);
|
|
border: 1px solid var(--blue); outline: 0; padding: 0 1ch; }
|
|
.gb-form input { width: 22ch; }
|
|
.gb-form textarea { width: 58ch; vertical-align: top; resize: vertical; line-height: 1.4; }
|
|
.gb-form ::placeholder { color: var(--dgrey); }
|
|
.gb-form input:focus, .gb-form textarea:focus { border-color: var(--lcyan); color: var(--lcyan); }
|
|
.gb-form button { font: inherit; background: none; border: 0; padding: 0;
|
|
color: var(--yellow); cursor: pointer; }
|
|
.gb-form button:hover { background: var(--yellow); color: var(--black); }
|