/* ---- The chat box as a cooldown bar --------------------------------------------------------------
   Global is on a sixty-second gap — long enough that a player who types into it and watches nothing
   happen concludes the game is broken. So the input says how long is left, in the place they are
   already looking, and FILLS back up as it goes (`--cool` runs 0 at the moment of sending to 1 when
   it is spent): a bar that fills reads as "coming back", where one that drains reads as "running
   out". The disabled state does the locking; this only paints it.

   A gradient with a hard stop rather than a child element, because the input has no inside to put
   one in — and a bar drawn over the top would have to be positioned against a box that moves with
   the panel. */
.rpg-chat-input.is-cooling {
  background-image: linear-gradient(
    to right,
    rgba(201, 164, 110, .26) 0%,
    rgba(201, 164, 110, .26) calc(var(--cool, 0) * 100%),
    transparent calc(var(--cool, 0) * 100%),
    transparent 100%);
  /* The placeholder is the countdown, so it must read as text rather than as a hint. */
  cursor: default; }
.rpg-chat-input.is-cooling::placeholder { color: var(--gold-hi); opacity: .95;
  font-variant-numeric: tabular-nums; }

/* WHICH BAR IS UP. A counter disc notched over the rail's top-right corner: one character of state
   ABOUT the rail, so it sits on it rather than beside it as a fourth keyed page. */
.hud-hotbar-barno { position: absolute; top: -9px; right: -9px; z-index: 2;
  width: 22px; height: 22px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 12px; font-weight: 700; color: var(--gold-hi);
  text-shadow: 0 1px 2px rgba(0,0,0,.7); pointer-events: none;
  border: 1px solid var(--gold-mid);
  background: radial-gradient(120% 120% at 35% 25%, rgba(58,50,96,.98), rgba(18,16,38,.98));
  box-shadow: 0 0 8px rgba(154,134,232,.45), inset 0 1px 0 rgba(255,236,198,.22); }

/* THE TWO STEPPERS, right of the nine. Tab still cycles; these give the gesture a direction and
   make it visible to a player nobody told about Tab.
   THE RAIL IS CLICK-THROUGH so a click near the bottom of the screen still reaches the world —
   which makes every control on it dead unless it says otherwise. Measured, not assumed: the
   button rendered at the right size and in the right place and simply never fired. */
/* ALIGNED TO THE RAIL, not to the bottom of the row (owner's call, 2026-09-02). The row is
   `align-items: flex-end`, which is right for the mount and ammo pages — they are rails and their
   bottoms should line up — but the stepper column is FURNITURE ON the nine-cell rail, and hanging
   it off the row's baseline with a hand-tuned `margin-bottom` left it sitting at whatever height
   that constant happened to produce. Adding the padlock made the column taller and moved it again,
   which is how a hand-tuned offset always fails. `align-self: center` measures against the rail
   beside it instead, so the cluster is centred on the bar whatever it contains. */
.hud-hotbar-steps { display: flex; flex-direction: column; gap: 3px; align-self: center;
  /* TEN PIXELS OFF THE RAIL (owner's measurement). The ROW's own `gap: 34px` applies between every
     pair of children, so the steppers were sitting 34px out from the nine — as far from it as the
     mount rail is, which reads as a fourth keyed page rather than as furniture belonging to the
     bar. Pulled back by the difference; the far side keeps the full row gap. */
  margin-left: -24px;
  pointer-events: auto; }
.hud-hotbar-step { display: grid; place-items: center; width: 22px; height: 20px; padding: 0;
  cursor: pointer; border-radius: 5px; border: 1px solid var(--glass-stroke);
  color: var(--gold-hi);
  background: linear-gradient(180deg, rgba(42,36,74,.9), rgba(16,14,34,.9)); }
.hud-hotbar-step:hover { border-color: var(--gold); color: #fff3d6;
  box-shadow: 0 0 8px rgba(201,164,110,.4); }
/* An item's own rendered icon, when a weapon is dropped on the rail. Same box the action artwork
   gets, so a bar of mixed kinds still reads as one row. */
