/* OpenShell: a terminal in a neon frame. Every face is self-hosted. */
@font-face { font-family: 'IBM Plex Mono'; font-style: normal; font-weight: 200; font-display: swap; src: url(/fonts/ibm-plex-mono-200-latin.woff2) format('woff2'); }
@font-face { font-family: 'IBM Plex Mono'; font-style: normal; font-weight: 400; font-display: swap; src: url(/fonts/ibm-plex-mono-400-latin.woff2) format('woff2'); }
@font-face { font-family: 'IBM Plex Mono'; font-style: normal; font-weight: 600; font-display: swap; src: url(/fonts/ibm-plex-mono-600-latin.woff2) format('woff2'); }
@font-face { font-family: 'Pixelify Sans'; font-style: normal; font-weight: 400; font-display: swap; src: url(/fonts/pixelify-sans-latin.woff2) format('woff2'); }
@font-face { font-family: 'VT323'; font-style: normal; font-weight: 400; font-display: swap; src: url(/fonts/vt323-latin.woff2) format('woff2'); }
/* Box drawing for the banner, and the arrows */
@font-face { font-family: 'Banner Mono'; font-style: normal; font-weight: 400; font-display: block; src: url(/fonts/jetbrains-mono-400.woff2) format('woff2'); }

/* cyberpunk (default) */
:root {
  --bg: #0d0a1f;
  --border: #ff9ecf;
  --text: #f6dfe6;
  --prompt-at: #a7a6ad;
  --prompt-user: #ff6ac1;
  --prompt-host: #6ef2ff;
  --ascii: #ff9a52;
  --input: #ff7a8a;
  --link: #b9adf2;
  --command: #ffa3dc;
  --output: #ff7a8a;
  --keys: #ff9a52;
  --meta: #9b93b8;
  color-scheme: dark;
}
*, *::before, *::after { box-sizing: border-box; }
[hidden] { display: none !important; }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; margin: 0; }
html, body { height: 100%; margin: 0; }
/* Phones: the height of what is visible above the keyboard, set by the script */
html.has-keybar, html.has-keybar body { height: var(--vh, 100dvh); }
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
body {
  background: var(--bg);
  color: var(--text);
  font: 200 16px/22px 'IBM Plex Mono', ui-monospace, Menlo, Consolas, monospace;
  padding: max(16px, env(safe-area-inset-top)) max(16px, env(safe-area-inset-right)) max(16px, env(safe-area-inset-bottom)) max(16px, env(safe-area-inset-left));
  transition: background-color .4s ease, color .4s ease;
  overscroll-behavior: none;
}
::selection { background: var(--border); color: var(--bg); }

/* ---------- The frame ---------- */
.term {
  display: flex;
  flex-direction: column;
  height: 100%;
  border: 2px solid var(--border);
  border-radius: 2px;
  overflow-y: auto;
  overflow-x: hidden;
  scrollbar-width: none;
  overscroll-behavior: contain;
  box-shadow: rgba(0, 0, 0, .12) 0 1px 3px, rgba(0, 0, 0, .24) 0 1px 2px;
  transition: border-color .4s ease;
}
.term::-webkit-scrollbar { display: none; }

.bars { position: sticky; top: 0; z-index: 2; background: var(--bg); font: 400 20px 'Pixelify Sans', sans-serif; transition: background-color .4s ease; }
.bar-1 { height: 36px; line-height: 36px; padding-left: 10px; background: var(--border); color: var(--bg); transition: background-color .4s ease, color .4s ease; }
.bar-2, .bar-3, .bar-4, .bar-5 { background: var(--border); transition: background-color .4s ease; }
.bar-2 { height: 4px; margin-top: 1px; }
.bar-3 { height: 3px; margin-top: 2px; }
.bar-4 { height: 2px; margin-top: 3px; }
.bar-5 { height: 1px; margin-top: 4px; }

.terminal { flex: 1 0 auto; padding: 22px 20px 26px; cursor: text; }

