:root {
  --bg: #1c1a17;
  --panel: #2b2722;
  --panel-border: #4a4238;
  --text: #d8d0c0;
  --muted: #8f8677;
  --accent: #c8a45a;
}
* { box-sizing: border-box; }
html, body {
  margin: 0; height: 100%;
  background: var(--bg); color: var(--text);
  font: 13px/1.4 "Segoe UI", system-ui, sans-serif;
  overflow: hidden;
}
#app {
  display: grid;
  grid-template-columns: 1fr 240px;
  height: 100vh;
  /* Full screen on a phone means the notch and the gesture bar are the
     page's problem: the viewport meta says cover the lot, and these give
     the borrowed edges back so no panel hides under hardware. They are
     zero on everything that has no insets, which is every desktop. */
  padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);
}
/* Small screens are played by tapping, and a tap that has to wait to see
   whether it was a double tap is a tap that feels broken. Nothing here
   zooms — the world is drawn to fit — so the wait is pure cost. */
#game, #buttons button {
  touch-action: manipulation;
}
/* The viewport unit follows the browser's own chrome as it hides and
   shows, where the browser supports it; 100vh is the fallback above. */
@supports (height: 100dvh) {
  #app { height: 100dvh; }
}
#gamewrap {
  display: flex; flex-direction: column;
  min-width: 0; min-height: 0;
  background: #000;
}
/* The canvas and anything laid over it. It is its own positioned box so an
   overlay can cover the view alone: the console below it and the bag and
   stats beside it stay where they are, and stay readable. */
#view {
  position: relative;
  flex: 1 1 0; min-height: 0;
  display: flex;
}
#game {
  /* flex-basis 0 so the backing store's own size never feeds back into layout: the
     renderer sizes it from this element, in device pixels, and letterboxes itself. */
  flex: 1 1 0;
  display: block;
  width: 100%; min-height: 0;
  cursor: crosshair;
  outline: none;
  background: #000;
}
#console {
  height: 150px; flex: 0 0 auto;
  display: flex; flex-direction: column;
  background: var(--panel); border-top: 2px solid var(--panel-border);
}
/* What the console is showing, one toggle per kind of message. A strip
   rather than a menu: which kinds are off is the sort of thing you want to
   see without asking, since a filter you have forgotten about looks exactly
   like a game that has stopped telling you things. */
#logfilters {
  flex: 0 0 auto; display: flex; flex-wrap: wrap; gap: 3px;
  padding: 3px 6px; border-bottom: 1px solid var(--panel-border);
}
#logfilters button {
  font: inherit; font-size: 10px; line-height: 1.4;
  padding: 0 5px; border-radius: 3px; cursor: pointer;
  border: 1px solid #3a352c; background: #221f18; color: var(--text);
  /* Each switch is named by the kind it hides, and is given that kind's
     own string to display rather than a label written out beside it, so
     the two can never drift. Capitalising is this stylesheet's business:
     the button reads as a word on a strip, and the same string at the head
     of a line reads as what the line is. */
  text-transform: capitalize;
}
#logfilters button[aria-pressed="true"] { border-color: #6a6250; background: #332f24; }
/* An off filter is legible but plainly off: dimmed and struck through, so
   a glance along the strip says what is missing from the log. */
#logfilters button[aria-pressed="false"] { color: #6d675c; text-decoration: line-through; }
#log {
  flex: 1; overflow-y: auto; padding: 4px 8px;
  font-family: ui-monospace, Consolas, monospace; font-size: 12px;
  white-space: pre-wrap; word-break: break-word;
}
/* What kind each line is, shown only while the Type switch on the strip is
   on. Every line carries its label whether or not it is being shown, so
   switching it on names the log you already have rather than starting a
   new one. Each kind gets a colour of its own, unlike the lines
   themselves — a blow and a shopkeeper are both plain white to read, and
   the whole point of the label is to tell apart what looks alike. It is
   padded to the longest kind so the words after it line up in a column. */
