/* ---- THE GAME'S OWN TOOLTIP ---------------------------------------------------------------------
   Replaces the browser's `title` box — white ground, black system text, OS font, OS delay — which
   is the same seam `marks.ts` closes for icons. See `src/ui/tooltip.ts` for why the handler adopts
   `title` attributes instead of every call site being rewritten.

   `position: fixed` and a very high z-index: it is placed in VIEWPORT coordinates by the handler
   and has to clear every panel, the hotbar and the modal backdrop. `pointer-events: none` so the
   tip can never sit between the cursor and the thing it describes — which is how a tooltip starts
   eating the clicks that were meant for the control under it. */
.rpg-tip {
  position: fixed; z-index: 9000; pointer-events: none;
  /* A SHADE LARGER (owner's call). 12px was the size of the smallest label on the page, so the
     explanation read as more fine print rather than as the answer to it. */
  max-width: 300px; padding: 8px 11px;
  border: 1px solid var(--gold-deep, var(--gold-mid)); border-radius: var(--r-2, 7px);
  background: linear-gradient(180deg, #2a2150, #1a1338);
  color: var(--ink);
  font: 13px/1.5 var(--font-body); text-align: left;
  box-shadow: 0 0 0 1px rgba(13,10,32,.9), 0 10px 24px -8px rgba(0,0,0,.75);
  opacity: 0; transform: translateY(2px);
  transition: opacity .12s ease, transform .12s ease;
}
.rpg-tip.is-open { opacity: 1; transform: none; }

/* THE LITTLE "i". A circled letter beside a label, saying there is something to read — the hint
   used to hang off the whole row, so a player who did not know the explanations existed had no
   reason to hover anywhere. Sized in `em` so it tracks the text it sits beside rather than needing
   a size per panel. */
/* CENTRED ON THE LABEL'S OWN LINE. `vertical-align: text-top` hung the dot off the ascender, so it
   sat a pixel or two above the cap height of the word beside it and read as floating. `middle`
   against a `0.94em` box lands it on the text's optical centre. */
.rpg-info {
  display: inline-grid; place-items: center; vertical-align: middle; position: relative; top: -1px;
  width: 1.05em; height: 1.05em; margin-left: .4em; border-radius: 50%;
  border: 1px solid var(--gold-deep, var(--gold-mid)); color: var(--gold-hi);
  background: rgba(201,164,110,.10);
  font: 600 .74em/1 var(--font-mono); font-style: normal; cursor: help;
  user-select: none;
}
.rpg-info:hover, .rpg-info:focus-visible {
  border-color: var(--gold); color: var(--ink);
  background: rgba(201,164,110,.24);
}

/* A PARTY ROW AS A CAST TARGET, while a support spell is armed. Only then: a row that looks
   clickable at all times and does nothing most of the time is worse than one that never does. The
   accent is the heal green rather than the panel's gold, so it reads as "this spell" rather than as
   "this row is selected". */
.rpg-party-win-row.is-castable { cursor: crosshair; }
.rpg-party-win-row.is-castable:hover {
  border-color: #6fe39a; box-shadow: 0 0 10px -2px rgba(111,227,154,.7);
}

/* THE REGEN CONDITION, as a line rather than as a tooltip on each row (owner's call). The quill
   voice — this interface's face for an aside — so it reads as a note about the pair above it and
   not as a third row of data. */
.rpg-statnote { margin: 4px 0 0; font: italic 11px/1.4 var(--font-quill);
  color: var(--ink-quill, var(--ink-soft)); opacity: .9; }

/* ---- PARTY SETTINGS, INVITE, THEN PEOPLE ---------------------------------------------------- */
/* BOTH RULES ON ONE ROW (owner's call). They are the same kind of choice about the same party and
   stacked they spent two full rows saying so. Equal columns so neither reads as the primary one. */
.rpg-social-rules { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-3);
  margin: 0 0 var(--sp-3); }
.rpg-social-rules > * { min-width: 0; }
/* SMALLER TOGGLES to match. These were sized as primary controls, which is what made two of them
   fill a panel; they are a setting you change once a session. */
