:root{
  /* surfaces — elevation by lightness, dark→light */
  --bg:#0d1117; --surface:#161b22; --raised:#1c2330; --overlay:#232b3a;
  --scrim:rgba(5,8,12,.82);
  /* borders */
  --border:#2a3342; --border-strong:#3a465c;
  /* text — three tiers + non-text glyph tier */
  --text:#e6edf3; --text-2:#c3ccd8; --muted:#8b98a9; --faint:#5f6d80;
  --ink:#0d1117; /* text on solid accent / colored chips */
  /* accent + semantic roles (desaturated ~20%; all ≥6.2:1 on any surface) */
  --accent:#58b6ea; --accent-hover:#6fc1ee;
  --success:#7fd49e; --gold:#d9b25c; --danger:#ef8fb8;
  --male:#6aa8f0; --female:#e0708f;
  /* tint recipe: each semantic color gets exactly two alphas */
  --accent-tint:rgba(88,182,234,.08); --accent-line:rgba(88,182,234,.35);
  --success-tint:rgba(127,212,158,.08); --success-line:rgba(127,212,158,.35);
  --gold-tint:rgba(217,178,92,.08); --gold-line:rgba(217,178,92,.35);
  --danger-tint:rgba(239,143,184,.08); --danger-line:rgba(239,143,184,.35);
  /* element colors — data-viz identity, used as chip bg with --ink text */
  --neutral:#9aa5b1; --fire:#ff8a5c; --water:#5cb3ff; --electric:#ffd75c;
  --grass:#7ed67e; --dark:#b78aff; --dragon:#8f7dff; --ground:#d9a066; --ice:#7fe3e3;
  /* type — 7 sizes; heading jumps 15→19→24 (≥1.26×) */
  --fs-xs:11px; --fs-sm:12.5px; --fs-md:14px; --fs-base:15px;
  --fs-lg:17px; --fs-h2:19px; --fs-h1:24px;
  /* space — 4px base */
  --sp-1:4px; --sp-2:8px; --sp-3:12px; --sp-4:16px; --sp-5:20px; --sp-6:24px; --sp-7:32px;
  /* radius */
  --r-sm:6px; --r-md:10px; --r-lg:14px; --r-xl:18px; --r-full:999px;
  /* motion */
  --t-fast:120ms; --t-base:180ms; --ease-out:cubic-bezier(.2,.7,.3,1);
  /* render native UI (checkboxes, select dropdowns, scrollbars, search-clear
     buttons, autofill) in the browser's dark theme instead of light defaults */
  color-scheme:dark;
}
*{box-sizing:border-box;margin:0;padding:0;-webkit-tap-highlight-color:transparent}
::selection{background:rgba(88,182,234,.35);color:var(--text)}
::placeholder{color:var(--muted);opacity:1}
select option{background:var(--surface);color:var(--text)}
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.01ms!important;transition-duration:.01ms!important}
}
button:focus-visible,a:focus-visible,input:focus-visible,select:focus-visible,summary:focus-visible,[tabindex]:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.skip{position:absolute;left:-9999px;top:0;z-index:400;background:var(--accent);color:var(--ink);padding:10px 20px;border-radius:0 0 12px 0;font-weight:700;text-decoration:none}
.skip:focus{left:0}
html{scrollbar-color:var(--border-strong) var(--surface);-webkit-text-size-adjust:100%;text-size-adjust:100%}
/* strip the native inset search styling (iOS) so inputs match the theme;
   Chrome keeps its clear button, which color-scheme renders dark */
input[type="search"]{-webkit-appearance:none;appearance:none}
body{background:var(--bg);color:var(--text);font:var(--fs-base)/1.5 "Segoe UI",system-ui,sans-serif;min-height:100vh;min-height:100dvh}
button{font:inherit;color:inherit;background:none;border:none;cursor:pointer;
  transition:color var(--t-fast),border-color var(--t-fast),background-color var(--t-fast),transform var(--t-fast),box-shadow var(--t-fast)}
button:not(:disabled):active{transform:translateY(1px)}
button:disabled{opacity:.45;cursor:default}
input{font:inherit;color:inherit}
header{position:sticky;top:0;z-index:50;background:rgba(13,17,23,.92);backdrop-filter:blur(8px);border-bottom:1px solid var(--border)}
.hwrap{max-width:1200px;margin:0 auto;padding:12px 20px;display:flex;align-items:center;gap:16px;flex-wrap:wrap}
/* The wordmark is artwork, not text — outlined to paths so it needs no webfont
   and looks identical everywhere. Kept inside the h1 so the page still has a
   heading, and it's a real link so ctrl/middle-click opens a new tab (the JS
   handler only intercepts plain clicks). */