#log .kind { display: none; }
#log.types .kind {
  display: inline-block; width: 8ch; font-size: 11px;
}
#log .k-say { color: #f2d24a; }
#log .k-noise { color: #ff9a3c; }
#log .k-combat { color: #ff8a8a; }
#log .k-loot { color: #6ede6e; }
#log .k-level { color: #c9a2ff; }
#log .k-event { color: #6fb8e8; }
#log .k-server { color: #cfcfcf; }
#log .k-blocked { color: #d9863c; }
#log .k-debug { color: #8fa3b5; }
#log .k-error { color: #ff2d55; }
/* The arrival time on every line: quiet, so the words stay the loudest
   thing on the line. */
#log .ts { color: #7a746a; font-size: 11px; }
#log .say { color: #f0d060; }
#log .server { color: #dcdcdc; }
/* Blows land in the same plain white as anything else said to you: they
   are their own kind so the filters can turn them off, not because they
   should look different while they are on. */
#log .combat { color: #dcdcdc; }
/* World news — arrivals, departures, deaths, level-ups — reads apart from
   messages addressed to you. */
#log .event { color: #8fb8d8; font-style: italic; }
#log .loot { color: #7ed77e; }
#log .level { color: #ff8; font-weight: bold; }
#log .error { color: #f66; }
/* The damage sums, when they are asked for: quiet and monospaced, since
   they are arithmetic to be read rather than news to be told. */
#log .debug { color: #9aa8b4; font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace; font-size: 11px; }
/* The way between levels is blocked: a state of the world rather than a
   mistake of yours, so it gets its own colour between the two. */
#log .blocked { color: #f09a5a; }
/* Noises — eating, and whatever else gets a sound — in Tibia's
   creature-sound orange, apart from the yellow of words. */
#log .noise { color: #ffae42; }
/* The minimap's level peek: the floor being shown, named, and small arrows
   to change it. The name goes to the left of the arrows and the whole lot
   is floated right, so the arrows keep their place while the name beside
   them changes length. */
#maplevelctl { float: right; }
/* The zoom sits to the right of the level arrows and left of nothing, so
   the two pairs read as one row of controls on the panel's title. */
#mapzoomctl { float: right; margin-left: 6px; }
#maplevelctl button, #mapzoomctl button {
  background: #201c17; color: var(--text); border: 1px solid var(--panel-border);
  padding: 0 6px; margin-left: 2px; cursor: pointer; font-size: 10px; line-height: 16px;
}
#maplevelctl button:hover, #mapzoomctl button:hover { border-color: var(--accent); }
/* At either end of the range the button is plainly spent rather than
   gone: a control that disappears takes the pair's shape with it. */
#mapzoomctl button:disabled { color: var(--muted); border-color: #2a251e; cursor: default; }
#mapzoomctl button:disabled:hover { border-color: #2a251e; }
#maplevel { color: var(--muted); margin-right: 6px; font-size: 11px; }
/* A floor that is not the one you are standing on wears the accent, since
   that is the thing worth noticing about it. */
#maplevel.peek { color: var(--accent); }
#log .own { color: #ffe9a0; }
#chat {
  border: 0; border-top: 1px solid var(--panel-border);
  background: #16140f; color: var(--text); padding: 6px 8px; font: inherit; outline: none;
}
#chat:focus { background: #221f18; }

#side {
  background: var(--panel); border-left: 2px solid var(--panel-border);
  overflow-y: auto; padding: 6px;
  display: flex; flex-direction: column; gap: 6px;
}
.panel {
  background: #201d19; border: 1px solid var(--panel-border);
  padding: 6px; border-radius: 3px;
}
.panel .title { font-weight: bold; color: var(--accent); margin-bottom: 4px; }
.panel .title small { color: var(--muted); font-weight: normal; }
/* What the bag weighs, beside the panel's own name: a fact about the
   squares below rather than a stat of its own, so it is quiet. */
