/* Dragon Slayer Reborn Web — single stylesheet. Design tokens first; components use tokens only.
   Layout: .hud grid regions owned by Layout (web/src/ui.ts); desktop and mobile layouts rearrange regions. */
:root {
  --c-bg: #0b1220;
  --c-panel: #111a2e;
  --c-panel-2: #18233d;
  --c-border: #3a4a6b;
  --c-text: #eef2fa; /* on --c-panel: 14.9:1 */
  --c-muted: #b4bfd6; /* on --c-panel: 9.0:1 */
  --c-accent: #ffd166; /* on --c-panel: 11.7:1 */
  --c-accent-ink: #1b1300;
  --c-danger: #ff8a8a; /* on --c-panel: 7.3:1 */
  --c-hp: #d93a3a;
  --c-sp: #3a7bd9;
  --c-exp: #c9a227;
  --c-focus: #7ee0ff;
  --font-fallback: "Noto Sans Thai", "Leelawadee UI", "Leelawadee", Tahoma, "Segoe UI", system-ui, sans-serif;
  --font: var(--font-fallback); /* applyUiSkin puts ui.fontAlternative.cssStack in front */
  --fs-0: 12px;
  --fs-1: 14px;
  --fs-2: 16px;
  --fs-3: 20px;
  --fs-4: 28px;
  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 24px;
  --radius: 8px;
  --hit: 44px; /* minimum touch target (>= 40 px) */
  --slot: 52px;
  --shadow: 0 2px 10px rgb(0 0 0 / 0.45);
  --hud-pad: max(var(--sp-3), env(safe-area-inset-left));
}

* { box-sizing: border-box; }
[hidden] { display: none !important; }
html, body { margin: 0; height: 100%; background: var(--c-bg); color: var(--c-text); font: var(--fs-2)/1.5 var(--font); }
#app { height: 100%; }
:focus-visible { outline: 3px solid var(--c-focus); outline-offset: 2px; }
h1, h2, h3 { margin: 0 0 var(--sp-3); line-height: 1.25; }
h3 { font-size: var(--fs-2); color: var(--c-accent); }
.muted { color: var(--c-muted); }