/* ---------- Lines ---------- */
.out p, .out pre, .out .echo { margin: 0; }
/* Prose wraps at a reading measure instead of running the full width */
.ln { overflow-wrap: anywhere; max-width: 72ch; }
/* Each new line types itself in. Fill is backwards-only on purpose: when
   the animation ends the line falls back to its own, unclipped style, so
   no rounding at the last step can leave a few characters hidden. */
.type { animation: typing .5s steps(30, end) backwards; }
@keyframes typing { from { clip-path: inset(0 100% 0 0); } to { clip-path: inset(0 0 0 0); } }
.appear { animation: appear .25s ease-out backwards; }
@keyframes appear { from { opacity: 0; } }
/* Server-printed lines wait for the script to type them in; if the
   script never runs, they show anyway after a moment. */
.js .out.boot { visibility: hidden; animation: unhide 0s 1.5s forwards; }
@keyframes unhide { to { visibility: visible; } }

.ascii {
  font: 400 min(14px, calc((100vw - 64px) / 59 / 0.6)) / 1.08 'Banner Mono', ui-monospace, Consolas, monospace;
  color: var(--ascii);
  white-space: pre;
  overflow: hidden;
  transition: color .4s ease;
}
.ascii--gap { line-height: .7; }

.ps { white-space: nowrap; font-weight: 200; }
.ps__user { color: var(--prompt-user); }
.ps__at, .ps__tail { color: var(--prompt-at); }
.ps__host { color: var(--prompt-host); }
.ps__dir { color: var(--link); }
.echo { display: flex; flex-wrap: wrap; column-gap: .6ch; }
.output { color: var(--output); font-weight: 400; overflow-wrap: anywhere; }

a { color: var(--link); text-decoration: none; transition: color .4s ease, background-color .4s ease; }
a:focus-visible { background: var(--border); color: var(--bg); outline: none; }
/* Hover only where there is a mouse, so a tap leaves nothing lit */
@media (hover: hover) { a:hover { background: var(--border); color: var(--bg); } }
.command {
  font: inherit;
  font-weight: 400;
  color: var(--command);
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  text-decoration: none;
  transition: color .4s ease;
}
.command:focus-visible { background: var(--border); color: var(--bg); outline: none; }
@media (hover: hover) { .command:hover { background: var(--border); color: var(--bg); } }
.command--static { cursor: inherit; }
.command--static:hover { background: none; color: var(--command); }
.keys { color: var(--keys); font-weight: 400; }
.meta { color: var(--meta); }
.err { color: var(--output); font-weight: 400; }

/* ---------- Tables: help, about, essays ---------- */
.table { display: grid; grid-template-columns: minmax(16ch, max-content) 1fr; column-gap: 3ch; padding-left: 2ch; }
.table--about { grid-template-columns: 12ch 1fr; }
.table--essays { grid-template-columns: 3ch 1fr; column-gap: 2ch; row-gap: 2px; }
.table__k, .table__v { min-width: 0; overflow-wrap: anywhere; }
.num { color: var(--keys); font-weight: 400; }
.essay-link { font-weight: 400; margin-right: 2ch; }
.table--essays .meta { white-space: nowrap; }

/* ---------- Reading ---------- */
.essay__title { font: 600 1.35em/1.3 'IBM Plex Mono', monospace; color: var(--text); margin: 4px 0 2px; text-wrap: balance; max-width: 70ch; }
.essay__title::before { content: '# '; color: var(--command); }
.essay__deck { color: var(--text); opacity: .85; }
.essay__body { max-width: 72ch; font-weight: 400; line-height: 1.7; }
.essay__body p { margin: 0 0 1em; }
.essay__body h1, .essay__body h2, .essay__body h3, .essay__body h4 { font-size: 1em; font-weight: 600; margin: 1.6em 0 .6em; color: var(--text); }
.essay__body h1::before, .essay__body h2::before { content: '## '; color: var(--command); }
.essay__body h3::before, .essay__body h4::before { content: '### '; color: var(--command); }
.essay__body a { color: var(--link); text-decoration: underline; text-underline-offset: 3px; }
.essay__body blockquote { margin: 1.2em 0; padding-left: 2ch; border-left: 2px solid var(--border); font-style: italic; }
.essay__body ul, .essay__body ol { margin: 0 0 1em; padding-left: 3ch; }
.essay__body ul { list-style: none; }
.essay__body ul > li::before { content: '-'; color: var(--command); display: inline-block; width: 2ch; margin-left: -2ch; }
.essay__body li { margin: .25em 0; }
.essay__body strong, .essay__body b { font-weight: 600; }
.essay__body hr { border: 0; text-align: center; margin: 1.6em 0; }
.essay__body hr::after { content: '* * *'; color: var(--meta); }
.essay__body img { max-width: 100%; height: auto; display: block; margin: 1.2em 0; border: 1px solid var(--border); }
.essay__body figure { margin: 1.2em 0; }
.essay__body figcaption { color: var(--meta); font-size: .9em; }
.essay__body table { border-collapse: collapse; }
.essay__body td, .essay__body th { border: 1px solid var(--meta); padding: 3px 8px; }

