/* An 80-column VGA text screen, on the web.
 *
 * The font is the IBM VGA 8x16 character-generator ROM compiled to WOFF2, so
 * one character occupies exactly 9x16 pixels at 16px. Every measurement here
 * is therefore in whole cells: `ch` is one column, `1em` is one row. Keep it
 * that way -- the grid is the design, and a stray half-pixel shows. */

@font-face {
  font-family: "IBM VGA";
  src: url("/fonts/ibm-vga-8x16.woff2") format("woff2");
  font-display: block; /* the layout is meaningless in a fallback face */
}

:root {
  /* The four EGA entries the `word` app uses, plus two for chrome. */
  --screen: #0000aa;   /* 1  blue */
  --text: #aaaaaa;     /* 7  light grey */
  --bright: #ffffff;   /* 15 white */
  --dim: #5555ff;      /* 9  bright blue, for rules on the blue field */
  --bar: #aaaaaa;      /* the menu bar is light grey with black text */
  --bar-ink: #000000;

  --cols: 80;          /* screen width  */
  --measure: 65;       /* text width, as in the app: a 6.5in line at 10cpi */

  /* 80 columns is 45em wide, since a cell is 9/16 em. Fill the viewport up
   * to a comfortable reading size, then stop. */
  --size: clamp(9px, calc((100vw - 1.5rem) / 45), 21px);
}

* { box-sizing: border-box; }

