/* ============================================================================
   webdev.games · terminal.css
   One terminal, maximised, running tmux with three panes:
     0  bash      the list of games and a prompt you can type in
     1  preview   the screen: icat for stills, mpv for loops, the game itself
     2  man       a man page for the selected game
   Colours are the xterm-256 greyscale ramp plus colour 110, the blue that
   ls paints directories in. One font, one size in the panes; the two bars
   (the site nav, from bar.css, and the status line) share a size of their
   own, so the nav is the same bar on the /games/ pages. Hierarchy comes from
   bold, dim and reverse video, the way a terminal does it. No gradients, no
   glows.
   ========================================================================== */

@font-face { font-family: "Plex Mono"; src: url(fonts/plex-mono-400.woff2) format("woff2"); font-weight: 400; font-style: normal; font-display: swap; }
@font-face { font-family: "Plex Mono"; src: url(fonts/plex-mono-600.woff2) format("woff2"); font-weight: 600; font-style: normal; font-display: swap; }

:root {
  --bg:        #080808;   /* xterm 232 */
  --bg-2:      #121212;   /* 233 */
  --bg-3:      #1c1c1c;   /* 234  hover */
  --bar:       #303030;   /* 236  status line, soft keys */
  --bar-2:     #444444;   /* 238  status line hover */
  --border:    #4e4e4e;   /* 239  pane borders */
  --border-on: #a8a8a8;   /* 248  active pane border */
  --dim-2:     #6c6c6c;   /* 242 */
  --dim:       #8a8a8a;   /* 245 */
  --fg:        #d0d0d0;   /* 252 */
  --bright:    #eeeeee;   /* 255  bold text */
  --accent:    #87afd7;   /* 110  the ls directory blue: prompt host, cursor, links */
  --accent-2:  #afd7ff;   /* 153  link hover */

  --fs: 13px;
  --lh: 20px;
  --font: "Plex Mono", "IBM Plex Mono", ui-monospace, Menlo, Consolas, monospace;
  --slugw: 12ch;          /* set from the longest slug by terminal.js */
}

