:root {
  --bg: #0b0b0b;
  --fg: #33ff66;
  --dim: #6a6;
  --panel: #111;
  --line: #1c1c1c;
  --accent: #5f6;
  --link: #6cf;
}
* { box-sizing: border-box; }
html, body {
  margin: 0; min-height: 100%; background: var(--bg); color: var(--fg);
  font-family: ui-monospace, Menlo, Consolas, monospace;
}
a { color: var(--link); text-decoration: none; }
a:hover { text-decoration: underline; }

/* ---- landing page ---- */
.wrap { max-width: 920px; margin: 0 auto; padding: 48px 20px 80px; }
header h1 { font-size: 30px; margin: 0 0 6px; letter-spacing: 1px; }
header h1 b { color: var(--accent); }
#install {
  font-family: inherit; font-size: 13px; vertical-align: middle; margin-left: 12px;
  cursor: pointer; color: var(--bg); background: var(--accent); border: 0;
  border-radius: 6px; padding: 5px 12px; letter-spacing: 0;
}
#install:hover { background: #7f8; }
header p { color: var(--dim); margin: 0 0 36px; line-height: 1.5; }

/* ---- home page: the plain exhibit list ---- */
.wrap.home { max-width: 620px; }
.home-head { display: flex; align-items: center; gap: 10px; margin: 0 0 24px; }
/* The title scales with the viewport and may wrap, and min-width:0 lets it
   shrink past its content so the "?" button never pushes off a phone. */
