/* The pixel skin: fonts, frames and icons are in ui.css (tools/gen-ui.mjs).
   Text sizes are whole pixels; frames are 2x pixel art like the item icons. */
:root {
  --bg: #0e0d0b;
  --panel: #1a1814;
  --panel-2: #23201a;
  --edge: #3a3428;
  --text: #e6dfcf;
  --muted: #9a917e;
  --accent: #e0a64b;
  --system: #8fb8e0;
  --npc: #8fd0ff;
  --world: #c9a0f0;
  --error: #f08a7a;
  --hp: #c43a2e;
  --exp: #d9a441;
  --skill: #5fa05a;
  --view-w: 960px;
  --view-h: 544px;
  /* The stage shows the whole view on desktop; touch screens crop it (main.js layout). */
  --stage-w: var(--view-w);
  --stage-h: var(--view-h);
  --view-x: 0px;
  --view-y: 0px;
  --side-w: 208px;
  /* items.png (16px icons + 1px gap) shown at 2x; main.js sets the real width. */
  --icon-sheet-w: 406px;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  height: 100%;
  background: var(--bg);
  color: var(--text);
  font: 14px/1.25 var(--font);
  font-synthesis: none;
  -webkit-tap-highlight-color: transparent;
}
body {
  /* A dark board, faintly planked. */
  background:
    repeating-linear-gradient(0deg, transparent 0 46px, rgba(0, 0, 0, 0.35) 46px 48px),
    var(--bg);
}

button, input, select { font: inherit; touch-action: manipulation; }

/* Frames (ui.css): stone buttons, brass for the main action, sunk fields. */
:is(#side-actions button, #container-panel .row button, .trade-list button, #trade-panel .row button, #talk-panel .row button,
    dialog .row button:not(.primary), #saved-list .small, #guest-reroll, #play-guest, #new-char, #login-other:not(.primary), #dest button, #worldmap .wm-bar button,
    #worldmap-btn, #toolbar button, #hud-attack, .mini-tabs button, .chat-tabs button) {
  border: var(--frame-button-w) solid transparent;
  border-image: var(--frame-button);
  border-radius: 0;
  background: none;
  color: var(--text);
  text-shadow: 0 2px 0 var(--ink);
  cursor: pointer;
}
:is(#side-actions button, #container-panel .row button, .trade-list button, #trade-panel .row button, #talk-panel .row button,
    dialog .row button:not(.primary), #saved-list .small, #guest-reroll, #play-guest, #new-char, #login-other:not(.primary), #dest button, #worldmap .wm-bar button,
    #worldmap-btn, #toolbar button, #hud-attack, .mini-tabs button, .chat-tabs button):hover:not(:disabled) { border-image: var(--frame-button-hover); }
:is(#side-actions button, #container-panel .row button, .trade-list button, #trade-panel .row button, #talk-panel .row button,
    dialog .row button:not(.primary), #saved-list .small, #guest-reroll, #play-guest, #new-char, #login-other:not(.primary), #dest button, #worldmap .wm-bar button,
    #worldmap-btn, #toolbar button, #hud-attack, .mini-tabs button, .chat-tabs button):active:not(:disabled) { border-image: var(--frame-button-down); }
:is(#login input, #totp-code, #claim-dialog input, #chat-input, #dg-title-pick) {
  border: var(--frame-input-w) solid transparent;
  border-image: var(--frame-input);
  border-radius: 0;
  background: none;
  color: var(--text);
}
:is(#login input, #totp-code, #claim-dialog input, #chat-input, #dg-title-pick):focus { border-image: var(--frame-input-focus); outline: none; }
/* Autofill forces black text, and the frame's fill paints over its pale
   background: keep our text colour (text-fill-color isn't forced). */
:is(#login input, #totp-code, #claim-dialog input):is(:autofill, :-webkit-autofill) {
  -webkit-text-fill-color: var(--text);
  caret-color: var(--text);
  transition: background-color 600000s 0s;
}
/* Icons (ui.css) in buttons: small, before the label. */
button > .pi, label > .pi, .login-links a > .pi { --pi-size: 16px; margin-right: 6px; }
button > .pi:only-child { margin: 0; }
/* Reduce motion (main.js): nothing slides or fades. */
body.reduce-motion *, body.reduce-motion *::after { transition: none !important; animation: none !important; }
.muted { color: var(--muted); font-weight: 400; }

/* Client frame: game view top-left, sidebar on the right, chat along the
   bottom. Nothing but in-world things (names, bubbles) draws over the view. */
#app {
  display: grid;
  grid-template-columns: minmax(0, 1fr) var(--side-w);
  grid-template-rows: minmax(0, 1fr) auto;
  grid-template-areas: "game side" "chat chat";
  gap: 4px;
  padding: 4px;
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
}
/* Panels moved to the left (or one being dragged): a second column. */
#app.has-left {
  grid-template-columns: var(--side-w) minmax(0, 1fr) var(--side-w);
  grid-template-areas: "left game side" "chat chat chat";
}

#game-area {
  grid-area: game;
  display: grid;
  place-items: center;
  min-height: 0;
}

#stage {
  position: relative;
  width: var(--stage-w);
  height: var(--stage-h);
  /* A slim wooden edge, like the panels. */
  box-shadow: 0 0 0 2px var(--ink), 0 0 0 4px #6b4a2b, 0 0 0 6px var(--ink);
  background: #000;
  overflow: hidden;
}

#view, #labels {
  position: absolute;
  left: var(--view-x);
  top: var(--view-y);
  width: var(--view-w);
  height: var(--view-h);
  /* The game handles taps itself: no zoom, scrolling, selection or callouts. */
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
}
#view { image-rendering: pixelated; cursor: pointer; }
#labels { pointer-events: none; }

/* ---------------------------------------------------------------- sidebar */

.sidebar {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-height: 0;
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: #6b4a2b transparent;
}
.sidebar > * { flex: none; }
#sidebar { grid-area: side; }
#sidebar-left { grid-area: left; display: none; }
#app.has-left #sidebar-left { display: flex; }

.panel, #chat {
  border: var(--frame-panel-w) solid transparent;
  border-image: var(--frame-panel);
}
.panel-head {
  padding: 3px 6px 3px;
  font: 8px/12px var(--caps);
  letter-spacing: 1px;
  color: var(--accent);
  text-shadow: 0 2px 0 var(--ink);
  border-bottom: 2px solid var(--ink);
  box-shadow: 0 2px 0 rgba(255, 233, 168, 0.06);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.panel-head .muted { font: 12px var(--font); letter-spacing: 0; text-shadow: none; }
.panel > .panel-head {
  cursor: pointer;
  user-select: none;
  display: flex;
  justify-content: space-between;
}
.panel > .panel-head::after { content: "-"; color: var(--muted); }
.panel.collapsed > .panel-head { border-bottom: 0; }
.panel.collapsed > .panel-head::after { content: "+"; }
.panel.collapsed > .panel-body { display: none; }
.panel-body { padding: 4px; }
.panel-body .hint { margin-top: 6px; }

/* 80px canvas shown at exactly 2x so the pixels stay crisp. */
#map-panel .panel-body { padding: 6px 0; }
#minimap {
  display: block;
  width: 160px;
  height: 160px;
  margin: 0 auto;
  image-rendering: pixelated;
  outline: 2px solid var(--ink);
  background: #000;
}

/* Skills */
/* Health: the bar in a sunk frame; what was just lost stays a moment in a
   pale band (.lag) that drains after the bar (main.js setHealth). */