.rpg-social-rules .rpg-rule-opt,
.rpg-social-rules .rpg-social-act { padding: 4px 8px; font-size: 11px; }

/* THE ROSTER SCROLLS ON THE GILDED RAIL, like the craft book and the bestiary — a stock grey OS
   bar bolted to a gilded panel is the seam the rest of this file exists to hide. */
.rpg-social-list { max-height: 40vh; overflow-y: auto; overflow-x: hidden; padding-right: 6px; }
@supports not selector(::-webkit-scrollbar) {
  .rpg-social-list { scrollbar-width: thin;
    scrollbar-color: var(--gold-deep, var(--gold-mid)) rgba(10, 8, 26, .55); }
}
.rpg-social-list::-webkit-scrollbar { width: 10px; }
.rpg-social-list::-webkit-scrollbar-track { background: rgba(10, 8, 26, .55);
  border-radius: var(--r-pill); }
.rpg-social-list::-webkit-scrollbar-thumb {
  background: linear-gradient(180deg, var(--gold-base), var(--gold-mid)) content-box;
  border: 2px solid transparent; border-radius: var(--r-pill); }
.rpg-social-list::-webkit-scrollbar-thumb:hover {
  background: linear-gradient(180deg, var(--gold-hi-base), var(--gold-base)) content-box; }
.rpg-social-list::-webkit-scrollbar-button { display: none; width: 0; height: 0; }

/* THE LEAVE CONFIRMATION, in place of the button rather than floating over the panel: the question
   is about that control, and the answer replaces it so nothing else moves. */
.rpg-social-confirm { display: flex; align-items: center; gap: var(--sp-2);
  margin-top: var(--sp-4); padding: 7px 10px; border-radius: var(--r-2);
  border: 1px solid rgba(200,90,90,.5); background: rgba(60,18,24,.45);
  font: 12px var(--font-body); color: var(--ink); }
.rpg-social-confirm > span { flex: 1 1 auto; }
/* A LEADER WHO STILL HAS MEMBERS CANNOT LEAVE — the role is handed over, not dropped. Greyed with
   a reason on hover; the server refuses it too. */
.rpg-social-act[data-blocked="must-transfer"] { opacity: .45; cursor: not-allowed; }

/* ...AND THE BIN'S CONTENTS ARE NOT SEPARATE TARGETS, exactly as a hotbar cell's are not. The
   handler guards with `relatedTarget` as well; both, because the guard is what survives somebody
   adding a second child later and the rule is what stops the case arising at all. */
.hud-hotbar-bin > * { pointer-events: none; }

/* THE MAP'S SEARCH SITS ABOVE THE BOARD NOW (owner's call), so its margin belongs underneath it
   rather than above — it used to be the last thing on the panel and wanted separating from the
   board it followed. */
.rpg-map-search { margin: var(--sp-3) 0 var(--sp-3); }

/* THE STACK COUNT ON A HOTBAR CELL. Bottom-right, opposite the keybind at bottom-left, so the two
   numbers on a cell never collide and neither has to be read to find the other. Shown only above
   one: "x1" on every consumable in the game is noise added to remove the ambiguity of one case. */