.home-head h1 { flex: 1 1 auto; min-width: 0; margin: 0; font-size: clamp(21px, 6vw, 30px); }
.infobtn {
  flex: 0 0 auto; width: 30px; height: 30px; padding: 0; cursor: pointer;
  font-family: inherit; font-size: 15px; line-height: 1;
  color: var(--dim); background: transparent;
  border: 1px solid var(--line); border-radius: 50%;
  transition: border-color .15s, color .15s;
}
.infobtn:hover { color: var(--fg); border-color: var(--accent); }
.mudlist {
  list-style: none; margin: 0; padding: 0; overflow: hidden;
  border: 1px solid var(--line); border-radius: 10px; background: var(--panel);
}
.mudrow { display: flex; align-items: center; gap: 14px; padding: 10px 16px; }
.mudrow + .mudrow { border-top: 1px solid var(--line); }
.mudrow:hover { background: #141414; }
.mudrow .mud-name { font-size: 15px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mudrow .leader { flex: 1 1 12px; min-width: 12px; border-bottom: 1px dotted #333; }
/* Quiet per-row link to the engine source; Play keeps the visual weight. */
.mudrow .srclink { flex: 0 0 auto; font-size: 12px; color: var(--dim); }
.mudrow .srclink:hover { color: var(--link); }
.mudrow .btn.play { flex: 0 0 auto; font-size: 12px; padding: 7px 16px; }
.mudrow.soon { opacity: .55; }
.mudrow.loading { color: var(--dim); justify-content: center; padding: 18px 16px; }
@media (pointer: coarse) { .mudrow { padding: 12px 14px; } .mudrow .btn.play { padding: 10px 18px; } }
/* footer links (About / Family tree) */
.home-links { margin: 0 0 6px; }
.home-links a { color: var(--link); }

/* ---- about page (about.html) ---- */
.wrap.about { max-width: 720px; }
.about .back { margin: 0 0 8px; font-size: 13px; }
.about h1 { font-size: 26px; margin: 6px 0 10px; letter-spacing: .5px; }
.about h1, .about h1 b { color: var(--accent); }
.about .lede { color: var(--dim); margin: 0 0 26px; line-height: 1.65; }
.about h2 { font-size: 16px; color: var(--accent); margin: 30px 0 8px; letter-spacing: .3px; }
.about p { color: #cfcfcf; line-height: 1.7; margin: 0 0 13px; font-size: 14px; }
.about a { color: var(--link); }
.about code { color: var(--fg); background: #161616; border: 1px solid var(--line); border-radius: 4px; padding: 0 4px; font-size: 12.5px; }
/* a code token that is itself a link reads as a link, not plain code */
.about a code { color: var(--link); cursor: pointer; }
.about .foot { margin-top: 30px; padding-top: 16px; border-top: 1px solid var(--line); color: var(--dim); font-size: 13px; }

.grid { display: grid; gap: 18px; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); }
.card {
  display: flex; flex-direction: column;
  border: 1px solid var(--line); border-radius: 10px;
  background: var(--panel); padding: 18px 18px 16px; color: inherit;
  transition: border-color .15s;
}
.card:hover { border-color: #2c2c2c; }
.card.soon { opacity: .55; }
.card .name { font-size: 19px; color: var(--accent); }
.card .edition { font-size: 12px; color: var(--dim); margin: 2px 0 10px; }
.card .edition-link { color: var(--link); }
.card .edition-link:hover { text-decoration: underline; }
.card .blurb { font-size: 13px; line-height: 1.5; color: #bdbdbd; }
.card .card-note { font-size: 11px; color: #c97; margin-top: 8px; line-height: 1.45; }
.card .tags { margin-top: 12px; display: flex; gap: 6px; flex-wrap: wrap; }
.card .tags span { font-size: 11px; color: var(--dim); border: 1px solid var(--line); border-radius: 999px; padding: 2px 8px; }
.card .card-actions { margin-top: auto; padding-top: 16px; display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
/* Compact buttons so Play / History / Resources fit on one row in a card. */
.card .card-actions .btn { font-size: 12px; padding: 6px 9px; gap: 4px; }

/* shared button used on the cards (and modals) */
.btn {
  font-family: inherit; font-size: 13px; line-height: 1; cursor: pointer;
  color: var(--fg); background: #161616; border: 1px solid var(--line);
  border-radius: 6px; padding: 8px 13px; text-decoration: none;
  display: inline-flex; align-items: center; gap: 6px;
  transition: border-color .15s, background .15s;
}
.btn:hover { border-color: var(--accent); background: #1d1d1d; text-decoration: none; }
.btn.play { color: var(--bg); background: var(--accent); border-color: var(--accent); font-weight: bold; }
.btn.play:hover { background: #7f8; border-color: #7f8; }
.btn.disabled, .btn.play.disabled { opacity: .5; pointer-events: none; }

/* modal body content (history / resources) */
.modal-body { font-size: 14px; line-height: 1.6; color: #cfcfcf; }
.modal-body p { margin: 0 0 12px; }
.modal-body .hist p:first-child { margin-top: 0; }
.modal-body .modal-foot { margin: 14px 0 0; }
.modal-body .modal-foot a, .modal-body .res-list a { color: var(--link); }
.modal-body .modal-foot a:hover, .modal-body .res-list a:hover { text-decoration: underline; }
.modal-body .modal-attrib { font-size: 11px; color: var(--dim); margin: 14px 0 0; }
.modal-body .res-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 12px; }
.modal-body .res-list a { font-size: 14px; }
footer { margin-top: 48px; color: var(--dim); font-size: 12px; line-height: 1.6; }

/* Build/version indicator: footer line on the landing page, and a line at the
   bottom of the client's Settings modal.  Deliberately quiet -- it's a dev aid. */
.build-info { font-size: 11px; color: var(--dim); opacity: .75; }
.build-info.stale { color: #d99a3c; opacity: 1; }
.build-info b { font-weight: 600; }
.build-info a, .build-info button {
  color: var(--link, #6cae6c); background: none; border: 0; padding: 0;
  font: inherit; cursor: pointer; text-decoration: underline;
}
.modal .build-info { margin: 14px 0 0; text-align: center; }

/* ---- player page ---- */
/* Fill exactly the *visible* viewport: a fixed-height bar on top and a terminal
   that fills the rest, with the body shrunk to visualViewport.height (set from
   JS) so the on-screen keyboard can't overlap the input -- the input sits at the
   body's bottom edge, just above the keyboard.  Normal flow (no position:fixed)
   keeps the width pinned to the device on iOS, where a fixed width:100% can
   resolve to a wider layout viewport and push text off-screen.  The page never
   scrolls; only the terminal scrolls internally. */
body.player {
  height: 100vh; height: 100dvh; height: var(--app-h, 100dvh);
  width: 100%; max-width: 100%;
  display: flex; flex-direction: column;
  overflow: hidden; overscroll-behavior: none;
}
#bar {
  flex: 0 0 auto; position: relative;
  padding: 6px 12px; font-size: 13px; color: #8a8;
  border-bottom: 1px solid var(--line); background: var(--panel);
  display: flex; align-items: center; gap: 8px 12px;
}
.bartitle { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#bar b { color: var(--accent); }
#bar .right, #status { font-size: 12px; color: var(--dim); }
#status { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.barright { display: flex; align-items: center; flex-wrap: wrap; justify-content: flex-end; gap: 8px 10px; }
#bar .barright button { margin: 0; }      /* neutralise the landing #install margin here */
/* Hamburger that collapses the bar controls on narrow screens (shown via @media). */
#menutoggle {
  display: none; flex: 0 0 auto; font: 18px/1 inherit;
  color: var(--fg); background: #161616; border: 1px solid var(--line);
  border-radius: 6px; padding: 4px 11px; cursor: pointer;
}
#menutoggle:hover { border-color: var(--accent); }
/* "Last saved …" indicator: a link-styled button that opens the save log. */
.savedlink { font-family: inherit; font-size: 12px; color: var(--dim); background: none; border: 0; cursor: pointer; padding: 0; margin-left: -8px; }
.savedlink:hover { color: var(--accent); text-decoration: underline; }
#term { flex: 1 1 auto; min-height: 0; min-width: 0; overflow-x: hidden; padding: 6px; }

/* ---- buttons ---- */
.barright button, .modal button, .fb-panel button {
  font-family: inherit; font-size: 12px; cursor: pointer;
  color: var(--fg); background: #161616; border: 1px solid var(--line);
  border-radius: 6px; padding: 4px 10px; transition: border-color .15s, background .15s;
}
.barright button:hover, .modal button:hover, .fb-panel button:hover { border-color: var(--accent); background: #1d1d1d; }
.modal button.primary { color: var(--bg); background: var(--accent); border-color: var(--accent); }
.modal button.primary:hover { background: #7f8; border-color: #7f8; }
.modal button.danger, .fb-panel button.danger { color: #f88; border-color: #532; }
.modal button.danger:hover, .fb-panel button.danger:hover { border-color: #f55; background: #221414; }
.modal button:disabled, .fb-panel button:disabled { opacity: .45; cursor: default; border-color: var(--line); background: #161616; }

/* ---- save-management modal ---- */
.modal-backdrop {
  position: fixed; inset: 0; z-index: 50; background: rgba(0,0,0,.65);
  display: flex; align-items: center; justify-content: center; padding: 16px;
}
.modal {
  position: relative;
  width: min(540px, 94vw); background: var(--panel);
  border: 1px solid var(--accent); border-radius: 10px; padding: 20px 22px;
  box-shadow: 0 12px 40px rgba(0,0,0,.6);
  max-height: calc(100dvh - 32px); overflow-y: auto;
}
.modal h2 { margin: 0 0 4px; padding-right: 26px; font-size: 18px; color: var(--accent); letter-spacing: .5px; }
/* Top-right "×" close affordance, injected by modal-close.js. The extra
   specificity (button.modal-x) is needed to beat the generic .modal button. */
.modal button.modal-x {
  position: absolute; top: 11px; right: 12px; z-index: 1;
  width: 30px; height: 30px; padding: 0; margin: 0;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 21px; line-height: 1; color: var(--dim);
  background: transparent; border: 1px solid transparent; border-radius: 8px;
}
.modal button.modal-x:hover { color: var(--fg); background: #1a1a1a; border-color: var(--line); }
.modal .sub { margin: 0 0 16px; font-size: 12px; color: var(--dim); }
.modal dl { margin: 0 0 18px; display: grid; grid-template-columns: auto 1fr; gap: 6px 16px; font-size: 13px; }
.modal dt { color: var(--dim); }
.modal dd { margin: 0; color: var(--fg); word-break: break-all; text-align: right; }
.modal .actions { display: flex; flex-wrap: wrap; gap: 10px; }
.modal .actions .spacer { flex: 1; }
.modal .form { margin: 0 0 18px; display: flex; flex-direction: column; gap: 2px; }
.modal .frow {
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; padding: 7px 0; border-bottom: 1px solid var(--line); font-size: 13px;
}
.modal .frow:last-child { border-bottom: 0; }
.modal .frow > span { color: var(--dim); }
.modal .frow select, .modal .frow input[type=number] {
  font-family: inherit; font-size: 13px; color: var(--fg);
  background: #161616; border: 1px solid var(--line); border-radius: 6px;
  padding: 4px 8px; min-width: 0;
}
.modal .frow select { max-width: 60%; }
.modal .frow input[type=number] { width: 72px; text-align: right; }
.modal .frow input[type=checkbox] { width: 16px; height: 16px; accent-color: var(--accent); cursor: pointer; }
.modal .frow input[type=range] { flex: 0 0 auto; width: 55%; accent-color: var(--accent); cursor: pointer; }

/* Collapsible settings groups -- keep the (long) settings list scannable. */
.modal .sgroup { border: 1px solid var(--line); border-radius: 8px; margin: 0 0 8px; background: #0d0d0d; overflow: hidden; }
.modal .sgroup > summary {
  list-style: none; cursor: pointer; user-select: none; padding: 10px 12px;
  font-size: 13px; color: var(--accent);
  display: flex; align-items: center; justify-content: space-between;
}
.modal .sgroup > summary::-webkit-details-marker { display: none; }
.modal .sgroup > summary::after { content: '\25B8'; color: var(--dim); transition: transform .15s ease; }
.modal .sgroup[open] > summary::after { transform: rotate(90deg); }
.modal .sgroup-body { padding: 0 12px 8px; }
.modal .sgroup-body .form { margin: 0; }
.modal .sgroup-body .login-editor, .modal .sgroup-body .quick-editor { margin-top: 8px; }
.modal .sgroup-body .moo-save { margin-top: 8px; border-top: 0; padding-top: 0; }

/* ---- file browser / editor overlay ---- */
/* A near-full-viewport workspace: a narrow file tree on the left and an editor
   that takes all the remaining width/height.  The tree is sized to fit names,
   not to claim a third of the panel, so the editor gets the space. */
.fb-panel {
  width: min(1100px, 96vw); height: min(92vh, 860px);
  background: var(--panel); border: 1px solid var(--accent); border-radius: 10px;
  display: flex; flex-direction: column; box-shadow: 0 12px 40px rgba(0,0,0,.6);
}
.fb-head { display: flex; align-items: center; gap: 8px; padding: 12px 16px; border-bottom: 1px solid var(--line); }
.fb-head b { color: var(--accent); }
.fb-head .fb-sub { font-size: 12px; color: var(--dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.fb-head .spacer { flex: 1; }
.fb-body { flex: 1; display: flex; min-height: 0; }
.fb-tree {
  flex: 0 0 240px; width: 240px; overflow: auto; border-right: 1px solid var(--line);
  padding: 6px 0; font-size: 13px; background: #0c0c0c;
}
.fb-row { padding: 3px 8px; cursor: pointer; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.fb-row:hover { background: #1a1a1a; }
.fb-dir { color: var(--dim); }
.fb-file { color: var(--fg); }
.fb-file.sel { background: #234; color: #fff; }
.fb-edit { flex: 1; display: flex; flex-direction: column; min-width: 0; padding: 12px 14px; gap: 10px; }
.fb-path { font-size: 12px; color: var(--dim); word-break: break-all; }
.fb-text {
  flex: 1; resize: none; font-family: ui-monospace, Menlo, Consolas, monospace;
  font-size: 13px; line-height: 1.45;
  color: var(--fg); background: #0c0c0c; border: 1px solid var(--line); border-radius: 6px;
  padding: 10px 12px; white-space: pre; overflow: auto; tab-size: 4;
}
.fb-text:disabled { opacity: .5; }
/* Empty editor: center the "pick a file" hint instead of stranding it at top. */
.fb-text:disabled:placeholder-shown { text-align: center; }
.fb-bin { flex: 1; display: flex; align-items: center; justify-content: center; text-align: center;
  color: var(--dim); font-size: 13px; border: 1px dashed var(--line); border-radius: 6px; padding: 16px; }
/* The display:flex above would otherwise beat the `hidden` attribute and leave
   an empty placeholder box wasting half the editor whenever a text file is open. */
.fb-bin[hidden] { display: none; }
.fb-actions { display: flex; flex-wrap: wrap; gap: 8px; }
.fb-actions .spacer { flex: 1; }
.fb-note { font-size: 12px; color: var(--dim); min-height: 1em; }
.fb-note.warn { color: #f88; }
@media (max-width: 560px) {
  .fb-panel { width: 96vw; height: 92vh; }
  .fb-body { flex-direction: column; }
  .fb-tree { flex: 0 0 34%; width: auto; max-height: 34%; border-right: 0; border-bottom: 1px solid var(--line); }
}
.modal .note { margin: 14px 0 0; font-size: 11px; color: var(--dim); line-height: 1.5; }
.modal .note.warn { color: #c97; }

/* ---- editable login (replay) sequence ---- */
.modal .login-editor { margin: 14px 0 0; display: flex; flex-direction: column; gap: 8px; }
.modal .login-editor.off { opacity: .45; }
.modal .le-label { font-size: 11px; color: var(--dim); line-height: 1.5; }
.modal .login-seq {
  font-family: inherit; font-size: 13px; line-height: 1.5; color: var(--fg);
  background: #0c0c0c; border: 1px solid var(--line); border-radius: 6px;
  padding: 8px; resize: vertical; min-height: 92px; white-space: pre; overflow: auto; tab-size: 4;
}
.modal .login-seq:disabled { cursor: default; }
.modal .le-row { display: flex; align-items: center; gap: 8px; font-size: 12px; color: var(--dim); }
.modal .le-row input[type=number] {
  font-family: inherit; font-size: 13px; color: var(--fg);
  background: #161616; border: 1px solid var(--line); border-radius: 6px;
  padding: 4px 8px; width: 84px; text-align: right;
}

/* ---- InfernoMOO saving section ---- */
.modal .moo-save { margin: 16px 0 0; padding-top: 14px; border-top: 1px solid var(--line); display: flex; flex-direction: column; gap: 8px; }
.modal .ms-title { font-size: 13px; color: var(--accent); letter-spacing: .3px; }
.modal .ms-row { display: flex; align-items: center; gap: 12px; }
.modal .ms-when { font-size: 11px; color: var(--dim); }
.modal .ms-num { color: var(--dim); font-size: 12px; display: inline-flex; align-items: center; gap: 6px; }
.modal .ms-num input[type=number] {
  font-family: inherit; font-size: 13px; color: var(--fg);
  background: #161616; border: 1px solid var(--line); border-radius: 6px;
  padding: 4px 8px; width: 64px; text-align: right;
}
.modal .ms-hint { font-size: 11px; color: var(--dim); margin-top: -2px; }
.modal .ms-log-label { font-size: 11px; color: var(--dim); margin-top: 6px; }
.modal .ms-log {
  display: flex; flex-direction: column; gap: 1px; max-height: 168px; overflow: auto;
  font-size: 12px; background: #0c0c0c; border: 1px solid var(--line); border-radius: 6px; padding: 6px 8px;
}
.modal .ms-le { display: grid; grid-template-columns: 64px 1fr auto; gap: 10px; padding: 1px 0; }
.modal .ms-le.bad { color: #f88; }
.modal .ms-t { color: var(--dim); }
.modal .ms-r { color: var(--fg); }
.modal .ms-d { color: var(--dim); text-align: right; }
.modal .ms-empty { color: var(--dim); }

/* --- MUD client (beta): HTML scrollback + separate input line ---------- */
/* Rendered inside #term when the "MUD client" front-end is selected.       */
#term.mudpane { position: relative; display: flex; flex-direction: column; min-width: 0; background: var(--mp-bg, #0b0b0b); }
.mudpane-out {
  flex: 1 1 auto; min-height: 0; min-width: 0; max-width: 100%; overflow-y: auto; overflow-x: hidden;
  white-space: pre-wrap; overflow-wrap: anywhere; word-break: break-word;
  color: var(--mp-fg, #33ff66);
  font-family: var(--mp-font, ui-monospace, Menlo, Consolas, monospace);
  font-size: var(--mp-fontsize, 15px); line-height: 1.3;
  padding: 2px 6px 6px 2px;
  /* Smooth momentum scrolling on iOS, and keep scroll/refresh gestures inside
     the pane instead of bouncing the page or triggering pull-to-refresh. */
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
  /* Allow one-finger vertical scroll, but reserve multi-finger gestures (pinch
     to zoom text / two-finger swipe to move) for the JS handler instead of the
     browser's page zoom. */
  touch-action: pan-y;
}
.mudpane-out a { color: var(--mp-link, #7db4ff); text-underline-offset: 2px; }
.mudpane-out ::selection, .mudpane-input::selection { background: var(--mp-sel, #264f30); }
.mudpane-inbar {
  flex: 0 0 auto; display: flex; align-items: center; gap: 8px;
  border-top: 1px solid var(--mp-line, var(--line)); padding: 6px 2px 2px;
}
.mudpane-prompt {
  color: var(--mp-accent, var(--accent)); opacity: .8; user-select: none;
  font-family: var(--mp-font, ui-monospace, monospace);
  font-size: var(--mp-fontsize, 15px);
}
.mudpane-input {
  flex: 1 1 auto; min-width: 0; background: transparent; border: 0; outline: 0;
  color: var(--mp-fg, #33ff66); caret-color: var(--mp-accent, var(--accent));
  font-family: var(--mp-font, ui-monospace, monospace);
  font-size: var(--mp-fontsize, 15px); padding: 4px 2px;
}
/* Password masking without a real type="password" field.  Using the native
   password type makes the browser treat the command line as a login field --
   it pops the "Passwords" autofill hint, offers to save, and password managers
   inject their own UI.  Instead the input stays type="text" (so none of that
   fires) and we hide the glyphs as dots with text-security when masking.
   Supported in Chrome/Edge/Safari and Firefox 118+; older Firefox simply shows
   the typed characters, which is no worse than a plain echo. */
.mudpane-input.masked {
  -webkit-text-security: disc;
  text-security: disc;
}
/* On-screen input-bar buttons: ▲/▼ history (outline) + ⏎ send (filled). */
.mudpane-histbtn, .mudpane-sendbtn {
  flex: 0 0 auto; display: flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; padding: 0; border-radius: 8px;
  font-size: 14px; line-height: 1; cursor: pointer;
  -webkit-tap-highlight-color: transparent; user-select: none;
}
.mudpane-histbtn {
  background: transparent; color: var(--mp-accent, var(--accent));
  border: 1px solid var(--mp-line, var(--line)); opacity: .85;
}
.mudpane-histbtn:hover { opacity: 1; border-color: var(--mp-accent, var(--accent)); }
.mudpane-histbtn:active { background: rgba(128, 128, 128, .2); opacity: 1; }
/* ⏎ send is the primary action -- filled accent so it reads as the button. */
.mudpane-sendbtn {
  background: var(--mp-accent, var(--accent)); color: var(--mp-accent-text, var(--bg));
  border: 1px solid var(--mp-accent, var(--accent)); font-size: 16px; font-weight: bold;
}
.mudpane-sendbtn:active { opacity: .8; }
/* Silhouette: the last command, ghosted, while the input is empty. */
.mudpane-input::placeholder { color: var(--mp-fg, #33ff66); opacity: .3; font-style: italic; }

/* ---- movement compass ------------------------------------------------ */
/* A translucent D-pad floating over the bottom-right of the scrollback (its
   `bottom` is set from JS to clear the input bar).  Idle it's semi-transparent
   so text reads through; it firms up on hover / touch.  Collapses to a small
   ⌖ launcher so it never permanently blocks the view. */
.mudpane-compass {
  position: absolute; right: 8px; z-index: 6;
  display: flex; align-items: flex-end; gap: 6px;
  padding: 8px 8px 6px; border-radius: 12px;
  background: color-mix(in srgb, var(--mp-bg, #0b0b0b) 60%, transparent);
  border: 1px solid var(--mp-line, var(--line)); backdrop-filter: blur(2px);
  opacity: var(--mp-compass-op, .55); transition: opacity .15s ease;
  -webkit-tap-highlight-color: transparent; user-select: none; touch-action: none;
}
/* Buttons default to touch-action:auto; force none so a drag on one is handed
   to our scroll-forwarding handler instead of the browser. */
.mudpane-compass button, .mudpane-compass-open { touch-action: none; }
/* Firm up while pressed.  Only brighten on :hover for devices that actually
   hover -- on touch, :hover sticks after a tap and would leave the pad opaque. */
.mudpane-compass:active { opacity: 1; }
@media (hover: hover) {
  .mudpane-compass:hover, .mudpane-compass:focus-within { opacity: 1; }
}
.cmp-grid {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 4px;
}
.cmp-vert { display: grid; grid-auto-rows: 1fr; gap: 4px; align-self: stretch; }
.cmp-btn {
  display: flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; padding: 0; border-radius: 7px;
  font-size: 16px; line-height: 1; cursor: pointer;
  background: transparent; color: var(--mp-accent, var(--accent));
  border: 1px solid var(--mp-line, var(--line)); opacity: .9;
  -webkit-tap-highlight-color: transparent;
}
.cmp-btn:hover { opacity: 1; border-color: var(--mp-accent, var(--accent)); }
.cmp-btn:active { background: rgba(128, 128, 128, .25); opacity: 1; }
.cmp-look { color: var(--mp-fg, #33ff66); opacity: .7; font-size: 14px; }
.cmp-blank { width: 32px; height: 32px; }         /* empty ring cell (no such exit) */
.cmp-vbtn { width: 32px; height: 100%; }
/* × handle to collapse the pad, tucked into its top-right corner. */
.cmp-hide {
  position: absolute; top: -8px; right: -8px;
  width: 20px; height: 20px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 13px; line-height: 1; cursor: pointer;
  background: var(--mp-bg, #0b0b0b); color: var(--mp-fg, #33ff66);
  border: 1px solid var(--mp-line, var(--line)); opacity: .85;
}
.cmp-hide:hover { opacity: 1; border-color: var(--mp-accent, var(--accent)); }
/* Collapsed launcher: a small pill in the corner. */
.mudpane-compass-open {
  position: absolute; right: 8px; z-index: 6;
  width: 36px; height: 36px; padding: 0; border-radius: 10px;
  display: flex; align-items: center; justify-content: center;
  font-size: 18px; line-height: 1; cursor: pointer;
  color: var(--mp-accent, var(--accent));
  background: color-mix(in srgb, var(--mp-bg, #0b0b0b) 60%, transparent);
  border: 1px solid var(--mp-line, var(--line)); backdrop-filter: blur(2px);
  opacity: var(--mp-compass-op, .55); transition: opacity .15s ease; -webkit-tap-highlight-color: transparent;
}
.mudpane-compass-open:active { opacity: 1; }
@media (hover: hover) { .mudpane-compass-open:hover { opacity: 1; } }
.mudpane-compass.hidden, .mudpane-compass-open.hidden { display: none; }

/* ---- quick-command bar ----------------------------------------------- */
/* A thin, horizontally-scrollable strip of verb chips just above the input.
   In normal flow (not an overlay), so it never covers scrollback. */
.mudpane-quickbar {
  flex: 0 0 auto; display: flex; align-items: center; gap: 6px;
  padding: 5px 6px; border-top: 1px solid var(--mp-line, var(--line));
  overflow-x: auto; overflow-y: hidden; white-space: nowrap;
  scrollbar-width: thin; -webkit-overflow-scrolling: touch; overscroll-behavior-x: contain;
}
.mudpane-quickbar.hidden { display: none; }
.qb-btn {
  flex: 0 0 auto; font-family: inherit; font-size: 12px; line-height: 1; cursor: pointer;
  color: var(--mp-fg, var(--fg)); background: var(--mp-chip, #161616);
  border: 1px solid var(--mp-line, var(--line));
  border-radius: 999px; padding: 6px 12px;
  -webkit-tap-highlight-color: transparent; user-select: none;
}
.qb-btn:hover { border-color: var(--mp-accent, var(--accent)); }
.qb-btn:active { background: rgba(128, 128, 128, .25); }
.qb-fill { border-style: dashed; }        /* chips that prefill the input rather than fire */

/* Settings: the editable quick-command list. */
.quick-editor { margin-top: 4px; }
.quick-editor .qe-label { font-size: 12px; color: var(--dim); line-height: 1.5; margin-bottom: 6px; }
.quick-editor .qe-label code { color: var(--fg); background: #161616; border: 1px solid var(--line); border-radius: 4px; padding: 0 4px; }
.quick-seq {
  width: 100%; box-sizing: border-box; resize: vertical;
  font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 13px;
  color: var(--fg); background: #0d0d0d; border: 1px solid var(--line);
  border-radius: 6px; padding: 8px;
}

/* Long-press chip editor (a small dialog). */
.qb-edit-back {
  position: fixed; inset: 0; z-index: 60; background: rgba(0,0,0,.6);
  display: flex; align-items: center; justify-content: center; padding: 16px;
}
.qb-edit {
  width: min(360px, 92vw); background: var(--panel);
  border: 1px solid var(--accent); border-radius: 10px; padding: 16px 18px;
  box-shadow: 0 12px 40px rgba(0,0,0,.6);
}
.qbe-title { font-size: 15px; color: var(--accent); margin-bottom: 12px; }
.qbe-row { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.qbe-row span { flex: 0 0 68px; font-size: 13px; color: var(--dim); }
.qbe-row input {
  flex: 1 1 auto; min-width: 0; font-family: inherit; font-size: 14px;
  color: var(--fg); background: #0d0d0d; border: 1px solid var(--line);
  border-radius: 6px; padding: 7px 8px;
}
.qbe-hint { font-size: 11px; color: var(--dim); line-height: 1.5; margin: 2px 0 12px; }
.qbe-hint code { color: var(--fg); background: #161616; border: 1px solid var(--line); border-radius: 4px; padding: 0 4px; }
.qbe-actions { display: flex; align-items: center; gap: 6px; }
.qbe-actions .qbe-spacer { flex: 1 1 auto; }
.qbe-move { min-width: 34px; }
.qbe-del { color: #f88; border-color: #532 !important; }
.qbe-del:hover { border-color: #f55 !important; background: #221414 !important; }

/* ---- mobile / touch tuning ------------------------------------------- */
@media (pointer: coarse) {
  /* Some browsers auto-zoom the page when a focused input's font is < 16px and
     stay zoomed (pushing text off-screen on the main view).  Force every form
     control to >= 16px on touch so focusing one never jump-zooms. */
  input, textarea, select { font-size: 16px; }
  .mudpane-input { font-size: max(16px, var(--mp-fontsize, 15px)); padding: 8px 2px; }
  .mudpane-inbar { padding: 8px 4px 4px; }
  /* 44px tap targets (Apple HIG / Material minimum) on touch. */
  .mudpane-histbtn, .mudpane-sendbtn { width: 44px; height: 44px; font-size: 16px; }
  .mudpane-sendbtn { width: 52px; }   /* primary action, a touch wider */
  /* Bigger compass hit targets on touch; sits a touch higher / brighter so a
     thumb can find it, and firms up while the pad is being used. */
  .cmp-btn { width: 42px; height: 42px; font-size: 19px; }
  .cmp-look { font-size: 16px; }
  .cmp-blank, .cmp-vbtn { width: 42px; }
  /* On touch there's no hover, so a press firms the pad to full opacity (idle
     opacity itself is the user's Compass-opacity setting). */
  .mudpane-compass:active, .mudpane-compass-open:active { opacity: 1; }
  .mudpane-compass-open { width: 44px; height: 44px; font-size: 20px; }
  /* Roomier quick-command chips on touch. */
  .qb-btn { font-size: 14px; padding: 9px 15px; }
}
/* Narrow screens: collapse the bar's controls into a tap-to-open dropdown (the
   ☰ button) so they don't eat several rows of the already-short viewport. */
@media (max-width: 720px) {
  #bar { padding: 6px 10px; font-size: 12px; }
  #bar #edition { display: none; }
  #menutoggle { display: inline-flex; align-items: center; }
  .barright {
    position: absolute; top: 100%; left: 6px; right: 6px;
    flex-direction: column; align-items: stretch; flex-wrap: nowrap; gap: 6px;
    margin: 0; padding: 8px;
    background: var(--panel); border: 1px solid var(--line); border-top: 0;
    border-radius: 0 0 10px 10px; box-shadow: 0 10px 28px rgba(0,0,0,.55);
    z-index: 40; display: none;
  }
  #bar.open .barright { display: flex; }
  #bar .barright button { width: 100%; justify-content: flex-start; padding: 11px 12px; font-size: 14px; }
  .barright .savedlink { padding: 8px 12px; text-align: left; }
  #term { padding: 4px; }
}

/* ===========================================================================
 * Family-tree page (tree.html) -- an interactive genealogy of the MUD family.
 * Built to read well on a phone (vertical, tap-to-expand, modest indentation)
 * and to spread out on a desktop, instead of one giant static tree image.
 * ========================================================================= */
.tree-page .wrap { max-width: 1040px; }
.tree-intro { color: var(--dim); margin: 0 0 14px; line-height: 1.5; }
.tree-intro a { color: var(--link); }
/* citation block: where the lineage/timeline comes from */
.tree-sources {
  margin: 0 0 22px; padding: 11px 14px; font-size: 12px; line-height: 1.6;
  color: var(--dim); background: #0e0e0e; border: 1px solid var(--line); border-radius: 8px;
}
.tree-sources a { color: var(--link); white-space: nowrap; }

/* toolbar: search + expand/collapse + legend */
.tree-tools { display: flex; flex-wrap: wrap; gap: 10px 14px; align-items: center; margin: 0 0 18px; }
.tree-search {
  flex: 1 1 220px; min-width: 0; font-family: inherit; font-size: 14px;
  color: var(--fg); background: #0c0c0c; border: 1px solid var(--line);
  border-radius: 8px; padding: 9px 12px;
}
.tree-search:focus { outline: none; border-color: var(--accent); }
.tree-search::placeholder { color: var(--dim); }
.tree-tools .btn { font-size: 12px; padding: 7px 11px; }
.tree-count { font-size: 12px; color: var(--dim); flex: 0 0 auto; }

/* family legend -- also clickable filters */
.tree-legend { display: flex; flex-wrap: wrap; gap: 6px 8px; margin: 0 0 20px; }
.legend-item {
  display: inline-flex; align-items: center; gap: 6px; cursor: pointer;
  font-size: 11px; color: var(--dim); background: #121212;
  border: 1px solid var(--line); border-radius: 999px; padding: 3px 10px 3px 8px;
  transition: border-color .15s, color .15s, opacity .15s;
}
.legend-item:hover { border-color: #2c2c2c; color: #bbb; }
.legend-item.off { opacity: .4; }
.legend-item .dot { width: 9px; height: 9px; border-radius: 50%; flex: 0 0 auto; }

/* the tree itself: nested lists with guide lines */
.tree-root, .tree-root ul {
  list-style: none; margin: 0; padding: 0;
}
.tree-root ul {
  margin-left: 9px; padding-left: 12px;
  border-left: 1px solid var(--line);
}
@media (min-width: 720px) { .tree-root ul { margin-left: 13px; padding-left: 18px; } }
/* The commercial branch runs on proprietary engines that don't share source
   code with the open tree, so its connectors are dashed to read as a parallel
   "influence" lineage rather than solid code-descent. */
.tree-node[data-fam="commercial"] > ul { border-left-style: dashed; border-left-color: #5a4a22; }
.tree-node { margin: 2px 0; }
.tree-node.hidden { display: none; }

/* Each node is a native <details>: the <summary> is the clickable row and the
   body holds its history and links, so the whole tree is real HTML that opens
   and reads with JavaScript off. */
.node-detail { margin: 0; }
.node-detail > summary { list-style: none; }
.node-detail > summary::-webkit-details-marker { display: none; }

/* a node's clickable row */
.node-row {
  display: flex; align-items: center; gap: 7px;
  border: 1px solid transparent; border-radius: 8px;
  padding: 5px 8px; cursor: pointer; min-width: 0;
  transition: background .12s, border-color .12s;
}
.node-row:hover { background: #141414; border-color: var(--line); }
.node-row.match, .node-detail[open] > .node-row { border-color: var(--accent); background: #14180f; }
/* detail body carries the .modal-body class for its prose styles; indent it
   under the row and keep it in the node's family column. */
.node-detail-body { margin: 2px 0 10px; padding: 2px 8px 2px 30px; font-size: 13px; }
.node-detail-body .hist p:first-child { margin-top: 0; }

/* child-collapse chevron (a JS enhancement). A leaf gets an invisible spacer. */
.node-toggle {
  flex: 0 0 auto; width: 18px; height: 18px; padding: 0; margin: 0;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 10px; line-height: 1; color: var(--dim);
  background: transparent; border: 0; cursor: pointer; user-select: none;
  transition: transform .12s, color .12s;
}
.node-toggle:hover { color: var(--accent); }
.node-toggle.leaf { visibility: hidden; cursor: default; }
.tree-node.collapsed > .node-detail > .node-row .node-toggle { transform: rotate(-90deg); }
.tree-node.collapsed > ul { display: none; }

.node-dot { flex: 0 0 auto; width: 9px; height: 9px; border-radius: 50%; }
.node-name { color: var(--fg); font-size: 14px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.node-year { flex: 0 0 auto; font-size: 11px; color: var(--dim); }
.node-badges { flex: 0 0 auto; display: inline-flex; gap: 5px; }
.node-badge {
  font-size: 10px; line-height: 1.4; padding: 0 6px; border-radius: 999px;
  border: 1px solid var(--line); white-space: nowrap;
}
.node-badge.play { color: var(--bg); background: var(--accent); border-color: var(--accent); font-weight: bold; }
.node-badge.live { color: #6cf; border-color: #245; }
.node-childcount { flex: 0 0 auto; font-size: 10px; color: #555; }

/* footer "Send a correction" link-styled button + the form it opens */
.linkbtn {
  font-family: inherit; font-size: inherit; color: var(--link);
  background: none; border: 0; padding: 0; cursor: pointer;
}
.linkbtn:hover { text-decoration: underline; }
.modal .correction { display: flex; flex-direction: column; gap: 13px; margin: 4px 0 0; }
.modal .cf-label { display: block; font-size: 12px; color: var(--dim); line-height: 1.9; }
.modal .cf-opt { color: #555; }
.modal .cf-input {
  display: block; width: 100%; font-family: inherit; font-size: 14px; color: var(--fg);
  background: #0c0c0c; border: 1px solid var(--line); border-radius: 6px; padding: 8px 10px;
}
.modal .cf-input:focus { outline: none; border-color: var(--accent); }
.modal .cf-text { min-height: 92px; resize: vertical; line-height: 1.5; }
.modal .cf-actions { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-top: 2px; }
.modal .cf-note { font-size: 12px; color: var(--dim); }

/* modal extras specific to the tree's node detail */
.modal-body .node-meta { margin: 0 0 12px; font-size: 12px; color: var(--dim); line-height: 1.5; }
.modal-body .node-meta b { color: var(--fg); font-weight: normal; }
.modal-body .node-lineage { margin: 0 0 14px; font-size: 12px; color: var(--dim); }
.modal-body .node-lineage a { color: var(--link); cursor: pointer; }
.modal-body .node-lineage .sep { color: #555; padding: 0 4px; }
.modal-body .res-group { margin: 14px 0 0; }
.modal-body .res-group h3 {
  font-size: 11px; letter-spacing: .5px; text-transform: uppercase;
  color: var(--dim); margin: 0 0 7px; font-weight: normal;
}
.modal-body .play-row { margin: 16px 0 0; }
.modal-body .btn.play { font-size: 13px; }
.modal-body .uncertain-note { margin: 14px 0 0; font-size: 11px; color: #c97; line-height: 1.5; }

/* Centered, non-interactive heads-up overlay for transient states (booting,
   downloading, saving, reconnecting).  pointer-events:none -> it never takes
   focus or blocks the MUD underneath; the player can keep typing/scrolling. */
.mud-status-overlay {
  position: fixed; left: 50%; top: 42%; transform: translate(-50%, -50%);
  display: flex; align-items: center; gap: 11px;
  max-width: min(90vw, 460px);
  padding: 13px 20px;
  background: rgba(14, 16, 20, .9); color: #e8edf4;
  border: 1px solid var(--line, #2b313b); border-radius: 12px;
  box-shadow: 0 10px 34px rgba(0, 0, 0, .55);
  font: 600 15px/1.35 system-ui, sans-serif; text-align: left;
  pointer-events: none; user-select: none;
  z-index: 60; opacity: 0; transition: opacity .25s ease;
}
.mud-status-overlay.show { opacity: 1; }
.mud-status-overlay[hidden] { display: none; }
.mud-status-overlay .mud-status-label { letter-spacing: .2px; }
.mud-status-overlay .mud-status-spin {
  width: 17px; height: 17px; flex: 0 0 auto;
  border: 2.5px solid rgba(163, 190, 140, .25); border-top-color: #a3be8c;
  border-radius: 50%; animation: mud-status-spin .8s linear infinite;
}
@keyframes mud-status-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .mud-status-overlay .mud-status-spin { animation: none; } }

/* ---- MOO object browser (Objects button; MOO exhibits only) ---- */
/* The ref box shares the fb-head flex row with the Open/me/here buttons. */
.fb-head input.moo-ref {
  flex: 0 1 220px; min-width: 90px;
  font-family: inherit; font-size: 12px;
  color: var(--fg); background: var(--bg);
  border: 1px solid var(--line); border-radius: 6px; padding: 4px 8px;
}
.fb-head input.moo-ref:focus { outline: none; border-color: var(--accent); }
.moo-obj { font-weight: 600; border-bottom: 1px solid var(--line); margin-bottom: 2px; }
.moo-hdr {
  padding: 10px 8px 2px; color: var(--dim); font-size: 11px;
  text-transform: uppercase; letter-spacing: .05em;
}

/* Objects panel: the × close pinned to the panel corner (modal idiom).  The
   head Close button it replaces was unreachable on phones -- the head row
   overflows and wraps there.  Room for it is reserved via head padding. */
.moo-panel { position: relative; }
.moo-panel .fb-head { padding-right: 54px; }
.moo-panel .fb-x {
  position: absolute; top: 8px; right: 10px; z-index: 2;
  width: 36px; height: 36px; padding: 0;
  border-radius: 50%; font-size: 20px; line-height: 1; text-align: center;
  color: var(--dim);
}
.moo-panel .fb-x:hover { color: var(--fg); }
@media (max-width: 560px) {
  /* Let the ref box + buttons wrap into rows instead of overflowing. */
  .moo-panel .fb-head { flex-wrap: wrap; row-gap: 6px; }
  .moo-panel .fb-head input.moo-ref { flex: 1 1 130px; }
}
