:root {
  --bg: #12141a;
  --bg-2: #181b23;
  --bg-3: #1f232d;
  --line: #2a2f3b;
  --fg: #e6e9f0;
  --fg-dim: #99a0b0;
  --fg-faint: #6b7284;
  --accent: #6ea8ff;
  --accent-dim: #2b4a80;
  --new: #7ad07a;
  --season: #8a6ad8;
  --val: #ffcc66;
  --val-line: #6b5520;
  --guess: #ff8f6b;
  --radius: 10px;
  --header-h: 64px;
  /* the inspector column, reserved whether or not something is selected */
  --detail-w: clamp(300px, 20vw, 400px);
}

@media (prefers-color-scheme: light) {
  :root {
    --bg: #f5f6f8;
    --bg-2: #ffffff;
    --bg-3: #eceef2;
    --line: #d8dbe3;
    --fg: #1b1e26;
    --fg-dim: #5b6273;
    --fg-faint: #878e9e;
    --accent: #2563c9;
    --accent-dim: #bcd0f0;
    --season: #6f4fc0;
    --val: #9a6b00;
    --val-line: #d8c08a;
    --guess: #c04a1e;
  }
}

* { box-sizing: border-box; }
[hidden] { display: none !important; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font: 14px/1.5 "Pretendard", "Malgun Gothic", -apple-system, system-ui, sans-serif;
  -webkit-font-smoothing: antialiased;
}

/* ---------------------------------------------------------------- topbar */
.topbar {
  position: sticky; top: 0; z-index: 30;
  /* Sized by its own content, never by --header-h: that variable is measured
     *from* this element (see syncHeaderHeight), and feeding it back in meant a
     tall header picked up at a narrow width stayed tall after the window grew. */
  min-height: 64px;
  display: flex; align-items: center; gap: 8px 24px; flex-wrap: wrap;
  padding: 8px 20px;
  background: color-mix(in srgb, var(--bg-2) 92%, transparent);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--line);
}
.brand { display: flex; align-items: center; gap: 12px; min-width: 0; }
.logo {
  display: grid; place-items: center;
  width: 34px; height: 34px; border-radius: 9px;
  background: linear-gradient(135deg, var(--accent), #a06bff);
  color: #fff; font-weight: 800; font-size: 13px; letter-spacing: .5px;
}
.topbar h1 { margin: 0; font-size: 15px; font-weight: 650; white-space: nowrap; }
.sub { margin: 0; font-size: 11.5px; color: var(--fg-faint); white-space: nowrap; }

.search-wrap { position: relative; flex: 1 1 200px; max-width: 520px; }
#search {
  width: 100%; padding: 9px 40px 9px 13px;
  background: var(--bg-3); color: var(--fg);
  border: 1px solid var(--line); border-radius: 8px;
  font: inherit; outline: none;
}
#search:focus { border-color: var(--accent); }
.search-wrap kbd {
  position: absolute; right: 10px; top: 50%; transform: translateY(-50%);
  font: 11px/1 ui-monospace, monospace; color: var(--fg-faint);
  border: 1px solid var(--line); border-radius: 4px; padding: 3px 5px;
  background: var(--bg-2); pointer-events: none;
}

.tabs { display: flex; gap: 4px; flex: 1 1 100%; order: 3; min-width: 0; overflow-x: auto; }
.tab {
  flex: none; white-space: nowrap;
  background: none; border: 0; color: var(--fg-dim);
  padding: 7px 12px; border-radius: 7px; font: inherit; cursor: pointer;
}
.tab:hover { background: var(--bg-3); color: var(--fg); }
.tab.active { background: var(--accent-dim); color: var(--fg); }

/* ---------------------------------------------------------------- layout */
.layout {
  display: grid;
  grid-template-columns: 232px minmax(0, 1fr);
  align-items: start;
}
.layout:has(.detail:not([hidden])) {
  grid-template-columns: 232px minmax(0, 1fr) var(--detail-w); }
body.no-sidebar .sidebar,
/* Views without a sidebar normally have nothing to inspect -- the monster tab
   does, so it opts back in rather than every other view opting out. */
body.no-sidebar:not(.has-detail) .detail { display: none; }
body.no-sidebar .layout,
body.no-sidebar .layout:has(.detail:not([hidden])) { grid-template-columns: minmax(0, 1fr); }
body.no-sidebar.has-detail .layout:has(.detail:not([hidden])) {
  grid-template-columns: minmax(0, 1fr) var(--detail-w); }

.sidebar {
  position: sticky; top: var(--header-h);
  height: calc(100vh - var(--header-h));
  overflow-y: auto;
  padding: 16px 12px 40px;
  border-right: 1px solid var(--line);
  background: var(--bg-2);
}
.side-block { margin-bottom: 22px; }
.side-block h2 {
  margin: 0 0 8px 6px; font-size: 11px; font-weight: 700;
  letter-spacing: .08em; text-transform: uppercase; color: var(--fg-faint);
}

.cat-list { list-style: none; margin: 0; padding: 0; }
.cat-list li > button {
  width: 100%; display: flex; align-items: center; gap: 8px;
  background: none; border: 0; color: var(--fg-dim);
  padding: 6px 8px; border-radius: 7px; font: inherit; cursor: pointer; text-align: left;
}
.cat-list li > button:hover { background: var(--bg-3); color: var(--fg); }
.cat-list li > button.active { background: var(--accent-dim); color: var(--fg); font-weight: 600; }
.cat-list .count { margin-left: auto; font-size: 11px; color: var(--fg-faint); font-variant-numeric: tabular-nums; }
.cat-list .kind-head {
  margin: 12px 6px 4px; font-size: 11px; font-weight: 700; color: var(--fg-faint);
}
.cat-list .sub-item { padding-left: 18px; }
.cat-list .leaf-item { padding-left: 30px; font-size: 12px; opacity: .82; }

.ctl { display: flex; align-items: center; gap: 10px; padding: 6px 8px; color: var(--fg-dim); }
.ctl > span { min-width: 34px; font-size: 12px; }
.ctl input[type=range] { flex: 1; accent-color: var(--accent); }
.ctl select {
  flex: 1; background: var(--bg-3); color: var(--fg);
  border: 1px solid var(--line); border-radius: 6px; padding: 5px 7px; font: inherit;
}
.ctl.checkbox { gap: 8px; font-size: 12.5px; cursor: pointer; }
.ctl.checkbox input { accent-color: var(--accent); }

