/* Aura Farmer. One terminal session on a black screen, built to his Kali photograph:
   no frame, no panel, no border, no footer. Everything is type on the field, and every graphic on
   the page except the trade pictures themselves is made of characters.

   The cell: Fira Mono at 15 px has an advance of exactly 9 px, so a column of the page is a whole
   number of cells and nothing lands on a half pixel. Rows are 20 px. */

@font-face {
  font-family: "Fira Mono";
  src: url("/fonts/FiraMono-Regular.woff2") format("woff2");
  font-weight: 400; font-style: normal; font-display: block;
}
@font-face {
  font-family: "Fira Mono";
  src: url("/fonts/FiraMono-Bold.woff2") format("woff2");
  font-weight: 700; font-style: normal; font-display: block;
}
@font-face {
  font-family: "Fira Sans";
  src: url("/fonts/FiraSans-Regular.woff2") format("woff2");
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Fira Sans";
  src: url("/fonts/FiraSans-Medium.woff2") format("woff2");
  font-weight: 500; font-style: normal; font-display: swap;
}

:root {
  --cell: 9px;
  --row: 20px;
  --gutter: clamp(16px, 2.2vw, 40px);
  --page: min(1071px, calc(100vw - 2 * var(--gutter)));
  --col: min(1071px, calc(100% - 2 * var(--gutter)));

  /* his field and his ink, straight off the photograph: rgb(0,0,0) and rgb(254,254,254) */
  --field: #000000;
  --ink: #ffffff;
  --dim: #9aa0a6;          /*  7.9:1  labels and anything secondary */
  --muted: #808790;        /*  5.8:1  separators, brackets and disabled keys only */
  --blue: #3b9ae1;         /*  6.4:1  the prompt, paths, structure */
  --mint: #6ddca4;         /* 11.3:1  whole objects, profit, a live session */
  --red: #ff6b63;          /*  7.0:1  broken objects, a loss */
  --gold: #ffc24d;         /* 12.9:1  over +100% */

  --mono: "Fira Mono", "DejaVu Sans Mono", ui-monospace, monospace;
  --sans: "Fira Sans", "DejaVu Sans", system-ui, sans-serif;

  color-scheme: dark;
}

* { box-sizing: border-box; }

html { background: var(--field); }

body {
  margin: 0;
  background: var(--field);
  color: var(--ink);
  font: 400 15px/20px var(--mono);
  font-synthesis: none;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}

a { color: inherit; }

/* ---------------------------------------------------------------- menu bar */
/* The one piece of chrome in his picture: five words in the desktop's own
   proportional face, flush left, over the session. */

.menubar {
  /* every block of the session is its own layer, so the bar needs to be one too, and above them:
     without this a menu opens UNDER the character art of the first screen */
  position: relative;
  z-index: 30;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  width: min(1071px, calc(100% - 2 * var(--gutter)));
  width: round(down, var(--col), 18px);
  margin-left: round(down, calc((100% - round(down, var(--col), 18px)) / 2), 1px);
  margin-right: 0;
  padding-top: 12px;
  font-family: var(--sans);
}

.menubar__list {
  display: flex;
  margin: 0;
  padding: 0;
  list-style: none;
}

.menubar__list > li { position: relative; }

.menubar__top {
  appearance: none;
  background: none;
  border: 0;
  color: var(--ink);
  font: 400 15px/1 var(--sans);
  height: 48px;
  padding: 0 14px;
  cursor: pointer;
}
.menubar__list > li:first-child .menubar__top { padding-left: 0; }

.menubar__top:hover,
.menubar__top:active,
.menubar__top[aria-expanded="true"] { background: var(--ink); color: var(--field); }
.menubar__top:focus-visible { outline: 2px solid var(--blue); outline-offset: -2px; }

.menu {
  position: absolute;
  top: 48px;
  left: 0;
  z-index: 20;
  min-width: 232px;
  margin: 0;
  padding: 10px 0;
  list-style: none;
  background: var(--field);
  box-shadow: 0 0 0 1px var(--muted);
}
.menubar__list > li:first-child .menu { left: -14px; }