.meter {
  position: relative;
  height: 18px;
  border: var(--frame-meter-w) solid transparent;
  border-image: var(--frame-meter);
  margin-bottom: 4px;
}
.meter .fill, .meter .lag { position: absolute; inset: 0 auto 0 0; width: 100%; }
.meter .fill {
  background: var(--hp);
  box-shadow: inset 0 2px 0 rgba(255, 255, 255, 0.28), inset 0 -2px 0 rgba(0, 0, 0, 0.3);
  transition: width 0.15s;
}
.meter .lag { background: #f2d7a0; transition: width 0.6s ease-in 0.5s; }
.meter .text {
  position: relative;
  display: block;
  text-align: center;
  font-size: 13px;
  line-height: 14px;
  text-shadow: 0 2px 0 var(--ink);
  font-variant-numeric: tabular-nums;
}
.stat {
  display: flex;
  justify-content: space-between;
  font-size: 13px;
  font-variant-numeric: tabular-nums;
}
.stat b { font-weight: 600; }
.bar {
  height: 6px;
  margin: 1px 0 4px;
  border: 2px solid var(--ink);
  background: #1d1a15;
}
.bar span { display: block; height: 100%; width: 0; background: var(--exp); transition: width 0.2s; }
#skills .bar span { background: var(--skill); }

/* Item slots: the icon is a background crop of items.png at 2x. */
/* Item slots: the frame is the background (36px), the icon inside it. */
.slot {
  position: relative;
  width: 36px;
  height: 36px;
  border: 0;
  border-radius: 0;
  background: var(--frame-slot);
  padding: 0;
}
.slot.filled { cursor: pointer; }
.slot.filled:hover, .slot.filled:focus-visible { background: var(--frame-slot-hover); outline: none; }
/* Uncommon and better: a frame in the item's rarity colour (main.js rarity). */
.slot.rare::after { content: ""; position: absolute; inset: 0; box-shadow: inset 0 0 0 2px var(--rarity), inset 0 0 8px -2px var(--rarity); pointer-events: none; }
.slot .icon {
  position: absolute;
  inset: 2px;
  background-image: url("assets/items.png");
  background-size: var(--icon-sheet-w) 32px;
  background-repeat: no-repeat;
  image-rendering: pixelated;
}
.slot .count {
  position: absolute;
  right: 3px;
  bottom: 1px;
  font-size: 13px;
  line-height: 13px;
  text-shadow: 2px 0 0 var(--ink), -2px 0 0 var(--ink), 0 2px 0 var(--ink), 0 -2px 0 var(--ink);
}
.slot .ghost {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  font: 8px var(--caps);
  color: #6e6553;
}
.equip-grid {
  display: grid;
  grid-template-columns: repeat(3, 36px);
  gap: 3px;
  justify-content: center;
}
.bag-grid {
  display: grid;
  grid-template-columns: repeat(5, 36px);
  gap: 2px;
  justify-content: center;
}

/* Daily dungeon panel */
#dungeon-panel .qname { color: var(--accent); font-size: 14px; }
#dungeon-panel .small { font-size: 12px; margin: 2px 0 4px; }
#dg-steps { margin: 2px 0 4px; padding-left: 16px; font-size: 13px; }
#dg-steps .done { color: var(--muted); text-decoration: line-through; }
#dg-steps .current { color: var(--accent); }
#dg-title-pick { font-size: 13px; max-width: 120px; }
#dg-title-pick option { background: var(--panel); }
/* The last 14 days: a row of little stone blocks, lit when passable. */
.chain { display: flex; gap: 2px; margin: 6px 0; }
.chain .day { position: relative; flex: 1; height: 14px; background: #2a2a30; border: 2px solid var(--ink); box-shadow: inset 0 2px 0 rgba(255, 255, 255, 0.08); }
.chain .day.cleared { background: #3f9b45; box-shadow: inset 0 2px 0 #7fd585; }
.chain .day.bridged { background: #c9a227; box-shadow: inset 0 2px 0 #f2d76a; }
.chain .chest-dot { position: absolute; left: 50%; top: 50%; width: 4px; height: 4px; margin: -2px 0 0 -2px; outline: 2px solid var(--ink); }
#chat-log .line { white-space: pre-line; }

#quests { list-style: none; margin: 0; padding: 0; font-size: 13px; }
#quests li + li { margin-top: 4px; }
#quests .qname { color: var(--accent); }
#quests .qhead { display: flex; justify-content: space-between; align-items: baseline; gap: 6px; }
.quest-abandon { padding: 0 5px; font-size: 11px; line-height: 16px; min-height: 0; opacity: 0.55; }
.quest-abandon:hover, .quest-abandon.sure { opacity: 1; }
.quest-abandon.sure { color: #ff8a70; }

#side-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 3px; }
#side-actions > :is(#guest-save, .volume-row, .check-row, .select-row) { grid-column: 1 / -1; }
#side-actions button {
  display: flex;
  align-items: center;
  min-width: 0;
  padding: 1px 4px;
  font-size: 13px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
#side-actions button > .pi { margin-right: 4px; }
body:not(.touch-ui) #side-actions .touch-only { display: none; }
#side-actions button:disabled { opacity: 0.5; cursor: default; }
#side-actions :is(.volume-row, .check-row) { display: flex; align-items: center; gap: 0; padding: 1px 4px; font-size: 13px; color: var(--muted); cursor: pointer; }
#side-actions .volume-row input { flex: 1; min-width: 0; margin-left: 8px; accent-color: var(--accent); }
#side-actions .check-row input { margin: 0 8px 0 2px; accent-color: var(--accent); }
#side-actions .select-row { display: flex; align-items: center; padding: 1px 4px; font-size: 13px; color: var(--muted); }
#side-actions .select-row select { flex: 1; min-width: 0; margin-left: 8px; font: inherit; color: var(--text); background: var(--ink); border: 2px solid #1d2140; }

#status {
  padding: 0 4px 4px;
  font-size: 12px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

/* ------------------------------------------------------------------ login */

/* The login screen: the town drawn live behind a framed card (main.js
   startScene); black until the backdrop fades in. */
/* The whole window: there's nothing to see in the panels before logging in. */
#login {
  position: fixed;
  inset: 0;
  z-index: 40;
  background: #000;
  text-align: center;
  /* Brighter than in the game: it's read over the dark backdrop. */
  --muted: #bdb39c;
}
/* Scaled to the space there is (main.js fitLogin): big screens get a big card. */
.login-scroll > * { zoom: var(--login-zoom, 1); }
#login[hidden] { display: none; }
#login-scene {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  transition: opacity 1.5s;
}
#login-scene.on { opacity: 1; }
.login-scroll {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: safe center;
  align-items: center;
  padding: 12px 16px;
  overflow-y: auto;
  background: radial-gradient(ellipse at center, rgba(8, 7, 5, 0.1) 30%, rgba(8, 7, 5, 0.7));
}
.login-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  width: min(330px, 100%);
  padding: 8px 14px 10px;
  border: var(--frame-dialog-w) solid transparent;
  border-image: var(--frame-dialog);
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.6);
}
#login h1.logo {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  font: 32px/32px var(--caps);
  color: #ffd27a;
  text-shadow: 0 2px 0 #9a6a24, 0 4px 0 var(--ink);
}
.logo .pi { --pi-size: 32px; margin-bottom: 4px; }
/* The mode after the name (Where to, main.js setDest). All three words share
   one grid cell, so the slot is as wide as "Clubroom" whichever shows and
   "Delvia" never moves. Gradient fills, so the shadow is a drop-shadow (a
   text-shadow would show through the clear fill). */
