/* AshenRO wiki — components for the search home, the database tables and the
   guide pages. Layers on top of assets/site.css + assets/refresh.css; the
   palette, fonts and card styling are inherited, never redefined here. */


/* =========================================================
   1. SEARCH HOME
   ========================================================= */
.search-home{max-width:760px;margin:0 auto;padding:72px 0 40px;text-align:center}
.search-home h1{font:800 35px/1.2 Manrope,sans-serif;letter-spacing:-.03em;margin:0 0 10px}
.search-home > p{font-size:17px;color:var(--muted);margin:0 auto 30px;max-width:520px}

.bigsearch{position:relative;max-width:620px;margin:0 auto;text-align:left}
.bigsearch input{width:100%;height:62px;padding:0 112px 0 54px;font:500 18px/1 "Source Sans 3",sans-serif;
  color:var(--text);background:var(--surface);border:1.5px solid var(--border);border-radius:14px;outline:0;
  box-shadow:var(--shadow)}
.bigsearch input:focus{border-color:var(--accent);box-shadow:0 0 0 4px var(--accent2)}
.bigsearch .ui-icon{position:absolute;left:19px;top:19px;width:24px;height:24px;color:var(--muted)}
.bigsearch kbd{position:absolute;right:18px;top:20px;font:700 12px/1 "Source Sans 3",sans-serif;
  color:var(--muted);background:var(--surface2);border:1px solid var(--border);border-radius:6px;padding:6px 8px}

/* live results panel */
.results{max-width:620px;margin:10px auto 0;text-align:left;background:var(--surface);
  border:1px solid var(--border);border-radius:14px;box-shadow:var(--shadow);overflow:hidden}
.res-group{border-bottom:1px solid var(--border)}
.res-group:last-child{border-bottom:0}
.res-head{display:flex;align-items:center;justify-content:space-between;padding:9px 16px;
  background:var(--surface2);font:800 11px/1 Manrope,sans-serif;letter-spacing:.14em;color:var(--muted)}
.res-head a{font:700 12px/1 "Source Sans 3",sans-serif;letter-spacing:0;color:var(--accent)}
.res{display:grid;grid-template-columns:34px minmax(0,1fr) auto;align-items:center;gap:12px;
  padding:10px 16px;border-top:1px solid var(--border)}
.res:first-of-type{border-top:0}
.res:hover,.res.on{background:var(--accent2)}
.res-ico{width:34px;height:34px;display:grid;place-items:center;border-radius:8px;
  background:var(--surface2);font-size:18px}