.logo{font-size:0;line-height:0}
.logo a{display:inline-block;border-radius:var(--r-sm)}
.logo img{display:block;height:31px;width:auto;transition:opacity var(--t-fast)}
.logo a:hover img{opacity:.82}
@media(max-width:640px){.logo img{height:26px}}
@media(max-width:360px){.logo img{height:23px}}
.tabs{display:flex;gap:4px;background:var(--surface);border:1px solid var(--border);border-radius:var(--r-md);padding:4px;align-items:center}
.tabs button{padding:7px 14px;border-radius:var(--r-sm);color:var(--muted);font-weight:600;font-size:var(--fs-md)}
.tabs button.active{background:var(--raised);color:var(--text);box-shadow:inset 0 0 0 1px var(--border-strong)}
.tabs button:hover:not(.active){color:var(--text)}
.tabs .sep{width:1px;align-self:stretch;background:var(--border);margin:3px 2px;flex-shrink:0}
.ghlink{margin-left:auto;display:flex;align-items:center;gap:7px;color:var(--muted);text-decoration:none;font-size:var(--fs-md);font-weight:600;padding:6px 12px;border:1px solid var(--border);border-radius:var(--r-md);transition:color var(--t-fast),border-color var(--t-fast)}
.ghlink:hover{color:var(--text);border-color:var(--border-strong)}
@media(max-width:720px){
  .ghlink span{display:none}
  .hwrap{flex-wrap:nowrap;gap:10px;padding:10px 12px}
  .logo{flex-shrink:0}
  .ghlink{flex-shrink:0;padding:6px 8px}
  .tabs{overflow-x:auto;flex-wrap:nowrap;max-width:100%;scrollbar-width:none;-webkit-overflow-scrolling:touch;
    -webkit-mask-image:linear-gradient(90deg,var(--eL,#000),#000 26px,#000 calc(100% - 26px),var(--eR,#000));
    mask-image:linear-gradient(90deg,var(--eL,#000),#000 26px,#000 calc(100% - 26px),var(--eR,#000))}
  .tabs.fadeL{--eL:transparent}
  .tabs.fadeR{--eR:transparent}
  .tabs::-webkit-scrollbar{display:none}
  .tabs button{white-space:nowrap;flex-shrink:0;padding:7px 12px}
}
/* first-run setup checklist (replaces the old prose tipbar) */
.setup{display:flex;align-items:center;gap:10px;flex-wrap:wrap;background:var(--accent-tint);border:1px solid var(--accent-line);border-radius:var(--r-lg);padding:10px 14px;font-size:var(--fs-md);margin-bottom:20px}
.setup[hidden]{display:none}
.setup .lb{font-weight:700}
.setup .step{display:inline-flex;align-items:center;gap:6px;background:var(--surface);border:1px solid var(--border);border-radius:var(--r-full);padding:6px 14px;font-size:var(--fs-sm);font-weight:600;color:var(--muted)}
.setup .step:hover{color:var(--text);border-color:var(--border-strong)}
.setup .step.done{color:var(--success);border-color:var(--success-line)}
.setup .dismiss{margin:-5px -6px -5px auto;color:var(--muted);font-size:var(--fs-base);padding:10px 12px;border-radius:var(--r-sm);flex-shrink:0}
.setup .dismiss:hover{color:var(--text);background:var(--surface)}
.viewsub{color:var(--muted);font-size:var(--fs-md);margin-bottom:14px}
main{max-width:1200px;margin:0 auto;padding:28px 20px 80px}
@media(max-width:640px){main{padding:18px 12px 60px}}
.hint{color:var(--muted);text-align:center;padding:40px 0;font-size:var(--fs-base)}
.view{display:none}.view.active{display:block}

/* ---------- bottom tab bar (thumb zone, ≤640px) ---------- */
.bottomnav{display:none}
.moresheet{display:none}
@media(max-width:640px){
  .tabs{display:none}
  .bottomnav{position:fixed;left:0;right:0;bottom:0;z-index:90;display:flex;background:rgba(13,17,23,.94);backdrop-filter:blur(8px);border-top:1px solid var(--border);padding-bottom:env(safe-area-inset-bottom)}
  .bottomnav button{flex:1;display:flex;flex-direction:column;align-items:center;gap:2px;padding:8px 4px 10px;font-size:var(--fs-xs);font-weight:600;color:var(--muted);border-radius:0}
  .bottomnav button .bi{font-size:18px;line-height:1}
  .bottomnav button.active{color:var(--accent)}
  .moresheet.open{display:flex}
  .moresheet{position:fixed;right:8px;bottom:calc(64px + env(safe-area-inset-bottom));z-index:95;flex-direction:column;min-width:190px;background:var(--overlay);border:1px solid var(--border-strong);border-radius:var(--r-lg);box-shadow:0 12px 40px rgba(0,0,0,.5);overflow:hidden}
  .moresheet button{text-align:left;padding:12px 16px;font-size:var(--fs-md);font-weight:600;color:var(--muted)}
  .moresheet button:hover{color:var(--text);background:var(--raised)}
  .moresheet button.active{color:var(--text);background:var(--raised)}
  main{padding:18px 12px calc(88px + env(safe-area-inset-bottom))}
  /* .toasts and footer also have to clear the nav, but their base rules are
     declared further down the file and would win this tie — those two live in
     the phone block at the end instead */
}

/* ---------- picker ---------- */
.picker{position:relative;flex:1;min-width:230px;max-width:340px}
.picker-btn{width:100%;display:flex;align-items:center;gap:12px;background:var(--surface);border:1px solid var(--border);border-radius:var(--r-lg);padding:10px 14px;text-align:left}
.picker-btn:hover{border-color:var(--border-strong)}
.picker.open .picker-btn{border-color:var(--accent)}
.picker-btn.invalid{border-color:var(--danger)}
.picker-btn .ph{color:var(--muted)}
.picker-btn .sel{display:flex;align-items:center;gap:12px;min-width:0}
.picker-btn .sel .nm{font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.picker-btn .sel .zk{color:var(--muted);font-size:var(--fs-sm)}
.picker-btn .clear{margin-left:auto;color:var(--muted);font-size:16px;padding:2px 6px;border-radius:var(--r-sm);flex-shrink:0}
.picker-btn .clear:hover{background:var(--raised);color:var(--text)}
.picker-btn .caret{margin-left:auto;color:var(--muted);flex-shrink:0}
.pop{position:absolute;top:calc(100% + 6px);left:0;width:min(340px,calc(100vw - 24px));z-index:60;background:var(--overlay);border:1px solid var(--border-strong);border-radius:var(--r-lg);box-shadow:0 12px 40px rgba(0,0,0,.5);overflow:hidden;display:none}
.pop.flip{left:auto;right:0}
/* opens upward when the trigger sits too close to the bottom nav (see fitPopup) */
.pop.up,.ptag .tpop.up{top:auto;bottom:calc(100% + 6px)}
.picker.open .pop{display:block}
.pop input{width:100%;background:var(--raised);border:none;border-bottom:1px solid var(--border);padding:10px 14px;outline:none}
.pop .list{max-height:340px;overflow-y:auto;overscroll-behavior:contain}
.pop .row{display:flex;align-items:center;gap:11px;width:100%;padding:7px 12px;text-align:left}
.pop .row:hover,.pop .row.hl{background:var(--raised)}
.pop .row .nm{font-weight:600;font-size:var(--fs-md)}
.pop .row .zk{color:var(--muted);font-size:var(--fs-sm)}
.pop .row .own{color:var(--gold);font-size:var(--fs-sm)}
.pop .row .types{margin-left:auto;display:flex;gap:4px}
.pop .empty{padding:16px;color:var(--muted);text-align:center;font-size:var(--fs-md)}
.pop .lgroup{padding:8px 12px 3px;font-size:var(--fs-xs);font-weight:700;letter-spacing:.6px;text-transform:uppercase;color:var(--muted)}
@media(max-width:640px){
  .pop .list{display:grid;grid-template-columns:repeat(4,1fr)}
  .pop .lgroup{grid-column:1/-1}
  .pop .row{flex-direction:column;gap:4px;padding:9px 4px;align-items:center}
  .pop .row .pico{width:44px;height:44px}
  .pop .row .zk,.pop .row .types{display:none}
  .pop .row .nm{font-size:var(--fs-xs);white-space:normal;text-align:center;line-height:1.15;word-break:break-word}
}

/* ---------- pal icon / chips ---------- */
.pico{border-radius:50%;background:var(--raised);flex-shrink:0;object-fit:cover;border:2px solid var(--border-strong)}
.pico.f{display:flex;align-items:center;justify-content:center;font-weight:700;color:var(--muted)}
.pico.click{cursor:pointer;transition:border-color var(--t-fast)}
.pico.click:hover{border-color:var(--border-strong)}
.dot{width:9px;height:9px;border-radius:50%;display:inline-block;flex-shrink:0}
.types{display:inline-flex;align-items:center;gap:3px}
.chip{font-size:var(--fs-xs);font-weight:700;padding:2px 9px 2px 6px;border-radius:var(--r-full);color:var(--ink);text-transform:capitalize;
  display:inline-flex;align-items:center;gap:3px}
/* Game UI icons, extracted from the paks. .uii is the shared base: never let
   one stretch a flex row, and never let a missing file reserve empty space. */
.uii{display:inline-block;flex-shrink:0;vertical-align:-2px}
/* The element icon is element-coloured and so is its chip, so it's knocked
   down to the chip's ink colour instead of vanishing into the background. */
.chip .uii{filter:brightness(0);opacity:.82;vertical-align:0}
.works span .uii{vertical-align:-3px;margin-right:5px}
.mchip .uii{vertical-align:0}
.tworks .uii{vertical-align:-3px;margin-right:1px}
.mchip.drop{padding-left:5px}
.mchip{font-size:var(--fs-sm);font-weight:600;padding:2px 10px;border-radius:var(--r-full);background:var(--bg);border:1px solid var(--border-strong);color:var(--muted);
  display:inline-flex;align-items:center;gap:6px}
.tier{font-size:var(--fs-xs);font-weight:700;letter-spacing:.4px;padding:1px 8px;border-radius:var(--r-sm);text-transform:uppercase}
.tier.common{background:rgba(154,165,177,.14);color:var(--neutral)}
.tier.rare{background:rgba(92,179,255,.14);color:var(--water)}
.tier.epic{background:rgba(183,138,255,.14);color:var(--dark)}
.tier.legendary{background:var(--gold-tint);color:var(--gold)}

/* ---------- breed view ---------- */
.parents{display:flex;align-items:flex-end;justify-content:center;gap:14px;flex-wrap:wrap;margin-bottom:8px}
.pwrap{flex:1;min-width:230px;max-width:340px}
.pwrap .picker{max-width:none;min-width:0}
.op{font-size:22px;color:var(--muted);font-weight:400;padding-bottom:9px}
/* stacked layout: the decorative × wraps to the row edge and reads as a close button */
@media(max-width:640px){.op{display:none}}
.swap{background:var(--surface);border:1px solid var(--border);border-radius:var(--r-md);padding:8px 12px;color:var(--muted);font-size:var(--fs-base);margin-bottom:3px}
.swap:hover{color:var(--text);border-color:var(--border-strong)}
.result-zone{margin-top:26px;display:flex;flex-direction:column;align-items:center;gap:16px}
.child-card{width:min(560px,100%);background:linear-gradient(180deg,var(--raised),var(--surface));border:1px solid var(--border-strong);border-radius:var(--r-xl);padding:24px 28px;display:flex;gap:22px;align-items:center;animation:pop var(--t-base) var(--ease-out)}
.child-card.clickable{cursor:pointer;transition:border-color var(--t-fast),transform var(--t-fast)}
.child-card.clickable:hover{border-color:var(--border-strong);transform:translateY(-1px)}
@keyframes pop{from{transform:scale(.97);opacity:0}to{transform:scale(1);opacity:1}}
.child-card .pico{width:84px;height:84px;font-size:30px}
.child-card h2{font-size:var(--fs-h1);line-height:1.2}
.child-card .zk{color:var(--muted);font-weight:400;font-size:var(--fs-base);margin-left:6px}
.crow{display:flex;align-items:center;gap:7px;margin-top:7px;flex-wrap:wrap}
.badge{font-size:var(--fs-xs);font-weight:700;letter-spacing:.6px;padding:3px 10px;border-radius:var(--r-sm);text-transform:uppercase}
.badge.unique{background:var(--gold-tint);color:var(--gold);border:1px solid var(--gold-line)}
.badge.same{background:var(--success-tint);color:var(--success);border:1px solid var(--success-line)}
.badge.gender{background:var(--danger-tint);color:var(--danger);border:1px solid var(--danger-line)}
.gbar{display:flex;align-items:center;gap:8px;margin-top:9px;font-size:var(--fs-sm);color:var(--muted)}
.gtrack{width:130px;height:7px;border-radius:var(--r-full);background:var(--female);overflow:hidden}
.gtrack i{display:block;height:100%;background:var(--male);border-right:2px solid var(--bg)}
.works{display:flex;gap:9px;margin-top:9px;flex-wrap:wrap;font-size:var(--fs-sm);color:var(--muted)}
.works span{background:var(--bg);border:1px solid var(--border);border-radius:var(--r-sm);padding:2px 8px 2px 6px;display:inline-flex;align-items:center}
.works span.hot{border-color:var(--accent);color:var(--text)}
.mathline{color:var(--muted);font-size:var(--fs-sm);text-align:center}
.mathline b{color:var(--text);font-weight:600}
.gender-note{width:min(560px,100%);color:var(--muted);font-size:var(--fs-md);text-align:center}
.multi{display:flex;gap:16px;flex-wrap:wrap;justify-content:center;width:100%}
.multi .child-card{width:min(440px,100%)}
.gtag{font-size:var(--fs-sm);color:var(--muted);font-weight:600;margin-top:4px}
.linkrow{display:flex;gap:10px;flex-wrap:wrap;justify-content:center}
.alink{background:var(--surface);border:1px solid var(--border);border-radius:var(--r-md);padding:7px 16px;font-size:var(--fs-md);font-weight:600;color:var(--muted)}
.alink:hover{color:var(--text);border-color:var(--border-strong)}
/* the one solid primary per view */
.alink.primary{background:var(--accent);border-color:var(--accent);color:var(--ink);font-weight:700}
.alink.primary:hover{background:var(--accent-hover);border-color:var(--accent-hover);color:var(--ink)}

/* ---------- reverse view ---------- */
.controls{display:flex;gap:14px;flex-wrap:wrap;align-items:flex-end;margin-bottom:22px}
.ctl label{display:block;font-size:var(--fs-sm);font-weight:700;letter-spacing:.5px;text-transform:uppercase;color:var(--muted);margin-bottom:6px}
.search-inp{background:var(--surface);border:1px solid var(--border);border-radius:var(--r-lg);padding:10px 14px;outline:none;width:210px}
.search-inp:focus{border-color:var(--accent)}
.toggle{display:flex;align-items:center;gap:9px;background:var(--surface);border:1px solid var(--border);border-radius:var(--r-lg);padding:10px 14px;cursor:pointer;user-select:none;font-size:var(--fs-md);color:var(--muted)}
.toggle:hover:not(.on){border-color:var(--border-strong);color:var(--text)}
.toggle.on{color:var(--text);border-color:var(--accent)}
.toggle .kn{width:36px;height:20px;border-radius:var(--r-full);background:var(--raised);border:1px solid var(--border-strong);position:relative;transition:background var(--t-fast),border-color var(--t-fast);flex-shrink:0}
.toggle .kn::after{content:'';position:absolute;top:2px;left:2px;width:14px;height:14px;border-radius:50%;background:var(--muted);transition:left var(--t-fast),background var(--t-fast)}
.toggle.on .kn{background:var(--accent);border-color:var(--accent)}
.toggle.on .kn::after{left:18px;background:var(--ink)}
.rsummary{display:flex;align-items:baseline;gap:10px;margin-bottom:14px;flex-wrap:wrap}
.rsummary .cnt{font-size:var(--fs-lg);font-weight:700}
.rsummary .sub{color:var(--muted);font-size:var(--fs-md)}
.pairs{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(380px,100%),1fr));gap:10px}
@media(max-width:560px){.pairs{grid-template-columns:1fr}}
.pair{display:flex;align-items:center;gap:10px;background:var(--surface);border:1px solid var(--border);border-radius:var(--r-lg);padding:9px 14px;text-align:left}
.pair:hover{border-color:var(--border-strong)}
.pair .pside{display:flex;align-items:center;gap:9px;flex:1;min-width:0}
.pair .pside .nm{font-weight:600;font-size:var(--fs-md);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.pair .pside .g{font-size:var(--fs-md)}
.pair .own{font-size:var(--fs-sm);color:var(--gold)}
.pair .x{color:var(--muted)}
.pair .badge{margin-left:auto;flex-shrink:0}
/* ---------- unique combos ----------
   Two tiers per card: the result is the heading (these rows sort by it), the
   recipe is a muted caption. Nothing truncates — the recipe wraps instead. */
.combos{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(330px,100%),1fr));gap:10px}
.combo{display:flex;align-items:center;gap:13px;background:var(--surface);border:1px solid var(--border);border-radius:var(--r-lg);padding:11px 15px;text-align:left}
.combo:hover{border-color:var(--border-strong)}
.combo>.pico{width:40px;height:40px}
.combo .cbody{flex:1;min-width:0}
.combo .cres{display:block;font-weight:600;font-size:var(--fs-md);line-height:1.3}
.combo .crecipe{display:flex;align-items:center;gap:7px;flex-wrap:wrap;margin-top:4px;font-size:var(--fs-sm);color:var(--muted)}
.combo .cp{display:inline-flex;align-items:center;gap:5px}
.combo .cp .pico{width:20px;height:20px;border-width:1px}
.combo .cx{color:var(--faint)}
.combo .cself{font-style:italic;color:var(--faint)}
.more{margin:22px auto 0;display:block;background:var(--surface);border:1px solid var(--border-strong);padding:10px 26px;border-radius:var(--r-md);font-weight:600}
.more:hover{border-color:var(--border-strong);color:var(--text)}

/* ---------- dex view ---------- */
.dex-controls{display:flex;gap:12px;margin-bottom:18px;flex-wrap:wrap;align-items:center}
/* The table pans inside its own container rather than panning the page — but
   overflow-x makes .tablewrap a scrollport, and a scrollport is what a sticky
   <th> resolves against, so the column header silently stops sticking. JS adds
   .panning only when the table genuinely can't fit, keeping the sticky header
   on every screen wide enough for it. The mask marks the clipped edge. */
.tablewrap.panning{overflow-x:auto;-webkit-overflow-scrolling:touch;
  -webkit-mask-image:linear-gradient(90deg,#000,#000 calc(100% - 24px),transparent);
  mask-image:linear-gradient(90deg,#000,#000 calc(100% - 24px),transparent)}
.tablewrap.panning.atend{-webkit-mask-image:none;mask-image:none}
.dex-controls .search-inp{width:auto;flex:1;min-width:160px;max-width:300px}
.dex-controls .isel{flex:0 1 auto}
@media(max-width:640px){.dex-controls select,.dex-controls .isel{flex:1;min-width:140px}}
select{background:var(--surface);border:1px solid var(--border);border-radius:var(--r-lg);color:var(--text);padding:10px 14px;outline:none;cursor:pointer}
select:focus{border-color:var(--accent)}

/* Dropdowns that show an icon. A native <option> can't hold an image, so the
   <select> stays as the state (and the thing every listener talks to) while
   this draws over it. Sized to sit flush next to the plain selects it doesn't
   replace. */
.nativehide{position:absolute;width:1px;height:1px;opacity:0;pointer-events:none}
.isel{position:relative;display:inline-flex}
.isel-btn{display:inline-flex;align-items:center;gap:8px;width:100%;
  background:var(--surface);border:1px solid var(--border);border-radius:var(--r-lg);
  color:var(--text);padding:10px 32px 10px 14px;font-size:var(--fs-base);text-align:left;
  background-image:linear-gradient(45deg,transparent 50%,var(--muted) 50%),linear-gradient(135deg,var(--muted) 50%,transparent 50%);
  background-position:calc(100% - 17px) calc(50% + 2px),calc(100% - 12px) calc(50% + 2px);
  background-size:5px 5px,5px 5px;background-repeat:no-repeat}
.isel-btn:hover{border-color:var(--border-strong)}
.isel.open .isel-btn{border-color:var(--accent)}
.isel-pop{position:absolute;top:calc(100% + 4px);left:0;min-width:100%;max-height:320px;overflow-y:auto;
  z-index:60;display:none;flex-direction:column;background:var(--overlay);
  border:1px solid var(--border-strong);border-radius:var(--r-md);
  box-shadow:0 14px 40px rgba(0,0,0,.55);padding:4px}
.isel.open .isel-pop{display:flex}
.isel-row{display:flex;align-items:center;gap:9px;padding:8px 12px;border-radius:var(--r-sm);
  font-size:var(--fs-md);color:var(--text-2);cursor:pointer;white-space:nowrap}
.isel-row:hover{background:var(--raised);color:var(--text)}
.isel-row.on{background:var(--accent-tint);color:var(--text);font-weight:600}
table{width:100%;border-collapse:collapse}
th{position:sticky;top:var(--hh,64px);background:var(--bg);text-align:left;font-size:var(--fs-sm);letter-spacing:.5px;text-transform:uppercase;color:var(--muted);padding:8px 12px;border-bottom:1px solid var(--border-strong);cursor:pointer;user-select:none;white-space:nowrap;z-index:5}
th:hover{color:var(--text)}
th .arr{color:var(--accent)}
.thbtn{font:inherit;color:inherit;letter-spacing:inherit;text-transform:inherit;cursor:pointer;padding:0}
td{padding:7px 12px;border-bottom:1px solid var(--border);font-size:var(--fs-md)}
tbody tr{cursor:pointer}
tbody tr:hover{background:var(--surface)}
.tname{display:flex;align-items:center;gap:11px;font-weight:600}
.tworks{color:var(--muted);font-size:var(--fs-sm)}
/* inline where there's room, dropping to its own line in the narrow mobile
   column — nowrap keeps it from breaking into "unique" / "only" */
.uq{color:var(--muted);font-size:var(--fs-xs);white-space:nowrap;margin-left:5px}
.tworks b{color:var(--accent);font-weight:700}
.star{font-size:var(--fs-lg);color:var(--faint);padding:10px 11px;margin:-8px -5px;border-radius:var(--r-sm);line-height:1}
.star.on{color:var(--gold)}
.star:hover{background:var(--raised)}
@media(max-width:840px){
  th.hn,td.hn{display:none}
  td{padding:6px 8px}th{padding:7px 8px}
  .child-card{flex-direction:column;text-align:center;padding:20px}
  .child-card .crow,.child-card .gbar,.child-card .works{justify-content:center}
  .modal{padding:18px 16px 22px}
  .mhead{flex-direction:column;text-align:center}
  .mhead h2{justify-content:center}
  .mhead .crow{justify-content:center}
  .mbtns{justify-content:center}
}

/* ---------- modal ---------- */
.overlay{position:fixed;inset:0;z-index:100;background:var(--scrim);display:none;align-items:flex-start;justify-content:center;padding:36px 16px;overflow-y:auto}
.overlay.open{display:flex}
.modal{width:min(640px,100%);background:var(--surface);border:1px solid var(--border-strong);border-radius:var(--r-xl);padding:26px 30px 30px;position:relative;animation:pop var(--t-base) var(--ease-out);margin-bottom:36px}
.modal .close{position:absolute;top:14px;right:16px;color:var(--muted);font-size:var(--fs-h2);padding:4px 10px;border-radius:var(--r-md)}
.modal .close:hover{background:var(--raised);color:var(--text)}
.mhead{display:flex;gap:20px;align-items:center}
.mhead .pico{width:96px;height:96px;font-size:34px}
.mhead h2{font-size:var(--fs-h1);display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.mhead .zk{color:var(--muted);font-size:16px;font-weight:400}
.mdesc{margin-top:16px;color:var(--text-2);font-size:var(--fs-md);background:var(--bg);border:1px solid var(--border);border-radius:var(--r-lg);padding:12px 16px;font-style:italic}
.msec{margin-top:18px}
.msec h3{font-size:var(--fs-sm);letter-spacing:.7px;text-transform:uppercase;color:var(--accent);margin-bottom:9px;font-weight:700}
.statgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(130px,1fr));gap:8px}
.stat{background:var(--bg);border:1px solid var(--border);border-radius:var(--r-md);padding:7px 12px}
.stat .lb{font-size:var(--fs-xs);color:var(--muted)}
.stat .vl{font-weight:700;font-size:var(--fs-base)}
.pskill{background:var(--bg);border:1px solid var(--border);border-radius:var(--r-lg);padding:14px 16px}
.pskill .psn{font-weight:700;color:var(--gold);font-size:var(--fs-base)}
.pskill .pst{display:flex;gap:6px;flex-wrap:wrap;margin:7px 0}
.pskill .psd{color:var(--text-2);font-size:var(--fs-md)}
.pskill .psn .badge{margin-left:8px;vertical-align:1px}
/* The rank table can be wider than a phone card; it pans inside itself rather
   than pushing the page sideways (same deal as .tablewrap in the Paldex). */
.ranktbl{margin-top:10px;width:100%;font-size:var(--fs-sm);border-collapse:collapse}
.ranktbl caption{caption-side:top;text-align:left;color:var(--muted);font-size:var(--fs-xs);padding-bottom:4px}
.ranktbl th{position:static;background:none;padding:4px 8px;font-size:var(--fs-xs);cursor:default;white-space:nowrap}
.ranktbl thead th{color:var(--muted)}
/* row headers are effect names, not column labels — the Paldex's uppercase
   table-header treatment makes a phrase like "Extra mid-air jumps" shout */
.ranktbl tbody th{text-align:left;font-weight:600;color:var(--text-2);font-size:var(--fs-sm);
  white-space:normal;text-transform:none;letter-spacing:0}
/* who the effect lands on — Sekhmet grants work speed to the base and to
   itself, and without this the two rows read as one repeated twice */
.ranktbl .rtgt{display:block;font-weight:400;font-size:var(--fs-xs);color:var(--muted)}
.ranktbl td{padding:4px 8px;border-bottom:1px solid var(--border);text-align:right;font-variant-numeric:tabular-nums}
.ranktbl tbody th{border-bottom:1px solid var(--border)}
/* rank 5 is the one people are deciding whether to pay for */
.ranktbl td:last-child{color:var(--text);font-weight:600}
.rosentry{background:var(--bg);border:1px solid var(--border);border-radius:var(--r-lg);padding:12px 16px;display:flex;flex-direction:column;gap:8px}
.rosentry .row1{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.rosentry .row1 .g{font-size:var(--fs-base)}
.rosentry .rnote{color:var(--muted);font-size:var(--fs-sm);font-style:italic}
.mbtns{display:flex;gap:10px;margin-top:20px;flex-wrap:wrap}
.mbtns .alink{padding:9px 18px}
.droplist{display:flex;gap:8px;flex-wrap:wrap}
.breedmeta{display:flex;gap:8px;flex-wrap:wrap;align-items:center}

/* ---------- guide ---------- */
.guide{max-width:780px;margin:0 auto}
.gcard{background:var(--surface);border:1px solid var(--border);border-radius:var(--r-xl);padding:26px 30px;margin-bottom:22px}
.gcard>h2{font-size:var(--fs-h2);margin-bottom:6px}
.gcard>h2 span{margin-right:9px}
.gcard .sub{color:var(--muted);font-size:var(--fs-md);margin-bottom:16px}
.gcard ol,.gcard ul{margin:10px 0 10px 22px;display:flex;flex-direction:column;gap:8px}
.gcard p{margin:10px 0}
.gcard b{color:var(--accent)}
.gcard .gold{color:var(--gold)}
/* box-decoration-break keeps each wrapped fragment a complete pill instead of
   splitting one border across two lines (the breeding formula on narrow screens) */
.gcard code{background:var(--bg);border:1px solid var(--border);border-radius:var(--r-sm);padding:1px 7px;font-size:var(--fs-md);font-family:Consolas,monospace;
  overflow-wrap:break-word;-webkit-box-decoration-break:clone;box-decoration-break:clone}
.gcard details{background:var(--bg);border:1px solid var(--border);border-radius:var(--r-lg);padding:0;margin:10px 0}
.gcard summary{cursor:pointer;font-weight:700;padding:13px 18px;user-select:none;color:var(--text)}
.gcard summary:hover{color:var(--accent)}
.gcard details>div{padding:2px 18px 16px;color:var(--text-2);font-size:var(--fs-md)}
.gcard details ul{margin-left:20px}
.recipe{display:flex;gap:8px;flex-wrap:wrap;margin:8px 0}
.note{border-left:3px solid var(--gold);background:var(--gold-tint);padding:10px 14px;border-radius:0 10px 10px 0;font-size:var(--fs-md);margin:12px 0;color:var(--text-2)}
/* ---------- planner ---------- */
.pcard{background:var(--surface);border:1px solid var(--border);border-radius:var(--r-xl);padding:22px 26px;margin-bottom:22px}
.pcard>h2{font-size:var(--fs-h2);margin-bottom:4px}
.pcard>.sub{color:var(--muted);font-size:var(--fs-md);margin-bottom:16px}
.addrow{display:flex;gap:12px;flex-wrap:wrap;align-items:flex-start}
.ptag{position:relative;flex:1;min-width:220px;max-width:360px}
.ptag .taginp{width:100%;background:var(--raised);border:1px solid var(--border);border-radius:var(--r-lg);padding:10px 14px;outline:none}
.ptag .taginp:focus{border-color:var(--accent)}
.ptag .tpop{position:absolute;top:calc(100% + 6px);left:0;right:0;z-index:60;background:var(--overlay);border:1px solid var(--border-strong);border-radius:var(--r-lg);box-shadow:0 12px 40px rgba(0,0,0,.5);max-height:260px;overflow-y:auto;display:none}
.ptag.open .tpop{display:block}
.ptag .trow{display:flex;align-items:center;gap:8px;width:100%;padding:7px 12px;text-align:left;font-size:var(--fs-md)}
.ptag .trow:hover,.ptag .trow.hl{background:var(--raised)}
.ptag .trow .tr-r{margin-left:auto;font-size:var(--fs-xs);color:var(--muted)}
.pchips{display:flex;gap:6px;flex-wrap:wrap;margin-top:8px}
.pchip .uii,.trow-n .uii{margin-right:1px}
.trow-n{display:inline-flex;align-items:center;gap:7px}
.pchip{display:inline-flex;align-items:center;gap:6px;background:var(--success-tint);border:1px solid var(--success-line);color:var(--success);border-radius:var(--r-full);padding:2px 11px;font-size:var(--fs-sm);font-weight:600;cursor:pointer}
.pchip:hover{border-color:var(--danger);color:var(--danger)}
.pchip.neg{background:var(--danger-tint);border-color:var(--danger-line);color:var(--danger)}
.pchip.ro{cursor:default}
.pchip.ro:hover{border-color:var(--success-line);color:var(--success)}
.pchip.neg.ro:hover{border-color:var(--danger-line);color:var(--danger)}
/* min(…,100%) so a 300px track floor can't outgrow a 268px column on a 320px phone */
.roster{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(300px,100%),1fr));gap:10px;margin-top:16px}
.strip{display:flex;flex-wrap:wrap;gap:8px}
.spal{display:flex;align-items:center;gap:8px;background:var(--bg);border:1px solid var(--border);border-radius:var(--r-full);padding:4px 13px 4px 5px;cursor:pointer;font-size:var(--fs-md);font-weight:600}
.spal:hover{border-color:var(--border-strong)}
.spal .g{font-size:var(--fs-md)}
.gm,.gf{font-weight:700}
.gm{color:var(--male)}.gf{color:var(--female)}
.g svg{width:.95em;height:.95em;display:inline-block;vertical-align:-.08em}
.rstats{color:var(--muted);font-size:var(--fs-sm);white-space:nowrap}
.rospal .nick{color:var(--muted);font-weight:400;font-size:var(--fs-sm);margin-left:6px}
select#genderSel{padding:10px 12px}
.ivrow{display:flex;gap:6px}
.iv{width:62px;background:var(--surface);border:1px solid var(--border);border-radius:var(--r-lg);padding:10px 8px;outline:none;text-align:center;-moz-appearance:textfield}
.iv::-webkit-outer-spin-button,.iv::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}
.iv:focus{border-color:var(--accent)}
.ivchip{font-size:var(--fs-xs);color:var(--muted);background:var(--surface);border:1px solid var(--border);border-radius:var(--r-sm);padding:1px 7px;margin-left:6px;white-space:nowrap;display:inline-block}
/* a roster note is a caption, not a callout — reset the guide's .note blockquote */
.rospal .note{border:0;background:none;padding:0;border-radius:0;
  color:var(--muted);font-size:var(--fs-sm);font-style:italic;margin:4px 0 0}
.warnbox{border-left:3px solid var(--danger);background:var(--danger-tint);padding:10px 14px;border-radius:0 10px 10px 0;font-size:var(--fs-md);margin-bottom:12px;color:var(--text-2)}
.rmodal{width:min(480px,100%)}
.rmtitle{font-size:var(--fs-h2);margin-bottom:16px}
/* said once to a new roster, then gone — see openRosterEditor */
.dlgwhy{color:var(--muted);font-size:var(--fs-sm);margin:-8px 0 16px;line-height:1.5}
.dlgwhy b{color:var(--text-2)}
/* what "Save & add another" carried over, and the way back out of it */
.carrynote{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin:-6px 0 16px;
  background:var(--accent-tint);border:1px solid var(--accent);border-radius:var(--r-lg);padding:9px 13px;
  font-size:var(--fs-sm);color:var(--text-2)}
.carrynote[hidden]{display:none} /* a display: of its own outranks the UA's [hidden] */
.carrynote>span{flex:1;min-width:120px}
.carrynote .alink{padding:4px 12px;font-size:var(--fs-sm)}
/* passive sets offered back for one tap — dashed, so they read as a suggestion
   rather than as the selected chips sitting underneath them */
.psets{display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin-bottom:8px}
.psets[hidden]{display:none}
.psetlb{font-size:var(--fs-xs);letter-spacing:.6px;text-transform:uppercase;color:var(--muted);font-weight:700}
.pset{background:var(--surface);border:1px dashed var(--border-strong);border-radius:var(--r-full);
  padding:3px 12px;font-size:var(--fs-sm);font-weight:600;color:var(--muted);max-width:100%;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pset:hover{color:var(--text);border-color:var(--accent);border-style:solid}
.emptywhy{max-width:52ch;margin:14px auto 0;font-size:var(--fs-sm);line-height:1.6}
.emptywhy>span{display:block;margin-bottom:9px}
.vform{display:flex;flex-direction:column;gap:15px}
.fld label{display:block;font-size:var(--fs-xs);letter-spacing:.6px;text-transform:uppercase;color:var(--muted);margin-bottom:6px;font-weight:700}
.fld label .opt{text-transform:none;letter-spacing:0;font-weight:400;opacity:.75}
.fld .picker{max-width:none;min-width:0}
.fld .search-inp{width:100%}
.fld .ivrow .iv{flex:1;min-width:0}
.segrow{display:flex;gap:6px}
.segrow button{flex:1;display:inline-flex;align-items:center;justify-content:center;gap:6px;padding:9px 10px;border-radius:var(--r-md);background:var(--raised);border:1px solid var(--border);font-size:var(--fs-md);font-weight:600;color:var(--muted)}
.segrow button:hover:not(.on){color:var(--text);border-color:var(--border-strong)}
.segrow button.on{color:var(--text);border-color:var(--accent);background:var(--accent-tint)}
.moredet{border:1px solid var(--border);border-radius:var(--r-lg);background:var(--bg)}
.moredet summary{cursor:pointer;padding:11px 16px;font-weight:600;color:var(--muted);user-select:none;font-size:var(--fs-md);list-style-position:inside}
.moredet summary:hover{color:var(--text)}
.moredet>div{padding:4px 16px 15px;display:flex;flex-direction:column;gap:13px}
.formacts{margin-top:18px;display:flex;gap:10px;align-items:center}
.formacts .primary{flex:1;text-align:center}
.collhead{display:flex;align-items:baseline;gap:14px;flex-wrap:wrap;margin-bottom:14px}
.collhead h2{font-size:var(--fs-h2)}
.collhead .collacts{margin-left:auto;display:flex;gap:8px;flex-wrap:wrap}
.rospal.editing{border-color:var(--accent);box-shadow:0 0 0 1px var(--accent)}
.rosgroup{background:var(--bg);border:1px solid var(--border);border-radius:var(--r-lg);padding:12px 15px}
.rosgroup .ghead{display:flex;align-items:center;gap:10px;font-weight:700;font-size:var(--fs-md)}
.rosgroup .cntb{background:var(--raised);border:1px solid var(--border-strong);border-radius:var(--r-full);font-size:var(--fs-xs);padding:1px 9px;color:var(--muted);font-weight:600}
.rosgroup .gentry{display:flex;align-items:center;gap:8px;margin-top:9px;padding-top:9px;border-top:1px solid var(--border);flex-wrap:wrap}
.rosgroup .gentry .who{font-size:var(--fs-sm);font-weight:600;min-width:0}
.rosgroup .gentry .acts{margin-left:auto;display:flex;gap:5px}
.rosgroup .gentry.editing{border-top-color:var(--accent)}
/* shared small ghost button: roster actions, plan delete, step-open, chain nav */
.acts button,.stepopen,.planhead .del,.chainhead .nav button{background:var(--surface);border:1px solid var(--border);border-radius:var(--r-md);padding:4px 10px;font-size:var(--fs-sm);font-weight:600;color:var(--muted)}
.acts button:hover,.stepopen:hover,.planhead .del:hover,.chainhead .nav button:hover:not(:disabled){color:var(--text);border-color:var(--border-strong)}
.planhead .del.danger:hover{color:var(--danger);border-color:var(--danger)}
/* the stack spans the viewport and centres its toasts, rather than starting at
   the 50% mark — anchored there, a toast could never be wider than half the
   screen, so on a 320px phone every message over a few words became a column
   of one-word lines. The container ignores pointer events; the toasts don't. */
.toasts{position:fixed;bottom:18px;left:0;right:0;z-index:300;display:flex;flex-direction:column;gap:8px;align-items:center;pointer-events:none}
.toast{pointer-events:auto;display:flex;align-items:center;gap:14px;background:var(--overlay);border:1px solid var(--border-strong);border-radius:var(--r-lg);padding:11px 16px;box-shadow:0 10px 34px rgba(0,0,0,.55);font-size:var(--fs-md);animation:pop var(--t-base) var(--ease-out);max-width:min(480px,92vw)}
.toast .undo{color:var(--accent);font-weight:700}
.toast .undo:hover{text-decoration:underline}
.toast .tx{color:var(--muted);padding:2px 6px;border-radius:var(--r-sm)}
.toast .tx:hover{color:var(--text);background:var(--raised)}
.subtabs{margin-bottom:18px;width:fit-content}
.subtabs button{padding:6px 15px;font-size:var(--fs-md)}
@media(max-width:640px){.subtabs{display:flex}}
.subtabs[hidden]{display:none}
.hatchpanel .rstep{background:var(--surface)}
#hatchDepth,#comboKind{flex-shrink:0}
#hatchDepth button,#comboKind button{white-space:nowrap;flex:0 0 auto;padding:9px 12px}
.hatchgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(230px,100%),1fr));gap:10px}
/* the NEW and "n pairs" chips don't shrink, so let them wrap and let a long
   species name give ground rather than push the card past the screen edge */
.hcard{display:flex;align-items:center;gap:11px;flex-wrap:wrap;background:var(--surface);border:1px solid var(--border);border-radius:var(--r-lg);padding:10px 14px;text-align:left}
.hcard:hover{border-color:var(--border-strong)}
.hcard .nm{font-weight:600;font-size:var(--fs-md);min-width:0;overflow:hidden;text-overflow:ellipsis}
.hcard .ways{margin-left:auto;font-size:var(--fs-xs);color:var(--muted);background:var(--bg);border:1px solid var(--border);border-radius:var(--r-full);padding:1px 8px;flex-shrink:0}
.hcard .newb{font-size:var(--fs-xs);font-weight:700;letter-spacing:.5px;color:var(--success);border:1px solid var(--success-line);border-radius:var(--r-sm);padding:1px 6px}
.hcard.expanded{border-color:var(--accent)}
.hatchpanel{grid-column:1/-1;background:var(--bg);border:1px solid var(--border-strong);border-radius:var(--r-lg);padding:13px 15px;display:flex;flex-direction:column;gap:10px}
.hatchpanel .hpttl{font-size:var(--fs-sm);font-weight:700;color:var(--muted)}
.hatchpanel .pair{background:var(--surface)}
.warnchip{font-size:var(--fs-xs);color:var(--danger);border:1px solid var(--danger-line);border-radius:var(--r-sm);padding:1px 7px;flex-shrink:0}
.odds{font-size:var(--fs-xs);color:var(--muted);border:1px solid var(--border);border-radius:var(--r-sm);padding:1px 7px;flex-shrink:0;cursor:pointer}
.odds:hover{color:var(--text);border-color:var(--border-strong)}
.odds[aria-expanded="true"]{color:var(--text);border-color:var(--accent)}
.oddsinfo{flex-basis:100%;font-size:var(--fs-sm);color:var(--muted);line-height:1.45}
/* "where do I catch one" — same expand-in-place shape as .odds/.oddsinfo, but
   its own class so the two toggles can't remove each other's panel */
.odds.wild{border-color:var(--accent-line);color:var(--text-2)}
.odds.wild:hover{border-color:var(--accent)}
.wildinfo{flex-basis:100%;min-width:0;font-size:var(--fs-sm);color:var(--muted);line-height:1.45;
  display:flex;flex-direction:column;align-items:flex-start;gap:6px;
  border-top:1px solid var(--border);margin-top:2px;padding-top:9px}
.wildinfo .wline{display:flex;align-items:center;flex-wrap:wrap;gap:8px;max-width:100%}
.wildinfo b{color:var(--text);font-weight:700}
.wildinfo .wnote{color:var(--text-2)}
.wildinfo .wtag{font-size:var(--fs-xs);font-weight:700;color:var(--accent);background:var(--accent-tint);
  border:1px solid var(--accent-line);border-radius:var(--r-full);padding:1px 8px}
.wildinfo .wlb{font-size:var(--fs-xs);text-transform:uppercase;letter-spacing:.06em;font-weight:700;color:var(--muted)}
.wildinfo .whub{display:flex;align-items:center;gap:6px;min-width:0;max-width:100%;color:var(--text-2);
  background:var(--surface);border:1px solid var(--border);border-radius:var(--r-sm);padding:2px 9px}
.wildinfo .whub>span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.wildinfo .whub i{font-style:normal;font-size:var(--fs-xs);color:var(--muted);flex-shrink:0}
.wildinfo .wlink{color:var(--accent);font-weight:600;text-decoration:none;border-bottom:1px solid var(--accent-line)}
.wildinfo .wlink:hover{border-bottom-color:var(--accent)}
.needrow{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin:0 0 12px;font-size:var(--fs-sm);color:var(--muted)}
.needrow .tchip{cursor:pointer}
.needrow .tchip:hover{border-color:var(--border-strong)}
/* how gettable a species is — a named tier plus the facts it came from.
   Four ordered steps on one severity ramp (green -> neutral -> gold -> pink)
   so the order is readable without the labels, and two categorical ones off
   that scale: an alpha and an uncatchable pal aren't "harder", they're a
   different kind of answer. */
.accb{font-size:var(--fs-xs);font-weight:700;letter-spacing:.3px;padding:1px 8px;border-radius:var(--r-sm);white-space:nowrap}
.accb.easy{background:var(--success-tint);color:var(--success);border:1px solid var(--success-line)}
.accb.mid{background:rgba(154,165,177,.12);color:var(--neutral);border:1px solid var(--border-strong)}
.accb.hard{background:var(--gold-tint);color:var(--gold);border:1px solid var(--gold-line)}
.accb.grind{background:var(--danger-tint);color:var(--danger);border:1px solid var(--danger-line)}
.accb.alpha{background:rgba(183,138,255,.12);color:var(--dark);border:1px solid rgba(183,138,255,.35)}
.accb.none{background:transparent;color:var(--muted);border:1px dashed var(--border-strong)}
.accr{font-size:var(--fs-xs);font-weight:500;color:var(--muted);white-space:nowrap}
.wildinfo .accb{flex-shrink:0}
.fldhint{font-size:var(--fs-sm);color:var(--muted);margin-top:6px}
/* optional "my level" — deliberately the smallest control in the slot, since
   it changes only how catches are worded and ordered, never what's offered */
.mylv{display:flex;align-items:center;gap:9px;font-size:var(--fs-sm);color:var(--muted)}
.mylv label{font-weight:600}
.mylv input{width:74px;background:var(--bg);border:1px solid var(--border);border-radius:var(--r-md);
  padding:7px 9px;color:var(--text);font:inherit;font-weight:600}
.mylv input:hover{border-color:var(--border-strong)}
.gjump{padding:3px 12px;font-size:var(--fs-sm);margin-left:4px}
.slotlb.mt{margin-top:12px}
.slot .ptag{max-width:none;min-width:0}
.plannerhow{margin-bottom:16px}
.plannerhow>div{padding:2px 16px 14px;color:var(--text-2);font-size:var(--fs-md)}
.plannerhow b{color:var(--accent)}
.tree{display:flex;justify-content:center;padding:6px 0 14px}
.tvp{position:relative;overflow:hidden;border:1px solid var(--border);border-radius:var(--r-lg);background:var(--bg);cursor:grab;touch-action:none;margin-bottom:10px;width:100%;user-select:none}
.tvp *{user-select:none}
.tvp img{-webkit-user-drag:none}
.tvp.grabbing{cursor:grabbing}
.tvp-inner{transform-origin:0 0;width:max-content;padding:16px}
.tvp-ctrl{position:absolute;right:10px;bottom:10px;display:flex;gap:6px;z-index:5}
.tvp-ctrl button{width:32px;height:32px;border-radius:var(--r-md);background:var(--surface);border:1px solid var(--border-strong);color:var(--muted);font-size:var(--fs-base);line-height:1}
.tvp-ctrl button:hover{color:var(--text);border-color:var(--border-strong)}
.tvp-hint{position:absolute;left:12px;bottom:12px;font-size:var(--fs-xs);color:var(--muted);pointer-events:none}
.tchip.cur{border-color:var(--accent);box-shadow:0 0 0 1px var(--accent)}
.stepopen{margin-left:auto;flex-shrink:0}
.chaincard{width:min(760px,100%);background:var(--surface);border:1px solid var(--border);border-radius:var(--r-xl);padding:16px 18px}
.chainhead{display:flex;align-items:center;gap:10px;margin-bottom:10px;flex-wrap:wrap}
.chainhead .ttl{font-weight:700;font-size:var(--fs-md)}
.chainhead .nav{margin-left:auto;display:flex;gap:6px}
.plantree{margin:6px 0 10px}
.tn{display:flex;align-items:center;gap:0}
.tn-parents{display:flex;flex-direction:column;gap:10px;align-items:flex-end;position:relative;padding-right:14px}
.tn-parents>*{position:relative}
.tn-parents>*::after{content:'';position:absolute;right:-14px;top:50%;margin-top:-1px;width:14px;height:2px;background:var(--border-strong)}
/* vertical connector drawn per child, anchored to each child's true center —
   a single group-level bar assumed chip-height children and left orphaned
   stubs next to taller nested subtrees */
.tn-parents>*::before{content:'';position:absolute;right:-14px;top:-10px;bottom:-10px;width:2px;background:var(--border-strong);border-radius:2px}
.tn-parents>:first-child::before{top:50%}
.tn-parents>:last-child::before{bottom:50%}
.tn-join{width:20px;height:2px;background:var(--border-strong);flex-shrink:0;position:relative}
.tn-join::after{content:'▸';position:absolute;right:-6px;top:-9px;color:var(--accent);font-size:var(--fs-sm)}
.tchip{display:inline-flex;align-items:center;gap:7px;background:var(--bg);border:1px solid var(--border);border-radius:var(--r-full);padding:4px 12px 4px 5px;font-size:var(--fs-sm);font-weight:600;white-space:nowrap}
.tchip.final{border-color:var(--gold)}
.tchip .own{color:var(--gold);font-size:var(--fs-xs)}
.tchip .g{font-size:var(--fs-sm)}
.mnav{position:absolute;top:13px;color:var(--muted);font-size:var(--fs-h2);line-height:1;padding:5px 11px;border-radius:var(--r-md)}
.mnav:hover{color:var(--text);background:var(--raised)}
.mnav.prev{right:104px}
.mnav.next{right:60px}
.pop .srcrow{display:flex;gap:4px;padding:7px 10px;border-bottom:1px solid var(--border)}
.pop .srcrow button{flex:1;padding:5px 10px;border-radius:var(--r-sm);font-size:var(--fs-sm);font-weight:700;color:var(--muted);background:var(--raised)}
.pop .srcrow button.on{color:var(--text);background:var(--accent-tint);box-shadow:inset 0 0 0 1px var(--accent-line)}
.pop .srcrow button:hover:not(.on){color:var(--text)}
.rospal{background:var(--bg);border:1px solid var(--border);border-radius:var(--r-lg);padding:11px 14px;display:flex;gap:12px;align-items:flex-start;cursor:pointer;transition:border-color var(--t-fast)}
.rospal:hover{border-color:var(--border-strong)}
.rosgroup .ghead{cursor:pointer}
.rosgroup .ghead:hover{color:var(--accent)}
/* the action buttons take ~135px of a ~360px grid tile; sharing a row with them
   left the body too narrow to put two passive chips side by side, at any width */
.rospal{flex-wrap:wrap}
.rospal .body{flex:1 1 150px;min-width:0}
.rospal .nm{font-weight:700;font-size:var(--fs-md)}
.rospal .acts{display:flex;gap:5px;flex-shrink:0;width:100%;justify-content:flex-end;margin-top:4px}
.plansec{display:flex;align-items:center;gap:12px;font-size:var(--fs-sm);font-weight:700;letter-spacing:.7px;text-transform:uppercase;color:var(--accent);margin:22px 0 12px}
.plansec::after{content:'';flex:1;height:1px;background:var(--border);order:1}
.plansec .alink{order:2;text-transform:none;letter-spacing:0}
.quicklb{font-size:var(--fs-sm);color:var(--muted);margin-bottom:8px}
.strip{margin-bottom:16px}
.slotgrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:12px;margin-bottom:14px}
.slot{background:var(--bg);border:1px dashed var(--border-strong);border-radius:var(--r-lg);padding:12px 14px}
.slotlb{font-size:var(--fs-xs);font-weight:700;letter-spacing:.6px;text-transform:uppercase;color:var(--muted);margin-bottom:7px}
.slot .picker{max-width:none;min-width:0}
.slot .picker-btn{padding:8px 12px}
.targetrow{display:flex;gap:14px;flex-wrap:wrap;align-items:stretch}
.targetrow .slot{flex:1;min-width:240px;max-width:380px;border-style:solid;border-color:var(--accent);border-width:1px}
/* max-width sized to the three-way partner control: at 320px "Any species"
   was the only label wrapping to two lines, which read as a broken column */
