.modal-wrapper {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  width: 100%;
  position: absolute;
  /* Without these, an absolutely positioned box with no offset keeps its normal-flow
     position instead of resetting to the corner -- harmless for the two that already sat
     first inside their own wrapper, but wrong for one sitting later in the document, like
     select-character's own wrapper (outside both login/game wrappers, so a character
     switch can show it over the still-visible game world). */
  top: 0;
  left: 0;
  /* This now genuinely covers the full screen (the fix above), which means it would swallow
     every click behind it -- the login/game buttons included -- for as long as no modal
     inside it is even open. pointer-events is inherited, so .modal below opts back in. */
  pointer-events: none;
}

.modal {
  display: none;
  position: absolute;
  pointer-events: auto;
  /* Above market-window/stash-window (40000): a modal opened from one of them, like the
     stack-split prompt when withdrawing from the stash, must render on top of it */
  z-index: 50000;
  border: 1px solid black;
  box-shadow: 0px 0px 10px 0px black;
  background-image: url("../png/bg.png");
}

.modal-header {
  background-image: url("../png/bg2.png");
  cursor: grab;
  text-align: center;
  padding: 4px;
}

.modal .modal-footer {
  text-align: right;
}

/* Every modal's Cancel/Confirm/OK footer button uses the same two-state gray graphic as the
   NPC Trade window's Buy/Sell buttons (see the #offer-modal rules below, which this mirrors):
   left half of the image is idle/up, right half is pressed/down. This is deliberately a plain
   ".modal .modal-footer button" rule rather than "!important" -- it only needs to beat the
   generic "button" rule in new.css (lower specificity), and a modal that genuinely wants its
   own look (like #offer-modal's taller buttons, or #spellbook-modal's tabs) can still win by
   being more specific, exactly like it already does today. */
.modal .modal-footer button {
  background: url("../png/button_gray.png") no-repeat left center / 200% 100%;
  border: 0;
  box-shadow: none;
  outline: none;
  filter: none;
  height: 26px;
  font-size: 11px;
  color: #ddd;
}

.modal .modal-footer button:hover {
  background: url("../png/button_gray.png") no-repeat left center / 200% 100%;
}

.modal .modal-footer button:active {
  background: url("../png/button_gray.png") no-repeat right center / 200% 100%;
}

.modal-body {
  box-shadow: inset 0 0 6px black;
  padding: 12px;
}

/* The window that says a character died floats over whatever is on the screen, which after
   dying is the last picture of the world. It is dragged by its header like the others, so
   it can be pushed aside to look at what happened. */
#death-modal {
  position: fixed;
  left: 50%;
  top: 28%;
  width: 340px;
  margin-left: -170px;
  font-size: 11px;
}

#death-modal .modal-body {
  padding: 8px;
}

.tab-flex {
  display: flex;
}

.offer-tab {
  flex: 1 1 auto;
  padding: 4px;
}

.modal input {
  color: white;
  border: 1px solid black;
}

/* NPC Trade window: a tall vertical rectangle, matching real Tibia's own layout */

#offer-modal {
  width: 260px;
}

/* Same 340px "small utility modal" width as #death-modal above, #house-info-modal and
   #hub-modal (hub.css) -- otherwise this one has no width of its own and sizes itself to
   whatever the /bed status text happens to be, which looked randomly sized next to those
   (Douglas 2026-09-18). */
#bed-sleep-modal {
  width: 340px;
}

/* Buy/Sell and Ok/Cancel all use the same two-state gray button graphic: the left half of the
   image is the idle/up look, the right half is the pressed/down look. A held-down mouse button
   shows the pressed half; the Buy/Sell tabs also show it permanently for whichever is selected,
   the same way a pressed button looks "pushed in". */