/* --------------------------------------------------------------- content */
.content { min-width: 0; padding: 16px 20px 60px; }
.result-bar {
  display: flex; align-items: center; gap: 10px;
  margin-bottom: 14px; font-size: 12.5px; color: var(--fg-dim);
}
.spacer { flex: 1; }
.chips { display: flex; gap: 6px; flex-wrap: wrap; }
.chip {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--bg-3); border: 1px solid var(--line);
  border-radius: 999px; padding: 3px 10px; font-size: 12px; color: var(--fg-dim);
}
.chip button { background: none; border: 0; color: var(--fg-faint); cursor: pointer; padding: 0; font-size: 14px; line-height: 1; }
.chip button:hover { color: var(--fg); }

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(var(--cell, 96px), 1fr));
  gap: 10px;
}
.card {
  background: var(--bg-2); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 8px 6px 7px;
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  cursor: pointer; position: relative;
  transition: border-color .12s, transform .12s;
}
.card:hover { border-color: var(--accent); transform: translateY(-1px); }
.card.selected { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent) inset; }
.card img {
  width: 100%; aspect-ratio: 1; object-fit: contain;
  image-rendering: -webkit-optimize-contrast;
  background: repeating-conic-gradient(var(--bg-3) 0 25%, transparent 0 50%) 50%/12px 12px;
  border-radius: 6px;
}
.card .name {
  font-size: 10.5px; line-height: 1.3; color: var(--fg-dim);
  word-break: break-all; text-align: center;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.card .name.ko {
  color: var(--fg); font-size: 11.5px; font-weight: 600;
  word-break: keep-all; -webkit-line-clamp: 2;
}
.card .name.sub {
  font-size: 9.5px; color: var(--fg-faint); margin-top: -3px; -webkit-line-clamp: 1;
}
/* label borrowed from the icon id because the sheet carries no name */
.card .name.unnamed {
  color: var(--fg-dim); font-size: 10.5px; font-style: italic;
  word-break: break-all; -webkit-line-clamp: 2;
}
.ko-desc {
  margin: 10px 0 0; padding: 9px 11px;
  background: var(--bg-3); border: 1px solid var(--line); border-radius: 8px;
  font-size: 12.5px; line-height: 1.55; color: var(--fg-dim);
  white-space: pre-wrap; word-break: keep-all;
}
.card .badge-new {
  position: absolute; top: 5px; right: 5px;
  background: var(--new); color: #06210a;
  font-size: 9px; font-weight: 800; padding: 1px 5px; border-radius: 4px;
}
.card .badge-3d {
  position: absolute; bottom: 5px; right: 5px;
  background: var(--accent-dim); color: var(--fg);
  font-size: 9px; font-weight: 800; padding: 1px 5px; border-radius: 4px;
  letter-spacing: .3px;
}
/* A number the client resolved from a sheet, as opposed to one the writer
   typed into the sentence. Tinted, and its column named on hover. */
.ko-desc .val, .kv .val {
  color: var(--val); font-weight: 600;
  border-bottom: 1px dotted var(--val-line); cursor: help;
}
/* Inferred, not read. Deliberately a different hue from the confirmed values
   so the two are never mistaken for each other at a glance. */
.ko-desc .val.guess, .kv .val.guess {
  color: var(--guess); border-bottom-style: dashed; border-bottom-color: var(--guess);
}
.ko-desc .val.guess sup { font-size: 8px; opacity: .8; margin-left: 1px; }
.detail h4 .hint { font-weight: 400; font-size: 11px; color: var(--fg-faint); }
/* Read off the screen rather than out of the sheets -- the only source for the
   cards that point at rows this build does not ship. */
.ko-desc .val.measured, .kv .val.measured {
  color: var(--new); border-bottom-color: var(--new); border-bottom-style: solid;
}
.sk-tags { margin: 2px 0 10px; display: flex; flex-wrap: wrap; gap: 4px; }
.sk-tags .chip {
  font-size: 10.5px; font-weight: 700; padding: 2px 7px; border-radius: 999px;
  border: 1px solid var(--line); color: var(--fg-dim);
}
.sk-tags .chip.tag { color: var(--val); border-color: var(--val-line); cursor: help; }
.sk-tags .chip.kind.active { color: var(--accent); border-color: var(--accent); }
.sk-tags .chip.kind.passive { color: var(--fg-faint); }
.sk-tags .chip.season { color: #fff; background: var(--season); border-color: var(--season); }
.sk-tags .chip.ult { background: var(--accent-dim); color: var(--fg); border-color: transparent; }
/* Top-left, the one corner the other three badges do not use. */
.card .badge-kind {
  position: absolute; top: 5px; left: 5px;
  font-size: 9px; font-weight: 800; padding: 1px 5px; border-radius: 4px;
  background: var(--bg-3); color: var(--fg-dim); border: 1px solid var(--line);
}
.card .badge-kind.passive { opacity: .75; }
.card .badge-kind.active { color: var(--accent); }
/* Its own corner, so a skill that is both season and ultimate shows both. */
.card .badge-season {
  position: absolute; bottom: 5px; left: 5px;
  background: var(--season); color: #fff;
  font-size: 9px; font-weight: 800; padding: 1px 5px; border-radius: 4px;
  letter-spacing: .3px;
}
.badge-new.inline {
  position: static; display: inline-block; margin-left: 3px; vertical-align: 1px;
  background: var(--new); color: #06210a;
  font-size: 8.5px; font-weight: 800; padding: 1px 4px; border-radius: 4px;
}
.model-jump { margin-top: 10px; }
.model-jump button {
  width: 100%; padding: 8px 10px; font: inherit; font-size: 12.5px; cursor: pointer;
  background: var(--accent-dim); color: var(--fg);
  border: 1px solid var(--accent); border-radius: 8px;
}
.model-jump button:hover { background: var(--accent); color: #071426; }

/* `flex: none` matters: inside `.model-browse`, which is a flex column,
   the sentinel was shrunk to zero height -- and a zero-height element never
   intersects, so the 3D grid stopped loading after its first 120 cards. */
.sentinel { height: 40px; flex: none; }
.empty { color: var(--fg-faint); text-align: center; padding: 60px 0; }

/* ---------------------------------------------------------------- detail */
.detail {
  position: sticky; top: var(--header-h);
  height: calc(100vh - var(--header-h));
  overflow-y: auto;
  border-left: 1px solid var(--line);
  background: var(--bg-2);
  padding: 18px 18px 40px;
}
.detail .close {
  position: absolute; top: 10px; right: 12px;
  background: none; border: 0; color: var(--fg-faint);
  font-size: 22px; line-height: 1; cursor: pointer;
}
.detail .close:hover { color: var(--fg); }
/* nothing selected: the column holds its place and says so */
.detail.empty .close { display: none; }
.detail-hint { color: var(--fg-faint); font-size: 12.5px; line-height: 1.7;
  margin: 6px 2px; word-break: keep-all; }
.detail h3 { margin: 0 0 4px; font-size: 15px; word-break: break-all; }
.detail .hero {
  width: 100%; aspect-ratio: 1; object-fit: contain; border-radius: 10px;
  background: repeating-conic-gradient(var(--bg-3) 0 25%, transparent 0 50%) 50%/16px 16px;
  margin-bottom: 14px;
}
.kv { display: grid; grid-template-columns: 84px 1fr; gap: 6px 10px; font-size: 12.5px; margin: 12px 0; }
.kv.stats {
  grid-template-columns: 108px 1fr;
  background: var(--bg-3); border: 1px solid var(--line); border-radius: 8px;
  padding: 10px 12px; margin: 10px 0 0;
}
.kv.stats dd { color: var(--fg); font-variant-numeric: tabular-nums; }
.kv dt { color: var(--fg-faint); }
.kv dd { margin: 0; color: var(--fg-dim); word-break: break-all; }
.layer-row { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 6px; }
.layer-row figure { margin: 0; width: 72px; text-align: center; }
.layer-row img {
  width: 72px; height: 72px; object-fit: contain; border-radius: 6px;
  background: repeating-conic-gradient(var(--bg-3) 0 25%, transparent 0 50%) 50%/10px 10px;
}
.layer-row figcaption { font-size: 10px; color: var(--fg-faint); margin-top: 3px; }
.dl-row { display: flex; gap: 8px; margin-top: 14px; }
.dl-row a {
  flex: 1; text-align: center; text-decoration: none;
  background: var(--bg-3); border: 1px solid var(--line); border-radius: 8px;
  padding: 8px; color: var(--fg-dim); font-size: 12.5px;
}
.dl-row a:hover { border-color: var(--accent); color: var(--fg); }

/* ----------------------------------------------------------- other views */
.view { min-width: 0; }
.panel {
  background: var(--bg-2); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 18px 20px; margin-bottom: 16px;
}
.panel h2 { margin: 0 0 10px; font-size: 15px; }
.panel p { color: var(--fg-dim); margin: 6px 0; }
.panel code {
  background: var(--bg-3); border: 1px solid var(--line); border-radius: 5px;
  padding: 1px 5px; font: 12px ui-monospace, monospace;
}
.panel pre {
  background: var(--bg-3); border: 1px solid var(--line); border-radius: 8px;
  padding: 12px 14px; overflow-x: auto; font: 12px/1.6 ui-monospace, monospace;
  color: var(--fg-dim);
}
table.stat { width: 100%; border-collapse: collapse; font-size: 13px; }
table.stat th, table.stat td { text-align: left; padding: 7px 10px; border-bottom: 1px solid var(--line); }
table.stat th { color: var(--fg-faint); font-weight: 600; font-size: 11.5px; text-transform: uppercase; letter-spacing: .05em; }
table.stat td.num { text-align: right; font-variant-numeric: tabular-nums; }

/* ---------------------------------------------------------------- sheets */
.sheet-layout {
  display: grid; grid-template-columns: 260px minmax(0, 1fr);
  gap: 14px; height: calc(100vh - var(--header-h) - 40px);
}
.sheet-list {
  display: flex; flex-direction: column; min-height: 0;
  background: var(--bg-2); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 10px;
}
.sheet-list input {
  width: 100%; padding: 7px 10px; margin-bottom: 6px;
  background: var(--bg-3); color: var(--fg);
  border: 1px solid var(--line); border-radius: 7px; font: inherit; outline: none;
}
.sheet-list input:focus { border-color: var(--accent); }
.sheet-meta { font-size: 11px; color: var(--fg-faint); margin: 0 2px 6px; }
.sheet-list ul { list-style: none; margin: 0; padding: 0; overflow-y: auto; flex: 1; }
.sheet-list li button {
  width: 100%; display: flex; align-items: baseline; gap: 8px;
  background: none; border: 0; color: var(--fg-dim); text-align: left;
  padding: 5px 8px; border-radius: 6px; font: inherit; cursor: pointer;
}
.sheet-list li button:hover { background: var(--bg-3); color: var(--fg); }
.sheet-list li button.active { background: var(--accent-dim); color: var(--fg); }
.sheet-list .n { margin-left: auto; font-size: 11px; color: var(--fg-faint); font-variant-numeric: tabular-nums; }
.sheet-list .dot { width: 5px; height: 5px; border-radius: 50%; background: var(--new); flex: none; }
.sheet-list .dot.bad, .sheet-note .dot.bad { background: #d8a13a; }
.sheet-list .dot.none, .sheet-meta .dot.none { background: var(--fg-faint); opacity: .5; }
.sheet-list .dot.part, .sheet-meta .dot.part, .sheet-note .dot.part { background: var(--accent); }

.sheet-head .chk { display: flex; align-items: center; gap: 5px; font-size: 11.5px; color: var(--fg-dim); white-space: nowrap; }
.sheet-hits {
  max-height: 46%; overflow: auto; padding: 8px 12px 10px;
  border-bottom: 1px solid var(--line); background: var(--bg-3);
}
.sheet-hits .hint { margin: 0 0 8px; font-size: 11.5px; color: var(--fg-faint); line-height: 1.5; }
.sheet-hits ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 3px; }
.sheet-hits button {
  width: 100%; display: flex; align-items: baseline; gap: 10px;
  background: var(--bg-2); border: 1px solid var(--line); border-radius: 7px;
  padding: 6px 9px; font: inherit; color: var(--fg); text-align: left; cursor: pointer;
}
.sheet-hits button:hover { border-color: var(--accent); }
.sheet-hits .s { font-size: 12.5px; }
.sheet-hits .c { font-size: 11px; color: var(--fg-faint); font-variant-numeric: tabular-nums; }
.sheet-hits .ex { margin-left: auto; font-size: 11px; color: var(--fg-faint); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 45%; }
#sheetTable tr.unwalked td { background: var(--bg-3); white-space: normal; max-width: none; }
#sheetTable tr.unwalked .tag {
  display: inline-block; margin-right: 8px; padding: 0 5px; border-radius: 4px;
  background: var(--line); color: var(--fg-faint); font-size: 10px; font-weight: 700;
}
#sheetTable tr.unwalked .lv {
  display: inline-block; margin: 0 4px 2px 0; padding: 0 5px;
  background: var(--bg-2); border: 1px solid var(--line); border-radius: 4px;
  color: var(--fg-dim); font-variant-numeric: tabular-nums;
}
#sheetTable tr.unwalked .lv.ko { color: var(--fg); }
#sheetTable tr.added td { box-shadow: inset 3px 0 0 var(--new); }
#sheetTable tr.changed td { box-shadow: inset 3px 0 0 var(--accent); }
.sheet-note .chg { color: var(--accent); }
.sheet-list .chg-dot {
  margin-left: 6px; padding: 0 5px; border-radius: 999px;
  background: var(--accent-dim); color: var(--fg); font-size: 10px; font-weight: 700;
}
.sheet-list .chg-dot.approx { background: var(--line); color: var(--fg-faint); }
.card .badge-edit {
  position: absolute; top: 5px; right: 5px;
  background: var(--accent); color: #071426;
  font-size: 9px; font-weight: 800; padding: 1px 5px; border-radius: 4px;
}
.kv.text-diff { grid-template-columns: 44px 1fr; }
.kv.text-diff dd { display: grid; gap: 3px; word-break: keep-all; overflow-wrap: anywhere; }
.kv.text-diff .was { color: var(--fg-faint); text-decoration: line-through; }
.kv.text-diff .was.none, .kv.text-diff .now.none { font-style: italic; text-decoration: none; }
.kv.text-diff .now { color: var(--fg); }
.kv.text-diff .arrow { color: var(--fg-faint); font-size: 10px; }
.sheet-meta .dot { display: inline-block; width: 5px; height: 5px; border-radius: 50%; background: var(--new); margin-right: 4px; }
.sheet-meta .dot.bad { background: #d8a13a; }

.sheet-pane {
  display: flex; flex-direction: column; min-width: 0; min-height: 0;
  background: var(--bg-2); border: 1px solid var(--line); border-radius: var(--radius);
}
.sheet-head {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 12px; border-bottom: 1px solid var(--line);
  /* a toolbar of toggles and selects; the UI tab's row alone measures 1808px,
     so it wraps at every width rather than pushing the page sideways */
  flex-wrap: wrap; row-gap: 8px;
}
.sheet-head h2 { margin: 0; font-size: 14px; }
.sheet-head input:not([type=checkbox]):not([type=range]) {
  width: 200px; padding: 6px 9px; background: var(--bg-3); color: var(--fg);
  border: 1px solid var(--line); border-radius: 7px; font: inherit; outline: none;
}
.sheet-head input:focus { border-color: var(--accent); }
.ctl-note { margin: -2px 0 8px; font-size: 11px; line-height: 1.45; color: var(--fg-faint); }

.kv.stats dd.long {
  grid-column: 1 / -1; margin: 2px 0 6px; line-height: 1.55;
  word-break: keep-all; overflow-wrap: anywhere;
}
dl.args {
  display: grid; grid-template-columns: auto 1fr; gap: 2px 10px;
  margin: 2px 0 0; font-size: 11.5px;
}
dl.args dt { color: var(--fg-faint); word-break: break-all; }
dl.args dd { margin: 0; color: var(--fg); word-break: break-all; }

.ko-desc .ref, .kv.stats .ref {
  color: var(--fg-faint); font-size: .92em;
  border-bottom: 1px dotted var(--line);
}

.card.no-art .noart {
  width: 100%; aspect-ratio: 1; display: flex;
  align-items: center; justify-content: center;
  background: var(--bg-3); border: 1px dashed var(--line); border-radius: 8px;
  color: var(--fg-faint); font-size: calc(var(--cell, 96px) * .26); font-weight: 700;
}
.card.no-art:hover .noart { border-color: var(--accent); color: var(--fg-dim); }
.hero.none {
  display: flex; align-items: center; justify-content: center;
  aspect-ratio: 1; border: 1px dashed var(--line); border-radius: 10px;
  background: var(--bg-3); color: var(--fg-faint); font-size: 13px;
  margin-bottom: 14px;
}
.note-none {
  margin: 10px 0 0; padding: 8px 10px; font-size: 11.5px; line-height: 1.55;
  color: var(--fg-faint); background: var(--bg-3);
  border: 1px solid var(--line); border-radius: 8px;
}

.badge-share {
  position: absolute; top: 4px; left: 4px; padding: 0 5px; height: 15px;
  display: flex; align-items: center; border-radius: 8px;
  background: var(--accent-dim); color: var(--fg);
  font-size: 10px; font-weight: 700; font-variant-numeric: tabular-nums;
}
.share-head { margin: 14px 0 6px; font-size: 12px; color: var(--fg-faint); }
.share-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 3px; }
.share-list button {
  width: 100%; display: flex; align-items: baseline; gap: 8px;
  background: var(--bg-3); border: 1px solid var(--line); border-radius: 7px;
  padding: 6px 9px; font: inherit; color: var(--fg); text-align: left; cursor: pointer;
}
.share-list button:hover { border-color: var(--accent); }
.share-list .ko { font-size: 12.5px; }
.share-list .sub { margin-left: auto; font-size: 11px; color: var(--fg-faint); }

.sheet-note { padding: 6px 12px; font-size: 11.5px; color: var(--fg-faint); }
.sheet-note .dot { display: inline-block; width: 5px; height: 5px; border-radius: 50%; background: var(--new); margin-right: 4px; vertical-align: 2px; }
.sheet-note.warn {
  color: #c98b1e; background: rgba(216, 161, 58, .09);
  border-bottom: 1px solid rgba(216, 161, 58, .3); line-height: 1.5;
}
.sheet-scroll { overflow: auto; flex: 1; min-height: 0; }
#sheetTable { border-collapse: collapse; font-size: 12px; width: max-content; min-width: 100%; }
#sheetTable th, #sheetTable td {
  border-bottom: 1px solid var(--line); border-right: 1px solid var(--line);
  padding: 5px 9px; text-align: left; white-space: nowrap;
  max-width: 380px; overflow: hidden; text-overflow: ellipsis;
}
#sheetTable th {
  position: sticky; top: 0; z-index: 2;
  background: var(--bg-3); color: var(--fg-dim);
  font-weight: 600; font-size: 11px;
}
#sheetTable th.guess { color: var(--fg-faint); font-weight: 400; }
#sheetTable td.num { text-align: right; font-variant-numeric: tabular-nums; color: var(--fg-dim); }
#sheetTable td.ko { color: var(--fg); }
#sheetTable tbody tr:hover td { background: var(--bg-3); }
#sheetTable td.idx { color: var(--fg-faint); font-variant-numeric: tabular-nums; }