.hud-slot img { width: 78%; height: 78%; object-fit: contain; display: block; margin: auto;
  /* ...and the artwork sits ON the socket floor, unshaded. See `.hud-slot::after`. */
  position: relative; z-index: 1; }
.hud-slot-glyph { font-size: 20px; line-height: 1; position: relative; z-index: 1; }

/* ── THE HOTBAR, WHILE SOMETHING IS BEING DRAGGED ONTO IT ─────────────────────────────────────
   THE RAIL IS NORMALLY `pointer-events: none`, and that is not incidental — it is what lets a
   click near the bottom of the screen reach the WORLD instead of the furniture. It also means the
   cells cannot receive a drop, so the rail becomes a drop target for exactly as long as something
   is being dropped on it and goes back to being scenery afterwards. The class is put on the body
   by `hotbarDrag.ts` on `dragstart` and taken off on `dragend` — which the browser fires for a
   cancelled drag too, so a player who thinks better of it does not leave the rail clickable. */
body.is-hotbar-drag .hud-hotbar { pointer-events: auto; }
body.is-hotbar-drag.is-hotbar-drag-cell .hud-hotbar-bin { display: flex; }

/* AND THE RAIL HAS TO BE ON TOP OF THE OPEN PANEL, which is not a detail — it is the whole
   feature. The skill window is inside `.rpg-ui` (z-index 40) with a backdrop that takes pointer
   events while a panel is open; the hotbar row is z-index 15 in the same stacking context. So a
   skill dragged out of the window travelled BEHIND the backdrop and could never reach a cell: the
   drop simply never fired, with nothing visibly wrong. Found by driving the real game — the DOM
   was correct and the pixels were correct and the gesture was impossible.
   Both halves are needed: the backdrop must stop intercepting, and the rail must come above it. */
body.is-hotbar-drag .rpg-backdrop { pointer-events: none; }
body.is-hotbar-drag .hud-hotbar-row { z-index: 60; }
/* THE LEDGER IS NOT MADE INERT DURING A DRAG, and the rule that used to do it was the bug.
   It read `body.is-hotbar-drag .rpg-ui, .rpg-ui * { pointer-events: none !important }`, on the
   theory that the open panel was swallowing drops aimed at the rail. Two things were wrong with
   that, and only measuring in the real browser showed either:
     - THE PANEL NEVER OVERLAPPED THE RAIL. `document.elementFromPoint` at a hotbar cell's centre
       returns the `.hud-slot` both at rest and mid-drag, with the skill window open. There was
       nothing to excuse.
     - AND THE RULE MATCHED THE DRAG SOURCE. The skill entry lives inside `.rpg-ui`, so the instant
       `dragstart` added the body class the element being dragged went to `pointer-events: none` —
       which in Chrome cancels the drag in flight. The gesture died a frame after it began, which
       is exactly "I am unable to drag skills into the hotbar".
   The backdrop keeps its exemption below: it genuinely does cover the screen when a panel is open,
   and it is not the source. */


/* The cell a drop would land in. A BORDER, not a fill: the cell already shows its contents and a
   wash over them hides the thing the player is deciding about. */
.hud-slot.is-drop {
  border-color: var(--gold-hi) !important;
  box-shadow: 0 0 14px rgba(255,214,110,.75), inset 0 0 10px rgba(255,214,110,.25) !important;
}

/* THE BIN. Centred above the rail — the one direction nothing is dragged FROM (the skill window
   and the bag are both further up the screen, a bin below would sit under the rail's own cells,
   and one to either side would be in the path of a reorder).
   Hidden until a drag starts: a permanent delete target beside a bar of skills is an invitation. */
