/* ===========================================================================
   Idle RO — classic Ragnarok client skin, blue-and-white window set.

   The old client's windows are pale: a light blue gradient caption bar with
   navy text, a near-white body, and sunken slots drawn as flattened ovals
   rather than squares. Empty equipment cells carry a ghosted label (head,
   body, accessory) so the doll reads even with nothing on it.
   =========================================================================== */

:root {
  /* Sampled straight out of the client screenshots rather than guessed.
     The windows are essentially WHITE — 35-55% of every reference shot is
     #ffffff — with periwinkle chrome. An overall blue tint reads wrong. */
  --face:      #ffffff;
  --face-2:    #f4f5fb;
  --face-3:    #eeeef8;   /* alternating table row */
  --hi:        #ffffff;
  --lo:        #cdd5e6;
  --edge:      #8794bc;   /* outer window line */
  --edge-soft: #c6cde9;

  /* caption bar: bright highlight, periwinkle body, darker foot */
  --title-hi:  #daf7ff;
  --title-a:   #c4d9f9;
  --title-b:   #b6c7e9;
  --title-c:   #9aaed3;
  --title-txt: #16233d;

  --txt:       #1c2436;
  --dim:       #737d94;
  --link:      #4a5fa0;
  --accent:    #7b94ce;
  --gold:      #8a5a00;
  --red:       #a32020;
  --green:     #16713a;

  --hp-a: #ff7676; --hp-b: #c02020;
  --sp-a: #7fb0ff; --sp-b: #2352ad;
  --exp-a: #86df86; --exp-b: #227f2c;
  --job-a: #ffdc84; --job-b: #b98c1c;

  --slot:      #ffffff;
  --slot-edge: #cdd5e6;
  --scene:     #0d151f;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background:
    radial-gradient(ellipse 1100px 600px at 15% -10%, #ffffff 0%, rgba(255,255,255,0) 70%),
    radial-gradient(ellipse 900px 520px at 95% 110%, #e4e9f7 0%, rgba(228,233,247,0) 70%),
    linear-gradient(170deg, #ffffff 0%, #f2f4fb 45%, #e6eaf6 100%);
  background-attachment: fixed;
  color: var(--txt);
  font: 12px/1.45 Tahoma, Verdana, Geneva, "DejaVu Sans", sans-serif;
  -webkit-font-smoothing: antialiased;
}

/* The game owns the viewport: one screen, no page scrollbar. Everything that
   can overflow scrolls inside its own box instead — the panel body, and the
   full-page character screens. */
html, body { height: 100%; overflow: hidden; }

#app { display: flex; flex-direction: column; height: 100%; min-height: 0; }

.shell {
  display: flex; flex-direction: column;
  width: 100%; max-width: 1400px;
  height: 100%; min-height: 0;
  margin: 0 auto; padding: 10px; gap: 8px;
  box-sizing: border-box;
}

.splash {
  padding: 60px; text-align: center; color: #cfc5ac;
  text-shadow: 1px 1px 0 #000;
}

/* ---------------------------------------------------------------------------
   Window chrome
   --------------------------------------------------------------------------- */
.win {
  background: var(--face);
  border: 1px solid var(--edge);
  border-radius: 6px 6px 3px 3px;
  box-shadow: 0 1px 0 rgba(120, 135, 170, 0.25), 0 6px 18px rgba(90, 110, 150, 0.18);
}

.win-title {
  display: flex; align-items: center; gap: 7px;
  background:
    linear-gradient(180deg,
      var(--title-hi) 0%, var(--title-a) 18%,
      var(--title-b) 70%, var(--title-c) 100%);
  color: var(--title-txt);
  font-weight: 700; font-size: 11px; letter-spacing: 0.3px;
  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.7);
  padding: 4px 8px;
  border-bottom: 1px solid #8794bc;
  border-radius: 5px 5px 0 0;
}
.win-title::before {
  content: "";
  width: 9px; height: 9px; flex: none;
  border: 1px solid #6f7fa8;
  border-radius: 2px;
  background: linear-gradient(180deg, #ffffff, #aebfe0);
}
.win-title .spacer { flex: 1; }

/* sunken area (scene, lists, slots) */
.sunken {
  background: var(--face);
  border: 1px solid var(--slot-edge);
  border-radius: 3px;
  box-shadow: inset 0 1px 2px rgba(140, 152, 185, 0.35);
}

/* ---------------------------------------------------------------------------
   Buttons
   --------------------------------------------------------------------------- */
button.ro, .chip, .tab {
  font: 11px/1 Tahoma, Verdana, sans-serif;
  color: var(--txt);
  background: linear-gradient(180deg, #ffffff 0%, var(--face-2) 55%, #d8e4f1 100%);
  border: 1px solid var(--edge);
  border-radius: 3px;
  box-shadow: inset 0 1px 0 #fff, 0 1px 0 rgba(70, 100, 135, 0.18);
  padding: 4px 10px;
  cursor: pointer;
  white-space: nowrap;
}
button.ro:hover, .chip:hover, .tab:hover {
  background: linear-gradient(180deg, #ffffff, #e4eefa 60%, #cfe0f2);
}
button.ro:active, .chip:active {
  background: linear-gradient(180deg, #cfdcea, #e6eef7);
  box-shadow: inset 1px 1px 2px rgba(70, 100, 135, 0.35);
  padding: 5px 9px 3px 11px;
}
/* Full-width modal actions: a big button deserves big type. 11px text on a
   100%-wide control looked like a label that got lost. */
button.wide { width: 100%; margin-top: 6px; padding: 9px 6px; font-size: 12.5px; border-radius: 5px; }
button.mini { padding: 2px 6px; font-size: 10px; }
button.good { color: var(--green); font-weight: 700; }
button.bad  { color: var(--red); font-weight: 700; }
button.disabled, .disabled { opacity: 0.45; pointer-events: none; filter: grayscale(0.6); }

.chip.active {
  background: linear-gradient(180deg, #7ba6d8, #3f6fa8);
  color: #fff; text-shadow: 0 1px 0 rgba(0, 0, 0, 0.45);
  border-color: #2f5c92;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.5);
}

/* ---------------------------------------------------------------------------
   BAR MODE (top window)
   --------------------------------------------------------------------------- */
.bar { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; }
/* The field and the party sit SIDE BY SIDE.
 *
 * They used to stack, which cost the whole height of a party strip before the
 * panel got a single pixel — on a laptop that is most of the reason the content
 * area felt cramped. Beside it, the same information rides in space the sky was
 * wasting anyway, and the panel keeps everything the strip used to take. */
.bar-body {
  display: grid; grid-template-columns: minmax(0, 1fr) 306px;
  gap: 7px; padding: 7px; flex: 1; min-height: 0;
}
@media (max-width: 900px) {
  /* Too narrow to sit beside anything — go back to stacking. */
  .bar-body { grid-template-columns: minmax(0, 1fr); }
}

/* Three party cards and the HUD, all the same width: the left block takes
   three units to the HUD's one, and the card grid uses the dock's own gap, so
   the four columns line up exactly. */
.bar-left { display: flex; flex-direction: column; gap: 6px; min-width: 0; }

.portrait {
  width: 52px; height: 52px; flex: none; align-self: flex-start;
  background: #6d6a5a; overflow: hidden;
  border: 1px solid var(--edge);
  box-shadow: inset 1px 1px 0 var(--lo), inset -1px -1px 0 var(--hi);
  image-rendering: pixelated;
}
.portrait-canvas { display: block; image-rendering: pixelated; }

.bar-info { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.bar-name { display: flex; gap: 6px; align-items: baseline; }
.bar-name .nm { font-weight: 700; font-size: 13px; }
.bar-name .jb { color: var(--link); font-weight: 700; font-size: 11px; }
.bar-lv { display: flex; gap: 5px; flex-wrap: wrap; font-size: 10px; color: var(--dim); }
.bar-lv .pip {
  background: linear-gradient(180deg, #ffe9a8, #e0b850);
  border: 1px solid #8a6a10; color: #4a3200; font-weight: 700;
  padding: 0 4px;
}
.bar-bars { display: flex; flex-direction: column; gap: 2px; margin-top: 2px; }

.bar2 {
  position: relative; height: 12px;
  background: #2f2b23;
  border: 1px solid var(--edge);
  box-shadow: inset 1px 1px 0 #16130e, inset -1px -1px 0 #5a5245;
  overflow: hidden;
}
.bar2-fill {
  height: 100%;
  transition: width 0.18s linear;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.5), inset 0 -3px 4px rgba(0, 0, 0, 0.3);
}
.bar2.hp   .bar2-fill { background: linear-gradient(180deg, var(--hp-a), var(--hp-b)); }
.bar2.sp   .bar2-fill { background: linear-gradient(180deg, var(--sp-a), var(--sp-b)); }
.bar2.exp  .bar2-fill { background: linear-gradient(180deg, var(--exp-a), var(--exp-b)); }
.bar2.jexp .bar2-fill { background: linear-gradient(180deg, var(--job-a), var(--job-b)); }
.bar2-label {
  position: absolute; inset: 0;
  font: 9px/12px "DejaVu Sans Mono", Menlo, monospace;
  text-align: center; color: #fff;
  text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.85), -1px 0 0 rgba(0,0,0,0.6);
  letter-spacing: 0.3px;
}

/* party roster — every member other than the leader */
.bar-party {
  width: 148px; flex: none;
  display: flex; flex-direction: column; gap: 3px;
  padding: 3px 5px;
  background: linear-gradient(180deg, rgba(0,0,0,0.16), rgba(0,0,0,0.06));
  border: 1px solid var(--edge);
  box-shadow: inset 1px 1px 0 var(--lo), inset -1px -1px 0 var(--hi);
  overflow: hidden;
}
.pty-title {
  font: 700 9px/11px "DejaVu Sans Mono", Menlo, monospace;
  color: var(--dim); letter-spacing: 0.6px;
}
.pty-row { display: flex; flex-direction: column; gap: 1px; }
.pty-row.down { opacity: 0.45; }
.pty-line { display: flex; align-items: baseline; gap: 4px; font-size: 10px; }
.pty-line .pn { font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pty-line .pj { color: var(--link); font-size: 9px; }
.pty-line .pl { margin-left: auto; color: var(--dim); font-size: 9px; }
.bar2.mini { height: 9px; }
.bar2.mini .bar2-label { font-size: 8px; line-height: 9px; }
.bar2.thin { height: 4px; }

/* battlefield */
.bar-field {
  /* Grows into whatever the panel leaves behind, down to a floor that still
     shows the party and the monsters they are fighting. */
  position: relative; width: 100%; flex: 1 1 190px; min-height: 118px;
  background: var(--scene);
  border: 1px solid var(--edge);
  box-shadow: inset 1px 1px 0 var(--lo), inset -1px -1px 0 var(--hi), inset 0 0 22px rgba(0,0,0,0.7);
  overflow: hidden;
}
/* Absolute, not in flow. The canvas carries an intrinsic size — its backing
   store, which `Battlefield.resize()` sets from the element it is inside — so
   in flow it fed its own height back into the box that measures it, and the
   field could only ever grow. Taking it out of flow makes the box the single
   source of the size. */
.field-canvas {
  position: absolute; inset: 0;
  display: block; width: 100%; height: 100%; image-rendering: pixelated;
}
/* Party cards folded — see WorldSettings.fieldMin.
 *
 * ONLY the cards. The previous version hid the map plate and the belt as well,
 * and the button lives beside those, so folding took the way back with it —
 * there was no route to the party or the potions short of a reload. Whatever
 * else this hides, the control that undoes it has to stay on screen. */
.field-min .bar-left { display: none; }
/* Folded, with the Character window open: the battlefield STOPS GROWING and
   settles at the height of the dock beside it — the belt plus the Show party
   button, nothing more. Everything left over goes to the content.
 *
 * It used to be `flex: 1 1 auto` on the panel, which makes the panel's basis
 * its own content height, so the split depended on whatever the open tab
 * happened to contain: the battlefield visibly shrank on Wallet (a long
 * ledger) and grew back on Status (a short one). How tall the sky is was never
 * the tab's business. Pinning the field to its neighbour takes the question
 * away from flex entirely.
 *
 * Only while the panel is up. With it shut there is nothing else on screen and
 * the field should have all of it. */
.field-min.panel-open .bar { flex: 0 0 auto; }
.field-min.panel-open .bar-body { flex: 0 0 auto; }
.field-min.panel-open .bar-field { flex: 0 0 auto; }
/* A shade taller than the dock exactly. The row is sized by the dock, so the
   breathing room goes there — the belt and the Show party button stay where
   they are and the sky gets the extra 20px. */
.field-min.panel-open .bar-dock { padding-bottom: 20px; }
.field-min.panel-open .panel { flex: 1 1 auto; }


.ticker {
  position: absolute; left: 5px; top: 4px; max-width: 64%;
  display: flex; flex-direction: column; gap: 1px;
  pointer-events: none;
  font: 10px/1.35 "DejaVu Sans Mono", Menlo, monospace;
}
.ticker-line { color: #e6ddc8; text-shadow: 1px 1px 0 #000, 0 0 4px #000; }
.ticker-line.good { color: #8ef29a; }
.ticker-line.bad  { color: #ff9a9a; }
.ticker-line.card { color: #ffaee6; }
.ticker-line.mvp  { color: #ffd76a; font-weight: 700; }

/* --- party wipe: the client's "Game option" window -------------------------
   A titled window with the three choices stacked in it, over a darkened field.
   The banner this replaced looked like a notification; this looks like a
   decision, which is what it is. */
.wipe {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  background: radial-gradient(120% 100% at 50% 60%, rgba(20,4,6,0.42), rgba(0,0,0,0.66));
  z-index: 4;
}
.win.rowin { width: 300px; max-width: 84%; max-height: 96%; overflow: hidden; }
/* A short field (the Character window open on a small screen) gets a tighter
   box rather than one that spills over the party strip. */
@media (max-height: 700px) {
  .rowin-body { gap: 4px; padding: 7px 9px 8px; }
  button.ro.rowin-btn { padding: 5px 8px; font-size: 12px; }
  .rowin-note { display: none; }
}
.rowin-body {
  display: flex; flex-direction: column; gap: 6px;
  padding: 10px 12px 11px;
  background: linear-gradient(180deg, var(--face), var(--face-2));
}
button.ro.rowin-btn {
  width: 100%; padding: 7px 10px;
  font: 13px/1.2 Tahoma, Verdana, sans-serif;
  text-align: center;
}
button.ro.rowin-btn.counting {
  color: #6b5a2a; font-weight: 700;
  font-variant-numeric: tabular-nums;
  background: linear-gradient(180deg, #fff6d9, #f0e2b4);
}
.rowin-note {
  margin-top: 2px; font-size: 10px; line-height: 1.4; color: var(--dim); text-align: center;
}

/* the way back once "Return to game" has put the window away */
.wipe-chip {
  position: absolute; right: 8px; top: 8px; z-index: 5;
  padding: 4px 10px; cursor: pointer;
  font: 700 11px/1.4 Tahoma, Verdana, sans-serif;
  color: #ffd9d9;
  background: rgba(90, 20, 24, 0.85);
  border: 1px solid #8a3a3a; border-radius: 3px;
  font-variant-numeric: tabular-nums;
}
.wipe-chip:hover { background: rgba(120, 28, 32, 0.92); }

.bar-dock {
  display: flex; flex-direction: column; gap: 6px;
  min-width: 0; min-height: 0; overflow-y: auto;
}
.bar-right {
  min-width: 0; box-sizing: border-box;
  display: flex; flex-direction: column; gap: 4px;
  align-items: stretch;
}
@media (max-width: 900px) {
  .bar-left { flex-direction: row; }
}

/* --- map plate -------------------------------------------------------------- */
.dock-map {
  display: flex; align-items: center; gap: 6px;
  padding: 4px 8px;
  border: 1px solid var(--edge);
  border-radius: 4px;
  background: linear-gradient(180deg, var(--title-hi) 0%, var(--title-a) 40%, var(--title-b) 100%);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.7);
}
.dm-flag {
  width: 9px; height: 11px; flex: none;
  background: linear-gradient(180deg, #ffd76a, #d99a1e);
  border: 1px solid #8a6410;
  clip-path: polygon(0 0, 100% 0, 100% 62%, 50% 100%, 0 62%);
}
.dm-name {
  font: 700 11px/1.2 Tahoma, Verdana, sans-serif;
  color: var(--title-txt);
  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.6);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* --- party dots ------------------------------------------------------------- */
.dock-party { display: flex; align-items: center; gap: 4px; padding: 1px 3px; }
.pdot {
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--job, #9aaed3);
  border: 1px solid rgba(40, 55, 90, 0.45);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.55);
}
.pdot.j-swordman, .pdot.j-knight { --job: #c2603a; }
.pdot.j-mage,     .pdot.j-wizard { --job: #4f7fd0; }
.pdot.j-archer,   .pdot.j-hunter { --job: #4a9a5c; }
.pdot.j-acolyte,  .pdot.j-priest { --job: #d0a63a; }
.pdot.out { background: #cfd5e4; box-shadow: none; opacity: 0.7; }
.pnum {
  margin-left: auto;
  font: 700 10px/1 Tahoma, sans-serif; color: var(--dim); letter-spacing: 0.3px;
}

/* --- resource chips --------------------------------------------------------- */
.dock-stats { display: flex; gap: 4px; }
.dchip {
  flex: 1 1 0; min-width: 0;
  display: flex; align-items: center; gap: 4px;
  padding: 3px 6px;
  border: 1px solid var(--edge-soft);
  border-radius: 10px;
  background: linear-gradient(180deg, #ffffff, var(--face-3));
}
.dc-ico { width: 12px; height: 12px; flex: none; }
.dc-val {
  font: 700 11px/1 Tahoma, Verdana, sans-serif;
  color: var(--txt); margin-left: auto;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.dchip.zeny .dc-ico {
  border-radius: 50%;
  background: radial-gradient(circle at 34% 30%, #fff3b0 0%, #f0c33a 45%, #b07d10 100%);
  box-shadow: inset 0 0 0 1px rgba(120, 82, 8, 0.6);
}
.dchip.zeny .dc-val { color: var(--gold); }
.dchip.kp .dc-ico {
  background: linear-gradient(180deg, #cfe0ff, #6f92d8);
  border: 1px solid #40598f;
  transform: rotate(45deg) scale(0.82);
}
.dchip.card .dc-ico {
  width: 10px; height: 13px;
  border-radius: 2px;
  background: linear-gradient(180deg, #ffffff, #dfe6f6);
  border: 1px solid #7f8db3;
  box-shadow: 1.5px -1.5px 0 -0.5px #b9c4dd, 1.5px -1.5px 0 0 #7f8db3;
}

button.ro.expand {
  padding: 6px 10px;
  font: 700 12px/1 Tahoma, Verdana, sans-serif;
}
.map-name { font-weight: 700; font-size: 12px; }
.zeny {
  color: var(--gold); font-weight: 700;
  font-family: "DejaVu Sans Mono", Menlo, monospace;
}
.kafra { color: var(--dim); font-size: 10px; }

/* ---------------------------------------------------------------------------
   PANEL
   --------------------------------------------------------------------------- */
.panel { display: flex; flex-direction: column; flex: 1 1 460px; min-height: 0; }

/* --- the menu column -------------------------------------------------------
   A sidebar rather than a strip of tabs: sections are added by appending to a
   list that grows downwards, instead of competing for a fixed width. */
.panel-main { display: flex; flex: 1; min-height: 0; }
.panel-right { flex: 1; min-width: 0; min-height: 0; display: flex; flex-direction: column; }
.panel-head {
  flex: none;
  padding: 8px 10px 6px;
  background: linear-gradient(180deg, #ffffff, var(--face-2));
  border-bottom: 1px solid var(--edge-soft);
}
.panel-head .char-select { margin-bottom: 0; }

.side {
  flex: none; width: 168px;
  display: flex; flex-direction: column; gap: 2px;
  padding: 8px 7px 10px;
  overflow-y: auto;
  background: linear-gradient(180deg, var(--face-2), var(--face-3));
  border-right: 1px solid var(--edge);
}
.side-group { display: flex; flex-direction: column; gap: 2px; }
.side-group + .side-group { margin-top: 10px; }
.side-cap {
  font: 700 9px/1 Tahoma, Verdana, sans-serif;
  letter-spacing: 0.8px; text-transform: uppercase;
  color: var(--dim);
  padding: 0 0 3px 6px;
}
.side-item {
  display: flex; align-items: center; gap: 8px;
  width: 100%; padding: 6px 8px;
  font: 12px/1 Tahoma, Verdana, sans-serif; text-align: left;
  color: var(--txt);
  background: transparent; border: 1px solid transparent; border-radius: 3px;
  cursor: pointer;
}
.side-item:hover { background: rgba(255, 255, 255, 0.75); border-color: var(--edge-soft); }
.side-item.active {
  font-weight: 700; color: #23315c;
  background: linear-gradient(180deg, #ffffff, #e8eefb);
  border-color: #93a8d2;
  box-shadow: inset 2px 0 0 var(--link);
}
.si-ico {
  width: 16px; height: 16px; flex: none;
  display: flex; align-items: center; justify-content: center;
  color: var(--link);
}
.si-ico svg { width: 16px; height: 16px; display: block; }
.side-item.active .si-ico { color: #2f4e88; }
.si-lab { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.panel-close {
  font: 700 10px/1 Tahoma, Verdana, sans-serif;
  color: #7a2f2f; background: transparent; border: 0; cursor: pointer;
  padding: 2px 4px;
}
.panel-close:hover { color: var(--red); text-decoration: underline; }

/* Narrow windows drop the labels and keep the icons, so the menu never eats
   the content it is a menu for. */
@media (max-width: 900px) {
  .side { width: 46px; padding: 8px 5px; align-items: center; overflow-x: hidden; }
  .side-cap { display: none; }
  .side-item { position: relative; justify-content: center; padding: 7px 4px; min-width: 0; }
  .si-lab { display: none; }
  /* Both of these are `margin-left: auto` pills built for a labelled row. In a
     46px icon rail they are wider than the rail itself — the SOON pill was
     hanging into the content area. The word goes; the fact does not (the
     entry is still dimmed and still refuses to open), and the unread count
     becomes a corner pip. */
  .side-item.soon::after {
    content: ''; position: absolute; top: 5px; right: 5px;
    width: 6px; height: 6px; border-radius: 50%; background: #c0392b;
  }
}

.panel-body {
  padding: 10px;
  flex: 1; min-height: 0;
  overflow-y: auto;
  background: var(--face);
}

/* scrollbar */
.panel-body::-webkit-scrollbar { width: 14px; }
.panel-body::-webkit-scrollbar-track { background: var(--face-3); border-left: 1px solid var(--edge); }
.panel-body::-webkit-scrollbar-thumb {
  background: linear-gradient(90deg, #f0e9d6, var(--face-2));
  border: 1px solid var(--edge);
  box-shadow: inset 1px 1px 0 var(--hi), inset -1px -1px 0 var(--lo);
}

h3 { margin: 0 0 7px; font-size: 12px; letter-spacing: 0.4px; text-transform: uppercase; color: var(--link); }
h4 { margin: 9px 0 5px; font-size: 11px; color: var(--link); text-transform: uppercase; letter-spacing: 0.3px; }
p { margin: 4px 0; }
.small { font-size: 10px; }
.muted { color: var(--dim); }

/* `min(330px, 100%)` rather than a flat 330px: a track floor larger than the
   track itself cannot be honoured, so on a phone the two cards kept their
   330px and pushed straight out of the panel. Identical wherever there is
   330px to give. */
.grid2 {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(330px, 100%), 1fr));
  gap: 9px;
}
.grid3 { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(250px, 100%), 1fr)); gap: 9px; }

.card {
  /* The client's panels are white with periwinkle edges, not beige. */
  background: linear-gradient(180deg, #ffffff 0%, var(--face-2) 100%);
  border: 1px solid var(--edge-soft);
  border-radius: 4px;
  box-shadow: inset 0 1px 0 #fff, 0 1px 2px rgba(120,135,170,0.16);
  padding: 10px;
}

.row { display: flex; gap: 5px; flex-wrap: wrap; margin-top: 6px; }
.row-between { display: flex; justify-content: space-between; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 6px; }

.kv {
  display: flex; justify-content: space-between; gap: 8px;
  padding: 2px 4px;
  border-bottom: 1px dotted rgba(60, 54, 44, 0.28);
}
.kv:nth-child(even) { background: var(--face-3); }
.kv .k { color: var(--dim); }
.kv .v { font-family: "DejaVu Sans Mono", Menlo, monospace; font-weight: 700; text-align: right; }
.kv-how {
  display: block; font-size: 9px; line-height: 1.25;
  color: var(--dim); opacity: 0.72; font-weight: 400;
}

/* stats */
.stat-row {
  /* Never wrap: in a three-column layout the + button was dropping onto its
     own line and doubling the height of the list. */
  display: flex; align-items: center; gap: 6px; padding: 3px 4px;
  flex-wrap: nowrap; min-width: 0;
}
.stat-row .stat-val { flex: 1; }
.stat-row:nth-child(even) { background: var(--face-3); }
.stat-name { width: 32px; flex: none; font-weight: 700; color: var(--link); font-size: 11px; }
.stat-val { flex: 1; min-width: 0; font-family: "DejaVu Sans Mono", Menlo, monospace; font-size: 13px; font-weight: 700; }
.stat-plus  { color: var(--green); font-size: 11px; }
.stat-minus { color: var(--red); font-size: 11px; }

.char-select { display: flex; gap: 5px; margin-bottom: 9px; flex-wrap: wrap; }

/* ---------------------------------------------------------------------------
   Item slots & grids — the RO inventory look
   --------------------------------------------------------------------------- */
.slot {
  position: relative;
  width: 46px; height: 46px; flex: none;
  background: var(--slot);
  border: 1px solid var(--edge);
  box-shadow: inset 1px 1px 0 var(--lo), inset -1px -1px 0 rgba(255,255,255,0.55);
  display: flex; align-items: center; justify-content: center;
  cursor: pointer;
  overflow: hidden;
}
.slot.empty { background: #f7f8fc; cursor: default; }

/* --- rarity ----------------------------------------------------------------
   Common is the plain slot. Everything above it gets a coloured border, a wash
   of its colour, and a corner flag, so an upgrade is visible in a grid of
   forty icons without reading a single name. */
.slot.r-uncommon  { border-color: #4f9b5a; background: linear-gradient(180deg, #eefaf0, #dcf0e0); }
.slot.r-rare      { border-color: #3f74c4; background: linear-gradient(180deg, #eaf1ff, #d8e5fb); }
.slot.r-epic      { border-color: #8a55c8; background: linear-gradient(180deg, #f4ecff, #e6d9fa); }
.slot.r-legendary { border-color: #c08a1e; background: linear-gradient(180deg, #fff6e0, #ffe9bd); }
.slot.r-epic, .slot.r-legendary { box-shadow: inset 0 0 8px rgba(255, 214, 130, 0.35); }
.slot.r-uncommon::after, .slot.r-rare::after,
.slot.r-epic::after, .slot.r-legendary::after {
  content: ""; position: absolute; right: 0; top: 0;
  border-width: 0 7px 7px 0; border-style: solid;
  border-color: transparent currentColor transparent transparent;
}
.slot.r-uncommon::after  { color: #4f9b5a; }
.slot.r-rare::after      { color: #3f74c4; }
.slot.r-epic::after      { color: #8a55c8; }
.slot.r-legendary::after { color: #d9a52a; }
/* An item that beats what the character is wearing */
.slot.upgrade { outline: 2px solid rgba(90, 200, 120, 0.75); outline-offset: -2px; }
.slot:not(.empty):hover { box-shadow: inset 0 0 0 2px #ffd76a, inset 1px 1px 0 var(--lo); }
.slot.selected { box-shadow: inset 0 0 0 2px #ffffff, inset 0 0 0 3px var(--title-b); }
.slot canvas { image-rendering: pixelated; width: 44px; height: 44px; }
.icon-sm canvas { image-rendering: pixelated; }

.slot-refine {
  position: absolute; top: 1px; left: 1px;
  padding: 0 3px;
  font: 700 9px/13px "DejaVu Sans Mono", monospace;
  color: #ffe27a;
  background: rgba(24, 30, 44, 0.86);
  border-radius: 2px;
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.35);
}
.slot-qty {
  /* A count needs its own ground to stand on. Outlined white text over pixel
     art of any colour is a coin toss, and on the pale loot icons it lost. */
  position: absolute; bottom: 1px; right: 1px;
  min-width: 13px; padding: 0 3px;
  font: 700 9px/13px "DejaVu Sans Mono", monospace; text-align: center;
  color: #fff;
  background: rgba(24, 30, 44, 0.86);
  border-radius: 2px;
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.45);
}
.slot-cards {
  position: absolute; bottom: 1px; left: 1px; display: flex; gap: 1px;
}
.slot-cards i { width: 4px; height: 4px; background: #ff7ad4; border: 1px solid #000; display: block; }
.slot-cards i.free { background: #4a4a4a; }

.slot-label {
  font-size: 9px; color: var(--dim); text-align: center;
  margin-top: 2px; letter-spacing: 0.2px;
}

.item-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, 46px);
  gap: 4px;
  padding: 7px;
  min-height: 120px;
  align-content: start;
}

/* detail strip under a grid */
.detail {
  display: flex; gap: 10px; align-items: flex-start;
  margin-top: 8px; padding: 8px;
  background: linear-gradient(180deg, #eef3ff, var(--face-2));
  border: 1px solid var(--edge);
  box-shadow: inset 1px 1px 0 var(--hi), inset -1px -1px 0 var(--lo);
  min-height: 74px;
}
.detail-name { font-weight: 700; font-size: 12px; }
.detail-name .rf { color: var(--gold); }
.detail-sub { font-size: 10px; color: var(--dim); }
.detail-stats { font-size: 11px; margin-top: 3px; font-family: "DejaVu Sans Mono", Menlo, monospace; }
.detail-cards { font-size: 10px; color: #8a2f74; margin-top: 2px; }
.detail-actions { margin-left: auto; display: flex; flex-direction: column; gap: 4px; }

/* ---------------------------------------------------------------------------
   Paper doll
   --------------------------------------------------------------------------- */
.doll {
  display: grid;
  grid-template-columns: auto minmax(140px, 200px) auto;
  justify-content: center;
  gap: 8px; align-items: start;
  padding: 6px 4px 2px;
}
.doll-col { display: flex; flex-direction: column; gap: 5px; }
.doll-cell { display: flex; flex-direction: column; align-items: center; }
.doll {
  /* the middle column stretches to whatever the slot columns come to */
  align-items: stretch;
}
.doll-stage {
  position: relative;
  width: 190px; margin: 0 auto;
  /* No green box. The character stands on the panel itself, the way the client
     has it, and the stage matches the height of the slot columns either side
     instead of being a picture frame in the middle of them. */
  background: none;
  border: 0; box-shadow: none;
  height: 100%; min-height: 190px;
  display: flex; align-items: flex-end; justify-content: center;
  padding-bottom: 14px;
}
.doll-stage canvas { image-rendering: pixelated; }
.doll-stage .floor {
  position: absolute; left: 14%; right: 14%; bottom: 12px; height: 12px;
  background: radial-gradient(ellipse at center, rgba(74, 88, 118, 0.30), transparent 72%);
}

/* ---------------------------------------------------------------------------
   Skills
   --------------------------------------------------------------------------- */
.skill-row {
  display: flex; gap: 8px; align-items: flex-start;
  padding: 5px; margin-bottom: 2px;
  background: rgba(255, 255, 255, 0.2);
  border: 1px solid transparent;
}
.skill-row.learned {
  background: linear-gradient(180deg, #f3edda, #e2d9bf);
  border-color: var(--lo);
  box-shadow: inset 1px 1px 0 var(--hi);
}
.skill-info { flex: 1; min-width: 0; }
.skill-name { font-weight: 700; font-size: 11px; }
.skill-lv {
  font-family: "DejaVu Sans Mono", monospace;
  color: var(--gold); font-weight: 700;
}
.skill-meta { font-size: 10px; color: var(--link); font-family: "DejaVu Sans Mono", monospace; }
.skill-desc { font-size: 10px; color: var(--dim); }
.skill-req { font-size: 9px; color: var(--red); }
.skill-req.ok { color: var(--green); }

.prio-row {
  display: flex; gap: 5px; align-items: center; padding: 3px 4px;
}
.prio-row:nth-child(even) { background: rgba(255,255,255,0.22); }
.prio-num {
  width: 18px; height: 18px; flex: none;
  display: flex; align-items: center; justify-content: center;
  background: linear-gradient(180deg, var(--title-a), var(--title-b));
  color: #fff; font: 700 10px/1 monospace;
  border: 1px solid var(--edge);
}
.prio-name { flex: 1; font-size: 11px; }
/* Fixed width and right-aligned: this is the only variable-width text in the
   row's right cluster, so 'always' vs 'multiTarget' was shoving the level
   controls and arrows to different x on every row. Pin it and every column
   lines up like a table, which is what the eye expects a list to be. */
.prio-cond { font-size: 9px; color: var(--dim); width: 78px; flex: none; text-align: right; }

/* ---------------------------------------------------------------------------
   Maps
   --------------------------------------------------------------------------- */
.map-card.current { box-shadow: inset 0 0 0 2px var(--title-b), inset 1px 1px 0 var(--hi); }
.map-card.locked { opacity: 0.5; filter: grayscale(0.5); }
.mvp-line {
  color: #6d3a00; font-size: 10px; margin-top: 4px; font-weight: 700;
  background: rgba(255, 210, 120, 0.4);
  border-left: 3px solid var(--gold);
  padding: 2px 5px;
}

.toggle-row { display: flex; gap: 8px; align-items: center; padding: 4px 2px; }
.text-input, .save-area {
  width: 100%; margin-top: 5px; padding: 5px;
  background: #fffdf3; color: var(--txt);
  border: 1px solid var(--edge);
  box-shadow: inset 1px 1px 0 var(--lo);
  font: 10px "DejaVu Sans Mono", monospace;
}

.notice {
  margin-top: 7px; padding: 6px 8px; font-size: 10px; font-weight: 700;
  background: rgba(255, 214, 120, 0.55);
  border: 1px solid var(--gold);
  color: #6d3a00;
}

.filters { display: flex; gap: 4px; flex-wrap: wrap; }

.loot-list { display: flex; flex-wrap: wrap; gap: 4px; }
.loot-chip {
  background: var(--face-2); border: 1px solid var(--edge);
  box-shadow: inset 1px 1px 0 var(--hi);
  padding: 2px 6px; font-size: 10px;
}

/* progress meter used by the card album */
.meter { margin: 6px 0 10px; }

/* ---------------------------------------------------------------------------
   Modal
   --------------------------------------------------------------------------- */
.modal-back {
  position: fixed; inset: 0; z-index: 50;
  background: rgba(0, 0, 0, 0.6);
  display: flex; align-items: center; justify-content: center; padding: 20px;
}
.modal {
  background: var(--face);
  border: 1px solid var(--edge);
  box-shadow: inset 1px 1px 0 var(--hi), inset -1px -1px 0 var(--lo), 0 14px 40px rgba(0,0,0,0.6);
  max-width: 470px; width: 100%;
}
.modal-inner { padding: 14px; }
.modal h2 { margin: 0 0 4px; font-size: 15px; color: var(--gold); text-transform: uppercase; letter-spacing: 0.5px; }
.modal-rows { margin: 9px 0; }

@media (max-width: 900px) {
  /* The dock is a row of [party cards | HUD]. Telling both children to be
     100% wide without letting the row WRAP just squeezed them into slivers —
     which is exactly what the party cards had become. */
  /* `flex-direction` is COLUMN on the base rule, and wrapping a column wraps
     into extra COLUMNS — which is how the belt and the Show party button ended
     up off the right edge of a phone with a scrollbar under them. Say row. */
  .bar-dock { display: flex; flex-direction: row; flex-wrap: wrap; overflow: visible; }
  .bar-left { flex-wrap: wrap; }
  .mem { flex: 1 1 220px; }
  .bar-left, .bar-right, .bar-party { width: 100%; }
  .bar-right { flex: 1 1 100%; border-left: 0; padding-left: 0; }
  .bar-party { flex-direction: row; flex-wrap: wrap; gap: 6px; }
  .bar-party .pty-row { flex: 1 1 130px; }
  .pty-title { flex: 1 1 100%; }
  .bar-right { flex-direction: row; align-items: center; flex-wrap: wrap; }
}
@media (max-width: 620px) {
  /* Party dots, the belt and the Show party button in one row is about 470px
     of content in 350px of phone — with three in the party it ran off the
     right edge and took a scrollbar with it. Stack them. */
}

/* character creation */
.modal.create { max-width: 560px; }
.job-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; margin: 8px 0; }
.job-card {
  background: var(--face-3);
  border: 1px solid var(--edge);
  box-shadow: inset 1px 1px 0 var(--lo), inset -1px -1px 0 var(--hi);
  padding: 5px; cursor: pointer; text-align: center;
}
.job-card:hover { box-shadow: inset 0 0 0 2px #ffd76a; }
.job-card.active {
  box-shadow: inset 0 0 0 2px #fff, inset 0 0 0 3px var(--title-b);
  background: linear-gradient(180deg, #eef3ff, var(--face-2));
}
.job-portrait {
  height: 96px; display: flex; align-items: flex-end; justify-content: center;
  background: linear-gradient(180deg, #6f8f6a, #3f5a3c);
  border: 1px solid var(--edge);
  box-shadow: inset 1px 1px 0 var(--lo);
}
.job-portrait canvas { image-rendering: pixelated; }
.job-name { font-weight: 700; font-size: 11px; margin-top: 4px; }

/* ---------------------------------------------------------------------------
   Wallet login + roster
   --------------------------------------------------------------------------- */
.login-wrap {
  height: 100%; overflow-y: auto; box-sizing: border-box; display: flex; align-items: safe center; justify-content: safe center;
  padding: 24px;
}
.win.login { width: 580px; max-width: 100%; }
.login-body { padding: 38px 34px 28px; text-align: center; }
.login-mark {
  font: 700 40px/1 Tahoma, Verdana, sans-serif; letter-spacing: 4px;
  color: #2b5c9c; text-shadow: 0 1px 0 #fff;
}
.login-sub { color: var(--dim); margin: 12px 0 24px; font-size: 14px; }
.login-btn { font-weight: 700; padding: 14px; font-size: 15px; }
.login-msg { min-height: 22px; margin-top: 14px; font-size: 13px; color: var(--dim); }
.login-msg.bad { color: var(--red); }
.login-note {
  margin-top: 18px; font-size: 12px; line-height: 1.55; color: var(--dim);
  border-top: 1px solid var(--edge-soft); padding-top: 10px;
}
.login-note.bad { color: var(--red); border-color: #e0b4b4; }

.wallet-chip {
  display: flex; align-items: center; gap: 6px;
  font: 10px/1 "DejaVu Sans Mono", monospace; color: var(--dim);
}
.wc-dot {
  width: 7px; height: 7px; border-radius: 50%;
  background: #35c46a; box-shadow: 0 0 0 1px rgba(0,0,0,0.2);
}

.roster-head { display: flex; align-items: baseline; gap: 8px; }
.roster-head .spacer { flex: 1; }
.roster-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(148px, 1fr));
  gap: 8px; margin: 8px 0;
}
.roster-card {
  border: 1px solid var(--edge-soft); border-radius: 4px;
  background: linear-gradient(180deg, #ffffff, var(--face-2));
  padding: 8px; display: flex; flex-direction: column; gap: 2px;
}
.roster-card.fielded {
  border-color: #4a7fbe;
  box-shadow: inset 0 0 0 1px #bcd6ef, 0 1px 0 rgba(70,100,135,0.2);
}
.rc-name { font-weight: 700; }
.rc-slot { color: #2b6cb0; font-size: 10px; }
.rc-job { color: var(--link); font-size: 11px; text-transform: capitalize; }
.rc-lv { color: var(--dim); font-size: 10px; }
.rc-act { margin-top: 6px; }

/* ---------------------------------------------------------------------------
   Character Select

   The client's select screen is a full-bleed scene, not a dialog: three tall
   slot panels standing side by side, a folder tab over the chosen one, a
   chevron either side, the stat plate down the left and the wordmark right.
   --------------------------------------------------------------------------- */
.cs-scene {
  height: 100%; overflow-y: auto; box-sizing: border-box;
  display: flex; flex-direction: column;
  align-items: center; justify-content: safe center;
  gap: 16px; padding: 24px 20px 28px;
  background:
    radial-gradient(ellipse 900px 460px at 50% 8%, rgba(255,255,255,0.95) 0%, rgba(255,255,255,0) 72%),
    radial-gradient(ellipse 1200px 700px at 50% 120%, #d7e0f4 0%, rgba(215,224,244,0) 70%),
    linear-gradient(175deg, #f7f9ff 0%, #e9eefb 55%, #dde5f6 100%);
}

.cs-stage { display: flex; align-items: center; gap: 20px; }

.cs-arrow {
  width: 42px; height: 88px; flex: none;
  font: 20px/1 Tahoma, sans-serif; color: #3d4c74;
  border: 1px solid var(--edge);
  border-radius: 5px;
  background: linear-gradient(180deg, #ffffff 0%, var(--title-a) 46%, var(--title-b) 100%);
  box-shadow: inset 0 1px 0 #fff, 0 1px 2px rgba(90,110,150,0.3);
  cursor: pointer;
}
.cs-arrow:hover { background: linear-gradient(180deg, #ffffff, #d3e2fb 46%, var(--title-a)); }
.cs-arrow:active { box-shadow: inset 0 2px 3px rgba(90,110,150,0.4); }
.cs-arrow.off { opacity: 0.32; cursor: default; }

.cs-cards { display: flex; gap: 16px; }
.cs-cell { display: flex; flex-direction: column; align-items: center; }

/* folder tab — kept in the layout when hidden so the cards stay level */
.cs-tab {
  width: 112px; height: 27px;
  display: flex; align-items: center; justify-content: center;
  font: 700 14px/1 Tahoma, Verdana, sans-serif;
  color: var(--title-txt);
  text-shadow: 0 1px 0 rgba(255,255,255,0.75);
  border: 1px solid var(--edge);
  border-bottom: 0;
  border-radius: 6px 6px 0 0;
  background: linear-gradient(180deg, var(--title-hi) 0%, var(--title-a) 40%, var(--title-b) 100%);
  margin-bottom: -1px; position: relative; z-index: 2;
}
.cs-tab.off { visibility: hidden; }

.cs-card {
  width: 200px;
  border: 1px solid var(--edge);
  border-radius: 6px;
  background: linear-gradient(180deg, #ffffff 0%, #f6f8ff 62%, #e8ecf9 100%);
  box-shadow: 0 2px 0 rgba(120,135,170,0.18), 0 8px 20px rgba(90,110,150,0.16);
  padding: 8px 8px 0;
  cursor: pointer;
  overflow: hidden;
}
.cs-card.on {
  border-color: #5f7bb6;
  box-shadow:
    0 0 0 2px rgba(140, 172, 226, 0.55),
    0 2px 0 rgba(120,135,170,0.2), 0 10px 24px rgba(70,95,150,0.24);
}
.cs-card:hover { background: linear-gradient(180deg, #ffffff 0%, #f2f6ff 62%, #e2e9fa 100%); }
.cs-card.empty .cs-canvas { opacity: 0.9; }

.cs-canvas {
  display: block; width: 184px; height: 250px;
  image-rendering: pixelated;
  border: 1px solid var(--slot-edge);
  border-radius: 3px;
  box-shadow: inset 0 1px 3px rgba(140,152,185,0.3);
}

.cs-plate {
  margin: 8px -8px 0;
  padding: 6px 8px;
  font: 700 14px/1.3 Tahoma, Verdana, sans-serif;
  text-align: center;
  color: var(--title-txt);
  text-shadow: 0 1px 0 rgba(255,255,255,0.7);
  border-top: 1px solid var(--edge-soft);
  background: linear-gradient(180deg, var(--title-a) 0%, var(--title-b) 100%);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.cs-card.locked {
  opacity: 0.4; cursor: default;
  box-shadow: none;
  filter: grayscale(0.4);
}
.cs-card.empty .cs-plate {
  color: #8b93ab; font-weight: 400;
  background: linear-gradient(180deg, #f1f3fa, #e5e9f5);
}

/* --- lower band: stats left, counter and wordmark right ------------------- */
.cs-lower {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 30px; width: 790px; max-width: 100%;
}

.cs-stats {
  flex: none; width: 430px;
  padding: 9px 12px;
  background: var(--face);
  border: 1px solid var(--edge);
  border-radius: 4px;
  box-shadow: inset 0 1px 2px rgba(140,152,185,0.28);
}
.cs-strow {
  display: grid;
  grid-template-columns: 56px 1fr 40px 48px;
  align-items: baseline;
  font-size: 14px; line-height: 1.72;
}
.cs-strow:nth-child(odd) { background: var(--face-3); }
.cs-k, .cs-k2 { color: var(--dim); }
.cs-v { color: var(--txt); font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cs-v2 { color: var(--txt); font-weight: 700; text-align: right; }
.cs-stats.blank .cs-v, .cs-stats.blank .cs-v2 { color: transparent; }

.cs-right { display: flex; flex-direction: column; align-items: flex-end; gap: 8px; }
.cs-count { text-align: right; }
.cs-count .n {
  display: block; font: 700 21px/1.1 Tahoma, Verdana, sans-serif; color: #2f4e88;
}
.cs-count .l { display: block; font-size: 11px; color: var(--dim); }
/* "2 ready to claim" — presale slots and bonus characters not yet made. */
.cs-count .c { display: block; margin-top: 6px; font-size: 12px;
               font-weight: 700; color: #1d7a3c; }

.cs-mark {
  text-align: right; line-height: 0.94;
  font-family: Georgia, "Times New Roman", serif;
  color: #3a63a8;
  text-shadow: 0 1px 0 #fff, 0 2px 3px rgba(90,110,150,0.28);
}
.cs-mark .m1 { display: block; font-size: 40px; font-style: italic; font-weight: 700; }
.cs-mark .m2 { display: block; font-size: 22px; font-style: italic; color: #6b83b6; }
.cs-mark .m3 { display: block; font-size: 33px; font-style: italic; font-weight: 700; }

.cs-dots { display: flex; gap: 5px; margin-top: 2px; }
.cs-dot {
  width: 10px; height: 10px; border-radius: 50%;
  border: 1px solid var(--edge); background: #fff; cursor: pointer;
}
.cs-dot.on { background: var(--accent); }

/* --- footer --------------------------------------------------------------- */
.cs-foot {
  display: flex; align-items: center; gap: 10px;
  width: 790px; max-width: 100%;
}
.cs-foot .spacer { flex: 1; }
button.ro.cs-btn { min-width: 104px; padding: 9px 18px; font-size: 14px; }
button.ro.cs-btn.primary { font-weight: 700; }
button.ro.cs-btn:disabled { opacity: 0.45; cursor: default; }

/* Rendered always, shown only on a phone — see the fold notes in panels.ts. */
.cp-fold { display: none; }
.map-select {
  display: none; width: 100%; margin: 0 0 10px; padding: 9px 10px;
  font: 700 13px/1.2 Tahoma, sans-serif; color: var(--txt);
  background: var(--face); border: 1px solid var(--edge); border-radius: 5px;
}

@media (max-width: 620px) {
  /* The window caption fits on one line or it takes two, and two lines of
     chrome at the top of a phone is a real chunk of the battlefield. */
  .win-title { font-size: 9.5px; letter-spacing: 0; gap: 5px; padding: 4px 6px; }
  .win-title > span { min-width: 0; overflow: hidden; text-overflow: ellipsis;
                      white-space: nowrap; }

  /* The select screen is a fixed-width stage: two 42px chevrons, three 200px
     cards and a 790px lower band. On a phone that is 474px of stage inside
     350px of screen, and it took the whole page sideways with it.
     The cards give up their fixed width and share the row instead. */
  .cs-scene { padding: 16px 10px 20px; gap: 12px; }
  .cs-stage { gap: 0; width: 100%; }
  /* The dots underneath page just as well and cost no width. */
  .cs-arrow { display: none; }
  .cs-cards { gap: 7px; width: 100%; }
  .cs-cell { flex: 1 1 0; min-width: 0; }
  .cs-tab { width: 100%; height: 24px; font-size: 12px; }
  .cs-card { width: 100%; padding: 6px 6px 0; }
  .cs-canvas { width: 100%; height: 132px; }
  .cs-plate { margin: 6px -6px 0; padding: 5px 4px; font-size: 12px; }

  /* Stats and wordmark stop competing for one line — the stat plate was left
     with 19px for its values, so every number on it was invisible.
     `display: contents` dissolves the band so its two halves become children
     of the scene itself, which is what lets the wordmark move: on a phone it
     reads as the screen's title and belongs at the top, above the cards,
     rather than buried between the stat plate and the buttons. */
  .cs-lower { display: contents; }
  .cs-right { order: -1; }
  .cs-mark { order: -1; }
  /* The scene centres its children, so anything with `width: auto` shrinks to
     its own text and sits in the middle of a half-empty row. These want the
     whole width — the stat plate especially, where the Exp value was running
     into the Str label with nowhere to go. */
  .cs-right, .cs-stats, .cs-foot, .cs-stage { align-self: stretch; }
  .cs-stats { width: 100%; flex: none; }
  .cs-strow { grid-template-columns: 46px minmax(0, 1fr) 34px 40px; font-size: 13px; }
  .cs-v { min-width: 0; }
  .cs-right { align-items: center; }
  .cs-count { text-align: center; }
  .cs-mark { text-align: center; }
  .cs-mark .m1 { font-size: 24px; }
  .cs-mark .m2 { font-size: 15px; }
  .cs-mark .m3 { font-size: 20px; }

  /* Four buttons on one 350px line do not fit. Let them wrap. */
  .cs-foot { width: 100%; flex-wrap: wrap; justify-content: center; }
  .cs-foot .cs-btn { flex: 1 1 96px; min-width: 0; }
  .cs-foot .spacer { display: none; }
}

/* ---------------------------------------------------------------------------
   Make Character

   The client's creation screen: the character on the left between job arrows
   with a hair arrow above, the six stats as a hexagon with a triangle pointing
   outward from each vertex, the numbers top right, name bottom left and the
   wordmark bottom right.
   --------------------------------------------------------------------------- */
.mk-scene {
  height: 100%; overflow-y: auto; box-sizing: border-box;
  display: flex; align-items: safe center; justify-content: safe center;
  padding: 24px 20px;
  background:
    radial-gradient(ellipse 900px 460px at 50% 8%, rgba(255,255,255,0.95) 0%, rgba(255,255,255,0) 72%),
    radial-gradient(ellipse 1200px 700px at 50% 120%, #d7e0f4 0%, rgba(215,224,244,0) 70%),
    linear-gradient(175deg, #f7f9ff 0%, #e9eefb 55%, #dde5f6 100%);
}
.win.mk-win { width: 1020px; max-width: 100%; }
.mk-win .win-title { font-size: 13px; padding: 6px 10px; }

.mk-body {
  display: grid;
  grid-template-columns: 300px 1fr 260px;
  grid-template-rows: auto auto;
  gap: 10px 18px;
  padding: 20px 24px 8px;
}

/* --- left column ----------------------------------------------------------- */
.mk-left { grid-column: 1; grid-row: 1; display: flex; flex-direction: column; align-items: center; }
.mk-sprrow { display: flex; align-items: center; gap: 6px; }
.mk-spr {
  display: block; width: 190px; height: 250px;
  image-rendering: pixelated;
}
.mk-job {
  margin-top: 4px;
  font: 700 15px/1 Tahoma, Verdana, sans-serif;
  color: #2f4e88; text-shadow: 0 1px 0 #fff;
}
/* The job picker, spelled out. See the note in charmake.ts: the arrows alone
   were not discoverable, so every job is on the screen with its name on it. */
.mk-jobcap {
  margin: 10px 0 5px;
  font: 700 9.5px/1 Tahoma, sans-serif; letter-spacing: 0.09em;
  text-transform: uppercase; color: #7387a8;
}
.mk-jobs {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 4px; width: 100%; max-width: 250px;
}
button.mk-jobb {
  padding: 6px 4px; border: 1px solid #b6c6e0; border-radius: 6px;
  background: linear-gradient(180deg, #ffffff, #eaf0fa);
  font: 700 11px/1.1 Tahoma, sans-serif; color: #33507f; cursor: pointer;
}
button.mk-jobb:hover { background: #e6eefb; border-color: #8fa9d4; }
button.mk-jobb.on {
  background: linear-gradient(180deg, #dff0e2, #bfe3c6);
  border-color: #5fa96e; color: #1e5b2c;
  box-shadow: inset 0 0 0 1px #a6dbb0;
}

button.mk-tri {
  border: 0; padding: 0; cursor: pointer;
  width: 26px; height: 22px; flex: none;
  background: linear-gradient(180deg, #e3ecfc 0%, #a9bfe6 55%, #7f9ad2 100%);
  clip-path: polygon(50% 0%, 100% 100%, 0% 100%);
  filter: drop-shadow(0 1px 1px rgba(90,110,150,0.35));
}
button.mk-tri:hover { background: linear-gradient(180deg, #ffffff 0%, #b9cdf3 55%, #6a88c8 100%); }
button.mk-tri.up { margin-bottom: 4px; }
button.mk-tri.left { transform: rotate(-90deg); }
button.mk-tri.right { transform: rotate(90deg); }

/* --- hexagon --------------------------------------------------------------- */
.mk-mid { grid-column: 2; grid-row: 1; display: flex; justify-content: center; align-items: center; }
.mk-radar { position: relative; width: 300px; height: 300px; }
.mk-radar canvas { display: block; }

/* Clip-path rather than a glyph: a rotated ▲ character reads as a blob at this
   size, and the direction it points is the whole point of the control. */
button.mk-arrow {
  position: absolute;
  width: 30px; height: 25px;
  border: 0; padding: 0; cursor: pointer;
  background: linear-gradient(180deg, #e3ecfc 0%, #a9bfe6 55%, #7f9ad2 100%);
  clip-path: polygon(50% 0%, 100% 100%, 0% 100%);
  filter: drop-shadow(0 1px 1px rgba(90,110,150,0.35));
}
button.mk-arrow:hover {
  background: linear-gradient(180deg, #ffffff 0%, #b9cdf3 55%, #6a88c8 100%);
}
button.mk-arrow:active { filter: none; }
.mk-alab {
  position: absolute;
  transform: translate(-50%, -50%);
  font: 700 13px/1 Tahoma, Verdana, sans-serif;
  color: #43537d; text-shadow: 0 1px 0 #fff;
  white-space: nowrap;
}

/* --- stat table ------------------------------------------------------------ */
.mk-right { grid-column: 3; grid-row: 1; }
.mk-table {
  border: 1px solid var(--edge);
  border-radius: 3px; overflow: hidden;
  background: var(--face);
}
.mk-trow { display: grid; grid-template-columns: 88px 1fr auto auto; align-items: center; font-size: 14px; }
.mk-trow:nth-child(odd) .mk-tk { background: #dfe6f6; }
.mk-trow:nth-child(even) .mk-tk { background: #eaeef9; }
.mk-tk {
  padding: 5px 10px; font-weight: 700; color: #2c3c60;
  border-right: 1px solid var(--edge-soft);
}
.mk-tv { padding: 5px 12px; color: var(--txt); }
.mk-minus {
  position: absolute; width: 20px; height: 20px; padding: 0;
  font: 700 14px/18px Tahoma, Verdana, sans-serif; color: #45558a;
  background: rgba(255, 255, 255, 0.86);
  border: 1px solid #8fa4cd; border-radius: 50%;
  cursor: pointer;
}
.mk-minus:hover:not(:disabled) { background: #fff; border-color: #45558a; color: #23315c; }
.mk-minus:active:not(:disabled) { background: #dbe3f3; }
.mk-minus:disabled { opacity: 0.25; cursor: default; }
.mk-arrow:disabled { opacity: 0.3; cursor: default; }

.mk-step {
  width: 26px; height: 24px; margin: 2px 3px 2px 0;
  font: 700 15px/1 Tahoma, Verdana, sans-serif; color: #2f4e88;
  background: linear-gradient(180deg, #fdfefe, #dbe3f3);
  border: 1px solid var(--edge); border-radius: 3px; cursor: pointer;
}
.mk-step:hover:not(:disabled) { background: linear-gradient(180deg, #ffffff, #e7edfa); border-color: #5f7bb6; }
.mk-step:active:not(:disabled) { background: #ccd6ec; }
.mk-step:disabled { opacity: 0.35; cursor: default; }
.mk-points {
  margin-top: 8px; font: 700 13px/1 Tahoma, Verdana, sans-serif; color: #2f4e88;
}
.mk-reset {
  margin-top: 7px; padding: 5px 12px; cursor: pointer;
  font: 12px/1 Tahoma, Verdana, sans-serif; color: #2f4e88;
  background: linear-gradient(180deg, #fdfefe, #dde5f4);
  border: 1px solid var(--edge); border-radius: 3px;
}
.mk-reset:hover { border-color: #5f7bb6; }
.mk-err {
  margin-left: 10px;
  font: 700 12px/1.3 Tahoma, Verdana, sans-serif; color: #b03a3a;
}
.mk-desc { margin-top: 8px; font-size: 12px; line-height: 1.5; color: var(--dim); }

/* --- name field ------------------------------------------------------------ */
.mk-name {
  grid-column: 1; grid-row: 2;
  display: flex; align-items: center; gap: 10px;
}
.mk-nlab { font: 700 16px/1 Tahoma, Verdana, sans-serif; color: #2f4e88; text-shadow: 0 1px 0 #fff; }
.mk-input {
  flex: 1; min-width: 0;
  font: 14px/1 Tahoma, Verdana, sans-serif;
  padding: 7px 9px;
  color: var(--txt);
  background: #fff;
  border: 1px solid var(--edge);
  border-radius: 2px;
  box-shadow: inset 0 1px 2px rgba(140,152,185,0.35);
}
.mk-input:focus { outline: none; border-color: #5f7bb6; box-shadow: inset 0 1px 2px rgba(140,152,185,0.35), 0 0 0 2px rgba(140,172,226,0.45); }

/* --- wordmark and footer --------------------------------------------------- */
.mk-mark {
  grid-column: 2 / span 2; grid-row: 2;
  text-align: right; line-height: 0.94;
  font-family: Georgia, "Times New Roman", serif;
  color: #3a63a8;
  text-shadow: 0 1px 0 #fff, 0 2px 3px rgba(90,110,150,0.28);
}
.mk-mark .m1 { font-size: 40px; font-style: italic; font-weight: 700; }
.mk-mark .m2 { font-size: 22px; font-style: italic; color: #6b83b6; margin-left: 6px; }
.mk-mark .m3 { display: block; font-size: 33px; font-style: italic; font-weight: 700; }

.mk-foot {
  display: flex; align-items: center; justify-content: flex-end; gap: 10px;
  padding: 6px 24px 18px;
}
.mk-fee { font-size: 12px; color: var(--dim); margin-right: auto; }
/* The one button on this screen that costs money says so on its face and is
   built to be pressed; cancel stays quiet beside it. */
.mk-foot .cs-btn.primary { min-width: 176px; font-weight: 800; letter-spacing: 0.2px; }
.mk-foot .cs-btn { min-width: 110px; }

@media (max-width: 960px) {
  .mk-body { grid-template-columns: 1fr; grid-template-rows: auto auto auto auto auto; }
  .mk-left, .mk-mid, .mk-right, .mk-name, .mk-mark { grid-column: 1; grid-row: auto; }
  .mk-mark { text-align: center; }
}
@media (max-width: 620px) {
  /* Stacked, the wordmark landed between the name field and the buttons — in
     the middle of the form rather than over it. It reads as the screen's
     title, so it goes first, the same way it does on the select screen. */
  .mk-scene { padding: 12px 8px; }
  .mk-body { padding: 12px 10px 6px; gap: 8px; }
  .mk-mark { order: -1; text-align: center; }
  .mk-mark .m1 { font-size: 24px; }
  .mk-mark .m2 { font-size: 15px; }
  .mk-mark .m3 { font-size: 20px; }
  /* A 300px hexagon is most of a 374px screen — but its step buttons and axis
     labels are absolutely positioned against that 300px box by the code that
     draws it, so shrinking the BOX scattered them across the stat table.
     A transform scales the whole assembly, overlays included, and the negative
     margin gives back the height it no longer occupies. */
  .mk-radar { transform: scale(0.7); transform-origin: top center; margin: 0 auto -90px; }
  .mk-spr { width: 150px; height: 200px; }
  .mk-name { flex-wrap: wrap; }
  /* Stacked, and in the order the decision is made: what it costs, the button
     that spends it, then the way out. */
  .mk-foot {
    flex-direction: column; align-items: stretch; gap: 8px; padding: 6px 12px 16px;
  }
  .mk-fee { margin: 0 0 2px; text-align: center; }
  .mk-foot .cs-btn { width: 100%; min-width: 0; padding: 12px; font-size: 14px; }
  .mk-foot .cs-btn.primary { font-size: 15px; }
}

/* ---------------------------------------------------------------------------
   Party tab — the My Characters slots, at panel size
   --------------------------------------------------------------------------- */
.pty-stage { display: flex; justify-content: center; padding: 6px 0 12px; }
.cs-cards.sm { gap: 12px; }
.cs-cards.sm .cs-card { width: 150px; padding: 6px 6px 0; }
.cs-cards.sm .cs-canvas { width: 138px; height: 188px; }
.cs-cards.sm .cs-plate { margin: 6px -6px 0; padding: 5px 6px; font-size: 12px; }
.cs-cards.sm .cs-tab { width: 92px; height: 22px; font-size: 12px; }

/* --- the whole roster in one row ------------------------------------------
   Party, bench and the maker card are the same kind of thing — a character
   slot — so they sit in one wrapping row at card size rather than in two
   stacked sections a scroll apart. */
.roster-row { flex-wrap: wrap; justify-content: flex-start; gap: 8px; margin: 6px 0 10px; }
.cs-cards.mini .cs-card { width: 108px; padding: 4px 4px 0; cursor: pointer; }
.cs-cards.mini .cs-canvas { width: 100px; height: 136px; }
.cs-cards.mini .cs-plate { margin: 4px -4px 0; padding: 4px; font-size: 11px; }
.cs-cards.mini .cs-tab { width: 74px; height: 18px; font-size: 10px; }
.cs-cards.mini .cs-card:hover { border-color: #5f7bb6; box-shadow: 0 0 0 2px rgba(140,172,226,0.5); }

.pty-lower {
  display: flex; align-items: flex-start; justify-content: flex-start;
  gap: 16px; flex-wrap: wrap;
}
.pty-line { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.pty-line .pty-lab {
  width: 74px; flex: none;
  font: 700 10px/1 Tahoma, Verdana, sans-serif;
  letter-spacing: 0.6px; text-transform: uppercase; color: var(--dim);
  cursor: help;
}

/* --- the bench: everyone who is not fielded -------------------------------- */
.bench { margin-top: 12px; }
.bench-cards {
  margin: 8px 0 6px;
  flex-wrap: wrap; justify-content: flex-start;
  gap: 10px;
}
.bench-cards .cs-card { width: 120px; padding: 5px 5px 0; cursor: pointer; }
.bench-cards .cs-canvas { width: 110px; height: 150px; }
.bench-cards .cs-tab { width: 84px; height: 20px; font-size: 11px; }
.bench-cards .cs-card:hover { border-color: #5f7bb6; box-shadow: 0 0 0 2px rgba(140,172,226,0.5); }
.pty-ctl { min-width: 260px; display: flex; flex-direction: column; gap: 6px; }
.pty-lab {
  font: 700 11px/1 Tahoma, Verdana, sans-serif;
  letter-spacing: 0.4px; text-transform: uppercase; color: var(--dim);
  margin-top: 4px;
}
.pty-recruit { max-width: 420px; }

/* --- save / sync status ---------------------------------------------------- */
.sync-line {
  display: flex; align-items: center; gap: 7px;
  font-weight: 700; color: var(--red);
}
.sync-line.on { color: var(--green); }
.sync-dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--red); box-shadow: 0 0 0 1px rgba(0,0,0,0.15);
}
.sync-line.on .sync-dot { background: #35c46a; }
.sync-acct {
  margin-top: 4px;
  font: 11px/1 "DejaVu Sans Mono", monospace; color: var(--dim);
}

/* button.ro sets a font shorthand, so the login button needs the same
   specificity to grow rather than a bare font-size. */
button.ro.login-btn {
  font: 700 16px/1 Tahoma, Verdana, sans-serif;
  padding: 15px;
}

/* a card that is in the party wears a numbered tab and a warmer edge */
.cs-tab.party {
  background: linear-gradient(180deg, #fff6d8 0%, #ffe49b 40%, #dcb659 100%);
}
.cs-card.fielded { border-color: #c79a37; }
.cs-count .p {
  display: block; margin-top: 4px;
  font: 700 12px/1 Tahoma, Verdana, sans-serif; color: #8a6a12;
}

/* --- title-bar music toggle ------------------------------------------------ */
button.bar-mute {
  width: 22px; height: 18px; flex: none;
  margin-left: 8px; padding: 0;
  font: 13px/1 Tahoma, sans-serif;
  color: var(--title-txt);
  background: rgba(255, 255, 255, 0.55);
  border: 1px solid rgba(111, 127, 168, 0.55);
  border-radius: 3px;
  cursor: pointer;
}
button.bar-mute:hover { background: #fff; }
button.bar-mute.off { color: #97a2bd; background: rgba(255, 255, 255, 0.25); }

.vol-row { display: flex; align-items: center; gap: 8px; padding: 2px 0 6px 46px; }
.vol-row .vol { flex: 1; accent-color: var(--accent); }
.vol-row .vol:disabled { opacity: 0.4; }

/* --- wallet picker ---------------------------------------------------------- */
.wallet-list { display: flex; flex-direction: column; gap: 8px; margin: 4px 0 2px; }
.wallet-wait { color: var(--dim); font-size: 13px; padding: 14px 0; }

button.ro.wallet-btn {
  display: flex; align-items: center; gap: 12px;
  width: 100%; padding: 11px 14px;
  font: 700 14px/1 Tahoma, Verdana, sans-serif;
  text-align: left;
}
.wallet-icon {
  width: 28px; height: 28px; flex: none;
  display: flex; align-items: center; justify-content: center;
  border-radius: 6px; overflow: hidden;
  background: linear-gradient(180deg, #eef3ff, #cfdaf2);
  border: 1px solid var(--edge-soft);
  font: 700 14px/1 Tahoma, sans-serif; color: #46598a;
}
.wallet-icon img { width: 100%; height: 100%; object-fit: contain; display: block; }
.wallet-name { flex: 1; }
.wallet-go { color: var(--dim); font-weight: 400; font-size: 18px; }

.wallet-none { padding: 10px 0; color: var(--dim); font-size: 13px; line-height: 1.6; }
.wallet-links { display: flex; gap: 12px; justify-content: center; margin: 8px 0 6px; }
.wallet-links a { color: var(--link); font-weight: 700; }

/* ---------------------------------------------------------------------------
   Party strip — one compact tile per member, laid out along the dock
   --------------------------------------------------------------------------- */
/* A grid, not a row: an empty party slot keeps its column, so two members are
   the same width as three and the HUD stays aligned with them. */
/* Three across when the party sits under the field, one above the other when it
   sits beside it. The container decides; the card does not need to know. */
.mem-row {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 8px; flex: 1; min-width: 0;
}
.bar-body > .bar-dock .mem-row {
  grid-template-columns: minmax(0, 1fr); gap: 6px;
}
/* Denser in the column: the wide-strip padding wasted a third of the height. */
.bar-dock .mem { padding: 4px 7px 6px; gap: 7px; }
@media (max-width: 900px) {
  .bar-body > .bar-dock .mem-row { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 620px) {
  /* Three across on a phone is three cards none of which fit their own text —
     the name, the job and both bars were all clipped. One at a time. */
  .mem-row,
  .bar-body > .bar-dock .mem-row { grid-template-columns: minmax(0, 1fr); }
}

.mem {
  position: relative; overflow: hidden;
  display: flex; gap: 8px; align-items: center;
  flex: 1 1 0; min-width: 0;
  padding: 5px 8px 8px;
  border: 1px solid var(--edge-soft);
  border-radius: 5px;
  background: linear-gradient(180deg, #ffffff 0%, var(--face-2) 70%, #e9edf8 100%);
  box-shadow: 0 1px 0 rgba(120, 135, 170, 0.16);
}
/* class stripe down the leading edge */
.mem::before {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 3px;
  background: var(--job, #9aaed3);
}
.mem.j-swordman, .mem.j-knight   { --job: #c2603a; }
.mem.j-mage,     .mem.j-wizard   { --job: #4f7fd0; }
.mem.j-archer,   .mem.j-hunter   { --job: #4a9a5c; }
.mem.j-acolyte,  .mem.j-priest   { --job: #d0a63a; }
.mem.lead { border-color: var(--edge); }
.mem.down { opacity: 0.5; }
.mem.hurt {
  border-color: #d06a6a;
  animation: memPulse 1.1s ease-in-out infinite;
}
@keyframes memPulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(200, 60, 60, 0.0); }
  50%      { box-shadow: 0 0 0 2px rgba(200, 60, 60, 0.35); }
}

.mem-av {
  position: relative; flex: none;
  width: 46px; height: 46px;
  border: 1px solid var(--slot-edge);
  border-radius: 4px;
  background:
    radial-gradient(ellipse 36px 26px at 50% 100%, #e8eefb 0%, rgba(232,238,251,0) 70%),
    linear-gradient(180deg, #ffffff, #eef2fb);
  box-shadow: inset 0 1px 2px rgba(140, 152, 185, 0.3);
  overflow: hidden;
}
.mem-canvas { display: block; image-rendering: pixelated; width: 46px; height: 46px; }
.mem-lv {
  position: absolute; right: -1px; bottom: -1px;
  min-width: 17px; padding: 0 3px;
  font: 700 10px/13px Tahoma, Verdana, sans-serif; text-align: center;
  color: #fff; background: linear-gradient(180deg, #6a83bd, #3d5490);
  border: 1px solid #2c3f72; border-radius: 3px 0 3px 0;
  text-shadow: 0 1px 0 rgba(0, 0, 0, 0.4);
}
.mem-crown {
  position: absolute; left: 1px; top: 0;
  font: 11px/11px Tahoma, sans-serif; color: #f0c040;
  text-shadow: 0 1px 1px rgba(0, 0, 0, 0.5);
}
.mem-dead {
  /* Sits across the middle of the portrait, not along the bottom edge, where it
     ran straight into the level badge and read as "DEA 1". */
  position: absolute; inset: auto 0 auto 0; top: 50%;
  transform: translateY(-50%);
  font: 700 9px/1.7 Tahoma, sans-serif; letter-spacing: 1px; text-align: center;
  color: #fff; background: rgba(163, 32, 32, 0.88);
  box-shadow: 0 0 0 1px rgba(0,0,0,0.35);
}

.mem-info { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.mem-head {
  display: flex; align-items: baseline; gap: 5px;
  font-size: 11px; line-height: 1.1;
}
.mem-head .spacer { flex: 1; }
.mem-head .nm {
  font-weight: 700; font-size: 12px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.mem-head .jb { color: var(--link); font-size: 10px; }
.mem-head .lv { font: 700 10px/1 Tahoma, sans-serif; color: var(--dim); }
.mem-head .pip {
  font: 700 9px/1 Tahoma, sans-serif; color: #7a5400;
  background: linear-gradient(180deg, #ffe9a8, #ffd166);
  border: 1px solid #d8a93c; border-radius: 8px;
  padding: 1px 5px;
}
.mem-head .pip.skill {
  color: #2b4a86;
  background: linear-gradient(180deg, #d8e6ff, #a8c4f0);
  border-color: #7d9bd0;
}

.mem .bar-bars { display: flex; flex-direction: column; gap: 3px; }
.mem .bar2 {
  height: 12px; border-radius: 6px;
  border-color: #8d97b3;
  background: #dfe3ee;
  box-shadow: inset 0 1px 2px rgba(90, 105, 140, 0.45);
}
/* a glass highlight across the top half sells it as a gauge */
.mem .bar2-fill { position: relative; border-radius: 6px 0 0 6px; }
.mem .bar2-fill::after {
  content: ""; position: absolute; inset: 0 0 45% 0;
  background: linear-gradient(180deg, rgba(255,255,255,0.55), rgba(255,255,255,0));
  border-radius: 6px 0 0 0;
}
.mem .bar2-label { font-size: 9px; line-height: 12px; letter-spacing: 0.2px; }

/* EXP rail along the bottom edge: base from the left, job from the right */
.mem-rail {
  position: absolute; left: 0; right: 0; bottom: 0; height: 4px;
  display: flex; justify-content: space-between;
  background: #dfe3ee;
  border-top: 1px solid rgba(140, 152, 185, 0.4);
}
.rail-base {
  height: 100%; max-width: 50%;
  background: linear-gradient(180deg, var(--exp-a), var(--exp-b));
}
.rail-job {
  height: 100%; max-width: 50%;
  background: linear-gradient(180deg, var(--job-a), var(--job-b));
}

/* ---------------------------------------------------------------------------
   Panel tabs, in two groups
   --------------------------------------------------------------------------- */

/* --- character picker on the scoped tabs ------------------------------------ */
.char-select { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 8px; }
button.cpick {
  position: relative;
  display: flex; align-items: center; gap: 7px;
  padding: 4px 12px 4px 4px;
  font: 11px/1.2 Tahoma, Verdana, sans-serif;
  color: var(--txt); text-align: left;
  border: 1px solid var(--edge-soft);
  border-radius: 5px;
  background: linear-gradient(180deg, #ffffff, var(--face-2));
  cursor: pointer;
}
button.cpick::before {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 3px;
  border-radius: 4px 0 0 4px;
  background: var(--job, #9aaed3);
}
button.cpick.j-swordman, button.cpick.j-knight { --job: #c2603a; }
button.cpick.j-mage,     button.cpick.j-wizard { --job: #4f7fd0; }
button.cpick.j-archer,   button.cpick.j-hunter { --job: #4a9a5c; }
button.cpick.j-acolyte,  button.cpick.j-priest { --job: #d0a63a; }
button.cpick:hover { background: linear-gradient(180deg, #ffffff, #eef3ff); }
/* The selected character is the subject of the whole tab — it should be
   obvious at a glance which one you are editing, not a two-pixel border. */
button.cpick.active {
  border-color: #3f63ad;
  box-shadow: 0 0 0 3px rgba(95, 138, 214, 0.55), 0 2px 8px rgba(60, 90, 150, 0.28);
  background: linear-gradient(180deg, #ffffff, #d9e5fb);
  transform: translateY(-1px);
}
button.cpick.active::before { width: 5px; }
button.cpick.active .cp-name { color: #22346a; font-weight: 700; }
button.cpick.active .cp-av {
  border-color: #3f63ad;
  box-shadow: 0 0 0 1px rgba(95, 138, 214, 0.6);
}
/* a benched character being edited is still clearly the selected one */
button.cpick.benched.active { border-style: solid; opacity: 1; }
button.cpick.down { opacity: 0.5; }
.cp-av {
  width: 34px; height: 34px; flex: none; margin-left: 4px;
  border: 1px solid var(--slot-edge); border-radius: 3px;
  background: linear-gradient(180deg, #ffffff, #eef2fb);
  overflow: hidden;
}
.cp-av canvas { display: block; image-rendering: pixelated; }
.cp-txt { display: flex; flex-direction: column; gap: 1px; }
.cp-name { font-weight: 700; font-size: 12px; }
.cp-sub { font-size: 10px; color: var(--dim); }
/* party status: green fielded, red benched */
.cp-status {
  position: absolute; top: 3px; right: 4px;
  width: 8px; height: 8px; border-radius: 50%;
  background: linear-gradient(180deg, #8fe6a1, #2f9c4a);
  border: 1px solid #227a37;
  box-shadow: 0 0 4px rgba(60, 190, 100, 0.55);
}
.cp-status.out {
  background: linear-gradient(180deg, #ff9d9d, #c0392b);
  border-color: #93261a;
  box-shadow: none;
}
/* unspent points, alongside it */
.cp-dot {
  position: absolute; top: 3px; right: 15px;
  width: 7px; height: 7px; border-radius: 50%;
  background: linear-gradient(180deg, #ffe08a, #e0a92c);
  border: 1px solid #b3861f;
}

/* ---------------------------------------------------------------------------
   Status tab — hero banner, stat hexagon, combat chips, job progress
   --------------------------------------------------------------------------- */
.hero {
  display: flex; gap: 10px; align-items: stretch; flex-wrap: wrap;
  padding: 7px 10px; margin-bottom: 8px;
  border: 1px solid var(--edge-soft); border-radius: 5px;
  background: linear-gradient(180deg, #ffffff, #eef2fc);
  box-shadow: 0 1px 0 rgba(120,135,170,0.16);
}
.hero-av {
  width: 64px; height: 64px; flex: none;
  border: 1px solid var(--slot-edge); border-radius: 4px;
  background: linear-gradient(180deg, #ffffff, #e9eefb);
  box-shadow: inset 0 1px 3px rgba(140,152,185,0.35);
  overflow: hidden;
}
.hero-av canvas { display: block; image-rendering: pixelated; }
.hero-main { flex: 1 1 420px; min-width: 0; max-width: 620px; display: flex; flex-direction: column; gap: 4px; }
.hero-line { display: flex; align-items: baseline; gap: 8px; }
.hero-line .spacer { flex: 1; }
.hero-name { font: 700 16px/1 Tahoma, Verdana, sans-serif; }
.hero-job { color: var(--link); font-size: 12px; }
.hero-lv {
  font: 700 10px/1 Tahoma, sans-serif; color: var(--title-txt);
  background: linear-gradient(180deg, var(--title-a), var(--title-b));
  border: 1px solid var(--edge); border-radius: 9px; padding: 2px 8px;
}
.hero-bars { display: flex; flex-direction: column; gap: 3px; }
.hero-bars .bar2 { height: 13px; border-radius: 7px; }
.hero-bars .bar2-fill { border-radius: 7px 0 0 7px; }
.hero-bars .bar2-label { line-height: 13px; }
.hero-xp { display: flex; gap: 4px; }
.hero-xp .bar2 { flex: 1; height: 10px; }
.hero-xp .bar2-label { line-height: 10px; font-size: 8px; }

.pts-line { display: flex; gap: 5px; align-items: center; }
.pts {
  font: 700 10px/1 Tahoma, sans-serif; border-radius: 9px; padding: 2px 7px;
}
.pts.stat { color: #7a5400; background: #ffe9a8; border: 1px solid #d8a93c; }
.pts.skill { color: #2b4a86; background: #d8e6ff; border: 1px solid #7d9bd0; }

.stat-hex { position: relative; width: 168px; height: 168px; margin: auto; }
.stat-hex canvas { display: block; }
.hex-lab {
  position: absolute; transform: translate(-50%, -50%);
  font: 700 9px/1 Tahoma, sans-serif; color: #43537d;
  text-shadow: 0 1px 0 #fff; white-space: nowrap;
}

.stat-list { display: flex; flex-direction: column; gap: 1px; }
.stat-row {
  /* name | value | what the next point costs | the + button. The cost column
     is new; without it here the grid pushed the + onto a second row. */
  display: grid; grid-template-columns: 36px 1fr auto 22px;
  align-items: center; gap: 6px;
  padding: 2px 4px; border-radius: 3px;
}
.stat-row:nth-child(odd) { background: var(--face-3); }
.stat-name { font: 700 11px/1 Tahoma, sans-serif; color: var(--link); }
.stat-val { font: 700 13px/1 Tahoma, sans-serif; }
button.ro.raise {
  width: 20px; height: 20px; padding: 0;
  font: 700 13px/1 Tahoma, sans-serif; border-radius: 50%;
}

.combat-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 3px; }
.cstat {
  display: flex; align-items: baseline; gap: 6px;
  padding: 4px 7px; border-radius: 4px;
  background: var(--face-3);
  border: 1px solid rgba(140, 152, 185, 0.25);
  cursor: help;
}
/* Named cbt-* rather than cs-*: Character Select's stat plate already owns
   .cs-k / .cs-v, and the collision squashed its Name column into the Str
   column on the select screen. */
.cbt-k {
  font: 10px/1.2 Tahoma, sans-serif; color: var(--dim);
  text-transform: uppercase; letter-spacing: 0.3px;
}
.cbt-v {
  margin-left: auto;
  font: 700 12px/1.2 "DejaVu Sans Mono", Menlo, monospace; color: var(--txt);
  white-space: nowrap;
}

.job-chain { font: 700 11px/1.4 Tahoma, sans-serif; color: var(--link); }
.jobnext {
  margin-top: 8px; padding: 7px 8px;
  border: 1px solid var(--edge-soft); border-radius: 5px;
  background: linear-gradient(180deg, #ffffff, var(--face-2));
}
.jobnext.ready { border-color: #7fae7f; box-shadow: 0 0 0 1px rgba(110, 170, 110, 0.35); }
.jobnext h4 { margin: 0; font-size: 13px; }
.jn-ok {
  font: 700 9px/1 Tahoma, sans-serif; color: #1d6b34;
  background: #ddf3e0; border: 1px solid #8cc194; border-radius: 8px; padding: 2px 7px;
}
.jn-lock {
  font: 700 9px/1 Tahoma, sans-serif; color: var(--dim);
  background: var(--face-3); border: 1px solid var(--edge-soft); border-radius: 8px; padding: 2px 7px;
}
.reqrow { display: flex; align-items: center; gap: 6px; margin: 4px 0; }
.req-k { font: 700 10px/1 Tahoma, sans-serif; color: var(--dim); width: 30px; flex: none; }
.reqrow .bar2 { flex: 1; height: 11px; border-radius: 6px; }
.reqrow .bar2-label { line-height: 11px; }

/* --- game logo -------------------------------------------------------------- */
.login-logo { display: flex; justify-content: center; margin: -6px 0 2px; }
.login-logo img {
  width: 260px; max-width: 100%; height: auto; display: block;
  filter: drop-shadow(0 4px 10px rgba(70, 95, 150, 0.28));
}
.cs-logo { display: flex; justify-content: center; margin-bottom: 2px; }
.cs-logo img {
  width: 190px; height: auto; display: block;
  filter: drop-shadow(0 3px 8px rgba(70, 95, 150, 0.25));
}

/* --- "what fits here" picker under the paper doll --------------------------- */
.slot-pick {
  margin-top: 8px; padding: 7px 8px;
  border: 1px solid var(--edge-soft); border-radius: 5px;
  background: linear-gradient(180deg, #ffffff, var(--face-2));
}
.slot-pick h4 { margin: 0 0 4px; font-size: 12px; }
.slot-pick .item-grid { max-height: 132px; overflow-y: auto; }

/* ---------------------------------------------------------------------------
   Equipment window — the client's General / Special tabs and Status block
   --------------------------------------------------------------------------- */
.eq-tabs { display: flex; gap: 4px; margin-bottom: 8px; }
button.eq-tab {
  flex: 1;
  padding: 6px 10px;
  font: 700 12px/1 Tahoma, Verdana, sans-serif;
  color: var(--dim);
  border: 1px solid var(--edge-soft);
  border-radius: 5px 5px 0 0;
  background: linear-gradient(180deg, var(--face-3), #e2e7f4);
  cursor: pointer;
}
button.eq-tab.active {
  color: var(--title-txt);
  border-color: var(--edge);
  background: linear-gradient(180deg, var(--title-hi), var(--title-a) 45%, var(--title-b));
}
.eq-empty { padding: 26px 12px; text-align: center; color: var(--dim); font-size: 12px; }

.slot-ghost {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  font: 9px/1 Tahoma, Verdana, sans-serif;
  color: rgba(120, 133, 165, 0.55);
  letter-spacing: 0; text-align: center;
  padding: 0 2px; overflow: hidden;
  pointer-events: none;
}
.doll-cell .slot { position: relative; }
.doll-cell .slot { width: 44px; height: 44px; }
.doll-cell .slot.empty {
  border-radius: 14px;
  background: linear-gradient(180deg, #f2f5fd, #e6ebf8);
  box-shadow: inset 0 2px 3px rgba(140, 152, 185, 0.35);
}
.doll-cell .slot-label {
  max-width: 74px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.eq-status {
  margin-top: 10px; padding: 8px 9px;
  border: 1px solid var(--edge-soft); border-radius: 5px;
  background: linear-gradient(180deg, #ffffff, var(--face-2));
}
.eq-status-cap {
  font: 700 10px/1 Tahoma, Verdana, sans-serif;
  letter-spacing: 0.7px; text-transform: uppercase; color: var(--dim);
  margin-bottom: 5px;
}
.eq-status-cols { display: grid; grid-template-columns: 1fr 1fr; gap: 4px 16px; }
.eqs-col { display: flex; flex-direction: column; gap: 1px; }
.eqs-row {
  display: grid; grid-template-columns: 1fr auto auto;
  align-items: center; gap: 6px;
  padding: 2px 5px; border-radius: 3px;
}
.eqs-row.plain { grid-template-columns: 1fr auto; }
.eqs-row:nth-child(odd) { background: var(--face-3); }
.eqs-k { font: 11px/1 Tahoma, sans-serif; color: var(--dim); }
.eqs-v { font: 700 12px/1 "DejaVu Sans Mono", Menlo, monospace; }

/* ---------------------------------------------------------------------------
   Map tab — region chip bar + one compact row per map
   --------------------------------------------------------------------------- */
.map-regions {
  position: sticky; top: 0; z-index: 3;
  display: flex; gap: 4px; flex-wrap: wrap;
  padding: 6px 0; margin-bottom: 6px;
  background: linear-gradient(180deg, var(--face, #eef2fb) 84%, rgba(238, 242, 251, 0));
}
.map-regions .chip.locked { opacity: 0.5; cursor: default; }
.map-row {
  display: flex; align-items: center; gap: 8px;
  padding: 5px 8px; margin-bottom: 3px;
  border: 1px solid var(--edge-soft); border-left: 3px solid #9aaed3;
  border-radius: 4px;
  background: linear-gradient(180deg, #ffffff, var(--face-2));
}
.map-row.current {
  border-left-color: #2f8a4a;
  box-shadow: 0 0 0 2px rgba(120, 190, 140, 0.35);
  background: linear-gradient(180deg, #ffffff, #eaf5ec);
}
.map-row.locked { opacity: 0.55; }
.map-row-info { flex: 1; min-width: 0; }
.map-row-head { display: flex; align-items: baseline; gap: 6px; flex-wrap: wrap; }
.map-row-head strong { font: 700 12px/1.2 Tahoma, Verdana, sans-serif; }
.map-row-mobs {
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%;
}
.map-row-act { flex: none; display: flex; align-items: center; gap: 5px; }
.map-here { font: 700 10px/1 Tahoma, sans-serif; color: #1d6b34; white-space: nowrap; }
.mvp-tag {
  font: 700 9px/1 Tahoma, sans-serif; color: #8a3d3d;
  border: 1px solid #d9b2b2; border-radius: 8px; padding: 2px 6px;
  background: linear-gradient(180deg, #fff3f3, #fbe3e3);
  white-space: nowrap;
}

/* --- active party buffs on the Status header -------------------------------- */
.buff-row { display: flex; gap: 5px; flex-wrap: wrap; margin-top: 3px; }
.buffchip {
  display: flex; align-items: center; gap: 4px;
  padding: 2px 7px 2px 3px;
  border: 1px solid #b7c9e6; border-radius: 10px;
  background: linear-gradient(180deg, #f2f7ff, #dfe9fa);
}
.buffchip canvas {
  width: 14px; height: 14px; display: block; image-rendering: pixelated;
}
.bc-n { font: 700 10px/1 Tahoma, Verdana, sans-serif; color: #2b4a86; }
.bc-t { font: 9px/1 "DejaVu Sans Mono", monospace; color: var(--dim); }

/* ---------------------------------------------------------------------------
   Refine tab, and the "can equip" column beside the doll
   --------------------------------------------------------------------------- */
.rf-row {
  display: flex; align-items: center; gap: 8px;
  padding: 4px 6px; margin-bottom: 3px;
  border: 1px solid var(--edge-soft); border-left-width: 3px; border-radius: 3px;
  background: linear-gradient(180deg, #ffffff, var(--face-2));
}
.rf-row.r-common    { border-left-color: #9aa6bf; }
.rf-row.r-uncommon  { border-left-color: #4f9b5a; }
.rf-row.r-rare      { border-left-color: #3f74c4; }
.rf-row.r-epic      { border-left-color: #8a55c8; }
.rf-row.r-legendary { border-left-color: #d9a52a; }
.rf-ic { width: 48px; height: 48px; flex: none; display: flex; align-items: center; justify-content: center; }
.rf-ic canvas { image-rendering: pixelated; }
.rf-txt { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.rf-name { font-size: 12px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rf-name .rf { color: #b8860b; font-weight: 700; }
.rf-sub { font-size: 10px; color: var(--dim); }
.rf-cost { font-size: 10px; color: var(--dim); white-space: nowrap; }
.rf-max { font: 700 10px/1 Tahoma, sans-serif; color: #b8860b; letter-spacing: 0.5px; }

/* One row per slot, sized to what is in it.
 *
 * These reuse .item-grid, which carries min-height:120px so the INVENTORY has a
 * stable drop area that does not jump about as it fills. Here each group holds
 * one or two things, so that floor was reserving 120px of empty space per slot
 * — a Mage with a rod and a shirt got a screen and a half of nothing between
 * two icons. */
.wear-group { margin-bottom: 8px; }
.wear-group .item-grid { min-height: 0; padding: 2px; }
.wear-cap {
  font: 700 9px/1 Tahoma, Verdana, sans-serif;
  letter-spacing: 0.7px; text-transform: uppercase; color: var(--dim);
  margin: 0 0 4px 2px;
}

/* ---------------------------------------------------------------------------
   Item tooltip — hover with a pointer, tap without one
   --------------------------------------------------------------------------- */
.tip {
  position: fixed; z-index: 60; pointer-events: none;
  max-width: 300px;
  background: linear-gradient(180deg, #ffffff, var(--face-2));
  border: 1px solid var(--edge);
  border-radius: 4px;
  box-shadow: 0 6px 22px rgba(60, 76, 110, 0.32), 0 0 0 1px rgba(255,255,255,0.6) inset;
  padding: 8px 10px 7px;
  font: 12px/1.45 Tahoma, Verdana, sans-serif; color: var(--txt);
}
.tip-body { display: flex; flex-direction: column; gap: 6px; }
.tip-head { display: flex; align-items: center; gap: 8px; }
.tip-ht { min-width: 0; }
.tip-name { font-weight: 700; font-size: 13px; line-height: 1.2; }
.tip-name .rf { color: #b8860b; }
.tip-sub { font-size: 10px; color: var(--dim); letter-spacing: 0.3px; text-transform: uppercase; }
/* the name takes the rarity colour, the way a loot line does */
.tip-body.r-uncommon  .tip-name { color: #2f7a3c; }
.tip-body.r-rare      .tip-name { color: #2c5aa8; }
.tip-body.r-epic      .tip-name { color: #6c3fa8; }
.tip-body.r-legendary .tip-name { color: #a8761a; }
.tip-body.r-uncommon  { border-left: 3px solid #4f9b5a; padding-left: 7px; margin-left: -10px; }
.tip-body.r-rare      { border-left: 3px solid #3f74c4; padding-left: 7px; margin-left: -10px; }
.tip-body.r-epic      { border-left: 3px solid #8a55c8; padding-left: 7px; margin-left: -10px; }
.tip-body.r-legendary { border-left: 3px solid #d9a52a; padding-left: 7px; margin-left: -10px; }

.tip-stats { display: grid; grid-template-columns: 1fr 1fr; gap: 1px 12px; }
.tip-row { display: flex; justify-content: space-between; gap: 8px; font-size: 11px; }
.tip-row .k { color: var(--dim); }
.tip-row .v { font-weight: 700; }
.tip-eff {
  font-size: 11px; color: #2f5a34;
  background: rgba(90, 170, 110, 0.10);
  border: 1px solid rgba(90, 170, 110, 0.35); border-radius: 3px;
  padding: 4px 6px;
}
.tip-fits { font-size: 10px; color: var(--dim); }
.tip-foot {
  display: flex; align-items: center; gap: 6px;
  border-top: 1px solid var(--edge-soft); padding-top: 4px;
  font-size: 10px; color: var(--dim);
}
.tip-foot .spacer { flex: 1; }

/* a roster member who is not in the party, on the character picker */
button.cpick.benched { opacity: 0.86; border-style: dashed; }
button.cpick.benched:hover { opacity: 1; }

/* --- Equipment tab: the doll stays put --------------------------------------
   The right column can run to forty items; the left is what you are dressing.
   Scrolling the list should not take the character off screen. */
.eq-grid { align-items: start; }
.eq-grid > .card:first-child {
  position: sticky; top: 0;
  align-self: start;
  z-index: 2;
}
@media (max-height: 640px) {
  .eq-grid > .card:first-child { position: static; }
}

/* --- auto-cast on/off ------------------------------------------------------ */
.prio-row.off { opacity: 0.55; }
.prio-sw {
  flex: none; min-width: 34px; padding: 2px 5px;
  font: 700 9px/1.5 Tahoma, Verdana, sans-serif; letter-spacing: 0.5px;
  color: #6b7285; background: linear-gradient(180deg, #f4f6fb, #e3e8f3);
  border: 1px solid var(--edge); border-radius: 3px; cursor: pointer;
}
.prio-sw.on {
  color: #1f5b2b; background: linear-gradient(180deg, #e7f8ea, #c9edd1);
  border-color: #64a874;
}
.prio-sw:hover { filter: brightness(1.05); }

/* the "make a character" cell on the character picker */
button.cpick.add {
  border-style: dashed; color: var(--link);
  align-items: center; gap: 6px;
}
button.cpick.add:hover { background: #eef3ff; border-color: #5f7bb6; }
.cp-plus {
  width: 26px; height: 26px; flex: none;
  display: flex; align-items: center; justify-content: center;
  font: 700 18px/1 Tahoma, Verdana, sans-serif; color: #4a68a8;
  background: linear-gradient(180deg, #ffffff, #e4ebfa);
  border: 1px solid var(--edge); border-radius: 50%;
}
button.cpick.add .cp-txt { font-size: 11px; color: var(--link); font-weight: 700; }

/* what the next point costs, beside the + on a stat row */
.stat-cost {
  min-width: 14px; flex: none; text-align: right;
  font: 10px/1 "DejaVu Sans Mono", monospace; color: var(--dim);
}
.stat-cost.short { color: #b03a3a; font-weight: 700; }
.pts.stat.short {
  background: linear-gradient(180deg, #ffe0e0, #f3bcbc);
  border-color: #c58a8a; color: #7a2f2f;
}

/* --- Status row one: identity, job, and where they are playing ------------- */
/* The job block takes real width instead of leaving a hole in the middle of
   the banner: the bars stop stretching at ~560px and this fills the rest. */
.hero-side {
  flex: 1 1 340px; min-width: 0; max-width: 560px;
  display: flex; flex-direction: column; gap: 6px;
  padding-left: 10px;
  border-left: 1px solid var(--edge-soft);
}
.hero-job-box { display: flex; flex-direction: column; gap: 5px; }
.hj-cap {
  font: 700 10px/1 Tahoma, Verdana, sans-serif;
  letter-spacing: 0.7px; text-transform: uppercase; color: var(--dim);
}
.hj-chain { font: 700 11px/1 Tahoma, Verdana, sans-serif; color: var(--link); }
/* one line: what the next job is, how far off it is, and the button */
.hero-job-box .jobnext {
  margin: 0; padding: 5px 7px;
  display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: 8px;
}
.hero-job-box .jobnext h4 { margin: 0; font-size: 11px; }
.hero-job-box .jobnext > .row-between { grid-column: 1; gap: 6px; }
.jn-reqs { display: flex; gap: 8px; margin: 0; grid-column: 2; min-width: 0; }
/* The job box is a grid whose named children are PINNED to columns, so an
   unpinned child gets auto-placed into whichever cell the algorithm finds
   first — which was the requirement bars' cell, printing the CLOSED note
   straight through 'Base' and 'Job'. The note owns a full-width row instead. */
.jobnext .jn-closed { grid-column: 1 / -1; margin-top: 3px; }
.jn-reqs .reqrow { flex: 1; min-width: 0; }
.hero-job-box .jobnext > button { grid-column: 3; width: auto; margin: 0; white-space: nowrap; }
.hero-acts { display: flex; gap: 6px; flex-wrap: wrap; }
.hero-acts .cs-btn { flex: 1; min-width: 0; padding: 5px 8px; font-size: 11px; }

/* the hexagon's own numbers, under it */

@media (max-width: 1100px) {
  .hero-side { width: 100%; border-left: 0; padding-left: 0; }
}
@media (max-width: 620px) {
  /* Three things on one line — the job name, two progress bars and the button
     — leaves the bars nothing. On a phone they get their own row, full width,
     which is the only way "how far off am I" is readable at all. */
  .hero-job-box .jobnext { grid-template-columns: 1fr auto; }
  .hero-job-box .jobnext > .row-between { grid-column: 1; }
  .hero-job-box .jobnext > button { grid-column: 2; }
  .jn-reqs { grid-column: 1 / -1; flex-direction: column; gap: 2px; }
  .jn-reqs .reqrow { margin: 0; }
  /* Two columns of stat pairs at 390px clip their own numbers. */
  .combat-grid { grid-template-columns: 1fr; }
}

/* --- Status row two: three columns of equal height ------------------------- */
.status-grid { align-items: stretch; }
.status-grid > .card { display: flex; flex-direction: column; }
/* Every column uses the whole height of the row: the hexagon centres in it,
   the stat rows spread out to meet the button at the bottom, and the combat
   chips stay packed at the top where they belong. */
.status-grid > .card .stat-hex { align-self: center; margin: auto; }
.status-grid > .card .stat-list {
  flex: 1; display: flex; flex-direction: column; justify-content: space-evenly;
}
.status-grid > .card .combat-grid { align-content: start; }

/* In the party, or not — the same switch the auto-cast list uses. */
.cp-toggle {
  position: absolute; right: 4px; bottom: 4px;
  min-width: 30px; padding: 1px 5px;
  font: 700 9px/14px Tahoma, Verdana, sans-serif; letter-spacing: 0.5px;
  border-radius: 3px; cursor: pointer;
}
.cp-toggle.on {
  color: #1f5b2b; background: linear-gradient(180deg, #e7f8ea, #c9edd1);
  border: 1px solid #64a874;
}
.cp-toggle.off {
  color: #6b7285; background: linear-gradient(180deg, #f4f6fb, #e3e8f3);
  border: 1px solid var(--edge);
}
.cp-toggle.locked { opacity: 0.45; cursor: default; }
.cp-toggle:hover:not(.locked) { filter: brightness(1.06); }
button.cpick { padding-right: 40px; }
/* the amber "unspent points" pip keeps the corner to itself now */
.cp-dot { right: 5px; }

/* ---------------------------------------------------------------------------
   Away report
   The offline summary is the one screen a returning player always sees, so it
   is built as a haul rather than a receipt: what happened up top, three big
   numbers, then the loot as icons. A column of "Name x12" rows reads as a
   spreadsheet no matter how much is in it.
   --------------------------------------------------------------------------- */
.modal-inner.away { padding: 0 0 14px; }
.away-hero {
  padding: 16px 16px 14px;
  background:
    radial-gradient(120% 90% at 50% -30%, rgba(255, 214, 120, 0.55), transparent 70%),
    linear-gradient(180deg, var(--face-2), var(--face));
  border-bottom: 1px solid var(--edge);
  text-align: center;
}
.away-away {
  display: inline-block; margin-bottom: 6px; padding: 2px 9px;
  font-size: 10px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
  color: #6d3a00; background: rgba(255, 214, 120, 0.6);
  border: 1px solid var(--gold);
}
.away-head {
  font-size: 17px; font-weight: 700; color: var(--gold);
  text-transform: uppercase; letter-spacing: 0.04em; margin-bottom: 4px;
}
.away-hero p { margin: 0; }

/* Flex, not a fixed column count. The zeny tile was removed and the third
   column stayed behind as a blank grey box, because `repeat(3, 1fr)` does not
   care how many tiles there actually are. `flex: 1` does: two tiles split in
   half, three split in thirds, and nothing has to be edited here again. */
.away-stats { display: flex; gap: 1px; background: var(--edge); }
.away-stat { flex: 1 1 0; min-width: 0; background: var(--face); padding: 11px 6px; text-align: center; }
.away-stat .av { font-size: 17px; font-weight: 700; color: var(--txt); font-variant-numeric: tabular-nums; }
.away-stat .ak { font-size: 9px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); margin-top: 2px; }

.away-levels { margin: 10px 14px 0; }
.away-level {
  display: flex; justify-content: space-between; align-items: center;
  padding: 4px 8px; font-size: 11px;
  background: rgba(120, 220, 140, 0.16);
  border-left: 3px solid #3f9d55;
}
.away-level + .away-level { margin-top: 3px; }
.away-level .g { font-weight: 700; color: #1f6b33; }

.modal-inner.away h4 { margin: 12px 14px 6px; }
.away-loot {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(66px, 1fr));
  gap: 5px; margin: 0 14px;
  max-height: 232px; overflow-y: auto;
}
.away-item {
  background: var(--face-2); border: 1px solid var(--edge);
  box-shadow: inset 1px 1px 0 var(--hi);
  padding: 6px 3px 4px; text-align: center;
}
.away-item canvas { display: block; margin: 0 auto 3px; image-rendering: pixelated; }
.away-item .nm {
  font-size: 9px; color: var(--muted); line-height: 1.15;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.away-item .qt { font-size: 11px; font-weight: 700; font-variant-numeric: tabular-nums; }
.modal-inner.away > button { margin: 12px 14px 0; width: calc(100% - 28px); }

/* ---------------------------------------------------------------------------
   Map-change loading plate
   The client covers the screen with a painted panel when you cross a portal,
   and the pause is what makes a new map feel like somewhere else rather than
   like the same field with different monsters. Only a real map change shows
   it; the short march between waves does not.
   --------------------------------------------------------------------------- */
.mapload {
  position: absolute; inset: 0; z-index: 6;
  background-color: #0b0d13;
  background-size: cover; background-position: center;
  display: flex; align-items: flex-end; justify-content: center;
  animation: ml-in 0.18s ease-out;
}
.mapload::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(8,10,16,0.15) 0%, rgba(8,10,16,0.35) 45%, rgba(8,10,16,0.92) 100%);
}
@keyframes ml-in { from { opacity: 0; } to { opacity: 1; } }

.ml-plate {
  position: relative; z-index: 1;
  width: min(440px, 78%); margin-bottom: 14px; text-align: center;
}
.ml-kicker {
  font-size: 10px; letter-spacing: 0.22em; text-transform: uppercase;
  color: rgba(255, 226, 160, 0.85); margin-bottom: 2px;
}
.ml-name {
  font-size: 20px; font-weight: 700; color: #fff;
  text-shadow: 0 2px 0 rgba(0,0,0,0.65); margin-bottom: 8px;
}
.ml-track {
  height: 10px; background: rgba(0, 0, 0, 0.6);
  border: 1px solid rgba(255, 226, 160, 0.5);
  box-shadow: inset 0 1px 0 rgba(0,0,0,0.6);
  overflow: hidden;
}
.ml-fill {
  height: 100%; width: 0;
  background: linear-gradient(180deg, #ffe6a4, #e0a83c 55%, #b57c1c);
  transition: width 0.08s linear;
}

/* ---------------------------------------------------------------------------
   Early access
   A quest log, in the client's own window chrome, because that is what it is.
   Locked tasks are drawn locked rather than left clickable — the invite code
   gates everything after it, and a rule you can see beats a rejection you get
   after pressing the button.
   --------------------------------------------------------------------------- */
/* The global rule above hands the viewport to the game: `html, body` are
   height:100% overflow:hidden, and #app is a full-height flex column. That is
   right for a game screen and wrong for a document — this page is taller than
   the window and simply could not be scrolled.
   Rather than unpick the global rule (and give the game a page scrollbar), the
   early page becomes its own scroll container, the same way the panel bodies
   and the character screens already do. */
.ea-wrap {
  flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
  display: flex; align-items: flex-start; justify-content: center;
  padding: 26px 14px 60px;
  background: #0d1017;
}
/* Tiled at its native size and never scaled up, so the pixel art stays sharp on
   any window. The gradient on top is what keeps it wallpaper: a warm pool of
   light behind the logo, falling away to near-black at the foot of the page so
   long content never has to compete with the pattern. */
.ea-bg {
  position: fixed; inset: 0; z-index: 0; pointer-events: none;
  background-color: #0b0e14;
  background-repeat: repeat;
  background-size: 256px 256px;
  image-rendering: pixelated;
}
.ea-bg::after {
  content: ''; position: absolute; inset: 0;
  background:
    radial-gradient(90% 55% at 50% 0%, rgba(255, 217, 138, 0.10), transparent 68%),
    radial-gradient(120% 80% at 50% 30%, transparent 30%, rgba(9, 11, 16, 0.72) 100%),
    linear-gradient(180deg, transparent 0%, transparent 40%, rgba(9, 11, 16, 0.6) 100%);
}
.win.ea { position: relative; z-index: 1; max-width: 580px; width: 100%; }
.ea-count { font-size: 10px; color: #3d4a6b; font-weight: 700; letter-spacing: 0.04em; }
.ea-body { padding: 14px 14px 16px; }
.ea-h { margin: 0 0 4px; font-size: 16px; color: var(--gold); text-transform: uppercase; letter-spacing: 0.4px; }

/* The masthead. The logo used to float on a white field with nothing to sit
   against; giving it a plate of its own separates the pitch from the working
   part of the page below it. */
.ea-hero {
  margin: -14px -14px 10px; padding: 9px 14px 9px; text-align: center;
  background:
    radial-gradient(120% 90% at 50% 0%, rgba(120, 170, 255, 0.28), transparent 70%),
    linear-gradient(180deg, #e9f0fb, #cfdcf0);
  border-bottom: 1px solid var(--edge-soft);
}
/* Was 200px and took a third of the first screen before anyone saw a task. */
.ea-hero .login-logo { margin: 0 auto 2px; display: block; max-width: 132px; }
.ea-tag {
  margin: 0; font-size: 11px; font-weight: 600; color: #3d4a6b;
}
.ea-launch {
  display: inline-flex; align-items: center; gap: 6px; margin-top: 7px;
  padding: 2px 4px 2px 8px; font-size: 11px; font-weight: 700;
  background: rgba(255, 255, 255, 0.55); border: 1px solid var(--edge-soft);
}
.ea-launch .k { color: #55607d; font-weight: 600; }
.ea-launch .d { color: #1e2740; }
.ea-launch .c {
  padding: 1px 6px; color: #6d3a00;
  background: rgba(255, 214, 120, 0.7); border: 1px solid var(--gold);
}
.ea-launch .c.hot { color: #fff; background: #c0392b; border-color: #8e2a1f; }

/* speaker toggle, in the title bar where a window's controls belong */
.ea-mute {
  font-size: 11px; line-height: 1; padding: 1px 4px; cursor: pointer;
  background: var(--face-2); border: 1px solid var(--edge-soft);
  box-shadow: inset 1px 1px 0 var(--hi);
}
.ea-mute:hover { background: var(--face-3); }

/* --- tabs ---------------------------------------------------------------- */
.ea-tabs { display: flex; gap: 3px; margin-bottom: -1px; }
.ea-tab {
  flex: 1; display: flex; align-items: center; justify-content: center; gap: 5px;
  font-size: 11.5px; font-weight: 700; padding: 7px 4px 6px; cursor: pointer;
  color: var(--dim);
  background: var(--face-3); border: 1px solid var(--edge-soft); border-bottom: none;
}
.ea-tab:hover { background: var(--face-2); color: inherit; }
.ea-tab.on {
  color: inherit; background: var(--face);
  box-shadow: inset 0 2px 0 var(--gold);
}
.ea-tab-b {
  font-size: 9px; font-weight: 700; padding: 0 4px; border-radius: 7px;
  background: var(--face-2); border: 1px solid var(--edge-soft); color: var(--dim);
}
.ea-tab.on .ea-tab-b { background: rgba(255, 214, 120, 0.55); border-color: var(--gold); color: #6d3a00; }
.ea-panel {
  border: 1px solid var(--edge-soft); background: var(--face);
  padding: 12px 12px 14px;
}

.ea-meter {
  height: 8px; margin: 14px 0 4px;
  background: var(--face-3); border: 1px solid var(--edge-soft);
  box-shadow: inset 1px 1px 0 var(--lo); overflow: hidden;
}
.ea-meter i { display: block; height: 100%; background: linear-gradient(180deg, #ffdc84, #b98c1c); transition: width .25s ease; }
.ea-progress { font-size: 10px; color: var(--dim); text-align: right; margin-bottom: 12px; }

.ea-tasks { display: grid; gap: 7px; }
.ea-task {
  border: 1px solid var(--edge-soft); background: var(--face-2);
  box-shadow: inset 1px 1px 0 var(--hi);
  padding: 9px 11px 10px;
}
.ea-task.locked { opacity: 0.5; }
.ea-task.done { background: rgba(120, 220, 140, 0.14); border-color: #7fc98f; }
.ea-task-h { display: flex; align-items: center; gap: 8px; }
.ea-mark {
  flex: none; width: 19px; height: 19px; border-radius: 50%;
  display: grid; place-items: center; font-size: 10px; font-weight: 700;
  background: var(--face-3); border: 1px solid var(--edge-soft); color: var(--dim);
}
.ea-task.done .ea-mark { background: #3f9d55; border-color: #2c7a3f; color: #fff; }
.ea-task.todo .ea-mark { background: var(--title-a); border-color: var(--edge); color: var(--title-txt); }
.ea-task-t { font-size: 12.5px; font-weight: 700; }
.ea-proof {
  margin-left: auto; font-size: 10px; font-weight: 700; color: var(--green);
  background: rgba(120, 220, 140, 0.25); border: 1px solid #7fc98f;
  padding: 1px 6px; white-space: nowrap; max-width: 40%; overflow: hidden; text-overflow: ellipsis;
}
.ea-task-b { margin: 5px 0 0 27px; font-size: 11.5px; color: var(--dim); }
.ea-slot { margin: 8px 0 0 27px; }
.ea-form { display: flex; gap: 6px; margin-top: 6px; }
.ea-input { margin-top: 0 !important; flex: 1; }
/* Only the invite code is upper-cased. This used to sit on .ea-input, which
   also drove the reply field, so a pasted post link was displayed shouting. */
.ea-caps { text-transform: uppercase; }

/* the three actions on the post, as three lines rather than one sentence */
.ea-mini { display: grid; gap: 3px; margin: 2px 0 7px; }
.ea-mini-r { display: flex; align-items: center; gap: 7px; font-size: 11.5px; }
.ea-mini-d { color: var(--gold); font-weight: 700; }
.ea-link { display: inline-block; font-size: 11.5px; color: var(--link); font-weight: 600; }
/* a link on the card body itself, lined up under the description */
.ea-task-link { margin: 5px 0 0 27px; }
/* A link and a button on one row ran into each other. Give the slot spacing of
   its own rather than relying on each child to leave room. */
.ea-slot { margin: 8px 0 0 27px; display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.ea-slot > .ea-link { margin-right: 2px; }
.ea-slot > .ea-form { flex: 1 1 100%; }
.ea-slot > .ea-mini, .ea-slot > .ea-soon, .ea-slot > .ea-err { flex: 1 1 100%; }
/* The full address next to Disconnect. The chip in the header is truncated, and
   the one moment someone wants to read the whole thing is when deciding
   whether this is the account they meant to connect. */
.ea-addr {
  font: 10.5px "DejaVu Sans Mono", monospace; color: var(--dim);
  word-break: break-all; flex: 1 1 auto; min-width: 0;
}
.ea-soon {
  margin-top: 6px; font-size: 11px; color: #6d3a00;
  background: rgba(255, 214, 120, 0.5); border: 1px solid var(--gold);
  padding: 4px 7px;
}
.ea-err {
  margin-top: 6px; font-size: 11px; font-weight: 700; color: #7a1414;
  background: rgba(255, 140, 140, 0.28); border: 1px solid #c86a6a; padding: 4px 7px;
}

/* What a callback redirect left to say. Sits above the task list because it is
   about the list as a whole, not about whichever card happens to be open. */
.ea-note {
  margin: 0 0 10px; padding: 7px 10px; font-size: 12px; font-weight: 700;
  text-align: center; border-radius: 2px;
}
.ea-note.good {
  color: #14532d; background: rgba(150, 235, 170, 0.35); border: 1px solid #4f9c68;
}
.ea-note.bad {
  color: #7a1414; background: rgba(255, 140, 140, 0.28); border: 1px solid #c86a6a;
}

/* the panel once they are through */
.ea-done { text-align: center; }
.ea-badge {
  display: inline-block; font-size: 10px; font-weight: 700; letter-spacing: 0.1em;
  text-transform: uppercase; color: #6d3a00;
  background: rgba(255, 214, 120, 0.55); border: 1px solid var(--gold);
  padding: 2px 9px;
}
.ea-no { font-size: 40px; font-weight: 700; line-height: 1.1; margin: 4px 0 2px; }
.ea-done h4 { margin: 16px 0 3px; }
.ea-codes { display: grid; grid-template-columns: repeat(2, 1fr); gap: 5px; margin-top: 8px; }
.ea-code {
  display: flex; align-items: center; justify-content: space-between; gap: 6px;
  font: 11px "DejaVu Sans Mono", monospace;
  background: var(--face-2); border: 1px solid var(--edge-soft);
  box-shadow: inset 1px 1px 0 var(--hi); padding: 5px 8px; cursor: pointer;
}
.ea-code:hover { background: var(--face-3); }
.ea-code.used { opacity: 0.45; cursor: default; text-decoration: line-through; }
.ea-code .cs { font-size: 9px; color: var(--link); text-transform: uppercase; letter-spacing: 0.06em; }
.ea-ref {
  display: flex; justify-content: space-between; align-items: center;
  margin-top: 14px; padding: 7px 10px;
  background: var(--face-2); border: 1px solid var(--edge-soft);
}
.ea-ref .k { font-size: 11.5px; color: var(--dim); }
.ea-ref .v { font-size: 16px; font-weight: 700; }

/* ---------------------------------------------------------------------------
   Rewards
   A ladder the whole community climbs together, so the counter is the shared
   total and every tier stays visible from the start — including the one at the
   top. Hiding the prize until it is nearly won wastes the only reason anyone
   has to recruit.
   --------------------------------------------------------------------------- */
.ea-track { margin: 12px 0 14px; }
.ea-track-bar {
  position: relative; height: 12px;
  background: var(--face-3); border: 1px solid var(--edge-soft);
  box-shadow: inset 1px 1px 0 var(--lo);
}
.ea-track-bar > i {
  display: block; height: 100%;
  background: linear-gradient(180deg, #ffdc84, #b98c1c);
  transition: width .3s ease;
}
.ea-pips { position: absolute; inset: 0 5px; pointer-events: none; }
.ea-pip {
  position: absolute; top: 50%; width: 9px; height: 9px;
  margin-top: -5px; transform: translateX(-50%);
  border-radius: 50%; background: var(--face); border: 1px solid var(--edge);
}
.ea-pip.on { background: #ffd76a; border-color: #8a6510; box-shadow: 0 0 0 1px rgba(0,0,0,.15); }
.ea-track-stat { display: flex; align-items: baseline; gap: 6px; margin-top: 7px; }
.ea-track-stat .n { font-size: 22px; font-weight: 700; line-height: 1; }
.ea-track-stat .k { font-size: 11px; color: var(--dim); }

.ea-tiers { display: grid; gap: 7px; }
.ea-tier {
  border: 1px solid var(--edge-soft); background: var(--face-2);
  box-shadow: inset 1px 1px 0 var(--hi); padding: 8px 10px 9px;
  opacity: 0.62;
}
.ea-tier.next { opacity: 1; border-color: var(--gold); background: rgba(255, 236, 190, 0.5); }
.ea-tier.on { opacity: 1; background: rgba(120, 220, 140, 0.16); border-color: #7fc98f; }
.ea-tier-h { display: flex; align-items: center; gap: 8px; }
.ea-tier-n {
  flex: none; min-width: 40px; text-align: center;
  font-size: 11px; font-weight: 700; padding: 1px 5px;
  background: var(--face-3); border: 1px solid var(--edge-soft); color: var(--dim);
}
.ea-tier.on .ea-tier-n { background: #3f9d55; border-color: #2c7a3f; color: #fff; }
.ea-tier.next .ea-tier-n { background: var(--gold); border-color: #8a6510; color: #4a2f00; }
.ea-tier-t { font-size: 12.5px; font-weight: 700; }
.ea-tier-s {
  font-size: 9px; font-weight: 700; letter-spacing: 0.07em; text-transform: uppercase;
  color: var(--dim); white-space: nowrap;
}
.ea-tier.on .ea-tier-s { color: #2c7a3f; }
.ea-tier.next .ea-tier-s { color: #6d3a00; }
.ea-items { display: flex; flex-wrap: wrap; gap: 6px; margin: 7px 0 0 48px; }
.ea-item {
  display: flex; align-items: center; gap: 6px; font-size: 11px; font-weight: 600;
  padding: 3px 8px 3px 3px;
  background: var(--face); border: 1px solid var(--edge-soft);
}
.ea-item-i { display: block; image-rendering: pixelated; }
.ea-item-x { background: var(--face-3); border: 1px solid var(--edge-soft); }
.ea-tier-b { margin: 6px 0 0 48px; font-size: 11px; color: var(--dim); }
.ea-fine { margin: 12px 0 0; font-size: 10px; color: var(--dim); text-align: center; }

/* ---------------------------------------------------------------------------
   Invites
   The 5% is stated before anyone owns a code, because it is the reason to
   finish the quests at all.
   --------------------------------------------------------------------------- */
.ea-deal {
  display: flex; align-items: center; gap: 12px; padding: 11px 12px;
  background:
    linear-gradient(180deg, rgba(255, 236, 190, 0.75), rgba(255, 219, 140, 0.55));
  border: 1px solid var(--gold);
}
.ea-deal-n {
  flex: none; font-size: 30px; font-weight: 700; line-height: 1; color: #6d3a00;
}
.ea-deal-t strong { display: block; font-size: 12.5px; color: #4a2f00; }
.ea-deal-t p { margin: 4px 0 0; font-size: 11px; color: #6d3a00; }

/* the three earning levels: rate, who they are, how many */
.ea-lv { display: grid; gap: 5px; margin: 10px 0 6px; }
.ea-lv-r {
  display: flex; align-items: center; gap: 10px; padding: 7px 10px;
  background: var(--face-2); border: 1px solid var(--edge-soft);
  box-shadow: inset 1px 1px 0 var(--hi); opacity: 0.72;
}
.ea-lv-r.live { opacity: 1; border-color: var(--gold); background: rgba(255, 236, 190, 0.42); }
.ea-lv-p {
  flex: none; min-width: 42px; text-align: center;
  font-size: 15px; font-weight: 700; color: #6d3a00;
  background: rgba(255, 214, 120, 0.55); border: 1px solid var(--gold); padding: 3px 4px;
}
.ea-lv-t { flex: 1; min-width: 0; }
.ea-lv-h { display: flex; align-items: baseline; gap: 6px; }
.ea-lv-n { font-size: 11.5px; font-weight: 700; }
.ea-lv-l { font-size: 11px; color: var(--dim); }
.ea-lv-t p { margin: 1px 0 0; font-size: 10.5px; color: var(--dim); }
.ea-lv-c { flex: none; font-size: 19px; font-weight: 700; min-width: 26px; text-align: right; }

.ea-how { display: grid; gap: 5px; margin: 12px 0; }
.ea-how-r {
  display: flex; align-items: flex-start; gap: 8px; font-size: 11.5px;
  padding: 6px 9px; background: var(--face-2); border: 1px solid var(--edge-soft);
}
.ea-how-n {
  flex: none; width: 17px; height: 17px; border-radius: 50%;
  display: grid; place-items: center; font-size: 9px; font-weight: 700;
  background: var(--title-a); border: 1px solid var(--edge); color: var(--title-txt);
}
.ea-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 5px; margin-bottom: 12px; }
.ea-stat {
  text-align: center; padding: 8px 4px;
  background: var(--face-2); border: 1px solid var(--edge-soft);
  box-shadow: inset 1px 1px 0 var(--hi);
}
.ea-stat .v { display: block; font-size: 18px; font-weight: 700; line-height: 1.1; }
.ea-stat .k { display: block; margin-top: 3px; font-size: 9.5px; color: var(--dim); }
.ea-inv h4 { margin: 14px 0 3px; }

.btn-share {
  display: block; margin-top: 12px; padding: 9px; text-align: center;
  text-decoration: none; font-size: 12.5px; font-weight: 700;
  color: #fff; background: #111; border: 1px solid #333;
}
.btn-share:hover { background: #222; }

@media (max-width: 480px) {
  .ea-wrap { padding: 12px 8px 40px; }
  .ea-codes { grid-template-columns: 1fr; }
  .ea-proof { max-width: 32%; }
  /* On a phone the 48px indent under a tier header costs a third of the line,
     so the items fall back under the full width instead. */
  .ea-items, .ea-tier-b { margin-left: 0; }
  .ea-tab { font-size: 10.5px; padding: 7px 2px 6px; }
  .ea-deal-n { font-size: 24px; }
  .ea-stat .v { font-size: 15px; }
  .ea-stat .k { font-size: 9px; }
  .ea-hero .login-logo { max-width: 160px; }
}

/* ---------------------------------------------------------------------------
   Admin
   One question drives this screen: should this person be let in? So the row
   carries the evidence and nothing else. `proved` and `claimed` are separate
   words on purpose — the gap between them is the only thing on the page that
   actually needs a human.
   --------------------------------------------------------------------------- */
.ad-wrap {
  flex: 1; min-height: 0; overflow-y: auto;
  padding: 18px 14px 60px; background: #0d1017;
}
.win.ad { max-width: 1180px; width: 100%; margin: 0 auto; }
.ad-body { padding: 12px; }

.ad-sum { display: flex; flex-wrap: wrap; gap: 5px; margin-bottom: 10px; }
.ad-cell {
  flex: 1 1 100px; text-align: center; padding: 7px 6px;
  background: var(--face-2); border: 1px solid var(--edge-soft);
  box-shadow: inset 1px 1px 0 var(--hi);
}
.ad-cell .v { display: block; font-size: 17px; font-weight: 700; line-height: 1.1; }
.ad-cell .k { display: block; margin-top: 2px; font-size: 9.5px; color: var(--dim); }
.ad-cell.good .v { color: #2c7a3f; }
.ad-cell.warn { background: rgba(255, 236, 190, 0.6); border-color: var(--gold); }
.ad-cell.warn .v { color: #6d3a00; }

.ad-actions {
  display: flex; flex-wrap: wrap; align-items: center; gap: 7px;
  padding: 9px 10px; margin-bottom: 10px;
  background: var(--face-2); border: 1px solid var(--edge-soft);
}
.ad-lab { font-size: 11.5px; font-weight: 700; color: var(--dim); }
.ad-n { margin-top: 0 !important; width: 68px; }
.ad-check { display: flex; align-items: center; gap: 5px; font-size: 11px; color: var(--dim); }
.ad-busy, .ad-when { flex: 1 1 100%; font-size: 11px; }
.ad-busy { font-weight: 700; }
.ad-when { color: var(--dim); }

.ad-tabs { display: flex; align-items: flex-end; gap: 3px; margin-bottom: -1px; }
.ad-tabs .ad-find { margin-bottom: 3px; }
.ad-find-n { margin: 0 0 6px 8px; font-size: 10.5px; color: var(--dim); }
.ad-tab {
  font-size: 11.5px; font-weight: 700; padding: 6px 12px; cursor: pointer;
  color: var(--dim); background: var(--face-3);
  border: 1px solid var(--edge-soft); border-bottom: none;
}
.ad-tab:hover { background: var(--face-2); color: inherit; }
.ad-tab.on { color: inherit; background: var(--face); box-shadow: inset 0 2px 0 var(--gold); }

.ad-table { border: 1px solid var(--edge-soft); background: var(--face); }
.ad-r {
  display: grid; align-items: center; gap: 8px;
  grid-template-columns: 46px 92px minmax(110px, 1.3fr) minmax(96px, 1fr) 74px 88px
    minmax(88px, 1fr) 62px 78px 128px;
  padding: 6px 9px; font-size: 11.5px;
  border-bottom: 1px solid var(--edge-soft);
}
.ad-r:last-child { border-bottom: none; }
.ad-head {
  font-size: 9.5px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--dim); background: var(--face-2);
}
.ad-q { font-weight: 700; }
.ad-w { font: 11px "DejaVu Sans Mono", monospace; cursor: pointer; }
.ad-w:hover { color: var(--link); }
.ad-sub { color: var(--dim); font-size: 10.5px; }
.ad-link { color: var(--link); font-weight: 600; }
.ad-pill {
  /* Shrink to the word. As a grid child it stretched to the whole column,
     which turned a one-word status into a coloured bar the width of a name. */
  display: inline-block; justify-self: start; max-width: 100%;
  padding: 1px 6px; font-size: 10px; font-weight: 700;
  text-align: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  background: var(--face-3); border: 1px solid var(--edge-soft); color: var(--dim);
}
.ad-pill.ok { color: #14532d; background: rgba(150, 235, 170, 0.45); border-color: #4f9c68; }
.ad-pill.warn { color: #6d3a00; background: rgba(255, 214, 120, 0.6); border-color: var(--gold); }
/* Absence is not a state worth a coloured chip. A boxed dash in every empty
   cell read as louder than the evidence beside it. */
.ad-pill.no { color: var(--dim); background: none; border-color: transparent; }
.ad-acts { display: flex; gap: 4px; }
.ad-empty { padding: 18px; text-align: center; color: var(--dim); font-size: 12px; }
.btn.danger, button.danger {
  color: #7a1414; background: rgba(255, 140, 140, 0.3); border-color: #c86a6a;
}

@media (max-width: 900px) {
  /* The table stops being a table: each person becomes a stacked card, because
     nine columns on a phone is nine columns of nothing. */
  .ad-r { grid-template-columns: 46px 1fr; grid-auto-rows: min-content; }
  .ad-head { display: none; }
  .ad-r > * { grid-column: 2; }
  .ad-q { grid-column: 1; grid-row: 1 / span 2; align-self: start; }
}

/* --- admin: sections, cards, chart ---------------------------------------- */
/* --- Players: who is already inside ---------------------------------------
   A separate grid from .ad-r on purpose. The waiting-list row is evidence for a
   decision; this one is save state, and forcing both through one column set
   made every column a compromise. */
.ad-pr {
  display: grid; align-items: center; gap: 8px;
  grid-template-columns: 108px minmax(96px, 1fr) 82px 62px 58px minmax(84px, 1fr)
    58px 52px 96px 92px;
  padding: 6px 9px; font-size: 11.5px;
  border-bottom: 1px solid var(--edge-soft);
}
.ad-pr:last-child { border-bottom: none; }
.ad-num { text-align: right; font: 11px "DejaVu Sans Mono", monospace; }
.ad-num.gold { color: #8a5a00; font-weight: 700; }
.ad-find { margin-top: 0 !important; width: 168px; }
/* a live session, in the only space a wallet column has to spare */
.ad-dot {
  display: inline-block; width: 6px; height: 6px; margin-left: 5px;
  border-radius: 50%; background: #35a35d; vertical-align: middle;
}

/* the roster, opened in place under its player */
.ad-chars { background: var(--face-2); border-bottom: 1px solid var(--edge-soft); }
.ad-cr {
  display: grid; align-items: center; gap: 8px;
  grid-template-columns: 54px minmax(96px, 1.1fr) 76px 46px 52px 56px 52px
    minmax(150px, 1fr) minmax(110px, 1fr) 88px;
  padding: 5px 9px 5px 18px; font-size: 11px;
  border-bottom: 1px solid var(--edge-soft);
}
.ad-cr:last-child { border-bottom: none; }
.ad-cname { font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ad-stats { font: 10.5px "DejaVu Sans Mono", monospace; white-space: pre; color: var(--dim); }
.ad-chars-f { padding: 6px 9px 8px 18px; font-size: 10.5px; color: var(--dim); }

/* --- the presale gate ------------------------------------------------------ */
.ad-gate {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 9px 11px; margin-bottom: 10px;
  border: 1px solid var(--edge-soft); background: var(--face);
}
.ad-gate.on { border-color: #4f9c68; background: rgba(150, 235, 170, 0.16); }
.ad-gate-t { display: flex; flex-direction: column; gap: 1px; }
.ad-gate-t .l { font-size: 12.5px; font-weight: 700; }
.ad-gate-t .s { font-size: 10.5px; color: var(--dim); }
.ad-switch {
  flex: none; width: 42px; height: 23px; padding: 2px; cursor: pointer;
  border: 1px solid var(--edge); border-radius: 999px; background: var(--face-2);
  transition: background 120ms linear, border-color 120ms linear;
}
.ad-switch i {
  display: block; width: 17px; height: 17px; border-radius: 50%;
  background: var(--dim); transition: transform 120ms ease, background 120ms linear;
}
.ad-switch.on { background: #3f9b5f; border-color: #2f7a49; }
.ad-switch.on i { transform: translateX(19px); background: #fff; }

/* --- the in-game feedback form ------------------------------------------- */
.fb { max-width: 1180px; }
.fb-main { max-width: 620px; min-width: 0; }
.fb-h { margin: 0 0 4px; font-size: 15px; }
.fb-sub { margin: 0 0 12px; font-size: 12px; color: var(--dim); line-height: 1.5; }
.fb-field { margin-bottom: 11px; }
.fb-lab {
  margin-bottom: 3px; font-size: 10px; font-weight: 700;
  letter-spacing: 0.06em; text-transform: uppercase; color: var(--dim);
}
.fb-title, .fb-body { width: 100%; margin-top: 0 !important; }
.fb-body { resize: vertical; font: inherit; line-height: 1.5; }
.fb-file { display: none; }
.fb-shot { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.fb-shot-n { font-size: 11px; color: var(--dim); }
.fb-ctx { margin: 4px 0 12px; font-size: 11px; color: var(--dim); }
.fb-ctx summary { cursor: pointer; }
.fb-ctx pre {
  max-height: 190px; overflow: auto; margin: 6px 0 0; padding: 7px;
  border: 1px solid var(--edge-soft); background: var(--face-2);
  font: 10.5px "DejaVu Sans Mono", monospace; white-space: pre-wrap; word-break: break-all;
}
.fb-err { margin: 8px 0 0; font-size: 12px; color: #c0392b; }

/* --- report history: the ticket side of the feedback panel ---------------
   Two columns. The form does not get wider than a form should be, so the
   window's spare width goes to the history instead of to nothing. */
.fb-grid {
  /* The form is capped, so the history takes whatever is left rather than a
     column of nothing opening up between the two. */
  display: grid; grid-template-columns: minmax(0, 620px) minmax(0, 1fr);
  gap: 18px; align-items: start;
}
@media (max-width: 1000px) {
  .fb-grid { grid-template-columns: minmax(0, 1fr); }
  .fb-rail { border-left: none; border-top: 1px solid var(--edge-soft); padding: 14px 0 0; }
}
.fb-rail {
  min-width: 0; padding-left: 18px; border-left: 1px solid var(--edge-soft);
}
.fb-rail-h { display: flex; align-items: center; gap: 7px; margin-bottom: 9px; }
.fb-rail-t {
  font: 800 10.5px/1 Tahoma, sans-serif; text-transform: uppercase;
  letter-spacing: 0.7px; color: var(--dim);
}
.fb-rail-e {
  margin: 0; font: 500 11.5px/1.55 Tahoma, sans-serif; color: var(--dim);
}
.fb-count {
  font: 700 10px/1 Tahoma, sans-serif; color: #5a6f92;
  background: #e3eaf5; border-radius: 999px; padding: 3px 6px;
}
.fb-dot {
  font: 800 10px/1 Tahoma, sans-serif; color: #fff;
  background: #3f9d55; border-radius: 999px; padding: 3px 6px;
}

.fb-list { display: flex; flex-direction: column; gap: 6px; }
.fb-tk {
  display: block; width: 100%; text-align: left; cursor: pointer;
  padding: 9px 11px; margin: 0;
  border: 1px solid var(--edge-soft); border-radius: 7px; background: var(--face);
}
.fb-tk:hover { border-color: #a9c0e2; background: #f2f6fd; }
.fb-tk.unread { border-color: #8fc79c; background: rgba(224, 245, 228, 0.6); }
.fb-tk.on { border-color: #7f9bd0; background: #eaf1fd; box-shadow: inset 2px 0 0 #4a6b95; }
.fb-tk-top { display: flex; align-items: center; gap: 8px; }
.fb-tk-t {
  flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; font: 700 12px/1.35 Tahoma, sans-serif;
}
.fb-tk-sub {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin-top: 4px;
  font: 500 10.5px/1.3 Tahoma, sans-serif; color: var(--dim);
}
.fb-tk-r { color: #4a6b95; }
.fb-tk-new { font-weight: 800; color: #2c7a3f; }

.fb-st {
  flex: none; padding: 2px 8px; border-radius: 999px;
  font: 700 9.5px/1.6 Tahoma, sans-serif;
  text-transform: uppercase; letter-spacing: 0.4px;
  border: 1px solid transparent;
}
.fb-st.st-new  { background: #fdf0d0; border-color: #e0c273; color: #7a5c11; }
.fb-st.st-seen { background: #e2ecfa; border-color: #a8c6ea; color: #29527f; }
.fb-st.st-plan { background: #e7e2fb; border-color: #b6ace8; color: #453a86; }
.fb-st.st-done { background: #ddf2e1; border-color: #93ca9d; color: #276b36; }
.fb-st.st-no   { background: #eceff3; border-color: #c4ccd8; color: #62707f; }

.fb-th-h { display: flex; align-items: center; gap: 9px; margin: 0 0 2px; }
.fb-th-t { flex: 1 1 auto; min-width: 0; font: 800 13.5px/1.3 Tahoma, sans-serif; }
.fb-th-s { font: 500 11px/1.3 Tahoma, sans-serif; color: var(--dim); margin-bottom: 10px; }
.fb-th { display: flex; flex-direction: column; gap: 8px; margin-bottom: 12px; }
.fb-msg {
  max-width: 88%; padding: 8px 11px; border-radius: 9px;
  border: 1px solid var(--edge-soft);
}
.fb-msg.me   { align-self: flex-start; background: var(--face-2); }
.fb-msg.them {
  align-self: flex-end; background: #e8f3ff; border-color: #a8c6ea;
}
.fb-msg-w {
  display: flex; align-items: baseline; gap: 8px; margin-bottom: 3px;
  font: 500 10px/1.3 Tahoma, sans-serif; color: var(--dim);
}
.fb-msg-a { font-weight: 800; color: #4a6b95; }
.fb-msg.me .fb-msg-a { color: #6b7f9e; }
.fb-msg-b { font: 500 12px/1.55 Tahoma, sans-serif; white-space: pre-wrap; word-break: break-word; }
.fb-th-shot { margin: 0 0 12px; }
.fb-img { max-width: 100%; max-height: 320px; border: 1px solid var(--edge-soft); border-radius: 6px; }
.fb-reply { width: 100%; resize: vertical; font: inherit; line-height: 1.5; margin-bottom: 8px; }

/* the unread pip on the sidebar's Report a Bug / Suggest an Idea entries */
.si-new {
  margin-left: auto; min-width: 16px; height: 16px; padding: 0 4px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 999px; background: #3f9d55; color: #fff;
  font: 800 9.5px/1 Tahoma, sans-serif;
}
.fb-done { padding: 16px 0; }
.fb-done-t { font-size: 14px; font-weight: 700; color: #2c7a3f; margin-bottom: 4px; }
.fb-done p { margin: 0 0 12px; font-size: 12px; color: var(--dim); }

/* --- the admin feedback queue -------------------------------------------- */
.ad-badge {
  margin-left: 6px; padding: 0 5px; border-radius: 999px;
  background: var(--gold); color: #4a2c00;
  font-size: 9.5px; font-weight: 800; line-height: 15px; display: inline-block;
}
.fbr { border-bottom: 1px solid var(--edge-soft); padding: 8px 10px; }
.fbr:last-child { border-bottom: none; }
.fbr.unread { background: rgba(255, 236, 190, 0.4); }
.fbr-h { display: flex; align-items: center; gap: 8px; cursor: pointer; }
.fbr-t { font-size: 12.5px; font-weight: 700; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fbr-clip { font-size: 9.5px; color: var(--dim); border: 1px solid var(--edge-soft);
  border-radius: 3px; padding: 0 4px; }
.fbr-who { margin: 2px 0 0 4px; font-size: 11px; }
.fbr-body {
  margin: 8px 0; padding: 8px 10px; font-size: 12px; line-height: 1.55;
  white-space: pre-wrap; border-left: 3px solid var(--edge-soft); background: var(--face-2);
}
.fbr-shot { margin: 8px 0; }
.fbr-img { max-width: 100%; max-height: 340px; border: 1px solid var(--edge-soft); }
.fbr-ctx { font-size: 11px; color: var(--dim); }
.fbr-ctx summary { cursor: pointer; }
.fbr-ctx pre {
  max-height: 200px; overflow: auto; margin: 6px 0; padding: 7px;
  border: 1px solid var(--edge-soft); background: var(--face-2);
  font: 10.5px "DejaVu Sans Mono", monospace; white-space: pre-wrap; word-break: break-all;
}
.fbr-th { display: flex; flex-direction: column; gap: 6px; margin: 8px 0; }
.fbr-msg { max-width: 86%; padding: 6px 9px; border-radius: 8px; border: 1px solid var(--edge-soft); }
.fbr-msg.them { align-self: flex-start; background: var(--face-2); }
.fbr-msg.us { align-self: flex-end; background: #e8f3ff; border-color: #a8c6ea; }
.fbr-msg-w { display: flex; gap: 8px; font-size: 9.5px; color: var(--dim); margin-bottom: 2px; }
.fbr-msg-a { font-weight: 800; }
.fbr-msg-b { font-size: 11.5px; line-height: 1.5; white-space: pre-wrap; word-break: break-word; }
.fbr-reply-row { display: flex; gap: 6px; align-items: flex-end; margin: 8px 0 0; }
.fbr-reply { flex: 1 1 auto; margin-top: 0 !important; resize: vertical; font: inherit; }
.fbr-acts { display: flex; align-items: center; gap: 5px; flex-wrap: wrap; margin-top: 8px; }
.fbr-note { margin-top: 0 !important; flex: 1 1 180px; min-width: 140px; }

/* --- belt picker: the auto-buy half --------------------------------------- */
.belt-buy {
  border-top: 1px solid var(--edge-soft); background: var(--face-2);
  padding: 9px 11px 11px;
}
.belt-buy-h { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.belt-buy-t { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.belt-buy-t .l { font-size: 12.5px; font-weight: 700; }
.belt-buy-t .s { font-size: 10.5px; color: var(--dim); }
.belt-shelfcap { margin: 8px 0 2px; font: 500 10.5px/1.4 Tahoma, sans-serif; color: #6b7f9e; }
.belt-shelf {
  display: grid; gap: 6px; margin-top: 9px;
  grid-template-columns: repeat(auto-fill, minmax(112px, 1fr));
}
.belt-opt.small { padding: 6px 4px; }
.belt-opt.small .bo-name { font-size: 11px; }

/* --- "where should this card go" picker ----------------------------------- */
.card-fits {
  padding: 9px 14px 0; font: 500 11px/1.45 Tahoma, sans-serif; color: #6b7f9e;
}
.card-list { overflow: auto; padding: 10px 12px 12px; display: grid; gap: 5px; }
.card-opt {
  display: flex; align-items: center; gap: 9px; width: 100%; text-align: left;
  padding: 7px 9px; border: 1px solid #d5dfef; border-radius: 8px;
  background: #fff; cursor: pointer;
}
.card-opt:hover { background: #e6eefb; border-color: #a9c0e2; }
.card-opt.dead { opacity: 0.5; cursor: default; background: #f4f6fb; }
.card-opt.dead:hover { background: #f4f6fb; border-color: #d5dfef; }
.card-opt-m { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1; }
.card-opt-m .n {
  font: 700 12px/1.2 Tahoma, sans-serif; color: #23406e;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.card-opt-m .s { font: 500 10.5px/1.2 Tahoma, sans-serif; color: #6b7f9e; }
/* Worn or bagged, at a glance — the same sword reads differently depending on
   who is holding it. */
.card-where {
  flex: none; padding: 2px 7px; border-radius: 999px;
  border: 1px solid #d5dfef; background: #f2f5fd;
  font: 700 9.5px/1.5 Tahoma, sans-serif; color: #6b7f9e; white-space: nowrap;
}
.card-where.worn { border-color: #7fc48a; background: #e2f0e4; color: #1e5b2c; }

/* --- Wallet and Referrals ------------------------------------------------- */
.wl-strip { display: flex; flex-wrap: wrap; gap: 5px; margin: 9px 0 4px; }
.wl-cell {
  flex: 1 1 92px; padding: 7px 9px;
  border: 1px solid var(--edge-soft); background: var(--face-2); border-radius: 5px;
}
.wl-cell .v { display: block; font-size: 15px; font-weight: 700; line-height: 1.15; }
.wl-cell .k { display: block; margin-top: 2px; font-size: 9.5px; color: var(--dim); }
.wl-cell.good .v { color: #2c7a3f; }
.wl-cell.warn { background: rgba(255, 236, 190, 0.6); border-color: var(--gold); }
.wl-cell.warn .v { color: #6d3a00; }

.wl-cap {
  margin: 10px 0 4px; font: 700 9.5px/1 Tahoma, sans-serif;
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--dim);
}
.wl-codes { display: flex; flex-wrap: wrap; gap: 5px; }
button.wl-code {
  padding: 5px 9px; border: 1px dashed var(--edge); border-radius: 5px;
  background: var(--face-2); cursor: pointer;
  font: 700 11px/1 "DejaVu Sans Mono", monospace; color: #33507f;
}
button.wl-code:hover { background: #e6eefb; border-style: solid; }

.wl-row {
  display: grid; align-items: center; gap: 8px;
  grid-template-columns: 96px minmax(80px, 1fr) 30px 92px;
  padding: 5px 4px; font-size: 11.5px;
  border-bottom: 1px solid var(--edge-soft);
}
.wl-row.wide { grid-template-columns: 96px minmax(120px, 1fr) 62px 74px 96px; }
/* the zeny trail: when, what, how much, and what the balance was after */
/* active buffs on a party card */
.mem-buffs { display: flex; flex-wrap: wrap; gap: 3px; margin-top: 3px; }
.buff {
  padding: 1px 5px; border-radius: 3px;
  border: 1px solid #8fc79a; background: rgba(150, 235, 170, 0.32);
  font: 700 8.5px/1.5 Tahoma, sans-serif; letter-spacing: 0.02em; color: #1e5b2c;
  white-space: nowrap;
}
/* a potion buff reads differently from a cast one — nobody cast it */
.buff.potion { border-color: #9aa9d6; background: rgba(180, 198, 240, 0.4); color: #2b4a8a; }
/* about to drop — the moment a player would want to notice */
.buff.fading { border-color: var(--gold); background: rgba(255, 214, 120, 0.5); color: #6d3a00; }

/* a button that asks once — see Panels.confirmButton */

/* --- the zeny trail ------------------------------------------------------- */
.wl-top {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 14px; flex-wrap: wrap;
}
.wl-caption {
  font: 700 9.5px/1 Tahoma, sans-serif; letter-spacing: 0.09em;
  text-transform: uppercase; color: var(--dim); margin-bottom: 5px;
}
.wl-bal { display: flex; align-items: baseline; gap: 2px; }
.wl-bal .v { font: 800 30px/1 Tahoma, sans-serif; color: #2c7a3f; letter-spacing: -0.5px; }
.wl-bal .z { font: 700 15px/1 Tahoma, sans-serif; color: #2c7a3f; opacity: 0.65; }
.wl-minis { display: flex; gap: 6px; }
.wl-mini {
  min-width: 104px; padding: 6px 9px; border-radius: 6px;
  border: 1px solid var(--edge-soft); background: var(--face-2);
}
.wl-mini .v { display: block; font: 700 14px/1.1 Tahoma, sans-serif; }
.wl-mini .k { display: block; margin-top: 2px; font-size: 9.5px; color: var(--dim); }
.wl-mini.good .v { color: #2c7a3f; }
.wl-mini.bad .v { color: #a9442f; }

.wl-trail { padding-top: 4px; }
.wl-day {
  position: sticky; top: 0; z-index: 1;
  margin: 8px -10px 2px; padding: 5px 12px;
  background: var(--face-2); border-top: 1px solid var(--edge-soft);
  border-bottom: 1px solid var(--edge-soft);
  font: 700 9.5px/1 Tahoma, sans-serif; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--dim);
}
.wl-day:first-child { margin-top: 0; border-top: none; }
.wl-r {
  display: flex; align-items: center; gap: 10px;
  padding: 7px 2px; border-bottom: 1px solid rgba(0, 0, 0, 0.05);
}
.wl-r:last-child { border-bottom: none; }
.wl-dot {
  flex: none; width: 22px; height: 22px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font: 700 13px/1 Tahoma, sans-serif;
}
.wl-dot.in { background: rgba(150, 235, 170, 0.5); color: #1e5b2c; }
.wl-dot.out { background: rgba(240, 190, 180, 0.5); color: #8c3520; }
.wl-rm { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
.wl-rm .n {
  font: 700 12px/1.2 Tahoma, sans-serif; color: #23406e;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.wl-rm .s { font: 500 10px/1.2 Tahoma, sans-serif; color: var(--dim); }
.wl-rr { flex: none; display: flex; flex-direction: column; align-items: flex-end; gap: 2px; }
.wl-rr .a { font: 700 12.5px/1.2 "DejaVu Sans Mono", monospace; }
.wl-rr .a.good { color: #2c7a3f; }
.wl-rr .a.bad { color: #a9442f; }
.wl-rr .b { font: 10px/1.2 "DejaVu Sans Mono", monospace; color: var(--dim); }
.wl-row:last-child { border-bottom: none; }
.wl-when { font-size: 10.5px; color: var(--dim); white-space: nowrap; }
.wl-who { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wl-mid { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.wl-mid .n { font-weight: 700; font-size: 11.5px; }
.wl-mid .s { font-size: 10px; color: var(--dim);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wl-lv {
  font: 700 9.5px/1.6 Tahoma, sans-serif; text-align: center;
  border: 1px solid var(--edge-soft); border-radius: 3px; color: var(--dim);
}
.wl-sig { font: 10.5px "DejaVu Sans Mono", monospace; color: var(--link); }
.wl-st {
  font: 700 9px/1.6 Tahoma, sans-serif; text-transform: uppercase;
  letter-spacing: 0.04em; color: var(--dim); text-align: center;
}
.wl-st.ok { color: #2c7a3f; }
.wl-st.warn { color: #8a5a00; }
.wl-amt { text-align: right; font: 700 11.5px "DejaVu Sans Mono", monospace; }
.wl-amt.good { color: #2c7a3f; }
.wl-amt.bad { color: #a9442f; }
.mono { font-family: "DejaVu Sans Mono", monospace; font-size: 10.5px; }

/* the are-you-sure step, in place of the list */
.card-confirm { padding: 6px 4px 2px; text-align: center; }
.card-confirm-p {
  display: flex; align-items: center; justify-content: center; gap: 10px;
  margin-bottom: 10px;
}
.card-confirm-p .arw { font: 700 18px/1 Tahoma, sans-serif; color: #8fa4cd; }
.card-confirm-t { font: 700 13px/1.35 Tahoma, sans-serif; color: #23406e; }
.card-confirm-s {
  margin: 4px 0 12px; font: 500 11px/1.45 Tahoma, sans-serif; color: #9a6a1e;
}
.card-confirm-a { display: flex; gap: 8px; justify-content: center; }
.card-confirm-a button { min-width: 96px; }

/* --- the unspent-points prompt above the auto-cast list ------------------ */
/* Shaped like a quest prompt, not a paragraph. The old one ran the button
   through the middle of a wrapping sentence, so the text broke around it and
   the thing you were meant to press read as part of the copy. */
.quest-nag {
  display: flex; align-items: center; gap: 11px; flex-wrap: wrap;
  margin: 0 0 12px; padding: 10px 12px;
  border: 1px solid #d9ad4e; border-radius: 8px;
  background:
    linear-gradient(180deg, rgba(255, 246, 222, 0.96), rgba(253, 234, 190, 0.96));
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.8), 0 1px 3px rgba(120, 80, 10, 0.16);
}
.qn-medal {
  flex: none; width: 30px; height: 30px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font: 800 17px/1 Tahoma, sans-serif; color: #fff;
  background: radial-gradient(circle at 34% 28%, #ffd977, #e0a022 62%, #b57a12);
  border: 1px solid #a8710f;
  box-shadow: 0 0 0 2px rgba(255, 236, 186, 0.85), 0 2px 5px rgba(120, 80, 10, 0.32);
  text-shadow: 0 1px 1px rgba(120, 70, 0, 0.55);
  animation: qn-pulse 1.9s ease-in-out infinite;
}
@keyframes qn-pulse {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.07); }
}
@media (prefers-reduced-motion: reduce) { .qn-medal { animation: none; } }

.qn-mid { flex: 1 1 230px; min-width: 0; }
.qn-title {
  font: 800 12.5px/1.25 Tahoma, sans-serif; color: #6b3d00; letter-spacing: 0.2px;
}
.qn-chips { display: flex; flex-wrap: wrap; gap: 5px; margin: 5px 0 4px; }
.qn-chip {
  display: inline-flex; align-items: baseline; gap: 3px;
  padding: 2px 8px; border-radius: 999px;
  font: 600 10.5px/1.5 Tahoma, sans-serif;
  border: 1px solid transparent;
}
.qn-chip b { font: 800 12px/1 Tahoma, sans-serif; }
.qn-chip.stat  { background: #dfeeff; border-color: #a8c6ea; color: #1f4a7d; }
.qn-chip.skill { background: #e6e2ff; border-color: #b8b0ea; color: #443a86; }
.qn-sub { font: 500 11px/1.4 Tahoma, sans-serif; color: #7a5518; }

button.qn-go {
  flex: none; margin-left: auto;
  padding: 9px 16px; font: 800 11.5px/1 Tahoma, sans-serif; letter-spacing: 0.3px;
  color: #23430f; border: 1px solid #6f9c46; border-radius: 7px;
  background: linear-gradient(180deg, #d8f0b8, #aed983);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.7), 0 1px 3px rgba(40, 70, 20, 0.22);
  cursor: pointer;
}
button.qn-go:hover { background: linear-gradient(180deg, #e2f7c4, #b9e28d); }
button.qn-go:active { transform: translateY(1px); box-shadow: inset 0 1px 3px rgba(40,70,20,0.3); }

/* --- refine odds table --------------------------------------------------- */
/* Five groups across, +1..+10 down. Read straight out of the refine data, so
   what is printed is what the attempt actually rolls against. */
.odds { margin: 6px 0 8px; font: 600 11px/1 Tahoma, sans-serif; }
.odds-row {
  display: grid; grid-template-columns: 40px repeat(5, 1fr); gap: 2px;
  margin-bottom: 2px;
}
.odds-row.head .odds-c {
  background: none; border-color: transparent; color: var(--dim);
  font: 700 10px/1 Tahoma, sans-serif; text-transform: uppercase; letter-spacing: 0.4px;
}
.odds-lv {
  display: flex; align-items: center;
  font: 700 11px/1 Tahoma, sans-serif; color: var(--dim);
}
.odds-c {
  display: flex; align-items: center; justify-content: center;
  padding: 4px 2px; border-radius: 4px; border: 1px solid transparent;
  cursor: default;
}
.odds-c.safe { background: #dff2e0; border-color: #9fcea6; color: #2c6b39; }
.odds-c.ok   { background: #fdf3d4; border-color: #e2c877; color: #7a5c11; }
.odds-c.risk { background: #ffe6d2; border-color: #eab387; color: #8a4b17; }
.odds-c.bad  { background: #ffdcdc; border-color: #e6a3a3; color: #8f2f2f; }
@media (max-width: 700px) {
  .odds { font-size: 10px; }
  .odds-row { grid-template-columns: 30px repeat(5, 1fr); }
  .odds-c { padding: 4px 0; }
}

/* --- auto-build preview modal ------------------------------------------- */
.ab-card { width: min(460px, 94vw); }
.ab-scroll { overflow: auto; padding: 2px 14px 4px; }
.ab-sec { margin: 10px 0 4px; }
.ab-sec h4 {
  margin: 0 0 6px; font: 800 10.5px/1 Tahoma, sans-serif;
  text-transform: uppercase; letter-spacing: 0.6px; color: #7b8aa6;
  border-bottom: 1px solid #e2e9f4; padding-bottom: 5px;
}
.ab-row {
  display: grid; grid-template-columns: 1fr 44px 14px 52px 40px;
  align-items: center; gap: 4px;
  padding: 4px 2px; border-bottom: 1px dotted #e8edf6;
  font: 600 11.5px/1.3 Tahoma, sans-serif; color: #23406e;
}
.ab-row.ab-skill { grid-template-columns: 24px 1fr 40px 14px 40px 34px; }
.ab-ic { display: flex; align-items: center; }
.ab-ic canvas { image-rendering: pixelated; }
.ab-n { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ab-a { text-align: right; color: #7b8aa6; }
.ab-arw { text-align: center; color: #9db4d4; font-weight: 800; }
.ab-b { text-align: right; font-weight: 800; color: #1f5c33; }
.ab-d { text-align: right; font: 700 10.5px/1 Tahoma, sans-serif; }
.ab-d.up { color: #2c8a4a; }
.ab-row.same { color: #9aa8c2; border-bottom-color: #f1f4fa; }
.ab-row.same .ab-a { color: #9aa8c2; }
.ab-note { margin: 6px 0 0; font: 500 10.5px/1.4 Tahoma, sans-serif; color: #8a7a52; }
.ab-none {
  margin: 10px 0 0; padding: 9px 11px; border-radius: 7px;
  border: 1px solid #e0c273; background: rgba(255, 246, 222, 0.9);
  font: 600 11.5px/1.5 Tahoma, sans-serif; color: #6b3d00;
}
.ab-acts {
  display: flex; gap: 8px; justify-content: flex-end;
  padding: 11px 14px; border-top: 1px solid #dde5f2; background: #f4f7fc;
}
/* Footer buttons match each other exactly — same height, same type size —
   so Cancel and the primary action read as a pair, not as two strangers. */
.ab-acts button {
  min-width: 104px; padding: 8px 14px; font-size: 12px; line-height: 1;
  border-radius: 6px;
}

.ad-nav { display: flex; gap: 3px; padding: 8px 12px 0; background: var(--face-2); }
.ad-nav-b {
  font-size: 12px; font-weight: 700; padding: 7px 16px; cursor: pointer;
  color: var(--dim); background: var(--face-3);
  border: 1px solid var(--edge-soft); border-bottom: none;
}
.ad-nav-b:hover { background: var(--face); color: inherit; }
.ad-nav-b.on { color: inherit; background: var(--face); box-shadow: inset 0 2px 0 var(--gold); }
/* auto-refresh pill in the admin caption bar */
.ad-auto {
  display: inline-flex; align-items: center; gap: 5px;
  margin-right: 8px; padding: 2px 8px; cursor: pointer;
  font: 700 9px/1.6 Tahoma, sans-serif; letter-spacing: 0.06em; text-transform: uppercase;
  color: #3a4a68; background: rgba(255, 255, 255, 0.6);
  border: 1px solid var(--edge-soft); border-radius: 999px;
}
.ad-auto:hover { background: #fff; }
.ad-auto-d {
  width: 6px; height: 6px; border-radius: 50%; background: #b3bccd;
}
.ad-auto.on .ad-auto-d { background: #35c46a; animation: ad-blip 1.6s ease-in-out infinite; }
@keyframes ad-blip { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }
@media (prefers-reduced-motion: reduce) { .ad-auto.on .ad-auto-d { animation: none; } }
.ad-auto-t { font-weight: 500; text-transform: none; letter-spacing: 0; color: var(--dim); }

/* the two poles of the net chart, named — identity is never colour alone */
.ch-net-key { display: flex; gap: 16px; margin-top: 8px; flex-wrap: wrap; }
.ch-net-k {
  display: inline-flex; align-items: center; gap: 6px;
  font: 500 10.5px/1.4 Tahoma, sans-serif; color: var(--dim);
}
.ch-net-k .sw { width: 10px; height: 10px; border-radius: 2px; flex: none; }

/* a sub-heading inside an admin card, above each chart */
.ad-sub-h {
  margin: 14px 0 6px; font: 800 10px/1 Tahoma, sans-serif;
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--dim);
}

.ad-live {
  font-size: 9px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
  color: #14532d; background: rgba(150, 235, 170, 0.5);
  border: 1px solid #4f9c68; padding: 0 5px; margin-right: 7px;
}

.ad-card {
  margin-bottom: 10px; background: var(--face-2);
  border: 1px solid var(--edge-soft); box-shadow: inset 1px 1px 0 var(--hi);
}
.ad-card-h {
  display: flex; align-items: baseline; gap: 8px;
  padding: 7px 10px; border-bottom: 1px solid var(--edge-soft);
}
.ad-card-h .t { font-size: 12px; font-weight: 700; }
.ad-card-h .s { font-size: 10.5px; color: var(--dim); }
.ad-fine { margin: 0; padding: 0 10px 8px; font-size: 10px; color: var(--dim); }
.ad-two { display: grid; grid-template-columns: 1.3fr 1fr; gap: 10px; }

.ad-feed { padding: 4px 0; max-height: 320px; overflow-y: auto; }
.ad-feed-r {
  display: grid; grid-template-columns: 96px 1fr auto; gap: 8px; align-items: center;
  padding: 4px 10px; font-size: 11.5px;
}
.ad-feed-r:nth-child(odd) { background: rgba(0, 0, 0, 0.025); }
/* A fixed grid track does not clip its contents — anything too wide for the
   column simply draws over the name beside it. Clip it here. */
.ad-when-c {
  font-size: 10.5px; color: var(--dim);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.ad-who { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* The inviter, kept a step quieter than the person who just arrived — it is
   context on the row, not the subject of it. */
.ad-via { margin-left: 7px; font-size: 10px; white-space: nowrap; }
.ad-via .l { color: var(--dim); margin-right: 3px; }
.ad-via .ad-link { font-weight: 400; }
.ad-src { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* The referral tree, one row per person, three levels plus a total. */
.ad-ref-r {
  display: grid; grid-template-columns: 1fr 38px 38px 38px 42px;
  gap: 6px; align-items: center; padding: 4px 10px; font-size: 11.5px;
}
.ad-ref-r:nth-child(even) { background: rgba(0, 0, 0, 0.025); }
.ad-ref-h {
  font-size: 9px; font-weight: 700; letter-spacing: 0.05em;
  text-transform: uppercase; color: var(--dim); background: var(--face-2);
  position: sticky; top: 0; z-index: 1;
}
.ad-ref-h > span { text-align: right; }
.ad-ref-h .pc { margin-left: 3px; font-weight: 400; opacity: 0.75; }
.ad-lv { text-align: right; font-variant-numeric: tabular-nums; }
/* A zero is not news — it should not pull the eye off the level that has depth. */
.ad-lv.nil { color: var(--dim); opacity: 0.45; }
.ad-lv.tot { font-weight: 700; }

/* The submitted post, labelled with what it turned out to be. */
.ad-post { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ad-post .pending { color: var(--dim); font-weight: 400; }
.ad-post .bad { color: #7a1414; }

/* The chart. One series, so no legend — the card heading names it. */
.ch-box { padding: 8px 10px 4px; }
/* The plot is stretched horizontally to fill the card, so nothing with letters
   in it may live inside the SVG. Both axes are HTML laid over/under the plot. */
.ch-plot { position: relative; }
.ch-svg { display: block; width: 100%; height: 100%; }
.ch-y { position: absolute; left: 0; top: 0; bottom: 0; }
.ch-tick {
  position: absolute; right: 5px; transform: translateY(-50%);
  font-size: 9.5px; color: var(--dim); white-space: nowrap;
}
.ch-axis { position: relative; height: 13px; margin-top: 2px; }
.ch-x {
  position: absolute; top: 0; transform: translateX(-50%);
  font-size: 9.5px; color: var(--dim); white-space: nowrap;
}
.ch-empty { padding: 24px; text-align: center; color: var(--dim); font-size: 12px; }

@media (max-width: 900px) {
  .ad-two { grid-template-columns: 1fr; }
  .ad-nav-b { flex: 1; padding: 7px 6px; }
  /* On a phone the heading and its sub-line fight over one line and both wrap
     mid-phrase. Stack them instead. */
  .ad-card-h { flex-wrap: wrap; }
  .ad-card-h .spacer { display: none; }
  .ad-card-h .s { flex-basis: 100%; }
}

/* "You are nearly out of codes." Always drawn, so somebody on their eighth
   invite can see what is coming instead of finding it by accident. */
.ea-topup {
  display: flex; align-items: center; gap: 10px; margin-top: 10px;
  padding: 9px 11px; border: 1px solid var(--edge-soft); background: var(--face-2);
}
.ea-topup.on {
  border-color: var(--gold);
  background: linear-gradient(180deg, rgba(255, 236, 190, 0.7), rgba(255, 219, 140, 0.5));
}
.ea-topup-t { flex: 1; min-width: 0; }
.ea-topup-t strong { display: block; font-size: 12px; }
.ea-topup-t p { margin: 3px 0 0; font-size: 11px; color: var(--dim); }
.ea-topup.on .ea-topup-t strong { color: #4a2f00; }
.ea-topup.on .ea-topup-t p { color: #6d3a00; }
.ea-topup .ea-err { flex-basis: 100%; }

/* ---------------------------------------------------------------------------
   Daily check-in.

   One row per day, and only one of them has a control on it — the open day.
   Everything above it is settled and everything below is locked, so the eye has
   exactly one place to land.
   --------------------------------------------------------------------------- */
.ea-days { display: flex; flex-direction: column; gap: 6px; margin: 12px 0; }
.ea-day {
  display: grid; grid-template-columns: 44px 1fr auto; gap: 10px; align-items: center;
  padding: 8px 10px; border: 1px solid var(--edge-soft); background: var(--face-2);
}
.ea-day.done { border-color: #4f9c68; background: rgba(150, 235, 170, 0.16); }
.ea-day.next {
  border-color: var(--gold);
  background: linear-gradient(180deg, rgba(255, 236, 190, 0.7), rgba(255, 219, 140, 0.5));
}
/* A locked day is still legible — it is the reason to come back tomorrow. */
.ea-day.locked { opacity: 0.62; }
.ea-day-n { text-align: center; line-height: 1; }
.ea-day-n .d { display: block; font-size: 19px; font-weight: 700; }
.ea-day-n .l { font-size: 8px; letter-spacing: 0.12em; color: var(--dim); }
.ea-day.next .ea-day-n .d { color: #6d3a00; }
.ea-day-m { min-width: 0; }
.ea-day-items { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }
.ea-day-r { display: flex; flex-direction: column; align-items: flex-end; gap: 4px; }
.ea-day-s { font-size: 10.5px; color: var(--dim); white-space: nowrap; }
.ea-day-s.ok { color: #14532d; font-weight: 700; }
.ea-day-s.bad { color: #7a1414; font-weight: 700; }
.ea-day-go { display: flex; flex-direction: column; align-items: flex-end; gap: 5px; }

@media (max-width: 560px) {
  /* The reward labels are the first thing to overflow on a phone; give them the
     whole width rather than squeezing three columns. */
  .ea-day { grid-template-columns: 38px 1fr; }
  .ea-day-r { grid-column: 2; align-items: flex-start; }
  .ea-day-go { align-items: flex-start; }
}

/* Map panel: real-map regions */
.region-head { margin: 14px 0 6px; color: #2b4a8a; border-bottom: 1px solid #c9d6ec; padding-bottom: 3px; }
.region-teaser { margin: 6px 0; padding: 5px 9px; background: #eef2f9; border: 1px dashed #c3cfe4; border-radius: 4px; }

/* The belt — party-wide auto-use slots on the dock.
 *
 * The picker used to be `.belt-menu`, a slot-anchored list of wide rows, and its
 * rules outlived it. `.belt-opt .bo-sub { margin-left: auto }` made sense when a
 * tile was a ROW and the effect stat belonged on the right — but the tiles are
 * centred columns now, and an `auto` left margin in a column flex shoves the one
 * line it is set on hard against the right edge. That is why "19 HP" sat off to
 * the side under a centred name. Deleted rather than overridden: the markup it
 * was written for is gone.
 */


/* --- auto-use belt panel (dock) -------------------------------------------- */
.belt-panel {
  border: 1px solid var(--edge-soft); border-radius: 10px;
  background: linear-gradient(180deg, #f2f6fd, #e2eaf7);
  padding: 5px 6px 6px; margin: 2px 0;
}
.belt-head { display: flex; align-items: center; gap: 6px; margin: 0 1px 5px; }
.belt-title { font: 800 9px/1 Tahoma, sans-serif; letter-spacing: 1px; color: #6a7fa6; }
.belt-boost {
  font: 700 9px/1 Tahoma, sans-serif; color: #2f8f3a;
  background: #e2f6e4; border: 1px solid #b6e2ba; border-radius: 8px; padding: 2px 5px;
}
.belt-coin { margin-left: auto; display: flex; align-items: center; gap: 3px; }
.bc-ico {
  width: 14px; height: 14px; border-radius: 50%; flex: none;
  display: flex; align-items: center; justify-content: center;
  background: radial-gradient(circle at 34% 30%, #fff3b0 0%, #f0c33a 45%, #b07d10 100%);
  box-shadow: inset 0 0 0 1px rgba(120, 82, 8, 0.6);
  /* struck, not printed: the letter is the darker metal of the coin face */
  font: 800 9px/1 Tahoma, Verdana, sans-serif;
  color: #6d4a06; text-shadow: 0 1px 0 rgba(255, 243, 176, 0.65);
}
.bc-val { font: 700 11px/1 Tahoma, sans-serif; color: var(--gold); }
/* One currency, one look — see dom.ts zeny(). */
.zeny { display: inline-flex; align-items: center; gap: 4px; vertical-align: baseline; }
.zeny .zv { font-weight: 700; }
.zeny.muted .zv { color: var(--dim); font-weight: 500; }
.zeny.big .bc-ico { width: 22px; height: 22px; font-size: 14px; }
.zeny.big .zv { font: 800 30px/1 Tahoma, sans-serif; color: #2c7a3f; letter-spacing: -0.5px; }
.zeny.b .zv { font: 10px/1.2 "DejaVu Sans Mono", monospace; color: var(--dim); font-weight: 400; }
.zeny.b .bc-ico { width: 10px; height: 10px; font-size: 7px; }
h3 .zeny { margin-left: 2px; }
.h3-sep { margin: 0 6px; color: var(--dim); font-weight: 400; }

.belt-slots { display: flex; gap: 5px; }
.beltslot {
  position: relative; flex: 1 1 0; height: 40px; padding: 2px;
  display: flex; align-items: center; justify-content: center;
  border: 1px solid #aabfdb; border-radius: 8px;
  background: linear-gradient(180deg, #ffffff, #dbe6f6);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.7), 0 1px 2px rgba(40,60,100,0.12);
  cursor: pointer; transition: transform .06s, box-shadow .1s;
}
.beltslot:hover { transform: translateY(-1px); box-shadow: 0 3px 7px rgba(40,60,100,0.22); }
.beltslot:active { transform: translateY(0); }
.beltslot.empty {
  border-style: dashed; background: linear-gradient(180deg,#eef2f9,#e2e8f3);
}
.beltslot .belt-plus { color: #8aa0c4; font-size: 20px; line-height: 1; font-weight: 300; }
.belt-qty {
  position: absolute; right: 2px; bottom: 1px;
  font: 700 9px/1 Tahoma, sans-serif; color: #23406e;
  background: rgba(255,255,255,0.9); border-radius: 3px; padding: 0 3px;
}
.belt-qty.none { color: #c23a3a; }


/* --- belt picker: centred modal with search ------------------------------- */
.belt-modal {
  position: fixed; inset: 0; z-index: 5000;
  display: flex; align-items: center; justify-content: center;
  background: rgba(18, 28, 48, 0.5); backdrop-filter: blur(1.5px);
}
.belt-card {
  width: min(500px, 92vw); max-height: 82vh; display: flex; flex-direction: column;
  background: linear-gradient(180deg, #fbfdff, #eef3fb);
  border: 1px solid #9db4d4; border-radius: 12px;
  box-shadow: 0 18px 50px rgba(15, 30, 65, 0.4);
  overflow: hidden;
}
.belt-mhead {
  display: flex; align-items: center; padding: 11px 14px;
  background: linear-gradient(180deg, #e7eefb, #d6e1f3); border-bottom: 1px solid #c2d0e8;
}
.belt-mtitle { font: 800 13px/1 Tahoma, sans-serif; color: #23406e; letter-spacing: 0.3px; }
/* One close button for every modal that has one. The `ro` base class dresses
   buttons in a 3D gradient with inset shadows — right for chunky action
   buttons, wrong for a small dismiss control, where it read as a fat square
   with a floating x. Flat, round-cornered, glyph dead-centre. */
.belt-mx {
  margin-left: auto; width: 24px; height: 24px; border-radius: 6px;
  border: 1px solid #c2d0e8; background: #fff; color: #5a6f92;
  font: 700 15px/1 Tahoma; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  padding: 0; box-shadow: none;
}
.belt-mx:hover { background: #ffe9e9; color: #c23a3a; border-color: #e8b6b6; }
.belt-search {
  margin: 10px 12px 6px; padding: 9px 11px;
  border: 1px solid #b6c6e0; border-radius: 8px;
  font: 500 13px/1 Tahoma, sans-serif; color: #23406e; background: #fff;
}
.belt-search:focus { outline: none; border-color: #6d92d6; box-shadow: 0 0 0 3px rgba(109,146,214,0.2); }
.belt-list {
  overflow: auto; padding: 8px 10px 10px;
  display: grid; grid-template-columns: repeat(auto-fill, minmax(104px, 1fr)); gap: 6px;
  align-content: start;
}
.belt-opt {
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  padding: 10px 6px 8px; margin: 0; border: 1px solid #d5dfef;
  background: #fff; text-align: center; border-radius: 8px; cursor: pointer;
}
.belt-opt:hover { background: #e6eefb; border-color: #a9c0e2; }
.belt-opt.current { background: #e2f0e4; border-color: #7fc48a; box-shadow: inset 0 0 0 1px #b6e0bb; }
.belt-opt .bo-none {
  width: 28px; height: 28px; line-height: 28px;
  text-align: center; color: #9aa8c2; font-size: 20px;
}
.belt-opt .bo-name { font: 700 11px/1.15 Tahoma, sans-serif; color: #23406e; }
.belt-opt .bo-sub { font: 500 10px/1.2 Tahoma, sans-serif; color: #6b7f9e; }
.belt-opt .bo-own { font: 600 10px/1.2 Tahoma, sans-serif; color: #4a7d52; min-height: 12px; }
.belt-empty { grid-column: 1 / -1; padding: 18px; text-align: center; color: #8090ab; font: 500 12px Tahoma; }
.belt-hint {
  padding: 9px 14px 12px; font: 500 11px/1.4 Tahoma, sans-serif; color: #6b7f9e;
  border-top: 1px solid #dde5f2;
}

/* --- pickup lines ------------------------------------------------------- */
/* The classic Ragnarok drop notice: icon + "<name> - <n> obtained.", stacked
   over the field. pointer-events:none so they never eat a click meant for the
   battlefield underneath. */
.pickups {
  position: absolute; left: 10px; bottom: 8px; z-index: 6;
  display: flex; flex-direction: column-reverse; gap: 3px;
  pointer-events: none;
}
.pickup {
  display: flex; align-items: center; gap: 6px;
  padding: 3px 9px 3px 4px;
  background: rgba(22, 26, 38, 0.82);
  border: 1px solid rgba(255, 255, 255, 0.16);
  border-radius: 4px;
  font-size: 12px; color: #eef1f7;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.8);
  animation: pickup-in 260ms cubic-bezier(0.2, 1.3, 0.4, 1) both;
}
.pickup.card { border-color: rgba(255, 214, 92, 0.7); color: #ffe08a; }
.pickup.out { animation: pickup-out 380ms ease-in both; }
.pickup-ic { display: flex; width: 20px; height: 20px; }
.pickup-ic canvas { image-rendering: pixelated; }
@keyframes pickup-in {
  from { opacity: 0; transform: translateX(-14px) scale(0.94); }
  to   { opacity: 1; transform: none; }
}
@keyframes pickup-out {
  from { opacity: 1; transform: none; }
  to   { opacity: 0; transform: translateY(-8px); }
}
@media (prefers-reduced-motion: reduce) {
  .pickup, .pickup.out { animation-duration: 1ms; }
}
/* a net loss on the offline report reads red, not as a win */
.away-stat.bad .av { color: #c0392b; }
/* --- bulk-sell review --------------------------------------------------- */
.sell-list { max-height: 46vh; overflow-y: auto; margin: 8px 0;
             border: 1px solid var(--line); border-radius: 4px; }
.sell-row { display: flex; align-items: center; gap: 8px; padding: 4px 8px; }
.sell-row + .sell-row { border-top: 1px solid var(--line); }
.sell-row canvas { image-rendering: pixelated; flex: 0 0 auto; }
.sell-row .nm { flex: 1 1 auto; font-size: 13px; }
.sell-row .qt { flex: 0 0 auto; font-size: 12px; color: var(--dim); }
.sell-row .zn { flex: 0 0 auto; font-size: 12px; font-weight: 700; min-width: 62px;
                text-align: right; }
.sell-foot { display: flex; align-items: center; gap: 8px; }
.sell-foot .sum { flex: 1 1 auto; font-size: 13px; font-weight: 700; }
/* auto-cast level stepper: learned level vs the level actually cast */
.prio-lv { display: flex; align-items: center; gap: 3px; margin-left: 6px; }
.prio-lv button { min-width: 20px; padding: 0 5px; line-height: 18px; }
.prio-lvn { font-size: 12px; width: 58px; flex: none; text-align: center; font-variant-numeric: tabular-nums; }
.prio-lvn.cut { color: #b8860b; font-weight: 700; }
/* a listed-but-unbuilt sidebar entry */
.side-item.soon { opacity: 0.72; cursor: default; }
.side-item.soon:hover { background: none; }
.si-soon { margin-left: auto; font-size: 10px; font-weight: 700; letter-spacing: .04em;
           text-transform: uppercase; color: #fff; background: #c0392b;
           border-radius: 3px; padding: 1px 5px; }


/* ---------------------------------------------------------------------------
   Cursors — the client's own.

   Ragnarok ships its pointer as a sprite, and the browser default arrow beside
   this art looks like a screenshot of two different programs. Three frames off
   the official cursor sheet, inlined as data URLs so they cost no request and
   cannot 404: the arrow for everything outside the game, and the pointing hand
   inside it, with the closed hand while a button is down.

   The hotspot is the fingertip / arrow tip in the trimmed image, not the
   corner of the box — `url(...) X Y` where X and Y are that pixel. Get it
   wrong and every click lands a few pixels off where the player aimed.

   `, default` / `, pointer` at the end is the fallback: if the data URL is
   ever rejected the interface still has a working cursor.
   --------------------------------------------------------------------------- */
html, body {
  cursor: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAeCAYAAAAo5+5WAAABP0lEQVR42q3WP2rDMBTH8a+M16wZYjJnyAWyeAi5QEBkMPgCntohB6mnXqDQJb1CBnfJXMgNnFzjdamL/0m28RMIjCw+/Hh6wjaAAIiIQXEEAJeixBgj6jDAwZ5V8bB6yF5eWSzXGGNEoyxBe+GY5SrJ/2EbRwCstjsVvJE4Tawa3oBtHPG831TwTo2r1HPxDlxPPQcPxmxabXeT+7wXThPbSA2w2Z8m4WHfoo0jPj6765v9CWDUJXKWoi/1lOSh64UrdYUPXX/v4blSj+kWL1xdc1+3uPDBdvOl9uHB2L583m/esrQPNBwC24fowtutGI5JmyaW689jcF8dH4S/vh+8528ALJbrQby+Ry5FKX3jUpRysGf5+5KPniLihuuoiDB19sJz0V5YA+3AWmgD1kQb8DHL1VARwVQ/hdo/hr/zXBs3TXosLQAAAABJRU5ErkJggg==") 1 1, default;
}

/* Inside the game proper. The select, create and login screens are menus and
   keep the arrow — see the resets below. */
/* The element selectors are not padding. `.shell *` is one class and one
   universal, which loses to `button.ro { cursor: pointer }` — so every button
   in the game, which is most of what a player's pointer is ever over, kept the
   browser's own hand instead of Ragnarok's. These tie on specificity and win
   on source order. */
.shell, .shell *,
.shell button, .shell select, .shell a, .shell input, .shell canvas {
  cursor: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAWCAYAAADeiIy1AAABeklEQVR42q1Wu23DMBC9I9TbsEtpBrfpBBgZIECgNjskE2SEZBAmgAcwDLBz6xnoUoY8wUthn0JKPEv+POAKiTo93uPjkQyArgUzt0kAeExONpQYjgms873xMYSwzkNwygGdK0XdIIJ1HtZ51A3asM5HeakwPVaAmBnMDOs8zSbx+HKRExHRZreP3lnnk9ULTOpl3SCSh4jocDxFSNadwEUykSiUTyCyhM9DocnI4jpmRt2gJ9XheJIpVYWG+ZR75jCh2+ZTbuURzCZ0FYm4siuh6ciYJHsEssSascj4SBhtILTvtVgucnr7/InkM4oTuSqLu8henp/GVXQPNrs9VWURtSijNc3uhh3C+9dvq8BykUebnpmRPWL2q/WWvj9e1W5RlQVlY36k7SONJLW2ZuysU1itt71F735blQUB4ExznSyi6KyRhdVecqkqnfSqS60/NEyKRKohov+meutxLh1Ek2ywosFj+Sxv1yyyf3pXglsr0u4U2t3hD8FScS9g0OmhAAAAAElFTkSuQmCC") 2 1, pointer;
}
.shell *:active, .shell button:active, .shell a:active {
  cursor: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAUCAYAAACTQC2+AAABbUlEQVR42q1VMXKDMBDcY+g94xbekDKdmXG+YF5B3pBfkLwgJf6CmcEVKfUGVMYTv+BSmGPEIQSxcx2HpNWt9vaImREKIhotqJpu9D/PUgAAM1PonFgfJhskpy9yPFsAwGGXAAC+fxi1sSAiDoHFRMRF2U4qKMoWL0/JZMO+zx3PFoddgu3mlquaLghGALgoW7y/PgMALtfbj9rY0eHbzXijrHOjNhZ5lnppjHVCDpSb18YOoHtPhbraucoizb0LKLQsAfionVDHzMO7VE03oclH0VL4KIy10gTsvyNyP5iZ8iwdCeHeKMp21DaRXiBgb59fDwHp1ohCC/8CptXpKnAQg892XKsJvVltLE7GDn2oRSTCiO+Vqwvi0qTbZJG6NSEg4ntzIEGgU8/3nAIlvwbEa0GiPCLij76JQ3K/XDHxQT1GmJlm30iPC99MkrdZ4x6LYvA5sQsechLXhmhpwi6FboW5qfswkI9eHwu/aGvgAZsKTUsAAAAASUVORK5CYII=") 2 1, pointer;
}
/* Everything on the login screen takes the root's cursor, spin included —
   otherwise the `cursor: pointer` on its buttons would stop the animation
   exactly where the pointer spends most of its time. */
.login-wrap, .login-wrap * { cursor: inherit; }

/* Text entry keeps a caret; a hand over a field you are typing in is a lie. */
.shell input[type="text"], .shell input[type="search"], .shell textarea,
.shell input[type="text"]:active, .shell textarea:active {
  cursor: text;
}
/* The login screen is deliberately NOT in this list: its pointer is the
   client's spinning one, driven from cursor.ts, and it is set as an inline
   style on the login root. A rule here would beat that inline value on every
   descendant and the spin would only be visible over the backdrop. */
.cs-scene, .cs-scene *, .mk-scene, .mk-scene *,
.belt-modal, .belt-modal * {
  cursor: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAeCAYAAAAo5+5WAAABP0lEQVR42q3WP2rDMBTH8a+M16wZYjJnyAWyeAi5QEBkMPgCntohB6mnXqDQJb1CBnfJXMgNnFzjdamL/0m28RMIjCw+/Hh6wjaAAIiIQXEEAJeixBgj6jDAwZ5V8bB6yF5eWSzXGGNEoyxBe+GY5SrJ/2EbRwCstjsVvJE4Tawa3oBtHPG831TwTo2r1HPxDlxPPQcPxmxabXeT+7wXThPbSA2w2Z8m4WHfoo0jPj6765v9CWDUJXKWoi/1lOSh64UrdYUPXX/v4blSj+kWL1xdc1+3uPDBdvOl9uHB2L583m/esrQPNBwC24fowtutGI5JmyaW689jcF8dH4S/vh+8528ALJbrQby+Ry5FKX3jUpRysGf5+5KPniLihuuoiDB19sJz0V5YA+3AWmgD1kQb8DHL1VARwVQ/hdo/hr/zXBs3TXosLQAAAABJRU5ErkJggg==") 1 1, default;
}

/* ===========================================================================
   PHONE OVERRIDES — THIS BLOCK MUST STAY LAST IN THE FILE.

   A media query adds no specificity. Every rule below targets a selector whose
   base declaration appears further down this stylesheet than the narrow block
   it used to live in, so the base simply won on source order and the fix
   silently did nothing — the region chip bar stayed on screen next to the
   dropdown that was meant to replace it, the hero portrait kept its own empty
   line, and the pickup notices stayed desktop-sized. Anything added here has
   to stay at the bottom, after every base rule it is correcting.

   Nothing in this file below 620px affects the desktop layout.
   =========================================================================== */

@media (max-width: 900px) {
  /* The 46px icon rail: both of these are `margin-left: auto` pills built for
     a labelled row and are wider than the rail itself. */
  .si-soon { display: none; }
  .si-new {
    position: absolute; top: 3px; right: 3px; margin: 0;
    min-width: 14px; height: 14px; padding: 0 3px; font-size: 9px;
  }
  /* NOT one column. Stacking the paper doll's three columns turned the slots
     into a single tall ladder and pushed the character out of view — the one
     thing the screen exists to show. Keep the shape, shrink the parts. */
  .doll { grid-template-columns: auto minmax(96px, 1fr) auto; gap: 4px; padding: 4px 0 2px; }
  .doll-stage { width: auto; min-height: 160px; padding-bottom: 8px; }
  .doll-cell .slot { width: 40px; height: 40px; }
  .doll-cell .slot-label { font-size: 8px; }
}

@media (max-width: 620px) {
  /* Party dots, the belt and the Show party button in one row is about 470px
     of content in 350px of phone. Stack them. */
  .bar-right { flex-direction: column; align-items: stretch; }
  .bar-right > .belt-panel { width: 100%; }
  .bar-right > button.expand { width: 100%; }

  /* The hero banner: `.hero-main` asked for a 420px basis, so it wrapped under
     the portrait and left the portrait alone on a line with 240px of nothing
     beside it. `auto` was not enough — that is still the content's own width,
     which is wider than what is left after a 64px avatar, so it kept wrapping.
     A basis of ZERO is the one that says "take whatever is left". */
  .hero-main { flex: 1 1 0; }
  .hero { gap: 8px; padding: 6px 8px; align-items: center; }
  /* One line, not two. The name gives way before the level chips do — the
     chips are the numbers you came to read and they are unambiguous truncated
     to nothing, whereas half a name is just wrong. The job is dropped here
     because it is already on the strip above and on the JOB row below; on this
     screen it was the third copy. */
  .hero-line { flex-wrap: nowrap; gap: 5px; }
  .hero-name {
    font-size: 15px; min-width: 0;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .hero-job { display: none; }
  .hero-lv { white-space: nowrap; flex: none; font-size: 9px; padding: 2px 6px; }

  /* Pickup notices are sized for a 1050px field; on a 330px one two of them
     cover the party they came from. */
  .pickup { font-size: 10px; padding: 2px 7px 2px 3px; gap: 4px; border-radius: 3px; }
  .pickup-ic { width: 15px; height: 15px; }
  .pickup-ic canvas { width: 15px; height: 15px; }
  .pickups { left: 6px; bottom: 5px; gap: 2px; }

  /* One chip per region is twenty-odd chips, and they filled the screen before
     a single map was visible. The select carries the same list in one row. */
  .map-regions { display: none; }
  .map-select { display: block; }
  .map-row-mobs { white-space: normal; overflow: visible; }

  /* The character strip folds to the one you are on — see panels.ts. */
  .char-select { flex-direction: column; align-items: stretch; flex-wrap: nowrap; gap: 4px; }
  .char-select > .cpick { width: 100%; }
  .char-select:not(.open) > .cpick:not(.active) { display: none; }
  .cp-fold {
    display: block; width: 100%; margin: 0; padding: 7px 10px; cursor: pointer;
    font: 700 11px/1.2 Tahoma, sans-serif; color: var(--link); text-align: center;
    background: var(--face-2);
    border: 1px dashed var(--edge-soft); border-radius: 5px;
  }
  .cp-fold:active { background: #e6eefb; }

  /* Party tab: four mini cards on one 302px row is four clipped cards. */
  .cs-cards.mini { gap: 6px; }
  .cs-cards.mini .cs-cell { flex: 1 1 80px; min-width: 0; }
  .cs-cards.mini .cs-card { width: 100%; }
  .cs-cards.mini .cs-canvas { width: 100%; height: 108px; }
  .cs-cards.mini .cs-tab { width: 100%; }
  .cs-cards.mini .cs-plate { margin: 4px 0 0; }
}

/* The watchlist row: wallet | map | badges | gross | rate, on ONE line.
   Its own grid because .wl-row is a fixed 4-column layout and a fifth child
   wraps into the wrong cells. The badges own the flexible middle — the space
   that was previously blank — and the two numbers sit right-aligned where
   numbers belong. */
.watch-row {
  display: grid; align-items: center; gap: 8px;
  grid-template-columns: 92px 92px minmax(0, 1fr) 84px 72px;
  padding: 5px 6px; font-size: 11.5px;
  border-bottom: 1px solid var(--edge-soft);
}
.watch-row:last-child { border-bottom: none; }
.watch-row .ad-num { text-align: right; }
.watch-row .ad-sub.num { text-align: right; font-variant-numeric: tabular-nums; }

/* Watchlist badges: color says temperature, the title says why. */
.ad-badges { display: inline-flex; gap: 4px; flex-wrap: wrap; min-width: 0; }
.ad-badge {
  font-size: 9px; font-weight: 800; letter-spacing: 0.05em;
  padding: 2px 6px; border-radius: 3px; border: 1px solid transparent; cursor: help;
}
.ad-badge.calm { color: #3a6ea5; background: #e8eef7; border-color: #b9cbe4; }
.ad-badge.warm { color: #7a5c0c; background: #f7efd8; border-color: #dcc37a; }
.ad-badge.hot  { color: #fff;    background: #c0392b; border-color: #8e2a1f; }
.mono { font-family: ui-monospace, monospace; font-size: 11px; }

/* The boot splash is the map-load plate promoted to the whole viewport. It
   exists before the game shell does, so it pins to the screen, not to a bar
   that has not been built yet. */
.mapload.boot { position: fixed; inset: 0; z-index: 40; }
.ml-fill.sweep {
  width: 34%;
  animation: ml-sweep 1.1s ease-in-out infinite alternate;
}
@keyframes ml-sweep {
  from { margin-left: 0; }
  to   { margin-left: 66%; }
}

.save-flag {
  font-size: 10px; font-weight: 800; color: #7a5c0c;
  background: #f7efd8; border: 1px solid #dcc37a; border-radius: 3px;
  padding: 1px 6px; margin-left: 4px;
}

/* The Kafra fare dialog: small, one decision. */
.warp-card { max-width: 360px; }
.warp-body { padding: 12px 14px 4px; }
.warp-dest { font-weight: 800; font-size: 14px; color: var(--txt); margin-bottom: 8px; }
.warp-fare { background: var(--face); border: 1px solid var(--edge-soft); padding: 9px 11px; }
.warp-line { font-weight: 700; font-size: 12.5px; font-variant-numeric: tabular-nums; }
.warp-sub { font-size: 11px; color: var(--muted); margin-top: 4px; }
.warp-sub.bad { color: #c0392b; font-weight: 700; }

/* Marketplace */
.mkt-wallet {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin: 8px 0; padding: 8px 10px;
  background: var(--face); border: 1px solid var(--edge-soft); border-radius: 5px;
}
.mw-bal { font-weight: 800; font-size: 12.5px; font-variant-numeric: tabular-nums; }
.mw-sub { font-size: 11px; color: var(--muted); margin-right: auto; }
.mkt-claim {
  display: flex; align-items: center; gap: 10px; justify-content: space-between;
  margin: 6px 0; padding: 8px 10px; font-size: 11.5px;
  background: #f7efd8; border: 1px solid #dcc37a; border-radius: 5px; color: #6b4e00;
}
.mk-tabs { display: flex; gap: 4px; flex-wrap: wrap; margin: 6px 0; }
.mkt-list { border: 1px solid var(--edge-soft); background: var(--face); border-radius: 4px; }
.mkt-row {
  display: grid; grid-template-columns: 26px minmax(0,1fr) 74px minmax(96px, auto) auto;
  gap: 8px; align-items: center; padding: 4px 8px; font-size: 11.5px;
  border-bottom: 1px solid var(--edge-soft);
}
.mkt-ico {
  width: 24px; height: 24px; display: flex; align-items: center; justify-content: center;
  background: var(--face-2); border: 1px solid var(--edge-soft); border-radius: 3px;
}
.mkt-bar { display: flex; gap: 5px; align-items: center; margin: 6px 0; flex-wrap: wrap; }
.mkt-in.grow { flex: 1 1 160px; min-width: 0; width: auto; }
.mkt-row:last-child { border-bottom: none; }
.mkt-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mkt-kind { color: var(--muted); font-size: 10px; }
.mkt-price { text-align: right; font-weight: 700; font-variant-numeric: tabular-nums; color: #7a5c0c; }
.mkt-sold { font-size: 10px; color: var(--muted); }
.mkt-in {
  width: 92px; padding: 4px 6px; font: 600 11.5px/1 Tahoma, sans-serif;
  border: 1px solid var(--edge); border-radius: 3px;
}
.mkt-in.wide { width: 100%; margin-top: 6px; box-sizing: border-box; }

/* Marketplace stalls: a tile per listing, Kafra-shop family resemblance. */
.mkt-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(148px, 1fr));
  gap: 6px; margin-top: 6px;
}
.mkt-tile {
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  padding: 9px 8px 7px; cursor: pointer; text-align: center;
  font: inherit; color: var(--txt);
  background: linear-gradient(180deg, #ffffff, var(--face-2));
  border: 1px solid var(--edge-soft); border-radius: 5px;
  box-shadow: inset 0 1px 0 #fff;
}
.mkt-tile:hover:not(:disabled) {
  border-color: #7fae7f; box-shadow: 0 0 0 1px rgba(110,170,110,0.35), inset 0 1px 0 #fff;
  transform: translateY(-1px);
}
.mkt-tile.mine { opacity: 0.65; cursor: default; }
.mkt-tile-ico {
  width: 48px; height: 48px; display: flex; align-items: center; justify-content: center;
  background: var(--face); border: 1px solid var(--edge-soft); border-radius: 4px;
}
.mkt-tile-ico canvas, .mkt-hero-ico canvas { image-rendering: pixelated; }
.warp-body .tip-body { margin: 8px 0 4px; width: 100%; box-sizing: border-box; }
.mkt-tile-name {
  font-size: 11px; font-weight: 700; line-height: 1.25; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; max-width: 100%;
}
.mkt-tile-cards { font-size: 9px; color: #7a3fa0; font-weight: 700; }
.mkt-tile-slots { font-size: 9px; color: #7a3fa0; font-weight: 700; }
.mkt-tile-price { font-size: 12.5px; font-weight: 800; color: #7a5c0c; font-variant-numeric: tabular-nums; }
.mkt-tile-kind { font-size: 9px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.05em; }
.mkt-ico.inline { display: inline-flex; vertical-align: middle; margin-right: 4px; }
.mkt-sub-price { font-size: 10px; color: var(--muted); text-align: right; }

.map-row-act .lock-reason { display: inline-flex; align-items: center; gap: 3px; white-space: nowrap; }

.warp-qrow { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
.warp-qlab { font-size: 11px; font-weight: 700; color: var(--muted); }
.warp-qrow .mkt-in { width: 90px; }

/* Marketplace — list modal, gamified */
.mkt-hero { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.mkt-hero-ico {
  width: 46px; height: 46px; display: flex; align-items: center; justify-content: center;
  background: linear-gradient(180deg, #fbfdff, #e8eef7);
  border: 1px solid #b9cbe4; border-radius: 6px; box-shadow: inset 0 1px 0 #fff;
}
.mkt-hero-name { font-weight: 800; font-size: 15px; color: var(--txt); }
.mkt-hero-sub { font-size: 11px; color: var(--muted); margin-top: 2px; }
.mkt-take {
  margin-top: 8px; padding: 8px 10px; border-radius: 6px;
  background: linear-gradient(180deg, #f2f8ef, #e6f1e0);
  border: 1px solid #a9cf9a; font-size: 12px; color: #2f5522;
}
.mkt-take-k { font-weight: 700; }
.mkt-take-v { font-weight: 800; font-size: 14px; color: #1d6b34; font-variant-numeric: tabular-nums; }
.mkt-take-x { color: #5a7a4e; }

/* My Shop bag rows: NPC price wears the coin, List button reads as an action */
.mkt-sub-price { font-size: 10.5px; color: var(--muted); text-align: right; font-variant-numeric: tabular-nums; }

/* My Shop: interactive bag rows + status pills */
.mkt-row:hover { background: rgba(120,170,110,0.08); }
.mkt-status {
  font-size: 9.5px; font-weight: 800; letter-spacing: 0.05em; text-align: center;
  padding: 2px 6px; border-radius: 3px; white-space: nowrap;
}
.mkt-status.open { color: #1d5e8a; background: #e6f0f8; border: 1px solid #b9cbe4; }
.mkt-status.sold { color: #2f7a3a; background: #e8f4e6; border: 1px solid #a9cf9a; }

/* My Shop — shelves and the bag share Browse's tile family (no more dead full-width rows). */
.mkt-tile { position: relative; }
.mkt-grid.shelves { margin-bottom: 10px; }
.mkt-tile.shelf {
  cursor: default; padding-top: 20px; gap: 4px;
  background: linear-gradient(180deg, #ffffff, #eef4fb); border-color: #c4d4e8;
}
.mkt-tile.shelf.sold { background: linear-gradient(180deg, #f4faf1, #e6f2e2); border-color: #b6d6a8; }
.mkt-tile.shelf:hover { transform: none; box-shadow: inset 0 1px 0 #fff; border-color: #c4d4e8; }
.mkt-tile.shelf.sold:hover { border-color: #b6d6a8; }
.mkt-tile-status {
  position: absolute; top: 5px; left: 50%; transform: translateX(-50%);
  font-size: 8.5px; font-weight: 800; letter-spacing: 0.04em; white-space: nowrap;
  padding: 1px 8px; border-radius: 8px;
}
.mkt-tile-status.open { color: #1d5e8a; background: #e6f0f8; border: 1px solid #b9cbe4; }
.mkt-tile-status.sold { color: #2f7a3a; background: #e8f4e6; border: 1px solid #a9cf9a; }
.mkt-tile-note { font-size: 9px; color: var(--muted); }
.mkt-tile-act { width: 100%; margin-top: 2px; }
.mkt-tile.sell { padding-top: 9px; }
.mkt-tile-meta { display: flex; gap: 5px; align-items: center; justify-content: center; flex-wrap: wrap; }
.mkt-tile-qty {
  font-size: 9px; font-weight: 800; color: #444; background: var(--face);
  border: 1px solid var(--edge-soft); border-radius: 7px; padding: 0 5px;
}
.mkt-tile-npc { font-size: 10px; color: var(--muted); font-variant-numeric: tabular-nums; }
.mkt-tile-list {
  margin-top: 3px; font-size: 9.5px; font-weight: 800; letter-spacing: 0.04em;
  text-transform: uppercase; color: #2f7a3a; background: #eaf6e6;
  border: 1px solid #bfe0b0; border-radius: 8px; padding: 2px 9px;
}
.mkt-tile.sell:hover .mkt-tile-list { background: #2f7a3a; color: #fff; border-color: #2f7a3a; }

/* Kafra Reset — two option cards, same family as the shop tiles. */
.reset-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 10px; margin-top: 10px; }
.reset-card {
  display: flex; flex-direction: column; gap: 7px; align-items: flex-start;
  padding: 14px; border: 1px solid var(--edge-soft); border-radius: 6px;
  background: linear-gradient(180deg, #ffffff, var(--face-2)); box-shadow: inset 0 1px 0 #fff;
}
.reset-title { font-weight: 800; font-size: 14px; color: var(--txt); }
.reset-blurb { font-size: 11.5px; color: var(--muted); line-height: 1.4; }
.reset-price {
  font-size: 13px; font-weight: 800; color: #7a5c0c; font-variant-numeric: tabular-nums;
  padding: 2px 9px; border-radius: 8px; background: #fbf2da; border: 1px solid #e6d6a6;
}
.reset-price.free { color: #2f7a3a; background: #eaf6e6; border-color: #bfe0b0; }
.reset-card .ro.good { margin-top: 2px; }

/* Official item flavor text in the info box. */
.tip-flavor { font-size: 10.5px; color: var(--muted); font-style: italic; margin-top: 5px; line-height: 1.4; }

/* Daily quests — the request board. */
.q-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(215px, 1fr)); gap: 10px; margin-top: 10px; align-items: start; }
@media (min-width: 1280px) { .q-grid { grid-template-columns: repeat(5, minmax(0, 1fr)); } }
.q-card {
  display: flex; flex-direction: column; gap: 7px; padding: 10px 11px 11px;
  border: 1px solid var(--edge-soft); border-top-width: 3px; border-radius: 6px;
  background: linear-gradient(180deg, #ffffff, var(--face-2)); box-shadow: inset 0 1px 0 #fff;
}
.q-card.t-small { border-top-color: #4f9b5a; }
.q-card.t-medium { border-top-color: #3f74c4; }
.q-card.t-large { border-top-color: #b8860b; }
.q-prog {
  margin-left: auto; font-size: 10px; font-weight: 800; font-variant-numeric: tabular-nums;
  color: var(--muted); background: var(--face); border: 1px solid var(--edge-soft);
  border-radius: 8px; padding: 1px 7px;
}
.q-prog.full { color: #2f7a3a; background: #eaf6e6; border-color: #bfe0b0; }
.q-bar { height: 4px; border-radius: 2px; background: var(--face); border: 1px solid var(--edge-soft); overflow: hidden; }
.q-bar-fill { display: block; height: 100%; background: linear-gradient(90deg, #7fae7f, #4f9b5a); transition: width 0.2s; }
.q-card.done { opacity: 0.62; background: linear-gradient(180deg, #f4faf1, #e6f2e2); border-color: #b6d6a8; }
.q-top { display: flex; align-items: center; gap: 7px; }
.q-tier {
  width: 20px; height: 20px; display: inline-flex; align-items: center; justify-content: center;
  font-size: 10.5px; font-weight: 800; border-radius: 5px; color: #fff;
}
.q-tier.t-small { background: #4f9b5a; }
.q-tier.t-medium { background: #3f74c4; }
.q-tier.t-large { background: #b8860b; }
.q-title { font-weight: 800; font-size: 12.5px; }
.q-items { display: flex; flex-direction: column; gap: 3px; }
.q-item { display: grid; grid-template-columns: 24px minmax(0,1fr) auto; gap: 6px; align-items: center; font-size: 11px; }
.q-item .q-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.q-item .q-have { font-variant-numeric: tabular-nums; font-weight: 700; color: #a03d3d; }
.q-item.ok .q-have { color: #2f7a3a; }
.q-ico { width: 24px; height: 24px; display: inline-flex; align-items: center; justify-content: center;
  background: var(--face); border: 1px solid var(--edge-soft); border-radius: 3px; }
.q-ico canvas { image-rendering: pixelated; }
.q-reward { display: flex; align-items: center; gap: 7px; font-size: 11.5px; padding-top: 5px; border-top: 1px dashed var(--edge-soft); }
.q-rlab { font-size: 9.5px; font-weight: 800; letter-spacing: 0.05em; color: var(--muted); text-transform: uppercase; }
.q-rline b { color: #7a5c0c; }
.q-rline .q-ico { width: 20px; height: 20px; vertical-align: middle; }

/* --- Swap (in-game AMM) panel --------------------------------------------- */
.sw-head { display: flex; align-items: center; gap: 7px; margin: 0 0 2px; }
.sw-head h3 { margin: 0; }
.sw-closed {
  margin: 8px 0; padding: 8px 10px; border-radius: 8px;
  background: rgba(123, 148, 206, 0.12); border: 1px solid var(--slot-edge);
  font-size: 12px; color: var(--dim);
}
.sw-closed.bad { background: rgba(163, 32, 32, 0.10); border-color: rgba(163,32,32,0.35); color: var(--red); }
.sw-seg { display: flex; gap: 6px; margin: 10px 0 8px; }
.sw-tab {
  flex: 1; padding: 8px 6px; border-radius: 8px; cursor: pointer;
  border: 1px solid var(--slot-edge); background: var(--slot);
  font-size: 12px; font-weight: 700; color: var(--dim); font-family: inherit;
}
.sw-tab.on { border-color: var(--gold); background: rgba(255, 214, 120, 0.35); color: #6d3a00; }
.sw-amt { display: flex; gap: 6px; margin: 4px 0 8px; }
.sw-in {
  flex: 1; padding: 9px 10px; border-radius: 8px; border: 1px solid var(--slot-edge);
  background: var(--slot); font-size: 14px; font-weight: 700; color: var(--txt); font-family: inherit;
}
.sw-max {
  padding: 0 12px; border-radius: 8px; border: 1px solid var(--gold);
  background: rgba(255, 214, 120, 0.45); color: #6d3a00; font-weight: 700; cursor: pointer;
}
.sw-det { margin: 2px 0 10px; }
.sw-line { display: flex; justify-content: space-between; align-items: baseline; padding: 3px 0; }
.sw-line .k { font-size: 11.5px; color: var(--dim); }
.sw-line .v { font-size: 13px; font-weight: 700; color: var(--txt); }
.sw-cta { text-align: center; }
.sw-cta .small { margin-top: 6px; }

/* Swap headline: rate + fee, big */
.sw-hl { display: flex; gap: 8px; margin: 10px 0 4px; }
.sw-hl-t {
  flex: 1; text-align: center; padding: 10px 8px; border-radius: 10px;
  background: rgba(255, 214, 120, 0.22); border: 1px solid var(--gold);
}
.sw-hl-v { font-size: 22px; font-weight: 800; color: #6d3a00; line-height: 1.1; }
.sw-hl-k { font-size: 11px; color: var(--dim); margin-top: 3px; text-transform: uppercase; letter-spacing: 0.4px; }

/* Admin: verified earned vs client-claimed zeny */
.ad-zc { display: flex; flex-direction: column; align-items: flex-end; line-height: 1.15; }
.ad-zc .v { font-weight: 700; }
.ad-zsub { font-size: 10px; color: var(--dim); }
.ad-zsub.bad { color: var(--red); font-weight: 700; }