#offer-modal .offer-tab,
#offer-modal .modal-footer button {
  background: url("../png/button_gray.png") no-repeat left center / 200% 100% !important;
  border: 0 !important;
  box-shadow: none !important;
  outline: none !important;
  filter: none !important;
  height: 26px;
  font-size: 11px;
  color: #ddd !important;
}

#offer-modal .offer-tab:hover,
#offer-modal .modal-footer button:hover {
  background: url("../png/button_gray.png") no-repeat left center / 200% 100% !important;
}

#offer-modal .offer-tab.selected,
#offer-modal .offer-tab:active,
#offer-modal .modal-footer button:active {
  background: url("../png/button_gray.png") no-repeat right center / 200% 100% !important;
}

/* Spellbook modal: same tabbed idea as the NPC Trade window's Buy/Sell buttons above, just
   with three tabs (Basic/Vocation/Runes) instead of two -- one flat button image, right half
   shown for whichever tab is currently selected */
#spellbook-modal .spellbook-tab {
  background: url("../png/button_gray.png") no-repeat left center / 200% 100% !important;
  border: 0 !important;
  box-shadow: none !important;
  outline: none !important;
  filter: none !important;
  height: 26px;
  font-size: 11px;
  color: #ddd !important;
  flex: 1 1 auto;
  padding: 4px;
}

#spellbook-modal .spellbook-tab:hover {
  background: url("../png/button_gray.png") no-repeat left center / 200% 100% !important;
}

#spellbook-modal .spellbook-tab.selected,
#spellbook-modal .spellbook-tab:active {
  background: url("../png/button_gray.png") no-repeat right center / 200% 100% !important;
}

/* Hotkeying a real item instead of a spell: see Mouse.armHotkeyAssignment */
.spellbook-target-buttons {
  display: flex;
  gap: 4px;
  margin-top: 4px;
}

.spellbook-target-button {
  flex: 1 1 auto;
  font-size: 10px;
  padding: 4px 2px;
}

/* Hotkeying plain text: see HotbarManager.assignText */
.spellbook-text-row {
  display: flex;
  gap: 4px;
  margin-top: 4px;
}

.spellbook-text-row input {
  flex: 1 1 auto;
  min-width: 0;
}

.spellbook-text-row button {
  flex: 0 0 auto;
  font-size: 10px;
  padding: 4px 6px;
}

/* Same flat button_gray.png look as the Basic/Vocation/Runes tabs above, instead of the
   generic rounded bg3.png button every other plain <button> falls back to -- these are
   momentary actions rather than persistent tabs, so unlike .spellbook-tab there is no
   ".selected" case, just idle (left) and pressed (right) */
#spellbook-modal .spellbook-target-button,
#spellbook-modal #spellbook-text-add {
  background: url("../png/button_gray.png") no-repeat left center / 200% 100% !important;
  border: 0 !important;
  box-shadow: none !important;
  outline: none !important;
  filter: none !important;
  color: #ddd !important;
}

#spellbook-modal .spellbook-target-button:hover,
#spellbook-modal #spellbook-text-add:hover {
  background: url("../png/button_gray.png") no-repeat left center / 200% 100% !important;
}

#spellbook-modal .spellbook-target-button:active,
#spellbook-modal #spellbook-text-add:active {
  background: url("../png/button_gray.png") no-repeat right center / 200% 100% !important;
}

.offer-currency-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 6px;
  font-size: 11px;
  color: #cfcfcf;
}

#offer-currency-slot {
  margin: 0;
}

#offer-search {
  width: 100%;
  box-sizing: border-box;
  margin-top: 6px;
  color: white;
  background-image: url("../png/bg2.png");
  border: 1px solid black;
  padding: 3px 4px;
}

/* .offers is wrapped in place by TibiaScrollbar (see tibia-scrollbar.js): the wrapper keeps
   this class for its own box (sizing/background/border), the content pane inside it keeps the
   class too so its row layout still applies -- split into the two halves below rather than
   one rule, since the wrapper is now a flex ROW (content next to the scrollbar) while the
   content itself still needs to stack its rows in a COLUMN. */