html { background: #000; }

body {
  margin: 0;
  background: var(--screen);
  color: var(--text);
  font: var(--size) / 1 "IBM VGA", ui-monospace, "Courier New", monospace;
  font-variant-ligatures: none;
  /* Cells are 9px wide at 16px; never let the browser round them apart. */
  -webkit-font-smoothing: none;
  font-smooth: never;
  text-rendering: optimizeSpeed;
  padding-block: 1em calc(2em + env(safe-area-inset-bottom));
  min-height: 100dvh;
}

/* Anything that must not break the grid. */
b, strong { font-weight: normal; }

/* ---------------------------------------------------------------- palette */

.i0  { color: #000000 } .i3  { color: #00aaaa } .i6  { color: #aa5500 }
.i7  { color: #aaaaaa } .i8  { color: #555555 } .i11 { color: #55ffff }
.i15 { color: #ffffff }
.k6  { background: #aa5500 } .k7 { background: #aaaaaa }

/* --------------------------------------------------------------- menu bar */

.menubar {
  position: sticky;
  top: 0;
  z-index: 3;
  display: flex;
  background: var(--bar);
  color: var(--bar-ink);
  height: 1em;
  margin: -1em 0 1em;       /* sit flush against the top of the screen */
  padding: 0;               /* a DOS menu bar starts in column one */
}

.menubar > li { position: relative; list-style: none; }

.menubar button {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  border-radius: 0;
  padding: 0 1ch;
  height: 1em;
  line-height: 1em;
  cursor: pointer;
}

/* DOS highlighted an item by swapping the cell colours. So do we. */
.menubar button:hover,
.menubar button:focus-visible,
.menubar button[aria-expanded="true"] {
  background: var(--bar-ink);
  color: var(--bright);
  outline: none;
}

/* The mnemonic letter, underlined, as every DOS menu did. */
.menubar u, .menu u { text-decoration-thickness: 1px; text-underline-offset: 1px; }

/* --------------------------------------------------------------- dropdown */

.menu {
  position: absolute;
  top: 1em;
  left: 0;
  margin: 0;
  padding: 0;
  min-width: 24ch;
  background: var(--bar);
  color: var(--bar-ink);
  /* A DOS dropdown cast a hard black shadow one cell down and right. */
  box-shadow: 0.5ch 0.5em 0 rgb(0 0 0 / 0.5);
  border: 1px solid var(--bar-ink);
  z-index: 4;
}

.menu[hidden] { display: none }
.menu li { list-style: none }

.menu a, .menu button {
  display: flex;
  justify-content: space-between;
  gap: 3ch;
  width: 100%;
  padding: 0 1ch;
  height: 1em;
  line-height: 1em;
  font: inherit;
  color: inherit;
  text-decoration: none;
  background: none;
  border: 0;
  cursor: pointer;
  text-align: left;
}

.menu a:hover, .menu a:focus-visible,
.menu button:hover, .menu button:focus-visible {
  background: var(--bar-ink);
  color: var(--bright);
  outline: none;
}

.menu .key { opacity: 0.65 }
.menu [aria-disabled="true"] { color: #777; pointer-events: none }
.menu .sep { height: 1em; display: flex; align-items: center; overflow: hidden }
.menu .sep::after {
  content: "";
  flex: 1;
  border-top: 1px solid var(--bar-ink);
  opacity: 0.4;
}
.menu [aria-checked="true"] .tick::before { content: "√" }

/* --------------------------------------------------------------- document */

.screen {
  width: calc(var(--cols) * 1ch);
  max-width: 100%;
  margin-inline: auto;
}

.doc {
  width: calc(var(--measure) * 1ch);
  max-width: 100%;
  margin-inline: auto;
}

.doc p, .doc li, .doc pre { margin: 0 }
.doc p + p { margin-top: 1em }

/* WordPerfect opened a paragraph with a tab, and so does the source text. */
.doc p { text-indent: 8ch }
.doc p.flush { text-indent: 0 }

h1, h2 {
  font: inherit;
  margin: 0 0 1em;
  text-transform: uppercase;
}

/* A DOS screen titled a pane by swapping the cell colours across the row. */
h1 {
  background: var(--bright);
  color: var(--screen);
  padding: 0 1ch;
  text-shadow: none;
}

h2 {
  color: var(--bright);
  margin-top: 2em;
}
.doc > h1:first-child, .doc > h2:first-child { margin-top: 0 }

a {
  color: var(--bright);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
}
/* Inverse video is how a DOS screen said "this one". */
a:hover, a:focus-visible {
  background: var(--bright);
  color: var(--screen);
  outline: none;
  text-decoration: none;
}

hr {
  border: 0;
  height: 1em;
  margin: 1em 0;
  color: var(--dim);
  overflow: hidden;
}
hr::before {
  content: "────────────────────────────────────────────────────────────────────────";
  letter-spacing: 0;
}

/* ------------------------------------------------------------------ lists */

.entries { padding: 0; margin: 0 }
.entries li { list-style: none; margin-bottom: 1em }
.entries .title { display: block }
.entries .meta { display: block; color: var(--text) }
.entries .meta b { color: var(--dim) }

/* ----------------------------------------------------------------- avatar */

.avatar {
  margin: 0 0 1em;
  white-space: pre;
  /* Pinned to 16px, which is the one size where a cell is exactly 9x16
   * whole pixels. At the body's fluid size the cell is fractional and the
   * seams between colour runs land mid-pixel, which draws a grid of hairline
   * gaps straight through the face. This is also, pleasingly, 1:1 with the
   * framebuffer the app itself blits. */
  font-size: 16px;
  line-height: 16px;
  width: 24ch;   /* 24 cells of this font-size: 216px */
}
.card { display: flex; gap: 3ch; align-items: flex-start; flex-wrap: wrap }
.card .bio { flex: 1 1 34ch; min-width: 34ch }

/* ------------------------------------------------------------ status line */

.status {
  position: fixed;
  inset-inline: 0;
  bottom: 0;
  z-index: 3;
  background: var(--screen);
  color: var(--bright);
  height: calc(1em + env(safe-area-inset-bottom));
  padding-bottom: env(safe-area-inset-bottom);
  border-top: 1px solid rgb(255 255 255 / 0.15);
}

.status .inner {
  width: calc(var(--cols) * 1ch);
  max-width: 100%;
  margin-inline: auto;
  display: flex;
  justify-content: space-between;
  gap: 2ch;
  height: 1em;
  line-height: 1em;
  padding-inline: 1ch;
  white-space: nowrap;
  overflow: hidden;
}
.status .name { overflow: hidden; text-overflow: clip }
.status .gauge { flex: none }
.status .gauge span { margin-left: 3ch }

/* ------------------------------------------------------------ reveal codes */

/* Alt-F3 in WordPerfect split the screen and showed the formatting codes.
 * This is the joke version: the codes, inline, in bright blue. */
body.reveal .doc p::before { content: "[Tab]"; color: var(--dim) }
body.reveal .doc p { text-indent: 0 }
body.reveal .doc p::after { content: "[HRt]"; color: var(--dim) }
body.reveal .doc h1::after,
body.reveal .doc h2::after { content: " [Bold][HRt]"; color: var(--dim) }

/* -------------------------------------------------------------------- CRT */

/* Scanlines are locked to the cell height so they never moire against the
 * glyphs, and the whole overlay is off by default for anyone who has asked
 * for less motion or more contrast. */
.crt {
  position: fixed;
  inset: 0;
  z-index: 9;
  pointer-events: none;
  background:
    radial-gradient(120% 120% at 50% 50%, transparent 55%, rgb(0 0 0 / 0.55)),
    repeating-linear-gradient(
      to bottom,
      rgb(0 0 0 / 0.11) 0 1px,
      transparent 1px 2px);
}
body.no-crt .crt { display: none }
body:not(.no-crt) { text-shadow: 0 0 calc(1em / 8) rgb(170 170 255 / 0.45) }
body:not(.no-crt) .menubar { text-shadow: none }

@media (prefers-contrast: more) {
  .crt { display: none }
  body { text-shadow: none }
}

/* --------------------------------------------------------------- exit shell */

.dos {
  position: fixed;
  inset: 0;
  z-index: 10;
  background: #000;
  color: var(--text);
  padding: 1em 1ch;
  white-space: pre-wrap;
}
.dos[hidden] { display: none }
.dos .cursor {
  display: inline-block;
  width: 1ch;
  height: 1em;
  background: var(--text);
  vertical-align: text-bottom;
  animation: blink 1s steps(1) infinite;
}
@keyframes blink { 50% { opacity: 0 } }

@media (prefers-reduced-motion: reduce) {
  .dos .cursor { animation: none }
  html { scroll-behavior: auto }
}

/* ------------------------------------------------------------------ print */

@media print {
  .menubar, .status, .crt { display: none }
  body { background: #fff; color: #000; text-shadow: none; padding: 0 }
  a { color: #000 }
}

/* --------------------------------------------------------------- narrow */

/* Eighty columns on a phone is nine-pixel type, which is authentic and
 * unreadable. Real hardware had a forty-column mode for exactly this
 * reason, so drop to it and let the characters grow. */
@media (max-width: 44em) {
  :root {
    --cols: 40;
    --measure: 38;
    --size: clamp(12px, calc((100vw - 1rem) / 22.5), 20px);
  }

  .doc p { text-indent: 4ch }          /* an 8-column tab eats a 38-column line */
  .card { gap: 0 }
  .card .bio { min-width: 0; flex-basis: 100% }

  /* Doc and Pos never change; on a short status line they are the first to go. */
  .status .gauge span:first-child,
  .status .gauge span:last-child { display: none }
  .status .gauge span { margin-left: 2ch }
}