.targetrow .slot.opts{border-style:dashed;border-color:var(--border-strong);flex:0 1 auto;min-width:220px;max-width:352px;display:flex;flex-direction:column;gap:8px;align-items:stretch}
#partnerMode button{padding-left:7px;padding-right:7px}
.targetrow .slot.opts .slotlb{margin-bottom:0}
.routewrap{margin-top:20px}
.rstep{display:flex;align-items:center;gap:12px;background:var(--bg);border:1px solid var(--border);border-radius:var(--r-lg);padding:12px 16px;margin-bottom:8px;flex-wrap:wrap}
.rstep .stepno{width:26px;height:26px;border-radius:50%;background:var(--raised);border:1px solid var(--border-strong);display:flex;align-items:center;justify-content:center;font-size:var(--fs-sm);font-weight:700;color:var(--accent);flex-shrink:0}
.rstep .unit{display:flex;align-items:center;gap:8px;min-width:0}
.rstep .unit .nm{font-weight:600;font-size:var(--fs-md)}
.rstep .unit .g{font-size:var(--fs-md)}
.rstep .sym{color:var(--muted);font-size:16px}
.rstep .arr2{color:var(--accent);font-size:var(--fs-lg);font-weight:700}
.rstep .own{color:var(--gold);font-size:var(--fs-sm)}
.rstep .badge{flex-shrink:0}
.rstep .carrier{font-size:var(--fs-xs);color:var(--success);border:1px solid var(--success-line);border-radius:var(--r-sm);padding:1px 7px}
.routemeta{display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin:12px 0}
.saverow{display:flex;gap:10px;flex-wrap:wrap;margin-top:14px;align-items:center}
.planhead{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-bottom:10px}
.planhead .nm{font-weight:700;font-size:16px}
.planhead .prog{font-size:var(--fs-sm);color:var(--muted);background:var(--raised);border-radius:var(--r-sm);padding:2px 9px}
.planhead .pushr{margin-left:auto}
.plan{background:var(--bg);border:1px solid var(--border);border-radius:var(--r-lg);padding:16px 18px;margin-bottom:12px}
.plan .rstep{background:var(--surface);cursor:default}
.plan .rstep.done{opacity:.45;transition:opacity var(--t-base)}
.plan .rstep .chk{appearance:none;-webkit-appearance:none;width:22px;height:22px;margin:0;border-radius:var(--r-sm);background:var(--raised);border:1px solid var(--border-strong);cursor:pointer;flex-shrink:0;transition:background var(--t-fast),border-color var(--t-fast)}
.plan .rstep .chk:hover{border-color:var(--muted)}
.plan .rstep .chk:checked{border-color:var(--success);background:var(--success) url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path d="M3 8.5 6.5 12 13 4.5" fill="none" stroke="%230d1117" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/></svg>') center/14px no-repeat}
footer{max-width:1200px;margin:0 auto;padding:0 20px 30px;color:var(--muted);font-size:var(--fs-sm);text-align:center}
footer code{background:var(--surface);border:1px solid var(--border);border-radius:var(--r-sm);padding:0 5px;font-family:Consolas,monospace}
@media(pointer:coarse){.kbdonly{display:none}}

/* ===================== interactive map =====================
   A tile pyramid (assets/map/<layer>/<z>/<x>_<y>.webp) drawn into a fixed
   8192x8192 "map pixel" stage that gets one transform. Everything inside —
   tiles, markers, the link line — is positioned in map pixels, so nothing has
   to be repositioned when the view moves; only the stage's transform changes.
   Markers counter-scale off --iz (= 1/scale, written once per frame on the
   stage) so they stay a constant size on screen without 255 style writes. */
.mapbar{margin-bottom:12px}
.mapbar .mfilters{flex-wrap:wrap}
.mapbar .mlabels{align-items:center;gap:4px;background:var(--surface);border:1px solid var(--border);
  border-radius:var(--r-lg);padding:4px 4px 4px 12px}
.mapbar .mlabels .mlb-cap{font-size:var(--fs-sm);color:var(--muted);font-weight:600;padding-right:5px;white-space:nowrap}
.mapbar .mlabels button{flex:0 0 auto;padding:6px 11px;font-size:var(--fs-sm);background:none;border-color:transparent}
.mapbar .mlabels button.on{background:var(--accent-tint);border-color:var(--accent)}
.mapbar .mfilters button{flex:0 1 auto;gap:7px;padding:9px 13px}
.mdot{width:16px;height:16px;flex-shrink:0;background:center/contain no-repeat}
.mdot.alpha{background-image:url(../assets/ui/map/alpha.webp)}
.mdot.ft{background-image:url(../assets/ui/map/waypoint.webp)}
.mdot.tower{background-image:url(../assets/ui/map/tower.webp)}
.mdot.region{background:none;border:1px dashed var(--muted);border-radius:3px;width:14px;height:11px}
.mapresults{display:flex;gap:8px;flex-wrap:wrap;margin:-4px 0 12px}
.mapresults[hidden]{display:none}
.mapresults .mres{display:inline-flex;align-items:center;gap:7px;background:var(--surface);border:1px solid var(--border);border-radius:var(--r-full);padding:4px 12px 4px 5px;font-size:var(--fs-sm);font-weight:600;color:var(--text-2)}
.mapresults .mres:hover{border-color:var(--accent);color:var(--text)}
.mapresults .mres img{width:22px;height:22px;border-radius:50%;object-fit:cover;background:var(--raised)}
.mapresults .mres .rt{width:22px;height:22px;border-radius:50%;background:var(--raised) center/13px no-repeat}
.mapresults .mres .rt.ft{background-image:url(../assets/ui/map/waypoint.webp)}
.mapresults .mres .rt.tw{background-image:url(../assets/ui/map/tower.webp);background-size:16px}
.mapresults .mres.sp{border-color:var(--accent-line)}
.mapresults .mres.sp:hover{background:var(--accent-tint)}
.mapresults .more{color:var(--muted);font-size:var(--fs-sm);align-self:center}

/* the persistent "you are looking at X's range" bar above the viewport */
/* The legend is 182px of nowrap and .sb-clear can't shrink, so on a phone the
   row had nothing left to give and took it out of .sb-txt (min-width:0) — the
   pal's name and level range were squeezed to 0px at 320 and 15px at 360, and
   the Clear button still hung 2px off the right edge of a 320px viewport. Let
   the row wrap instead: Clear (with the legend) drops to a second line and the
   name gets its width back. Inert at any width the row already fits. */
.spawnbar{display:flex;flex-wrap:wrap;align-items:center;gap:11px;margin:0 0 12px;padding:8px 12px 8px 8px;
  background:var(--accent-tint);border:1px solid var(--accent-line);border-radius:var(--r-lg)}
.spawnbar[hidden]{display:none}
.spawnbar .pico{flex-shrink:0}
.spawnbar .sb-txt{display:flex;flex-direction:column;line-height:1.3;min-width:0}
.spawnbar .sb-txt b{font-size:var(--fs-md)}
.spawnbar .sb-txt span{color:var(--muted);font-size:var(--fs-sm)}
.spawnbar .sbadge{font-size:var(--fs-xs);font-weight:700;padding:3px 9px;border-radius:var(--r-full);
  background:var(--raised);border:1px solid var(--border-strong);color:var(--text-2);white-space:nowrap}
.spawnbar .sb-legend{margin-left:auto;display:flex;align-items:center;gap:8px;
  font-size:var(--fs-xs);color:var(--muted);white-space:nowrap}
/* the swatches carry the same alpha the map does, so the key matches the
   thing it's a key for */
.spawnbar .sb-ramp{display:flex;height:11px;border-radius:3px;overflow:hidden;
  border:1px solid var(--border-strong);background:var(--bg)}
.spawnbar .sb-ramp i{width:15px;height:100%}
.spawnbar .sb-clear{flex-shrink:0;padding:6px 12px;font-size:var(--fs-sm)}
.mapinfo .inote{margin-top:9px;line-height:1.45}

.mapview{position:relative;overflow:hidden;height:min(72vh,760px);min-height:420px;
  background:#0a1b2a;border:1px solid var(--border);border-radius:var(--r-xl);
  touch-action:none;cursor:grab;user-select:none;-webkit-user-select:none;contain:layout paint}
.mapview.drag{cursor:grabbing}
.mapstage{position:absolute;top:0;left:0;width:8192px;height:8192px;transform-origin:0 0}
/* Spawn areas are a canvas, not SVG: a common species has thousands of
   overlapping circles. Its position and size are set in map pixels by the
   drawing code, which sizes the backing store to the resolution it's actually
   displayed at — a fixed canvas spanning the whole 8192px map was a
   quarter-scale texture being stretched 4x at maximum zoom. */
.mapzones{position:absolute;pointer-events:none}
.mapzones[hidden]{display:none}
.maptiles{position:absolute;inset:0}
.maptiles img{position:absolute;display:block;pointer-events:none;-webkit-user-drag:none}
/* the z0 tile stays underneath every detail level, so switching level never
   flashes the empty background while the new tiles decode */
.maptiles img.base{left:0;top:0;width:8192px;height:8192px}
.maplink{position:absolute;left:0;top:0;overflow:visible;pointer-events:none}
.maplink line{stroke:var(--accent);stroke-linecap:round;stroke-dasharray:14 18;opacity:.9}
.maplink.off{display:none}
.mapmarks{position:absolute;inset:0}
/* Region names sit under the markers and never take a click. They're bucketed
   by the real size of the game's region volume, so a zoomed-out map shows the
   handful of big biomes and the small landmarks arrive as you go in. */
.mapregions{position:absolute;inset:0;pointer-events:none}
.mapregions[hidden]{display:none}
.rg{position:absolute;transform:translate(-50%,-50%) scale(var(--iz,1));transform-origin:50% 50%;
  white-space:nowrap;font-size:12px;font-weight:700;letter-spacing:.09em;text-transform:uppercase;
  color:rgba(230,237,243,.72);text-shadow:0 0 4px #000,0 0 9px #000,0 1px 2px #000;display:none}
.mapstage.r0 .rg.t0,
.mapstage.r1 .rg.t0,.mapstage.r1 .rg.t1,
.mapstage.r2 .rg.t0,.mapstage.r2 .rg.t1,.mapstage.r2 .rg.t2,
.mapstage.r3 .rg{display:block}
.mapstage.r2 .rg.t0,.mapstage.r3 .rg.t0{font-size:13px;color:rgba(230,237,243,.55)}
.mapregions .rg.nolb{display:none}

/* --fx/--fy fan apart the two spawners that hold a pair of alphas (see
   MARK_FAN). They come after scale(--iz), which undoes the stage's zoom, so
   the offset is a fixed number of screen pixels however far you are zoomed in
   — the same trick that keeps the icon itself one size. Default 0: every other
   marker is untouched. */
.mk{position:absolute;padding:0;background:none;border:none;line-height:0;
  transform:translate(-50%,-50%) scale(var(--iz,1)) translate(var(--fx,0px),var(--fy,0px));transform-origin:50% 50%;
  transition:none}
.mk:not(:disabled):active{transform:translate(-50%,-50%) scale(var(--iz,1)) translate(var(--fx,0px),var(--fy,0px))}
.mk .g{display:block;box-sizing:border-box}
.mk .lb{position:absolute;left:50%;top:100%;transform:translateX(-50%);margin-top:3px;
  font-size:10.5px;font-weight:700;line-height:1.25;white-space:nowrap;color:var(--text);
  text-shadow:0 0 3px #000,0 0 6px #000,0 1px 2px #000;pointer-events:none;opacity:0;transition:opacity var(--t-fast)}
/* the three alternative anchors the placer tries before giving up on a label */
.mk.lb-t .lb{top:auto;bottom:100%;margin:0 0 3px}
/* alphas wear their level badge above the icon, so a label anchored up there
   has to clear it — matches MK_TOP in the placer */
.mk-alpha.lb-t .lb{margin-bottom:16px}
.mk.lb-r .lb{left:100%;top:50%;transform:translateY(-50%);margin:0 0 0 5px}
.mk.lb-l .lb{left:auto;right:100%;top:50%;transform:translateY(-50%);margin:0 5px 0 0}
.lab .mk .lb,.mk.sel .lb{opacity:1}
/* .nolb is "the placer couldn't fit this one" — hover still reveals it, which
   is what makes Off a usable mode rather than a blindfold. The hover rules have
   to out-specify the .lab zoom tier above, or a suppressed label stays hidden
   under the cursor exactly when you're zoomed in enough to want it. */
.lab .mk.nolb .lb,.mk.nolb .lb{opacity:0}
.mk:hover .lb,.lab .mk.nolb:hover .lb,.mk.nolb:hover .lb{opacity:1}
.mk:focus-visible{outline:none}
.mk:focus-visible .g{outline:2px solid var(--accent);outline-offset:2px}

/* Waypoints and towers use the game's own compass icons, so a marker here reads
   the same as the one on your screen in-game. They're artwork on transparent,
   so legibility over a busy map comes from a drop-shadow rather than a border. */
.mk-fastTravel,.mk-tower,.mk-middleBoss{z-index:1}
.mk-fastTravel .g,.mk-tower .g,.mk-middleBoss .g{background:center/contain no-repeat;
  filter:drop-shadow(0 1px 2px rgba(0,0,0,.9))}
.mk-fastTravel .g{width:19px;height:19px;background-image:url(../assets/ui/map/waypoint.webp)}
.mk-tower,.mk-middleBoss{z-index:3}
.mk-tower .g{width:26px;height:26px;background-image:url(../assets/ui/map/tower.webp)}
.mk-middleBoss .g{width:21px;height:21px;background-image:url(../assets/ui/map/alpha.webp)}
.mk-tower .lb,.mk-middleBoss .lb{color:var(--gold);opacity:1}
.mk-tower.nolb .lb,.mk-middleBoss.nolb .lb{opacity:0}
.mk-tower:hover .lb,.mk-middleBoss:hover .lb{opacity:1}
.mk-fastTravel:hover .g,.mk-fastTravel.sel .g,
.mk-tower:hover .g,.mk-tower.sel .g,
.mk-middleBoss:hover .g,.mk-middleBoss.sel .g{filter:drop-shadow(0 0 5px var(--accent)) brightness(1.2)}

/* alphas — the pal's own icon, which is the only label that scans at a glance */
.mk-alpha{z-index:2}
.mk-alpha .g{width:26px;height:26px;border-radius:50%;overflow:hidden;background:var(--raised);
  border:2px solid var(--danger);box-shadow:0 1px 4px rgba(0,0,0,.7)}
.mk-alpha img{width:100%;height:100%;display:block;object-fit:cover;pointer-events:none}
.mk-alpha .fb{width:100%;height:100%;display:grid;place-items:center;font-size:12px;font-weight:800;color:var(--text)}
.mk-alpha:hover .g,.mk-alpha.sel .g{border-color:var(--text);box-shadow:0 0 0 3px var(--danger-line)}
.mk-alpha .lvl{position:absolute;left:50%;top:-4px;transform:translate(-50%,-100%);
  background:var(--danger);color:var(--ink);font-size:9px;font-weight:800;line-height:1;
  padding:2px 4px;border-radius:var(--r-full);pointer-events:none;opacity:0;transition:opacity var(--t-fast)}
.lab .mk .lvl,.mk-alpha:hover .lvl,.mk-alpha.sel .lvl{opacity:1}
/* Search dims the misses rather than hiding them, so you keep the sense of
   where everything else is. Their labels go, though: 16%-opacity text is a
   real contrast failure, and it's noise the search was meant to cut. */
.mk.dim{opacity:.16;pointer-events:none}
.mk.dim .lb,.mk.dim .lvl{display:none}

/* nearest-waypoint highlight, driven from the info panel */
.mk.near .g{filter:drop-shadow(0 0 4px var(--accent)) drop-shadow(0 0 9px var(--accent)) brightness(1.25)}
.mk-alpha.near .g{filter:none;box-shadow:0 0 0 3px var(--accent),0 0 12px var(--accent)}

.mapzoom{position:absolute;top:12px;right:12px;z-index:6;display:flex;flex-direction:column;gap:6px}
.mapzoom button{width:36px;height:36px;display:grid;place-items:center;font-size:19px;font-weight:700;
  background:rgba(22,27,34,.92);border:1px solid var(--border-strong);border-radius:var(--r-md);color:var(--text-2);backdrop-filter:blur(6px)}
.mapzoom button:hover{color:var(--text);border-color:var(--accent)}
.maphelp{position:absolute;left:12px;top:12px;z-index:5;pointer-events:none;
  background:rgba(13,17,23,.78);border:1px solid var(--border);border-radius:var(--r-full);
  padding:5px 13px;font-size:var(--fs-xs);color:var(--muted);backdrop-filter:blur(6px);
  transition:opacity var(--t-base)}
.maphelp.gone{opacity:0}

.mapinfo{position:absolute;left:12px;bottom:12px;z-index:6;width:290px;max-width:calc(100% - 24px);
  max-height:calc(100% - 90px);overflow-y:auto;overscroll-behavior:contain;
  background:rgba(22,27,34,.96);border:1px solid var(--border-strong);border-radius:var(--r-lg);
  padding:14px 16px 15px;box-shadow:0 12px 40px rgba(0,0,0,.55);backdrop-filter:blur(8px);
  font-size:var(--fs-md);touch-action:pan-y}
.mapinfo[hidden]{display:none}
.mapinfo .ihead{display:flex;align-items:flex-start;gap:10px;margin-bottom:2px}
.mapinfo .ihead img{width:44px;height:44px;border-radius:var(--r-md);flex-shrink:0;background:var(--raised);cursor:pointer}
.mapinfo h3{font-size:var(--fs-lg);line-height:1.25;font-weight:700}
.mapinfo .isub{color:var(--muted);font-size:var(--fs-sm)}
.mapinfo .iclose{position:absolute;top:6px;right:8px;font-size:15px;color:var(--muted);padding:4px 7px;border-radius:var(--r-sm);line-height:1}
.mapinfo .iclose:hover{color:var(--text);background:var(--raised)}
.mapinfo .crow{display:flex;gap:6px;flex-wrap:wrap;margin:9px 0 4px}
.mapinfo .nlb{margin-top:12px;font-size:var(--fs-xs);text-transform:uppercase;letter-spacing:.06em;color:var(--muted);font-weight:700}
.mapinfo .near{display:flex;flex-direction:column;gap:4px;margin-top:6px}
.mapinfo .near button{display:flex;align-items:center;gap:8px;width:100%;text-align:left;
  background:var(--bg);border:1px solid var(--border);border-radius:var(--r-md);padding:7px 10px;font-size:var(--fs-sm);color:var(--text-2)}
.mapinfo .near button:hover{border-color:var(--accent);color:var(--text)}
.mapinfo .near .d{margin-left:auto;color:var(--muted);font-variant-numeric:tabular-nums;white-space:nowrap}
.mapinfo .iacts{display:flex;gap:8px;margin-top:12px}
.mapinfo .iacts .alink{flex:1;text-align:center;padding:7px 8px;font-size:var(--fs-sm)}
.mapfoot{margin:12px 0 0}

/* ===================== skills catalog =====================
   Two indexes and the base-aura group. Everything here is a card grid, so the
   shared shape lives in .auracard/.skillcard/.pvcard and the differences are
   only in what each card leads with. */
.psfam{flex-wrap:wrap;margin:-6px 0 18px}
.psfam button{flex:1 1 auto;min-width:88px}
/* a section heading inside a view — smaller than the page h1, with its count
   trailing it rather than sitting in a separate row */
.aurasec,.pvsec{margin-bottom:26px}
.aurasec h2,.pvsec h2{font-size:var(--fs-h2);font-weight:700;margin-bottom:6px;display:flex;align-items:baseline;gap:10px;flex-wrap:wrap}
.aurasec h2 .rstats,.pvsec h2 .rstats{font-weight:400}
.aurasec .viewsub{max-width:78ch}
.pvsec.bad h2{color:var(--danger)}
.auragrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(280px,100%),1fr));gap:10px}
.auracard,.skillcard,.pvcard{background:var(--surface);border:1px solid var(--border);border-radius:var(--r-lg);padding:13px 15px;display:flex;flex-direction:column;gap:8px;min-width:0}
.auracard:hover,.skillcard:hover,.pvcard:hover{border-color:var(--border-strong)}
.ahead,.shead,.pvhead{display:flex;align-items:center;gap:8px;flex-wrap:wrap;min-width:0}
.atitle{font-weight:700;font-size:var(--fs-lg);color:var(--text)}
/* the work auras are the headline fact of the whole tab — the icon leads */
.auracard .ahead .uii{filter:none}
.askill{color:var(--gold);font-weight:600;font-size:var(--fs-md)}
.aclause,.skillcard .psd{color:var(--text-2);font-size:var(--fs-md);margin:0}
.rankstrip{display:flex;flex-direction:column;gap:3px;font-size:var(--fs-sm);color:var(--muted);
  border-top:1px solid var(--border);padding-top:7px;margin-top:auto}