#invcn { color: var(--muted); font-weight: normal; font-size: 11px; }
.row { display: flex; justify-content: space-between; margin-top: 3px; }
.row b.hungry { color: #e66; }
/* The ping reads as what it costs you rather than as a number to admire:
   green while nothing notices, amber where a step starts to lag, red where
   a swing lands late. A dash — nothing to report — keeps the plain colour. */
.row b.good { color: #8ec98e; }
.row b.fair { color: #d8bd6a; }
.row b.bad { color: #e66; }
.bar {
  position: relative; height: 14px; background: #111; border: 1px solid #000;
  margin: 3px 0; overflow: hidden;
}
.bar > div { height: 100%; width: 0; transition: width .15s; }
.bar.hp > div { background: linear-gradient(#e33, #900); }
.bar.food > div { background: linear-gradient(#c98a3a, #7a4d18); }
.bar.food.empty > div { background: linear-gradient(#6a3030, #3a1a1a); }
/* Violet, and nothing else on the panel is: health is red, mana blue and
   food brown, and experience used to be a blue near enough to mana's that
   the two read as one fact at a glance. It is also the one bar that only
   ever climbs, which is worth seeing without reading the numbers. */
.bar.xp > div { background: linear-gradient(#b07ae8, #4c2a8c); }
/* Mana is Tibia's blue, and deliberately not the experience bar's: one is
   a pool that empties and fills all day, the other only ever climbs. */
.bar.mana > div { background: linear-gradient(#3aa0e8, #1a4a86); }
.bar span {
  position: absolute; inset: 0; text-align: center; font-size: 11px; line-height: 14px;
  color: #fff; text-shadow: 0 0 2px #000, 0 0 2px #000;
}
/* Shown only while the player stands on safe ground. */
/* Statuses share one line. The row hands the whole remaining width to the
   value so it can be measured for overflow: the labels are shortened until
   they fit rather than wrapping or being cut off. */
.row.statuses { align-items: baseline; gap: 6px; }
#statuses {
  flex: 1 1 auto; min-width: 0; overflow: hidden;
  display: flex; gap: 4px; justify-content: flex-end; white-space: nowrap;
}
#statuses .status {
  /* Never shrink. The line picks between writing the statuses out in full,
     as initials, or as icons by measuring whether they overflow, and a chip
     that squashes instead of overflowing hides that from the measurement:
     the row then reads as fitting while the words inside it are cut off. */
  flex: 0 0 auto;
  padding: 0 3px; border: 1px solid #3a4048; border-radius: 2px;
  font-size: 10px; font-weight: bold; letter-spacing: .5px; color: #b9c2cc;
}
#statuses .status.good { border-color: #4a6a8c; color: #9cc4ee; }
#statuses .status.warn { border-color: #8c7a3a; color: #e0c46a; }
#statuses .status.bad { border-color: #8c4a4a; color: #e88; }
#statuses .status.icon { border: 0; padding: 0; font-size: 12px; letter-spacing: 0; }
#statuses .none { color: #666; font-size: 11px; }

/* Skills: a name, a thin bar of progress to the next level, and the level. */
.skillstitle { margin-top: 6px; font-size: 12px; }
#skills .skill {
  display: grid; grid-template-columns: 5.2em 1fr 2em; align-items: center; gap: 6px;
  margin-top: 2px; font-size: 12px;
}
#skills .skill span { color: var(--muted); text-transform: capitalize; }
#skills .skill b { text-align: right; }
/* A broken piece in the bag: the sprite is already greyed and cracked, so
   the slot only has to stop it looking like usable gear. */
.slot.broken { border-style: dashed; opacity: 0.75; }
.slot.broken canvas { filter: contrast(0.85); }

/* How worn a piece is: a hairline along the bottom of its square, as wide as
   the condition is high. A bar rather than a number because a bag is twenty
   squares of 32 pixels and twenty numbers in them would be unreadable — what
   the bar has to do is let you pick the worn one out of a bagful at a glance,
   and the tooltip and the look say the figure for whoever wants it.

   It is only drawn on a piece that has been used. Untouched is what
   everything starts as, so a full bar under every new item would be a row of
   lines that mean nothing, and the one piece that is actually going would be
   lost among them.

   The colour is the warning and it is the whole of it: iron while there is
   plenty left, amber past the point where a trip to the yard is worth
   planning, red when it is nearly gone. Nothing blinks and nothing pops up —
   the number is on the screen, and noticing it is the player's job. */
.slot .cond {
  position: absolute; left: 1px; right: 1px; bottom: 1px; height: 2px;
  background: #000;
}
.slot .cond > i { display: block; height: 100%; background: #9a8a6a; }
.slot .cond.low > i { background: #c8a45a; }
.slot .cond.spent > i { background: #a4453a; }

#skills .skillbar { height: 6px; background: #111; border: 1px solid #000; overflow: hidden; }
#skills .skillbar > div { height: 100%; width: 0; background: linear-gradient(#9c7, #463); transition: width .15s; }

#inv, #depot {
  display: grid; grid-template-columns: repeat(5, 1fr); gap: 3px;
}
#inv .slot, #depot .slot {
  aspect-ratio: 1; background: #111; border: 1px solid #3a342c;
  display: flex; align-items: center; justify-content: center; position: relative;
  cursor: pointer;
}
/* A touch long-press is the right-click, so the browser's own answers to a
   held finger — iOS's magnifier and callout, text selection, double-tap
   zoom — must stand aside on everything that takes one. */
#game, #inv .slot, #depot .slot {
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
  touch-action: manipulation;
}
/* The minimap wants the same hands off, and a touch-action of its own:
   dragging it pans the map, so the browser may not have the gesture. */
#minimap {
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
}
#inv .slot:hover, #depot .slot:hover, #forgeslot:hover { border-color: var(--accent); }

/* The anvil: the one piece laid out, beside what the work costs and how far
   along it is. The slot borrows the bag's own square rather than inventing
   another kind, since it holds the same thing a bag slot does — one piece,
   drawn the same way, cracked while it is still broken. */
#forgework { display: flex; gap: 6px; align-items: stretch; }
#forgeslot {
  flex: 0 0 auto; width: 40px; aspect-ratio: 1;
  background: #111; border: 1px solid #3a342c;
  display: flex; align-items: center; justify-content: center; position: relative;
}
/* An empty anvil is a square waiting for something, so it says so quietly
   rather than sitting there looking like a slot that failed to draw. */
#forgeslot:empty::after { content: "—"; color: #555; }
#forgeslot canvas { width: 32px; height: 32px; image-rendering: pixelated; }
#forgeslot.filled { cursor: pointer; }
#forgefacts { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; justify-content: center; }
#forgefacts .row { margin-top: 0; font-size: 12px; }
/* The cooldown between swings, in the same shape as the bars on the stat
   panel: iron, because that is what is being beaten. It empties rather than
   fills — what it shows is the wait running out. */
.bar.forge { height: 8px; margin: 4px 0 0; }
.bar.forge > div { background: linear-gradient(#c8b28a, #6a5a3a); transition: width .1s linear; }
.bar.forge span { font-size: 9px; line-height: 8px; }
/* The one control. It reads as the state it is in, and wears the accent
   while the hammer is swinging, the way the toggles below the map do. */
#forgebtn {
  width: 100%; margin-top: 6px;
  background: #16140f; color: var(--accent); border: 1px solid var(--panel-border);
  padding: 5px 10px; font: inherit; font-weight: bold; border-radius: 2px; cursor: pointer;
}
#forgebtn:hover:not(:disabled), #forgebtn:focus-visible { border-color: var(--accent); background: #221f18; }
#forgebtn:disabled { color: #665f4f; cursor: default; }
#forgebtn.working { border-color: var(--accent); background: #2a2419; }
/* The weapon and armor the server is actually fighting with. */
#inv .slot.equipped { border-color: var(--accent); box-shadow: inset 0 0 0 1px rgba(200, 164, 90, .5); }
#inv .slot canvas { width: 32px; height: 32px; image-rendering: pixelated; }
#inv .slot .count, #depot .slot .count {
  position: absolute; right: 2px; bottom: 0; font-size: 10px; color: #fff; text-shadow: 0 0 2px #000;
}
/* Dragged to look around, so the browser's own idea of what a drag on a
   canvas means — scrolling the panel, zooming the page — is called off.
   The pointer stays a pointer, because the commonest thing done here is
   still a click that walks you somewhere; the hand appears only once a
   drag is actually under way, which the script says by hanging .panning
   on the canvas. An open hand sitting there all the time advertised the
   rarer of the two gestures and hid the other one. */
#minimap {
  width: 100%; image-rendering: pixelated; border: 1px solid #000;
  cursor: pointer; touch-action: none;
}
#minimap.panning { cursor: grabbing; }

#buttons { display: flex; flex-wrap: wrap; gap: 4px; }
#buttons button {
  flex: 1 1 auto;
  background: #16140f; color: var(--accent); border: 1px solid var(--panel-border);
  padding: 5px 10px; font: inherit; font-weight: bold; border-radius: 2px; cursor: pointer;
}
#buttons button:hover, #buttons button:focus-visible { border-color: var(--accent); background: #221f18; }
/* PvP on is the state worth noticing, so the button goes red for it. */
#buttons button.on { border-color: #8c4a4a; color: #e88; }
#buttons button.on:hover, #buttons button.on:focus-visible { border-color: #e88; }
/* Logging out is refused while something is after you; say so by feel. */
#buttons button:disabled { color: var(--muted); cursor: not-allowed; opacity: .55; }
#buttons button:disabled:hover { border-color: var(--panel-border); background: #16140f; }

#help, #invhelp, #maphelp, #scores, #changes, #slotmenu, #login {
  position: fixed; inset: 0; background: rgba(0,0,0,.85);
  display: flex; align-items: center; justify-content: center;
}
#help[hidden], #invhelp[hidden], #maphelp[hidden], #scores[hidden], #changes[hidden], #slotmenu[hidden], #login[hidden] { display: none; }
#counter[hidden] { display: none; }
#help, #invhelp, #maphelp, #scores, #changes, #slotmenu { z-index: 10; }
/* A panel's own help: a question mark beside its title, quiet until it is
   wanted. It replaced a caption that had room for two clicks out of six
   and was in the way of the panel the rest of the time. */
.panelhelp {
  float: right; width: 16px; height: 16px; padding: 0; line-height: 14px;
  background: #201c17; color: var(--muted); border: 1px solid var(--panel-border);
  border-radius: 8px; font: inherit; font-size: 10px; cursor: pointer;
}
.panelhelp:hover { color: var(--accent); border-color: var(--accent); }
/* The boards from the login screen: a link under the form rather than a
   button competing with Enter Game, since it is a thing to read on the way
   in rather than a way in. */

/* What to do with one thing in the bag: the touchscreen's answer to the
   right-click, and the only way a phone can reach the whole pile. Its
   buttons are finger-sized rather than pointer-sized — a mis-tap here puts
   forty rocks on the floor — and the whole box sits in the middle of the
   screen rather than beside the slot, since a menu anchored to a square in
   the corner of a telephone has nowhere to open. */
#slotmenubox {
  background: var(--panel); border: 2px solid var(--panel-border); border-radius: 4px;
  padding: 16px 18px; width: min(320px, calc(100vw - 32px)); max-height: 85vh; overflow-y: auto;
}
#slotmenubox h2 { margin: 0 0 6px; color: var(--accent); font-size: 17px; letter-spacing: 1px; }
/* What the thing is. On a mouse this is the slot's tooltip; a finger
   cannot hover, so the one place a phone can read it is here. */
#slotmenubox p { margin: 0 0 12px; color: var(--muted); font-size: 12px; line-height: 1.4; }
#slotmenuacts { display: flex; flex-direction: column; gap: 6px; margin-bottom: 10px; }
#slotmenubox button {
  font: inherit; font-size: 14px; padding: 10px 12px; width: 100%;
  border: 1px solid var(--panel-border); border-radius: 3px;
  background: #201c17; color: var(--text); cursor: pointer; text-align: left;
}
#slotmenubox button:hover, #slotmenubox button:focus-visible { border-color: var(--accent); }
/* Letting go of a whole pile is the one action here worth a second's
   thought, so it is coloured like one rather than sitting in the row
   looking exactly like the button above it. */
#slotmenuacts button.all { color: #e8a; border-color: #6a4a58; }
#slotmenuacts button.all:hover, #slotmenuacts button.all:focus-visible { border-color: #e8a; }
#slotmenuclose { color: var(--muted); text-align: center; }

#helpbox {
  background: var(--panel); border: 2px solid var(--panel-border); border-radius: 4px;
  padding: 18px 22px; max-width: 460px; max-height: 85vh; overflow-y: auto;
}
#helpbox h2 { margin: 0 0 10px; color: var(--accent); font-size: 20px; letter-spacing: 1px; }
/* Each section of the help has its own heading and its own key/value list,
   so the controls can be found without reading how the game works. */
#helpbox h3 {
  margin: 12px 0 6px; padding-bottom: 3px; border-bottom: 1px solid var(--panel-border);
  color: var(--accent); font-size: 14px; letter-spacing: 1px; text-transform: uppercase;
}
#helpbox h2 + h3 { margin-top: 0; }
#helpbox dl {
  display: grid; grid-template-columns: auto 1fr; gap: 4px 14px;
  margin: 0; font-size: 12px;
}
#helpbox dt { color: var(--accent); white-space: nowrap; }
#helpbox dd { margin: 0; color: var(--muted); }
#helpclose, #scoresclose, #counterclose {
  display: block; width: 100%; margin-top: 14px;
  background: var(--accent); color: #221; border: 0; padding: 7px;
  font: inherit; font-weight: bold; cursor: pointer;
}
/* The highscores: one small table per board — level, then each skill —
   flowing side by side as the width allows. */