.hud-hotbar-bin {
  position: absolute; left: 50%; bottom: 108px; transform: translateX(-50%);
  display: none; align-items: center; justify-content: center;
  width: 46px; height: 46px; pointer-events: auto; z-index: 61;
  border-radius: 10px; border: 1px solid #7d2b22;
  background: linear-gradient(180deg, rgba(74,22,18,.92), rgba(38,12,10,.92));
  box-shadow: 0 0 12px rgba(200,60,40,.35), inset 0 1px 0 rgba(255,160,140,.18);
}
.hud-hotbar-bin.is-over {
  border-color: #ff7a5e;
  background: linear-gradient(180deg, rgba(140,34,26,.96), rgba(70,18,14,.96));
  box-shadow: 0 0 20px rgba(255,90,60,.7), inset 0 1px 0 rgba(255,190,170,.3);
  transform: translateX(-50%) scale(1.08);
}

/* ── THE SKILL WINDOW'S ABILITY GRIDS ─────────────────────────────────────────────────────────
   Both tabs are grids of the SAME 64px disc the tree draws, under category headings. They used to
   be rows of prose beside a grid of discs, which made one window look like two: a thing you have
   and can drag onto the bar is one kind of object, and it should be drawn one way. The sentence
   moves into the tooltip, where the tree already keeps its own. */
/* THE WINDOW DOES NOT RESIZE WHEN YOU CHANGE TAB (owner's call). The two tabs hold different
   amounts — a six-row tree and a short list of abilities — so switching between them made the whole
   panel jump, and the tabs themselves moved under the pointer that had just clicked one. A minimum
   on the body means the taller tab sets the size and the shorter one sits inside it; the panel
   still grows for a tree that outgrows the floor. */
.rpg-panel--skill .rpg-skill-body { min-height: 52vh; }
.rpg-skill-list { margin: var(--sp-4) 0 0; }
.rpg-skill-head { margin: var(--sp-4) 0 var(--sp-2); font-family: var(--font-banner);
  font-size: 11px; letter-spacing: .14em; text-transform: uppercase;
  color: var(--gold-hi);
  border-bottom: 1px solid var(--glass-stroke); padding-bottom: 4px; }
.rpg-skill-head:first-child { margin-top: 0; }
.rpg-ability-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(76px, 1fr));
  gap: var(--sp-3, 10px) 6px; align-items: start; }
.rpg-ability { display: flex; flex-direction: column; align-items: center; gap: 5px;
  cursor: grab; user-select: none; }
.rpg-ability:active { cursor: grabbing; }
.rpg-node--ability { font-size: 26px; }
.rpg-ability:hover .rpg-node--ability { border-color: var(--gold-hi);
  box-shadow: 0 0 16px var(--gold-glow); }
.rpg-ability-name { font-family: var(--font-banner); font-size: 11px; line-height: 1.15;
  text-align: center; color: var(--ink-soft); max-width: 76px; }

/* The one line of instruction in the window. It earns its place because drag-and-drop is the only
   gesture in this game that is not discoverable by clicking things. */
.rpg-panel-note { margin: var(--sp-4) 0 0; font-family: var(--font-quill); font-style: italic;
  font-size: 12px; color: var(--ink-mute); }

/* RESET. Deliberately quiet — bordered, not filled: it is a rarely-wanted action sitting under a
   tree the player has just spent points in, and a bright button there is a button that gets
   pressed by accident. It turns warm only on hover, once the pointer has committed to it. */
.rpg-respec { margin: var(--sp-5) 0 0; padding: 6px 14px; cursor: pointer;
  border-radius: var(--r-1, 5px); border: 1px solid var(--glass-stroke);
  background: none; color: var(--ink-mute);
  font-family: var(--font-banner); font-size: 10px; font-weight: 600; letter-spacing: .12em;
  text-transform: uppercase; transition: color .15s, border-color .15s; }
.rpg-respec:hover { color: var(--gold-hi); border-color: var(--gold); }

/* ── THE DISCONNECT SCREEN ────────────────────────────────────────────────────────────────────
   Shown when the socket goes and never before. It TAKES THE SCREEN, unlike the warning that
   precedes it (a notice line), because at this point there is nothing left to play: every input
   from here is a lie, and a panel the player can click past would be inviting them to keep trying.
   Above everything, including the hotbar's 60 and the Ledger's 40 — it is the last thing on screen
   by definition. */