/* ---------- Booking ---------- */
.slots { display: grid; grid-template-columns: 12ch 1fr; column-gap: 2ch; row-gap: 2px; padding-left: 2ch; }
.slots__day { color: var(--keys); font-weight: 400; }
.slots__times { display: flex; flex-wrap: wrap; gap: 0 2ch; }
.slot { font: inherit; color: var(--text); background: none; border: 0; padding: 0 2px; cursor: pointer; }
.slot b { color: var(--command); font-weight: 400; }
.slot:focus-visible, .slot.is-picked { background: var(--border); color: var(--bg); outline: none; }
.slot:focus-visible b, .slot.is-picked b { color: var(--bg); }
@media (hover: hover) { .slot:hover { background: var(--border); color: var(--bg); } .slot:hover b { color: var(--bg); } }

/* ---------- The input line ---------- */
.input-line { display: flex; align-items: baseline; gap: .6ch; margin-top: 22px; }
.input-line.is-busy { opacity: .5; }
/* The real input sits on top, invisible but selectable; the mirror under
   it draws the text and a block cursor that follows the caret. */
.field { position: relative; flex: 1; min-width: 0; display: block; }
#cmd, .mirror { font: 400 16px/22px 'IBM Plex Mono', ui-monospace, monospace; }
#cmd {
  position: absolute;
  inset: 0;
  width: 100%;
  color: transparent;
  caret-color: transparent;
  background: transparent;
  border: 0;
  padding: 0;
  margin: 0;
  outline: none;
  z-index: 1;
}
#cmd::selection { background: var(--border); color: transparent; }
.mirror { display: block; min-height: 22px; white-space: pre; overflow: hidden; color: var(--input); }
.cursor { display: inline-block; min-width: 1ch; background: var(--input); color: var(--bg); animation: blink 1.06s steps(1) infinite; }
.is-typing .cursor { animation: none; }
.field:not(.is-focused) .cursor { background: transparent; color: inherit; outline: 1px solid var(--input); outline-offset: -1px; animation: none; }
@keyframes blink { 50% { background: transparent; color: inherit; } }

/* ---------- The key row (touch screens) ---------- */
.keybar { position: sticky; bottom: 0; z-index: 2; flex-shrink: 0; background: var(--bg); padding: 0 6px 6px; }
/* Stepped rules above the keys, mirroring the bars at the top */
.keybar::before { content: ""; display: block; height: 10px; margin: 0 -6px 6px; background: linear-gradient(var(--border), var(--border)) 0 0 / 100% 1px no-repeat, linear-gradient(var(--border), var(--border)) 0 3px / 100% 2px no-repeat, linear-gradient(var(--border), var(--border)) 0 7px / 100% 3px no-repeat; }
.keybar__row { display: flex; gap: 6px; }
.key {
  flex: 1 1 0;
  min-width: 0;
  height: 40px;
  padding: 0 2px;
  font: 400 13px/1 'IBM Plex Mono', ui-monospace, monospace;
  color: var(--command);
  background: transparent;
  border: 1px solid color-mix(in srgb, var(--border) 55%, transparent);
  border-radius: 2px;
  cursor: pointer;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  user-select: none;
  -webkit-user-select: none;
}
.key:active { background: var(--border); color: var(--bg); }
.key:focus-visible { outline: 1px solid var(--border); outline-offset: 1px; }
.is-ruined .keybar { display: none; }