.logo-mode { display: grid; align-self: flex-end; margin: 0 0 3px -4px; font: 18px/20px var(--caps); text-align: left; text-shadow: none; }
.logo-mode > span {
  grid-area: 1 / 1;
  visibility: hidden;
  color: transparent;
  background-clip: text;
  -webkit-background-clip: text;
  filter: drop-shadow(0 2px 0 var(--mode-shade)) drop-shadow(0 2px 0 var(--ink));
}
.logo-mode > span::before { content: ':'; margin-right: 6px; }
.logo[data-dest="dungeon"] [data-dest="dungeon"],
.logo[data-dest="club"] [data-dest="club"],
.logo[data-dest="world"] [data-dest="world"] { visibility: visible; }
/* Each mode's colours, for the logo's word and the mode panel's title (.mi-page). */
.mi-page[data-dest="dungeon"], .logo-mode [data-dest="dungeon"] { --mode-shade: #4a2378; --mode-fill: linear-gradient(#e2c4ff, #a76cf0 55%, #7c3fd0); }
.mi-page[data-dest="world"], .logo-mode [data-dest="world"] { --mode-shade: #1f5a4a; --mode-fill: linear-gradient(#bfe9ff, #6cc4f0 50%, #5fc76a); }
.mi-page[data-dest="club"], .logo-mode [data-dest="club"] { --mode-shade: #3a1450; --mode-fill: linear-gradient(90deg, #ff4f6d, #ffb340, #f6f05a, #5ff08a, #4fc8ff, #9a6bff, #ff5fd2, #ff4f6d); }
.logo-mode > span, .di-title { background-image: var(--mode-fill); }
/* The dance floor's colours: only the colours move (the word stays still),
   the rainbow turning once every 16 beats of the cellar's 126 BPM (rave.rs BPM). */
.logo-mode [data-dest="club"], .mi-page[data-dest="club"] .di-title {
  background-size: 200% 100%;
  animation: club-hue 7.619s linear infinite;
}
@keyframes club-hue { to { background-position: -200% 0; } }
@media (prefers-reduced-motion: reduce) { .logo-mode [data-dest="club"], .mi-page[data-dest="club"] .di-title { animation: none; } }
/* The three taglines share one cell too: as tall as the longest, so changing mode never moves the card. */
#login .tagline { display: grid; max-width: 290px; text-align: center; }
.tagline > span { grid-area: 1 / 1; visibility: hidden; }
.tagline[data-dest="dungeon"] [data-dest="dungeon"],
.tagline[data-dest="club"] [data-dest="club"],
.tagline[data-dest="world"] [data-dest="world"] { visibility: visible; }
.server-status { display: inline-flex; align-items: center; gap: 7px; margin: 0 0 4px; padding: 1px 8px; border: 2px solid var(--ink); background: rgba(0, 0, 0, 0.35); font-size: 13px; color: var(--muted); }
.motd { margin: 0 0 8px; padding: 6px 12px; max-width: min(460px, 100%); border-left: 4px solid var(--accent); background: rgba(224, 166, 75, 0.08); font-size: 15px; text-align: left; white-space: pre-wrap; }
.motd.warn { border-color: #e5533f; background: rgba(229, 83, 63, 0.1); color: #ff9a8a; }
.motd[hidden] { display: none; }
.server-status .dot { width: 8px; height: 8px; background: #8a8170; outline: 2px solid var(--ink); }
.server-status[data-state="online"] { color: var(--text); }
.server-status[data-state="online"] .dot { background: #4cd36b; box-shadow: 0 0 6px #4cd36b; }
.server-status[data-state="offline"] { color: #ff8a7a; border-color: #6b2b24; }
.server-status[data-state="offline"] .dot { background: #e5533f; }
.login-label { margin: 4px 0 0; font: 10px/14px var(--caps); color: var(--muted); }
.tagline { margin: 0 0 6px; font-size: 14px; color: var(--muted); }
/* The views stack in one cell: the card is as tall as the tallest, so switching
   views (and fitLogin's zoom) never moves anything. */
#login .views { display: grid; width: min(280px, 100%); }
#login .view { grid-area: 1 / 1; display: flex; flex-direction: column; align-items: stretch; gap: 6px; min-width: 0; }
#login .view[hidden] { visibility: hidden; }
.row { display: flex; gap: 6px; justify-content: space-between; align-items: center; }
#login input, #totp-code {
  min-width: 0;
  padding: 2px 8px;
  font-size: 16px; /* 16px+: phones don't zoom in on focus */
}
#login input[hidden] { display: none; }
#login .remember { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--muted); cursor: pointer; }
#login .remember input { margin: 0; padding: 0; border: 0; border-image: none; accent-color: var(--accent); }
/* The main action: brass. */
.primary, .continue {
  padding: 2px 14px;
  border: var(--frame-primary-w) solid transparent;
  border-image: var(--frame-primary);
  border-radius: 0;
  background: none;
  color: #2a1a06;
  font-size: 15px;
  text-shadow: 0 2px 0 rgba(255, 240, 200, 0.45);
  cursor: pointer;
}
.primary:hover:not(:disabled), .continue:hover:not(:disabled) { border-image: var(--frame-primary-hover); }
.primary:active:not(:disabled), .continue:active:not(:disabled) { border-image: var(--frame-primary-down); }
.primary:disabled, .continue:disabled { opacity: 0.6; cursor: progress; }
/* Where to: today's dungeon or the world, two halves of one switch. */
.dest { display: flex; gap: 4px; }
.dest button { flex: 1; padding: 2px 6px; font-size: 14px; white-space: nowrap; }
.row.pair > button { flex: 1; padding: 2px 6px; font-size: 14px; white-space: nowrap; }
.row.pair > button[hidden] { display: none; }
#login-other { padding: 2px 14px; font-size: 15px; }
#dest button[aria-checked="true"], #dest button[aria-checked="true"]:hover:not(:disabled) { border-image: var(--frame-primary); color: #2a1a06; text-shadow: 0 2px 0 rgba(255, 240, 200, 0.45); }
#saved { width: 100%; }
#saved-list { list-style: none; margin: 4px 0 0; padding: 0; display: grid; gap: 4px; }
#saved-list li { display: flex; gap: 4px; }
#saved-list .continue { flex: 1; text-align: left; }
#saved-list .small { padding: 0 8px; color: var(--muted); }
#saved-list .small:hover { color: var(--text); }
.link {
  border: 0;
  background: none;
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
  font-size: 14px;
}
#login-error { min-height: 1.3em; margin: 2px 0 0; color: var(--error); font-size: 15px; text-shadow: 0 2px 0 var(--ink); }
.hint { margin: 0; font-size: 12px; color: var(--muted); }

/* ------------------------------------------------------------------- chat */

#chat {
  grid-area: chat;
  display: flex;
  flex-direction: column;
}
#chat-head { display: flex; align-items: center; gap: 8px; padding: 2px 4px 2px 6px; }
.chat-tabs { display: flex; gap: 2px; }
.chat-tabs button { position: relative; padding: 0 6px; font: 12px/12px var(--font); letter-spacing: 0; color: var(--muted); }
.chat-tabs button[aria-selected="true"] { border-image: var(--frame-tab-on) !important; color: var(--accent); }
/* Lines arrived in a tab not shown. */
.chat-tabs button.news::after { content: ""; position: absolute; right: -2px; top: -2px; width: 4px; height: 4px; background: var(--accent); outline: 2px solid var(--ink); }
#chat-log[data-tab="local"] .line:not([data-tab="local"]),
#chat-log[data-tab="world"] .line:not([data-tab="world"]),
#chat-log[data-tab="system"] .line:not([data-tab="system"]) { display: none; }
#chat-log {
  height: 104px;
  overflow-y: auto;
  padding: 2px 6px;
  font-size: 14px;
  overflow-wrap: anywhere;
}
#chat-log .line { margin: 0; }
#chat-log .time { color: var(--muted); margin-right: 6px; font-variant-numeric: tabular-nums; }
#chat-log .from { color: var(--accent); }
#chat-log .system { color: var(--system); }
#chat-log .yell { color: #ffb070; }
#chat-log .npc .from, #chat-log .npc { color: var(--npc); }
#chat-log .world .from, #chat-log .world { color: var(--world); }
#chat-log .warn { color: var(--error); }
#chat-input {
  margin: 2px;
  padding: 1px 6px;
  font-size: 14px;
}

#vitals { margin: 0; flex: none; }

/* ------------------------------------------------------------- 2FA dialog */

/* Dialogs: the heavy frame (ui.css), headings in capitals. */
dialog {
  padding: 8px 12px;
  border: var(--frame-dialog-w) solid transparent;
  border-image: var(--frame-dialog);
  border-radius: 0;
  background: none;
  color: var(--text);
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.6);
}
dialog::backdrop { background: rgba(0, 0, 0, 0.6); }
dialog h2 { margin: 0 0 8px; font: 16px/16px var(--caps); color: var(--accent); text-shadow: 0 2px 0 var(--ink); }
dialog .row button:not(.primary) { padding: 2px 14px; }
#totp-dialog { width: min(380px, calc(100vw - 32px)); }
#totp-dialog p { margin: 0 0 8px; font-size: 15px; }
#totp-dialog .small { font-size: 13px; }
#totp-qr {
  display: block;
  width: 200px;
  height: 200px;
  margin: 4px auto 8px;
  image-rendering: pixelated;
  border-radius: 4px;
}
#totp-key { overflow-wrap: anywhere; color: var(--text); font-size: 13px; }
#totp-code { width: 100%; font-size: 20px; letter-spacing: 0.2em; text-align: center; margin-bottom: 6px; }
#totp-dialog .error { color: var(--error); min-height: 1.2em; margin: 0 0 6px; }
#totp-dialog .row { margin-top: 10px; }


/* Highscores panel */
.mini-tabs { display: flex; flex-wrap: wrap; gap: 2px; margin-bottom: 6px; }
.mini-tabs button { flex: 1; padding: 0 4px; color: var(--muted); font-size: 12px; }
.mini-tabs button[aria-selected="true"] { color: var(--accent); border-image: var(--frame-tab-on) !important; }
#hiscores { list-style: none; margin: 0; padding: 0; font-size: 13px; }
#hiscores li { display: flex; gap: 6px; padding: 0; }
#hiscores .r { width: 18px; color: var(--muted); font-variant-numeric: tabular-nums; }
#hiscores .n { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#hiscores .v { font-variant-numeric: tabular-nums; color: var(--muted); }
#hiscores .me .n { color: #8cf58c; }
#hiscores .on { color: #7fd07a; }
.view-all { display: block; margin-top: 6px; font-size: 13px; color: var(--accent); }
#login a.link { font-size: 14px; }
.login-links { display: flex; justify-content: center; flex-wrap: wrap; gap: 4px 16px; margin: 0; }
.support-link[hidden], .x-link[hidden] { display: none !important; }
.di-foot .support-link a { color: var(--accent); }

/* Item tooltips (WoW style) and coins. */
#tooltip {
  position: fixed;
  z-index: 50;
  display: flex;
  gap: 6px;
  align-items: flex-start;
  pointer-events: none;
}
#tooltip[hidden] { display: none; }
.tip {
  min-width: 190px;
  max-width: 290px;
  padding: 4px 8px;
  border: var(--frame-tip-w) solid transparent;
  border-image: var(--frame-tip);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.6);
  color: #fff;
  font: 13px/1.25 var(--font);
}
.tip .t-name { font-size: 15px; }
.tip .t-yellow { color: #ffd100; }
.tip .t-green { color: #1eff00; }
.t-red, .tip .t-red { color: #ff4040; }
.tip .t-muted { color: #9d9d9d; }
.tip .t-orange { color: #ff8040; }
.tip .t-row { display: flex; justify-content: space-between; gap: 18px; }
.coins { display: inline-flex; align-items: center; gap: 2px; }
.coin {
  display: inline-block;
  width: 8px;
  height: 8px;
  margin: 0 5px 0 2px;
  outline: 2px solid var(--ink);
  box-shadow: inset -2px -2px 0 rgba(0, 0, 0, 0.3);
}
.coin.gold { background: #f2c84b; }
.coin.silver { background: #cfd4d9; }
.coin.copper { background: #c87533; }
.money { margin-top: 4px; text-align: right; font-size: 13px; }

/* Drag and drop: the dragged item follows the cursor. */
#drag-ghost {
  position: fixed;
  z-index: 60;
  width: 32px;
  height: 32px;
  pointer-events: none;
  background-image: url(assets/items.png);
  background-size: var(--icon-sheet-w) 32px;
  background-repeat: no-repeat;
  image-rendering: pixelated;
  filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.7));
}
#drag-ghost[hidden] { display: none; }
body.dragging, body.dragging * { cursor: grabbing !important; user-select: none; }
body.dragging .slot:hover { box-shadow: inset 0 0 0 2px var(--accent); }

/* Login screen: who's around. */
.login-board { width: min(400px, 100%); margin-top: 10px; padding: 10px 14px; border: 2px solid var(--ink); background: rgba(8, 7, 5, 0.82); box-shadow: 0 10px 30px rgba(0, 0, 0, 0.6); }
/* What each mode is (#mode-info): always shown, a panel like the board. Its
   pages share one cell like the tagline's lines: as tall as the tallest, so
   changing mode never moves anything. */
.mode-info { display: grid; width: min(340px, 100%); margin-top: 10px; padding: 10px 14px 12px; border: 2px solid var(--ink); background: rgba(8, 7, 5, 0.82); box-shadow: 0 10px 30px rgba(0, 0, 0, 0.6); text-align: left; }
.mi-page { grid-area: 1 / 1; visibility: hidden; }
.mode-info[data-dest="dungeon"] .mi-page[data-dest="dungeon"],
.mode-info[data-dest="club"] .mi-page[data-dest="club"],
.mode-info[data-dest="world"] .mi-page[data-dest="world"] { visibility: visible; }
/* In the mode's colours, like the logo's word (--mode-fill above). */
.di-title {
  justify-self: start;
  margin: 0;
  font: 22px/24px var(--caps);
  letter-spacing: 1px;
  color: transparent;
  background-clip: text;
  -webkit-background-clip: text;
  filter: drop-shadow(0 2px 0 var(--mode-shade)) drop-shadow(0 2px 0 var(--ink));
}
/* One box per feature (like the today card), two by two; the chain spans both. */
.di-boxes { list-style: none; margin: 8px 0 0; padding: 0; display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.di-boxes > li { display: flex; flex-direction: column; gap: 3px; padding: 6px 8px 7px; background: rgba(0, 0, 0, 0.3); outline: 2px solid var(--ink); box-shadow: inset 0 2px 0 rgba(255, 255, 255, 0.05); font-size: 12px; line-height: 15px; color: var(--muted); }
.di-boxes > li.wide, .di-bullets > li.wide { grid-column: 1 / -1; }
.di-boxes .pi { --pi-size: 16px; }
.di-boxes b { display: flex; align-items: center; gap: 6px; color: var(--text); font-size: 13px; }
/* The market's list: two columns of small icon bullets. */
.di-bullets { list-style: none; margin: 3px 0 0; padding: 0; display: grid; grid-template-columns: 1fr 1fr; gap: 4px 8px; }
.di-bullets li { display: flex; align-items: center; gap: 6px; color: var(--text); }
.di-bullets .pi { flex: none; }
.di-chain { margin: 3px 0 1px; }
.di-chain .day { height: 14px; }
/* Today: not cleared yet, glowing. */
.chain .day.today { background: #3a2f52; border-color: #a76cf0; box-shadow: 0 0 6px #a76cf0; }
.di-foot { margin: 8px 0 0; font-size: 12px; color: var(--muted); text-align: center; }
/* Wide screens: how it works, the card, then who's around, side by side. */
@media (min-aspect-ratio: 4/3) and (min-width: 900px) {
  body:not(.touch-ui) .login-scroll { flex-direction: row; justify-content: center; gap: 24px; }
  body:not(.touch-ui) .login-board { margin: 0; }
  body:not(.touch-ui) .mode-info { order: -1; margin: 0; }
}
.login-board[hidden] { display: none; }
.today-card { margin: 0 0 2px; padding: 4px 8px 6px; background: rgba(0, 0, 0, 0.25); outline: 2px solid var(--ink); }
.today-card[hidden] { display: none; }
.tc-line { margin: 2px 0 0; font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tc-line .v { color: var(--muted); }
.market-note { margin: 2px 0 0; font-size: 12px; color: var(--accent); }
.lb-cols { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; text-align: left; }
.lb-cols ol, .lb-cols ul { margin: 2px 0 0; padding: 0; list-style: none; font-size: 13px; }
.lb-cols ol { counter-reset: rank; }
.lb-cols li { display: flex; justify-content: space-between; gap: 8px; padding: 0; }
.lb-cols ol li::before { counter-increment: rank; content: counter(rank) "."; width: 1.4em; color: var(--muted); }
.lb-cols .n { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lb-cols .v { color: var(--muted); white-space: nowrap; }
.lb-cols .on { color: #3ecf4a; }
@media (max-width: 420px) { .lb-cols { grid-template-columns: 1fr; } }

/* ------------------------------------------------- moving panels around */

.panel > .panel-head { touch-action: none; }
.panel.moving { opacity: 0.5; }
.panel-drop { flex: none; height: 4px; background: var(--accent); outline: 2px solid var(--ink); }
body.panel-dragging, body.panel-dragging * { cursor: grabbing !important; }
body.panel-dragging .sidebar {
  outline: 1px dashed var(--edge);
  outline-offset: -1px;
  border-radius: 4px;
  min-height: 120px;
}
#container-panel .row { margin-top: 6px; }
#container-panel .row button { flex: 1; padding: 2px 4px; }

/* ------------------------------------------------------- right-click menu */

#ctx-menu {
  position: fixed;
  z-index: 30;
  min-width: 170px;
  max-width: 290px;
  padding: 2px;
  border: var(--frame-tip-w) solid transparent;
  border-image: var(--frame-tip);
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.6);
  font-size: 14px;
}
#ctx-menu[hidden] { display: none; }
#ctx-menu button {
  display: block;
  width: 100%;
  border: 0;
  padding: 2px 10px;
  text-align: left;
  background: transparent;
  color: var(--text);
  cursor: pointer;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
#ctx-menu button:hover, #ctx-menu button:focus-visible { background: #1d2140; color: #ffd27a; outline: none; }
#ctx-menu hr { border: 0; border-top: 2px solid #1d2140; margin: 3px 2px; }

/* ------------------------------------------------------------ trade window */

/* The talk window (talk.rs): what the NPC says, then what one can say back. */
.talk-text p { margin: 0 0 6px; font-size: 13px; line-height: 1.35; }
.talk-options { list-style: none; margin: 4px 0; padding: 0; }
.talk-options button { display: flex; align-items: center; gap: 6px; width: 100%; padding: 3px 4px; text-align: left; font: inherit; font-size: 13px; color: #f2e6c8; background: none; border: 0; cursor: pointer; }
.talk-options button:hover { background: rgba(255, 220, 140, 0.12); }
.talk-mark { display: inline-block; width: 14px; text-align: center; font-family: var(--caps); font-size: 13px; color: #ffd42a; text-shadow: 1px 1px 0 #000; }
.talk-mark.grey { color: #a8a8a8; }
.talk-mark.topic { color: #9fc8ff; }
.talk-mark.trade { color: #e8c060; }
.quest-title { margin: 0 0 6px; font-family: var(--caps); font-size: 10px; color: #ffd42a; }
.quest-head { margin: 8px 0 3px; font-family: var(--caps); font-size: 8px; color: #e8c890; }
.quest-objectives { list-style: none; margin: 0; padding: 0; font-size: 13px; }
.quest-objectives li.done { color: #8cf58c; }
.quest-rewards { display: flex; flex-wrap: wrap; gap: 4px; align-items: center; }
.quest-pick { padding: 2px; min-height: 0; line-height: 0; border: 1px solid transparent; background: none; }
.quest-pick .slot { display: block; }
.quest-pick.picked { border-color: #ffd42a; box-shadow: 0 0 4px #ffd42a; }
.quest-pick:disabled { opacity: 1; cursor: default; }
.trade-list { list-style: none; margin: 0; padding: 0; max-height: 320px; overflow-y: auto; scrollbar-width: thin; }
.trade-list li { display: flex; align-items: center; gap: 6px; padding: 2px 0; font-size: 13px; }
.trade-list li + li { border-top: 2px solid var(--ink); }
.trade-list .trade-icon { flex: none; cursor: default; }
.trade-list .tr-info { flex: 1; min-width: 0; }
.trade-list .tr-name { display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.trade-list .tr-sub { display: flex; align-items: center; gap: 2px; }
.trade-list button, #trade-panel .row button { flex: none; padding: 0 8px; }
#trade-panel .row { margin: 6px 0; }
#talk-panel .row { display: flex; flex-wrap: wrap; gap: 4px; margin: 6px 0; }
#talk-panel .row button { flex: 1 1 auto; min-width: 0; padding: 0 6px; }
#trade-panel .row button { flex: 1; display: inline-flex; justify-content: center; align-items: center; gap: 3px; }
#trade-panel .row button:disabled { opacity: 0.5; cursor: default; }
#trade-panel.drop-here { outline: 2px solid var(--accent); }

/* ---------------------------------------------------- touch screens (phones)
   body.touch-ui (main.js): the game first, a slim HUD, the last chat lines,
   and a tab bar that opens one panel at a time in the sheet below the view.
   Landscape phones (.landscape): tabs down the right, the sheet slides over
   the game (the one place UI covers the view: there's no room around it). */

#hud, #chat-strip, #tabbar, .touch-only { display: none; }

body.touch-ui #app {
  grid-template-columns: minmax(0, 1fr);
  /* The view is sized by main.js layout(); spare height goes to the chat strip. */
  grid-template-rows: auto auto minmax(3.9em, 1fr) auto auto;
  grid-template-areas: "game" "hud" "strip" "sheet" "tabs";
  gap: 4px;
  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));
}
body.touch-ui #game-area { border: 0; background: none; }
body.touch-ui #stage { border-width: 1px; }
body.touch-ui .touch-only { display: block; }
body.touch-ui #sidebar-left { display: none !important; }

/* The sheet: the right sidebar (and chat) show only the open tab's panels. */
body.touch-ui #sidebar, body.touch-ui #chat { grid-area: sheet; display: none; max-height: 48dvh; }
body.touch-ui.sheet-open #sidebar { display: flex; }
body.touch-ui.sheet-chat #sidebar { display: none; }
body.touch-ui.sheet-chat #chat { display: flex; height: 42dvh; }
body.touch-ui.sheet-chat #chat-log { flex: 1; height: auto; }
body.touch-ui #sidebar > * { display: none; }
body.touch-ui #sidebar > .tab-shown:not([hidden]) { display: block; }
body.touch-ui #sidebar > #side-actions.tab-shown { display: grid; }
body.touch-ui .panel > .panel-head { cursor: default; }
body.touch-ui .panel > .panel-head::after { content: none; }
body.touch-ui .panel.collapsed > .panel-body { display: block; }
body.touch-ui .panel.collapsed > .panel-head { border-bottom: 2px solid var(--ink); }
body.touch-ui #minimap { width: min(320px, 80vw); height: min(320px, 80vw); }
body.touch-ui #side-actions button { padding: 8px 8px; font-size: 16px; }
body.touch-ui #ctx-menu button { padding: 10px 14px; font-size: 16px; }
body.touch-ui .slot { touch-action: none; }

body.touch-ui #hud {
  grid-area: hud;
  display: flex;
  align-items: center;
  gap: 6px;
}
#hud .meter { flex: 1; margin: 0; height: 26px; }
#hud .meter .text { line-height: 22px; }
.hud-chip { font-size: 15px; white-space: nowrap; font-variant-numeric: tabular-nums; text-shadow: 0 2px 0 var(--ink); }
#hud-level { color: var(--accent); }
#hud-attack { flex: none; display: grid; place-items: center; width: 44px; height: 34px; padding: 0; }
#hud-combat { flex: none; height: 34px; padding: 0 10px; font-size: 15px; touch-action: none; user-select: none; }
#hud-arrows { display: flex; gap: 2px; }
#hud-arrows[hidden], #hud-combat[hidden] { display: none; }
#hud-arrows button { width: 34px; height: 34px; padding: 0; font-size: 14px; touch-action: none; }

body.touch-ui #chat-strip {
  grid-area: strip;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  min-height: 0;
  padding: 0 4px;
  font-size: 14px;
  line-height: 1.25;
  color: var(--muted);
  text-shadow: 0 2px 0 var(--ink);
  overflow: hidden;
}
#chat-strip .line { flex: none; margin: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
#chat-strip .line:not(:nth-last-child(-n+3)) { opacity: 0.55; }
#chat-strip .from { color: var(--accent); }
#chat-strip .system { color: var(--system); }
#chat-strip .npc { color: var(--npc); }
#chat-strip .time { display: none; }

body.touch-ui #tabbar {
  grid-area: tabs;
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  gap: 2px;
  padding-top: 2px;
}
/* The tab bar: stone tabs, the open one lit. */
#tabbar button {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1px;
  padding: 2px 0;
  border: var(--frame-tab-w) solid transparent;
  border-image: var(--frame-tab);
  border-radius: 0;
  background: none;
  color: var(--muted);
  font-size: 12px;
  line-height: 1.1;
}
#tabbar button .pi { --pi-size: 32px; }
#tabbar button[aria-pressed="true"] { color: var(--accent); border-image: var(--frame-tab-on); }
#tabbar button .dot { width: 4px; height: 4px; background: var(--accent); outline: 2px solid var(--ink); margin-top: 1px; visibility: hidden; }
#tabbar button.news .dot { visibility: visible; }

/* The joystick, bottom-left over the game view. */
body.touch-ui.stick-on #stick:not([hidden]) {
  position: absolute;
  left: 14px;
  bottom: 14px;
  display: block;
  width: 112px;
  height: 112px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255, 255, 255, 0.10), rgba(255, 255, 255, 0.04));
  border: 2px solid rgba(255, 255, 255, 0.18);
  touch-action: none;
  z-index: 5;
}
#stick { display: none; }
#stick-knob {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 48px;
  height: 48px;
  margin: -24px 0 0 -24px;
  border-radius: 50%;
  background: rgba(224, 166, 75, 0.45);
  border: 2px solid rgba(255, 255, 255, 0.35);
  pointer-events: none;
}
#stick.active { border-color: rgba(224, 166, 75, 0.6); }

/* Logging in: the form gets the whole screen, never cut off. */
body.touch-ui #login {
  position: fixed;
  inset: 0;
  z-index: 20;
}
body.touch-ui .login-scroll { padding: max(12px, env(safe-area-inset-top)) 12px max(12px, env(safe-area-inset-bottom)); }
body.touch-ui #login .views, body.touch-ui #login-board, body.touch-ui .mode-info { width: min(340px, 100%); }
body.touch-ui .login-card { width: min(390px, 100%); }
body.touch-ui .primary, body.touch-ui .continue, body.touch-ui #login-other { padding: 8px 14px; font-size: 16px; }
@media (max-width: 420px) {
  #login h1.logo { font-size: 32px; line-height: 32px; }
  .login-card { padding: 8px 10px 10px; }
}
/* Phones: everything on one screen. Smaller buttons and gaps; no who's-around
   board (Highscores is linked from the card) or market countdown; the Delvia
   Daily panel keeps its titles, the market's list and the chain, and drops the
   lines marked .di-more. */
@media (max-width: 600px) {
  .login-scroll { justify-content: flex-start; padding-top: max(8px, env(safe-area-inset-top)) !important; }
  .login-card { gap: 4px; padding-top: 6px; padding-bottom: 8px; }
  #login .view { gap: 5px; }
  #login .tagline { margin-bottom: 2px; font-size: 13px; }
  .server-status { margin-bottom: 0; }
  #market-note, #login-board, .di-more { display: none !important; }
  body.touch-ui .primary, body.touch-ui .continue, body.touch-ui #login-other { padding: 5px 14px; font-size: 15px; }
  .mode-info { margin-top: 8px; padding: 8px 10px 10px; }
  .di-title { font-size: 18px; line-height: 20px; }
  .di-boxes { margin-top: 6px; gap: 6px; }
  .di-boxes > li { padding: 5px 8px 6px; }
  .di-bullets { gap: 3px 8px; }
}
/* Short phones (iPhone SE and the like): no "playing now" pill either. */
@media (max-width: 600px) and (max-height: 740px) {
  #server-status { display: none !important; }
  .mode-info { margin-top: 6px; }
}

/* Landscape phones: the game fills the height; tabs down the right edge. */
body.touch-ui.landscape #app {
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-rows: auto minmax(0, 1fr) auto;
  grid-template-areas: "hud tabs" "game tabs" "strip tabs";
}
body.touch-ui.landscape #tabbar {
  grid-auto-flow: row;
  grid-auto-rows: 1fr;
  grid-auto-columns: auto;
  padding: 0 0 0 2px;
  width: 60px;
}
body.touch-ui.landscape #tabbar button { padding: 0; font-size: 11px; }
body.touch-ui.landscape #tabbar button .pi { --pi-size: 16px; }
@media (min-height: 420px) { body.touch-ui.landscape #tabbar button .pi { --pi-size: 32px; } }
body.touch-ui.landscape #sidebar, body.touch-ui.landscape.sheet-chat #chat {
  position: fixed;
  top: max(4px, env(safe-area-inset-top));
  bottom: max(4px, env(safe-area-inset-bottom));
  right: calc(64px + env(safe-area-inset-right));
  width: min(320px, 46vw);
  max-height: none;
  height: auto;
  z-index: 10;
  padding: 4px;
  background: var(--bg);
  border: var(--frame-dialog-w) solid transparent;
  border-image: var(--frame-dialog);
  box-shadow: -6px 0 18px rgba(0, 0, 0, 0.5);
}
body.touch-ui.landscape #hud .meter { max-width: 220px; }
#ctx-menu .menu-head .tip { padding: 4px 8px 6px; font-size: 13px; border: 0; border-bottom: 2px solid #1d2140; margin-bottom: 3px; max-width: 260px; box-shadow: none; }
body.touch-ui.landscape #chat-strip { max-height: 3.9em; }

/* ------------------------------------------------------ notices on the view
   System messages (welcome, Look, loot, "too far away"...) float over the
   bottom of the game view for a few seconds, as well as going to the chat. */
#notices {
  position: absolute;
  left: 50%;
  bottom: 9%;
  transform: translateX(-50%);
  width: max-content;
  max-width: 92%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  pointer-events: none;
  z-index: 4;
}
#notices .notice {
  padding: 2px 10px;
  background: rgba(10, 9, 7, 0.62);
  color: #e8f1ff;
  font-size: 15px;
  line-height: 1.3;
  text-align: center;
  text-shadow: 0 2px 0 #000;
  white-space: pre-line;
  animation: notice-in 0.18s ease-out;
  transition: opacity 0.6s;
}
#notices .notice.fading { opacity: 0; }
@keyframes notice-in { from { opacity: 0; transform: translateY(6px); } }
body.touch-ui #notices { bottom: auto; top: 6%; }
body.touch-ui #notices .notice { font-size: 14px; }
body.touch-ui .desktop-only { display: none; }

/* ---------------------------------------------------------- outfit window */

#outfit-dialog { width: min(480px, calc(100vw - 24px)); }
#outfit-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); gap: 8px; margin-bottom: 12px; }
.outfit-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 6px 4px 4px;
  border: var(--frame-tab-w) solid transparent;
  border-image: var(--frame-tab);
  background: radial-gradient(circle at 50% 40%, #3a3428, #1a1814 70%) padding-box;
  color: var(--text);
  font-size: 14px;
  cursor: pointer;
}
.outfit-card canvas { image-rendering: pixelated; max-width: 100%; height: auto; }
.outfit-card[aria-checked="true"] { border-image: var(--frame-tab-on); color: var(--accent); }

/* ----------------------------------------------------------- panel toolbar
   Desktop: one icon per panel (main.js PANEL_ICONS); closed panels hide. */
#toolbar-panel .panel-body { padding: 4px; }
#toolbar { display: flex; gap: 2px; }
#toolbar button {
  flex: 1 1 0;
  display: grid;
  place-items: center;
  min-width: 0;
  height: 22px;
  padding: 0;
}
#toolbar button > .pi { opacity: 0.55; filter: grayscale(0.7); }
#toolbar button:hover > .pi { opacity: 0.85; filter: none; }
#toolbar button[aria-pressed="true"] { border-image: var(--frame-tab-on); }
#toolbar button[aria-pressed="true"] > .pi { opacity: 1; filter: none; }
body:not(.touch-ui) .panel.off { display: none; }

/* ------------------------------------------------------------- key hints
   Which key does what (body.key-hints, desktop only; main.js applyKeyHints):
   key caps on buttons, the key in a corner of backpack slots and panel icons. */
kbd.hint-key {
  display: none;
  margin-left: 6px;
  padding: 1px 3px 0;
  font: 8px/8px var(--caps);
  color: #2a241e;
  background: #f2ead8;
  box-shadow: 0 0 0 1px var(--ink), 0 2px 0 1px #b8b0a0;
  vertical-align: 2px;
}
body.key-hints:not(.touch-ui) kbd.hint-key { display: inline-block; }
:is(.slot, #toolbar button)[data-key]::before {
  content: attr(data-key);
  display: none;
  position: absolute;
  left: 3px;
  top: 3px;
  font: 8px/8px var(--caps);
  color: var(--muted);
  text-shadow: 1px 0 0 var(--ink), -1px 0 0 var(--ink), 0 1px 0 var(--ink), 0 -1px 0 var(--ink);
  pointer-events: none;
}
#toolbar button { position: relative; }
#toolbar button[data-key]::before { left: auto; right: 2px; top: auto; bottom: 1px; }
body.key-hints:not(.touch-ui) :is(.slot, #toolbar button)[data-key]::before { display: block; }
#keys-dialog { width: min(860px, calc(100vw - 24px)); max-height: calc(100vh - 24px); padding: 12px 24px; }
#keys-dialog h2 { font-size: 24px; line-height: 24px; margin-bottom: 8px; }
#keys-dialog .row button { font-size: 18px; padding: 4px 24px; }
#keys-table { width: 100%; border-collapse: collapse; margin-bottom: 12px; font-size: 18px; line-height: 22px; }
#keys-table tr + tr td { border-top: 1px solid rgba(242, 234, 216, 0.08); }
#keys-table td { padding: 4px 10px; vertical-align: middle; }
#keys-table td:first-child { white-space: nowrap; }
#keys-table kbd { display: inline-block; margin: 1px 6px 3px 0; padding: 4px 7px 2px; font: 16px/16px var(--caps); color: #2a241e; background: #f2ead8; box-shadow: 0 0 0 1px var(--ink), 0 2px 0 1px #b8b0a0; }
body.touch-ui #toolbar-panel { display: none !important; }

/* --------------------------------------------------------- player profiles */

.player-link {
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.player-link:hover, .player-link:focus-visible { color: var(--accent); text-decoration: underline; outline: none; }

#results-dialog { width: min(380px, calc(100vw - 24px)); }
#results-dialog p { margin: 0 0 6px; }
.rs-status { font-size: 18px; color: var(--accent); }
.rs-rooms { font-size: 20px; letter-spacing: 2px; }
.rs-small { font-size: 13px; margin-top: 8px !important; }
.rs-board { margin: 0 0 8px; padding-left: 22px; font-size: 13px; font-variant-numeric: tabular-nums; }
.rs-board li.me { color: var(--accent); }
.rs-leave { margin-top: 6px; }
#profile-dialog { width: min(460px, calc(100vw - 24px)); }
.pf-top { display: flex; gap: 14px; align-items: center; margin-bottom: 10px; }
.pf-look {
  flex: none;
  display: grid;
  place-items: center;
  width: 96px;
  height: 104px;
  border: var(--frame-tab-w) solid transparent;
  border-image: var(--frame-tab);
  background: radial-gradient(circle at 50% 40%, #3a3428, #1a1814 70%) padding-box;
}
.pf-look canvas { image-rendering: pixelated; max-width: 100%; }
.pf-who { flex: 1; min-width: 0; }
.pf-who h2 { margin: 0; font: 16px/20px var(--caps); color: var(--accent); overflow-wrap: anywhere; }
.pf-title { font-size: 14px; min-height: 0; }
.pf-guild { color: #9fe39a; font-size: 13px; }
.pf-guild:empty { display: none; }
.pf-supporter { color: #ff6f91; font-size: 13px; }
#pf-seen { margin: 2px 0 6px; font-size: 13px; }
#pf-seen.on { color: #6fdc6f; }
.pf-cols { display: grid; grid-template-columns: auto 1fr; gap: 16px; margin-bottom: 12px; }
.pf-cols .login-label { margin: 0 0 4px; }
.pf-cols section > .login-label:not(:first-child) { margin-top: 10px; }
#pf-equip .slot { display: block; }
@media (max-width: 420px) { .pf-cols { grid-template-columns: 1fr; } }
#bag .no-bag { grid-column: 1 / -1; margin: 4px 2px; color: var(--error); }

/* ---------------------------------------------------------- the world map */

.minimap-wrap { position: relative; width: fit-content; margin: 0 auto; }
#worldmap-btn {
  position: absolute;
  right: 4px;
  top: 4px;
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  padding: 0;
}
#worldmap {
  position: fixed;
  inset: 0;
  z-index: 45;
  background: #07070a;
}
#worldmap[hidden] { display: none; }
#wm-canvas { position: absolute; inset: 0; width: 100%; height: 100%; cursor: grab; touch-action: none; }
#wm-canvas:active { cursor: grabbing; }
/* A zone under the mouse (worldmap-zones.js). */
#wm-zone-tip { position: fixed; z-index: 60; min-width: 0; pointer-events: none; }
#wm-zone-tip[hidden] { display: none; }
#worldmap .wm-bar {
  position: absolute;
  top: max(10px, env(safe-area-inset-top));
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 4px 8px;
  border: var(--frame-panel-w) solid transparent;
  border-image: var(--frame-panel);
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.5);
}
#worldmap .wm-bar b { font: 16px var(--caps); color: var(--accent); margin-right: 4px; text-shadow: 0 2px 0 var(--ink); }
#wm-floor { color: var(--muted); font-size: 14px; min-width: 100px; }
#worldmap .wm-bar button { width: 32px; height: 30px; padding: 0; }
#worldmap .wm-hint {
  position: absolute;
  bottom: max(10px, env(safe-area-inset-bottom));
  left: 0;
  right: 0;
  margin: 0;
  text-align: center;
  font-size: 14px;
  color: var(--muted);
  text-shadow: 0 2px 0 var(--ink);
  pointer-events: none;
}
@media (max-width: 600px) {
  #worldmap .wm-bar { flex-wrap: wrap; justify-content: center; width: calc(100vw - 20px); }
  #worldmap .wm-bar b { display: none; }
}

/* ---------------------------------------------------------------- guests */

#play-guest { padding: 2px 14px; color: #ffd27a; font-size: 15px; }
#login .name-row { display: flex; gap: 6px; }
#login .name-row input { flex: 1; }
#guest-reroll { display: grid; place-items: center; width: 40px; padding: 0; }
#login .small { margin: 0; font-size: 13px; line-height: 1.3; }
#saved-list .guest-tag { color: var(--muted); font-weight: 400; }
#side-actions #guest-save { color: #ffd27a; }
#side-actions button[hidden] { display: none; }

#claim-dialog { width: min(380px, calc(100vw - 32px)); }
#claim-dialog p { margin: 0 0 8px; font-size: 15px; }
#claim-dialog input { width: 100%; margin-bottom: 6px; padding: 4px 8px; font-size: 16px; }
#claim-dialog .error { color: var(--error); min-height: 1.2em; margin: 0 0 6px; }
#claim-dialog .row { margin-top: 10px; }


/* ---------------------------------------------------------- WoW interface
   An experiment (body.wow-ui, main.js applyUiStyle; desktop only): the view
   covers the window and the UI floats over it, as in World of Warcraft. The
   one desktop layout where UI covers the view. Health top-left, the round
   minimap top-right, windows down the left (#wow-windows), the bag and the
   game menu bottom-right (#wow-right) over the micro menu (the toolbar),
   the chat bottom-left. */

body.wow-ui #app { grid-template-columns: minmax(0, 1fr); grid-template-rows: minmax(0, 1fr); grid-template-areas: "game"; padding: 0; gap: 0; }
body.wow-ui #game-area { position: relative; }
body.wow-ui #stage { box-shadow: none; }
body.wow-ui :is(#sidebar, #sidebar-left) { display: contents; }
body.wow-ui #status { display: none; }
#wow[hidden] { display: none; }
body.wow-ui #wow { position: absolute; inset: 0; z-index: 6; pointer-events: none; }
/* Nothing of the game shows over the login screen. */
body.wow-ui:has(#login:not([hidden])) :is(#wow, #toolbar-panel, #map-panel, #health-panel, #chat) { display: none !important; }

/* Windows: the panels, with a ✕ for the head's - (a click closes them). */
body.wow-ui .panel { box-shadow: 0 6px 18px rgba(0, 0, 0, 0.55); }
body.wow-ui .panel > .panel-head { cursor: default; }
body.wow-ui .panel > .panel-head::after { content: "✕"; cursor: pointer; }
body.wow-ui :is(#container-panel, #trade-panel, #talk-panel, #health-panel, #map-panel, #toolbar-panel) > .panel-head::after { content: none; }
body.wow-ui .panel.collapsed > .panel-body { display: block; }
body.wow-ui .panel.collapsed > .panel-head { border-bottom: 2px solid var(--ink); }
#wow-windows {
  position: absolute;
  left: 12px;
  top: 84px;
  bottom: 224px; /* over the chat */
  display: flex;
  flex-direction: column;
  flex-wrap: wrap;
  align-content: flex-start;
  align-items: flex-start;
  gap: 6px;
}
#wow-windows > .panel { width: 228px; max-height: 100%; overflow-y: auto; scrollbar-width: thin; pointer-events: auto; }
#wow-windows > .panel[hidden] { display: none; }
#wow-right {
  position: absolute;
  right: 12px;
  bottom: 52px;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 6px;
}
#wow-right > * { pointer-events: auto; }
#wow-right > .panel { width: 228px; }
body.wow-ui #side-actions {
  width: 228px;
  padding: 6px;
  border: var(--frame-panel-w) solid transparent;
  border-image: var(--frame-panel);
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.55);
}
body.wow-ui #side-actions.off { display: none; }
body:not(.wow-ui) #toolbar [data-panel="side-actions"],
body.wow-ui #toolbar :is([data-panel="char-panel"], [data-panel="health-panel"]) { display: none; }