#scoresbox {
  background: var(--panel); border: 2px solid var(--panel-border); border-radius: 4px;
  padding: 18px 22px; max-width: 640px; max-height: 85vh; overflow-y: auto;
}
#scoresbox h2 { margin: 0 0 10px; color: var(--accent); font-size: 20px; letter-spacing: 1px; }
#scoresbody { display: flex; flex-wrap: wrap; gap: 14px; }
#scoresbody table { border-collapse: collapse; font-size: 12px; min-width: 150px; }
#scoresbody caption {
  color: var(--accent); font-size: 13px; letter-spacing: 1px; text-transform: uppercase;
  text-align: left; padding-bottom: 4px; border-bottom: 1px solid var(--panel-border);
}
#scoresbody td { padding: 2px 6px; color: var(--muted); }
/* The changelog reads as a column of dated entries. Anything that landed
   while the player was away wears the accent down its edge, so what is new
   is found by scanning rather than by reading dates. */
#changesbox {
  background: var(--panel); border: 2px solid var(--panel-border); border-radius: 4px;
  padding: 18px 22px; max-width: 520px; max-height: 85vh; overflow-y: auto;
}
#changesbox h2 { margin: 0 0 10px; color: var(--accent); font-size: 20px; letter-spacing: 1px; }
#changesbody .entry { padding: 0 0 10px 10px; border-left: 3px solid transparent; margin-bottom: 10px; }
#changesbody .entry.new { border-left-color: var(--accent); }
#changesbody .when { color: var(--muted); font-size: 11px; letter-spacing: 1px; }
#changesbody .entry.new .when::after {
  content: "NEW"; margin-left: 8px; color: var(--accent); font-weight: 700;
}
#changesbody h3 { margin: 2px 0 4px; color: var(--text); font-size: 14px; }
#changesbody p { margin: 0; color: var(--muted); font-size: 12px; line-height: 1.5; }
#changesbody .none { color: var(--muted); font-size: 12px; }
/* The button says how many are waiting, and stops saying so once they have
   been looked at. */