.rankstrip .rscap{font-size:var(--fs-xs);color:var(--muted);letter-spacing:.4px;text-transform:uppercase}
.rankstrip .rk{display:flex;gap:8px;justify-content:space-between;align-items:baseline}
.rankstrip .rk b{color:var(--text-2);font-weight:600}
.rankstrip .rk span{white-space:nowrap;font-variant-numeric:tabular-nums}
/* pal name + icon as one control, wherever a card points back at a pal card */
.palref{display:inline-flex;align-items:center;gap:8px;font-weight:600;color:var(--text);
  border:1px solid transparent;border-radius:var(--r-full);padding:2px 10px 2px 2px;max-width:100%}
.palref>span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.palref:hover{border-color:var(--border-strong);background:var(--raised)}
.badge.nostack{background:var(--raised);color:var(--muted);border:1px solid var(--border);text-transform:none;letter-spacing:0}
.badge.aura{background:var(--success-tint);color:var(--success);border:1px solid var(--success-line)}
.badge.mut{background:var(--accent-tint);color:var(--accent);border:1px solid var(--accent-line);text-transform:none;letter-spacing:0}
.badge.have{background:var(--gold-tint);color:var(--gold);border:1px solid var(--gold-line);text-transform:none;letter-spacing:0}
button.badge.aura:hover,button.badge.have:hover{border-color:currentColor}
/* an effect tag is a filter you can click from any pal card */
.mchip.tagbtn:hover{color:var(--text);border-color:var(--accent)}
.skillgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(330px,100%),1fr));gap:10px;align-items:start}
.skillcard .psn{font-weight:700;color:var(--gold);font-size:var(--fs-base)}
.skillcard .pst{display:flex;gap:6px;flex-wrap:wrap}
.flatnote{color:var(--muted);font-size:var(--fs-sm)}
.pskill .flatnote{margin-top:7px}
/* a number the game's own description ships without — see psDesc */
.phold{display:inline-block;min-width:1.1em;text-align:center;color:var(--muted);
  background:var(--raised);border:1px dashed var(--border-strong);border-radius:var(--r-sm);
  font-size:var(--fs-sm);line-height:1.3;cursor:help}
