/**
 * client_skin/skin.css
 *
 * Shared palette, layout, and transcript styling for the HTML
 * adventure clients (facebook_client/, browser_client/). Each page
 * links this file absolutely (<link rel="stylesheet" href="/skin.css">)
 * instead of keeping its own copy of the :root palette -- see
 * server.py's _resolve_client_skin_path, wired into the HTTP command
 * server (port 9002).
 *
 * Palette and component shapes follow Material Design 3's baseline
 * dark color scheme -- the same tokens Compose's darkColorScheme()
 * defaults to, which is what android_client renders with no custom
 * theme of its own (see MainActivity.kt). Filled/outlined buttons are
 * pill-shaped, text fields and dialogs use M3's corner radii, and
 * FontFamily.Monospace is reserved for the game transcript itself
 * (android_client/.../ui/TerminalScreen.kt) -- everything else (chrome,
 * labels, buttons) uses the system sans-serif stack, matching Roboto's
 * role on Android.
 *
 * Anything genuinely page-specific (the login/register panel in
 * browser_client, the FBInstant loading state in facebook_client)
 * stays inline in that page's own <style> block rather than living here.
 */

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

:root {
  /* Surfaces (M3 dark baseline tonal elevation) */
  --bg:              #141218;
  --surface:         #1d1b20;
  --surface-variant: #49454f;
  --surface-high:    #2b2930;
  --outline:         #938f99;
  --outline-variant: #49454f;

  /* Content */
  --text:      #e6e1e5;
  --text-dim:  #cac4d0;

  /* M3 primary/error roles */
  --primary:           #d0bcff;
  --on-primary:        #381e72;
  --primary-container: #4f378b;
  --error:             #f2b8b5;
  --on-error:          #601410;

  /* Game-transcript semantic colors (no direct M3 equivalent --
     tuned to sit comfortably on the surfaces above) */
  --success: #92d9a0;
  --warning: #ffd682;
  --info:    #a8c8ff;
  --quest:   #d0bcff;

  --accent: var(--primary);

  --font:      -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
               Helvetica, Arial, sans-serif;
  --font-mono: "Roboto Mono", "SF Mono", Consolas, "Liberation Mono", Menlo,
               monospace;

  --ease: cubic-bezier(0.2, 0, 0, 1);
}

html, body {
  height: 100%;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-size: 14px;
  overflow: hidden;
}

button, input { font-family: inherit; }

:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

/* ── App shell ──
   Android has no equivalent of this: a phone's width never exceeds a
   few hundred dp, so RoomPanel's fixed 160dp image height (matched
   here by .room-image-wrap) always reads as a sensible banner. A
   browser window has no such ceiling -- without a cap here, that same
   fixed height stretches into a thin, heavily-cropped strip on a wide
   desktop window. Capping width and centering keeps every fixed-px
   measurement (room image height, item thumbnails) at the same
   proportions this UI was actually designed at, regardless of how
   wide the browser window is. */
#app {
  display: flex;
  flex-direction: column;
  height: 100dvh;   /* dynamic viewport height -- handles mobile chrome/safari bars */
  width: 100%;
  max-width: 560px;
  margin: 0 auto;
}

/* ── Header ── */
#header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 16px;
  background: var(--surface-variant);
  flex-shrink: 0;
  gap: 8px;
}

#header h1 {
  font-size: 15px;
  font-weight: 500;
  color: var(--text);
  white-space: nowrap;
}

#status-pill {
  font-family: inherit;
  font-size: 12px;
  font-weight: 500;
  padding: 4px 12px;
  border: none;
  border-radius: 999px;
  white-space: nowrap;
  background: rgba(230, 225, 229, 0.12);
  cursor: pointer;
  transition: background-color 150ms var(--ease), color 150ms var(--ease);
}
#status-pill.connected    { color: var(--success); background: rgba(146, 217, 160, 0.16); }
#status-pill.disconnected { color: var(--error);   background: rgba(242, 184, 181, 0.16); }
#status-pill.connecting   { color: var(--warning); background: rgba(255, 214, 130, 0.16); }

#connect-btn {
  font-size: 12px;
  font-weight: 500;
  padding: 6px 16px;
  border-radius: 999px;
  border: 1px solid var(--outline);
  background: transparent;
  color: var(--primary);
  cursor: pointer;
  white-space: nowrap;
  transition: background-color 150ms var(--ease);
}
#connect-btn:hover { background: rgba(208, 188, 255, 0.08); }

