/* SpiritValers shared theme — single source of truth for palette + fonts.
   Loaded (cache-busted) in every app page's <head> BEFORE its inline <style>,
   so page rules resolve these custom properties in either theme. Do not
   re-declare these palette vars inline in a page; add new roles here.
   Theme is selected by the <html data-theme="light|dark"> attribute, set by
   each page's inline theme-init script (reads localStorage 'sv-theme'). */

/* self-hosted variable fonts — Google Fonts, OFL. Full weight axis; latin/latin-ext/vietnamese subsets. */
@font-face{font-family:'Crimson Pro';font-style:normal;font-weight:200 900;font-display:swap;src:url('fonts/crimson-pro-vietnamese.woff2') format('woff2');unicode-range:U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB}
@font-face{font-family:'Crimson Pro';font-style:normal;font-weight:200 900;font-display:swap;src:url('fonts/crimson-pro-latin-ext.woff2') format('woff2');unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF}
@font-face{font-family:'Crimson Pro';font-style:normal;font-weight:200 900;font-display:swap;src:url('fonts/crimson-pro-latin.woff2') format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
@font-face{font-family:'Atkinson Hyperlegible Next';font-style:normal;font-weight:200 800;font-display:swap;src:url('fonts/atkinson-hyperlegible-next-latin-ext.woff2') format('woff2');unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF}
@font-face{font-family:'Atkinson Hyperlegible Next';font-style:normal;font-weight:200 800;font-display:swap;src:url('fonts/atkinson-hyperlegible-next-latin.woff2') format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
@font-face{font-family:'JetBrains Mono';font-style:normal;font-weight:100 800;font-display:swap;src:url('fonts/jetbrains-mono-vietnamese.woff2') format('woff2');unicode-range:U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB}
@font-face{font-family:'JetBrains Mono';font-style:normal;font-weight:100 800;font-display:swap;src:url('fonts/jetbrains-mono-latin-ext.woff2') format('woff2');unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF}
@font-face{font-family:'JetBrains Mono';font-style:normal;font-weight:100 800;font-display:swap;src:url('fonts/jetbrains-mono-latin.woff2') format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}

:root{
  /* Native-widget scheme: without this the browser renders select POPUPS, scrollbars and
     spinners in its default LIGHT scheme even on the dark site (styling the closed <select>
     never reaches the popup list — it follows color-scheme, not CSS). */
  color-scheme:dark;
  /* fonts */
  --font-display:'Crimson Pro',Georgia,serif;
  --font-body:'Atkinson Hyperlegible Next',system-ui,sans-serif;
  --font-mono:'JetBrains Mono',ui-monospace,monospace;
  /* weight scale — use deliberately: body 400, labels/meta 500, section titles 600, page & brand 700 */
  --fw-normal:400;--fw-medium:500;--fw-semibold:600;--fw-bold:700;

  /* core surfaces & text */
  --bg:#0f1411;--panel:#1a221c;--panel2:#151c17;--line:#2b3830;--line2:#3c4e43;
  --ink:#d2dad4;--ink-strong:#e7ede8;--dim:#9fb0a4;--faint:#7c8d83;
  --acc:#5fd39a;--acc2:#8fb6a4;--gold:#d9b24a;--warn:#e0a85f;
  --bg-grad-top:#16211a;--header-bg:rgba(15,20,17,.92);
  --shadow:rgba(0,0,0,.5);--shadow-strong:rgba(0,0,0,.6);
  --hover:#28332b;--surface:#232d26;--inset:#0a0e0b;--img-bg:#0a0e0b;
  --row-hover:rgba(95,211,154,.06);--on-acc:#062012;--on-gold:#241c07;
  --like:#e0705f;--badge-bg:rgba(8,11,9,.85);--cls-l:70%;--rare:#ff8a8a;

  /* accent-tinted surfaces */
  --acc-bg:#11201a;--acc-glow:rgba(95,211,154,.4);--gold-glow:rgba(217,178,74,.35);
  --chip-on-bg:#1c3f30;--chip-on-ink:#dfffe8;

  /* gold substat family */
  --gold-bg:#15120a;--gold-line:#4a3d1c;--gold-bg2:#221c0c;

  /* chaos (purple) substat family */
  --chaos-bg:#140f1e;--chaos-line:#6b46a8;--chaos-line2:#9a6cf0;--chaos-ink:#c9a6ff;

  /* artifact (slate) family — distinct from the purple chaos-substat + unique-item families */
  --arti-bg:#10141d;--arti-line:#2d3650;--arti-pic-bg:#171d29;--arti-pic-line:#333d59;
  --uniq-bg:#3a2a4f;--uniq-ink:#d0b0ff;

  /* danger / destructive */
  --danger:#e0705f;--danger-ink:#ff9a9a;--danger-bg:#2a1414;--danger-line:#5a2a2a;
  --danger-bg2:#3a1c1c;--danger-line2:#7a3535;--danger-armed-bg:#a02828;--danger-armed-line:#c23636;

  /* hp / category badges */
  --boss-bg:#5a2a2a;--boss-ink:#ffb0b0;
  --hb-red-bg:#5a2a2a;--hb-red-ink:#ffb0b0;--hb-grn-bg:#264a3a;--hb-grn-ink:#9fe0c0;
  --hb-blu-bg:#26324f;--hb-blu-ink:#a8c4ff;

  /* toast + 3D viewer */
  --toast-bg:#1b2a20;--toast-ink:#eafff0;--viz-bg-top:#16221b;--viz-bg-bot:#0a0e0b;

  /* on-image overlays & worldmap — intentionally theme-independent (sit over art) */
  --on-image:#fff;--on-image-dim:rgba(255,255,255,.82);--on-image-shadow:#000;
  --wtile-border:rgba(90,130,210,.35);--wtile-bg:rgba(0,0,0,.14);--wtile-hover:rgba(255,255,255,.34);
  --wboss:#ffc04d;--mapcap-grad:rgba(11,15,12,.85);--map-edge:#5fd39a;

  /* Field Codex reskin tokens — sharp radii, spine accent, hairline rules, mono labels, HUD chrome */
  --radius-base:4px;      /* chips, small controls */
  --radius-module:6px;    /* sections, inputs, framed art */
  --radius-icon:9px;      /* icon tiles */
  --spine-w:2px;          /* the signature accent bar */
  --rule:var(--line);     /* hairline separator */
  --focus-glow:0 0 0 3px rgba(95,211,154,.20);
  --hud-bg:rgba(12,16,13,.86);
  --mono-label:600 10.5px/1 var(--font-mono);
}

:root[data-theme="light"]{
  color-scheme:light;
  --bg:#e8efe4;--panel:#f9fbf7;--panel2:#eef4eb;--line:#d0dccb;--line2:#bccdb6;
  --ink:#2f3a33;--ink-strong:#263129;--dim:#4f5e55;--faint:#6a776d;
  --acc:#0d7a4d;--acc2:#2c6e4a;--gold:#7d5f0e;--warn:#a85f12;
  --bg-grad-top:#dfe9db;--header-bg:rgba(232,239,228,.9);
  --shadow:rgba(31,50,40,.15);--shadow-strong:rgba(31,50,40,.22);
  --hover:#dfe8db;--surface:#e5ede2;--inset:#eef3ea;--img-bg:#dfe7dc;
  --row-hover:rgba(31,158,99,.10);--on-acc:#ffffff;--on-gold:#fff7e0;
  --like:#c0392b;--badge-bg:rgba(255,255,255,.86);--cls-l:34%;--rare:#c0392b;

  --acc-bg:#cdeeda;--acc-glow:rgba(21,122,74,.30);--gold-glow:rgba(138,106,16,.30);
  --chip-on-bg:#cdeeda;--chip-on-ink:#14532d;

  --gold-bg:#f5ecd0;--gold-line:#d8c48a;--gold-bg2:#ecdfb8;

  --chaos-bg:#efe6fb;--chaos-line:#b39ddb;--chaos-line2:#7a4fd0;--chaos-ink:#5b3a9e;

  --arti-bg:#e9edf3;--arti-line:#c6cede;--arti-pic-bg:#dfe4ee;--arti-pic-line:#c9d0df;
  --uniq-bg:#e6d9f7;--uniq-ink:#6b3fa0;

  --danger:#c0392b;--danger-ink:#b3261e;--danger-bg:#fbe6e4;--danger-line:#e2b3ae;
  --danger-bg2:#f6d8d4;--danger-line2:#d89b93;--danger-armed-bg:#c0392b;--danger-armed-line:#a02020;

  --boss-bg:#f7dcd8;--boss-ink:#9a2020;
  --hb-red-bg:#f7dcd8;--hb-red-ink:#9a2020;--hb-grn-bg:#cdeeda;--hb-grn-ink:#14532d;
  --hb-blu-bg:#d6e0f5;--hb-blu-ink:#28407a;

  --toast-bg:#1c2620;--toast-ink:#eafff0;--viz-bg-top:#e8efe4;--viz-bg-bot:#d2dccd;

  /* Field Codex reskin overrides */
  --focus-glow:0 0 0 3px rgba(21,122,74,.20);
  --hud-bg:rgba(255,255,255,.88);
}

/* shared theme toggle button (sun/moon), far-right in every header */
.tgl{flex:none;background:var(--panel2);border:1px solid var(--line2);color:var(--ink);border-radius:8px;width:32px;height:32px;font-size:15px;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:border-color .15s,color .15s}
.tgl:hover{border-color:var(--acc);color:var(--acc)}

/* CLS reservations for JS-filled header chrome (#130).
   .svnav, .svsupport and the auth widget span all ship EMPTY in page markup and are filled by
   chrome.js / auth.js at DOMContentLoaded. Until then the header was short by their combined width,
   so on a <=700px header the arriving chrome wrapped onto a second row and pushed the entire page
   down 41px: 0.25 CLS on /simulator mobile, and it hit every page that renders this header.
   These rules live here, NOT in chrome.js's injected CSS, because theme.css is a render-blocking
   <link> and so is the only shared sheet that can reserve anything at FIRST paint -- module CSS
   arrives with the module, i.e. at the same moment as the content it would have reserved for.
   Values are the measured rendered control boxes; a stale cached theme.css just loses the
   reservation (degrades to the old shift, never to a broken header). verify.mjs [header reserve]. */
.svnav{min-width:58px;min-height:33px}
.svsupport{min-width:38px;min-height:30px}
#authWidget:empty,.wl-authmount:empty{display:inline-block;min-width:83px;min-height:34px}
@media(min-width:641px){.svsupport{min-width:92px;min-height:36px}}
/* Same reservation problem, opposite direction: at <=640px chrome.js's collapseUtils() MOVES
   #themeToggle out of the header and into the site menu, leaving a zero-width comment marker -- so the
   FINAL mobile header has no toggle in it. Painting it and removing it later shrank the header by a row
   and pulled the whole page UP 40px. Hide it up front so first paint matches the settled layout.
   Direct-child selector on purpose: once moved the toggle lives in .svnav-util-row (still inside the
   header) and must stay visible there. Id-level specificity so a page's own #themeToggle rule can't
   silently re-show it. Breakpoint must match chrome.js's utilMQ -- verify.mjs [header reserve]. */
@media(max-width:640px){header>#themeToggle{display:none}}

/* live twitch streamers widget — shared header component (markup: .livewrap#liveWrap, logic: live.js).
   Anchor defaults to the right edge; add .lw-left to .livewrap when the button sits on the header's left. */
.livewrap{position:relative;flex:none}
.livewrap[hidden]{display:none}
.livebtn{display:inline-flex;align-items:center;gap:6px;padding:7px 10px;border:1px solid var(--line2);background:var(--panel2);color:var(--ink);border-radius:9px;font:inherit;font-size:12px;font-weight:800;letter-spacing:.03em;text-transform:uppercase;cursor:pointer;transition:border-color .15s}
.livebtn:hover{border-color:#e0484d}
.livedot{width:8px;height:8px;border-radius:50%;background:#e0484d;flex:none;animation:livepulse 1.8s ease-out infinite}
@keyframes livepulse{0%{box-shadow:0 0 0 0 rgba(224,72,77,.55)}70%{box-shadow:0 0 0 7px rgba(224,72,77,0)}100%{box-shadow:0 0 0 0 rgba(224,72,77,0)}}
@media(prefers-reduced-motion:reduce){.livedot{animation:none}}
.livecount{font-family:var(--font-mono);font-size:11px;color:var(--faint);font-weight:700}
.livepop{position:absolute;top:calc(100% + 6px);right:0;width:340px;max-width:86vw;max-height:70vh;overflow:auto;background:var(--panel);border:1px solid var(--line2);border-radius:12px;box-shadow:0 14px 34px var(--shadow);padding:6px;display:none;z-index:60}
.livepop.on{display:block}
.livepop .livehd{padding:8px 9px 6px;color:var(--faint);font-size:10.5px;font-weight:700;text-transform:uppercase;letter-spacing:.06em}
.liverow{display:flex;gap:10px;padding:8px;border-radius:10px;color:var(--ink);text-decoration:none;align-items:flex-start}
.liverow:hover{background:var(--hover);text-decoration:none}
.liverow.feat{background:var(--chip-on-bg)}
.livethumb{width:96px;height:54px;border-radius:7px;overflow:hidden;flex:none;background:var(--img-bg);border:1px solid var(--line2)}
.livethumb img{width:100%;height:100%;object-fit:cover;display:block}
.livemeta{min-width:0;display:flex;flex-direction:column;gap:2px}
.livename{font-weight:700;font-size:13px;color:var(--ink-strong);display:flex;align-items:center;gap:6px;min-width:0}
.livename .nm{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.livefeat{flex:none;font-size:9px;font-weight:800;text-transform:uppercase;letter-spacing:.05em;color:var(--gold);border:1px solid var(--gold);border-radius:5px;padding:1px 4px}
.livetitle{font-size:11.5px;color:var(--dim);line-height:1.35;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.liveviewers{font-size:11px;color:#e0484d;font-weight:700;font-family:var(--font-mono)}
.liveempty{padding:14px 12px;color:var(--faint);font-size:12.5px;text-align:center}

/* ---- shared components (promoted from per-page copies, #105 P2-3) ----
   Base rules only; pages keep overrides. NOT for: index.html .card (list tile),
   minigame.html .card (playing card), minigame/training .btn (game HUD buttons) —
   same class names, different components; those pages pin the conflicting props. */

/* app button — simulator/guild/account consensus (effective radius comes from field-codex) */
.btn{font:inherit;padding:8px 13px;border:1px solid var(--line2);background:var(--surface);color:var(--ink);border-radius:var(--radius-module);cursor:pointer;text-decoration:none}
.btn:hover{border-color:var(--acc)}
.btn:disabled{opacity:.5;cursor:default}

/* module section card + header (simulator/guild/refine family) */
.card{background:var(--panel);border:1px solid var(--line);border-radius:14px;padding:16px;margin-bottom:18px}
.card h2{font-family:var(--font-display);font-weight:var(--fw-semibold);font-size:13px;letter-spacing:.08em;text-transform:uppercase;color:var(--acc2);margin:0 0 14px;padding-bottom:9px;border-bottom:1px solid var(--line);display:flex;justify-content:space-between;align-items:baseline;gap:10px}
.card h2 .tiny{font-family:var(--font-body);font-size:11px;letter-spacing:0;text-transform:none;color:var(--faint);font-weight:400}

/* small info tag (wiki item pages; arcade genre chips adopt it) */
.tag{display:inline-block;font-size:11px;font-weight:600;padding:2px 9px;border-radius:var(--radius-base);background:var(--panel2);border:0;color:var(--dim);margin:3px 5px 0 0}
.tag.uniq{background:var(--uniq-bg);color:var(--uniq-ink);font-weight:700}

/* modal skeleton — overlay scrim + centered dialog (guild's copy promoted; open with .on) */
.ov{position:fixed;inset:0;background:rgba(0,0,0,.66);display:none;z-index:50;align-items:flex-start;justify-content:center;padding:40px 16px;overflow:auto}
.ov.on{display:flex}
.modal{background:var(--panel);border:1px solid var(--line2);border-radius:14px;max-width:640px;width:100%;padding:18px}
.modal h3{font-family:var(--font-display);color:var(--ink-strong);margin:0 0 6px;font-size:16px}

/* select popup options — brand colors where the engine honors option styling (Chromium does
   once color-scheme matches; the :root color-scheme declarations above are the load-bearing fix) */
select option{background:var(--panel);color:var(--ink)}

/* global "Search everything" bar — the shared look of the SVSearch/SVWikiDB component.
   The MARKUP (#gsearch > #gsi + #gres) and the behaviour are already shared (search.js owns the
   keyboard/ARIA shell, wiki-db.js owns the rows); only these rules were copy-pasted, once per
   hosting page, and had already drifted a pixel apart. Golden rule 5: one definition here.
   Pages keep the LAYOUT of #gsearch (a 420px header slot on the wiki, a centered block on the
   404 lander) — that genuinely differs per page; the field and the dropdown do not. */
#gsearch{position:relative}
#gsearch input{width:100%;background:var(--panel2);border:1px solid var(--line2);color:var(--ink);border-radius:9px;padding:9px 12px;font:inherit}
#gsearch input:focus{outline:none;border-color:var(--acc)}
#gres{position:absolute;top:44px;left:0;right:0;background:var(--panel);border:1px solid var(--line2);border-radius:10px;max-height:60vh;overflow:auto;display:none;z-index:30;box-shadow:0 12px 30px var(--shadow)}
#gres.on{display:block}
#gres .r{display:flex;align-items:center;gap:9px;padding:8px 12px;cursor:pointer;border-bottom:1px solid var(--line);font-size:13px;color:var(--ink)}
#gres .r:hover{background:var(--hover)}
#gres .r .cat{margin-left:auto;font-size:10px;color:var(--faint);text-transform:uppercase;letter-spacing:.05em}

/* substat rolled-value editor (SVSubstats subsHtml `editValues`) — ONE definition for every page
   that renders the picker: the build simulator, the auction house and the guild board. It used to
   live only in market.html, so shipping inline values in the simulator would have meant a second
   copy (golden rule 5). Pages keep their own .subs container/select rules; only the value row is
   shared. `.over` = the value sits above the substat's natural maximum roll, which only an Essence
   of Chaos multiply can do — the game paints those gold, and so do we. Our whole substat vocabulary
   is already gold-on-gold, so the marker leans on full-strength --gold + weight + a glow ring rather
   than hue alone. Colour ONLY — no glyph: an extra element in the picker row shifts the flex layout
   and adds noise to a card that is already a wall of numbers. */
.subs .srow{display:flex;gap:5px;align-items:center;flex-basis:100%;width:100%}
.subs .srow select{flex:1 1 auto;min-width:0;max-width:none}
.subs input.subval{width:52px;flex:none;font-family:var(--font-mono);font-size:11px;padding:3px 5px;text-align:right;background:var(--surface);border:1px solid var(--line2);border-radius:5px;color:var(--ink);appearance:textfield;-moz-appearance:textfield}
.subs input.subval::-webkit-outer-spin-button,.subs input.subval::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}
.subs input.subval:focus{border-color:var(--gold-line)}
.subs input.subval[readonly]{color:var(--chaos-ink);border-color:var(--chaos-bg);background:var(--chaos-bg)}
.subs .subrange{flex:none;min-width:38px;color:var(--faint);font-family:var(--font-mono);font-size:9.5px;white-space:nowrap}
.subs input.subval.over{color:var(--gold);font-weight:700;border-color:var(--gold);background:var(--gold-bg2);box-shadow:0 0 0 1px var(--gold-glow)}
.subs .subrange.over{color:var(--gold)}
.subsum .over,.subs-line .over{color:var(--gold);font-weight:700;font-style:normal}
/* …and on the slot card's FUSED stat line (simulator .slotstats): mergeSlot ORs the flag up from the
   contributing substat, so the line the player actually reads carries the same gold the game shows.
   Outranks the page's own `.slotstats .sv{color:var(--acc2)}` on specificity, not order. */
.slotstats .sl.over,.slotstats .sv.over{color:var(--gold);font-weight:700}

/* ---- per-class hue plate (#137, generalised for #167) ----
   The canonical treatment for showing a CLASS icon anywhere: a plate tinted by
   SVComponents.hue(className), DARK in both themes. That last part is the whole point and is not a
   style preference — class art is a black line drawing with an OPAQUE WHITE FILL, so on a dark tile
   the fill reads as the glyph, while on a light tile the glyph disappears into the background. The
   white silhouettes on a pale tile were the actual bug in #137; do not "fix" this to follow the
   theme. Prior copies of these exact declarations live in builds.html (.cico/.dico) and index.html
   (.fbico/.clico) and should migrate here.
   Used by the monster fallback: the Umbral/Echo monsters are shadow copies of the player classes
   and have no monster art of their own (it is assembled at runtime, so it cannot be extracted), so
   the class plate IS their honest identity rather than a stand-in. */
.svhue{background:hsl(var(--h,150) 40% 14%);border-color:hsl(var(--h,150) 45% 32%);color:hsl(var(--h,150) 60% 74%)}
/* Nested form: iconHTML()/monThumb() return markup that a caller drops into its own sized box
   (.ic/.mth/.pgci/…), so the plate fills that box and inherits its rounding. `contain`, not the
   containers' usual `cover`: a glyph must never be cropped. */
.svhue.svhuefill{display:block;width:100%;height:100%;border-radius:inherit;box-sizing:border-box}
.svhue>img{width:100%;height:100%;object-fit:contain;padding:2px;box-sizing:border-box;display:block}