.rankdet{border-top:1px solid var(--border);padding-top:6px;margin-top:auto}
.rankdet summary{color:var(--accent);font-size:var(--fs-sm);font-weight:600;cursor:pointer;list-style:none;
  display:inline-flex;align-items:center;gap:6px;border-radius:var(--r-sm)}
.rankdet summary::-webkit-details-marker{display:none}
.rankdet summary::before{content:'▸';color:var(--muted);transition:transform var(--t-fast)}
.rankdet[open] summary::before{transform:rotate(90deg)}
.rankdet .ranktbl{margin-top:6px;display:block;overflow-x:auto}
.pvgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(270px,100%),1fr));gap:10px}
.pvcard{gap:6px}
.pvn{font-weight:700;font-size:var(--fs-base);flex:1;min-width:0}
.pvrank{margin-left:auto;letter-spacing:1px;color:var(--gold);border-color:var(--gold-line)}
.pvcard.s-bad .pvrank{color:var(--danger);border-color:var(--danger-line)}
.pvcard.s-bad{border-color:var(--danger-line)}
.pvfx{list-style:none;display:flex;flex-direction:column;gap:2px;font-size:var(--fs-md);color:var(--text-2)}
.pvfx .up::before{content:'▲';color:var(--success);font-size:9px;margin-right:6px;vertical-align:1px}
.pvfx .dn::before{content:'▼';color:var(--danger);font-size:9px;margin-right:6px;vertical-align:1px}
.pvfx li:not(.up):not(.dn)::before{content:'•';color:var(--muted);margin-right:6px}
.pvfoot{display:flex;gap:6px;flex-wrap:wrap;margin-top:2px}