/* ---------- Boot log ---------- */
.boot-ok { color: var(--prompt-host); font-weight: 400; }

/* ---------- ls ---------- */
.ls { display: flex; flex-wrap: wrap; gap: 0 3ch; }
.ls__dir { color: var(--prompt-host); }
.ls__file { color: var(--text); }
.ls a.ls__dir:hover, .ls a.ls__file:hover, .ls .command:hover { color: var(--bg); }
.tree { white-space: pre; font-family: 'Banner Mono', ui-monospace, monospace; font-size: .9em; line-height: 1.5; margin: 0; overflow-x: auto; }

/* ---------- man ---------- */
.man__head { color: var(--keys); font-weight: 400; }
.man__body { display: block; padding-left: 4ch; max-width: 72ch; }

/* ---------- matrix ---------- */
.matrix { position: fixed; inset: 0; width: 100vw; height: 100vh; z-index: 20; cursor: pointer; background: var(--bg); }

/* ---------- After rm -rf src ---------- */
body.is-ruined { background: #000; color: #fff; font: 400 20px/24px 'VT323', monospace; }
.is-ruined .term { border: 0; }
.is-ruined .bars { display: none; }
.is-ruined .out *, .is-ruined .ps * { color: #fff !important; }
.is-ruined .ascii { font-family: 'VT323', monospace; }
.is-ruined #cmd, .is-ruined .mirror { font: 400 20px/24px 'VT323', monospace; }
.is-ruined .mirror { color: #fff; }
.is-ruined .cursor { background: #fff; color: #000; }
.is-ruined .essay__title { font-family: 'VT323', monospace; }

/* ---------- Small screens ---------- */
@media (max-width: 600px) {
  body { font-size: 14px; line-height: 20px; padding: max(4px, env(safe-area-inset-top)) max(4px, env(safe-area-inset-right)) max(4px, env(safe-area-inset-bottom)) max(4px, env(safe-area-inset-left)); }
  .term { border-width: 1px; }
  .bars { font-size: 16px; }
  .bar-1 { height: 30px; line-height: 30px; }
  .terminal { padding: 14px 10px 18px; }
  .ascii { font-size: min(14px, calc((100vw - 32px) / 59 / 0.6)); }
  /* 16px keeps iOS from zooming into the field */
  #cmd, .mirror { font-size: 16px; }
  .input-line { margin-top: 12px; padding: 8px 0; }
  .essay__body { font-size: 15px; line-height: 1.65; }
  .table--essays { row-gap: 12px; }
  .ps__host { display: none; }
  .ps__at { display: none; }
  .table { grid-template-columns: 1fr; padding-left: 1ch; }
  .table--about .table__v { padding-left: 2ch; margin-bottom: 3px; }
  .table--essays { grid-template-columns: 3ch 1fr; }
  .table--essays .meta { display: block; }
  .slots { grid-template-columns: 1fr; }
}

/* Fingers: the same words, a taller place to land */
@media (pointer: coarse) {
  .command, .essay-link, .slot, .ls a { padding-top: 5px; padding-bottom: 5px; margin-top: -5px; margin-bottom: -5px; -webkit-tap-highlight-color: transparent; }
  .command:active, .essay-link:active, .slot:active, .ls a:active { background: var(--border); color: var(--bg); }
}

@media (prefers-reduced-motion: reduce) {
  .type, .appear, .cursor { animation: none; }
  .js .out.boot { visibility: visible; animation: none; }
  body, a, .command, .bars, .bar-1, .term { transition: none; }
}

@media print {
  body { background: #fff; color: #000; padding: 0; }
  .term { border: 0; height: auto; overflow: visible; }
  .bars, .input-line, .keybar { display: none !important; }
  .command { text-shadow: none; }
}