.rpg-disconnect {
  position: fixed; inset: 0; z-index: 200;
  display: grid; place-items: center;
  background: radial-gradient(120% 90% at 50% 20%, rgba(30,24,58,.82), rgba(6,6,16,.94));
  backdrop-filter: blur(3px);
  font-family: var(--font-body);
}
.rpg-disconnect-card {
  min-width: 320px; max-width: 460px; padding: 28px 32px; text-align: center;
  border-radius: var(--r-3, 11px); border: 1px solid var(--glass-stroke);
  background: linear-gradient(180deg, rgba(34,29,64,.98), rgba(16,14,34,.98));
  box-shadow: 0 0 40px rgba(0,0,0,.6), inset 0 1px 0 rgba(255,236,198,.14);
}
.rpg-disconnect-card h2 {
  margin: 0 0 10px; font-family: var(--font-banner); font-size: 20px;
  letter-spacing: .06em; color: var(--gold-hi);
}
.rpg-disconnect-why {
  margin: 0 0 20px; font-family: var(--font-quill); font-style: italic;
  font-size: 14px; line-height: 1.5; color: var(--ink-soft);
}
.rpg-disconnect-refresh { min-width: 140px; }

/* ── SEARCH BOXES on the bestiary and the world map ───────────────────────────────────────────
   Both panels grew past the size a grid is scannable at. Styled as one thing because they do one
   thing; a search that looked different in two places would read as two features. */
.rpg-bestiary-search, .rpg-map-search {
  display: block; width: 100%; margin: var(--sp-3, 10px) 0 0; padding: 7px 11px;
  border-radius: var(--r-2, 7px); border: 1px solid var(--glass-stroke);
  background: var(--glass-deep); color: var(--ink);
  font-family: var(--font-body); font-size: 13px;
}
.rpg-bestiary-search::placeholder, .rpg-map-search::placeholder {
  color: var(--ink-soft); opacity: .7;
}
.rpg-bestiary-search:focus, .rpg-map-search:focus {
  outline: none; border-color: var(--gold); box-shadow: 0 0 10px var(--gold-glow);
}
/* SEARCH AND SORT SHARE ONE ROW. Two full-width controls stacked would spend two rows of a panel
   whose whole job is showing tiles — and they are asked together ("show me the fire ones, hardest
   first"), so they belong side by side. The search takes the slack; the sort is its content width,
   because a select stretched across half a panel reads as a text field. */
/* ONE HEIGHT FOR THE WHOLE ROW, and everything centred on it (owner's call). The search box, the
   two selects, the arrow and Reset were each sized by their own padding and line-height, so they
   came out four different heights sitting on four different baselines — which reads as a row that
   was assembled rather than designed. `--bestiary-ctl` is that height, and every control on the row
   takes it; `align-items: center` then lines up the labels and the button with the boxes.
   `box-sizing: border-box` is load-bearing: without it the borders push each control a couple of
   pixels past the shared number and the alignment is off by exactly the border width. */
.rpg-bestiary-controls { --bestiary-ctl: 32px;
  display: flex; align-items: center; gap: var(--sp-3);
  margin: var(--sp-3) 0 var(--sp-2); }
.rpg-bestiary-controls > *,
.rpg-bestiary-controls .rpg-bestiary-search,
.rpg-bestiary-controls .rpg-bestiary-sort-sel,
.rpg-bestiary-controls .rpg-bestiary-elem-sel,
.rpg-bestiary-controls .rpg-bestiary-dir,
.rpg-bestiary-controls .rpg-bestiary-reset {
  box-sizing: border-box; height: var(--bestiary-ctl); }
/* A LABEL IS NOT A BOX. The `<label>` wrapping each select is full height so the row centres it,
   but its own text and its select have to centre INSIDE that. */
.rpg-bestiary-controls .rpg-bestiary-sort { display: flex; align-items: center; }
/* THE SEARCH AND THE SELECTS ARE THE SAME CONTROL, dimensionally: same height, same vertical
   padding (none — the height sets it), same border width and the same radius. They sat at
   different heights on different baselines because each was sized by its own padding, which is what
   made the row read as assembled rather than designed.
   `line-height` matters as much as the padding here: a select centres its own text by line box, and
   leaving it at the inherited value put the label a pixel or two above the search's. */