/* ===================== read a save file =====================
   Sits beside Export/Import data but must not read as the same thing: one
   restores a Palarium backup, this one reads a game file. Hence its own icon
   and wording, and a preview before anything is written. */
.savebtn{gap:6px}
.savebtn .sicon{font-size:var(--fs-md);line-height:1}
.smodal{width:min(680px,100%)}
/* the promise the whole feature rests on, said where the file is picked */
.privacy{background:var(--raised);border:1px solid var(--border);border-left:3px solid var(--accent);
  border-radius:0 10px 10px 0;padding:12px 15px;font-size:var(--fs-sm);line-height:1.55;
  color:var(--text-2);margin:-4px 0 18px}
.privacy b{color:var(--text)}
.alink.big{padding:12px 20px;font-size:var(--fs-md)}
.mono{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:var(--fs-xs);
  background:var(--raised);border:1px solid var(--border);border-radius:var(--r-md);
  padding:8px 10px;overflow-x:auto;white-space:nowrap;color:var(--text-2)}
.pbar{height:8px;background:var(--raised);border:1px solid var(--border);border-radius:999px;
  overflow:hidden;margin:12px 0 14px}
.pbarfill{height:100%;width:4%;background:var(--accent);border-radius:999px;transition:width .18s linear}
.smsum{font-size:var(--fs-md);color:var(--text-2);line-height:1.55;margin:-4px 0 14px}
.smfilter{margin-bottom:14px}
.smh3{font-size:var(--fs-md);margin:18px 0 6px}
.smconf{display:flex;flex-direction:column;gap:12px;margin-top:10px}
.confrow{border:1px solid var(--border);border-radius:var(--r-lg);padding:12px 14px;background:var(--raised)}
.confmine,.confsave{font-size:var(--fs-sm);color:var(--text-2);line-height:1.5;margin-bottom:4px;overflow-wrap:anywhere}
.confsave.amb{color:var(--muted);font-style:italic}
.conflab{display:block;font-size:var(--fs-xs);color:var(--muted);margin:8px 0 4px}
.confseg{margin-top:8px}
.smprev{margin-top:4px}
.smlist{display:flex;flex-direction:column;gap:4px;max-height:260px;overflow-y:auto;
  border:1px solid var(--border);border-radius:var(--r-lg);padding:8px 10px;background:var(--raised)}