.menu a {
  display: block;
  padding: 11px 20px;
  color: var(--ink);
  text-decoration: none;
  font: 400 15px/22px var(--sans);
}
.menu a:hover, .menu a:active { background: var(--ink); color: var(--field); }
.menu a:focus-visible { outline: 2px solid var(--blue); outline-offset: -2px; }

.ident {
  margin: 0;
  font: 400 15px/48px var(--sans);
  color: var(--dim);
  white-space: nowrap;
}
.ident .dim { color: var(--muted); }

/* ----------------------------------------------------------------- session */

.session {
  width: min(1071px, calc(100% - 2 * var(--gutter)));
  width: round(down, var(--col), 18px);
  margin-left: round(down, calc((100% - round(down, var(--col), 18px)) / 2), 1px);
  margin-right: 0;
  padding: 20px 0 120px;
}

/* Every block of the session gets its own layer for the same reason the character art does: Chrome
   on Windows paints colour fringes on a one pixel stroke, and a terminal is nothing but those. */
.block,
.menubar,
.session > .prompt,
.session > .cmd { transform: translateZ(0); }

.block { margin: 0 0 60px; }
.block:last-of-type { margin-bottom: 40px; }

p { margin: 0 0 20px; }
.say { max-width: 74ch; color: var(--dim); }
.dim { color: var(--dim); }

/* the start-up banner --------------------------------------------------- */

.intro {
  display: flex;
  align-items: flex-start;
  gap: 36px;
  margin-bottom: 20px;
}

.fork {
  /* The boxes already shared a top line; the INK did not. The drawing's first mark (the ring) sits
     5 px into its line box and the prose's first mark 3 px into its own, so the figure goes up two
     whole pixels and the two really start on one line. Measured, not guessed. */
  margin: -2px 0 0;
  font: 400 15px/15px var(--mono);
  color: var(--ink);
  white-space: pre;
  letter-spacing: 0;
  word-spacing: 0;
  tab-size: 8;
  font-kerning: none;
  font-variant-ligatures: none;
  font-feature-settings: "liga" 0, "calt" 0;
  text-rendering: geometricPrecision;
  /* Chrome on Windows ignores -webkit-font-smoothing and runs its LCD filter, which paints an
     orange edge on one side of a one pixel stroke and a cyan edge on the other. Character art is
     nothing but one pixel strokes, so it gets its own layer, where the text is drawn in grey. */
  will-change: transform;
}
.fork .halo { color: var(--mint); }

.intro__text { max-width: 74ch; }
.intro__text p:last-child { margin-bottom: 0; }

.state { color: var(--ink); margin-bottom: 20px; }
.state b { font-weight: 700; }

.word {
  margin: 0 0 40px;
  /* His NMAP fills 79.9% of his screen: 95 columns of this banner over the 118 column page is 80.5%.
     The size is STEPPED, never fluid: a fractional cell puts every row under the banner on a half
     pixel, and a one pixel stroke on a half pixel is a grey smear. */
  font: 700 15px/15px var(--mono);
  color: var(--ink);
  white-space: pre;
  overflow: hidden;
  letter-spacing: 0;
  word-spacing: 0;
  tab-size: 8;
  font-kerning: none;
  font-variant-ligatures: none;
  font-feature-settings: "liga" 0, "calt" 0;
  text-rendering: geometricPrecision;
  will-change: transform;
}
.word-narrow { display: none; }

.caps {
  display: table;
  margin-bottom: 28px;
  padding: 0 7px 0 9px;
  background: var(--ink);
  color: var(--field);
  text-transform: uppercase;
  letter-spacing: 1px;
  font-weight: 700;
}

.tail { color: var(--dim); margin-top: 24px; margin-bottom: 0; }

/* the facts block: his `Configured with:` ladder ------------------------- */

.facts { margin: 0; }

.fact {
  display: grid;
  grid-template-columns: 135px minmax(0, 1fr);
  gap: 0 27px;
  align-items: baseline;
  margin-bottom: 20px;
}
.fact dt { color: var(--dim); }
.fact dd { margin: 0; }

.fact__mint { display: flex; align-items: center; flex-wrap: wrap; gap: 0 12px; }
.mint {
  font: inherit;
  overflow-wrap: anywhere;
  min-width: 0;
}
.mint.is-empty { color: var(--dim); }