.hud-slot .hud-slot-count {
  position: absolute; right: 3px; bottom: 2px; pointer-events: none;
  font: 600 10px var(--font-mono); font-variant-numeric: tabular-nums;
  color: var(--ink); text-shadow: 0 1px 2px #000, 0 0 3px #000; }
/* A GREYED CELL'S COUNT IS EMPTY ANYWAY (nothing left to count), but the filter that greys the cell
   would otherwise wash the badge out with it if one ever showed. */
.hud-slot .hud-slot-count { filter: none; }

/* ---- THE STRONGBOX --------------------------------------------------------------------------
   Your bag on the left, the account's 250 slots on the right, and an item crosses by drag or by
   right-click. Two grids of the SAME cell (`.rpg-cell`) at the SAME size as the inventory's, because
   an item must look the same wherever a player meets it — the rule the bag and the bestiary already
   follow, and the reason the first cut's fixed 44px tiles read as a different window. */
.rpg-panel--storage { width: min(980px, 96vw); overflow: hidden; }
.rpg-panel--storage.is-open { display: flex; flex-direction: column; }
.rpg-panel--storage > * { flex: none; }
.rpg-panel--storage > .rpg-storage-cols { flex: 1 1 auto; min-height: 0; }

/* IN THE CHEST'S COLUMN, AND STACKED. These describe the strongbox and nothing else, so they live
   inside its column rather than spanning the window — a full-width bar above both grids read as
   applying to the bag too. Stacked rather than side by side because this is now the narrow half:
   a search field sharing a row with the tab strip had almost no room to show what was typed. */
.rpg-storage-controls { display: flex; flex-direction: column; align-items: stretch;
  gap: var(--sp-2); margin: 0 0 var(--sp-2); }
/* The search reuses `.rpg-bag-search` wholesale — same well, same focus ring, same placeholder —
   so the two windows a player moves items between do not have two different search fields. */
.rpg-storage-search { width: 100%; min-width: 0; margin-bottom: 0; }
.rpg-storage-filters { display: flex; gap: 4px; flex-wrap: wrap; }

/* TWO COLUMNS SIZED BY THEIR CONTENT, not by a fraction each. The chest is FIVE fixed columns and
   the bag is five of the same, so both are stated in the same unit and the panel is as wide as the
   two grids plus the gap — which is what closes the dead space the first version had, where two
   `1fr` columns stretched to the panel and left the tiles marooned in it. */
/* The bag is eight columns and the chest five, so the split is 8:5 rather than even — an even split
   would squeeze the bag's tiles smaller than the chest's, and they are meant to be the same size. */
/* BOTH COLUMNS THE SAME HEIGHT. `align-items: start` sized each to its own content, so the two
   sides ended at different depths and the window had a ragged foot — most visible with the chest's
   controls and page rail making it the taller of the two. `stretch` makes both fill the row, and
   the grids below take the slack. */
.rpg-storage-cols { display: grid; grid-template-columns: 8fr 5fr;
  gap: var(--sp-4); align-items: stretch; }
.rpg-storage-side { display: flex; flex-direction: column; min-height: 0; min-width: 0; }
.rpg-storage-head { margin: 0 0 var(--sp-2); font-family: var(--font-banner); font-size: 12px;
  font-weight: 600; letter-spacing: .12em; text-transform: uppercase; color: var(--ink-mute); }
.rpg-storage-count { font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  letter-spacing: .02em; color: var(--ink-soft); text-transform: none; }

/* THE BAG SIDE IS THE INVENTORY'S OWN SHAPE — eight across (owner's call), so the bag a player
   already knows is laid out the way they know it rather than re-flowed into a narrow column. Forty
   slots over eight is five rows; the height below leaves room for six, so a bag grown past forty
   does not immediately start scrolling.
   THE CHEST IS FIVE BY FIVE, which is its page. Both are pinned rather than auto-fill:
   a grid that reflowed with the window would make "the third row" mean a different thing on every
   machine, which is why the bestiary pins its columns too. `1fr` columns against the cell's own
   `aspect-ratio: 1` is what makes the tiles the same size as the inventory's, rather than a fixed
   pixel guess — which is what the first cut got wrong. */
/* A WELL BEHIND THE TILES, in the search field's own colour (`--glass-deep`), so each grid reads as
   a container the items sit IN rather than as tiles floating on the page — and so the two grids and
   the search box above them are plainly the same surface. Padded, or the outer tiles would sit hard
   against the edge of the well. */
/* THE CHEST KEEPS ITS WELL; THE BAG DOES NOT (owner's call). The strongbox is the thing this window
   is about and the well marks it out; the bag is the player's own inventory, already familiar, and a
   second dark panel beside the first made the window read as two competing boxes rather than one
   with a destination in it. The bag keeps the padding so its outer tiles do not sit hard against
   the column edge, and keeps no border so nothing implies a container that is not there. */
.rpg-storage-chest { background: var(--glass-deep);
  border: 1px solid var(--glass-stroke); border-radius: var(--r-2); padding: var(--sp-2); }
.rpg-storage-bag { background: none; border: 1px solid transparent; padding: var(--sp-2); }
/* Grow into whatever height the equal-height row gives them, so a short bag and a full chest still
   finish level instead of one column trailing white space. */
.rpg-storage-bag, .rpg-storage-chest { flex: 1 1 auto; }
.rpg-storage-bag { display: grid; grid-template-columns: repeat(8, minmax(0, 1fr));
  gap: var(--sp-2); align-content: start; min-width: 0; }
.rpg-storage-chest { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: var(--sp-2); align-content: start; min-width: 0; }
/* The bag scrolls only if it outgrows the column. `max-height` was a fixed 52vh, which pinned it to
   the viewport rather than to the window it lives in and so fought the equal-height row above —
   `min-height: 0` is what lets a flex child actually shrink enough to scroll. */
.rpg-storage-bag { min-height: 0; overflow-y: auto; }
.rpg-storage-wait { grid-column: 1 / -1; margin: var(--sp-4) 0; text-align: center;
  font-family: var(--font-quill); color: var(--ink-mute); }

/* WHERE A DRAGGED STACK WILL LAND — only ever the grid it is NOT already on. */
.rpg-storage-bag.is-drop, .rpg-storage-chest.is-drop { border-radius: var(--r-2);
  outline: 2px dashed var(--gold); outline-offset: 3px;
  background: rgba(201,164,110,.07); }

/* THE PAGE RAIL. Ten identical numbers say nothing about where a player's things are, so a page
   holding anything carries a dot — computed over the whole chest, not the filtered view. */
.rpg-storage-pages { display: flex; gap: 4px; margin-top: var(--sp-3); flex-wrap: wrap; }
.rpg-storage-page { position: relative; width: 26px; height: 26px; border-radius: var(--r-1);
  font-family: var(--font-mono); font-size: 12px; font-variant-numeric: tabular-nums;
  color: var(--ink-soft); cursor: pointer;
  background: rgba(7,9,26,.5); border: 1px solid var(--glass-stroke); }
.rpg-storage-page:hover { border-color: var(--glass-stroke-hi); color: var(--ink); }
.rpg-storage-page.is-active { border-color: var(--gold); color: var(--gold-hi);
  background: linear-gradient(180deg, rgba(92,74,42,.85), rgba(52,40,22,.85)); }
.rpg-storage-page.has-items::after { content: ''; position: absolute; left: 50%; bottom: 3px;
  width: 3px; height: 3px; margin-left: -1.5px; border-radius: 50%;
  background: var(--gold); }

.rpg-storage-hint { margin: var(--sp-3) 0 0; font: italic 11px var(--font-quill);
  color: var(--ink-mute); text-align: center; }

/* ---- Number fields you TYPE INTO ---------------------------------------------------------------
   The coin field on the trade table and the batch field on the bench. Both were `type="number"`
   with the browser's own stepper, which is two 8-pixel arrows drawn in the OS's styling on a
   parchment panel — the same seam `tooltip.ts` and `marks.ts` exist to close, and it is at its most
   obvious on the one control a player is asked to commit real money through.

   The steppers are gone from the markup (both fields are `type="text"` with `inputmode="numeric"`),
   so this is the belt to that braces: a browser that still decides to draw a spinner gets nothing
   to draw it in. Firefox needs its own property; WebKit needs the pseudo-element. */
.rpg-trade-input, .rpg-craft-batch-n { -moz-appearance: textfield; appearance: textfield; }
.rpg-trade-input::-webkit-outer-spin-button,
.rpg-trade-input::-webkit-inner-spin-button,
.rpg-craft-batch-n::-webkit-outer-spin-button,
.rpg-craft-batch-n::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }

/* THE COIN FIELD, dressed as the purse it spends. Gold ink on a sunken well, so it reads as the
   one figure in the window that is money — the item lines beside it carry rarity colour, and a
   plain grey box among them looked like a form control that had wandered in. */
.rpg-trade-input { text-align: right; font-family: var(--font-mono);
  font-variant-numeric: tabular-nums; letter-spacing: .02em;
  color: var(--gold-hi);
  background: linear-gradient(180deg, rgba(7,9,26,.72), rgba(7,9,26,.5));
  border-color: var(--gold-deep);
  box-shadow: inset 0 1px 3px rgba(0,0,0,.55); }
.rpg-trade-input:focus { outline: none; border-color: var(--gold);
  box-shadow: inset 0 1px 3px rgba(0,0,0,.55), 0 0 0 2px var(--gold-glow, rgba(201,164,110,.28)); }

/* THE BATCH FIELD keeps the size and the centring it had as a read-only figure — it sits between
   two steppers and must not shove them apart as the number grows. */
.rpg-craft-batch-n { width: 3.6ch; padding: 2px 4px; border-radius: var(--r-1, 5px);
  border: 1px solid var(--glass-stroke, rgba(255,255,255,.10));
  background: rgba(7,9,26,.55); }
.rpg-craft-batch-n:focus { outline: none; border-color: var(--gold);
  box-shadow: 0 0 0 2px var(--gold-glow, rgba(201,164,110,.28)); }