/* ── Status line (land ▸ room ▸ score ▸ turns) ──
   Mirrors android_client's TerminalScreen running status text --
   stays visible even while #room-panel-body is collapsed, same as
   there. */
.status-line {
  padding: 4px 16px;
  font-size: 11px;
  color: var(--text-dim);
  background: var(--surface-variant);
  flex-shrink: 0;
}

/* ── Room panel (location image, items, NPCs, quest hint) ──
   Mirrors android_client's RoomPanel.kt composable field-for-field:
   collapsible strip between the header and the transcript, hidden
   entirely outside a room (e.g. the lobby), same surfaceVariant
   background as the header/input bar. */
#room-panel {
  display: none;
  background: var(--surface-variant);
  flex-shrink: 0;
}

.room-panel-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 8px 16px;
  cursor: pointer;
}

.room-panel-title {
  font-size: 13px;
  font-weight: 600;
}

.room-panel-toggle {
  font-size: 12px;
  color: var(--text-dim);
}

.room-panel-body {
  padding: 0 16px 12px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.room-dark-message {
  font-size: 13px;
  color: var(--text-dim);
  font-style: italic;
}

.room-image-wrap {
  position: relative;
  width: 100%;
  /* Every configured room image is 1408x768 (confirmed across every
     land's images/ directory) -- matching that ratio here means the
     box is always exactly the image's own shape, so object-fit: cover
     below never has anything to crop. A fixed px height cut off the
     bottom of every image on anything wider than a phone, since 160px
     was only ever right for one specific width. */
  aspect-ratio: 1408 / 768;
  border-radius: 8px;
  overflow: hidden;
}

.room-image {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.room-item-row {
  position: absolute;
  left: 8px;
  bottom: 8px;
  display: flex;
  gap: 6px;
}

.room-item-thumb {
  width: 48px;
  height: 48px;
  border-radius: 6px;
  object-fit: cover;
  cursor: pointer;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.5);
  transition: transform 150ms var(--ease);
}
.room-item-thumb:hover { transform: scale(1.06); }

.room-items-line {
  font-size: 13px;
}

/* ── Carried-item thumbnails ("Inventory (N)") ──
   Collapsed by default (a button, not a static label) to save
   vertical space -- same .room-item-thumb art as the room's own item
   row when expanded, just laid out as a normal (non-absolute) row
   since there's no background image to overlay here. */
.inventory-row-wrap {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.inventory-row-toggle {
  align-self: flex-start;
  font-family: inherit;
  font-size: 12px;
  font-weight: 500;
  padding: 3px 10px;
  border: 1px solid var(--outline);
  border-radius: 999px;
  background: transparent;
  color: var(--text-dim);
  cursor: pointer;
  transition: background-color 150ms var(--ease), border-color 150ms var(--ease), color 150ms var(--ease);
}
.inventory-row-toggle:hover { border-color: var(--primary); color: var(--primary); }

.inventory-item-row {
  display: flex;
  gap: 6px;
}

.room-items-line .item-link {
  color: var(--primary);
  text-decoration: underline;
  cursor: pointer;
}

.room-info-line {
  font-size: 12px;
  color: var(--text-dim);
}

.room-presence-line {
  font-size: 12px;
}

.room-quest-hint {
  font-size: 12px;
  color: var(--primary);
}

/* ── Output / transcript ── */
#output {
  flex: 1;
  overflow-y: auto;
  padding: 14px 16px 6px;
  line-height: 1.6;
  -webkit-overflow-scrolling: touch;
  font-family: var(--font-mono);
  /* Chrome's automatic scroll anchoring re-adjusts scrollTop on a
     later frame to compensate for content shifting above the
     viewport -- exactly what every command response does here
     (new lines appended, room panel/action bar re-rendered). That
     silently overrides appendText's own "scroll to bottom" a moment
     after it runs, landing partway up the transcript instead of at
     the new bottom. This is a log view, not a page a reader is
     mid-scrolling through, so there's nothing worth anchoring to. */
  overflow-anchor: none;
}

.line { white-space: pre-wrap; word-break: break-word; }
.line.server  { color: var(--text); }
.line.player  { color: var(--primary); }
.line.system  { color: var(--text-dim); font-style: italic; }
.line.error   { color: var(--error); }
.line.quest   { color: var(--quest); }
.line.heading { color: var(--warning); font-weight: bold; }
.line.success { color: var(--success); }
.line.sep     { color: var(--outline-variant); }

#output::-webkit-scrollbar { width: 4px; }
#output::-webkit-scrollbar-track { background: transparent; }
#output::-webkit-scrollbar-thumb { background: var(--outline-variant); border-radius: 2px; }

/* ── Input area ── */
#input-area {
  display: flex;
  align-items: center;
  padding: 10px 16px;
  gap: 10px;
  background: var(--surface-variant);
  flex-shrink: 0;
}