* { box-sizing: border-box; }
html {
  color-scheme: dark;
  background: var(--bg);
  height: 100%;
  -webkit-text-size-adjust: 100%;
}
body {
  margin: 0;
  height: 100%;
  background: var(--bg);
  color: var(--fg);
  font: 400 var(--fs) / var(--lh) var(--font);
  -webkit-font-smoothing: antialiased;
  overflow: hidden;
}
a { color: var(--accent); text-decoration: underline; text-underline-offset: 2px; }
a:hover { color: var(--accent-2); }
button, a { touch-action: manipulation; }
[hidden] { display: none !important; }
b, strong { font-weight: 600; color: var(--bright); }
.dim { color: var(--dim); }
.dim-2 { color: var(--dim-2); }
.sr-only { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

:focus-visible { outline: 1px solid var(--accent); outline-offset: 1px; }

/* ------------------------------------------------------------- the window */
.tmux {
  height: 100%;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: auto minmax(0, 1fr) auto;   /* nav, panes, status line */
}
.panes {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  grid-template-rows: auto minmax(0, 1fr);
  grid-template-areas:
    "shell preview"
    "shell man";
  min-width: 0;
  min-height: 0;
  padding: calc(var(--lh) / 2) 1ch 0;
}
.pane {
  position: relative;
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  border-top: 1px solid var(--border);
  padding-top: calc(var(--lh) / 2 + 4px);
}
.pane.is-active { border-color: var(--border-on); }
.pane-shell   { grid-area: shell; border-right: 1px solid var(--border); }
.pane-shell.is-active { border-right-color: var(--border-on); }
.pane-preview { grid-area: preview; }
.pane-man     { grid-area: man; }

/* the title sits on the border line, like tmux's pane-border-status */
.pane-title {
  position: absolute;
  top: 0;
  left: 1ch;
  transform: translateY(-50%);
  max-width: calc(100% - 2ch);
  padding: 0 1ch;
  background: var(--bg);
  color: var(--dim);
  white-space: nowrap;
  display: flex;
  gap: 1ch;
  align-items: baseline;
}
.pane-title .idx { flex: none; color: var(--dim); }
.pane.is-active .pane-title .idx { background: var(--fg); color: var(--bg); padding: 0 .5ch; }
.pane-title .t { color: var(--fg); min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.pane-title .t-note { flex: none; color: var(--dim-2); }
.pane-title .t-note:empty { display: none; }
.pane-title button, .cmdlink {
  appearance: none;
  border: 0;
  background: none;
  padding: 0;
  margin: 0;
  font: inherit;
  color: var(--fg);
  text-align: left;
  text-decoration: underline;
  text-decoration-style: dotted;
  text-underline-offset: 3px;
  cursor: pointer;
}
.pane-title button:hover, .cmdlink:hover { color: var(--accent-2); text-decoration-style: solid; }
.cmdlink { justify-self: start; }

/* ------------------------------------------------------------ pane 0: bash */
.shell {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: var(--border) transparent;
  padding: 0 1ch;
  cursor: text;
}
/* the prompt and the soft keys stay pinned to the bottom of the pane while
   the scrollback scrolls above them */
.cli {
  position: sticky;
  bottom: 0;
  background: var(--bg);
  padding-bottom: var(--lh);
}
.shell .line { white-space: pre-wrap; overflow-wrap: anywhere; min-height: var(--lh); }
.shell .banner { margin: 6px 0 10px; overflow: hidden; }
.banner svg { display: block; max-width: 100%; }
.banner .fg { fill: var(--bright); }
.banner .dot { fill: var(--accent); }
.ps1 { color: var(--accent); font-weight: 600; }
.ps1-path { color: var(--bright); font-weight: 600; }

/* the ls table: slot, name, tagline, then a play link for the game */
.ls { margin: 0; padding: 0; list-style: none; }
.ls li {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: baseline;
  white-space: nowrap;
}
.ls li:hover { background: var(--bg-3); }
.ls li.is-current { background: var(--fg); color: var(--bg); }
.ls-row {
  display: grid;
  grid-template-columns: 3ch var(--slugw) minmax(0, 1fr);
  gap: 0 2ch;
  align-items: baseline;
  min-width: 0;
  padding: 0;
  border: 0;
  background: none;
  color: var(--fg);
  font: inherit;
  text-align: left;
  cursor: pointer;
  white-space: nowrap;
}
.ls-row > span { overflow: hidden; text-overflow: ellipsis; }
.ls-num { text-align: right; color: var(--dim); font-variant-numeric: tabular-nums; }
.ls-name { font-weight: 600; color: var(--bright); }
.ls-tag { color: var(--fg); }
.ls-play {
  display: inline-flex;
  align-items: baseline;
  gap: 1ch;
  padding: 0 1ch;
  color: var(--accent);
  text-decoration: none;
}
.ls-play .ls-dom { text-decoration: underline; text-decoration-style: dotted; text-underline-offset: 3px; }
.ls-play:hover { color: var(--accent-2); }
.ls-play:hover .ls-dom { text-decoration-style: solid; }
.ls-where { padding: 0 1ch; color: var(--dim-2); }
.is-current .ls-name, .is-current .ls-tag { color: var(--bg); }
.is-current .ls-num, .is-current .ls-where { color: var(--bar-2); }
.is-current .ls-play, .is-current .ls-play:hover { color: var(--bg); }
.is-soon .ls-name { color: var(--dim); }
.ls-row:focus-visible, .ls-play:focus-visible { outline-offset: -1px; }

/* the prompt: a hidden input, mirrored into text with a block cursor */
.prompt {
  position: relative;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  min-height: var(--lh);
}
.prompt input {
  position: absolute;
  left: 0; top: 0;
  width: 1px; height: 1px;
  opacity: 0;
  border: 0; padding: 0; margin: 0;
  font: inherit;
  font-size: 16px;   /* under 16px iOS zooms the page when the input takes focus */
  pointer-events: none;
}
.cursor {
  display: inline-block;
  min-width: 1ch;
  background: var(--accent);
  color: var(--bg);
  white-space: pre;
}
.shell.is-blurred .cursor { background: none; color: var(--fg); box-shadow: inset 0 0 0 1px var(--accent); }
@keyframes blink { 50% { opacity: 0; } }
.shell:not(.is-blurred) .cursor { animation: blink 1.06s steps(1, end) infinite; }

/* keys a phone keyboard does not have, the way terminal apps add them */
.softkeys {
  display: none;
  flex-wrap: wrap;
  gap: 6px 1ch;
  padding-top: var(--lh);
  user-select: none;
  -webkit-user-select: none;
}
.softkeys button {
  appearance: none;
  border: 1px solid var(--border);
  background: var(--bar);
  color: var(--fg);
  font: inherit;
  min-width: 6ch;
  padding: 6px 1.5ch;
  border-radius: 0;
  cursor: pointer;
}
.softkeys button:active { background: var(--fg); color: var(--bg); }

/* --------------------------------------------------------- pane 1: preview */
.screen {
  position: relative;
  width: 100%;
  aspect-ratio: 40 / 21;
  max-height: 60vh;
  background: #000;
  overflow: hidden;
}
.screen > img, .screen > video, .screen > iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  border: 0;
  background: #000;
  object-fit: contain;
}
.screen > video { cursor: pointer; }
.screen-text {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 1ch;
}
.screen-text .dim { margin-top: var(--lh); }

/* the key bar: reverse-video chips like the F-key row at the bottom of htop */
.keys {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 1ch;
  /* room below for the next pane's title, which sits astride its border */
  padding: calc(var(--lh) / 2) 0 calc(var(--lh) / 2 + 8px);
}
.keys:empty { display: none; }
.key {
  display: inline-flex;
  align-items: baseline;
  gap: 1ch;
  padding: 6px 1.5ch;
  border: 0;
  border-radius: 0;
  font: inherit;
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
}
.key-play { background: var(--accent); color: var(--bg); }
.key-play:hover { background: var(--accent-2); color: var(--bg); }
.key-play .key-sub { font-weight: 400; }
.key-try { background: var(--fg); color: var(--bg); }
.key-try:hover { background: var(--bright); }
.key-off { color: var(--dim); box-shadow: inset 0 0 0 1px var(--border); cursor: default; }
.key-nav { margin-left: auto; display: inline-flex; gap: 1ch; }
.key-nav .key { background: none; color: var(--fg); font-weight: 400; box-shadow: inset 0 0 0 1px var(--border); }
.key-nav .key:hover { background: var(--bg-3); color: var(--bright); }
.is-zoomed .keys { display: none; }

/* ------------------------------------------------------------- pane 2: man */
.man {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: var(--border) transparent;
  padding: 0 1ch;
}
.man .hdr {
  display: flex;
  justify-content: space-between;
  gap: 2ch;
  font-weight: 600;
  color: var(--bright);
  white-space: nowrap;
}
.man .hdr .c { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.man .hdr .l, .man .hdr .r { flex: none; }
.man .sh {
  margin: var(--lh) 0 0;
  font-weight: 600;
  color: var(--bright);
  letter-spacing: .02em;
}
.man .p { margin: 0; padding-left: 7ch; white-space: pre-wrap; overflow-wrap: anywhere; }
.man .p + .p { margin-top: var(--lh); }
.man .kv { display: grid; grid-template-columns: 13ch minmax(0, 1fr); column-gap: 2ch; padding-left: 7ch; margin: 0; }
.man .kv dt { color: var(--dim); }
.man .kv dd { margin: 0; color: var(--bright); overflow-wrap: anywhere; }
.man .syn { display: grid; grid-template-columns: max-content minmax(0, 1fr); column-gap: 3ch; padding-left: 7ch; }
.man .syn .off { color: var(--dim-2); }
.man .syn .off .cmdlink { color: var(--dim); text-decoration: none; }
.man .ftr { margin-top: var(--lh); }
.man .empty { padding-left: 0; color: var(--dim); }
.pager {
  background: var(--fg);
  color: var(--bg);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  padding: 0 1ch;
}

/* ----------------------------------------------------------- the site nav */
/* The bar at the top (.bar) is in bar.css, shared with the /games/ pages so
   it is the same bar everywhere. The status line below borrows its tokens. */

/* --------------------------------------------------------- the status line */
.status {
  display: flex;
  align-items: center;
  background: var(--bar);
  color: var(--fg);
  font: 400 var(--bar-fs) / var(--bar-lh) var(--font);   /* the nav's type (bar.css), so the two bars match */
  padding: 2px 1ch;
  white-space: nowrap;
  overflow: hidden;
  min-width: 0;
  user-select: none;
  -webkit-user-select: none;
}
.status .sess { color: var(--bright); font-weight: 600; margin-right: 1ch; }
.status .wins {
  display: flex;
  flex: 1;
  min-width: 0;
  overflow-x: auto;
  scrollbar-width: none;
}
.status .wins::-webkit-scrollbar { display: none; }
.win {
  appearance: none;
  border: 0;
  background: none;
  padding: var(--bar-pad) 1ch var(--bar-pad) 0;
  margin: 0;
  font: inherit;
  color: var(--fg);
  cursor: pointer;
  white-space: nowrap;
}
.win:hover { background: var(--bar-2); }
.win.is-current { background: var(--fg); color: var(--bg); font-weight: 600; padding-left: 1ch; }
.win.is-soon { color: var(--dim); }
.win.is-soon.is-current { color: var(--bar); }
.status .right { margin-left: auto; padding-left: 2ch; color: var(--fg); }
.status .right .host { color: var(--bright); }

/* ---------------------------------------------------------------- zoomed */
/* try <game> zooms the preview pane to the whole window, tmux prefix-z style */
.is-zoomed .panes { grid-template-columns: minmax(0, 1fr); grid-template-rows: minmax(0, 1fr); grid-template-areas: "preview"; }
.is-zoomed .pane-shell, .is-zoomed .pane-man { display: none; }
.is-zoomed .screen { aspect-ratio: auto; max-height: none; flex: 1; min-height: 0; }

/* ----------------------------------------------------------------- dead */
.is-dead .prompt, .is-dead .softkeys { display: none; }

/* ------------------------------------------------------- stacked (phones) */
/* Narrow or short viewports stack the panes and let the page scroll: shell,
   then the screen, then the man page. The status line sticks to the bottom
   and stays the game select. */
@media (max-width: 899px), (max-height: 499px) {
  :root { --fs: 12px; --lh: 18px; }
  /* the viewport scrolls and clips sideways; body must not become a scroll
     container of its own or the sticky status line stops sticking */
  html { height: auto; overflow-x: hidden; overflow-y: auto; }
  body { height: auto; overflow: visible; }
  .tmux { height: auto; min-height: 100vh; min-height: 100dvh; grid-template-rows: auto minmax(0, 1fr) auto; }
  .panes {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto auto auto;
    grid-template-areas: "shell" "preview" "man";
    padding: calc(var(--lh) / 2) max(.5ch, env(safe-area-inset-right)) var(--lh) max(.5ch, env(safe-area-inset-left));
  }
  .pane { padding-top: calc(var(--lh) / 2 + 3px); }
  .pane-shell { border-right: 0; }
  /* the shell is a window of fixed size: it scrolls inside itself so a few
     commands do not push the screen and the man page down the page */
  .pane-shell { height: 62vh; height: 62svh; min-height: 300px; }
  .man { overflow: visible; max-height: none; }
  .screen { max-height: none; }
  .man .hdr .c { display: none; }
  .man .p, .man .syn { padding-left: 3ch; }
  .man .kv { grid-template-columns: 11ch minmax(0, 1fr); padding-left: 3ch; }
  .status {
    position: sticky;
    bottom: 0;
    z-index: 5;
    padding-left: max(1ch, env(safe-area-inset-left));
    padding-right: max(1ch, env(safe-area-inset-right));
    padding-bottom: max(2px, env(safe-area-inset-bottom));
  }
  .ls-play .ls-dom { display: none; }
  .ls-play { padding: 0 1.5ch; }

  /* the zoomed game takes the viewport above the status line */
  html.is-zoomed, html.is-zoomed body { height: 100%; overflow: hidden; }
  .tmux.is-zoomed { height: 100%; min-height: 0; }
  .is-zoomed .panes { padding-bottom: 0; }
}

/* --------------------------------------------------------- touch screens */
@media (hover: none) and (pointer: coarse) {
  .softkeys { display: flex; padding-top: 6px; gap: 6px 1ch; }
  .softkeys button { padding: 4px 1.5ch; }
  .shell.is-blurred .softkeys { display: none; }
  .shell.is-blurred .prompt.is-empty::after { content: " tap to type"; color: var(--dim-2); }
  .cli { padding-bottom: 8px; }
  .ls-row { padding-top: 5px; padding-bottom: 5px; }
  .cmdlink, .pane-title button { padding-top: 4px; padding-bottom: 4px; }
  .ls-play { padding-top: 5px; padding-bottom: 5px; }
  .key { padding: 9px 2ch; }
  .screen > video { cursor: default; }
}

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