.smitem{display:flex;align-items:center;gap:8px;font-size:var(--fs-sm);color:var(--text-2);
  overflow-wrap:anywhere;line-height:1.4}
.smacts{display:flex;gap:10px;margin-top:20px}
.smerr{background:var(--danger-tint);border-left:3px solid var(--danger);border-radius:0 10px 10px 0;
  padding:12px 15px;font-size:var(--fs-sm);line-height:1.55;color:var(--text-2);margin:0 0 16px}
/* the level and the in-game name, both from the save. The in-game name is
   muted and separate because it is not the nickname you typed. */
.lvchip{font-size:var(--fs-xs);color:var(--muted);background:var(--surface);border:1px solid var(--border);
  border-radius:var(--r-sm);padding:1px 7px;margin-left:6px;white-space:nowrap;display:inline-block}
.gname{color:var(--muted);font-style:italic}

/* the two ways in, and the world list a folder produces */
.smchoose{display:flex;gap:10px;flex-wrap:wrap;margin-bottom:8px}
.pathrow{display:flex;gap:8px;align-items:center}
.pathrow .mono{flex:1;min-width:0}
.worldlist{display:flex;flex-direction:column;gap:8px;margin:4px 0 4px}
.worldbtn{display:block;width:100%;text-align:left;background:var(--raised);border:1px solid var(--border);
  border-radius:var(--r-lg);padding:12px 15px;cursor:pointer;color:var(--text);transition:border-color var(--t-fast),background var(--t-fast)}