.offers.tibia-scroll-wrapper {
  flex: 1 1 auto;
  height: 220px;
  margin-top: 4px;
  background-image: url("../png/bg2.png");
  box-shadow: inset 0 0 6px black;
}

.offers.tibia-scroll-content {
  display: flex;
  flex-direction: column;
  padding: 2px;
  gap: 2px;
}

/* Generic: hides the native scrollbar on any element TibiaScrollbar has wrapped (Firefox's
   scrollbar-width is set inline by the widget itself; only the Webkit pseudo-element needs a
   real stylesheet rule) -- the widget's own real buttons+track+thumb are the visible one. */
.tibia-scroll-content::-webkit-scrollbar {
  display: none;
}

/* Custom scrollbar widget: an up-arrow button glued to the top of the track, a down-arrow
   button glued to the bottom, and a draggable thumb in between -- built from real DOM elements
   by TibiaScrollbar, not scrollbar pseudo-elements. Stretches to whatever height its wrapper
   ends up with, so the same widget fits any list it is attached to. */
.tibia-scrollbar-v {
  flex: 0 0 auto;
  width: 12px;
  display: flex;
  flex-direction: column;
}

.tibia-arrow-button-v {
  flex: 0 0 auto;
  width: 12px;
  height: 12px;
  padding: 0;
  margin: 0;
  border: 0 !important;
  box-shadow: none !important;
  background: url("../png/window/scrollbar_arrow_up.png") no-repeat center / contain !important;
}

.tibia-arrow-button-v.down {
  background-image: url("../png/window/scrollbar_arrow_down.png") !important;
}

.tibia-arrow-button-v.up:active {
  background-image: url("../png/window/scrollbar_arrow_up_pressed.png") !important;
}

.tibia-arrow-button-v.down:active {
  background-image: url("../png/window/scrollbar_arrow_down_pressed.png") !important;
}

.tibia-scrollbar-v-track {
  flex: 1 1 auto;
  position: relative;
  background-image: url("../png/window/scrollbar_track_vertical.png");
  background-repeat: repeat-y;
}

.tibia-scrollbar-v-thumb {
  position: absolute;
  left: 0;
  width: 12px;
  /* Fixed at the art's own native size -- stretching it to represent how much of the list is
     visible is what disfigured the pill shape. It just slides up and down the track instead. */
  height: 44px;
  background-image: url("../png/window/scrollbar_thumb_vertical.png");
  background-size: 100% 100%;
  cursor: pointer;
}

.offer-row {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 3px 4px;
  cursor: pointer;
  border-radius: 2px;
}

.offer-row:hover {
  background-color: rgba(255, 255, 255, 0.08);
}

.offer-row.selected {
  background-color: rgba(255, 255, 255, 0.22);
}

/* A sell offer for something the player is not actually carrying: half-opaque, the same
   "you can't do this right now" look used for empty/greyed elsewhere in the interface. Still
   selectable (so it can be inspected and the reason becomes obvious), just visually muted. */
.offer-row-unowned {
  opacity: 0.45;
}

.offer-row-unowned.selected {
  opacity: 0.7;
}

.offer-row .slot {
  flex: 0 0 auto;
}

.offer-row-text {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
}

.offer-row-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 12px;
}

.offer-row-meta {
  display: flex;
  gap: 10px;
  font-size: 10px;
  color: #a8a8a8;
}

.offer-row-price::before {
  content: "";
  display: inline-block;
  width: 10px;
  height: 10px;
  margin-right: 3px;
  vertical-align: middle;
  background-image: url("../png/gc.png");
  background-size: contain;
}

#offer-price {
  min-width: 40px;
  display: inline-block;
  text-align: right;
}

#offer-total-money {
  min-width: 40px;
  display: inline-block;
  text-align: right;
  font-weight: bold;
}