#changesbtn.unread { border-color: var(--accent); color: var(--accent); }
#scoresbody td.rank { color: var(--accent); text-align: right; }
#scoresbody td.val { text-align: right; color: var(--text); }
#scoresbody tr.me td { color: #ffe9a0; }
/* The collage of web/static/bg/ images behind the login form, darkened so
   the form stays readable over anything. */
#loginbg {
  position: absolute; inset: 0; z-index: -1; overflow: hidden;
  display: flex; flex-direction: column; gap: 2px;
  filter: brightness(0.4) saturate(0.9);
}
/* Rows are measured in script: each one fills the width exactly and every
   image in it keeps its own shape, so the cover here only swallows the odd
   rounding pixel. */
#loginbg .bgrow { display: flex; gap: 2px; flex: 0 0 auto; }
#loginbg img { height: 100%; flex: 0 0 auto; object-fit: cover; display: block; }

#loginform {
  background: var(--panel); border: 2px solid var(--panel-border); padding: 24px 28px;
  width: 320px; display: flex; flex-direction: column; gap: 10px; border-radius: 4px;
}
#loginform h1 { margin: 0; color: var(--accent); font-size: 26px; letter-spacing: 1px; }
#loginform p { margin: 0; color: var(--muted); font-size: 12px; }
#loginonline { color: var(--accent); min-height: 1em; }
#loginform label { display: flex; flex-direction: column; gap: 3px; font-size: 12px; color: var(--muted); }
#loginform input {
  background: #16140f; border: 1px solid var(--panel-border); color: var(--text);
  padding: 6px 8px; font: inherit; font-size: 14px;
}
#loginform button {
  background: var(--accent); color: #221; border: 0; padding: 8px; font: inherit; font-weight: bold;
  cursor: pointer; margin-top: 4px;
}
#loginerr { color: #f66; min-height: 1.4em; font-size: 12px; }
/* The boards from the login screen: a link under the form rather than a
   second button competing with Enter Game, since it is something to read
   on the way in rather than a way in. */