/* ------------------------------------------------------------- 3D models */
.models-layout {
  display: grid; grid-template-columns: 260px minmax(0, 1fr);
  gap: 14px; height: calc(100vh - var(--header-h) - 40px);
}
.model-list {
  display: flex; flex-direction: column; min-height: 0;
  background: var(--bg-2); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 10px;
}
.model-list #modelSearch {
  width: 100%; padding: 7px 10px; margin-bottom: 8px;
  background: var(--bg-3); color: var(--fg);
  border: 1px solid var(--line); border-radius: 7px; font: inherit; outline: none;
}
.model-list #modelSearch:focus { border-color: var(--accent); }
.model-cats { display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 8px; }
/* the models panel picks its grouping with selects; the pill styling below is
   still used by the UI and map tabs, which have few enough groups to show flat */
#modelCats { flex-direction: column; gap: 2px; }
#modelCats .ctl { padding: 4px 2px; }
#modelCats .ctl > span { min-width: 30px; }
.model-cats button {
  background: var(--bg-3); border: 1px solid var(--line); color: var(--fg-dim);
  border-radius: 999px; padding: 3px 9px; font-size: 11.5px; cursor: pointer;
}
.model-cats button:hover { color: var(--fg); }
.model-cats button.active { background: var(--accent-dim); border-color: var(--accent); color: var(--fg); }
.model-list ul { list-style: none; margin: 0; padding: 0; overflow-y: auto; flex: 1; }
.model-list li button {
  width: 100%; text-align: left; background: none; border: 0; color: var(--fg-dim);
  padding: 6px 8px; border-radius: 6px; font: inherit; cursor: pointer;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.model-list li button:hover { background: var(--bg-3); color: var(--fg); }
.model-list li button.active { background: var(--accent-dim); color: var(--fg); }

.model-browse {
  display: flex; flex-direction: column; min-height: 0; min-width: 0;
  background: var(--bg-2); border: 1px solid var(--line);
  border-radius: var(--radius); overflow: auto; padding: 10px 12px 0;
}
.browse-bar {
  display: flex; align-items: center; gap: 12px; padding-bottom: 10px;
  flex-wrap: wrap; row-gap: 8px;
  font-size: 12px; color: var(--fg-dim);
  position: sticky; top: -10px; z-index: 2;
  background: var(--bg-2); border-bottom: 1px solid var(--line); margin: -10px -12px 10px;
  padding: 10px 12px;
}
.browse-bar .spacer { flex: 1; }
.ctl.inline { display: flex; align-items: center; gap: 6px; margin: 0; font-size: 11.5px; }
.ctl.inline input[type=range] { width: 110px; }
.browse-bar .chk { display: flex; align-items: center; gap: 5px; font-size: 11.5px; white-space: nowrap; }
#modelGrid { --cell: 112px; }
#modelGrid .card .badge-3d {
  left: 5px; right: auto; bottom: 5px;
  max-width: calc(100% - 12px); overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.model-stage .back { position: absolute; top: 10px; left: 10px; z-index: 3; }
.model-stage .stage-toolbar { left: 84px; }
.stage-info .dim { color: var(--fg-faint); }

.model-stage {
  position: relative; min-height: 0;
  background: radial-gradient(circle at 50% 35%,
              color-mix(in srgb, var(--bg-3) 80%, var(--bg-2)), var(--bg-2));
  border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden;
}
#modelCanvas { display: block; width: 100%; height: 100%; touch-action: none; cursor: grab; }
#modelCanvas:active { cursor: grabbing; }
.stage-toolbar {
  position: absolute; top: 10px; left: 10px; right: 10px;
  display: flex; gap: 6px; align-items: center;
}
.sbtn {
  background: color-mix(in srgb, var(--bg-2) 88%, transparent);
  border: 1px solid var(--line); color: var(--fg-dim);
  border-radius: 7px; padding: 5px 10px; font: inherit; font-size: 12px;
  cursor: pointer; text-decoration: none; backdrop-filter: blur(6px);
}
.sbtn:hover { color: var(--fg); border-color: var(--accent); }
.sbtn[aria-pressed="true"] { background: var(--accent-dim); color: var(--fg); }
.stage-info {
  position: absolute; left: 12px; bottom: 34px;
  font-size: 12.5px; color: var(--fg-dim);
  background: color-mix(in srgb, var(--bg-2) 82%, transparent);
  border: 1px solid var(--line); border-radius: 8px; padding: 6px 10px;
  backdrop-filter: blur(6px); max-width: 70%;
}
.stage-hint {
  position: absolute; left: 12px; bottom: 10px;
  font-size: 11px; color: var(--fg-faint);
}

/* ------------------------------------------------------------- UI screens */
.ui-layout {
  display: grid; grid-template-columns: 300px minmax(0, 1fr);
  gap: 14px; height: calc(100vh - var(--header-h) - 40px);
}
.content:has(> #view-ui:not([hidden])) { padding-bottom: 16px; }
.content:has(> #view-ui:not([hidden])) .result-bar { display: none; }
.content > #view-ui .ui-layout { height: calc(100dvh - var(--header-h) - 32px); }
.ui-pane .sheet-head h2 { overflow-wrap: anywhere; min-width: 0; }
.ui-list {
  display: flex; flex-direction: column; min-height: 0;
  background: var(--bg-2); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 10px;
}
.ui-list #uiSearch {
  width: 100%; padding: 7px 10px; margin-bottom: 8px;
  background: var(--bg-3); color: var(--fg);
  border: 1px solid var(--line); border-radius: 7px; font: inherit; outline: none;
}
.ui-list #uiSearch:focus { border-color: var(--accent); }
.ui-list ul { list-style: none; margin: 0; padding: 0; overflow-y: auto; flex: 1; }
.ui-list li button {
  width: 100%; display: flex; align-items: baseline; gap: 8px;
  background: none; border: 0; color: var(--fg-dim); text-align: left;
  padding: 5px 8px; border-radius: 6px; font: inherit; font-size: 12px; cursor: pointer;
}
.ui-list li button span:first-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ui-list li button:hover { background: var(--bg-3); color: var(--fg); }
.ui-list li button.active { background: var(--accent-dim); color: var(--fg); }
.ui-list .n { margin-left: auto; font-size: 11px; color: var(--fg-faint); font-variant-numeric: tabular-nums; }
.ui-pane {
  display: flex; flex-direction: column; min-width: 0; min-height: 0;
  background: var(--bg-2); border: 1px solid var(--line); border-radius: var(--radius);
}
.ui-stage { flex: 1; min-height: 0; overflow: auto; position: relative; padding: 16px; }
/* the stage is the game's own canvas, so it does not follow the site theme --
   a screen drawn for a dark HUD needs a dark ground to be legible either way */
.ui-stage[data-bg="dark"] { background: #14161c; }
.ui-stage[data-bg="light"] { background: #e9ebf0; }
.ui-stage[data-bg="checker"] {
  background: repeating-conic-gradient(#9aa0ad 0 25%, #cfd4dc 0 50%) 50%/24px 24px;
}
#uiCanvasSize { position: relative; flex: none; overflow: hidden; }
#uiCanvas { position: absolute; transform-origin: top left; outline: 1px solid var(--line); }
.ui-stage[data-bg="dark"] #uiCanvas { background: rgba(0, 0, 0, .25); }
.ui-stage[data-bg="light"] #uiCanvas { background: rgba(255, 255, 255, .25); }
.ui-list #uiCats { max-height: 132px; overflow-y: auto; }
.uin { position: absolute; }
img.uin { object-fit: fill; image-rendering: auto; }
.uit { color: #fff; text-shadow: 0 1px 2px rgba(0,0,0,.8); overflow: hidden; line-height: 1.2; }
.uis { border-style: solid; box-sizing: border-box; }
.uib { border: 0; }
#uiCanvas.outline .uib { border: 1px dashed rgba(255,255,255,.4); }
.uio { border: 1px solid rgba(110,168,255,.35); }
#uiCanvas.outline .uin { outline: 1px solid rgba(110,168,255,.45); }
.warn-inline { color: #c98b1e; }

/* ------------------------------------------------- tween playback controls */
.tween-bar {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 8px 12px; border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line); background: var(--bg-3);
}
.tween-bar #uiTwTime { flex: 1; min-width: 140px; }
.tween-bar select { max-width: 260px; }
.tw-play {
  padding: 4px 12px; border-radius: var(--radius); cursor: pointer;
  border: 1px solid var(--line); background: var(--bg-2); color: var(--fg);
  font-variant-numeric: tabular-nums;
}
.tw-play:hover:not(:disabled) { background: var(--accent-dim); }
.tw-play:disabled { opacity: .45; cursor: default; }
.tw-time { font-variant-numeric: tabular-nums; color: var(--fg-dim); min-width: 52px; }
.tw-meta { font-size: 12px; color: var(--fg-faint); }
.tween-events {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  padding: 6px 12px; border-top: 1px solid var(--line); background: var(--bg-3);
}
.tween-events .tw-lbl { font-size: 12px; color: var(--fg-faint); }
.tween-events code {
  font-size: 11px; padding: 1px 6px; border-radius: 4px;
  background: var(--bg-2); border: 1px solid var(--line); color: var(--fg-dim);
}

/* ------------------------------------------------------------- maps view */
.map-grid {
  --cell: 130px;
  display: grid; gap: 10px; padding: 12px;
  grid-template-columns: repeat(auto-fill, minmax(var(--cell), 1fr));
}
.mapcell { margin: 0; min-width: 0; }
.mapcell img {
  width: 100%; aspect-ratio: 1; object-fit: contain; display: block;
  background: repeating-conic-gradient(#2a2d35 0 25%, #23262d 0 50%) 50%/16px 16px;
  border: 1px solid var(--line); border-radius: 6px;
}
.mapcell figcaption {
  font-size: 11px; color: var(--fg-faint); margin-top: 4px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.map-list { list-style: none; margin: 0; padding: 8px 12px; columns: 260px; }
.map-list li {
  font: 12px ui-monospace, monospace; color: var(--fg-dim);
  padding: 2px 0; break-inside: avoid;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.map-list li.gone { color: #d9a441; }
.map-list li .gver { margin-left: 8px; font-size: 10.5px; opacity: .8; }
/* a removed texture whose picture was not kept still gets a tile, so the row is
   visible instead of silently absent */
.ph-tex {
  width: 100%; aspect-ratio: 1; display: grid; place-items: center;
  border: 1px dashed rgba(217,164,65,.5); border-radius: 6px;
  background: rgba(217,164,65,.08); color: #d9a441; font-size: 11px;
}
#mapItems { list-style: none; margin: 0; padding: 0; overflow-y: auto; flex: 1; }
#mapItems li button {
  display: flex; gap: 8px; width: 100%; text-align: left; cursor: pointer;
  padding: 5px 8px; border: 0; border-radius: 4px; background: none;
  color: var(--fg-dim); font: inherit;
}
#mapItems li button:hover { background: var(--bg-3); color: var(--fg); }
#mapItems li button.active { background: var(--accent-dim); color: var(--fg); }
#mapItems li button span:first-child {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
#mapItems .n {
  margin-left: auto; font-size: 11px; color: var(--fg-faint);
  font-variant-numeric: tabular-nums;
}
.sheet-list #mapCats { max-height: 120px; overflow-y: auto; }

/* ----------------------------------------------------------- texts view */
/* The mode bar sits above a pane that has to scroll internally, so the view
   takes the viewport height and the pane gets whatever is left. Without a
   definite height here `flex: 1` has nothing to divide and the lists grow to
   their full length instead of scrolling. */
#view-texts {
  display: flex; flex-direction: column; gap: 12px;
  height: calc(100vh - var(--header-h) - 40px); min-height: 0;
}
#view-texts .sheet-layout, #view-texts #poolPane {
  flex: 1; min-height: 0; height: auto;
}
.text-modes { display: flex; align-items: center; gap: 8px; flex: none; }
.tmode {
  padding: 5px 14px; border-radius: var(--radius); cursor: pointer;
  border: 1px solid var(--line); background: var(--bg-2); color: var(--fg-dim);
}
.tmode:hover { color: var(--fg); }
.tmode.active { background: var(--accent-dim); color: var(--fg); border-color: var(--accent); }
#l10nGroups { list-style: none; margin: 0; padding: 0; overflow-y: auto; }
#l10nGroups li button {
  display: flex; gap: 8px; width: 100%; text-align: left; cursor: pointer;
  padding: 5px 8px; border: 0; border-radius: 4px; background: none;
  color: var(--fg-dim); font: inherit;
}
#l10nGroups li button:hover { background: var(--bg-3); color: var(--fg); }
#l10nGroups li button.active { background: var(--accent-dim); color: var(--fg); }
#l10nGroups li button span:first-child {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
#l10nGroups .n {
  margin-left: auto; font-size: 11px; color: var(--fg-faint);
  font-variant-numeric: tabular-nums;
}
#l10nTable .tkey, #poolTable .num { font-family: var(--mono, monospace); font-size: 12px; }
/* keys are long snake_case identifiers; wrap them only when they genuinely do
   not fit, rather than breaking every line mid-word in a narrow pane */
#l10nTable .tkey { color: var(--fg-dim); overflow-wrap: anywhere; word-break: normal; }
/* a narrow pane cannot hold two columns of this; stack the key over the text */
@media (max-width: 900px) {
  #l10nTable thead { display: none; }
  #l10nTable tr { display: block; border-bottom: 1px solid var(--line); }
  #l10nTable td { display: block; border: 0; padding: 4px 10px; }
  #l10nTable .tkey { padding-top: 8px; }
}
.tgrp {
  display: inline-block; margin-right: 6px; padding: 0 5px; border-radius: 3px;
  background: var(--bg-3); color: var(--fg-faint); font-size: 11px;
}
/* the game's own placeholders: {0} is a format argument, %noun,{0},가% is a noun
   plus the Korean particle that has to agree with it */
.tslot, .targ {
  padding: 0 4px; border-radius: 3px; font-size: 12px;
  border: 1px solid var(--line);
}
.tslot { background: rgba(110,168,255,.14); color: #7fb0ff; }
.targ { background: rgba(201,139,30,.16); color: #d9a441; }
.ttag {
  display: inline-block; margin-right: 4px; padding: 1px 6px; border-radius: 3px;
  font-size: 11px; border: 1px solid var(--line);
}
.ttag.ok { background: var(--accent-dim); color: var(--fg); }
.ttag.dim { background: var(--bg-3); color: var(--fg-faint); }
.ttag.none { background: rgba(201,139,30,.16); color: #d9a441; }
#poolTable tr.orphan td { background: rgba(201,139,30,.05); }

/* removed assets: a list, since there is usually no picture left to show */
.dgone { list-style: none; margin: 0 0 14px; padding: 0; }
.dgone li {
  display: flex; align-items: baseline; gap: 10px; padding: 4px 8px;
  border-bottom: 1px solid var(--line);
}
.dgone code {
  font-size: 11.5px; color: var(--fg-dim); overflow-wrap: anywhere; min-width: 0;
}
.dgone .gtype {
  margin-left: auto; flex: none; font-size: 11px; color: var(--fg-faint);
  padding: 1px 6px; border: 1px solid var(--line); border-radius: 3px;
}
.dgone .gver {
  flex: none; font-size: 11px; color: #d9a441; white-space: nowrap;
}
/* a map texture whose asset the game removed */
.mapcell.gone img { outline: 2px solid rgba(217,164,65,.55); outline-offset: -2px; }
.mapcell.gone figcaption { color: #d9a441; }
.mapcell.nofile img {
  background: rgba(217,164,65,.10);
  border-style: dashed;
}

/* ------------------------------------------------------------- diff view */
.diff-panel { max-width: 1100px; }
.diff-pick { display: flex; align-items: center; gap: 10px; margin: 4px 0 14px; }
.diff-pick select {
  background: var(--bg-3); color: var(--fg); border: 1px solid var(--line);
  border-radius: 7px; padding: 6px 10px; font: inherit;
}
.diff-pick .arrow { color: var(--fg-faint); }
.dtabs { display: flex; flex-wrap: wrap; gap: 6px; margin: 12px 0 14px; }
.dtab {
  background: var(--bg-3); border: 1px solid var(--line); color: var(--fg-dim);
  border-radius: 999px; padding: 5px 12px; font: inherit; font-size: 12.5px; cursor: pointer;
}
.dtab:hover { color: var(--fg); }
.dtab.active { background: var(--accent-dim); border-color: var(--accent); color: var(--fg); }
.dtab .n { font-variant-numeric: tabular-nums; opacity: .75; margin-left: 3px; }
.dgroup {
  margin: 18px 0 8px; font-size: 12.5px; color: var(--fg-dim);
  border-bottom: 1px solid var(--line); padding-bottom: 5px;
}
.dgroup span { color: var(--fg-faint); font-weight: 400; }
.dgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(88px, 1fr)); gap: 8px; }
.dgrid figure { margin: 0; text-align: center; }
.dgrid img { width: 100%; aspect-ratio: 1; object-fit: contain; background: var(--bg-3); border-radius: 7px; }
.dgrid figcaption {
  font-size: 11px; color: var(--fg-dim); margin-top: 3px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.dlist { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.dlist li {
  display: flex; gap: 10px; padding: 8px 10px;
  background: var(--bg-3); border: 1px solid var(--line); border-radius: 8px;
}
.dlist img, .dlist .ph { width: 44px; height: 44px; flex: none; border-radius: 6px; background: var(--bg-2); object-fit: contain; }
.dlist .meta { font-size: 11px; color: var(--fg-faint); margin-bottom: 4px; }
.dline { display: grid; grid-template-columns: 1fr auto 1fr; gap: 8px; align-items: start; font-size: 12px; margin-top: 3px; }
.dline .was { color: var(--fg-faint); text-decoration: line-through; }
.dline .now { color: var(--fg); }
.dline .arrow { color: var(--fg-faint); }
.dtable { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.dtable th, .dtable td { border-bottom: 1px solid var(--line); padding: 5px 8px; text-align: left; }
.dtable th { color: var(--fg-faint); font-weight: 400; }
.dtable .num { text-align: right; font-variant-numeric: tabular-nums; width: 84px; }
.dtable .add { color: var(--new); }
.dtable .chg { color: var(--accent); }
.dtable .del { color: #d8737a; }
.linky { background: none; border: 0; color: var(--fg); font: inherit; cursor: pointer; padding: 0; text-decoration: underline dotted; }
.linky:hover { color: var(--accent); }
.tagn { margin-left: 6px; padding: 0 5px; border-radius: 4px; background: var(--new); color: #06210a; font-size: 9.5px; font-weight: 700; }
.tagn.gone { background: #d8737a; color: #2a0b0d; }

.timeline { list-style: none; margin: 0; padding: 0; }
.timeline li { display: flex; gap: 14px; padding: 12px 0; border-bottom: 1px solid var(--line); }
.timeline .dot { width: 10px; height: 10px; border-radius: 50%; background: var(--accent); margin-top: 6px; flex: none; }
.timeline .meta { color: var(--fg-faint); font-size: 12px; }

@media (max-width: 1100px) {
  .layout, .layout:has(.detail:not([hidden])) { grid-template-columns: 1fr; }
  .sidebar { position: static; height: auto; border-right: 0; border-bottom: 1px solid var(--line); }
  .detail { position: fixed; inset: var(--header-h) 0 0 auto; width: min(360px, 92vw); z-index: 40; }
  /* an overlay cannot reserve anything, so an empty one just goes away */
  .detail.empty { display: none; }
  /* Eight tabs need ~530px. Squeezed into what is left of a one-line header they
     shrink until their labels break across two lines, which made the header
     146px tall at 820px wide. Giving the tab bar its own row and letting it
     scroll sideways keeps every label on one line at any width. */
  .topbar { height: auto; padding: 8px 16px; flex-wrap: wrap; row-gap: 8px; }
  .search-wrap { order: 2; flex: 1 1 260px; max-width: none; }
  .tabs {
    order: 3; flex: 1 1 100%; margin-left: 0;
    overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch;
  }
  .tabs::-webkit-scrollbar { display: none; }
  .tab { flex: none; white-space: nowrap; }
}

/* ------------------------------------------------------------- responsive */
/* The workhorse layouts here are two-pane: a list beside the thing it opens.
   Below ~880px that stops working -- the list keeps its 260px and the pane it
   feeds collapses (76px at 458px wide, 36px on the UI tab), which is unusable.
   So the panes stack instead: list on top with a capped height, content under
   it taking whatever is left. `dvh` keeps the mobile browser's shrinking
   toolbar from cutting the bottom off; `vh` stays as the fallback. */
@media (max-width: 880px) {
  .sheet-layout,
  .models-layout,
  .ui-layout {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto minmax(0, 1fr);
    height: calc(100vh - var(--header-h) - 24px);
    height: calc(100dvh - var(--header-h) - 24px);
  }
  #view-texts {
    height: calc(100vh - var(--header-h) - 24px);
    height: calc(100dvh - var(--header-h) - 24px);
  }
  .sheet-list, .model-list, .ui-list { max-height: 34vh; }
  /* the model viewer is the exception: when a model is open it wants the room,
     so the browse grid and the stage swap rather than share */
  .models-layout .model-stage { grid-row: 1 / -1; }
  .content { padding: 12px 12px 40px; }
  .grid { gap: 8px; }
  #modelGrid { --cell: 96px; }
  .map-grid { padding: 8px; gap: 8px; }
  .map-list { columns: 200px; }
  /* long control rows wrap instead of pushing the pane wide */
  .sheet-head, .browse-bar, .tween-bar, .text-modes {
    flex-wrap: wrap; row-gap: 8px;
  }
  .sheet-head input, .browse-bar input[type=search] { width: 100%; }
  .sheet-head .spacer, .browse-bar .spacer { display: none; }
}

/* Phones. The tab bar is 527px of buttons on its own, so it scrolls sideways
   rather than wrapping into three rows or squeezing the labels away. */
@media (max-width: 620px) {
  .topbar {
    height: auto; padding: 8px 12px; gap: 10px;
    flex-wrap: wrap; align-items: center;
  }
  .brand h1 { font-size: 13.5px; }
  .brand .sub { display: none; }
  .search-wrap { flex: 1 1 100%; }
  .search-wrap kbd { display: none; }
  .tab { padding: 6px 10px; font-size: 13px; }
  /* the header wraps to three rows here; its real height is measured at runtime
     into --header-h (see app.js), this is only the value before that runs */
  :root { --header-h: 146px; }
  .sidebar { padding: 12px 10px 20px; }
  .content { padding: 10px 10px 32px; }
  .grid { --cell: 84px !important; }
  #modelGrid { --cell: 84px; }
  .card .name { font-size: 10px; }
  .detail { width: 100vw; }
  .dgone li { flex-wrap: wrap; row-gap: 2px; }
  .dgone .gtype { margin-left: 0; }
  table.stat th, table.stat td { padding: 6px 6px; font-size: 12px; }
  .panel { padding: 14px 12px; }
}

/* Coarse pointers: the hit targets and the hover-only affordances */
@media (pointer: coarse) {
  .card:hover { transform: none; }
  .tab, .sbtn, .tmode, .model-cats button { min-height: 34px; }
  .sheet-list li button, #modelItems li button,
  #mapItems li button, #l10nGroups li button { min-height: 32px; }
}

/* the models bar carries two groupings; the inventory tabs are set apart */

/* item detail: disassemble materials and option lines */
.mat-list, .opt-list { list-style: none; margin: 6px 0 0; padding: 0; }
.mat-list li {
  display: flex; align-items: center; gap: 8px;
  padding: 5px 8px; border-radius: 6px; background: var(--bg-3);
  margin-bottom: 4px; font-size: 12.5px;
}
.mat-list .sub { margin-left: auto; color: var(--fg-faint); font-size: 11.5px; }
.opt-list .opt {
  padding: 7px 9px; margin-bottom: 4px; border-radius: 6px;
  background: var(--bg-3); border: 1px solid var(--line);
  font-size: 12.5px; line-height: 1.5; word-break: keep-all;
}

/* 판매 · 획득: one row per shop listing or lucky-box entry, with the window
   underneath and a chip saying what that window means right now */
.shop-list { list-style: none; margin: 6px 0 0; padding: 0; }
.shop-row {
  padding: 6px 9px; border-radius: 6px; background: var(--bg-3);
  border: 1px solid transparent; margin-bottom: 4px;
}
.shop-row.soon { border-color: var(--accent-dim); }
.shop-row.ended { opacity: .62; }
.shop-line {
  display: flex; align-items: baseline; gap: 8px; font-size: 12.5px;
  flex-wrap: wrap;
}
/* a box title is the whole point of the row, so it wraps rather than clipping */
.shop-line .ko { flex: 1 1 auto; min-width: 0; word-break: keep-all;
  overflow-wrap: anywhere; }
.shop-tag {
  flex: none; padding: 1px 5px; border-radius: 4px; font-size: 10.5px;
  background: var(--bg-2); border: 1px solid var(--line); color: var(--fg-faint);
}
.shop-price {
  margin-left: auto; flex: none; color: var(--fg);
  font-variant-numeric: tabular-nums;
}
.shop-when {
  /* .sub is nowrap by design; this line is long and has to wrap instead */
  margin-top: 3px; font-size: 11px; color: var(--fg-faint);
  white-space: normal; word-break: keep-all; overflow-wrap: anywhere;
  line-height: 1.5;
}
.shop-chip {
  margin-left: 6px; padding: 0 5px; border-radius: 4px; font-size: 10px;
  border: 1px solid var(--line);
}
.shop-chip.live { color: var(--new); border-color: var(--new); }
.shop-chip.soon { color: var(--fg); background: var(--accent-dim);
  border-color: transparent; }
.shop-chip.ended { color: var(--fg-faint); }
/* NPC 상점: shop list in the sidebar, its shelves in the pane */
.npc-list { list-style: none; margin: 6px 0 0; padding: 0; overflow-y: auto;
  flex: 1; min-height: 0; }
.npc-list li button {
  width: 100%; display: flex; align-items: baseline; gap: 8px;
  background: none; border: 0; color: var(--fg-dim); text-align: left;
  padding: 5px 8px; border-radius: 6px; font: inherit; cursor: pointer;
}
.npc-list li button:hover { background: var(--bg-3); color: var(--fg); }
.npc-list li button.active { background: var(--accent-dim); color: var(--fg); }
.npc-list .ko { min-width: 0; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; }
.npc-list .n { margin-left: auto; font-size: 11px; color: var(--fg-faint);
  font-variant-numeric: tabular-nums; }

/* these three fill the window: capping them at 720/1240 left most of an
   FHD screen empty and squeezed the item names into an ellipsis */
.npc-pane { padding: 4px 2px 24px; max-width: none; }
.npc-head { display: flex; align-items: baseline; gap: 10px; margin: 4px 0 14px; }
.npc-head h3 { margin: 0; font-size: 16px; }
.npc-shelf { margin-bottom: 18px; }
.npc-shelf h4 {
  display: flex; align-items: baseline; gap: 8px;
  margin: 0 0 6px; font-size: 12.5px; color: var(--fg-dim);
  border-bottom: 1px solid var(--line); padding-bottom: 5px;
}
.npc-shelf h4 .sub { margin-left: auto; }
.npc-table { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.npc-table td { padding: 4px 6px; border-bottom: 1px solid var(--line); }
.npc-table tr:last-child td { border-bottom: 0; }
.npc-table tr.hit { background: var(--accent-dim); }
.npc-table tr.off { opacity: .55; }
.npc-when {
  margin-top: 2px; font-size: 11px; color: var(--fg-faint);
  white-space: normal; word-break: keep-all; overflow-wrap: anywhere;
  line-height: 1.5;
}
.npc-shelf.off { opacity: .62; }
.npc-shelf-when {
  margin: 0 0 6px; font-size: 11px; color: var(--fg-faint);
  white-space: normal; word-break: keep-all; overflow-wrap: anywhere;
}
.npc-head .shop-chip { margin-left: 0; }
.npc-table .num { text-align: right; font-variant-numeric: tabular-nums;
  white-space: nowrap; width: 1%; }
.npc-table .cur { color: var(--fg-faint); white-space: nowrap; width: 1%; }
.linkish {
  background: none; border: 0; padding: 0; font: inherit; cursor: pointer;
  color: var(--fg); text-align: left;
}
.linkish:hover { color: var(--accent); text-decoration: underline; }

/* 거래소 tab -- wider than the NPC pane it borrows its shell from, because it
   runs a grid and a detail column side by side */
#marketPane, #cashPane, #npcPane { max-width: none; }
.mkt-tabs { display: flex; flex-wrap: wrap; gap: 4px; margin: 0 0 8px; }
.mkt-tab {
  padding: 6px 12px; border-radius: 8px; font: inherit; font-size: 13px;
  background: var(--bg-2); border: 1px solid var(--line); color: var(--fg-dim);
  cursor: pointer;
}
.mkt-tab:hover { color: var(--fg); border-color: var(--accent); }
.mkt-tab.active { background: var(--accent-dim); color: var(--fg);
  border-color: transparent; }
.mkt-chips { display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 6px; }
.mkt-chip {
  display: flex; align-items: baseline; gap: 5px;
  padding: 4px 9px; border-radius: 7px; font: inherit; font-size: 12px;
  background: none; border: 1px solid var(--line); color: var(--fg-dim);
  cursor: pointer;
}
.mkt-chip:hover { color: var(--fg); border-color: var(--accent); }
.mkt-chip.active { background: var(--bg-3); color: var(--fg);
  border-color: var(--accent); }
.mkt-chip .n { font-size: 10.5px; color: var(--fg-faint);
  font-variant-numeric: tabular-nums; }
.mkt-chips.kid .mkt-chip { font-size: 12.5px; }
.mkt-head { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
  margin: 14px 0 8px; }
.mkt-head h3 { margin: 0; font-size: 15px; }
.mkt-count { margin-left: auto; }

/* the list scrolls inside itself so the page does not grow to 2,000 rows.
   The detail column is always laid out, empty or not: making it appear on
   click would re-flow the grid under the reader's cursor. */
.mkt-body { display: grid;
  grid-template-columns: minmax(0, 1fr) clamp(330px, 22vw, 460px);
  gap: 14px; align-items: start; }
@media (max-width: 980px) {
  .mkt-body { grid-template-columns: minmax(0, 1fr); }
  .mkt-detail { position: static; }
}
.mkt-list { min-width: 0; padding-right: 4px; overflow-y: auto;
  /* clamped: on a short pane the bare calc goes negative and collapses the
     list to nothing */
  max-height: clamp(280px, calc(100vh - var(--header-h) - 200px), 1000px); }
.mkt-items {
  list-style: none; margin: 0; padding: 0; display: grid; gap: 4px;
  /* wide enough that a full item name fits rather than being clipped */
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
}
.mkt-item {
  width: 100%; display: flex; align-items: center; gap: 8px;
  padding: 5px 9px; border-radius: 7px; font: inherit; text-align: left;
  background: var(--bg-3); border: 1px solid transparent; color: var(--fg);
  cursor: pointer;
}
.mkt-item:hover { border-color: var(--accent); }
.mkt-item.active { border-color: var(--accent); background: var(--accent-dim); }

.mkt-detail {
  min-width: 0; position: sticky; top: 0; overflow-y: auto;
  max-height: clamp(280px, calc(100vh - var(--header-h) - 200px), 1000px);
  background: var(--bg-2); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 12px 14px;
}
.mkt-detail h3 { margin: 6px 0 2px; font-size: 15px; }
.mkt-empty { margin: 0; text-align: center; padding: 28px 0; }
.mkt-close { float: right; font-size: 11.5px; color: var(--fg-faint); }
.mkt-hero { width: 64px; height: 64px; object-fit: contain; border-radius: 8px;
  background: var(--bg-3); }
.mkt-desc { font-size: 12.5px; line-height: 1.6; color: var(--fg-dim);
  word-break: keep-all; margin: 8px 0 0; }
#mktSearch {
  padding: 5px 10px; min-width: 150px; font: inherit; font-size: 12.5px;
  background: var(--bg-3); color: var(--fg);
  border: 1px solid var(--line); border-radius: 7px; outline: none;
}
#mktSearch:focus { border-color: var(--accent); }
.mkt-ico {
  width: 30px; height: 30px; flex: none; object-fit: contain; border-radius: 5px;
  background: var(--bg-2);
}
.mkt-ico.blank {
  display: flex; align-items: center; justify-content: center;
  font-size: 12px; color: var(--fg-faint);
}
/* cash shop product names run long -- 217 of them were being clipped even at
   FHD -- so the name wraps instead of ending in an ellipsis. Grid rows size to
   their tallest tile, so a two-line name does not stagger the row. */
.mkt-item .ko { flex: 1 1 auto; min-width: 0; font-size: 12.5px;
  white-space: normal; word-break: keep-all; overflow-wrap: anywhere;
  line-height: 1.35; }
.mkt-item { min-height: 42px; }
.mkt-price { flex: none; font-size: 11.5px; font-variant-numeric: tabular-nums;
  color: var(--fg-dim); white-space: nowrap; }

.market-board { margin-bottom: 22px; }
.market-board h3 { margin: 0 0 8px; font-size: 15px; }
.market-rules { grid-template-columns: 168px 1fr; }
.npc-table th {
  text-align: left; font-weight: 400; font-size: 11px; color: var(--fg-faint);
  padding: 2px 6px 5px; border-bottom: 1px solid var(--line);
  white-space: nowrap;
}
/* the grade and bid tables are a handful of short columns; letting them fill
   720px pushes the numbers away from their labels */
#marketPane .npc-table { width: auto; min-width: 320px; max-width: 100%; }
#marketPane .npc-table td:not(.num):not(.cur) { padding-right: 22px; }
.market-rules { max-width: 480px; }
.swatch-list { list-style: none; margin: 6px 0 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: 6px 14px; }
.swatch-list li { display: flex; align-items: center; gap: 5px; font-size: 12.5px; }
.swatch { width: 13px; height: 13px; border-radius: 3px;
  border: 1px solid var(--line); flex: none; }

.shop-past { margin-top: 6px; }
.shop-past summary {
  cursor: pointer; padding: 5px 2px; font-size: 11.5px; color: var(--fg-faint);
}
.shop-past[open] summary { color: var(--fg-dim); }

/* box rewards: the badge marking a name inferred from the icon file */
.mat-list li .sub[title] {
  margin-left: 6px; padding: 1px 5px; border-radius: 4px;
  background: var(--bg-2); border: 1px solid var(--line); font-size: 10.5px;
}

/* 미출시 탭: long lists stay inside their own scroller */
.scroll-box { max-height: 420px; overflow-y: auto; }
#view-unreleased details { margin: 6px 0; }
#view-unreleased summary { cursor: pointer; padding: 6px 2px; color: var(--fg-dim); }
#view-unreleased details .mat-list { max-height: 340px; overflow-y: auto; }
#view-unreleased h3 { margin: 22px 0 4px; font-size: 14px; }

/* 미출시 탭: dev-marked rows shown as artwork, chips that navigate */
.dev-grid { --cell: 104px; margin-top: 8px; max-height: 560px; overflow-y: auto; }
.dev-grid .card { cursor: default; }
.dev-grid .card:hover { transform: none; border-color: var(--line); }
.chip.go { cursor: pointer; font: inherit; font-size: 12px; }
.chip.go:hover { border-color: var(--accent); color: var(--fg); }

/* monster drop lists: one pool per line, reward names inline */
.drops { list-style: none; margin: .4rem 0 .8rem; padding: 0; }
.drops li { padding: .25rem 0; border-bottom: 1px solid var(--line, #2a2a2a); }
.drops li:last-child { border-bottom: 0; }
.drops .sub { opacity: .65; font-size: .85em; }


/* monster tab: filter bar and card meta line */
.mon-bar { display: flex; flex-wrap: wrap; gap: .6rem; align-items: center;
  padding: .6rem 0; }
.mon-bar input[type=search] { flex: 1 1 14rem; min-width: 12rem; }
.mon-bar .sub { margin-left: auto; opacity: .7; }
#monGrid .card .sub { display: block; font-size: .78em; opacity: .6; }
/* a render stands in for a missing icon; keep it from filling the whole tile */
.card img.from3d { object-fit: contain; }

/* the render standing in for a missing icon keeps its aspect in the hero slot */
.hero.from3d { object-fit: contain; }

/* which dropped item matched the monster search */
#monGrid .card .sub.loot { color: var(--accent, #6ba7ff); opacity: .85; }


/* ------------------------------------------------- monster / skill tabs */
.side-block input[type=search] { width: 100%; margin-bottom: 8px; }
.side-block .ctl { display: flex; align-items: center; gap: 6px; margin: 6px 0; }
.side-block .ctl select { flex: 1; min-width: 0; }
.side-block .ctl input[type=range] { flex: 1; min-width: 0; }
.side-count { margin: 8px 0 0; font-size: 12px; color: var(--fg-dim); }

/* card labels stay inside the card: the monster and skill grids hang a second
   line under the name, and without a clamp a long class name ran off the tile */
.card > .sub {
  font-size: 9.5px; line-height: 1.25; color: var(--fg-faint);
  text-align: center; max-width: 100%; word-break: keep-all;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}
.card > .sub.loot { color: var(--accent); opacity: .85; -webkit-line-clamp: 1; }
.card .name { max-width: 100%; }

.graded { color: var(--accent); font-weight: 600; }

/* ----------------------------------------------------------- customize */
/* The dressing room is meant to sit still: the stage, the rail and the panel
   all fit the window and scroll inside themselves. The page was scrolling by
   36px because the layout asked for `100vh - header - 40` while .content adds
   16 above and 60 below -- so the window moved whenever the wheel was over
   anything but the canvas. The two numbers are matched here instead. */
.content:has(> #view-customize:not([hidden])) { padding-bottom: 16px; }
.content:has(> #view-customize:not([hidden])) .result-bar { display: none; }
.cz-layout {
  display: grid; grid-template-columns: 300px minmax(0, 1fr) 300px;
  gap: 14px; height: calc(100vh - var(--header-h) - 32px);
}
/* A warm, near-white stage rather than a dark one. These characters are drawn
   with pale skin and unlit pastel clothing, and against a dark ground every
   light garment read as the brightest thing on screen; against paper they read
   as they do in the game. The vignette is the floor, not a spotlight. */
/* The cream stage and the paper panels came from copying another dressing-room
   site. They made this one tab look like a different program, so the room is
   the browser's own again -- the rest of the palette below just inherits. */
.cz-stage {
  position: relative; min-height: 0; background: var(--bg-2);
  border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden;
}
#czCanvas { display: block; width: 100%; height: 100%; touch-action: none; cursor: grab; }
#czCanvas:active { cursor: grabbing; }
.cz-stage .stage-toolbar .sub { font-size: 11.5px; color: var(--fg-dim); }
/* The panel tokens now just alias the browser's own, so the dressing room is
   the same room as every other tab. */
.cz-layout {
  --paper: var(--bg-2); --paper-2: var(--bg-3); --ink: var(--fg);
  --ink-dim: var(--fg-dim); --ink-faint: var(--fg-faint); --rule: var(--line);
}
.cz-panel {
  display: flex; flex-direction: column; min-height: 0; overflow: hidden; gap: 10px;
  background: var(--paper); border: 1px solid var(--rule);
  border-radius: var(--radius); padding: 12px; color: var(--ink);
}
.cz-panel .sbtn {
  background: var(--paper-2); color: var(--ink-dim);
  border-color: var(--rule); backdrop-filter: none;
}
.cz-panel .sbtn:hover { background: #fff; color: var(--ink); }
.cz-panel .sbtn.on {
  background: var(--accent-dim); color: var(--fg); border-color: var(--accent);
}
.cz-panel #czSearch,
.cz-panel .cz-row select {
  background: var(--paper-2); color: var(--ink); border-color: var(--rule);
}
.cz-panel #czSearch:focus,
.cz-panel .cz-row select:focus { border-color: var(--ink-dim); }
.cz-panel .cz-row > h3,
.cz-panel .sw-head > span,
.cz-panel .cz-slider > em { color: var(--ink-dim); }
.cz-panel .sw-head > em { color: var(--ink-dim); }
.cz-panel .empty-inline { color: var(--ink-faint); }
.cz-panel .sw.on { box-shadow: 0 0 0 2px var(--bg-2), 0 0 0 3.5px var(--accent); }
.cz-panel .sw:focus-visible {
  box-shadow: 0 0 0 2px var(--bg-2), 0 0 0 3.5px var(--fg-dim);
}
.cz-panel input[type="range"] { accent-color: var(--ink); }
/* Two columns of controls around the stage: the character on the left, the
   wardrobe on the right. The game splits its customiser the same way, so a
   change of hair and a change of hat are never the same kind of act. */
.cz-panel {
  display: flex; flex-direction: column; min-height: 0; overflow: hidden;
  gap: 8px; background: var(--paper); border: 1px solid var(--rule);
  border-radius: var(--radius); padding: 12px; color: var(--ink);
}
.cz-panel-title {
  margin: 0; font-size: 12px; font-weight: 700; letter-spacing: .04em;
  color: var(--ink-dim); text-transform: none;
}
.cz-panel-body {
  overflow-y: auto; flex: 1; display: flex; flex-direction: column; gap: 11px;
  padding-right: 2px;
}
.cz-row > h3 {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 8px; margin: 0 0 4px; font-size: 11.5px; font-weight: 600;
  color: var(--ink-faint);
}
/* A row with something on reads as chosen at a glance, so the left panel can
   be skimmed for what is set rather than read line by line. */
.cz-row.on > h3 { color: var(--ink); }
.cz-row > h3 > em {
  font-style: normal; font-size: 11px; color: var(--ink-dim);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cz-btns { display: flex; gap: 6px; flex-wrap: wrap; }
.cz-btns .sbtn { flex: 1 1 auto; text-align: center; backdrop-filter: none; }
.cz-slider { display: flex; align-items: center; gap: 8px; }
.cz-slider input[type="range"] { flex: 1; min-width: 0; }
.cz-slider > em {
  font-style: normal; font-size: 11px; min-width: 48px; text-align: right;
}
.cz-panel #czSearch {
  width: 100%; padding: 7px 10px; background: var(--paper-2); color: var(--ink);
  border: 1px solid var(--rule); border-radius: 7px; font: inherit; outline: none;
}
.cz-panel #czSearch:focus { border-color: var(--ink-dim); }
/* The pieces themselves rather than their names. The grid is capped and
   scrolls: a slot can hold 300 pieces and the panel holds fifteen slots, so
   letting every one run full height would make the column unusable. */
.cz-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(44px, 1fr));
  gap: 4px; max-height: 170px; overflow-y: auto; padding: 2px;
}
.cz-thumb {
  aspect-ratio: 1; display: grid; place-items: center; padding: 2px;
  background: var(--bg-3); border: 1px solid var(--line); border-radius: 7px;
  cursor: pointer; font: inherit; font-size: 9px; line-height: 1.15;
  color: var(--fg-faint); overflow: hidden; outline: none;
}
.cz-thumb img { width: 100%; height: 100%; object-fit: contain; }
.cz-thumb:hover { border-color: var(--fg-dim); }
.cz-thumb.text { padding: 3px; word-break: break-all; }
.cz-thumb.none { font-size: 10px; color: var(--fg-dim); }
.cz-thumb.on {
  border-color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent);
}
.cz-thumb:focus-visible { border-color: var(--fg-dim); }
.empty-inline { color: var(--fg-faint); font-size: 12px; padding: 8px 2px; }

@media (max-width: 1100px) {
  .cz-layout {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: 55vh auto auto; height: auto;
  }
  .cz-panel { max-height: 60vh; }
}


/* A palette is a grid of the colours themselves. The name of the one in hand
   sits in the heading, so a hover is not the only way to read it. */
.sw-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 8px; margin-bottom: 5px; font-size: 11.5px;
}
.sw-head > span { color: var(--fg-faint); }
.sw-head > em { font-style: normal; color: var(--fg-dim); font-size: 11px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* The padding is load-bearing.

   A swatch grows on hover, and `transform` takes no part in layout -- but it
   does take part in *overflow*. At `padding: 1px` the grown circle stuck out of
   a box that scrolls, so a scrollbar appeared, which narrowed the box, which
   made `auto-fill` re-lay every circle smaller: the whole row twitched under
   the pointer. Four pixels is more than the 1.6 a scaled 18px circle needs on
   each side, so the growth stays inside and nothing moves. */
.sw-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(18px, 1fr));
  gap: 4px; max-height: 104px; overflow-y: auto; padding: 4px;
}
.sw {
  aspect-ratio: 1; border-radius: 50%; border: 1px solid rgba(0, 0, 0, .28);
  padding: 0; cursor: pointer; outline: none;
}
.sw:hover { transform: scale(1.18); }
/* A ring outside the swatch, so the colour itself is never covered up. */
.sw.on { box-shadow: 0 0 0 2px var(--bg-2), 0 0 0 3.5px var(--accent); }
.sw:focus-visible { box-shadow: 0 0 0 2px var(--bg-2), 0 0 0 3.5px var(--fg-dim); }

/* Before/after for an icon a patch redrew. The two images sit against a
   chequer so a change in transparency reads as clearly as a change in colour. */
.dgrid.art figure.pair > div {
  display: flex; gap: 6px; align-items: center; justify-content: center;
}
.dgrid.art figure.pair img {
  width: 64px; height: 64px; object-fit: contain; border-radius: 6px;
  background: repeating-conic-gradient(var(--bg-3) 0 25%, transparent 0 50%) 0 0 / 12px 12px;
}
.dgrid.art figure.pair img:first-child { opacity: .75; }
.dgrid.art figcaption .meta {
  display: block; font-size: 10px; color: var(--fg-faint); font-family: ui-monospace, monospace;
}

/* ------------------------------------------------------------------ 펫 */
/* The pets tab reuses the skills tab's card grid and detail panel; what it adds
   is the mode switch at the top and the per-skill block in the panel, where a
   pet's two or three unique skills each need their own chips and tooltip. */
#view-pets .text-modes { margin-bottom: 12px; }
.pmode {
  padding: 5px 14px; border-radius: var(--radius); cursor: pointer;
  border: 1px solid var(--line); background: var(--bg-2); color: var(--fg-dim);
}
.pmode:hover { color: var(--fg); }
.pmode.active { background: var(--accent-dim); color: var(--fg); border-color: var(--accent); }
.pet-skill {
  border-left: 2px solid var(--line); padding-left: 10px; margin: 10px 0;
}
.pet-skill .ko { margin: 0 0 3px; font-size: 13px; }
.pet-skill .ko-desc { margin: 0; }
/* Dye colours are read-only here -- they say what the game tints this pet, and
   there is nothing to pick -- so they get the swatch look without the button. */
.pet-dye { display: flex; gap: 6px; flex-wrap: wrap; margin: 4px 0 0; }
.pet-dye .sw { cursor: help; }
.kv .hint { color: var(--fg-faint); font-size: 11px; }

/* ------------------------------------------------- the map tab's 3D links */
/* One per playable space a place is cut into: a town is one, Alby is nine. */
.map-explore { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
.map-explore a {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 10px; border: 1px solid var(--accent-dim); border-radius: 999px;
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  color: var(--accent); font-size: 12px; text-decoration: none;
  white-space: nowrap;
}
.map-explore a:hover { background: var(--accent); color: #fff;
                       border-color: var(--accent); }
.map-explore a .n { opacity: .7; font-variant-numeric: tabular-nums; }
.map-explore-more { color: var(--fg-faint); font-size: 11px; }