#offer-info {
  position: relative;
  border: 1px solid black;
  padding: 6px;
  /* Reserve a gutter on the right so the preview slot pinned to the bottom-right corner never
     overlaps the amount slider or any of the text rows above it */
  padding-right: 44px;
  margin-top: 6px;
  background-image: url("../png/bg2.png");
  font-size: 11px;
}

#offer-info-main {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

#offer-preview-slot {
  position: absolute;
  right: 6px;
  bottom: 6px;
}

#buy-count-wrapper .offer-info-row {
  /* The amount row sits well above the preview slot pinned to the bottom-right corner of
     #offer-info, so it can safely borrow back the gutter reserved for it (see #offer-info's
     padding-right) and give the amount bar a longer, more visibly responsive track */
  width: calc(100% + 44px);
}

/* The amount control: the exact same widget as the list's own scrollbar (real buttons glued
   to a track, a thumb at its native size sliding along it), just laid out sideways. Built and
   driven the same way in modal-offer.js, not a native range input. */
.tibia-scrollbar-h {
  flex: 1 1 auto;
  min-width: 0;
  height: 12px;
  display: flex;
  align-items: center;
}

.tibia-arrow-button-h {
  flex: 0 0 auto;
  width: 12px;
  height: 12px;
  padding: 0;
  margin: 0;
  border: 0 !important;
  box-shadow: none !important;
  background: url("../png/window/scrollbar_arrow_left.png") no-repeat center / contain !important;
}

.tibia-arrow-button-h.right {
  background-image: url("../png/window/scrollbar_arrow_right.png") !important;
}

.tibia-arrow-button-h.left:active {
  background-image: url("../png/window/scrollbar_arrow_left_pressed.png") !important;
}

.tibia-arrow-button-h.right:active {
  background-image: url("../png/window/scrollbar_arrow_right_pressed.png") !important;
}

.tibia-scrollbar-h-track {
  flex: 1 1 auto;
  min-width: 0;
  height: 10px;
  position: relative;
  background-image: url("../png/window/scrollbar_track.png");
  background-repeat: repeat-x;
}

.tibia-scrollbar-h-thumb {
  position: absolute;
  top: 0;
  /* Fixed at the art's own native size, same fix as the vertical thumb: stretching it to
     represent anything is what made it look small/squashed */
  width: 44px;
  height: 12px;
  background-image: url("../png/window/scrollbar_thumb.png");
  background-size: 100% 100%;
  cursor: pointer;
}

.tibia-amount-value {
  flex: 0 0 auto;
  width: 30px;
  text-align: right;
  font-weight: bold;
  color: white;
  background-image: url("../png/bg2.png");
  border: 1px solid black;
  -moz-appearance: textfield;
}

/* Hide the native up/down spinner: it was quietly widening the box past its set width and
   eating into the amount bar's own track space */
.tibia-amount-value::-webkit-inner-spin-button,
.tibia-amount-value::-webkit-outer-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

.offer-info-row {
  display: flex;
  align-items: center;
  gap: 4px;
}

.offer-total-row {
  border-top: 1px solid rgba(255, 255, 255, 0.2);
  padding-top: 4px;
}

.offer-capacity-row {
  display: flex;
  align-items: center;
  gap: 6px;
  cursor: pointer;
}

/* Applied to #offer-total-capacity's own span when the current amount would exceed the free
   capacity being carried -- the same red the rest of the interface already uses for "this is
   over the line" (low health, cannot-afford states), so the warning reads at a glance. */
.offer-capacity-overload {
  color: #ff4444;
  font-weight: bold;
}

.tibia-checkbox {
  -webkit-appearance: none;
  appearance: none;
  width: 12px;
  height: 12px;
  margin: 0;
  border: 0 !important;
  background: url("../png/window/checkbox-unchecked.png") no-repeat center / contain;
  cursor: pointer;
}

.tibia-checkbox:checked {
  background-image: url("../png/window/checkbox-checked.png");
}