#loginform #loginscoreline { margin: 2px 0 0; text-align: center; }
#loginform #loginscores {
  background: none; border: 0; border-radius: 0; padding: 0; width: auto; cursor: pointer;
  color: var(--accent); font: inherit; font-size: 12px; font-weight: 400; text-decoration: underline;
}
#loginform #loginscores:hover:not(:disabled) { color: var(--text); }
#loginform #loginscores:disabled { color: var(--muted); cursor: default; text-decoration: none; }


@media (max-width: 720px) {
  #app { grid-template-columns: 1fr; grid-template-rows: 1fr auto; }
  #side { flex-direction: row; flex-wrap: wrap; border-left: 0; border-top: 2px solid var(--panel-border); max-height: 40vh; }
  .panel { flex: 1 1 45%; }
}

/* A counter — the outfitter's stock or the smith's anvil: a row per line,
   each with what it is, what it does and what it costs. Anything out of
   reach of the purse is dimmed rather than hidden, since knowing what to
   save up for is half of what such a window is for. */
/* Over the view rather than over the page: the bag is what you are
   spending out of and the stats are what you are spending on, so both stay
   in sight. The wash is lighter than a full-page dialog's for the same
   reason — what is under it is still meant to be looked at. */
#counter {
  position: absolute; inset: 0; z-index: 5;
  display: flex; align-items: center; justify-content: center;
  background: rgba(0,0,0,.6);
}
#counterbox {
  background: var(--panel); border: 2px solid var(--panel-border); border-radius: 4px;
  padding: 18px 22px; max-width: 460px; max-height: calc(100% - 24px); overflow-y: auto;
}
#counterbox h2 { margin: 0 0 4px; color: var(--accent); font-size: 20px; letter-spacing: 1px; }
#counternote { margin: 0 0 10px; color: var(--muted); font-size: 12px; }
#counterbody { display: flex; flex-direction: column; gap: 6px; }
#counterbody button {
  display: flex; align-items: center; gap: 10px; width: 100%; text-align: left;
  background: #2a2621; border: 1px solid var(--panel-border); border-radius: 3px;
  color: var(--text); font: inherit; font-size: 12px; padding: 6px 8px; cursor: pointer;
}
#counterbody button:hover:not(:disabled) { border-color: var(--accent); }
#counterbody button:disabled { opacity: .45; cursor: default; }
#counterbody canvas { image-rendering: pixelated; width: 32px; height: 32px; flex: none; }
#counterbody .what { flex: 1; }
#counterbody .what b { color: var(--text); font-weight: 600; }
#counterbody .what span { display: block; color: var(--muted); font-size: 11px; }
#counterbody .cost { color: var(--accent); font-weight: 700; white-space: nowrap; }