.rpg-bestiary-controls .rpg-bestiary-search,
.rpg-bestiary-controls .rpg-bestiary-sort-sel,
.rpg-bestiary-controls .rpg-bestiary-elem-sel {
  padding-top: 0; padding-bottom: 0; line-height: calc(var(--bestiary-ctl) - 2px);
  border-radius: var(--r-2);
  /* MARGIN ZEROED, and this is what was still tipping the row. `.rpg-bestiary-search` shares its
     base rule with the world map's, which carries `margin: var(--sp-3) 0 0` — a TOP margin, from
     when it was a block on a line of its own. In a centred flex row that margin pushes the search
     down while the filters stay put, so the row looked as though the filters were sitting high
     when it was the search that was low. */
  margin: 0;
  /* One border width for all three, or `box-sizing` distributes the difference unevenly and the
     text inside sits a pixel apart even at identical heights. */
  border-width: 1px; }
.rpg-bestiary-controls .rpg-bestiary-reset { padding-top: 0; padding-bottom: 0;
  display: inline-flex; align-items: center; }
/* THE TITLE AND THE TALLY share a line (owner's call): a count of what you have recorded belongs
   beside the name of the thing recording it, and it costs no row of its own there. */
.rpg-bestiary-titlerow { display: flex; align-items: baseline; gap: var(--sp-3); }
.rpg-bestiary-titlerow .rpg-panel-title { margin: 0; }

/* THE CONTROL ROW — search, the three lenses, and Reset.
   THE SELECTS ARE THE GAME'S, not the platform's. They wore one border colour from this file and
   everything else from the OS: the system type face, the system arrow, the system focus ring, and
   a grey plate that reads as a form control dropped onto parchment. `appearance: none` takes all of
   that off; what is rebuilt here is the same well the search field sits in, so the four controls on
   this row are one object rather than a set that happens to be adjacent. */
.rpg-bestiary-sort-sel, .rpg-bestiary-elem-sel {
  appearance: none; -webkit-appearance: none; color-scheme: dark;
  padding: 6px 26px 6px 10px; border-radius: var(--r-2);
  border: 1px solid var(--glass-stroke);
  /* The same inset well as the search box, plus the gilded hairline along the top that every
     recessed control in this interface carries. */
  background-color: rgba(10, 8, 26, .55);
  box-shadow: inset 0 1px 0 rgba(201,164,110,.16), inset 0 -1px 0 rgba(0,0,0,.35);
  color: var(--ink); font-family: var(--font-body); font-size: 12px; cursor: pointer;
  /* The chevron, DRAWN — inline so it needs no second element. Gold rather than the OS grey, which
     is the one detail that stops it reading as a form control. */
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8' fill='none' stroke='%23c9a46e' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'><path d='M1 1.5 6 6.5 11 1.5'/></svg>");
  background-repeat: no-repeat; background-position: right 8px center; background-size: 10px 7px;
  transition: border-color .12s ease, box-shadow .12s ease; }
.rpg-bestiary-sort-sel:hover, .rpg-bestiary-elem-sel:hover {
  border-color: var(--gold-deep); color: var(--gold-hi); }
.rpg-bestiary-sort-sel:focus, .rpg-bestiary-elem-sel:focus {
  border-color: var(--gold); box-shadow: 0 0 10px var(--gold-glow); }
/* THE OPTION LIST is the one part a page cannot style, so it is at least made to match the panel
   rather than the desktop — `color-scheme: dark` above is what stops a light-themed browser
   drawing white-on-white, and these give the popup the panel's own ground. */