#offer-info img {
  width: 12px;
  height: 12px;
}

#book-text-area {
  height: 220px;
  resize: none;
  scrollbar-width: thin;
  background-image: url("../png/bg2.png");
  color: white;
  font-weight: bold;
  padding: 16px;
  padding-right: 8px;
  font-size: 12px;
  font-family: Verdana;
  box-shadow: inset 0 0 8px black;
  border: 1px solid black;
  border-radius: 16px 0px 0px 16px;
}

#book-text-area:disabled {
  color: grey;
}

#book-text-area:focus {
  outline: none;
}

.map-modal-wrapper {
  position: relative;
  overflow: hidden;
}

#map-modal-canvas {
  display: block;
}

.map-touch-zoom {
  display: none;
}

#map-player-cross {
  position: absolute;
  width: 16px;
  height: 16px;
  transform: translate(-50%, -50%);
  pointer-events: none;
  image-rendering: pixelated;
}

/* Same floor gauge as the minimap's own (Minimap.__handleFloorGaugeClick), but this map keeps
   its own floor independently -- see MapModal.__changeFloor */
.map-modal-wrapper .map-floor-gauge {
  position: absolute;
  left: 4px;
  top: 30px;
  width: 14px;
  height: 67px;
  background-image: url("../png/minimap/automap-indicator-maplayers.png");
  background-repeat: no-repeat;
  cursor: pointer;
  image-rendering: pixelated;
}

#map-current-layer {
  position: absolute;
  left: 4px;
  bottom: 4px;
  color: white;
  font-size: 10px;
  font-weight: bold;
  pointer-events: none;
}

/* The inline "create mark" panel (see MapModal.__openMarkerPanel): hidden by default so
   creating a mark never has to leave the map view for a separate modal */
.map-marker-panel {
  display: none;
  margin-top: 8px;
}

.map-marker-panel.open {
  display: block;
}

.map-marker-icons {
  display: grid;
  grid-template-columns: repeat(10, 26px);
  gap: 2px;
  justify-content: center;
  margin-bottom: 8px;
}

/* Same checkbox strip real Tibia uses for its own flag picker: cell 0 is the checked (green)
   look, cell 1 the idle (grey) look, cells 2 and 3 their hover equivalents */
.map-marker-icon {
  width: 26px;
  height: 26px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  background-image: url("../png/minimap/flagcheckbox.png");
  background-repeat: no-repeat;
  background-size: 400% 100%;
  background-position: 33.333% 0;
}

.map-marker-icon:hover {
  background-position: 100% 0;
}

.map-marker-icon.selected {
  background-position: 0 0;
}

.map-marker-icon.selected:hover {
  background-position: 66.667% 0;
}

.map-marker-icon img {
  width: 11px;
  height: 11px;
  image-rendering: pixelated;
}

#map-marker-description {
  width: 100%;
  box-sizing: border-box;
  margin-bottom: 6px;
}

.map-marker-panel-buttons {
  text-align: right;
}

.map-marker-overlay {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.35);
}

.map-marker-overlay[hidden] {
  display: none;
}

.map-marker-overlay .map-marker-panel {
  width: 302px;
  max-width: calc(100% - 24px);
  box-sizing: border-box;
  margin: 0;
  padding: 12px;
  border: 1px solid black;
  box-shadow: 0 0 10px black;
  background-image: url("../png/bg.png");
}

.map-marker-title {
  margin: -12px -12px 12px;
  padding: 5px;
  text-align: center;
  background-image: url("../png/bg2.png");
}

.map-marker-overlay .map-marker-icons {
  grid-template-columns: repeat(10, 24px);
  gap: 3px;
}

.map-marker-overlay .map-marker-icon {
  width: 24px;
  height: 24px;
}

.map-marker-overlay label {
  display: block;
  margin-bottom: 4px;
}