/* Mending the lot: an action rather than a line of stock, so it wears the
   accent like the Close button under it rather than the row styling above. */
#counterall { margin-top: 10px; }
#counterall[hidden] { display: none; }

/* --- Programmable Play window ------------------------------------------------
   The second window on the device: a map to click and the route it makes.
   It shares the game's palette, but none of its layout: there is no viewport
   here, so the map takes the room the side panel would have had. */
.ppbody { overflow: auto; }
#pp { display: flex; flex-direction: column; height: 100vh; }
#pphead {
  padding: 10px 14px; border-bottom: 2px solid var(--panel-border); background: var(--panel);
  display: flex; align-items: baseline; gap: 14px; flex-wrap: wrap;
}
#pphead h1 { margin: 0; font-size: 16px; color: var(--accent); letter-spacing: 1px; }
#ppstatus { font-size: 12px; color: var(--muted); }
#ppstatus.ok { color: var(--text); }
#ppstatus.bad { color: #f66; }

#ppmain { flex: 1; display: grid; grid-template-columns: 1fr 260px; min-height: 0; }
#ppmapwrap {
  display: flex; align-items: center; justify-content: center;
  padding: 12px; min-width: 0; min-height: 0; background: #131210;
}
#ppmap { cursor: crosshair; image-rendering: pixelated; background: #0a0a0a; }

