:root {
  --bg: #12100e;
  --panel: #1c1916;
  --line: #2f2a24;
  --ink: #e8e2d8;
  --dim: #9a9088;
  --gold: #c8a45c;
  --gold-hi: #e0bc74;
  --bad: #d4674f;
  --good: #6fae72;
  --radius: 10px;

  /* The GM window's palette, read off the game's own skins: 0xaf9b73 is what every
     eui Label in resource/skins uses for body text, 0xff9b0f for anything active. */
  --tan: #af9b73;
  --amber: #ff9b0f;
  --pale: #cdc8be;
  --mute: #998563;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  background: var(--bg);
  color: var(--ink);
  font: 15px/1.5 -apple-system, BlinkMacSystemFont, "PingFang SC", "Microsoft YaHei", sans-serif;
  -webkit-text-size-adjust: 100%;
}

/* ---------- gate: login, register, pay receipt ---------- */

body.gate {
  display: grid;
  place-items: center;
  padding: 24px;
  background:
    radial-gradient(120% 80% at 50% -10%, #2a211a 0%, transparent 60%),
    var(--bg);
}

.card {
  width: 100%;
  max-width: 360px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 28px 24px 24px;
}

.brand {
  margin: 0 0 22px;
  font-size: 22px;
  font-weight: 600;
  letter-spacing: .12em;
  text-align: center;
  color: var(--gold);
}

.tabs {
  display: flex;
  gap: 4px;
  margin-bottom: 20px;
  padding: 3px;
  background: #16130f;
  border-radius: var(--radius);
}

.tab {
  flex: 1;
  padding: 9px 0;
  border: 0;
  border-radius: 7px;
  background: transparent;
  color: var(--dim);
  font: inherit;
  cursor: pointer;
}

.tab.is-on {
  background: var(--panel);
  color: var(--gold);
  box-shadow: 0 1px 3px rgba(0, 0, 0, .4);
}

.panel { display: none; }
.panel.is-on { display: block; }

label {
  display: block;
  margin-bottom: 14px;
  font-size: 13px;
  color: var(--dim);
}

input, select {
  display: block;
  width: 100%;
  margin-top: 6px;
  padding: 11px 12px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: #16130f;
  color: var(--ink);
  font: inherit;
}

input:focus, select:focus {
  outline: none;
  border-color: var(--gold);
}

input::placeholder { color: #6a625a; }

.go {
  width: 100%;
  margin-top: 6px;
  padding: 12px;
  border: 0;
  border-radius: 8px;
  background: linear-gradient(180deg, var(--gold-hi), var(--gold));
  color: #221a10;
  font: 600 15px/1 inherit;
  cursor: pointer;
}

.go:disabled {
  background: #3a342c;
  color: #6a625a;
  cursor: not-allowed;
}

.msg {
  min-height: 20px;
  margin: 14px 0 0;
  font-size: 13px;
  text-align: center;
  color: var(--dim);
}

.msg.bad { color: var(--bad); }
.msg.good { color: var(--good); }

.receipt { text-align: center; }

.mark {
  width: 52px;
  height: 52px;
  margin: 4px auto 18px;
  border-radius: 50%;
  font-size: 26px;
  line-height: 52px;
}

.mark.good { background: rgba(111, 174, 114, .15); color: var(--good); }
.mark.bad  { background: rgba(212, 103, 79, .15); color: var(--bad); }

.lede { margin: 0 0 22px; }

/* ---------- play: game stage, GM entry, GM window ----------

   The window is a port of the client's own dialog, fb/wanfa/WanFaWinSkin.exml -- the one
   behind 玩法. Every number below is that file's, or the button skins' in
   resource/resource/default.thm.json, rather than a value picked to look about right:

     frame          public_MU_frame0, 610x862, scale9Grid 59,78,493,13
     inner pattern  public_MU_patterndeep at x=14 y=58, scale9Grid 47,39,22,17
     close          public_MU_close 42x42 at x=565 y=4
     buttons        BtnMin1  -> public_MU_button0, grid 16,15,55,11, label 22 #ffebc8
                    BtnTab7  -> public_MU_sheet1 (on) / sheet0 (off), grids 14,9,84,29
                                and 12,10,87,29, label 22, #ffebc8 on / #645f4b off

   The art is cut out of the skin atlases into assets/ui/ and 9-sliced on those same
   grids. They are copies rather than references into /resource because they ship inside
   the binary with the rest of assets/, so the panel looks the same whether or not the
   art payload was unpacked.

   --k is one design pixel of that dialog. The client lays the dialog out in a 720-wide
   stage and scales by min(w/720, h/1280), which for a 610-wide dialog comes to 86vw --
   so --k is derived from the viewport alone and needs no script. --s, set in gm.js, is
   the separate basis the HUD uses; only the entry button below is placed in it. */

body.play {
  overflow: hidden;
  --k: min(calc(86vw / 610), calc(90vh / 862));
}

#stage {
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
  background: #000;
}

/* The entry stands in for the client's own 反馈 button, which does nothing on this
   server. MainUISkin.exml puts that button at group(top:27 left:3) > headGroup(y:-17
   left:-7) > btnFeedback(x:367 y:83), 56x36 -- so design (363,93), and this sits on the
   same spot two pixels larger all round to cover it. public_MU_sheet0 is the plate the
   rest of that row is drawn on. */
.ball {
  position: fixed;
  top: calc(91px * var(--s, .6));
  right: calc(219px * var(--s, .6));
  z-index: 30;
  width: calc(60px * var(--s, .6));
  height: calc(40px * var(--s, .6));
  padding: 0;
  border: 0 solid transparent;
  border-width: calc(10px * var(--s, .6)) calc(13px * var(--s, .6)) calc(9px * var(--s, .6)) calc(12px * var(--s, .6));
  border-image: url(/assets/ui/btn-off.png) 10 13 9 12 fill stretch;
  color: #f5e65a;
  font: 700 calc(20px * var(--s, .6)) / 1 inherit;
  letter-spacing: .04em;
  text-shadow: 0 1px 2px #000;
  cursor: pointer;
  -webkit-user-select: none;
  user-select: none;
}

.ball:active { filter: brightness(1.25); }

.scrim {
  position: fixed;
  inset: 0;
  z-index: 40;
  background: rgba(0, 0, 0, .6);
}

/* border-width is the layout inset -- the client puts content at x=14, y=58 -- while
   border-image-width is where the frame art draws, which is wider so the corner
   ornaments keep their own scale and spill back over the padding box. */
.gwin {
  position: fixed;
  left: 50%;
  top: 50%;
  z-index: 50;
  display: flex;
  flex-direction: column;
  width: calc(610 * var(--k));
  max-height: min(calc(862 * var(--k)), 94vh);
  border: solid transparent;
  border-width: calc(58 * var(--k)) calc(14 * var(--k)) calc(20 * var(--k));
  border-image:
    url(/assets/ui/frame0.png) 78 58 25 59 fill /
    calc(78 * var(--k)) calc(58 * var(--k)) calc(25 * var(--k)) calc(59 * var(--k))
    stretch;
  background: #17120e;
  box-shadow: 0 calc(12 * var(--k)) calc(40 * var(--k)) rgba(0, 0, 0, .6);
  transform: translate(-50%, -50%) scale(.96);
  opacity: 0;
  visibility: hidden;
  transition: opacity .18s ease, transform .18s ease, visibility .18s;
}

.gwin.is-open {
  transform: translate(-50%, -50%) scale(1);
  opacity: 1;
  visibility: visible;
}

/* Pulled back up over the top border, where frame0 draws its red plate. */
.gwin-bar {
  margin: calc(-58 * var(--k)) calc(-14 * var(--k)) 0;
  height: calc(46 * var(--k));
  line-height: calc(46 * var(--k));
  text-align: center;
}

.gwin-bar strong {
  display: inline-block;
  max-width: 58%;
  overflow: hidden;
  color: #f0dcae;
  font-size: calc(22 * var(--k));
  font-weight: 600;
  text-overflow: ellipsis;
  text-shadow: 0 1px 2px rgba(0, 0, 0, .7);
  vertical-align: top;
  white-space: nowrap;
}

.x {
  position: absolute;
  /* The client puts it at x=565 y=4 of a 610-wide frame. An absolutely positioned child
     is placed against the padding box, so both are offset back over the border. */
  top: calc(-54 * var(--k));
  right: calc(-11 * var(--k));
  width: calc(42 * var(--k));
  height: calc(42 * var(--k));
  padding: 0;
  border: 0;
  background: url(/assets/ui/close.png) 50% / contain no-repeat;
  cursor: pointer;
}

.x:hover { filter: brightness(1.2); }

/* patterndeep sits over the content area in the client too. On a pseudo so it costs the
   layout nothing; its middle is transparent and the frame's fill shows through. */
.gwin-body {
  position: relative;
  display: flex;
  flex: 1;
  min-height: 0;
  overflow: hidden;
}

.gwin-body::before {
  content: "";
  position: absolute;
  inset: calc(-6 * var(--k)) calc(-4 * var(--k));
  border: solid transparent;
  border-width: calc(30 * var(--k));
  border-image: url(/assets/ui/panel.png) 39 49 39 47 fill / calc(30 * var(--k)) stretch;
  pointer-events: none;
}

.gwin .panel.is-on {
  display: flex;
  flex: 1;
  min-height: 0;
  flex-direction: column;
  padding: 0 calc(10 * var(--k));
}

.gwin .tabs {
  gap: 0;
  margin: calc(6 * var(--k)) calc(10 * var(--k)) 0;
  padding: 0;
  border-bottom: 1px solid #2a2118;
  background: none;
  border-radius: 0;
}

.gwin .tab {
  padding: calc(10 * var(--k)) 0 calc(9 * var(--k));
  border-bottom: 2px solid transparent;
  border-radius: 0;
  color: #645f4b;
  font-size: calc(22 * var(--k));
  letter-spacing: .06em;
}

.gwin .tab.is-on {
  border-bottom-color: var(--amber);
  background: none;
  box-shadow: none;
  color: var(--amber);
}

.gwin input {
  height: calc(50 * var(--k));
  padding: 0 calc(12 * var(--k));
  border: 1px solid #3a3128;
  border-radius: calc(6 * var(--k));
  background: #100d0a;
  color: var(--pale);
  font-size: calc(22 * var(--k));
}

.gwin input:focus { border-color: var(--amber); }

.gwin .go {
  width: 100%;
  min-height: calc(48 * var(--k));
  padding: 0 calc(6 * var(--k));
  border: solid transparent;
  border-width: calc(9 * var(--k)) calc(14 * var(--k)) calc(10 * var(--k));
  border-image: url(/assets/ui/btn-on.png) 9 14 10 14 fill stretch;
  background: none;
  box-shadow: none;
  color: #ffebc8;
  font-size: calc(22 * var(--k));
  text-shadow: 0 1px 1px rgba(0, 0, 0, .55);
}

.gwin .go:disabled {
  border-image-source: url(/assets/ui/btn-off.png);
  border-image-slice: 10 13 9 12 fill;
  background: none;
  color: #645f4b;
  text-shadow: none;
}

/* BtnMin1's own size in WanFaItemSkin.exml is 110x50; the height here is the input's, so
   the two line up. The art's vertical caps are 15 and 24, which would leave 11 for a 22px
   label and push the box taller than the input -- they are 9-sliced, so drawing them
   thinner costs nothing. */
.gwin .go.ghost {
  width: calc(110 * var(--k));
  height: calc(50 * var(--k));
  min-height: 0;
  border-width: calc(11 * var(--k)) calc(17 * var(--k)) calc(13 * var(--k)) calc(13 * var(--k));
  border-image: url(/assets/ui/btn-min.png) 15 22 24 16 fill stretch;
  color: #ffebc8;
}

.gwin .go.ghost:disabled {
  border-image-source: url(/assets/ui/btn-min-off.png);
  color: #645f4b;
}

.row {
  display: flex;
  align-items: center;
  gap: calc(10 * var(--k));
  margin-top: calc(14 * var(--k));
}

.row .go { width: calc(150 * var(--k)); white-space: nowrap; }
.row #count { width: calc(110 * var(--k)); flex: none; }
.row #amount { flex: 1; }
.row #q { flex: 1; }

/* A <select size="6"> is a dropdown on every mobile browser -- size is ignored and
   nothing is selected, so the whole picker rendered as one blank line. This is a list. */
.picks {
  flex: 1;
  min-height: calc(150 * var(--k));
  margin: calc(14 * var(--k)) 0 0;
  padding: 0;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  border: 1px solid #3a3128;
  border-radius: calc(6 * var(--k));
  background: #100d0a;
  list-style: none;
}

.picks li {
  display: flex;
  align-items: center;
  gap: calc(10 * var(--k));
  padding: calc(9 * var(--k)) calc(12 * var(--k));
  font-size: calc(22 * var(--k));
  cursor: pointer;
}

.picks .nm {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.picks .ty {
  flex: none;
  color: #645f4b;
  font-size: calc(17 * var(--k));
}

/* GameConst.QUALITY_COLOR, the same five the client paints item names with. The selected
   row changes its background only -- recolouring the name would throw the quality away. */
.picks .q0 { color: #cdc8be; }
.picks .q1 { color: #5ac832; }
.picks .q2 { color: #23becd; }
.picks .q3 { color: #cd8cff; }
.picks .q4 { color: #ff9b0f; }

.picks li.is-on { background: linear-gradient(90deg, #3f331b, #2a2214); }

.picks li.none { color: #645f4b; cursor: default; }

/* Chips that wrap, not a row each: a cart of ten short names was ten lines of mostly
   empty panel. Each chip is as wide as its own text. */
.cart {
  display: flex;
  flex: 0 1 auto;
  flex-wrap: wrap;
  gap: calc(8 * var(--k));
  max-height: calc(190 * var(--k));
  margin: calc(14 * var(--k)) 0 0;
  padding: 0;
  overflow-y: auto;
  list-style: none;
}

.cart li {
  display: flex;
  align-items: center;
  gap: calc(6 * var(--k));
  max-width: 100%;
  padding: calc(5 * var(--k)) calc(4 * var(--k)) calc(5 * var(--k)) calc(10 * var(--k));
  border: 1px solid #3a3128;
  border-radius: calc(5 * var(--k));
  background: #16130f;
}

.cart .n {
  overflow: hidden;
  color: var(--tan);
  font-size: calc(21 * var(--k));
  text-overflow: ellipsis;
  white-space: nowrap;
}

.cart .c { color: var(--amber); font-size: calc(21 * var(--k)); }

.cart .del {
  flex: none;
  width: calc(26 * var(--k));
  height: calc(26 * var(--k));
  padding: 0;
  border: 0;
  background: none;
  color: #645f4b;
  font: calc(24 * var(--k)) / 1 inherit;
  cursor: pointer;
}

.cart .del::before { content: "×"; }
.cart .del:hover { color: var(--bad); }

/* Not full width: the client's action buttons are plates, not bars. */
#do-send {
  flex: none;
  width: calc(220 * var(--k));
  align-self: center;
  margin-top: calc(14 * var(--k));
}

/* On the left end of the title plate, mirroring the close key on the right. Both are
   positioned against the padding box, so both are pulled back over the top border. Same
   BtnMin1 plate as 加入 -- a CSS pill was the one thing in the window not drawn from the
   client's own art, and it showed. */
.out {
  position: absolute;
  top: calc(-52 * var(--k));
  left: calc(-6 * var(--k));
  display: flex;
  align-items: center;
  justify-content: center;
  width: calc(112 * var(--k));
  height: calc(36 * var(--k));
  border: solid transparent;
  border-width: calc(8 * var(--k)) calc(15 * var(--k)) calc(9 * var(--k)) calc(11 * var(--k));
  border-image: url(/assets/ui/btn-min.png) 15 22 24 16 fill stretch;
  color: #ffebc8;
  font-size: calc(19 * var(--k));
  text-decoration: none;
  white-space: nowrap;
}

.out:hover { filter: brightness(1.12); }

.gwin .msg {
  min-height: calc(26 * var(--k));
  margin: calc(10 * var(--k)) calc(10 * var(--k)) 0;
  font-size: calc(20 * var(--k));
}

/* ---------- supergm: the operator console ----------

   A desktop admin tool, not an in-game overlay, so it borrows the gate's flat primitives
   (.card, .tabs, .go, .msg, input) rather than the window's cut-out skin art, and lays
   them out wide. Nothing above this line is touched.

   Classes above that are shared with the GM window are sized there in --k, the design
   pixel of a 610-wide dialog: .picks and .cart, which the item picker builds. --k only
   exists on body.play, so those rules collapse here; every --k-sized property is
   re-stated below in real pixels rather than by defining a --k this page has no basis
   for. The colour rules (.picks .qN and friends) carry no --k and apply as they are. */

body.sgm {
  height: auto;
  min-height: 100%;
  padding-bottom: 72px;
}

.sgm-bar {
  position: sticky;
  top: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 12px 20px;
  border-bottom: 1px solid var(--line);
  background: var(--panel);
}

.sgm-brand {
  color: var(--gold);
  font-size: 16px;
  letter-spacing: .1em;
  white-space: nowrap;
}

.sgm-nav { display: flex; flex: 1; gap: 4px; }

.sgm-nav a {
  padding: 7px 14px;
  border-radius: 7px;
  color: var(--dim);
  font-size: 14px;
  text-decoration: none;
}

.sgm-nav a:hover { color: var(--ink); }
.sgm-nav a.is-on { background: #16130f; color: var(--gold); }

.sgm-who { color: var(--dim); font-size: 13px; }

.sgm-out {
  flex: none;
  padding: 6px 14px;
  border: 1px solid #8a6a34;
  border-radius: 999px;
  color: #e6cf9c;
  font-size: 13px;
  text-decoration: none;
  white-space: nowrap;
}

.sgm-out:hover { border-color: var(--amber); color: var(--amber); }

.sgm-main {
  display: grid;
  gap: 16px;
  max-width: 1100px;
  margin: 0 auto;
  padding: 20px;
}

/* The status line is fixed to the bottom because an action button can be a long way down
   a panel, and a message that scrolls out of view reads as no message at all. */
.sgm-msg {
  position: fixed;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 20;
  margin: 0;
  padding: 12px 20px;
  border-top: 1px solid var(--line);
  background: var(--panel);
}

.card.wide { max-width: none; padding: 20px; }

.head {
  margin: 0 0 14px;
  color: var(--gold);
  font-size: 15px;
  font-weight: 600;
  letter-spacing: .06em;
}

.sub {
  margin: 22px 0 10px;
  color: var(--tan);
  font-size: 14px;
  font-weight: 600;
}

.sub:first-child { margin-top: 0; }

.hint { margin: 8px 0 0; color: var(--dim); font-size: 12px; }
.hint p { margin: 2px 0; }

.warn {
  margin: 10px 0;
  padding: 9px 12px;
  border-left: 3px solid var(--bad);
  background: rgba(212, 103, 79, .08);
  color: #e0937f;
  font-size: 12px;
}

.sgm .row { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 12px; }
.sgm .row .go { width: auto; margin-top: 0; padding: 11px 18px; white-space: nowrap; }
.sgm .row input, .sgm .row select { flex: 1; min-width: 120px; margin-top: 0; }

.sgm textarea {
  display: block;
  width: 100%;
  margin-top: 6px;
  padding: 11px 12px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: #16130f;
  color: var(--ink);
  font: inherit;
  resize: vertical;
}

.sgm textarea:focus { outline: none; border-color: var(--gold); }

.sgm select[size] { height: auto; padding: 4px; }
.sgm select[size] option { padding: 5px 7px; }

label.inline {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin: 0 14px 6px 0;
  color: var(--ink);
  font-size: 13px;
}

label.inline input { display: inline; width: auto; margin: 0; padding: 0; }

/* Tables can be wider than the viewport; they scroll inside their own box rather than
   pushing the page sideways. */
.scroll { overflow-x: auto; }

.tbl {
  width: 100%;
  margin-top: 10px;
  border-collapse: collapse;
  font-size: 13px;
}

.tbl th, .tbl td {
  padding: 8px 10px;
  border-bottom: 1px solid var(--line);
  text-align: left;
  white-space: nowrap;
}

.tbl thead th { color: var(--dim); font-weight: 500; }
.tbl tbody tr:hover { background: #16130f; }
.tbl.kv th { width: 140px; color: var(--dim); font-weight: 400; }

.go.tiny {
  display: inline-block;
  width: auto;
  margin: 0;
  padding: 5px 12px;
  font-size: 12px;
  text-decoration: none;
}

.grid {
  display: grid;
  gap: 10px;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
}

.stat {
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: #16130f;
}

.stat .v { display: block; color: var(--gold); font-size: 21px; }
.stat .v.is-warn { color: var(--bad); }
.stat .k { color: var(--dim); font-size: 12px; }

.chips { margin: 12px 0 0; padding: 12px; border: 1px solid var(--line); border-radius: 8px; }
.chips legend { padding: 0 6px; color: var(--dim); font-size: 12px; }
.chiplist { display: flex; flex-wrap: wrap; }

.oplist { display: grid; gap: 10px; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); }

.op {
  display: flex;
  flex-direction: column;
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: #16130f;
}

.op.is-risky { border-color: #5a3a30; }
.op-t { color: var(--ink); font-size: 14px; }
.op-t code { margin-left: 8px; color: var(--mute); font-size: 12px; }
.op-d { flex: 1; margin: 6px 0 10px; color: var(--dim); font-size: 12px; }
.op .go { margin: 0; padding: 8px; font-size: 13px; }

.sgm .picks {
  min-height: 150px;
  max-height: 260px;
  margin: 12px 0 0;
  border-radius: 6px;
}
.sgm .picks li { gap: 8px; padding: 7px 10px; font-size: 14px; }
.sgm .picks .ty { font-size: 12px; }

.sgm .cart { gap: 6px; max-height: 200px; margin: 12px 0 0; }
.sgm .cart li { gap: 8px; padding: 7px 4px 7px 9px; border-radius: 4px; }
.sgm .cart .n, .sgm .cart .c { font-size: 14px; }
.sgm .cart .del { width: 24px; height: 24px; font: 15px/1 inherit; }