.map-marker-overlay #map-marker-description {
  height: 26px;
  margin-bottom: 10px;
}

.map-marker-overlay button {
  min-width: 60px;
}

.map-marker-overlay :focus-visible {
  outline: 1px solid #b4cbe0;
  outline-offset: 1px;
}

/* Wrapped by TibiaScrollbar (see tibia-scrollbar.js). #spellbook-list has no class of its own
   -- its id stays on the content pane, so the wrapper (which needs the box: size/background)
   is addressed through the derived id TibiaScrollbar gives it instead. A fixed height (not
   max-height) keeps every tab -- Basic, Vocation, Runes, even one with few or no spells --
   exactly the same size as Vocation (the fullest one), instead of shrinking to fit whatever
   is actually in it. */
#spellbook-list-scroll-wrapper {
  height: 250px;
  width: 400px;
  background-image: url("../png/bg.png");
}

#spellbook-list {
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
  /* Without this, a tab with fewer rows (e.g. Basic) has more leftover vertical space in the
     fixed 250px wrapper than a full one (Vocation) -- by default a wrapped flex container
     stretches its rows to fill that leftover space, so those tabs' boxes end up visibly taller
     than they should be. Packing rows at their natural height instead means every tab's boxes
     stay the same compact size, and any leftover space at the bottom just shows the wrapper's
     own background (see #spellbook-list-scroll-wrapper) instead of being eaten by taller rows. */
  align-content: flex-start;
}
.spellbook-wrapper {
  width: 45%;
  border: 1px solid black;
  flex: 1 1 auto;
  display: flex;
  margin: 4px;
  align-items: center;
  background-image: url("../png/bg2.png");
}

.spellbook-wrapper canvas {
  flex: 0 1 auto;
  width: 32px;
  height: 32px;
  box-shadow: 0px 0px 4px 0px black;
  cursor: pointer;
}

.spellbook-wrapper span {
  flex: 0 1 auto;
  text-align: center;
  width: 100%;
}

#spellbook-wrapper-prototype {
  display: none;
}
/* Character selection window */

#select-character {
  width: 790px;
  max-width: calc(100vw - 32px);
}

#character-list {
  border: 1px solid black;
  background-image: url("../png/bg2.png");
  margin-bottom: 8px;
}

/* Wrapped by TibiaScrollbar (see tibia-scrollbar.js): #character-rows has no class of its own,
   so the wrapper (which needs the box: capped height) is addressed through the derived id.
   Each row is 68px tall (the 64px outfit canvas plus 2px of vertical padding on each side), so
   five rows show before the scrollbar kicks in. */
#character-rows-scroll-wrapper {
  max-height: 340px;
}

.character-head, .character-row {
  display: grid;
  grid-template-columns: 64px minmax(0, 1fr) 112px 116px 118px;
  align-items: center;
  grid-gap: 12px;
}

.character-head {
  border-bottom: 1px solid black;
  padding: 8px 16px 8px 4px;
  color: #ddd;
  font-weight: bold;
}

/* The header has no outfit column of its own: push it past the sprite */
.character-head > span:first-child {
  grid-column: 1 / span 2;
  padding-left: 4px;
}

.character-head > span:nth-child(2), .character-row > span:nth-child(3) {
  text-align: center;
  font-variant-numeric: tabular-nums;
}

.character-head > span:last-child, .character-row > span:last-child { text-align: center; }
.character-row > span { min-width: 0; overflow-wrap: anywhere; }
.character-row:nth-child(even) { background-color: rgba(255, 255, 255, 0.07); }
.character-row:nth-child(odd) { background-color: rgba(0, 0, 0, 0.08); }

.character-row {
  padding: 2px 4px;
  cursor: pointer;
}

.character-row:hover {
  background-color: rgba(255, 255, 255, 0.14);
}

.character-row.selected {
  background-color: rgba(194, 174, 104, 0.20);
  box-shadow: inset 2px 0 #b5a165;
}