/* WHERE A DRAGGED STACK WILL LAND. The offer grid only lights while something droppable is over
   it — `is-drop` is added on dragenter and removed on a leave that genuinely leaves (crossing onto
   a child is not leaving; see the handler). */
.rpg-trade-lines.is-drop { border-radius: var(--r-1, 5px);
  outline: 2px dashed var(--gold); outline-offset: 2px;
  background: rgba(201,164,110,.08); }

/* THE TILE BEING AIMED AT, not the grid it is in. Both are drop targets and `dragenter` bubbles, so
   `StoragePanel.lightDrop` keeps exactly one of them lit — see the note there. The tile's cue is a
   filled plate rather than the grid's dashed outline: an outline on a 44px square reads as a border
   change, which the rarity ring already owns. */
.rpg-cell.is-drop { border-color: var(--gold);
  box-shadow: 0 0 0 2px var(--gold-glow, rgba(201,164,110,.35)), inset 0 0 12px rgba(201,164,110,.22);
  transform: translateY(-1px); }

/* THE HOTBAR PADLOCK, between the two bar arrows. Same 26px footprint and same glass as the arrows
   so the three read as one cluster — the lock is a sibling control, not a decoration hung off the
   end of the rail. Gold when engaged, because gold is this interface's "this is on" and the shut
   shackle alone is too small a difference to catch at a glance mid-fight. */
/* THE PADLOCK IS ONE OF THE THREE, and is skinned by the `.hud-hotbar-step` rule above rather than
   by a second description of the same button — it carries both classes. It had its own box (26px
   against the arrows' 22x20) and its own translucent `--glass-hi` fill, so the cluster read as two
   arrows plus a different thing wedged between them.
   Only the LOCKED state is described here, and it is deliberately the SAME gold the rail itself
   takes (`.hud-hotbar.is-locked`): the button and the bar it controls say "locked" in one visual
   language, so the eye does not have to learn two. */
.hud-hotbar-lock.is-locked { color: var(--gold-hi); border-color: var(--gold);
  box-shadow: inset 0 0 0 1px rgba(201,164,110,.34), 0 0 8px rgba(201,164,110,.35); }
/* The RAIL itself says so too. The padlock answers "is it locked" only if you look at the padlock,
   and the moment that matters is the one where the player is dragging something at the cells. A
   quiet gold rim on the bar is visible from wherever the cursor happens to be. */
.hud-hotbar.is-locked { box-shadow: inset 0 0 0 1px rgba(201,164,110,.34); }
/* NOT `cursor: not-allowed` on the cells: a locked bar is still fully usable by click and by key,
   and a refusal cursor over a control that works would be a lie. Only the DRAG is gone, which the
   `draggable` flag already communicates by simply not lifting. */