.worldbtn:hover{border-color:var(--accent);background:var(--surface)}
.worldbtn .wname{display:block;font-weight:600;font-size:var(--fs-md);margin-bottom:2px}
.worldbtn .wsub{display:block;color:var(--text-2);font-size:var(--fs-sm);line-height:1.45}
.worldbtn .wpath{display:block;color:var(--muted);font-size:var(--fs-xs);margin-top:3px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* ===================== phones (≤640px) =====================
   Desktop lays these views out as wrap-when-needed flex rows. At phone width
   almost every one of them wraps into a ragged stack of differently-sized
   controls, and a few squeeze a text column down to a couple of characters.
   The rules below give each row one column of equal, full-bleed widths.
   Kept last in the file so they win the equal-specificity ties above. */
@media(max-width:640px){
  /* --- clear the fixed nav bar. These two belong with the bottom-nav rules
         near the top of the file, but their base declarations come later and
         would win the equal-specificity tie, leaving the footer's last line and
         every toast underneath the nav. --- */
  footer{padding-bottom:calc(88px + env(safe-area-inset-bottom))}
  .toasts{bottom:calc(76px + env(safe-area-inset-bottom))}

  /* --- density: desktop gutters cost ~50px of a 390px screen --- */
  .pcard{padding:16px 14px}
  .gcard{padding:18px 16px}
  .gcard ol,.gcard ul{margin:10px 0 10px 18px}
  .modal{padding:20px 16px 24px}
  .setup{position:relative;padding:10px 42px 10px 14px}
  .setup .dismiss{position:absolute;top:5px;right:4px;margin:0}

  /* --- filter/search rows: one full-width control per line --- */
  .controls,.dex-controls{gap:10px}
  .controls>.ctl,
  .dex-controls>.search-inp,.dex-controls>select,.dex-controls>.isel,
  .dex-controls>.toggle,.dex-controls>.segrow{flex:1 1 100%;width:100%;min-width:0;max-width:none}
  .search-inp{width:100%}
  .dex-controls .search-inp,.dex-controls select,.dex-controls .isel{max-width:none}
  .ctl .picker,.ctl select,.ctl .search-inp,.ctl .toggle{width:100%;max-width:none;min-width:0}
  /* an &nbsp; label exists only to bottom-align the desktop row — on a stack
     it renders as a phantom gap above the toggle */
  .controls .ctl label[aria-hidden="true"]{display:none}
  #hatchDepth button,#comboKind button{flex:1 1 0;padding:9px 6px}

  /* --- breed: equal full-width parent slots, swap between them --- */
  .parents{flex-direction:column;align-items:stretch;gap:10px;margin-bottom:4px}
  .parents>.pwrap{max-width:none;width:100%}
  .parents>.pwrap:nth-child(1){order:1}
  .parents>.swap{order:2;align-self:center;margin:0;padding:7px 24px}
  .parents>.pwrap:nth-child(3){order:3}
  .result-zone{margin-top:20px}

  /* --- find parents: wrap the badge instead of crushing names to "An…" --- */
  .pair{flex-wrap:wrap}
  .pair .pside{flex:1 1 128px;min-width:128px}

  /* --- roster: .rospal already wraps its actions (see above); here the header
         buttons stop being pushed into the middle by margin-left:auto --- */
  .collhead .collacts{margin-left:0;width:100%}
  .rosgroup .gentry .acts{margin-left:0}

  /* --- add-pal dialog: three buttons in one row collapsed the primary to a
         73px column of single words --- */
  .formacts{flex-wrap:wrap}
  .formacts .primary{flex:1 1 100%}
  .formacts .alink:not(.primary){flex:1 1 0;text-align:center}

  /* --- planner --- */
  .slotgrid{grid-template-columns:1fr}
  .targetrow .slot,.targetrow .slot.opts{flex:1 1 100%;min-width:0;max-width:none}
  /* same treatment #hatchDepth and #comboKind get above: three equal columns
     that shrink their padding rather than ellipsizing the middle label */
  #partnerMode button{flex:1 1 0;padding:9px 4px}
  /* a catch-list chip carries a tier and a reason now, so at 320px it is a
     paragraph, not a pill — let it wrap inside its own border instead of
     pushing the row sideways */
  .needrow .tchip{white-space:normal;text-align:left}
  .needrow .accr{white-space:normal}
  /* margin-left:auto on a wrapping row gave the ↗ button a whole empty line */
  .rstep{position:relative;--gutter:50px;padding-right:var(--gutter)}
  .rstep .stepopen{position:absolute;top:11px;right:12px;margin-left:0}
  /* the gutter only clears the ↗ on the first line; the panel underneath isn't
     beneath anything, so give it the width back rather than ellipsizing statue
     names 34px early. flex-basis as well as the margin — the base rule pins the
     basis at 100%, so a negative margin alone moves the box without widening
     it. Same custom property throughout so the two can't drift apart. */
  .rstep .wildinfo{flex-basis:calc(100% + var(--gutter) - 16px);margin-right:calc(16px - var(--gutter))}
  .saverow>.search-inp{flex:1 1 100%}
  .planhead .pushr{margin-left:0}

  /* --- pal card: aligned action grid instead of a centred staircase --- */
  .mbtns{display:grid;grid-template-columns:1fr 1fr}
  .mbtns .alink{text-align:center;padding:9px 10px}

  /* --- picker grid: a ★ made starred cells a whole row taller --- */
  .pop .row{position:relative}
  .pop .row .own{position:absolute;top:5px;right:6px}

  /* --- paldex: trim the row (rarity chip, icon, gutters, wrapping headers)
         from 589px down to ~364px, so it fits outright on most phones instead
         of needing 220px of sideways panning --- */
  th{white-space:normal}
  .tname{gap:6px}
  .tname .tier{display:none}
  .tname .pico{width:28px;height:28px;border-width:1px}
  td{padding:6px 4px}th{padding:7px 4px}

  /* --- map: the viewport is the content, so give it the screen. The info
         panel becomes a bottom sheet — at 290px wide it covered half a phone
         and its own markers. --- */
  .mapview{height:calc(100dvh - var(--hh) - 190px);min-height:340px;border-radius:var(--r-lg)}
  .mapbar .mfilters{display:flex}
  .mapbar .mfilters button{flex:1 1 0;padding:9px 6px;justify-content:center}
  .mapinfo{left:8px;right:8px;bottom:8px;width:auto;max-width:none;max-height:56%}
  .maphelp{font-size:10px;padding:4px 10px}
  .mapzoom button{width:32px;height:32px}
  .spawnbar{gap:9px;padding:7px 10px 7px 7px}
  .spawnbar .sb-clear{padding:6px 9px}
  .spawnbar .sbadge{display:none}
  .rg{font-size:10.5px;letter-spacing:.06em}
  /* 83 alphas over a 364px-wide island is dense; give the icons back a little
     of the gap rather than making the user zoom before anything is readable */
  .mk-alpha .g{width:22px;height:22px}
  .mk-fastTravel .g{width:10px;height:10px}
  .mk-tower .g,.mk-middleBoss .g{width:18px;height:18px;font-size:11px}

  /* --- read-a-save dialog: the segmented choice per collision and the
         action row both need one full-width column here --- */
  .confseg{flex-direction:column}
  .confseg button{width:100%}
  .smacts{flex-direction:column}
  .smacts .alink{width:100%;justify-content:center}
  .smlist{max-height:200px}
  .mono{font-size:10px}

  /* --- the two entry buttons and each world row want a full column --- */
  .smchoose{flex-direction:column}
  .smchoose .alink{width:100%;justify-content:center}
  .pathrow{flex-direction:column;align-items:stretch}
}