.feedback { color: var(--mint); }

/* a reading is a label and a number, not prose: the words stay dim and the numbers stay in paper */
.pairs { display: flex; flex-wrap: wrap; gap: 0 27px; }
.pairs .pair { white-space: nowrap; }
.pairs .pair .dim { margin-right: 9px; }

.fact--markets, .fact--mint { align-items: center; min-height: 60px; }
.fact--markets dd { display: flex; flex-wrap: wrap; gap: 0 4px; max-width: none; }

/* a key is a bracketed word with a 48 px hit area; a terminal selects by inverting */
.key {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 48px;
  padding: 0 12px;
  margin: 0;
  border: 0;
  background: none;
  color: var(--ink);
  font: 400 15px/20px var(--mono);
  text-decoration: none;
  cursor: pointer;
}
.key:first-child { padding-left: 0; }
.key img { display: block; width: 18px; height: 18px; object-fit: contain; }
#link-pump img { width: 18px; height: 18px; }
#link-dex img { width: 18px; height: 18px; }
#link-scan img { width: 17px; height: 17px; }
#link-x img { width: 20px; height: 20px; }
.key:hover:not([aria-disabled="true"]):not(:disabled) { background: var(--ink); color: var(--field); }
.key:active:not([aria-disabled="true"]):not(:disabled) { background: var(--mint); color: var(--field); }
.key:focus-visible { outline: 2px solid var(--blue); outline-offset: -2px; }
/* a key that can be pressed wears its brackets in the live ink, so it reads as a key at rest */
.key:not([aria-disabled="true"]):not(:disabled) { color: var(--mint); }
.key:not([aria-disabled="true"]):not(:disabled) .label { color: var(--ink); }
/* Inverted, the whole key is one ink: a label that kept its own colour vanishes into the fill, and
   it really did until this rule carried MORE specificity than the resting one above (four class
   level selectors there, so the hover needs five). */
.key:not([aria-disabled="true"]):not(:disabled):hover .label,
.key:not([aria-disabled="true"]):not(:disabled):active .label,
.key:not([aria-disabled="true"]):not(:disabled):focus-visible .label { color: inherit; }
.key[aria-disabled="true"], .key:disabled {
  color: var(--muted);
  cursor: default;
  opacity: 0.74;
}

/* prompts and command echoes -------------------------------------------- */

.prompt { margin: 0; color: var(--blue); }
.prompt .who { color: var(--blue); font-weight: 700; }
.prompt .path { color: var(--ink); font-weight: 700; }
.prompt .elbow { color: var(--muted); }

.cmd { margin: 0 0 24px; }
.cmd .elbow { color: var(--muted); }
.cmd__word { color: var(--ink); }

.cmd--live { margin-bottom: 0; }

.cursor {
  display: inline-block;
  width: 9px;
  height: 17px;
  margin-left: 2px;
  vertical-align: -3px;
  background: var(--mint);
  animation: blink 1.1s step-end infinite;
}
@keyframes blink { 0%, 55% { opacity: 1; } 56%, 100% { opacity: 0; } }

.block.is-named .cmd__word { background: var(--ink); color: var(--field); }

/* output tables ---------------------------------------------------------- */

.out { margin: 0; }
.out p { margin: 0 0 20px; }
.out p:last-child { margin-bottom: 0; }
.out .prompt { margin-bottom: 0; }

/* A terminal's columns are as wide as what is in them, not stretched to the edge: a table that
   fills the width puts every column on a fractional x, and mono text goes soft on a half pixel. */
.rows { width: auto; max-width: 100%; border-collapse: collapse; text-align: left; }
.rows th {
  font-weight: 400;
  color: var(--dim);
  padding: 0 36px 10px 0;
  white-space: nowrap;
}
.rows td {
  padding: 0 36px 10px 0;
  vertical-align: top;
  overflow-wrap: anywhere;
}
.rows .reason { max-width: 62ch; }
.rows .coin { max-width: 26ch; }
.rows th:last-child, .rows td:last-child { padding-right: 0; }
.rows .num { font-variant-numeric: tabular-nums; }
.rows .when { white-space: nowrap; }
/* a board is four short columns: a terminal packs them left, it does not spread them to the edge */