@media (max-width: 650px) {
  .character-head, .character-row {
    grid-template-columns: 40px minmax(0, 1fr) 64px 78px 76px;
    gap: 6px;
    font-size: 10px;
  }
  #select-character .character-outfit { width: 40px; height: 40px; }
}

.character-name {
  font-weight: bold;
}

.character-outfit {
  width: 64px;
  height: 64px;
  image-rendering: pixelated;
}

#account-status {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 4px 0;
}

#account-status-icon {
  display: inline-block;
  width: 20px;
  height: 19px;
  background-repeat: no-repeat;
  background-position: center;
  background-size: contain;
  image-rendering: pixelated;
}

#account-status-icon.premium {
  background-image: url("../png/premium/icon-premium.png");
}

#account-status-icon.free {
  background-image: url("../png/premium/icon-nopremium.png");
}

/* NPC Chat Modal (see modal-npc-chat.js): a private conversation window with a single NPC --
   header with the NPC's own sprite and name, a scrollable log, and a footer with three quick-
   reply icons, a text box and a Chat Off toggle. */
.npc-chat-modal {
  width: 320px;
}

.npc-chat-header {
  display: flex;
  align-items: center;
  gap: 8px;
  padding-right: 8px;
}

.npc-chat-header .modal-header {
  flex: 1;
  text-align: left;
  padding-left: 0;
}

.npc-chat-portrait {
  width: 64px;
  height: 64px;
  flex-shrink: 0;
  background-image: url("../png/bg2.png");
  border-right: 1px solid black;
}

.npc-chat-body {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.npc-chat-log {
  height: 180px;
  overflow-y: auto;
  background-color: #000;
  border: 1px solid black;
  box-shadow: inset 0 0 6px black;
  padding: 4px 6px;
  font-size: 11px;
  line-height: 14px;
  color: #ccc;
}

.npc-chat-line {
  margin-bottom: 2px;
  word-wrap: break-word;
}

.npc-chat-line.npc-chat-system {
  color: #888;
}

/* Project-wide NPC conversation palette (see engine/data/1098/npcs/README.md), sampled straight
   off real Tibia's own NPC channel: what the NPC says is light blue, the player's own answers
   are periwinkle, and whichever words can be clicked to answer with are a deeper blue. The same
   three apply to the NPC channel (see css/chatbox.css) so a line reads identically whether it
   is in this window or the tab, and the first of them is what CONST.COLOR.NPC paints the
   in-world speech bubble with, engine side. The name carries its speaker's own color too. */
.npc-chat-line.npc-chat-line-npc {
  color: #66ffff;
}

.npc-chat-line.npc-chat-line-player {
  color: #9999ff;
}

.npc-chat-name {
  color: inherit;
}

.npc-chat-keyword {
  color: #3399ff;
  cursor: pointer;
}

.npc-chat-keyword:hover {
  text-decoration: underline;
}

.npc-chat-footer {
  display: flex;
  align-items: center;
  gap: 6px;
}

.npc-chat-icons {
  display: flex;
  gap: 4px;
}

.npc-chat-icon-button {
  width: 22px;
  height: 22px;
  padding: 0;
  background-repeat: no-repeat;
  background-position: center;
  background-size: 16px 16px;
  image-rendering: pixelated;
}

.npc-chat-icon-yes {
  background-image: url("../png/npcchat/icon-yes.png");
}

.npc-chat-icon-no {
  background-image: url("../png/npcchat/icon-no.png");
}

/* Placeholder art -- see the note at the top of modal-npc-chat.js/index.html's NPC Chat Modal
   comment for where a real icon should replace this */
.npc-chat-icon-trade {
  background-image: url("../png/npcchat/icon-trade-placeholder.png");
}

#npc-chat-input {
  flex: 1;
  min-width: 0;
}

.npc-chat-toggle-button {
  font-size: 10px;
  white-space: nowrap;
}