#prompt {
  color: var(--primary);
  font-family: var(--font-mono);
  font-size: 15px;
  flex-shrink: 0;
}

#input {
  flex: 1;
  background: var(--surface-high);
  border: 1px solid transparent;
  border-radius: 999px;
  outline: none;
  padding: 9px 16px;
  color: var(--text);
  font-family: var(--font-mono);
  caret-color: var(--primary);
  font-size: max(15px, 16px);   /* also prevents iOS zoom-on-focus */
  transition: border-color 150ms var(--ease), box-shadow 150ms var(--ease);
}
#input:focus {
  border-color: var(--primary);
  box-shadow: 0 0 0 1px var(--primary);
}

#send-btn {
  font-size: 13px;
  font-weight: 500;
  padding: 9px 18px;
  border-radius: 999px;
  border: none;
  background: var(--primary);
  color: var(--on-primary);
  cursor: pointer;
  flex-shrink: 0;
  transition: opacity 150ms var(--ease), box-shadow 150ms var(--ease);
}
#send-btn:hover { box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4); }
#send-btn:active { opacity: 0.85; }

/* ── Action bar (compass exits + look/inv/hint/help) ──
   Mirrors android_client's ActionBar.kt: a horizontally scrolling row
   of tap-to-send buttons below the command box, not instead of it. */
.action-bar {
  display: flex;
  gap: 6px;
  padding: 0 16px 10px;
  overflow-x: auto;
  flex-shrink: 0;
}
.action-bar::-webkit-scrollbar { display: none; }

.action-btn {
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 500;
  padding: 6px 12px;
  border-radius: 999px;
  border: 1px solid var(--outline);
  background: transparent;
  color: var(--text-dim);
  cursor: pointer;
  white-space: nowrap;
  flex-shrink: 0;
  transition: background-color 150ms var(--ease), border-color 150ms var(--ease), color 150ms var(--ease);
}
.action-btn:hover:not(:disabled) { border-color: var(--primary); color: var(--primary); }
.action-btn:disabled { opacity: 0.4; cursor: default; }

/* ── Lobby menu (tappable options + land "info" modal) ──
   Mirrors android_client's LobbyMenuPanel.kt: shown between the header
   and the transcript only while the server sends a lobby_menu; capped
   in height so a long land list scrolls instead of crowding out the
   transcript. */
.lobby-menu {
  display: none;
  background: var(--surface-variant);
  flex-shrink: 0;
  padding: 8px 16px 12px;
  max-height: 45vh;
  overflow-y: auto;
}

.lobby-menu-title {
  font-size: 13px;
  font-weight: 600;
  margin-bottom: 6px;
}

.lobby-menu-row {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 6px;
}

.lobby-menu-option {
  flex: 1;
  min-width: 0;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 8px;
  text-align: left;
  font-size: 13px;
  padding: 8px 12px;
  border-radius: 12px;
  border: 1px solid var(--outline);
  background: transparent;
  color: var(--text);
  cursor: pointer;
  transition: border-color 150ms var(--ease), color 150ms var(--ease);
}
.lobby-menu-option:hover:not(:disabled) { border-color: var(--primary); color: var(--primary); }
.lobby-menu-option:disabled { opacity: 0.4; cursor: default; }

.lobby-menu-hint {
  font-size: 11px;
  color: var(--text-dim);
  flex-shrink: 0;
}

.lobby-menu-info { flex-shrink: 0; }

.land-info-panel {
  max-height: 85vh;
}

.land-info-text {
  width: 100%;
  overflow-y: auto;
  text-align: left;
  font-size: 13px;
  line-height: 1.5;
  white-space: pre-wrap;
  word-break: break-word;
}

.land-info-controls { justify-content: flex-end; }

/* ── Modal chrome (connect status / login-register panels) ── */
#overlay {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.5);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 10;
}

.modal-panel {
  background: var(--surface-high);
  border-radius: 28px;
  padding: 32px 28px;
  width: min(360px, 90vw);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  text-align: center;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45);
}

.modal-panel h2 {
  color: var(--text);
  font-size: 18px;
  font-weight: 500;
}