#ppside {
  border-left: 2px solid var(--panel-border); background: var(--panel);
  display: flex; flex-direction: column; min-height: 0; padding: 10px; gap: 8px;
}
.ppbar { display: flex; align-items: center; justify-content: space-between; font-size: 12px; color: var(--muted); }
#pplevelctl { display: flex; align-items: center; gap: 4px; }
#pplevelctl button {
  background: #16140f; color: var(--text); border: 1px solid var(--panel-border);
  font: inherit; line-height: 1; padding: 2px 5px; cursor: pointer;
}
#pplevel { color: var(--accent); min-width: 52px; }

#ppempty { margin: 0; font-size: 12px; color: var(--muted); }
#pplist { list-style: none; margin: 0; padding: 0; overflow-y: auto; flex: 1; min-height: 0; }
.pprow {
  display: flex; align-items: center; gap: 8px; padding: 4px 2px;
  border-bottom: 1px solid #3a332b;
}
/* A point planned on another level stays in the list — the route is one
   route — but reads as not being what the clicks are landing on. */
.pprow.otherlevel { opacity: 0.5; }
.ppnum {
  flex: 0 0 22px; height: 22px; border-radius: 50%; background: #ffd600; color: #241c00;
  display: flex; align-items: center; justify-content: center; font-size: 12px;
}
.ppat { flex: 1; font-size: 12px; }
.ppdel {
  background: none; border: 0; color: var(--muted); font-size: 16px; line-height: 1;
  cursor: pointer; padding: 0 4px;
}
.ppdel:hover { color: #f66; }

.ppactions { display: flex; gap: 6px; }
.ppactions button {
  flex: 1; background: #16140f; color: var(--text); border: 1px solid var(--panel-border);
  padding: 6px; font: inherit; font-size: 12px; cursor: pointer;
}
.ppactions button:hover { border-color: var(--accent); }
.ppnote { margin: 0; font-size: 11px; color: var(--muted); }

@media (max-width: 720px) {
  #ppmain { grid-template-columns: 1fr; grid-template-rows: 1fr auto; }
  #ppside { border-left: 0; border-top: 2px solid var(--panel-border); max-height: 45vh; }
}