/* ---------- buttons / inputs */
.btn {
  min-height: var(--hit); min-width: var(--hit); padding: 0 var(--sp-4);
  border: 1px solid var(--c-border); border-radius: var(--radius);
  background: var(--c-panel-2); color: var(--c-text); font: inherit; white-space: nowrap; cursor: pointer;
}
.btn:hover { border-color: var(--c-accent); }
.btn:active { background: #22304f; }
.btn:disabled { opacity: 0.55; cursor: not-allowed; }
.btn-primary { background: var(--c-accent); color: var(--c-accent-ink); border-color: var(--c-accent); font-weight: 700; }
.btn-primary:active { background: #e8bb52; }
.btn-small { min-height: 40px; padding: 0 var(--sp-3); font-size: var(--fs-1); }
.btn-icon { padding: 0; width: var(--hit); }
input:not([type="radio"]) {
  width: 100%; min-height: var(--hit); padding: 0 var(--sp-3); border: 1px solid var(--c-border); border-radius: var(--radius);
  background: #0a1324; color: var(--c-text); font: inherit;
}
label { display: block; color: var(--c-muted); font-size: var(--fs-1); margin-top: var(--sp-3); }
.row { display: flex; gap: var(--sp-2); flex-wrap: wrap; align-items: center; margin-top: var(--sp-4); }
.form-error { color: var(--c-danger); min-height: 1.5em; margin: var(--sp-2) 0 0; }
fieldset { border: 0; padding: 0; margin: var(--sp-3) 0 0; min-width: 0; }
legend { color: var(--c-muted); font-size: var(--fs-1); margin-bottom: var(--sp-2); }

/* ---------- pre-game screens */
/* background art on a fixed layer: whole-viewport cover by default; .screen-bg-rect (ui.screens.<s>.image) crops the
   texture to its contentRect (--screen-bg-size/-pos) on a box with the content's aspect ratio that covers the viewport */
.screen {
  isolation: isolate; /* keeps the ::before art layer above the screen colour; not a containing block (char-screen windows) */
  min-height: 100%; display: flex; flex-wrap: wrap; gap: var(--sp-5); align-items: flex-start; justify-content: center;
  padding: var(--sp-5) var(--sp-4); overflow: auto; background: var(--c-bg);
}
.screen::before {
  content: ""; position: fixed; inset: 0; z-index: -1; pointer-events: none;
  background: linear-gradient(rgb(11 18 32 / 0.55), rgb(11 18 32 / 0.85)), var(--screen-bg, none) center / cover no-repeat;
}
.screen-bg-rect::before {
  inset: auto; left: 50%; top: 50%; transform: translate(-50%, -50%);
  width: max(100vw, 100dvh * var(--screen-bg-ar)); height: max(100dvh, 100vw / var(--screen-bg-ar));
  background: var(--screen-bg) var(--screen-bg-pos) / var(--screen-bg-size) no-repeat;
}
/* original login art: logo (Root/Login/TitileImage, 512 px at 1024×768) and publisher line (Root/Login/easyLogPhoto).
   The logo fills the top 58% of its square texture (alpha bbox y 46..597 of 1024), so its box crops the empty rest. */
.screen-logo { flex: 0 0 100%; display: flex; justify-content: center; margin: 0; line-height: 0; }
.screen-logo img { width: min(calc(512px * var(--ui-k)), 92vw, calc(55dvh * 1024 / 600)); height: auto; aspect-ratio: 1024 / 600; object-fit: cover; object-position: top; }
.screen-copyright { flex: 0 0 100%; display: flex; justify-content: center; }
.screen-copyright img { width: min(calc(475px * var(--ui-k)), 92vw); height: auto; }
.screen-auth { align-items: center; }
.panel { background: var(--c-panel); border: 1px solid var(--c-border); border-radius: var(--radius); padding: var(--sp-5); box-shadow: var(--shadow); width: min(100%, 440px); }
.title { font-size: var(--fs-4); color: var(--c-accent); }
.subtitle { color: var(--c-muted); margin-top: 0; }
.list-panel { width: min(100%, 420px); }
.create-panel { width: min(100%, 720px); }
.char-list { list-style: none; padding: 0; margin: 0 0 var(--sp-4); display: grid; gap: var(--sp-2); }
.char-card { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-2); background: var(--c-panel-2); border-radius: var(--radius); }
.char-meta { flex: 1; display: flex; flex-direction: column; min-width: 0; }
.char-meta span { color: var(--c-muted); font-size: var(--fs-1); }
.class-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: var(--sp-2); }
.class-grid legend { grid-column: 1 / -1; }
.class-card { margin: 0; cursor: pointer; color: var(--c-text); font-size: var(--fs-1); }
.visually-hidden-radio { position: absolute; opacity: 0; width: 1px; height: 1px; }
.class-card-inner { display: flex; flex-direction: column; gap: var(--sp-1); height: 100%; padding: var(--sp-3); border: 2px solid var(--c-border); border-radius: var(--radius); background: var(--c-panel-2); }
.class-card input:checked + .class-card-inner { border-color: var(--c-accent); background: #24304c; }
.class-card input:focus-visible + .class-card-inner { outline: 3px solid var(--c-focus); outline-offset: 2px; }
.class-name { font-size: var(--fs-2); color: var(--c-accent); }
.class-desc { color: var(--c-text); }
.class-stats { color: var(--c-muted); font-size: var(--fs-0); }
.chip { display: inline-flex; align-items: center; gap: var(--sp-1); min-height: var(--hit); padding: 0 var(--sp-3); margin: 0; border: 1px solid var(--c-border); border-radius: var(--radius); color: var(--c-text); cursor: pointer; }
.gender-row { display: flex; gap: var(--sp-2); }

/* ---------- icons */
.icon { width: 40px; height: 40px; flex: none; border-radius: 6px; object-fit: cover; background: #0a1324; display: inline-block; }
.icon-missing { display: inline-flex; align-items: center; justify-content: center; font-size: 9px; line-height: 1.1; color: var(--c-danger); border: 1px dashed var(--c-danger); text-align: center; overflow: hidden; word-break: break-all; }
.icon-blank { display: inline-flex; align-items: center; justify-content: center; font-size: 9px; line-height: 1.1; color: var(--c-muted); border: 1px solid var(--c-border); text-align: center; overflow: hidden; padding: 2px; }

/* ---------- world stage */
.stage { position: fixed; inset: 0; overflow: hidden; background: var(--c-bg); }
.world-canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; touch-action: none; }
.world-labels { position: absolute; inset: 0; pointer-events: none; overflow: hidden; }
.nameplate { position: absolute; left: 0; top: 0; display: flex; flex-direction: column; align-items: center; gap: 2px; white-space: nowrap; font-size: var(--fs-0); text-shadow: 0 1px 2px #000, 0 0 3px #000; will-change: transform; }
.nameplate-name { color: #fff; }
.nameplate-monster .nameplate-name { color: #ffd9a0; }
.nameplate-npc .nameplate-name { color: #9ee8ff; }
.nameplate-drop .nameplate-name { color: var(--c-accent); }
.nameplate-self .nameplate-name { color: #b8ffb8; }
.nameplate.is-target .nameplate-name { color: var(--c-accent); font-weight: 700; }
.nameplate.is-dead { opacity: 0.6; }
.nameplate-missing { color: #fff; background: #a3122a; padding: 0 4px; border-radius: 3px; }
.quest-mark { font-weight: 900; font-size: 18px; line-height: 1; color: var(--c-accent); text-shadow: 0 0 3px #000, 0 1px 2px #000; }
/* original marks: yellow '!' offer, grey '?' in progress, yellow '?' ready to turn in */
.quest-mark-turnin { color: var(--c-accent); }
.quest-mark-progress { color: #c8ccd4; }
.nameplate-title { color: #ffe9a8; font-size: 11px; }
.speech-bubble { display: block; max-width: 220px; margin-bottom: 4px; padding: 4px 8px; color: #222; background: #fffbe9; border: 1px solid #8a6a2c; border-radius: 8px; font-size: var(--fs-0); line-height: 1.3; white-space: normal; text-shadow: none; }
.nameplate-role-aggressive .nameplate-name { color: #ff9a9a; }
.nameplate-role-passive .nameplate-name { color: #ffd9a0; }
.nameplate-party .nameplate-name { color: #8dff8d; }
.portal-label { position: absolute; left: 0; top: 0; color: #9ee8ff; font-size: var(--fs-0); font-weight: 700; white-space: nowrap; text-shadow: 0 1px 2px #000, 0 0 3px #000; pointer-events: none; }
.portal-label.is-closed { color: #c8ccd4; }
.hpbar { width: 64px; height: 6px; background: rgb(0 0 0 / 0.7); border: 1px solid rgb(255 255 255 / 0.35); border-radius: 3px; overflow: hidden; }
.hpbar-fill { display: block; height: 100%; background: var(--c-hp); }
.nameplate-self .hpbar { display: none; }
.dmg { position: absolute; left: 0; top: 0; font-weight: 800; font-size: 20px; text-shadow: 0 2px 3px #000, 0 0 2px #000; animation: dmg-rise 1.2s ease-out forwards; }
.dmg-dealt { color: #fff3c4; }
.dmg-crit { color: #ffb020; font-size: 26px; }
.dmg-taken { color: #ff7070; }
.dmg-heal { color: #8dff8d; }
.dmg-exp { color: #d8b4ff; font-size: 16px; }
@keyframes dmg-rise { from { margin-top: 0; opacity: 1; } to { margin-top: -48px; opacity: 0; } }

/* ---------- HUD layout (Layout regions) */
.hud {
  position: absolute; inset: 0; pointer-events: none;
  display: grid; gap: var(--sp-2); padding: var(--sp-3) var(--hud-pad) max(var(--sp-3), env(safe-area-inset-bottom));
  grid-template-columns: minmax(260px, 1fr) minmax(0, 2fr) minmax(200px, 1fr);
  grid-template-rows: auto minmax(0, 1fr) auto;
  grid-template-areas: "tl tc tr" ". . sr" "bl bc br";
}
.hud-region { display: flex; flex-direction: column; gap: var(--sp-2); min-width: 0; min-height: 0; }
.hud-item { pointer-events: auto; }
.hud-top-left { grid-area: tl; align-items: flex-start; }
.hud-top-center { grid-area: tc; align-items: center; }
.hud-top-right { grid-area: tr; align-items: flex-end; }
.hud-side-right { grid-area: sr; align-items: flex-end; }
.hud-bottom-left { grid-area: bl; justify-content: flex-end; align-items: flex-start; }
.hud-bottom-center { grid-area: bc; justify-content: flex-end; align-items: center; }
.hud-bottom-right { grid-area: br; justify-content: flex-end; align-items: flex-end; }
.status-line { pointer-events: none; color: var(--c-text); font-size: var(--fs-1); text-shadow: 0 1px 2px #000; min-height: 1.5em; }
.status-line:empty { display: none; }

.frame { display: flex; gap: var(--sp-2); align-items: center; padding: var(--sp-2); background: rgb(17 26 46 / 0.88); border: 1px solid var(--c-border); border-radius: var(--radius); width: 300px; max-width: 100%; }
.frame-bars { flex: 1; display: grid; gap: 4px; min-width: 0; }
.frame-name { font-size: var(--fs-1); font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.target-frame { width: 320px; }
.bar { position: relative; height: 16px; background: #050a14; border: 1px solid var(--c-border); border-radius: 4px; overflow: hidden; }
.bar-fill { position: absolute; inset: 0 auto 0 0; width: 0; }
.bar-hp .bar-fill { background: var(--c-hp); }
.bar-sp .bar-fill { background: var(--c-sp); }
.bar-exp { width: min(620px, 100%); height: 12px; pointer-events: auto; }
.bar-exp .bar-fill { background: var(--c-exp); }
.bar-text { position: relative; display: block; text-align: center; font-size: 11px; line-height: 14px; color: #fff; text-shadow: 0 1px 1px #000; }
.bar-exp .bar-text { line-height: 10px; font-size: 10px; }

.minimap-box { display: grid; gap: 4px; padding: var(--sp-2); background: rgb(17 26 46 / 0.88); border: 1px solid var(--c-border); border-radius: var(--radius); justify-items: center; }
.minimap-title { font-size: var(--fs-1); color: var(--c-accent); font-weight: 700; }
.minimap { width: 180px; height: 180px; border-radius: 6px; display: block; }
.minimap-coords { font-size: var(--fs-0); color: var(--c-muted); }

.hotbar { display: flex; gap: var(--sp-1); padding: var(--sp-1); background: rgb(17 26 46 / 0.88); border: 1px solid var(--c-border); border-radius: var(--radius); }
.slot { position: relative; width: var(--slot); height: var(--slot); padding: 0; border: 1px solid var(--c-border); border-radius: 6px; background: #0a1324; color: var(--c-text); cursor: pointer; display: grid; place-items: center; overflow: hidden; }
.slot .icon { width: calc(var(--slot) - 6px); height: calc(var(--slot) - 6px); }
.slot:hover { border-color: var(--c-accent); }
.slot-key { position: absolute; left: 2px; top: 0; font-size: 11px; font-weight: 700; color: #fff; text-shadow: 0 0 2px #000, 0 1px 1px #000; }
.slot-count { position: absolute; right: 3px; bottom: 1px; font-size: 11px; color: #fff; text-shadow: 0 0 2px #000; }
.slot-cd { position: absolute; inset: auto 0 0 0; height: 0; background: rgb(0 0 0 / 0.62); color: #fff; font-weight: 700; display: grid; place-items: center; pointer-events: none; }
.slot-glyph { font-size: 24px; }
.slot-icon-host { display: contents; }
.slot-unsupported .icon, .slot-locked .icon { filter: grayscale(1) brightness(0.6); }
.slot-unsupported::after { content: "?"; position: absolute; right: 3px; top: 0; color: var(--c-danger); font-weight: 800; }

.chat { width: min(380px, 100%); background: rgb(17 26 46 / 0.82); border: 1px solid var(--c-border); border-radius: var(--radius); padding: var(--sp-2); display: grid; gap: var(--sp-1); }
.chat-log { list-style: none; margin: 0; padding: 0; height: 132px; overflow-y: auto; font-size: var(--fs-1); overflow-wrap: anywhere; }
.chat-log strong { color: var(--c-accent); }
.chat-system { color: #d8b4ff; }
.chat-form { display: flex; gap: var(--sp-1); }
.chat-toggle { display: none; }
.menu { display: flex; gap: var(--sp-1); flex-wrap: wrap; justify-content: flex-end; }
.menu .btn { background: rgb(24 35 61 / 0.95); }
.menu .btn[aria-pressed="false"] { opacity: 0.7; text-decoration: line-through; }
.joystick { display: none; }

/* ---------- windows (above HUD, never covered by it). Desktop anchors: left (character windows, below the player
   frame), right (bag, below the minimap), center (dialogs). Mobile: every window centred. Height stops above the
   bottom HUD row so the chat/hotbar stay reachable; only .window-body scrolls. */
.windows { position: absolute; inset: 0; pointer-events: none; z-index: 6; }
.window {
  --win-top: min(262px, 30%);
  pointer-events: auto; position: absolute; right: var(--hud-pad); top: var(--win-top);
  width: min(420px, calc(100% - 2 * var(--sp-3))); max-height: calc(100% - var(--win-top) - 120px);
  display: flex; flex-direction: column; background: var(--c-panel); border: 1px solid var(--c-border); border-radius: var(--radius); box-shadow: var(--shadow);
}
.window-left { right: auto; left: var(--hud-pad); --win-top: min(112px, 14%); max-height: calc(100% - var(--win-top) - 250px); min-height: min(320px, calc(100% - var(--win-top) - 250px)); }
.window-center { right: auto; left: 50%; top: 50%; transform: translate(-50%, -50%); max-height: calc(100% - 2 * var(--sp-4)); }
.window-modal { width: min(400px, calc(100% - 2 * var(--sp-3))); z-index: 2; }
.window-wide { width: min(560px, calc(100% - 2 * var(--sp-3))); }
.window-head { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); padding: var(--sp-2) var(--sp-2) var(--sp-2) var(--sp-4); border-bottom: 1px solid var(--c-border); flex: none; }
.window-title { margin: 0; font-size: var(--fs-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.window-body { padding: var(--sp-4); overflow-y: auto; min-height: 0; overscroll-behavior: contain; }
.bag-grid { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(48px, 1fr)); gap: var(--sp-1); }
.bag-slot { position: relative; width: 100%; aspect-ratio: 1; min-height: var(--hit); padding: 2px; border: 1px solid var(--c-border); border-radius: 6px; background: #0a1324; display: grid; place-items: center; cursor: pointer; color: var(--c-text); }
.bag-slot.is-selected { border-color: var(--c-accent); box-shadow: inset 0 0 0 1px var(--c-accent); }
.bag-slot .icon { width: 100%; height: 100%; }
.bag-discard { width: 100%; margin-top: var(--sp-3); min-height: var(--hit); border: 1px dashed var(--c-danger); border-radius: var(--radius); background: transparent; color: var(--c-danger); font: inherit; font-size: var(--fs-1); }
.drop-over { outline: 2px dashed var(--c-accent); outline-offset: 2px; }
.item-detail { margin-top: var(--sp-3); padding: var(--sp-3); background: var(--c-panel-2); border-radius: var(--radius); font-size: var(--fs-1); }
.item-detail .row { margin-top: var(--sp-2); }
.gold-line { margin: 0 0 var(--sp-2); color: var(--c-accent); font-weight: 700; }
.gold-icon { color: var(--c-accent); }
.inventory, .store, .equipment, .skills, .stats, .trade, .gm, .party-window, .death { display: grid; gap: var(--sp-2); }
.npc-talk { display: grid; gap: var(--sp-3); justify-items: stretch; }
.npc-head { display: flex; gap: var(--sp-3); align-items: flex-start; }
.npc-head .dialogue { flex: 1; min-width: 0; }
.dialogue { display: grid; gap: var(--sp-2); }
.dialogue-page { margin: 0; white-space: pre-line; font-size: var(--fs-1); }
.dialogue-page strong { color: var(--c-accent); }
.npc-quest { display: grid; gap: var(--sp-2); padding: var(--sp-3); background: var(--c-panel-2); border-radius: var(--radius); }
.npc-quest h3 { margin: 0; }
.tracker { width: var(--ui-questTracker-w, 280px); max-width: 100%; max-height: min(var(--ui-questTracker-h, 40dvh), 40dvh); overflow-y: auto; padding: var(--sp-2) var(--sp-3); background: rgb(17 26 46 / 0.82); border: 1px solid var(--c-border); border-radius: var(--radius); font-size: var(--fs-1); }
.tracker-title { font-size: var(--fs-1); color: var(--c-accent); margin: 0 0 var(--sp-1); }
.tracker .muted { margin: 0; }
.quest-card { display: grid; gap: 2px; padding: var(--sp-1) 0; justify-items: start; }
.quest-card + .quest-card { border-top: 1px solid var(--c-border); }
.quest-card.is-navigating { box-shadow: inset 3px 0 0 var(--c-accent); padding-left: var(--sp-2); }
.quest-name { color: var(--c-text); font-weight: 700; }
.quest-desc { margin: 0; white-space: pre-line; color: var(--c-muted); font-size: var(--fs-1); }
.quest-objs { list-style: none; margin: 0; padding: 0; }
.quest-objs li::before { content: "○ "; color: var(--c-muted); }
.quest-objs li.done { color: #8dff8d; }
.quest-objs li.done::before { content: "● "; color: #8dff8d; }
.quest-objs li.unsupported { color: var(--c-danger); }
.quest-finish { margin: 0; color: var(--c-accent); }
.quest-unsupported { margin: 0; color: var(--c-danger); }
.quest-log { display: grid; grid-template-columns: minmax(150px, 2fr) 3fr; gap: var(--sp-3); align-items: start; }
.quest-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; }
.quest-list-item { width: 100%; min-height: 40px; text-align: left; padding: var(--sp-1) var(--sp-2); border: 1px solid transparent; border-radius: 6px; background: var(--c-panel-2); color: var(--c-text); font: inherit; font-size: var(--fs-1); cursor: pointer; }
.quest-list-item[aria-selected="true"] { border-color: var(--c-accent); }
.quest-ready-mark { color: var(--c-accent); font-weight: 900; }
.quest-detail { display: grid; gap: var(--sp-1); min-width: 0; }
.quest-detail h3, .quest-detail h4 { margin: var(--sp-2) 0 0; }
.quest-detail h4 { font-size: var(--fs-1); color: var(--c-muted); }
.rewards { display: grid; gap: var(--sp-1); font-size: var(--fs-1); }
.rewards p { margin: 0; }
.reward-items { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.reward-item { display: inline-flex; align-items: center; gap: var(--sp-1); padding: 2px var(--sp-2) 2px 2px; background: var(--c-panel-2); border-radius: 6px; }
.reward-choices { display: grid; gap: var(--sp-1); }
.reward-choice { display: flex; align-items: center; gap: var(--sp-2); margin: 0; min-height: var(--hit); color: var(--c-text); cursor: pointer; }
.reward-choice input { width: 20px; height: 20px; }
.stats-line { color: var(--c-muted); font-size: var(--fs-0); }
.npc-portrait { width: min(128px, 30vw); height: auto; aspect-ratio: 1; border-radius: var(--radius); flex: none; }
.linkish { background: none; border: 0; padding: 2px 0; min-height: 28px; color: inherit; font: inherit; text-align: left; cursor: pointer; text-decoration: underline dotted; text-underline-offset: 3px; }
.linkish:disabled { text-decoration: none; cursor: default; color: inherit; }
.btn-danger { background: #5c1520; border-color: var(--c-danger); color: #fff; }
.btn-danger-ghost { color: var(--c-danger); }
.row-tight { margin-top: var(--sp-2); flex-wrap: nowrap; }
.row-tight input { flex: 1; min-width: 0; }
select { min-height: var(--hit); padding: 0 var(--sp-2); border: 1px solid var(--c-border); border-radius: var(--radius); background: #0a1324; color: var(--c-text); font: inherit; max-width: 100%; }
.inline-label { margin: 0; white-space: nowrap; }

/* tabs */
.tabbed { display: grid; gap: var(--sp-3); }
.tabs { display: flex; gap: var(--sp-1); border-bottom: 1px solid var(--c-border); overflow-x: auto; }
.tab { min-height: var(--hit); padding: 0 var(--sp-3); border: 1px solid transparent; border-bottom: 0; border-radius: var(--radius) var(--radius) 0 0; background: transparent; color: var(--c-muted); font: inherit; font-size: var(--fs-1); white-space: nowrap; cursor: pointer; }
.tab[aria-selected="true"] { background: var(--c-panel-2); border-color: var(--c-border); color: var(--c-accent); font-weight: 700; }

/* tooltip (single shared element, positioned by Tooltip.place) */
.tooltip { position: fixed; left: 0; top: 0; z-index: 30; width: max-content; max-width: min(320px, calc(100vw - 16px)); padding: var(--sp-3); background: #0a1324; border: 1px solid var(--c-accent); border-radius: var(--radius); box-shadow: var(--shadow); pointer-events: none; font-size: var(--fs-1); }
.tip { display: grid; gap: var(--sp-1); }
.tip-head { display: flex; gap: var(--sp-2); align-items: center; }
.tip-head > div { display: grid; }
.tip-lines { list-style: none; margin: 0; padding: 0; }
.tip-desc { margin: 0; white-space: pre-line; color: var(--c-muted); }
.tip-bad { color: var(--c-danger); }
.tip-quest { color: var(--c-accent); }
/* EItemQuality name colours (game.data items.quality) */
.q-0 { color: var(--c-text); } .q-1 { color: #b4bfd6; } .q-2 { color: #8dff8d; } .q-3 { color: #8fc1ff; } .q-4 { color: #ffb347; }
.q-5 { color: #d8b4ff; } .q-6 { color: var(--c-accent); } .q-7 { color: #ffb8a8; } .q-8 { color: #ff8a8a; }

/* equipment paper doll */
.paperdoll { display: grid; grid-template-columns: auto 1fr auto; grid-template-areas: "l1 c r1" "l2 c r2" "l3 c r3" "l4 c r4" "l5 c r5" "l6 c r6"; gap: var(--sp-1) var(--sp-3); align-items: center; }
.paperdoll-center { grid-area: c; display: grid; justify-items: center; align-content: center; gap: var(--sp-1); text-align: center; min-width: 0; padding: var(--sp-3); background: radial-gradient(circle, #1f2c4a, transparent 70%); border-radius: var(--radius); }
.paperdoll-center .icon { width: 64px; height: 64px; }
.paperdoll-extra { display: grid; grid-template-columns: repeat(auto-fill, minmax(64px, 1fr)); gap: var(--sp-2); }
.equip-cell { display: grid; justify-items: center; gap: 2px; }
.equip-slot { position: relative; width: 52px; height: 52px; padding: 2px; border: 1px solid var(--c-border); border-radius: 6px; background: #0a1324; color: var(--c-muted); display: grid; place-items: center; cursor: pointer; }
.equip-slot .icon { width: 46px; height: 46px; }
.equip-slot.is-empty { border-style: dashed; cursor: default; }
.equip-empty { font-size: 10px; line-height: 1.1; text-align: center; }
.equip-label { font-size: 11px; color: var(--c-muted); max-width: 72px; text-align: center; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* store */
.store-list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-1); }
.store-row { display: flex; align-items: center; gap: var(--sp-2); padding: 2px; border-radius: 6px; }
.store-row:hover { background: var(--c-panel-2); }
.store-name { flex: 1; min-width: 0; display: grid; font-size: var(--fs-1); }
.store-sell { padding: var(--sp-3); border: 1px dashed var(--c-border); border-radius: var(--radius); color: var(--c-muted); font-size: var(--fs-1); text-align: center; }

/* skills / stats */
.skill-list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-2); }
.skill-row { display: flex; align-items: center; gap: var(--sp-2); }
.skill-row.is-unlearned .icon { filter: grayscale(1) brightness(0.6); }
.skill-meta { flex: 1; min-width: 0; display: grid; font-size: var(--fs-1); }
.skill-actions { display: flex; gap: var(--sp-1); flex-wrap: wrap; justify-content: flex-end; }
.stat-grid { display: grid; grid-template-columns: 1fr auto; gap: 2px var(--sp-3); margin: 0; font-size: var(--fs-1); }
.stat-grid dt { color: var(--c-muted); }
.stat-grid dd { margin: 0; text-align: right; font-variant-numeric: tabular-nums; }
.stat-buffed { color: #8dff8d; }
.alloc-list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-1); }
.alloc-row { display: grid; grid-template-columns: 1fr auto auto auto; gap: var(--sp-2); align-items: center; font-size: var(--fs-1); }
.slot-empty { border-style: dashed; }

/* buffs / cast bars */
.buff-row { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 2px; }
.buff-row:empty { display: none; }
.buff { position: relative; width: 24px; height: 24px; border-radius: 4px; border: 1px solid #5fd35f; }
.buff-debuff { border-color: var(--c-danger); }
.buff .buff-icon { width: 22px; height: 22px; font-size: 6px; border-radius: 3px; }
.buff-time { position: absolute; inset: auto 0 -1px 0; font-size: 9px; line-height: 1; text-align: center; color: #fff; text-shadow: 0 0 2px #000, 0 0 2px #000; }
.buff-stacks { position: absolute; right: 0; top: -1px; font-size: 9px; color: #fff; text-shadow: 0 0 2px #000; }
.castbar { width: min(320px, 100%); }
.bar-cast .bar-fill { background: linear-gradient(90deg, #c9a227, #ffd166); }
.castbar.is-interrupted .bar-fill { background: var(--c-danger); }
.frame-tot { font-size: var(--fs-0); color: var(--c-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.target-frame .frame-name[data-kind="monster-aggressive"] { color: #ff9a9a; }
.target-frame .frame-name[data-kind="monster-passive"] { color: #ffd9a0; }
.target-frame .frame-name[data-kind="npc"] { color: #9ee8ff; }
.bar-thin { height: 12px; }
.bar-thin .bar-text { font-size: 9px; line-height: 10px; }
.death-penalty { color: var(--c-danger); }

/* party */
.party-frames { display: grid; gap: var(--sp-1); width: 220px; max-width: 100%; }
.party-member { display: grid; gap: 2px; padding: var(--sp-1) var(--sp-2); min-height: var(--hit); background: rgb(17 26 46 / 0.88); border: 1px solid var(--c-border); border-radius: var(--radius); color: var(--c-text); font: inherit; text-align: left; cursor: pointer; }
.party-member.is-offline { opacity: 0.6; }
.party-name { font-size: var(--fs-0); font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.party-leader { color: var(--c-accent); }
.party-zone { font-size: var(--fs-0); color: var(--c-muted); }
.party-list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-1); }
.party-list li { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); }
.ctx-menu { display: grid; gap: var(--sp-1); }
.ctx-menu .btn { text-align: left; }

/* trade */
.trade-cols { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-2); }
.trade-side { padding: var(--sp-2); background: var(--c-panel-2); border-radius: var(--radius); min-width: 0; }
.trade-side h3 { margin-bottom: var(--sp-1); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.trade-side p { margin: var(--sp-1) 0 0; font-size: var(--fs-1); }
.trade-items { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-1); min-height: 48px; font-size: var(--fs-1); }
.trade-item { display: flex; align-items: center; gap: var(--sp-1); flex-wrap: wrap; }
.trade-status.is-locked { color: var(--c-accent); }
.trade input[type="number"] { width: 8em; flex: none; }

/* chat channels */
.chat-tabs { display: flex; gap: 2px; overflow-x: auto; }
.chat-tab { min-height: 32px; padding: 0 var(--sp-2); border: 1px solid transparent; border-radius: 6px; background: transparent; color: var(--c-muted); font: inherit; font-size: var(--fs-0); white-space: nowrap; cursor: pointer; }
.chat-tab[aria-selected="true"] { border-color: var(--c-border); background: var(--c-panel-2); color: var(--c-text); }
.chat-channel { min-width: 0; width: 5.5em; flex: none; font-size: var(--fs-1); }
.chat-line .chat-from { color: inherit; font-weight: 700; }
.chat-tag { opacity: 0.85; }
.chat-ch-near { color: var(--c-text); }
.chat-ch-zone { color: #9ee8ff; }
.chat-ch-world { color: var(--c-accent); }
.chat-ch-party { color: #8dff8d; }
.chat-ch-whisper { color: #ffa8e6; }
.chat-ch-system { color: #d8b4ff; }
.chat-tab.chat-ch-all { color: var(--c-muted); }

/* GM */
.gm-fields { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 0 var(--sp-2); }
.gm-log { list-style: none; margin: 0; padding: var(--sp-2); max-height: 180px; overflow-y: auto; background: #0a1324; border-radius: var(--radius); font: var(--fs-0)/1.4 ui-monospace, Consolas, monospace; overflow-wrap: anywhere; }
.gm-ok { color: #8dff8d; }
.gm-err { color: var(--c-danger); }

/* confirm */
.confirm-box { display: grid; gap: var(--sp-1); }
.confirm-text { margin: 0; white-space: pre-line; }

/* loading screen (zone transfer): the zone's original loading art, letterboxed on dark */
.loading-screen { position: absolute; inset: 0; z-index: 20; display: grid; grid-template-rows: minmax(0, 1fr) auto; background: #000; }
.loading-stage { display: grid; place-items: center; min-height: 0; overflow: hidden; }
.loading-art { width: min(100%, calc((100dvh - 120px) * 4 / 3)); aspect-ratio: 4 / 3; background: #000 top center / 100% auto no-repeat; display: grid; place-items: center; color: var(--c-danger); font-size: var(--fs-1); }
.loading-panel { display: grid; gap: var(--sp-2); justify-items: center; padding: var(--sp-3) var(--sp-4) max(var(--sp-4), env(safe-area-inset-bottom)); background: #000; }
.loading-title { margin: 0; font-size: var(--fs-4); color: var(--c-accent); text-shadow: 0 2px 4px #000; text-align: center; }
.loading-status { margin: 0; color: var(--c-text); font-size: var(--fs-1); text-shadow: 0 1px 2px #000; min-height: 1.5em; text-align: center; }
.bar-loading { width: min(560px, 90vw); height: 14px; }
.bar-loading .bar-fill { background: linear-gradient(90deg, #c9a227, #ffd166); }
.bar-loading .bar-text { line-height: 12px; font-size: 10px; }

/* cutscene-lite */
.scene-banner { pointer-events: none; padding: var(--sp-2) var(--sp-5); background: rgb(0 0 0 / 0.7); border-top: 1px solid var(--c-accent); border-bottom: 1px solid var(--c-accent); color: var(--c-accent); font-size: var(--fs-3); font-weight: 700; text-align: center; max-width: min(720px, 100%); }
.scene-dialogue { width: min(640px, 100%); padding: var(--sp-3) var(--sp-4); background: rgb(10 19 36 / 0.95); border: 1px solid var(--c-accent); border-radius: var(--radius); display: grid; gap: var(--sp-1); }
.scene-speaker { color: var(--c-accent); }
.scene-text { margin: 0; white-space: pre-line; }
.scene-dialogue .row { justify-content: flex-end; }
.scene-blackout { position: absolute; inset: 0; background: #000; z-index: 4; pointer-events: none; }

.toasts { position: absolute; left: 50%; top: 22%; transform: translateX(-50%); display: grid; gap: var(--sp-1); pointer-events: none; z-index: 25; width: max-content; max-width: calc(100vw - 2 * var(--sp-3)); }
.toast { padding: var(--sp-2) var(--sp-4); background: rgb(17 26 46 / 0.95); border: 1px solid var(--c-border); border-radius: var(--radius); font-size: var(--fs-1); text-align: center; }
.toast-error { border-color: var(--c-danger); color: var(--c-danger); }

/* ---------- CEGUI skin (manifest ui → applyUiSkin in web/src/ui.ts; reference renderer tools/assets/render_ui.html).
   Every rule is gated by html.ui-<key>[-frame|-fill-frame], so the tokens above stay in force for every image the atlas
   does not provide (null/missing). Frames paint with border-image at the art's slice widths × --ui-k, so the box model
   and hit targets do not change. Size rules use :where(html.ui-…) (specificity of one class) so the mobile media
   queries below still win. Text over art: dark art keeps the token colours (≥ 4.5:1 on the backdrops, measured on the
   atlas crops composited over black and white); the orange/red button art (~3.9:1 for white) gets white bold text with a
   black halo. --ui-k scales the 1024×768 refResolution art on large screens (CEGUI draws AutoScaled=false art 1:1). */
:root { --ui-k: 1; }
@media (min-width: 1600px) and (min-height: 1000px) { :root { --ui-k: 1.25; } }
@media (min-width: 2400px) and (min-height: 1350px) { :root { --ui-k: 1.5; } }
:root:where(.ui-slot-frame) { --slot: max(var(--hit), var(--ui-slot-w)); }
:root:where(.ui-hpOrb) { --orb: min(calc(var(--ui-hpOrb-w) / 2), 88px); }

/* windows, dialogs, tooltip, popup menu, listbox */
html.ui-windowFrame-frame .window { border-color: transparent; border-image: var(--ui-windowFrame-frame) var(--ui-windowFrame-slice) / var(--ui-windowFrame-bw) stretch; }
html.ui-dialogFrame-frame .window-modal, html.ui-dialogFrame-frame .scene-dialogue { border-color: transparent; border-image: var(--ui-dialogFrame-frame) var(--ui-dialogFrame-slice) / var(--ui-dialogFrame-bw) stretch; }
html.ui-windowTitle-frame .window-head { border-image: var(--ui-windowTitle-frame) var(--ui-windowTitle-slice) / var(--ui-windowTitle-bw) stretch; border-bottom-color: transparent; }
html.ui-closeButton .win-close { background: var(--ui-closeButton) center / calc(24px * var(--ui-k)) calc(24px * var(--ui-k)) no-repeat; border-color: transparent; color: transparent; }
html.ui-closeButton .win-close:hover { background-image: var(--ui-closeButton-hover, var(--ui-closeButton)); }
html.ui-closeButton .win-close:active { background-image: var(--ui-closeButton-pushed, var(--ui-closeButton)); }
html.ui-tooltipFrame-frame .tooltip { border-color: transparent; border-image: var(--ui-tooltipFrame-frame) var(--ui-tooltipFrame-slice) / var(--ui-tooltipFrame-bw) stretch; }
html.ui-popupMenu-frame .ctx-menu { padding: var(--sp-2); border: 1px solid transparent; border-image: var(--ui-popupMenu-frame) var(--ui-popupMenu-slice) / var(--ui-popupMenu-bw) stretch; }
html.ui-listbox-frame :is([role="listbox"], .store-list) { padding: 3px; border: 1px solid transparent; border-image: var(--ui-listbox-frame) var(--ui-listbox-slice) / var(--ui-listbox-bw) stretch; }
html.ui-npcTalkFrame-frame .npc-head > .dialogue { padding: var(--sp-3); border: 1px solid transparent; border-image: var(--ui-npcTalkFrame-frame) var(--ui-npcTalkFrame-slice) / var(--ui-npcTalkFrame-bw) stretch; }

/* controls: buttons (normal/hover/pushed/disabled; DejaVu/Button2 = red for destructive actions), tabs, edit boxes,
   check boxes, scroll bars (fine pointers only: touch keeps the overlay scrollbars) */
html.ui-button-frame .btn:not(.btn-icon) { border-color: transparent; border-image: var(--ui-button-frame) var(--ui-button-slice) / var(--ui-button-bw) stretch; background: transparent; color: #fff; font-weight: 700; text-shadow: 0 0 2px #000, 0 0 2px #000, 0 1px 1px #000; }
html.ui-button-frame .btn-primary:not(.btn-icon) { color: var(--c-accent); }
html.ui-button2-frame .btn-danger:not(.btn-icon) { border-image-source: var(--ui-button2-frame); }
html.ui-buttonHover-frame .btn:not(.btn-icon, .btn-danger):hover:enabled { border-image-source: var(--ui-buttonHover-frame); }
html.ui-buttonPressed-frame .btn:not(.btn-icon, .btn-danger):active:enabled { border-image-source: var(--ui-buttonPressed-frame); }
html.ui-button2-frame .btn-danger:not(.btn-icon):hover:enabled { filter: brightness(1.15); }
html.ui-button2-frame .btn-danger:not(.btn-icon):active:enabled { filter: brightness(0.85); }
html.ui-buttonDisabled-frame .btn:not(.btn-icon):disabled { border-image-source: var(--ui-buttonDisabled-frame); }
html.ui-tabActive-frame :is(.tab, .chat-tab)[aria-selected="true"] { border-color: transparent; border-image: var(--ui-tabActive-frame) var(--ui-tabActive-slice) / var(--ui-tabActive-bw) stretch; }
html.ui-tabInactive-frame :is(.tab, .chat-tab)[aria-selected="false"] { border-image: var(--ui-tabInactive-frame) var(--ui-tabInactive-slice) / var(--ui-tabInactive-bw) stretch; }
html.ui-editbox-frame :is(input:not([type="radio"], [type="checkbox"]), select) { border-color: transparent; border-image: var(--ui-editbox-frame) var(--ui-editbox-slice) / var(--ui-editbox-bw) stretch; }
html.ui-checkbox input[type="checkbox"] { appearance: none; flex: none; width: calc(18px * var(--ui-k)); height: calc(18px * var(--ui-k)); min-height: 0; margin: 0; padding: 0; border: 0; background: var(--ui-checkbox) center / 100% 100% no-repeat; }
html.ui-checkboxChecked input[type="checkbox"]:checked { background-image: var(--ui-checkboxChecked), var(--ui-checkbox); }
@media (pointer: fine) {
  html.ui-scrollTrack-frame ::-webkit-scrollbar { width: calc(16px * var(--ui-k)); height: 10px; }
  html.ui-scrollTrack-frame ::-webkit-scrollbar-track:vertical { border: 0 solid transparent; border-image: var(--ui-scrollTrack-frame) var(--ui-scrollTrack-slice) / var(--ui-scrollTrack-bw) stretch; }
  html.ui-scrollTrack-frame ::-webkit-scrollbar-thumb { border-radius: 4px; background: var(--c-border); }
  html.ui-scrollThumb-frame ::-webkit-scrollbar-thumb:vertical { border: 0 solid transparent; border-radius: 0; background: none; border-image: var(--ui-scrollThumb-frame) var(--ui-scrollThumb-slice) / var(--ui-scrollThumb-bw) stretch; }
}

/* player frame: the original player HUD is the HP orb (DejaVu4:HPBall ring = hpOrb/playerFrame) with the SP ring
   (DejaVu4:SPBall, DejaVu/RoundImage → conic mask = SP share) around it; the class icon sits inside. The HP fill image
   is set by Game.bin at run time (unresolved), so the liquid is a designed gradient. The bars keep the numbers. */
.player-orb { position: relative; isolation: isolate; flex: none; display: grid; place-items: center; }
.orb-sp { display: none; }
html.ui-hpOrb .player-orb { width: var(--orb); height: var(--orb); }
html.ui-hpOrb .player-orb > .icon { width: 64%; height: 64%; border-radius: 50%; }
html.ui-hpOrb .player-orb::before { content: ""; position: absolute; inset: 14%; z-index: 1; border-radius: 50%; background: radial-gradient(circle at 40% 30%, #ff9a9a, #c41c1c 55%, #520808); opacity: 0.6; clip-path: inset(calc((1 - var(--hp, 1)) * 100%) 0 0 0); pointer-events: none; }
html.ui-hpOrb .player-orb::after { content: ""; position: absolute; inset: 0; z-index: 2; background: var(--ui-hpOrb) center / 100% 100% no-repeat; pointer-events: none; }
html.ui-spBar .player-orb .orb-sp { display: block; position: absolute; inset: 0; z-index: 3; background: var(--ui-spBar) center / 100% 100% no-repeat; mask: conic-gradient(#000 calc(var(--sp, 1) * 360deg), transparent 0); pointer-events: none; }
html.ui-partyFrame-frame :is(.party-member, .player-frame, .partner-frame) { border-color: transparent; border-image: var(--ui-partyFrame-frame) var(--ui-partyFrame-slice) / var(--ui-partyFrame-bw) stretch; }
:where(html.ui-partyFrame-frame) .party-frames { width: min(var(--ui-partyFrame-w), 100%); }

/* target frame (DejaVu3:FrameMonster): the art keeps its aspect at the top; its left 92 of 374 px is the round portrait
   socket, so the bars start after it. targetFrameElite/Boss stay unused: the wire snapshot has no monster rank. */
:where(html.ui-targetFrame) .target-frame { width: min(var(--ui-targetFrame-w), 100%); min-height: var(--ui-targetFrame-h); }
html.ui-targetFrame .target-frame { align-items: flex-start; background: var(--ui-targetFrame) left top / 100% auto no-repeat; border-color: transparent; }
html.ui-targetFrame .target-frame::before { content: ""; flex: 0 0 calc(100% * 92 / 374); }
html.ui-targetFrame .target-frame :is(.frame-name, .frame-tot) { text-shadow: 0 0 2px #000, 0 1px 2px #000; }

/* progress bars: the 3-slice fill art (hpBar = target/party HP, expBar, castBar) stretched over the fill width; the
   tracks (EXPBar*Slot*) are 0-size images in the client, so the token track stays */
html.ui-hpBar-fill-frame :is(.target-frame, .party-member, .partner-frame) .bar-hp .bar-fill { border: 0 solid transparent; background: none; border-image: var(--ui-hpBar-fill-frame) var(--ui-hpBar-fill-slice) / var(--ui-hpBar-fill-bw) stretch; }
html.ui-expBar-fill-frame .bar-exp .bar-fill { border: 0 solid transparent; background: none; border-image: var(--ui-expBar-fill-frame) var(--ui-expBar-fill-slice) / var(--ui-expBar-fill-bw) stretch; }
html.ui-castBar-fill-frame .bar-cast .bar-fill { border: 0 solid transparent; background: none; border-image: var(--ui-castBar-fill-frame) var(--ui-castBar-fill-slice) / var(--ui-castBar-fill-bw) stretch; }
html.ui-castBar-fill-frame .castbar.is-interrupted .bar-fill { border-image: none; background: var(--c-danger); }
html:is(.ui-hpBar-fill-frame, .ui-expBar-fill-frame, .ui-castBar-fill-frame) .bar-text { text-shadow: 0 0 2px #000, 0 0 2px #000, 0 1px 1px #000; }
html.ui-castFrame-frame .castbar.hud-item { padding: calc(6px * var(--ui-k)) calc(10px * var(--ui-k)); border: 1px solid transparent; border-image: var(--ui-castFrame-frame) var(--ui-castFrame-slice) / var(--ui-castFrame-bw) stretch; }
:where(html.ui-castFrame-frame) .castbar.hud-item { width: min(var(--ui-castFrame-w), 100%); }

/* slots: DejaVu/Embed frame (hotbar, bag, equipment), main:ImageSlot item shadow (bag/equipment), CDAni:SelectFrame
   over the hovered/focused slot. The hotbar strip itself (SystembarBG) is set by Game.bin, so it keeps the tokens. */
html.ui-slot-frame :is(.slot, .bag-slot, .equip-slot) { border-color: transparent; border-image: var(--ui-slot-frame) var(--ui-slot-slice) / var(--ui-slot-bw) stretch; }
html.ui-slot-frame .slot .icon { width: calc(var(--slot) - 12px); height: calc(var(--slot) - 12px); }
html.ui-slotItem :is(.bag-slot, .equip-slot) { background: var(--ui-slotItem) center / 100% 100% no-repeat, #0a1324; }
html.ui-slotHover :is(.slot, .bag-slot, .equip-slot):is(:hover, :focus-visible)::before { content: ""; position: absolute; inset: 0; background: var(--ui-slotHover) center / 100% 100% no-repeat; pointer-events: none; }

/* HUD panels */
html.ui-menuBar-frame .menu { border: 1px solid transparent; border-radius: var(--radius); border-image: var(--ui-menuBar-frame) var(--ui-menuBar-slice) / var(--ui-menuBar-bw) stretch; }
html.ui-chatFrame-frame .chat { border-color: transparent; border-image: var(--ui-chatFrame-frame) var(--ui-chatFrame-slice) / var(--ui-chatFrame-bw) stretch; }
:where(html.ui-chatFrame-frame) .chat { width: min(var(--ui-chatFrame-w), 100%); }
html.ui-questTrackerTitle .tracker-title { min-height: var(--ui-questTrackerTitle-h); padding: 2px var(--sp-2); background: var(--ui-questTrackerTitle) left center / 100% 100% no-repeat; text-shadow: 0 1px 2px #000; }
/* RadarMapWnd/MapBG halo around the map; the web map shows the whole zone (not a player-centred radar), so it stays
   square instead of the RoundImage circle that would hide the player near the map corners */
html.ui-minimapFrame .minimap-box { background: var(--ui-minimapFrame) center / 100% 100% no-repeat; border-color: transparent; }
:where(html.ui-minimapFrame) .minimap { width: min(calc(var(--ui-minimapFrame-w) * 0.75), 22vw); height: min(calc(var(--ui-minimapFrame-w) * 0.75), 22vw); }

/* character select: SelectCharacterWnd image (main:LoginFrame) behind each character row */
html.ui-screen-characterSelect-frame .char-card { background: var(--ui-screen-characterSelect-frame) center / 100% 100% no-repeat, var(--c-panel-2); }

/* ---------- mobile layout: coarse pointer or narrow viewport */
@media (max-width: 820px), (pointer: coarse) and (max-height: 520px) {
  :root { --slot: 48px; --orb: 56px; }
  .hud {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    grid-template-rows: auto auto minmax(0, 1fr) auto auto;
    grid-template-areas: "tl tr" "tc tc" "sr sr" "bl br" "bc bc";
    gap: var(--sp-1);
  }
  .frame { width: 220px; }
  .target-frame { width: min(300px, 100%); }
  .minimap { width: 112px; height: 112px; }
  .minimap-coords { display: none; }
  .hud-bottom-center { align-items: stretch; }
  .bar-exp { width: 100%; }
  .hud-bottom-right { align-items: flex-end; }
  .hotbar { flex-wrap: wrap; justify-content: flex-end; max-width: 100%; }
  .joystick {
    display: block; position: relative; width: 120px; height: 120px; border-radius: 50%;
    background: rgb(17 26 46 / 0.55); border: 2px solid var(--c-border); touch-action: none;
  }
  .joy-knob { position: absolute; left: 50%; top: 50%; width: 52px; height: 52px; margin: -26px 0 0 -26px; border-radius: 50%; background: rgb(255 209 102 / 0.85); }
  /* chat: collapsed behind the 'แชท' toggle; when open it fills the free middle row (side-right region on mobile) */
  .hud-side-right { align-items: stretch; justify-content: flex-end; min-height: 0; }
  .chat { width: 100%; display: none; }
  .chat.chat-open { display: grid; }
  /* the open chat takes the middle row: party frames, the quest tracker and the status line collapse instead of overlapping it */
  .stage:has(.chat.chat-open) :is(.party-frames, .status-line, .tracker) { display: none; }
  .chat-log { height: min(104px, 14vh); }
  .linkish { min-height: 40px; }
  .chat-tab { min-height: 40px; min-width: 40px; }
  .chat-toggle { display: inline-block; }
  .menu { gap: var(--sp-1); flex-wrap: nowrap; overflow-x: auto; justify-content: flex-start; max-width: 100%; scrollbar-width: thin; }
  .menu .btn { padding: 0 var(--sp-2); flex: none; }
  .window, .window-left, .window-center { right: auto; left: 50%; top: 50%; transform: translate(-50%, -50%); width: min(560px, calc(100% - 2 * var(--sp-2))); max-height: calc(100% - 2 * var(--sp-2)); min-height: 0; }
  .window-modal { width: min(400px, calc(100% - 2 * var(--sp-2))); }
  .window-body { padding: var(--sp-3); }
  .quest-log { grid-template-columns: 1fr; }
  .tracker { max-height: 22vh; width: 220px; }
  .party-frames { width: 180px; }
  .scene-banner { font-size: var(--fs-2); }
  .npc-head { flex-direction: column; align-items: center; }
  .loading-title { font-size: var(--fs-3); }
}
/* phone landscape: three columns so the HUD fits ~390 px of height */
@media (pointer: coarse) and (max-height: 520px) and (orientation: landscape) {
  .hud {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.3fr) minmax(0, 1fr);
    grid-template-rows: auto minmax(0, 1fr) auto;
    grid-template-areas: "tl tc tr" "tl sr tr" "bl bc br";
  }
  .hud-top-left { min-height: 0; }
  .tracker { max-height: 24vh; }
  .party-frames { width: 200px; }
  .party-member { min-height: 40px; padding: 2px var(--sp-2); }
  .joystick { width: 96px; height: 96px; }
  .joy-knob { width: 44px; height: 44px; margin: -22px 0 0 -22px; }
  .minimap { width: 88px; height: 88px; }
  .chat-log { height: min(96px, 20vh); }
  .scene-dialogue { max-height: 40vh; overflow-y: auto; }
}
@media (max-width: 420px) {
  .trade-cols { grid-template-columns: 1fr; }
}

@media (prefers-reduced-motion: reduce) {
  .dmg { animation: dmg-fade 1.2s linear forwards; }
  @keyframes dmg-fade { from { opacity: 1; } to { opacity: 0; } }
  * { scroll-behavior: auto !important; transition: none !important; }
}

/* ---------- partner (คู่หู) window + HP mini-frame, ride dismount, class change (M2) */
.partner-frame { width: 240px; padding: var(--sp-1) var(--sp-2); }
.partner-frame-icon .icon { width: 32px; height: 32px; }
.partner-frame .bar { height: 12px; }
.nameplate-partner .nameplate-name { color: #c9f7c9; }
.partner-locked { margin: 0; padding: var(--sp-3); color: var(--c-text); background: var(--c-panel-2); border: 1px solid var(--c-border); border-radius: var(--radius); }
.partner-window { display: grid; gap: var(--sp-2); }
.partner-window h3 { margin: var(--sp-2) 0 0; font-size: var(--fs-1); color: var(--c-muted); }
.partner-head { display: flex; align-items: center; gap: var(--sp-3); }
.partner-portrait { width: 56px; height: 56px; flex: none; }
.partner-meta { flex: 1; min-width: 0; display: grid; font-size: var(--fs-1); }
.partner-meta strong { font-size: var(--fs-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.partner-stars { color: var(--c-accent); letter-spacing: 1px; }
.partner-head .btn { flex: none; white-space: nowrap; }
.partner-desc { margin: 0; font-size: var(--fs-1); color: var(--c-muted); }
.partner-skills, .partner-classes { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-2); }
.partner-skill { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-1); }
.partner-skill > span { flex: 1; min-width: 0; }
.partner-class { display: flex; align-items: center; gap: var(--sp-2); padding: var(--sp-1); border: 1px solid transparent; border-radius: var(--radius); }
.partner-class.is-current { border-color: var(--c-accent); }
.partner-class-meta { flex: 1; min-width: 0; display: grid; font-size: var(--fs-1); }
.partner-class-actions { display: flex; gap: var(--sp-1); flex-wrap: wrap; justify-content: flex-end; }
.partner-class-actions .btn { white-space: nowrap; }
.ride-off { justify-self: start; }
.class-choices { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.class-choice { display: inline-flex; align-items: center; gap: var(--sp-2); min-height: var(--hit); }
.class-choice .icon { width: 32px; height: 32px; }
@media (max-width: 420px) {
  .partner-head { flex-wrap: wrap; }
  .partner-class { flex-wrap: wrap; }
  .partner-class-actions { width: 100%; }
}

/* ---------- achievements (ความสำเร็จ) window */
.achievements { display: grid; gap: var(--sp-2); }
.ach-total { margin: 0; font-size: var(--fs-1); }
.ach-groups { display: grid; gap: var(--sp-1); }
.ach-group { border: 1px solid var(--c-border); border-radius: var(--radius); background: rgb(10 19 36 / 0.6); }
.ach-group-head { display: flex; align-items: center; gap: var(--sp-2); min-height: var(--hit); padding: 0 var(--sp-3); cursor: pointer; font-size: var(--fs-1); font-weight: 700; }
.ach-group-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ach-group-count { flex: none; color: var(--c-muted); font-weight: 400; }
.ach-list { list-style: none; margin: 0; padding: 0 var(--sp-2) var(--sp-2); display: grid; gap: var(--sp-2); }
.ach-entry { display: flex; align-items: flex-start; gap: var(--sp-2); padding: var(--sp-1); border-radius: var(--radius); }
.ach-entry.is-completed { background: rgb(201 162 39 / 0.12); }
.ach-icon { flex: none; width: 40px; height: 40px; }
.ach-meta { flex: 1; min-width: 0; display: grid; gap: 2px; font-size: var(--fs-1); }
.ach-title { display: flex; gap: var(--sp-2); align-items: baseline; }
.ach-title strong { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.ach-point { flex: none; color: var(--c-accent); font-size: var(--fs-0); }
.ach-tip { margin: 0; color: var(--c-muted); font-size: var(--fs-0); white-space: pre-line; }
.bar-ach { height: 14px; }
.bar-ach .bar-fill { background: linear-gradient(90deg, #c9a227, #ffd166); }
.bar-ach .bar-text { line-height: 12px; font-size: 10px; text-shadow: 0 0 2px #000, 0 0 2px #000; }

/* ---------- life skills (hud/produce.ts): operation panel, c_qte keys, life-skill window, craft window */
.produce-panel { width: min(420px, 100%); align-items: center; }
.produce-main { flex: 1; min-width: 0; display: grid; gap: var(--sp-1); }
.produce-label { font-size: var(--fs-1); overflow-wrap: anywhere; }
.produce-bar { height: 14px; }
.produce-bar .bar-text { line-height: 12px; font-size: 10px; text-shadow: 0 0 2px #000, 0 0 2px #000; }
.produce-buttons { display: flex; flex-direction: column; gap: var(--sp-1); flex: none; }
.produce-action { min-width: 96px; }
.produce-keys { display: flex; flex-wrap: wrap; gap: var(--sp-1); }
.qte-key { min-width: var(--hit); font-weight: 700; }
.qte-key.is-done { border-color: var(--c-accent); color: var(--c-accent); }
.produce-window, .craft-window { display: grid; gap: var(--sp-2); }
.produce-skills { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-2); }
.produce-skill { display: grid; gap: 2px; font-size: var(--fs-1); }
.produce-skill-head { display: flex; justify-content: space-between; gap: var(--sp-2); }
.produce-help { margin: 0; font-size: var(--fs-1); }
/* talent grid window (web/src/hud/talents.ts): rows = c_spelltalent x, columns = cell y; the grid scrolls inside the window */
.talent-window { display: grid; gap: var(--sp-2); min-width: 0; }
.talent-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-2) var(--sp-3); }
.talent-points { color: var(--c-accent); }
.talent-level-gate { color: var(--c-danger); font-weight: 700; }
.talent-actions { flex-wrap: wrap; gap: var(--sp-2); }
.talent-scroll { position: relative; overflow: auto; max-height: min(52vh, 560px); border: 1px solid var(--c-border); border-radius: var(--radius); background: var(--c-bg); padding: var(--sp-2); }
.talent-grid { --cell: 34px; display: grid; grid-template-columns: repeat(var(--talent-cols), var(--cell)); grid-template-rows: repeat(var(--talent-rows), var(--cell)); gap: 3px; width: max-content; }
.talent-cell { width: var(--cell); height: var(--cell); padding: 0; display: grid; place-items: center; border: 2px solid var(--c-border); border-radius: 6px; background: var(--c-panel-2); color: var(--c-text); font-size: var(--fs-0); cursor: pointer; }
.talent-cell .talent-icon { width: 100%; height: 100%; border-radius: 4px; }
.talent-cell:disabled { cursor: default; }
.talent-cell.talent-locked { opacity: 0.45; filter: grayscale(1); }
.talent-cell.talent-learnable { border-color: var(--c-focus); }
.talent-cell.talent-pending { border-color: var(--c-accent); box-shadow: inset 0 0 0 2px var(--c-accent); }
.talent-cell.talent-learned { border-color: var(--c-accent); background: #3a2f0e; opacity: 1; }
.talent-abbr { font-weight: 700; }
.talent-totals ul { margin: 0; padding-left: var(--sp-4); columns: 2; font-size: var(--fs-1); }
.talent-totals h3 { margin-bottom: var(--sp-1); }
.talent-note, .talent-help { margin: 0; font-size: var(--fs-1); }
@media (max-width: 820px), (pointer: coarse) and (max-height: 520px) {
  .talent-grid { --cell: var(--hit); }
  .talent-scroll { max-height: 46vh; }
  .talent-totals ul { columns: 1; }
}
.recipe-list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-2); }
.recipe { display: flex; align-items: center; gap: var(--sp-2); padding: var(--sp-1); border: 1px solid var(--c-border); border-radius: var(--radius); background: rgb(10 19 36 / 0.6); }
.recipe.is-blocked { border-style: dashed; }
.recipe-meta { flex: 1; min-width: 0; display: grid; gap: 2px; font-size: var(--fs-1); }
.recipe-reason { color: var(--c-danger); }
.recipe .btn { flex: none; }
@media (max-width: 420px) {
  .produce-panel { flex-wrap: wrap; }
  .produce-buttons { flex-direction: row; width: 100%; }
  .recipe { flex-wrap: wrap; }
}

/* ---------- systems (hud/systems.ts, guild.ts, market.ts): NPC menu, board, cooking, mail, guild, auction, duel HUD */
.visually-hidden { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
.npc-menu:empty { display: none; }
.npc-menu { display: grid; gap: var(--sp-2); }
.npc-options { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.npc-option { white-space: normal; text-align: left; line-height: 1.3; padding-block: var(--sp-1); max-width: 100%; }
.npc-option.is-service { border-color: var(--c-accent); }
.npc-reply:empty { display: none; }
.npc-reply { padding: var(--sp-2) var(--sp-3); background: var(--c-panel-2); border-radius: var(--radius); }
.board-list, .mail-list, .guild-members { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-2); }
.board-quest { display: grid; gap: var(--sp-1); padding: var(--sp-3); background: var(--c-panel-2); border-radius: var(--radius); }
.board-quest.is-done { opacity: 0.75; }
.board-quest > .btn { justify-self: start; }
.board-quest-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: var(--sp-1) var(--sp-2); }
.board-quest-head h3 { margin: 0; min-width: 0; overflow-wrap: anywhere; }
.badge { flex: none; padding: 0 var(--sp-2); border: 1px solid var(--c-border); border-radius: 999px; font-size: var(--fs-0); color: var(--c-muted); white-space: nowrap; }
.badge-available { color: var(--c-accent); border-color: var(--c-accent); }
.badge-ready { color: #8dff8d; border-color: #8dff8d; }
.mail { display: grid; gap: var(--sp-1); padding: var(--sp-2) var(--sp-3); background: var(--c-panel-2); border-radius: var(--radius); font-size: var(--fs-1); }
.mail-head { display: grid; }
.mail-body { margin: 0; white-space: pre-line; overflow-wrap: anywhere; }
.mail-foot { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--sp-2); }
.mail-item { display: inline-flex; align-items: center; gap: var(--sp-2); min-width: 0; }
.row-actions { display: inline-flex; gap: var(--sp-1); }
.guild-window { display: grid; gap: var(--sp-3); }
.guild-head { display: grid; gap: var(--sp-1); }
.guild-head h3, .guild-head p, .guild-sub { margin: 0; }
.guild-head .muted { font-size: var(--fs-1); }
.guild-info-text { margin: 0; white-space: pre-line; overflow-wrap: anywhere; font-size: var(--fs-1); }
.guild-info-edit { width: 100%; min-height: calc(3 * 1.5em + var(--sp-3)); padding: var(--sp-2) var(--sp-3); border: 1px solid var(--c-border); border-radius: var(--radius); background: #0a1324; color: var(--c-text); font: inherit; font-size: var(--fs-1); resize: vertical; }
.guild-info .row, .guild-create .row { margin-top: var(--sp-2); }
.guild-create { display: grid; gap: var(--sp-1); }
.guild-create p { margin: 0; }
.inline-form { display: flex; gap: var(--sp-2); align-items: center; }
.inline-form input { flex: 1; min-width: 0; }
.guild-member { display: flex; align-items: center; gap: var(--sp-2); padding: var(--sp-1) var(--sp-2); min-height: var(--hit); background: var(--c-panel-2); border-radius: var(--radius); }
.guild-member.is-offline .guild-member-name { opacity: 0.7; }
.guild-member-name { flex: 1; min-width: 0; display: grid; font-size: var(--fs-1); }
.guild-member-name strong { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.online-dot { flex: none; width: 10px; height: 10px; border-radius: 50%; border: 1px solid var(--c-muted); }
.online-dot.is-on { background: #8dff8d; border-color: #8dff8d; }
.guild-actions { margin-top: 0; }
.chat-ch-guild { color: #ffbf80; }
.market { display: grid; gap: var(--sp-2); }
.market-tab { display: grid; gap: var(--sp-2); }
.market-filter { display: grid; grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr) auto; gap: var(--sp-2); align-items: center; }
.market-type { width: 100%; }
.market-row { flex-wrap: wrap; }
.market-price { flex: none; font-size: var(--fs-1); color: var(--c-accent); font-variant-numeric: tabular-nums; }
.market-pager { justify-content: center; margin-top: 0; }
.bag-slot.is-blocked { opacity: 0.4; cursor: not-allowed; }
.market-sell { display: grid; gap: var(--sp-2); padding: var(--sp-3); background: var(--c-panel-2); border-radius: var(--radius); }
.market-sell .row { margin-top: 0; }
.market-sell-item { display: flex; align-items: center; gap: var(--sp-2); }
.market-sell-fields { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); gap: var(--sp-2); }
.market-sell-fields label { margin-top: 0; }
.duel-hud { width: auto; justify-content: center; font-weight: 700; color: var(--c-accent); font-variant-numeric: tabular-nums; }
.duel-hud.is-countdown { font-size: var(--fs-3); }
@media (max-width: 420px) {
  .market-filter { grid-template-columns: minmax(0, 1fr) auto; }
  .market-type { grid-column: 1 / -1; }
  .market-sell-fields { grid-template-columns: 1fr; }
}

/* ---------- equipment growth (hud/gear.ts strengthen + Dragocite windows; hud/items.ts badges, tooltip lines, set summary) */
.slot-plus { position: absolute; left: 2px; top: 1px; font-size: 11px; font-weight: 700; color: var(--c-accent); text-shadow: 0 0 2px #000, 0 1px 1px #000; pointer-events: none; }
.tip-gear { color: var(--c-accent); }
.tip-jade { color: #8fe3ff; }
.tip-set-head { margin-top: var(--sp-1); color: #8dff8d; font-weight: 700; }
.tip-set { color: var(--c-muted); }
.tip-set.is-active { color: #8dff8d; }
.equip-sets { margin-top: var(--sp-3); display: grid; gap: var(--sp-2); font-size: var(--fs-1); }
.equip-sets h3 { margin: 0; }
.equip-set { padding: var(--sp-2); background: var(--c-panel-2); border-radius: var(--radius); }
.gear-window { display: grid; gap: var(--sp-3); min-width: 0; }
.gear-cols { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--sp-3); }
.gear-col { min-width: 0; display: grid; align-content: start; gap: var(--sp-2); }
.gear-col h3 { margin: 0; font-size: var(--fs-2); }
.gear-list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-1); max-height: min(30vh, 260px); overflow-y: auto; overscroll-behavior: contain; }
.gear-pick { width: 100%; min-height: var(--hit); display: flex; align-items: center; gap: var(--sp-2); padding: var(--sp-1); border: 1px solid var(--c-border); border-radius: var(--radius); background: rgb(10 19 36 / 0.6); color: var(--c-text); font: inherit; text-align: left; cursor: pointer; }
.gear-pick .icon { flex: none; width: 36px; height: 36px; }
.gear-pick.is-selected { border-color: var(--c-accent); box-shadow: inset 0 0 0 1px var(--c-accent); }
.gear-pick.is-blocked { border-style: dashed; }
.gear-pick:disabled { cursor: default; opacity: 0.7; }
.gear-pick-meta { min-width: 0; display: grid; gap: 2px; font-size: var(--fs-1); }
.gear-pick-meta > * { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.gear-preview { display: grid; gap: var(--sp-2); padding: var(--sp-3); background: var(--c-panel-2); border: 1px solid var(--c-border); border-radius: var(--radius); font-size: var(--fs-1); }
.gear-preview p { margin: 0; }
.gear-preview-body { display: grid; gap: var(--sp-2); }
.gear-preview-head { display: flex; align-items: center; gap: var(--sp-2); }
.gear-preview-head > div { display: grid; }
.gear-arrow { color: var(--c-accent); font-size: var(--fs-2); }
.gear-rate { font-weight: 700; }
.gear-rate.is-sure { color: #8dff8d; }
.gear-actions { margin-top: 0; justify-content: flex-end; }
.gear-result { padding: var(--sp-2); border-radius: var(--radius); font-weight: 700; text-align: center; }
.gear-result.is-success { background: #213a12; color: #c8ffb0; }
.gear-result.is-fail { background: #3a1616; color: var(--c-danger); }
.gear-preview.flash-success { animation: gear-flash-ok 0.9s ease-out; }
.gear-preview.flash-fail { animation: gear-flash-bad 0.9s ease-out; }
@keyframes gear-flash-ok { from { box-shadow: 0 0 0 3px #8dff8d, 0 0 24px #8dff8d; } to { box-shadow: none; } }
@keyframes gear-flash-bad { from { box-shadow: 0 0 0 3px var(--c-danger); } to { box-shadow: none; } }
@media (prefers-reduced-motion: reduce) {
  .gear-preview.flash-success, .gear-preview.flash-fail { animation: none; }
}
@media (max-width: 820px), (pointer: coarse) and (max-height: 520px) {
  .gear-cols { grid-template-columns: 1fr; }
  .gear-list { max-height: 22vh; }
}