.rpg-bestiary-sort-sel option, .rpg-bestiary-elem-sel option {
  background: #221a46; color: var(--ink); }
/* The label beside each select — small caps in the chrome voice, so a lens reads as one control
   rather than as a word and a box. */
.rpg-bestiary-sort { flex: none; display: flex; align-items: center; gap: 6px;
  font: 11px var(--font-mono); letter-spacing: .08em; text-transform: uppercase;
  color: var(--ink-soft); }

/* THE DIRECTION CONTROL — and it went MISSING, which is why it came back as a white browser button.
   Its whole rule block was removed by an edit aimed at the row's heights; nothing replaced it, so a
   `<button>` with no styling is exactly what the browser drew.
   Rebuilt here as one block, wearing the same well, border and focus ring as the two selects beside
   it — square, the row's shared height, so the three lenses read as one object. */
.rpg-bestiary-dir {
  flex: none; width: var(--bestiary-ctl, 32px); padding: 0;
  border-radius: var(--r-2); border: 1px solid var(--glass-stroke);
  background-color: rgba(10, 8, 26, .55);
  box-shadow: inset 0 1px 0 rgba(201,164,110,.16), inset 0 -1px 0 rgba(0,0,0,.35);
  cursor: pointer;
  /* THE ARROW IS DRAWN, not typed. A text glyph is the OS font's idea of an arrow at the OS font's
     weight, which is the seam the rest of this row already closed; this is the same chevron the
     selects carry. `font-size: 0` hides the button's own (now empty) text node in every engine. */
  font-size: 0;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8' fill='none' stroke='%23c9a46e' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'><path d='M1 1.5 6 6.5 11 1.5'/></svg>");
  background-repeat: no-repeat; background-position: center; background-size: 11px 8px;
  transition: border-color .12s ease, box-shadow .12s ease, transform .12s ease; }
.rpg-bestiary-dir:hover { border-color: var(--gold); }
.rpg-bestiary-dir:focus-visible { border-color: var(--gold);
  box-shadow: 0 0 10px var(--gold-glow); }
/* ASCENDING TURNS THE MARK OVER. One chevron, rotated — which is what an ascending/descending pair
   IS, and it cannot come out as two arrows drawn at slightly different weights. */
.rpg-bestiary-dir[data-dir="asc"] { transform: rotate(180deg); }

/* RESET. ALWAYS ON SCREEN, greyed when there is nothing to clear (owner's call, reversing the
   hide). A control that comes and goes reflows the row under the pointer, and a player cannot learn
   a button exists if it only appears once they have done the thing it undoes. */
.rpg-bestiary-reset { flex: none; margin-left: auto;
  padding: 5px 11px; border-radius: var(--r-2);
  border: 1px solid var(--glass-stroke); background: transparent;
  color: var(--ink-soft); font: 11px var(--font-mono); letter-spacing: .06em;
  text-transform: uppercase; cursor: pointer;
  transition: color .12s ease, border-color .12s ease, opacity .12s ease; }
.rpg-bestiary-reset:hover:not(:disabled) { color: var(--gold-hi); border-color: var(--gold); }
.rpg-bestiary-reset:disabled { opacity: .38; cursor: default; }

/* WHAT IT PAYS, beside what it is. Gold, because that is this interface's colour for a reward —
   and distinct from the element chips, which are about the fight rather than the prize. */
.rpg-bestiary-tag.is-xp { border-color: var(--gold-deep, var(--gold-mid)); color: var(--gold-hi);
  font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
/* A DROP ROW IS NOW HOVERABLE — it shows the item's catalogue leaf — so it has to look it. Only
   the unmasked rows: a masked row shows no card, and a pointer cursor on one would promise a
   reading that never arrives. */
.rpg-bestiary-drop:not(.is-masked) { cursor: help; border-radius: var(--r-1, 5px); }
.rpg-bestiary-drop:not(.is-masked):hover,
.rpg-bestiary-drop:not(.is-masked):focus-visible { background: rgba(201,164,110,.13); }

/* THE SELECTED CREATURE. The page is a decision now rather than a hover, so the grid has to say
   which decision is currently being displayed — without it, closing and reopening the page is the
   only way to find out what you are reading. */
.rpg-bestiary-tile { cursor: pointer; }
.rpg-bestiary-tile.is-selected {
  border-color: var(--gold);
  box-shadow: 0 0 14px var(--gold-glow), inset 0 0 0 1px rgba(201,164,110,.35);
}

/* A PLACE NAME THAT IS A LINK. Set as text, not as a button: it sits inside a sentence, and a
   sentence with a pill in the middle of it stops being a sentence. The underline is what says it
   can be pressed. */
.rpg-zone-link {
  padding: 0; border: 0; background: none; cursor: pointer;
  font: inherit; color: var(--gold-hi);
  text-decoration: underline; text-underline-offset: 2px;
  text-decoration-color: rgba(201,164,110,.5);
}
.rpg-zone-link:hover { color: #fff3d6; text-decoration-color: currentColor; }

/* A CREATURE CARD ON THE MAP is a button into the bestiary when the creature is known. Reset the
   element's own chrome — it has to keep looking exactly like the span it replaced. */
button.rpg-map-life {
  border: 0; background: none; font: inherit; color: inherit; text-align: inherit; cursor: pointer;
}
button.rpg-map-life:hover { filter: brightness(1.18); }

/* SEARCH DIMS, IT DOES NOT HIDE. A map with places removed from it is not a map — the value of the
   board is that everything sits in its place relative to everything else. */
.rpg-map-tile.is-dimmed { opacity: .28; filter: grayscale(.7); }

/* ── STAGED POINTS, AND THE BUTTON THAT SPENDS THEM ───────────────────────────────────────────
   Stats and skills both stage now: a press is a decision you can take back, and Save is where it
   stops being one. Shown only while something is staged, so the control never sits there meaning
   nothing. */
.rpg-stat-actions {
  display: flex; gap: 8px; justify-content: flex-end; align-items: center;
  margin-top: var(--sp-3, 10px);
}
.rpg-stat-reset {
  padding: 5px 12px; border-radius: var(--r-2, 7px);
  border: 1px solid var(--glass-stroke); background: var(--glass-deep);
  color: var(--ink-soft); font: inherit; font-size: 12px; cursor: pointer;
}
.rpg-stat-reset:hover { border-color: var(--gold); color: var(--gold-hi); }
.rpg-stat-save { padding: 5px 14px; font-size: 12px; }

/* WHAT A PRESS HAS ALREADY BOUGHT, before it is paid for. Without this the row and the tree node
   look exactly as they will after Save, and the player cannot see what they are about to spend. */
.rpg-stat-pending {
  margin-left: 5px; font-family: var(--font-mono); font-size: 11px; font-weight: 700;
  color: #8ef0a0;
}
.rpg-node.is-staged {
  border-color: #8ef0a0; box-shadow: 0 0 12px rgba(142,240,160,.5);
}

/* WHAT THE STAGED POINTS WOULD DO TO THE REST OF THE SHEET, drawn as "now -> then".
   The same green as `.rpg-stat-pending`, because it is the same claim — this has not been paid for
   yet — and the arrow is what stops the second figure being read as the value the character has.
   Deliberately lighter than the number it follows, so a glance down the column still reads the
   REAL stats and the preview sits beside them rather than replacing them. */
.rpg-stat-shift {
  margin-left: 6px; font-family: var(--font-mono); font-weight: 700;
  font-size: .88em; color: #8ef0a0; white-space: nowrap;
}
/* In the headline trio the number is set large, so the preview has to come down to a size that
   does not turn one figure into two headlines. */
.rpg-headline-fig .rpg-stat-shift { display: block; margin: 1px 0 0; font-size: 12px; }

/* ── CHARACTER SELECT: FIVE SLOTS, FILLED OR EMPTY ────────────────────────────────────────────
   The row used to be the server's result set in whatever order it arrived, which is unordered by
   definition — so characters swapped places between visits, and there was no way to see that the
   account had room for more. Five slots in creation order, and an empty one is the create button. */
.sel-slot { position: relative; display: inline-flex; }
.sel-card--empty {
  border-style: dashed; opacity: .72;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
}
.sel-card--empty:hover { opacity: 1; border-color: var(--gold); }
.sel-empty-plus {
  font-size: 34px; line-height: 1; color: var(--gold-hi); opacity: .8; margin-bottom: 6px;
}
.sel-hint {
  margin: 0; font-family: var(--font-quill); font-style: italic; font-size: 13px;
  color: var(--ink-soft);
}

/* THE DELETE HANDLE. Small, in the corner, and quiet — it is the one control on this screen that
   destroys something, so it must be reachable and must not compete with Join. */
.sel-del {
  position: absolute; top: 6px; right: 6px; z-index: 2;
  width: 20px; height: 20px; padding: 0; line-height: 1; font-size: 11px;
  display: grid; place-items: center; cursor: pointer;
  border-radius: 50%; border: 1px solid #7d2b22; color: #ffb4a4;
  background: rgba(38,12,10,.85); opacity: 0; transition: opacity .12s;
}
.sel-slot:hover .sel-del, .sel-del:focus-visible { opacity: 1; }
.sel-del:hover { background: #8c221a; color: #fff; }

/* ── THE TYPED CONFIRMATION ───────────────────────────────────────────────────────────────────
   A yes/no dialog on an irreversible action is a reflex the player has already clicked through a
   hundred times. Typing the word cannot be done by reflex. */
.sel-confirm {
  position: fixed; inset: 0; z-index: 300; display: grid; place-items: center;
  background: rgba(6,6,16,.82); backdrop-filter: blur(3px); font-family: var(--font-body);
}
.sel-confirm-card {
  width: min(440px, 92vw); padding: 26px 30px; text-align: left;
  border-radius: var(--r-3, 11px); border: 1px solid var(--glass-stroke);
  background: linear-gradient(180deg, rgba(34,29,64,.98), rgba(16,14,34,.98));
  box-shadow: 0 0 40px rgba(0,0,0,.6);
}
.sel-confirm-card h2 {
  margin: 0 0 10px; font-family: var(--font-banner); font-size: 19px;
  color: var(--gold-hi);
}
.sel-confirm-who { margin: 0 0 10px; font-size: 14px; color: var(--ink); }
.sel-confirm-warn {
  margin: 0 0 14px; font-family: var(--font-quill); font-style: italic; font-size: 13px;
  color: #ffb4a4;
}
.sel-confirm-ask { margin: 0 0 8px; font-size: 13px; color: var(--ink-soft); }
.sel-confirm-input {
  width: 100%; padding: 8px 11px; border-radius: var(--r-2, 7px);
  border: 1px solid var(--glass-stroke); background: var(--glass-deep);
  color: var(--ink); font-family: var(--font-mono); font-size: 14px;
  letter-spacing: .12em;
}
.sel-confirm-input:focus { outline: none; border-color: var(--gold); }
.sel-confirm-error { margin: 8px 0 0; min-height: 16px; font-size: 12px; color: #ff9c8c; }
.sel-confirm-actions {
  display: flex; gap: 10px; justify-content: flex-end; margin-top: 16px;
}

/* THE MOUNT CELL'S ICON. A rendered PNG now, not a 26px inline SVG, so it needs sizing the way the
   bag's icons do — `contain` because a saddle icon is wider than it is tall for a lizard and taller
   than it is wide for a dodo, and a cell that cropped either would be showing a different animal
   from the one it calls. */
.hud-mount-icon { width: 30px; height: 30px; object-fit: contain; display: block; }


/* "LIVES IN" / "FOUND IN" — ONE FORMAT (owner, 2026-09-24): creatures and resources identical, no
   background or border round the card or its picture, and one type size for both (14px since the one-per-row list, owner 2026-09-24). After
   `button.rpg-map-life` above, whose `font: inherit` had put the creatures at the panel's size. */
.rpg-map-life, button.rpg-map-life { border: 0; background: none; padding: 2px 0;
  font: 14px/1.2 var(--font-body); }
.rpg-map-life-art, .rpg-map-life.is-unknown .rpg-map-life-art { background: none; border: 0; }