/* ── Settings panel (baud/print-speed, music volume) ──
   Mirrors android_client's SettingsDialog: a modal reached from a
   header gear button, reusing .modal-panel's chrome via its own
   overlay id (kept separate from #overlay, which is the auth panel's
   and has its own show/hide lifecycle). */
.settings-overlay {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.5);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 20;
}

.settings-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  width: 100%;
}

/* Material "FilterChip" look, matching android_client's baud presets. */
.chip {
  font-size: 12px;
  font-weight: 500;
  padding: 6px 14px;
  border-radius: 999px;
  border: 1px solid var(--outline);
  background: transparent;
  color: var(--text-dim);
  cursor: pointer;
  transition: background-color 150ms var(--ease), border-color 150ms var(--ease), color 150ms var(--ease);
}
.chip:hover:not(.active) { border-color: var(--primary); color: var(--primary); }
.chip.active {
  background: var(--primary);
  color: var(--on-primary);
  border-color: var(--primary);
}

.settings-hint {
  font-size: 12px;
  color: var(--text-dim);
}

input[type="range"] {
  width: 100%;
  height: 20px;
  -webkit-appearance: none;
  appearance: none;
  background: transparent;
  cursor: pointer;
}
input[type="range"]::-webkit-slider-runnable-track {
  height: 4px;
  border-radius: 2px;
  background: var(--outline-variant);
}
input[type="range"]::-moz-range-track {
  height: 4px;
  border-radius: 2px;
  background: var(--outline-variant);
}
input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 16px;
  height: 16px;
  margin-top: -6px;
  border-radius: 50%;
  background: var(--primary);
  border: none;
}
input[type="range"]::-moz-range-thumb {
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--primary);
  border: none;
}

/* ── Generic form controls (login/register-style panels) ── */
.field {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 6px;
  width: 100%;
  text-align: left;
}

.field label {
  font-size: 12px;
  font-weight: 500;
  color: var(--text-dim);
}

.field input {
  font-size: 15px;
  padding: 11px 14px;
  border-radius: 4px;
  border: 1px solid var(--outline);
  background: transparent;
  color: var(--text);
  outline: none;
  transition: border-color 150ms var(--ease), box-shadow 150ms var(--ease);
}
.field input:focus {
  border-color: var(--primary);
  box-shadow: 0 0 0 1px var(--primary);
}

.btn-primary {
  font-size: 14px;
  font-weight: 500;
  padding: 11px 24px;
  border-radius: 999px;
  border: none;
  background: var(--primary);
  color: var(--on-primary);
  cursor: pointer;
  transition: opacity 150ms var(--ease), box-shadow 150ms var(--ease);
}
.btn-primary:hover { box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4); }
.btn-primary:active { opacity: 0.85; }
.btn-primary:disabled { opacity: 0.38; cursor: default; box-shadow: none; }

.btn-block { width: 100%; }

.btn-ghost {
  font-size: 13px;
  font-weight: 500;
  padding: 8px 18px;
  border-radius: 999px;
  border: 1px solid var(--outline);
  background: transparent;
  color: var(--text-dim);
  cursor: pointer;
  transition: background-color 150ms var(--ease), border-color 150ms var(--ease), color 150ms var(--ease);
}
.btn-ghost:hover { border-color: var(--primary); color: var(--primary); background: rgba(208, 188, 255, 0.08); }

.tab-row {
  display: flex;
  width: 100%;
  border-bottom: 1px solid var(--outline-variant);
}

.tab-row button {
  flex: 1;
  font-size: 13px;
  font-weight: 500;
  padding: 10px 0;
  border: none;
  border-bottom: 2px solid transparent;
  background: transparent;
  color: var(--text-dim);
  cursor: pointer;
  transition: color 150ms var(--ease), border-color 150ms var(--ease);
}
.tab-row button.active {
  border-color: var(--primary);
  color: var(--primary);
}

.field-error {
  color: var(--error);
  font-size: 12px;
  min-height: 16px;
}

@media (max-width: 480px) {
  html, body { font-size: 13px; }
  #header h1 { font-size: 14px; }
}

/* ── Drawn map window (POST /map) ─────────────────────────────── */
.map-panel { width: 92vw; max-width: 1000px; }
.map-header { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.map-view {
  max-height: 68vh;
  overflow: auto;
  background: #ffffff;
  border-radius: 8px;
  padding: 8px;
  margin: 10px 0;
  text-align: center;
  -webkit-overflow-scrolling: touch;
}
.map-view img { max-width: none; height: auto; display: inline-block; }
.map-controls { justify-content: flex-end; }