.res b{display:block;font:700 15px/1.3 Manrope,sans-serif}
.res small{display:block;font-size:13.5px;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.res em{font-style:normal;background:rgba(116,69,207,.14);color:var(--accent);border-radius:3px;padding:0 2px}
.res-tag{font:700 11px/1 "Source Sans 3",sans-serif;letter-spacing:.06em;text-transform:uppercase;
  color:var(--muted);border:1px solid var(--border);border-radius:5px;padding:4px 6px}

/* destination tiles */
.tiles-intro{margin:52px 0 14px;font:800 11px/1 Manrope,sans-serif;letter-spacing:.16em;color:var(--muted);text-align:center}
.tiles{display:grid;grid-template-columns:repeat(4,1fr);gap:13px;max-width:900px;margin:0 auto;text-align:left}
.tile{display:grid;gap:5px;padding:18px;background:var(--surface);border:1px solid var(--border);
  border-radius:12px;box-shadow:var(--shadow);transition:.18s;align-content:start}
.tile:hover{transform:translateY(-2px);border-color:var(--accent)}
.tile .ui-icon{width:26px;height:26px;margin-bottom:6px}
.tile b{font:700 15px/1.3 Manrope,sans-serif}
.tile small{font-size:13px;line-height:1.5;color:var(--muted)}

/* =========================================================
   2. DATABASE PAGE
   ========================================================= */
.main.wide{max-width:none;padding:34px 40px 70px}
.db-head{display:flex;align-items:flex-end;justify-content:space-between;gap:24px;
  padding-bottom:18px;margin-bottom:18px;border-bottom:1px solid var(--border)}
.db-head h1{font:800 33px/1.15 Manrope,sans-serif;letter-spacing:-.03em;margin:0 0 6px}
.db-head p{margin:0;font-size:15px;color:var(--muted);max-width:640px}
.db-gen{font-size:13px;color:var(--muted);text-align:right;white-space:nowrap}
.db-gen b{display:block;font:700 14px Manrope,sans-serif;color:var(--text)}

.filters{display:flex;flex-wrap:wrap;gap:9px;align-items:center;margin-bottom:12px}
.filters input[type=search]{flex:1 1 260px;min-width:220px;height:42px;padding:0 14px;font:inherit;font-size:15px;
  background:var(--surface);border:1px solid var(--border);border-radius:9px;outline:0;color:var(--text)}
.filters select{height:42px;padding:0 30px 0 12px;font:inherit;font-size:14px;color:var(--text);
  background:var(--surface);border:1px solid var(--border);border-radius:9px;outline:0;appearance:none;
  background-image:linear-gradient(45deg,transparent 50%,var(--muted) 50%),linear-gradient(135deg,var(--muted) 50%,transparent 50%);
  background-position:calc(100% - 15px) 19px,calc(100% - 10px) 19px;background-size:5px 5px;background-repeat:no-repeat}
.filters select:focus,.filters input:focus{border-color:var(--accent)}
.filters .reset{height:42px;padding:0 14px;font:700 14px "Source Sans 3",sans-serif;color:var(--muted);
  background:none;border:1px solid var(--border);border-radius:9px;cursor:pointer}
.chipbar{display:flex;flex-wrap:wrap;gap:7px;align-items:center;margin-bottom:14px;font-size:14px;color:var(--muted)}
.chipbar .count{font-weight:700;color:var(--text)}
.fchip{display:inline-flex;align-items:center;gap:6px;padding:4px 8px;font-size:13px;font-weight:600;
  color:var(--accent);background:var(--accent2);border:1px solid var(--border);border-radius:6px}
.fchip b{font-size:14px;line-height:1;opacity:.6}

/* the table */
/* No overflow:hidden here — it breaks position:sticky on the table head. */
.dbwrap{border:1px solid var(--border);border-radius:12px;background:var(--surface)}
table.db thead th:first-child{border-top-left-radius:11px}
table.db thead th:last-child{border-top-right-radius:11px}
table.db tbody tr:last-child td:first-child{border-bottom-left-radius:11px}
table.db tbody tr:last-child td:last-child{border-bottom-right-radius:11px}
table.db{width:100%;border-collapse:collapse;font-size:14.5px}
table.db thead th{position:sticky;top:66px;z-index:5;background:var(--surface2);
  font:700 12px/1 Manrope,sans-serif;letter-spacing:.07em;text-transform:uppercase;color:var(--muted);
  text-align:left;padding:11px 12px;border-bottom:1px solid var(--border);white-space:nowrap;cursor:pointer;user-select:none}
table.db thead th:hover{color:var(--text)}
table.db thead th.sorted{color:var(--accent)}
table.db thead th.sorted::after{content:" ▾";font-size:11px}
table.db thead th.num,table.db td.num{text-align:right;font-variant-numeric:tabular-nums}
table.db tbody tr{border-bottom:1px solid var(--border)}
table.db tbody tr:last-child{border-bottom:0}
table.db tbody tr:nth-child(even){background:color-mix(in srgb,var(--surface2) 55%,transparent)}
table.db tbody tr:hover{background:var(--accent2)}
table.db td{padding:9px 12px;vertical-align:middle}
.m-name{display:flex;align-items:center;gap:10px;min-width:180px}
.m-sprite{width:32px;height:32px;flex:0 0 32px;display:grid;place-items:center;border-radius:7px;
  background:var(--surface2);font-size:18px}
.m-name b{font:700 15px/1.25 Manrope,sans-serif;display:block}
.m-name small{display:block;font-size:12.5px;color:var(--muted)}
.mono{font-variant-numeric:tabular-nums;font-size:14px;color:var(--muted)}
.el{display:inline-block;padding:3px 7px;border-radius:5px;font:700 12px/1.3 "Source Sans 3",sans-serif;white-space:nowrap}
.el-water{background:#dbeafe;color:#1e4b8f}.el-earth{background:#e8e2d3;color:#6b5a2e}
.el-fire{background:#fde3d8;color:#9a3a18}.el-wind{background:#dcf5ee;color:#156b56}
.el-poison{background:#ecdcf7;color:#6a2e93}.el-neutral{background:var(--surface2);color:var(--muted)}
.el-shadow{background:#ded9e4;color:#3d3348}.el-undead{background:#e0e4d8;color:#4a5c34}
.dark .el-water{background:#1c3355;color:#a9cdf8}.dark .el-earth{background:#3a3323;color:#ddcda0}
.dark .el-fire{background:#4a2417;color:#f6b79b}.dark .el-wind{background:#14382e;color:#8fe4cb}
.dark .el-poison{background:#3a2150;color:#d4b1f3}.dark .el-shadow{background:#2e2839;color:#c3b7d3}
.dark .el-undead{background:#2c331f;color:#bcc9a4}
.drops{display:flex;flex-wrap:wrap;gap:5px;min-width:230px}
.drop{display:inline-flex;align-items:baseline;gap:5px;padding:3px 7px;font-size:13px;
  background:var(--surface2);border-radius:6px;white-space:nowrap}
.drop i{font-style:normal;font-variant-numeric:tabular-nums;font-weight:700;color:var(--green)}
.drop.rare i{color:var(--accent)}
.dbfoot{display:flex;align-items:center;justify-content:space-between;gap:16px;
  padding:14px 4px 0;font-size:14px;color:var(--muted)}
.dbfoot .pager{display:flex;gap:6px}
.dbfoot .pager a{padding:6px 11px;border:1px solid var(--border);border-radius:7px;font-weight:700;font-size:13.5px}
.dbfoot .pager a.on{background:var(--accent);border-color:var(--accent);color:#fff}
.ratenote{margin-top:16px;padding:13px 16px;border-left:3px solid var(--green);background:var(--green2);
  border-radius:0 10px 10px 0;font-size:14px;line-height:1.6;color:var(--text)}
.ratenote b{color:var(--green)}

/* =========================================================
   3. GUIDE PAGE
   ========================================================= */
.guide-layout{display:grid;grid-template-columns:minmax(0,760px) 212px;gap:52px;align-items:start}
.guide-col{min-width:0;max-width:760px}
.guide-col h1{font:800 43px/1.12 Manrope,sans-serif;letter-spacing:-.04em;margin:0 0 12px}
.guide-col > .lede{font-size:18px;line-height:1.65;color:var(--muted);margin:0 0 4px}
.guide-meta{display:flex;gap:16px;align-items:center;margin:16px 0 28px;font-size:13.5px;color:var(--muted)}
.guide-meta span{display:inline-flex;align-items:center;gap:6px}

.shortver{margin:0 0 40px;padding:20px 24px;background:var(--green2);border:1px solid var(--border);
  border-left:3px solid var(--green);border-radius:0 12px 12px 0}
.shortver b{display:block;font:800 12px/1 Manrope,sans-serif;letter-spacing:.14em;color:var(--green);margin-bottom:11px}
.shortver ul{margin:0;padding-left:19px}
.shortver li{font-size:16px;line-height:1.65;color:var(--text);margin-bottom:7px}
.shortver li:last-child{margin-bottom:0}

.gstep{padding:0 0 34px;margin-bottom:30px;border-bottom:1px solid var(--border);scroll-margin-top:92px}
.gstep:last-child{border-bottom:0}
.gstep > h2{display:flex;align-items:baseline;gap:14px;font:800 26px/1.25 Manrope,sans-serif;
  letter-spacing:-.02em;margin:0 0 12px}
.gnum{flex:0 0 auto;display:grid;place-items:center;width:34px;height:34px;border-radius:50%;
  background:var(--accent);color:#fff;font:800 16px/1 Manrope,sans-serif;align-self:center}
.gstep p,.gstep li{font-size:17px;line-height:1.75;color:var(--text)}
.gstep p{margin:0 0 14px}
.gstep ul{padding-left:20px;margin:0 0 14px}
.gstep li{margin-bottom:8px}
.gstep h3{font:700 19px/1.4 Manrope,sans-serif;margin:26px 0 10px}
.shot{margin:20px 0 6px;border:1px solid var(--border);border-radius:12px;overflow:hidden;background:var(--surface2)}
.shot .ph{height:210px;display:grid;place-items:center;color:var(--muted);font-size:14px;
  background:repeating-linear-gradient(45deg,transparent,transparent 9px,rgba(128,120,140,.07) 9px,rgba(128,120,140,.07) 18px)}
.shot figcaption{padding:9px 14px;font-size:13.5px;color:var(--muted);border-top:1px solid var(--border);background:var(--surface)}
.tipbox{margin:18px 0;padding:14px 17px;background:var(--accent2);border-radius:10px;font-size:15px;line-height:1.65}
.tipbox b{color:var(--accent)}
.nextup{display:flex;gap:13px;margin-top:8px}
.nextup a{flex:1;padding:16px 18px;background:var(--surface);border:1px solid var(--border);border-radius:12px}
.nextup b{display:block;font:700 15px/1.3 Manrope,sans-serif;margin-bottom:3px}
.nextup small{font-size:13.5px;color:var(--muted)}

/* on this page rail */
.otp{position:sticky;top:92px}
.otp b{display:block;font:800 11px/1 Manrope,sans-serif;letter-spacing:.15em;color:var(--muted);
  padding-bottom:11px;margin-bottom:5px;border-bottom:1px solid var(--border)}
.otp a{display:block;padding:7px 0 7px 13px;margin-left:-1px;border-left:2px solid transparent;
  font-size:14px;line-height:1.45;color:var(--muted)}
.otp a:hover{color:var(--text)}
.otp a.on{border-left-color:var(--accent);color:var(--accent);font-weight:700}
.otp .back{margin-top:16px;padding:0;border-left:0;font-weight:700;color:var(--accent)}

@media(max-width:1180px){.guide-layout{grid-template-columns:minmax(0,1fr)}.otp{display:none}}
@media(max-width:900px){.tiles{grid-template-columns:repeat(2,1fr)}}

/* --- additions for the live pages ------------------------------------- */
.res-empty{padding:22px 18px;font-size:15px;color:var(--muted)}
.bigsearch input:disabled{opacity:.6}
.tag-mvp,.tag-boss{display:inline-block;margin-left:6px;padding:2px 6px;border-radius:5px;
  font:700 11px/1.4 "Source Sans 3",sans-serif;letter-spacing:.04em;vertical-align:1px}
.tag-mvp{background:var(--accent2);color:var(--accent)}
.tag-boss{background:var(--green2);color:var(--green)}
.muted{color:var(--muted)}
td.maps{font-size:13.5px}
.drop.more{border:1px dashed var(--border);background:none;color:var(--accent);cursor:pointer;
  font:600 13px "Source Sans 3",sans-serif;padding:3px 7px;border-radius:6px}
.drop.more:hover{border-style:solid}
.drop.mvp i{color:var(--accent)}
.drop.coin i{color:#b8860b}
.dark .drop.coin i{color:#e8c76a}
.drop-sep{width:100%;margin:4px 0 1px;font:700 11px/1 Manrope,sans-serif;letter-spacing:.12em;color:var(--muted)}
.fchip{cursor:pointer;font-family:inherit}
table.db thead th.sorted.asc::after{content:" ▴"}
.chipbar .count{margin-right:2px}

.drops[hidden]{display:none}
.el-dark{background:#ded9e4;color:#3d3348}
.el-holy{background:#fdf3d6;color:#8a6a12}
.el-ghost{background:#e6e0f2;color:#5a4a8a}
.dark .el-dark{background:#2e2839;color:#c3b7d3}
.dark .el-holy{background:#3d3316;color:#f0d98a}
.dark .el-ghost{background:#2f2745;color:#c9b8ef}

/* --- artwork -------------------------------------------------------- */
/* Sprites and minimaps are extracted from the client; every <img> removes
   itself when the file is absent, so these rules only ever apply to art that
   actually loaded. */
.m-sprite{position:relative;overflow:hidden}
.m-sprite .sprite{position:absolute;inset:0;margin:auto;max-width:100%;max-height:100%;
  object-fit:contain;image-rendering:pixelated;background:transparent}
.m-sprite.map{width:72px;height:72px;flex:0 0 72px}
/* contain, not cover: minimaps have large pale margins, so a centre crop can
   land on empty space and look like a missing image. */
.m-sprite .minimap{position:absolute;inset:0;width:100%;height:100%;object-fit:contain;border-radius:5px;background:var(--surface2)}
.res-ico .sprite{max-width:100%;max-height:100%}
/* The "no preview" tile, for the five maps the client has no minimap for.
   A dashed edge so it does not read as a frame waiting for a picture, and two
   short words on their own lines so the label stays legible at the 72px the
   table uses on a desktop and the 52px it drops to on a phone — one line of
   "No preview" would have to shrink below where it can be read. */
.m-sprite.map .noart{position:absolute;inset:0;display:grid;align-content:center;
  gap:1px;padding:3px;border:1px dashed var(--border);border-radius:5px;
  background:var(--surface2);color:var(--muted);text-align:center}
/* The size is set on the words themselves, not inherited from the tile:
   `.m-name b` sets 17px for the map name in the same cell, and inheritance
   loses to it. Measured against the 52px tile the table actually uses — the
   widest word, PREVIEW, comes to 38px, so it fits without letter-spacing. */
.m-sprite.map .noart b{display:block;
  font:800 8.5px/1.2 Manrope,sans-serif;text-transform:uppercase;letter-spacing:.02em}

figure.art{margin:22px 0;padding:0;border:1px solid var(--border);border-radius:12px;
  background:var(--surface2);overflow:hidden}
figure.art img{display:block;margin:0 auto;max-width:100%;image-rendering:pixelated}
figure.art.photo img{image-rendering:auto;width:100%}
figure.art figcaption{padding:9px 14px;font-size:13.5px;color:var(--muted);
  border-top:1px solid var(--border);background:var(--surface)}

.npc-line{display:flex;align-items:center;gap:16px;margin:18px 0;padding:14px 16px;
  background:var(--surface);border:1px solid var(--border);border-radius:12px}

.npc-line b{display:block;font:700 16px/1.35 Manrope,sans-serif;margin-bottom:3px}
.npc-line p{margin:0;font-size:15px;line-height:1.6;color:var(--muted)}
.npc-line .where{font-variant-numeric:tabular-nums;color:var(--accent);font-weight:700}

/* The strip was 132px wide with a 104px-tall image cropped to fill it. Two
   things were wrong with that. It was too small to read terrain off, which
   is the only reason to show a map at all; and `cover` crops whatever does
   not fit the frame, which on a minimap eats the coastline and the edges of
   the very thing the reader is looking at. pay_fild02 is 193x260 — tall and
   narrow — so a 132x104 centre crop threw away most of it.

   `contain` instead, in a square frame. The maps run from 0.67 to 1.40 in
   aspect ratio with a median of exactly 1.00, so a square is the frame that
   letterboxes least across the set, and a fixed ratio keeps the captions on
   a line with each other when two cards sit side by side. Letterboxing on
   the tall and wide outliers is the right trade: a band of background costs
   nothing, a cropped map costs the information.

   Same reasoning the monster database already uses for .minimap at the top
   of this file. Worth being clear that these were never two stylesheets
   disagreeing — one rule, applied to two different components, and only
   this one was wrong. */
.map-strip{display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:12px;margin:20px 0}
.map-card{border:1px solid var(--border);border-radius:10px;overflow:hidden;background:var(--surface)}
/* `image-rendering` is auto here and pixelated everywhere else, which is
   not an inconsistency. Pixelated exists to keep art crisp when it is
   drawn LARGER than its source. These minimaps are extracted with a 260px
   cap and the frame lands at about 177px, so they are drawn well under
   native — and nearest-neighbour downscaling does not sharpen, it drops
   every nth row of pixels and puts a stipple through the terrain. */
.map-card img{display:block;width:100%;height:auto;aspect-ratio:1/1;object-fit:contain;
  background:var(--surface2);image-rendering:auto}
.map-card span{display:block;padding:7px 10px;font:700 13.5px Manrope,sans-serif;
  border-top:1px solid var(--border)}
.map-card small{display:block;padding:0 10px 8px;font-size:12.5px;color:var(--muted)}

/* A map card whose art has not been extracted yet degrades to a text chip
   rather than showing a broken-image box. */
.map-card{display:block;padding:0}
.map-card:not(:has(img)){padding:12px 12px 10px}
.map-card:not(:has(img)) span{border-top:0;padding:0 0 3px}
.map-card:not(:has(img)) small{padding:0}
.map-card:hover{border-color:var(--accent)}

/* --- footer with the Gravity attribution ---------------------------- */
.wiki-foot{margin-top:56px;padding-top:24px;border-top:1px solid var(--border);
  display:grid;gap:12px;font-size:13px;color:var(--muted)}
.wiki-foot b{display:block;color:var(--text);font:800 15px Manrope,sans-serif}
.wiki-foot .legal{max-width:760px;line-height:1.65}
.wiki-foot a{margin-right:16px;font-weight:700;color:var(--accent)}

/* --- table type size --------------------------------------------------
   Jasper: table text was noticeably smaller than the body copy. These are the
   pages people read longest, so the tables now use the same 17px/1.65 as the
   surrounding text rather than a shrunken variant, with padding raised to keep
   the rows from feeling cramped at the larger size. If a column no longer fits,
   the fix is fewer or narrower columns, not smaller type. */
.table-scroll table{font-size:17px;line-height:1.65}
.table-scroll td,.table-scroll th{padding:15px 18px}
.table-scroll th{font-size:16px}

table.db{font-size:17px;line-height:1.5}
table.db td{padding:11px 13px}
table.db thead th{font-size:14px;padding:13px 14px}
.m-name b{font-size:17px}
.m-name small{font-size:14.5px}
td.maps{font-size:16px}

/* Drop and level chips sit inside the cells, so they move up with them. */
.drop{font-size:15px;padding:4px 8px}
.drops{gap:6px}
.drop.more{font-size:15px;padding:5px 9px}
.chips span{font-size:14px}
.chipbar{font-size:16px}
.fchip{font-size:15px}
.dbfoot{font-size:16px}
.dbfoot .pager a{font-size:15.5px;padding:8px 13px}
.ratenote{font-size:16.5px}
.db-head p{font-size:17px}
.filters input[type=search]{font-size:17px;height:46px}
.filters select{font-size:16px;height:46px}
.filters .reset{font-size:16px;height:46px}

/* A monospace face reads smaller than a proportional one at the same nominal
   size, so code is nudged up to sit at the same optical size as the text. */

/* The monster and item tables carry the most columns; give them room to
   breathe rather than shrinking the type back down. */
.main.wide{padding:34px 28px 70px}

td.exp{white-space:nowrap}
td.exp .muted{opacity:.5;margin:0 1px}

/* Below this width the database tables no longer fit, and without this the
   whole page scrolls sideways instead of the table. position:sticky on the
   table head cannot survive an overflow ancestor, so the sticky header is
   traded away here — on a narrow screen it was of little use anyway. */
@media (max-width: 1360px) {
  .dbwrap{overflow-x:auto}
  table.db thead th{position:static}
  .main.wide{padding:34px 20px 70px}
}

/* =======================================================================
   BRAND COLOUR RULE
   Purple  (--accent, #7445cf) = navigation and structure. Where you are,
                                 what you can click, what something is.
   Green   (--green,  #168b58) = facts and status from the server. Rates,
                                 percentages, counts, "up to date".
   Backgrounds and panels are untouched; only accents and highlights.

   Colour is never the only signal: active states also carry weight or a
   background, so the menu still says "you are here" without relying on hue.
   ======================================================================= */

/* --- purple: navigation and structure --- */
.nav.active{background:var(--accent2);color:var(--accent);font-weight:700}
.nav-home{font-weight:700;margin-bottom:4px}
.otp a.on{border-left-color:var(--accent);color:var(--accent);font-weight:700}
.gnum{background:var(--accent);color:#fff}
.guide-col p a,.guide-col li a,.gstep a,.tipbox a{color:var(--accent)}
.bigsearch input:focus{border-color:var(--accent);box-shadow:0 0 0 4px var(--accent2)}
.filters input:focus,.filters select:focus{border-color:var(--accent)}
.dbfoot .pager a.on{background:var(--accent);border-color:var(--accent);color:#fff}
.fchip{color:var(--accent);background:var(--accent2)}
.tag-mvp,.tag-boss{background:var(--accent2);color:var(--accent)}
.res.on,.res:hover{background:var(--accent2)}
.res em{background:var(--accent2);color:var(--accent)}
.tile:hover,.card:hover,.map-card:hover{border-color:var(--accent)}
.table-scroll th{background:var(--accent2)}
.npc-line .where{color:var(--accent)}

/* --- green: server facts and status --- */
/* Every drop rate is green, including rare ones. Rarity is shown with a tint
   and weight instead of a second hue, so the rule stays "green means a number
   the server produced" rather than splitting into two meanings. */
.drop i,.drop.rare i,.drop.mvp i{color:var(--green)}
.drop.rare{background:var(--green2);font-weight:600}
.chipbar .count{color:var(--green);font-weight:700}
.db-gen b{color:var(--green)}
.ratenote{border-left-color:var(--green)}
.ratenote b{color:var(--green)}
.shortver{border-left-color:var(--green)}
.shortver b{color:var(--green)}
.fresh-note b,.fresh-note a{color:var(--green)}
.ui-icon{color:var(--green)}

/* --- home page blocks --------------------------------------------------
   The search block, the banner and the patch strip are independent siblings
   of .main so the banner keeps the live site's own hero styling, which is
   scoped to a direct child of .main. */
.search-home{padding-bottom:20px}
.main > .wiki-world-hero{margin:8px 0 0}
.main > .fresh-note{margin-top:16px}
.tiles-section{padding-top:36px}
.tiles-section .tiles-intro{margin-top:0}

/* The review block and the closing block, both restored from the live home
   page. The backdrop is the artwork the banner already uses, so the page ends
   on the same picture it opens with rather than introducing a second one.

   Contrast is bought with the overlay, not by moving the text: the gradient
   runs from rgba(17,10,30,.95) to .70 across the width, and every piece of
   text sits in the left two thirds where the overlay never drops below .86.
   White on that is far past the 4.5:1 the small text needs. The picture is
   still legible on the right, which is the only reason to have it. */
.review-block{position:relative;overflow:hidden;margin-top:8px;padding:36px;
  border-radius:16px;color:#fff;
  background:linear-gradient(90deg,rgba(17,10,30,.95),rgba(17,10,30,.86) 58%,rgba(17,10,30,.70)),
    url('ashenro-reborn-world-bg.webp') center/cover}
.review-block .eyebrow{color:#7fe8ba}
.review-block h2{margin:0;color:#fff;font:800 32px/1.18 Manrope,sans-serif;letter-spacing:-.025em}
.review-block .review-sub{margin:4px 0 0;color:#7fe8ba;font-weight:700}
.review-block p{max-width:560px;color:#e5ddec;font-size:16px;line-height:1.7}
.review-block p.cta{margin-top:22px}

.closing-block{margin-top:34px;padding:32px;border:1px solid var(--border);
  border-radius:16px;background:var(--surface)}
.closing-block h2{margin:0 0 10px;font:800 28px/1.2 Manrope,sans-serif;letter-spacing:-.02em}
.closing-block p{max-width:560px;color:var(--muted);font-size:16px;line-height:1.7}
.closing-block p.cta{display:flex;flex-wrap:wrap;gap:10px;margin-top:20px}
/* .section carries 54px of padding-bottom for a page of stacked sections;
   inside a panel that reads as a stray gap under the button. */
.review-block,.closing-block{padding-bottom:36px}

@media (max-width:620px){
  .review-block,.closing-block{padding:24px}
  .review-block h2{font-size:26px}
  .closing-block h2{font-size:24px}
}

/* NPC shown inside a table cell, same idea as the standalone card. */
.npc-cell{display:flex;align-items:center;gap:11px}

.npc-cell .where{font-size:14.5px;color:var(--accent);font-weight:700;font-variant-numeric:tabular-nums}
figure.art.photo{max-width:520px}

/* --- patch notes: index rows and per-patch pages --- */
.patch-index{display:grid;gap:12px}
.patch-row{display:grid;grid-template-columns:170px minmax(0,1fr) auto;align-items:center;gap:20px;
  padding:18px 20px;background:var(--surface);border:1px solid var(--border);border-radius:12px;
  box-shadow:var(--shadow);transition:.18s}
.patch-row:hover{transform:translateY(-1px);border-color:var(--accent)}
.patch-when{font:700 15px Manrope,sans-serif;color:var(--green);font-variant-numeric:tabular-nums}
.patch-row b{display:block;font:700 18px/1.35 Manrope,sans-serif;margin-bottom:4px}
.patch-row small{font-size:16px;line-height:1.55;color:var(--muted)}
.patch-go{font:700 15px "Source Sans 3",sans-serif;color:var(--accent);white-space:nowrap}
.patch-date{font:700 15px Manrope,sans-serif;letter-spacing:.04em;color:var(--green);margin-bottom:8px}

/* --- what the patch was for -------------------------------------------
   A chip rather than "Balancing: " glued to the front of the title, so the
   title still reads as a sentence and the category is what the eye lands
   on when scanning six of them.

   Every category is the SAME colour on purpose. Five colours would be a
   key the reader has to learn before the list is useful, and a list of six
   rows does not have enough repetition to teach one. The chip's job is to
   carry a word, not to encode one. */
.patch-tag{display:inline-block;margin-left:10px;padding:3px 9px;border-radius:999px;
  background:var(--accent2);color:var(--accent);
  font:800 11px/1.45 "Source Sans 3",sans-serif;letter-spacing:.07em;
  text-transform:uppercase;vertical-align:2px;white-space:nowrap}
/* On an index row the date column is narrow, so the chip sits under the
   date rather than pushing the title sideways. */
.patch-when .patch-tag{display:block;margin:7px 0 0;width:max-content}
.patch-body{padding-left:20px;margin:22px 0 36px}
.patch-body li{font-size:17px;line-height:1.75;margin-bottom:10px}
.patch-nav{display:flex;justify-content:space-between;align-items:center;gap:16px;
  padding-top:22px;border-top:1px solid var(--border);font-size:15.5px}
.patch-nav a{color:var(--accent);font-weight:700}
.patch-nav .up{color:var(--muted)}
@media(max-width:700px){.patch-row{grid-template-columns:1fr;gap:8px}}

/* --- NPC sprites at double height ------------------------------------
   Jasper: the Item Tutor sprite was too small to tell which NPC it was.
   Height doubled and width left to follow the aspect ratio, with pixelated
   rendering so they stay crisp instead of becoming blurred upscales. */


.m-sprite .sprite{image-rendering:pixelated}
table.db .m-sprite{width:64px;height:64px;flex:0 0 64px}
table.db .m-name{min-width:200px}
.quest-sprite .m-sprite{height:72px}

/* Bound-item tags, coloured as they appear in game. */
.tag-char{color:#c0392b;font-weight:700}
.tag-acct{color:#2a62c4;font-weight:700}
.dark .tag-char{color:#f08a7a}
.dark .tag-acct{color:#8fb4f5}

/* =======================================================================
   +1px pass on the inherited stylesheets.
   wiki.css sizes were raised in place; site.css and refresh.css are mirrored
   from the live site verbatim and are not edited, so the sizes they set are
   raised here instead.
   ======================================================================= */
body{font-size:17px}
.guide-section p,.guide-section li{font-size:17px}
.gstep p,.gstep li{font-size:17px}
.guide-col > .lede{font-size:18px}
.hero p,.page-head p{font-size:18px}
.nav{font-size:14px}
.nav-title{font-size:11px}
.card small{font-size:13.5px}
.card b{font-size:16px}
.section h2{font-size:30px}
.callout,details{font-size:14px}
.stat-row span,.info span{font-size:13px}
.fresh-note{font-size:15px}
footer,.wiki-foot{font-size:13px}
.top-actions a{font-size:14px}

/* --- the mascot, above the search heading -----------------------------
   Sized as a greeting rather than a hero image: the search box stays the
   thing the eye lands on. Not lazy-loaded, because it is above the fold and
   a lazy load would delay the animation. */

/* --- latest patch strip ----------------------------------------------
   Labelled so a first-time visitor can tell what it is. */
.fresh-note .patch-label{display:block;font:800 11px/1 Manrope,sans-serif;
  letter-spacing:.14em;color:var(--green);margin-bottom:5px}
.fresh-note .patch-meta{font-weight:700;color:var(--text)}

/* =======================================================================
   SIDEBAR
   One visual language for "you are here": a filled background plus weight,
   never a background and a marker bar at once. Colour is not the only signal.
   ======================================================================= */
.sidebar{padding-top:18px}
.nav{padding:8px 11px;margin:1px 0;border-radius:8px;color:var(--text);
  border-left:0;transition:background .14s,color .14s}
.nav:hover{background:var(--surface2);color:var(--text)}
.nav.active,.nav.active:hover{background:var(--accent2);color:var(--accent);font-weight:700}
.nav-home{margin-bottom:10px}

/* Group headers: clearly a header, clearly separated from what is above. */
.nav-title{padding:8px 11px 6px;margin-top:20px;font-weight:800;letter-spacing:.14em;
  color:var(--muted);border-top:1px solid var(--border)}
.nav-title:first-of-type{margin-top:14px}
.sidebar .wiki-return + .nav{margin-top:2px}

/* =======================================================================
   SIDEBAR — modelled on the live wiki's, which is the reference Jasper
   pointed at: an icon on every row, collapsible groups with a chevron,
   headers in brand purple, and an active state that uses a tint AND a bar.
   What is deliberately NOT copied is its 33 items and fifteen in-page
   anchors; the affordances are the lesson, not the structure.
   ======================================================================= */

.nav{display:flex;align-items:center;gap:10px;padding:8px 11px;margin:1px 0;
  border-radius:8px;border-left:3px solid transparent;color:var(--text);
  font-size:14px;line-height:1.4;transition:background .14s,color .14s}
.nav-ico{flex:0 0 20px;width:20px;text-align:center;font-size:15px;line-height:1}
.nav:hover{background:var(--surface2)}

/* Active: tint, left bar, weight and colour together — four signals, so it
   still reads as "you are here" without relying on hue. */
.nav.active,.nav.active:hover{background:var(--accent2);border-left-color:var(--green);
  color:var(--accent);font-weight:700}

.nav-toggle{width:100%;display:flex;align-items:center;justify-content:space-between;
  gap:8px;padding:7px 10px;border:0;background:transparent;cursor:pointer;
  border-radius:8px;font-family:inherit}
.nav-title{padding:0;margin:0;border:0;font:800 11px/1 Manrope,sans-serif;
  letter-spacing:.15em;color:var(--accent);text-transform:uppercase}
.nav-chevron{font-size:15px;line-height:1;color:var(--muted);
  transform:rotate(-90deg);transition:transform .16s ease}
.nav-home{margin-bottom:2px}

/* --- home tiles -------------------------------------------------------
   Illustrated tiles for the "start here" guides, line icons for database
   and reference tiles. Art sits above the title at roughly three lines of
   text, matching the live site's proportions — the tiles are navigation,
   not a gallery. */
.tile-art{display:block;width:84px;height:84px;object-fit:contain;margin:-2px 0 10px}
.tile > .ui-icon{width:30px;height:30px;margin:6px 0 16px;color:var(--green)}
.tile{align-content:start}

/* --- server stat band -------------------------------------------------
   One band that reads as a single statement about the server, not five
   separate cards: thin dividers rather than boxes, so it scans left to
   right in one pass. Every value links to where it is explained.

   All of these are server facts, so all of them are green. The live
   version alternated purple and green for rhythm, which under our own
   convention would make purple mean nothing — variation comes from weight
   and size instead of hue. */
.statband{display:flex;flex-wrap:wrap;margin:18px 0 0;background:var(--surface);
  border:1px solid var(--border);border-radius:14px;box-shadow:var(--shadow);overflow:hidden}
.statband .stat{flex:1 1 0;min-width:160px;padding:18px 20px;
  border-left:1px solid var(--border);transition:background .15s}
.statband .stat:first-child{border-left:0}
.statband .stat:hover{background:var(--surface2)}
.statband b{display:block;font:800 26px/1.15 Manrope,sans-serif;color:var(--green);
  letter-spacing:-.02em;margin-bottom:5px}
.statband span{display:block;font-size:13px;line-height:1.45;color:var(--muted)}

/* Two rows on a narrow window rather than shrinking the type. */
@media(max-width:980px){
  .statband .stat{flex:1 1 33%;min-width:0}
  .statband .stat:nth-child(4){border-left:0}
  .statband .stat:nth-child(n+4){border-top:1px solid var(--border)}
}
@media(max-width:620px){
  .statband .stat{flex:1 1 50%}
  .statband .stat:nth-child(odd){border-left:0}
  .statband .stat:nth-child(n+3){border-top:1px solid var(--border)}
}

/* =======================================================================
   NPC CARDS — one fixed icon column everywhere.
   Sprites have different natural widths, so a column that sizes to its content
   makes the text start at a different x on every card and the names go ragged.
   The column is therefore fixed for every NPC, with the sprite centred inside.

   Width is set from the MEDIAN rendered sprite width, not the maximum. Measured
   across the 14 NPCs actually used: 35px to 74px, median 43, mean 45. Sizing to
   the 74px Healing Orb left an empty gap on all thirteen other cards. Anything
   wider than the column scales down to fit — both dimensions, so the art is
   never distorted — and only the Healing Orb and the Stylist are affected at
   all, which is invisible next to a gap on every card.

   Horizontal padding is 0 for the same reason: vertically it does useful work,
   horizontally it was adding to a gap that was already too wide.
   ======================================================================= */

.npc-cell{display:grid;grid-template-columns:46px minmax(0,1fr);align-items:center;gap:10px}

table.db .m-sprite{width:52px;height:58px;flex:0 0 52px}

/* =======================================================================
   MONOSPACE — one declaration for every code span, chip and .mono run.
   Body text is 17px. The mono face has a larger x-height and wider glyphs,
   so at the same nominal size it reads BIGGER and bumps the line rhythm
   where it appears mid-sentence. 15px is the size at which an inline code
   span stops interrupting the line it sits in.
   The chip adds only padding and background on top of this — it does not
   set its own size, which is how three different mono sizes appeared.
   ======================================================================= */
code, .mono, table.db td.num, .drop i, td.maps {
  font-size:15px;
  font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
}
code{padding:2px 6px;border-radius:5px;background:var(--surface2)}
.table-scroll code{padding:2px 6px}
.m-name small{font-size:14px}

/* =======================================================================
   CARD BOX SPACING
   Three separate measurements that pull in opposite directions, set here
   together so one is not used to satisfy another:
     card edge -> PADDING 24px -> icon column -> GUTTER 12px -> text
   Vertical padding is equal top and bottom so the text block does not sit
   closer to one edge than the other.
   ======================================================================= */
.npc-line{padding:18px 24px;gap:12px;margin-bottom:12px}
.npc-line:last-child{margin-bottom:0}
/* Fixed height as well as width, so cards with a tall sprite and cards with
   a short one are the same height and the stack has an even rhythm. */
.shortver{padding:20px 24px}
.tipbox{padding:16px 24px}

/* --- NPC icon box: shared ground line, one governing dimension ---------
   place-items:center centred each sprite vertically, so three sprites of
   different heights had their feet at three different levels and appeared to
   float. These are standing characters: they read correctly sharing a ground
   line, as they do in game. Horizontal stays centred, vertical becomes end.

   Width is 60px, measured rather than guessed: at an 88px content height the
   widest sprite (Healing Orb, 82x120) needs 60px, so at 60px nothing is
   width-limited and HEIGHT alone governs scale. Below that, wide sprites got
   scaled down by width and ended up shorter than narrow ones — inconsistent
   scale that reads as another alignment fault.

   The gutter to the text stays at 12px; this widens the box only. */
.npc-line{display:grid;grid-template-columns:60px minmax(0,1fr);
  align-items:center;gap:12px;padding:18px 24px;margin-bottom:12px}
.npc-line .npc-pic{display:grid;place-items:end center;width:60px;height:94px;
  padding-bottom:6px}
.npc-cell{grid-template-columns:52px minmax(0,1fr)}
.npc-cell .npc-pic{display:grid;place-items:end center;width:52px;height:72px;
  padding-bottom:4px}

/* Explicit pixel caps, not percentages: max-height:100% does not resolve
   against an auto-height grid container, so the sprites rendered at natural
   size and each card was a different height again. Capping the height in px
   makes height the single governing dimension, which is what gives every
   sprite the same apparent scale. */
.npc-line img{max-height:88px;max-width:60px;width:auto;height:auto;
  object-fit:contain;image-rendering:pixelated}
.npc-cell img{max-height:64px;max-width:52px;width:auto;height:auto;
  object-fit:contain;image-rendering:pixelated}


/* --- the mascot ------------------------------------------------------
   Jasper: it was throwing the proportion off. Roughly half its previous
   height, so the order of weight reads search, heading, poring — not
   poring, heading, search. Aspect ratio kept; never cropped. It shrinks
   again on a narrow window, where the heading wraps to two lines and a
   fixed-size image would start to dominate. */
.poring-greet{display:block;width:auto;height:54px;margin:0 auto 10px}
@media(max-width:620px){.poring-greet{height:42px}}

/* --- Home: a distinct element, not a bigger list item ------------------
   Prominence comes from being a different KIND of thing to the nav items,
   not from more weight. It carries the search affordance now that the
   sidebar field is gone, and the Ctrl K hint sits where a user will look
   for it rather than being a secret shortcut. */
.home-btn{display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;
  gap:11px;margin:0 0 6px;padding:11px 13px;border-radius:10px;
  background:var(--accent2);border:1px solid var(--border);
  color:var(--accent);transition:background .15s,border-color .15s}
.home-btn:hover{border-color:var(--accent)}
.home-btn.active{border-color:var(--accent);box-shadow:inset 3px 0 0 var(--green)}
.home-ico{width:19px;height:19px;fill:none;stroke:currentColor;stroke-width:2;
  stroke-linecap:round}
.home-btn b{display:block;font:800 15px/1.2 Manrope,sans-serif}
.home-btn small{display:block;font-size:12.5px;line-height:1.3;color:var(--muted)}
.home-btn kbd{font-size:10.5px;padding:3px 5px;border:1px solid var(--border);
  border-radius:4px;background:var(--surface);color:var(--muted);white-space:nowrap}

/* Clear separation from the groups below, so Home does not read as the
   first item of an unnamed group. */
.sidebar .home-btn + 

/* =======================================================================
   STEP MARKERS — the client's inventory-slot frame (chosen option 6).
   A hairline frame and a pale inset fill, never a block: the two markers
   rejected before this were both heavy filled shapes, and the frame being
   a line rather than a slab is the reason this one works. Resist adding
   weight to it.
   Purple, per the colour convention — this is structure, not a server fact.
   ======================================================================= */
.gstep > h2{display:flex;align-items:center;gap:14px}
.stepslot{flex:0 0 34px;width:34px;height:34px;display:grid;place-items:center;
  font:800 16px/1 Manrope,sans-serif;font-variant-numeric:tabular-nums;
  color:var(--accent);background:var(--accent2);
  border:1px solid var(--accent);border-radius:2px;
  box-shadow:inset 1px 1px 0 rgba(255,255,255,.7),
             inset -1px -1px 0 rgba(0,0,0,.10)}
.dark .stepslot{box-shadow:inset 1px 1px 0 rgba(255,255,255,.12),
                           inset -1px -1px 0 rgba(0,0,0,.30)}
/* Two digits widen the slot rather than shrinking the numeral. */
.stepslot{padding:0 6px;min-width:34px;width:auto}

/* The "on this page" list numbers the same steps. It stays plain text so it
   does not compete with the page, with the numeral in the same purple so the
   two read as one sequence rather than two. */
.otp a{font-variant-numeric:tabular-nums}
.otp a.on{font-weight:800}

/* =======================================================================
   FAQ — native <details>, styled so it does not read as browser default.
   The closed list of questions IS the navigation, so the question text
   stays at full readability when collapsed rather than being greyed out.
   ======================================================================= */
.faq{display:grid;gap:8px;margin:20px 0 6px}
.faq-item{border:1px solid var(--border);border-radius:10px;background:var(--surface);
  padding:0;overflow:hidden}
.faq-item + .faq-item{margin:0}
.faq-item summary{display:flex;align-items:center;justify-content:space-between;gap:14px;
  padding:15px 18px;cursor:pointer;list-style:none;
  font:700 17px/1.45 Manrope,sans-serif;color:var(--text);
  transition:background .14s}
.faq-item summary::-webkit-details-marker{display:none}
.faq-item summary:hover{background:var(--accent2)}
.faq-item summary:focus-visible{outline:3px solid var(--accent);outline-offset:-3px}
.faq-item[open] summary{color:var(--accent);border-bottom:1px solid var(--border)}

/* A chevron drawn in CSS, rotating on open. */
.faq-mark{flex:0 0 11px;width:11px;height:11px;margin-right:2px;
  border-right:2px solid var(--accent);border-bottom:2px solid var(--accent);
  transform:rotate(45deg) translate(-2px,-2px);transition:transform .18s ease}
.faq-item[open] .faq-mark{transform:rotate(-135deg) translate(-3px,-3px)}

.faq-answer{padding:14px 18px 17px}
.faq-answer p{margin:0;font-size:17px;line-height:1.7;color:var(--muted)}

/* --- sidebar: categories are headers, entries may have children --------
   The chevron belongs to an ITEM with sub-pages, not to a category, so the
   three categories stay permanently open and a reader never has to expand a
   group to find anything. */
.nav-group + .nav-group{margin-top:16px}
.nav-group .nav-title{padding:8px 11px 6px;margin:0 0 2px;border-top:1px solid var(--border)}
.nav-group:first-of-type .nav-title{border-top:0}

.nav-item{display:block}
.nav-row{display:flex;align-items:stretch;gap:2px}
.nav-row .nav{flex:1;min-width:0}
/* place-content as well as place-items, and the reason is worth keeping:
   site.css sets `justify-content:space-between` on .nav-toggle for its own
   layout. `place-items` is align-items + justify-items — it does NOT touch
   justify-content — so the inherited space-between survived and pushed the
   single grid track hard against the left edge. The chevron was flush left
   in a box everyone assumed was centring it. */
.nav-toggle{flex:0 0 28px;display:grid;place-items:center;place-content:center;
  border:0;background:transparent;
  cursor:pointer;border-radius:8px;color:var(--muted);padding:0}
.nav-toggle:hover{background:var(--surface2);color:var(--text)}
.nav-toggle:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}
/* An SVG, so the mark is centred by centring the box. The old "⌄" was text
   and sat on a baseline, which is why it rode low in a button that was
   already using place-items:center — the container was never the problem. */
.nav-chevron{display:block;width:15px;height:15px;transform:rotate(-90deg);
  transform-origin:50% 50%;
  transition:transform var(--t-expand) var(--ease)}
.nav-item.open > .nav-row .nav-chevron{transform:rotate(0deg)}

/* --- expanding a nav item ----------------------------------------------
   `height:auto` cannot be transitioned, so the panel is a grid whose single
   row goes from 0fr to 1fr. That handles content of a height nobody knows
   in advance, and unlike a max-height trick it never spends most of the
   transition travelling through empty space — a short list of two dates
   opens in the same 200ms as a long one, instead of appearing to lag.

   The inner element carries overflow:hidden so the links are clipped as the
   row closes rather than spilling out of it.

   Nothing animates on arrival. The markup is written with .open already set
   when the group was left open, so the first computed value IS the open
   value and there is no transition to run — a page opening its own nav on
   load would read as a glitch rather than as an answer to anything. */
.nav-children{display:grid;grid-template-rows:0fr;
  transition:grid-template-rows var(--t-expand) var(--ease)}
.nav-item.open > .nav-children{grid-template-rows:1fr}
.nav-kids{overflow:hidden;min-height:0}

.nav.child{padding-left:42px;font-size:13.5px;color:var(--muted);
  font-variant-numeric:tabular-nums}
.nav.child:hover{color:var(--text)}
.nav.child.active{background:var(--accent2);color:var(--accent);font-weight:700;
  border-left-color:var(--green)}

/* =======================================================================
   SIDEBAR RHYTHM
   Jasper: the column felt suffocating. The cause is spacing, not colour —
   an emoji renders taller than a line of text, so a row height tuned for
   text and then given an emoji leaves the glyph nearly touching top and
   bottom. Twenty of those stacked is what reads as airless.

   Note the chain: this appeared when the categories stopped collapsing,
   which is a change that was asked for. Nothing in the sidebar itself
   regressed; you simply never saw twenty rows at once before.

   Group headers get noticeably more space ABOVE than below, so a header
   belongs to the items beneath it instead of floating between two groups.
   ======================================================================= */
.sidebar{padding:20px 15px 28px}
.nav{padding:10px 11px;margin:2px 0;line-height:1.45}
.nav-ico{flex:0 0 22px;width:22px;font-size:16px;line-height:1}
.nav.child{padding:8px 11px 8px 44px;margin:1px 0}

.nav-group + .nav-group{margin-top:0}
.nav-group .nav-title{padding:10px 11px 8px;margin:26px 0 4px;
  border-top:1px solid var(--border)}
.nav-group:first-of-type .nav-title{margin-top:18px;border-top:0}

.home-btn{margin-bottom:2px;padding:12px 13px}
/* Spacing as MARGINS on the children, never padding on .nav-kids. A grid
   track at 0fr still cannot shrink below its item's padding, so 8px of it
   stayed behind and a collapsed group kept a visible gap. Child margins sit
   inside the content box, which min-height:0 and overflow:hidden do collapse
   to nothing. */
.nav-kids > .nav:first-child{margin-top:2px}
.nav-kids > .nav:last-child{margin-bottom:6px}

/* --- sidebar: one separator, not two ----------------------------------
   The rule between groups was a second separator doing the job the 26px
   above a header already does. Deleted rather than lightened: a very faint
   line is still a line, and tuning its opacity never ends. */
.nav-group .nav-title{border-top:0}

/* --- horizontal breathing room ----------------------------------------
   Rows sat close to both edges. The sidebar gains side padding, and the
   row highlight is INSET from the sidebar edges rather than flush to them
   — it is a rounded pill, and bleeding a rounded shape to a hard edge
   reads as a misalignment. The Home block follows the same rule so the
   two do not disagree. */
.sidebar{padding:20px 20px 30px}
.nav{padding:10px 12px}
.nav.child{padding-left:46px}
.home-btn{padding:12px 14px}
.nav-group .nav-title{padding:10px 12px 8px}

/* =======================================================================
   SIDEBAR SCROLLING
   The sidebar is its own scrolling region again: sticky, 100vh minus the
   topbar, overflow-y:auto. That is what keeps the nav on screen on a long
   page, which is the behaviour worth having.

   The earlier fix here put the column back into normal flow so the page
   carried the only scrollbar. That solved the visible complaint — a 16px
   opaque grey bar eating width and drawing a hard edge down the column —
   by giving up the pinning, which was never what was wrong. The question
   is not "one scrollbar or two", it is "how wide is the scrollbar, and
   does it have to take space at all". It does not:

     - the native bar is hidden in both engines, so it reserves NO width
       and the rows keep every pixel they had;
     - an overlay dot (.nav-hint, positioned by wiki.js) floats above the
       column instead of sitting in the layout, so it costs nothing. It is
       invisible at rest, fades in while you scroll, and fades back out a
       second after you stop.

   Hiding a scrollbar removes the affordance, not the ability: wheel,
   trackpad, keyboard and touch all still scroll the column. The dot is a
   wayfinding hint — it says where you are, it is not a control you drag.

   Not scoped below 851px, where .sidebar becomes the off-canvas drawer
   and genuinely does need its own positioning.
   ======================================================================= */
@media (min-width: 851px) {
  .sidebar{position:sticky;top:66px;height:calc(100vh - 66px);overflow-y:auto;
    overflow-x:hidden;scrollbar-width:none;-ms-overflow-style:none}
  .sidebar::-webkit-scrollbar{width:0;height:0;display:none}
}

/* The dot itself. Fixed, so it is out of the layout entirely and cannot
   push the rows around however long the nav gets. wiki.js owns its top,
   left and visibility; everything here is appearance only. */
.nav-hint{position:fixed;width:6px;height:22px;border-radius:3px;
  background:var(--accent);opacity:0;pointer-events:none;z-index:40;
  transition:opacity .35s ease}
.nav-hint.on{opacity:.55}
@media (prefers-reduced-motion: reduce){.nav-hint{transition:none}}

/* =======================================================================
   MOTION
   Everything clickable answers when you touch it, and nothing moves on
   its own. Nothing here loops, pulses or plays unprompted: an animation
   that runs while you are reading competes with you, and this is a
   reference site people come to to read one number off a table. The only
   @keyframes in the file is the search panel arriving, which is one-shot
   and is a direct answer to the reader typing.

   Rules this section follows, and the reason for each:

   1. Fast. 140ms for hover, 190ms for anything with a shadow, 240ms as
      the ceiling. People move quickly through a wiki; slow is not elegant
      here, it is in the way.
   2. Ease-out — quick to start, settling at the end. No bounce.
   3. Named properties, never `transition:all`. `all` catches things you
      did not mean, and a transitioned layout property is a frame budget
      spent on nothing.
   4. transform and opacity wherever possible, because they are composited
      and do not force layout. That matters at 363 monster rows and 6,541
      item rows, where a hover that reflows would be felt.
   5. Nothing shifts the layout. Every lift is a transform, so the box the
      cursor is inside never actually moves — a list that re-flows under
      the pointer can swap the row out from under a click.
   6. prefers-reduced-motion: reduce turns all of it off, including the
      transforms. refresh.css already kills transition and animation
      globally under that query, but a transform with no transition still
      jumps, so the hover transforms are neutralised here as well.
   ======================================================================= */
:root{
  --ease:cubic-bezier(.22,.68,.36,1);   /* ease-out: fast, then settles */
  --t-hover:140ms;
  --t-lift:190ms;
  --t-panel:240ms;
  --t-expand:200ms;   /* nav item expand/collapse, chevron included */
}

/* --- the two `transition:.18s` shorthands, replaced ---------------------
   .tile and .patch-row were written with the shorthand, which means
   `all`. Both lift and change border colour on hover, so naming those
   three properties is the whole of what they were relying on. */
.tile,.patch-row{
  transition:transform var(--t-lift) var(--ease),
             box-shadow var(--t-lift) var(--ease),
             border-color var(--t-hover) var(--ease)}

/* --- lift, and press ---------------------------------------------------
   The press is the half people notice without being able to say why: an
   element that gives under the pointer reads as a physical thing. It is
   deliberately smaller and faster than the lift. */
.tile:hover,.patch-row:hover,.map-card:hover{box-shadow:0 12px 30px rgba(25,30,45,.10)}
.map-card:hover{transform:translateY(-2px)}
.tile:active,.patch-row:active,.map-card:active{
  transform:translateY(0) scale(.994);
  box-shadow:0 2px 8px rgba(25,30,45,.07);
  transition-duration:90ms}

.map-card{transition:transform var(--t-lift) var(--ease),
                     box-shadow var(--t-lift) var(--ease),
                     border-color var(--t-hover) var(--ease)}
/* No scale-up on the minimap inside a map card, deliberately. The image is
   fitted with `contain`, so it already touches the frame on its long axis;
   growing it crops the map edges, which is the exact thing the switch away
   from `cover` was for. The card lifts, the picture stays whole. */

/* The tile artwork grows a little inside the tile. `object-fit:contain`
   with a fixed box means the image scales within its own footprint and
   the text under it does not move. */
.tile-art{transition:transform var(--t-panel) var(--ease)}
.tile:hover .tile-art{transform:scale(1.06)}

/* --- buttons and link-buttons -----------------------------------------
   The download button is the one real button on the site, so it gets the
   full treatment; the quieter ones get colour and a press. */
.btn,.top-actions .wiki-download,.filters .reset,.drop.more,.fchip,
.patch-nav .up,.patch-nav .back,.otp .back,.res-head a{
  transition:transform var(--t-hover) var(--ease),
             box-shadow var(--t-lift) var(--ease),
             background-color var(--t-hover) var(--ease),
             border-color var(--t-hover) var(--ease),
             color var(--t-hover) var(--ease)}
.btn:hover{transform:translateY(-1px);box-shadow:0 8px 20px rgba(116,69,207,.24)}
.btn:active,.top-actions .wiki-download:active,.filters .reset:active,
.drop.more:active,.fchip:active{transform:translateY(0) scale(.97);transition-duration:90ms}
.top-actions .wiki-download:hover,.patch-nav .up:hover,
.patch-nav .back:hover,.otp .back:hover,.res-head a:hover{color:var(--accent)}
.filters .reset:hover,.drop.more:hover,.fchip:hover{border-color:var(--accent);color:var(--accent)}

/* --- table rows --------------------------------------------------------
   The tint is the reason this one earns its place: on a wide row you look
   across to a far column, and a highlight that fades in keeps your eye on
   the row you are actually reading. background-color only — no transform,
   nothing that could reflow a table this long. */
table.db tbody tr{transition:background-color var(--t-hover) var(--ease)}
table.db thead th{transition:color var(--t-hover) var(--ease),
                             background-color var(--t-hover) var(--ease)}

/* --- rows, cards and the things that already tinted --------------------
   These all changed background instantly before. Same colours, faded. */
.res,.statband .stat,.npc-line,.faq-item summary,.home-btn,.wiki-return{
  transition:background-color var(--t-hover) var(--ease),
             border-color var(--t-hover) var(--ease),
             color var(--t-hover) var(--ease)}
.npc-line:hover{border-color:var(--accent)}
.faq-item summary:active{transition-duration:80ms}

/* --- search results ----------------------------------------------------
   Results arrive in a batch, so they fade up together rather than one
   after another: a stagger on a list that rewrites itself on every
   keystroke turns into flicker. Four pixels and a fade, no more.

   This is the one animation in the file, and it earns the exception to
   "no keyframes": it is one-shot and it is a direct answer to the reader
   typing, not something that moves on its own. It runs when the panel
   stops being [hidden] — so it plays on the panel appearing and NOT on
   each keystroke that refines a list already open, which is when a
   restarting fade would be flicker.

   Keyframes rather than a transition on purpose. A transition needs
   JavaScript to move the element off a start state, and if that never
   runs the panel is stranded invisible. An animation that never runs
   leaves the element at its ordinary opacity, which is visible. Search
   results are the last thing on this site that should be able to
   disappear, so the failure mode chooses itself. */
@keyframes res-in{from{opacity:0;transform:translateY(4px)}
                  to{opacity:1;transform:none}}
.results:not([hidden]){animation:res-in var(--t-panel) var(--ease)}

/* --- links in body text ------------------------------------------------
   The underline grows from the left instead of appearing. Drawn as a
   background gradient rather than text-decoration, because a decoration
   appearing changes nothing about layout but cannot be transitioned;
   background-size can, and it is paint-only. */
.guide-col p a,.guide-col li a,.gstep a,.tipbox a{
  background-image:linear-gradient(currentColor,currentColor);
  background-repeat:no-repeat;
  background-position:0 100%;
  background-size:0% 1px;
  transition:background-size var(--t-hover) var(--ease),
             color var(--t-hover) var(--ease)}
.guide-col p a:hover,.guide-col li a:hover,.gstep a:hover,.tipbox a:hover{
  background-size:100% 1px}

/* --- focus -------------------------------------------------------------
   Keyboard users get the same answer the mouse gets. The ring itself is
   never faded in: a focus indicator that arrives late is a focus
   indicator you can miss. */
.tile:focus-visible,.map-card:focus-visible,.patch-row:focus-visible,
.btn:focus-visible,.res:focus-visible{outline:3px solid var(--accent);outline-offset:2px}

/* =======================================================================
   GLOW ON HOVER — .glow, one class, used on more than one button
   =======================================================================
   A blurred rainbow halo behind a button, invisible at rest, fading in on
   hover while the gradient sweeps across. Jasper's effect, and note that
   it does NOT need an exception to "nothing moves on its own": it is only
   ever visible as an answer to the pointer arriving. The rule stands.

   ONE CLASS, used twice, on purpose. Two hand-tuned copies of a nine-stop
   gradient diverge the first time either is touched, and a glow that is
   subtly different on two buttons reads as a fault rather than a style.
   Anything that needs tuning per button is a CUSTOM PROPERTY below, so
   the shape of the effect stays identical and only the numbers move.

   WHAT CHANGED FROM THE ORIGINAL, and why. The source pattern assumes a
   dark page — #000 behind a #111 button — where a blurred saturated
   gradient reads as light. Ours is a near-white sidebar and a near-white
   page, where the same blur spreads colour into a pale surround and goes
   grubby rather than luminous.

     - The fill is the button's OWN background (--glow-fill), never #111.
       Darkening the button to make the halo work would be fixing the
       wrong thing.
     - Blur goes from 5px to 10px and the inset from 2px to 3px. On a pale
       surround a tight blur reads as a coloured outline — a fringe, which
       looks like a rendering fault — where a wider one reads as light.
     - `saturate()` on the layer, because blurring toward a light
       background washes the stops out; this puts back what the blur takes.
     - The radius is inherited rather than the original's flat 10px, so it
       follows whichever button it is on.

   THE ANIMATION IS PAUSED AT REST, which the original does not do. This
   one animates `background-position`, which REPAINTS every frame — and on
   a blurred layer it re-blurs too. The original runs it forever so a hover
   never catches the sweep mid-stride; but forever, invisible, on all 29
   pages, in a pinned sidebar, is a real cost for a frame nobody sees.
   Starting at 0% on hover looks deliberate, so the trade is easy. */
.glow{position:relative;isolation:isolate;
  --glow-blur:10px;
  --glow-spread:3px}
.glow::before{
  content:"";position:absolute;inset:calc(var(--glow-spread) * -1);z-index:-1;
  border-radius:inherit;
  /* Brand colours, chosen over the nine-stop rainbow — the comparison is kept
     in build_homebtn.py. Two things this gradient has to do that a rainbow got
     for free:

     IT HAS TO READ AS MOVING. A spectrum looks like it is travelling even when
     it barely moves, because the hue is always changing. Two colours will not,
     so they alternate FIVE times across the width rather than relying on
     background-size to stretch two stops — that gives the sweep a rhythm
     instead of a slow pulse.

     IT HAS TO CLOSE. First and last stop are the same colour, exactly as the
     rainbow started and ended on #ff0000. Anything else flicks once per cycle
     at the wrap, and at 20 seconds that flick is the only thing you would
     notice.

     The hexes are lifted from the flat brand colours (#7445cf, #168b58)
     because the flat ones do not survive a 10px blur on a pale surface — they
     go grey before they spread. These read as the same two colours with the
     light behind them, which is the actual constraint. */
  background:linear-gradient(45deg,#8f5ff0,#2fbd85,#8f5ff0,#2fbd85,#8f5ff0);
  background-size:400% 400%;
  filter:blur(var(--glow-blur)) saturate(1.25);
  opacity:0;transition:opacity .3s ease-in-out;
  animation:glow-sweep 20s linear infinite;
  animation-play-state:paused}
/* focus-visible as well as hover: a keyboard user gets the same answer. */
.glow:hover::before,.glow:focus-visible::before{
  opacity:1;animation-play-state:running}
/* The button's own face, painted back over the middle of the halo so only
   the spread shows. Negative z-index children paint above the element's
   own background, so this layer is doing real work even on a button that
   already has one. */
.glow::after{
  content:"";position:absolute;inset:0;z-index:-1;border-radius:inherit;
  background:inherit}
@keyframes glow-sweep{
  0%{background-position:0 0}
  50%{background-position:400% 0}
  100%{background-position:0 0}}

/* The sidebar instance runs tighter than the page one. The Home button sits in
   a column with 20px of padding, and at the default blur the halo reached that
   edge — measured against the real column width, not guessed. The download
   button has a whole page around it and keeps the wider spread. Two values of
   one class, which is the point of having the values as properties. */
.home-btn{--glow-blur:8px;--glow-spread:2px}

/* The download button needs MORE spread than the default, and the reason is
   specific to brand colours. That button is itself a purple-to-green gradient,
   so a purple-and-green halo sits against an edge of its own colour and reads
   as the button being blurry rather than as light behind it — the exact
   muddiness the rainbow avoided by never matching the edge it met. Pushing the
   light further out separates the two again. Checked by eye against the
   rainbow version side by side; it is still the softer of the two. */
.btn.primary{--glow-blur:15px;--glow-spread:5px}

/* The fill is `background:inherit` rather than a per-button colour, so each
   button masks the halo with its OWN background whatever that is — flat on
   the Home button, a purple-to-green gradient on the download button — and
   nobody has to keep a copy of it in step. A .glow on a transparent button
   would show the halo through its middle; give such a button a background
   before adding the class.

   .glow needs a real box: an inline element's pseudo-elements do not take an
   `inset:0` containing block reliably, and .btn was display:inline. */
.btn{display:inline-flex;align-items:center}

/* A standalone primary action. Paragraphs here carry no top margin — they
   rely on the previous element's bottom margin — which left the download
   button 6px under its heading, reading as attached to it rather than as the
   thing you do next. Any future page with a lone call to action should use
   this class rather than inventing a margin.

   Selector written to outrank `.gstep p{margin-top:0}`, which is (0,1,1) and
   beat a bare `.cta` at (0,1,0) — the rule was there and doing nothing. */
.gstep p.cta,.guide-col p.cta{margin-top:20px}
/* The current-page marker lived on the button's own inset shadow, which
   the ::after fill now paints over. It moves onto the fill itself. */
.home-btn.active::after{box-shadow:inset 3px 0 0 var(--green)}

@media (prefers-reduced-motion: reduce){
  /* The halo still appears on hover — that feedback is the point, and it
     is a response rather than movement. Only the sweep stops, leaving a
     static gradient. refresh.css kills the animation globally; this is
     here so the intent is readable at the effect itself. */
  .glow::before{animation:none}
}

/* --- reduced motion ----------------------------------------------------
   Colour still changes, because that is information about what is
   clickable. Movement does not.

   The Home sheen FREEZES rather than disappearing: `refresh.css` kills
   every animation under this query, which leaves the gradient sitting
   static at its start angle, so the button still reads as the special one
   it is. Removing it here would make it plainest for the people most
   likely to need it to stand out. */
@media (prefers-reduced-motion: reduce){
  .home-btn::before{animation:none}
  .tile:hover,.tile:active,.tile:hover .tile-art,
  .patch-row:hover,.patch-row:active,
  .map-card:hover,.map-card:active,
  .btn:hover,.btn:active,.top-actions .wiki-download:active,
  .filters .reset:active,.drop.more:active,.fchip:active{transform:none}
  .results:not([hidden]){animation:none}
  .guide-col p a,.guide-col li a,.gstep a,.tipbox a{background-image:none}
  .guide-col p a:hover,.guide-col li a:hover,
  .gstep a:hover,.tipbox a:hover{text-decoration:underline}
}

/* Owner-supplied October guide additions. */
.guide-col .gstep{scroll-margin-top:100px}.guide-col .gstep h2{line-height:1.3}
.guide-col .gstep li{margin-bottom:.6em}.guide-col .table-scroll{overflow-x:auto;max-width:100%}
.guide-col .table-scroll table{min-width:580px;width:100%}.guide-col .table-scroll th{text-align:left}
.guide-col .table-scroll:focus-visible{outline:3px solid #7650a2;outline-offset:4px}
.update-guides{display:flex;flex-wrap:wrap;gap:12px 28px;padding:12px 0 24px}.update-guides a{font-weight:700;text-underline-offset:4px}

@media(min-width:1181px){.otp{max-height:calc(100svh - 120px);overflow-y:auto;padding-right:8px}}