/* Unit frames, top-left (main.js unitFrames): ours, then the target's. A
   round portrait in a ring, its level badge on the ring, name and health
   on a plate beside it. Monsters' bars are red, everyone else's green. */
.unit-frame {
  position: absolute;
  top: 12px;
  left: 12px;
  width: 236px;
  height: 64px;
  pointer-events: auto;
}
.unit-frame[hidden] { display: none; }
#wow-target { left: 260px; }
.unit-frame .portrait {
  position: absolute;
  left: 0;
  top: 0;
  z-index: 1;
  width: 60px;
  height: 60px;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 40%, #3a3428, #14110c 70%);
  box-shadow: 0 0 0 2px var(--ink), 0 0 0 5px #8a6a3a, 0 0 0 7px var(--ink), 0 4px 12px 6px rgba(0, 0, 0, 0.45);
  image-rendering: pixelated;
}
.unit-frame .unit-level {
  position: absolute;
  left: -4px;
  top: 42px;
  z-index: 2;
  min-width: 26px;
  height: 22px;
  padding: 0 3px;
  font: 13px/22px var(--font);
  text-align: center;
  color: #ffd27a;
  background: #14110c;
  border-radius: 11px;
  box-shadow: 0 0 0 2px #8a6a3a, 0 0 0 4px var(--ink);
  text-shadow: 0 1px 0 #000;
}
.unit-frame .unit-body {
  position: absolute;
  left: 40px;
  right: 0;
  top: 8px;
  padding: 3px 8px 0 28px;
  border: var(--frame-panel-w) solid transparent;
  border-image: var(--frame-panel);
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.55);
}
.unit-frame .unit-name {
  overflow: hidden;
  font-size: 14px;
  line-height: 17px;
  white-space: nowrap;
  text-overflow: ellipsis;
  color: #f0f0f0;
  text-shadow: 0 1px 0 #000;
}
.unit-frame .meter { height: 18px; margin: 2px 0 4px; }
.unit-frame .meter .fill { background: #1f9a2a; }
.unit-frame[data-kind="monster"] .meter .fill { background: #b8221a; }
.unit-frame .meter.still :is(.fill, .lag) { transition: none; }
.unit-frame .meter .text { text-shadow: 1px 1px 0 var(--ink), -1px 1px 0 var(--ink), 1px -1px 0 var(--ink), -1px -1px 0 var(--ink); }

/* The minimap, top-right: round, in a ring, the zone above it. */
body.wow-ui #map-panel {
  position: fixed;
  right: 12px;
  top: 8px;
  z-index: 6;
  border: 0;
  border-image: none;
  background: none;
  box-shadow: none;
}
body.wow-ui #map-panel > .panel-head {
  justify-content: center;
  border: 0;
  box-shadow: none;
  font: 13px var(--font);
  letter-spacing: 0;
  color: #ffd27a;
}
body.wow-ui #map-panel > .panel-head { font-size: 0; } /* "Map" goes; the zone stays */
body.wow-ui #map-zone { font-size: 14px; }
body.wow-ui #minimap {
  width: 176px;
  height: 176px;
  border-radius: 50%;
  outline: 0;
  box-shadow: 0 0 0 2px var(--ink), 0 0 0 5px #8a6a3a, 0 0 0 7px var(--ink), 0 4px 14px 7px rgba(0, 0, 0, 0.5);
}
body.wow-ui #worldmap-btn { right: -4px; top: auto; bottom: -4px; border-radius: 0; }

/* The micro menu: the toolbar, bottom-right. */
body.wow-ui #toolbar-panel { position: fixed; right: 12px; bottom: 12px; z-index: 6; width: auto; }
body.wow-ui #toolbar button { width: 32px; flex: none; height: 26px; }

/* The chat, bottom-left, see-through. */
body.wow-ui #chat {
  position: fixed;
  left: 12px;
  bottom: 12px;
  width: 400px;
  z-index: 5;
  border: 0;
  border-image: none;
  background: rgba(8, 7, 5, 0.42);
}
body.wow-ui #chat-head { border-bottom: 0; box-shadow: none; background: rgba(8, 7, 5, 0.35); }
body.wow-ui #chat-log { height: 150px; text-shadow: 0 1px 0 #000, 0 0 3px #000; }
body.wow-ui #chat-input:not(:focus) { opacity: 0.5; }
body.wow-ui #notices { bottom: 240px; max-width: min(720px, 50%); }