.rows tbody tr:last-child td { padding-bottom: 0; }

.up { color: var(--mint); }
.down { color: var(--red); }
.jack { color: var(--gold); }
.lock { color: var(--dim); }

/* the pictures ----------------------------------------------------------- */

.shot { margin: 0 0 20px; }
.shot img {
  display: block;
  width: min(540px, 100%);
  height: auto;
  background: #0a0a0a;
}
.shot figcaption { margin-top: 12px; color: var(--dim); }

/* The column is always a whole number of 18 px pairs, so six, three and two tracks with an 18 px
   gap are always whole pixels wide: (18k - 90) / 6, (18k - 36) / 3 and (18k - 18) / 2 never carry
   a fraction, and nothing in the sheet starts on a half pixel. */
.sheet {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 18px;
  margin-bottom: 28px;
}
.tile {
  display: block;
  padding: 0;
  border: 0;
  background: none;
  color: var(--ink);
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.tile img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  background: #0a0a0a;
}
.tile figcaption, .tile .cap { display: block; margin-top: 10px; }
.tile:hover img, .tile[aria-pressed="true"] img { outline: 2px solid var(--ink); outline-offset: 2px; }
.tile:focus-visible img { outline: 2px solid var(--blue); outline-offset: 2px; }

.keyset {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 18px;
  margin-bottom: 36px;
}
.keyset figure { margin: 0; }
.keyset img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  background: #0a0a0a;
}
.keyset figcaption { margin-top: 12px; }

/* the guess -------------------------------------------------------------- */

.ask { margin: 0 0 20px; }
.ask__row { display: flex; align-items: center; flex-wrap: wrap; gap: 0 4px; margin-bottom: 8px; }
.ask__label { color: var(--dim); width: 117px; flex: none; }
.pick {
  min-width: 48px;
  height: 48px;
  padding: 0 8px;
  border: 0;
  background: none;
  color: var(--ink);
  font: 400 15px/20px var(--mono);
  cursor: pointer;
}
.pick:hover { background: var(--ink); color: var(--field); }
.pick:active { background: var(--mint); color: var(--field); }
.pick:focus-visible { outline: 2px solid var(--blue); outline-offset: -2px; }
.pick[aria-pressed="true"] { background: var(--mint); color: var(--field); }
.pick:disabled { color: var(--muted); cursor: default; }

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

@media (max-width: 1080px) {
  .intro { gap: 28px; }
}

@media (max-width: 940px) {
  /* 95 columns of banner no longer fit a column this narrow, and a terminal that cannot print its
     banner prints its name instead: the display here is the program's own line, in type. */
  .word { display: none; }
  .word-narrow { display: block; }
  .sheet { grid-template-columns: repeat(3, 1fr); }
}

@media (max-width: 860px) {
  .intro { display: block; }
  .fork { margin-bottom: 20px; }
  .fact { grid-template-columns: minmax(0, 1fr); gap: 6px; }
  /* a reading that cannot fit one line of a narrow column wraps rather than pushing the page sideways */
  .pairs { gap: 0 18px; }
  .pairs .pair { white-space: normal; }
  .fact dt { font-size: 15px; }
  .ask__label { width: auto; }
  .ask__row { display: block; }
}

.word-narrow {
  margin: 0 0 32px;
  font: 700 30px/40px var(--mono);
  transform: translateZ(0);
}

@media (max-width: 520px) {
  .menubar { flex-wrap: wrap; padding-top: 8px; }
  .menubar__list { flex-wrap: wrap; }
  .menubar__top { padding: 0 10px; }
  .ident { line-height: 32px; }
  .sheet { grid-template-columns: repeat(2, 1fr); }
  .keyset { grid-template-columns: repeat(1, 1fr); }
  .rows, .rows tbody, .rows tr, .rows td { display: block; width: 100%; }
  .rows thead { display: none; }
  .rows tr { margin-bottom: 20px; }
  .rows td { padding: 0 0 4px; }
  .rows td::before {
    content: attr(data-label) " ";
    color: var(--dim);
  }
  .rows tbody tr:last-child td { padding-bottom: 4px; }
}

@media (prefers-reduced-motion: reduce) {
  .cursor { animation: none; }
}
