* { box-sizing: border-box; margin: 0; }
body {
  background: var(--bg);
  color: var(--text);
  font-family: "DM Sans", system-ui, sans-serif;
  font-weight: 600;
  height: 100vh;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

/* app bar */
header {
  height: 34px;
  flex: none;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 0 16px;
  position: relative; /* the quest strip floats over it */
  background: var(--bg-panel);
  border-bottom: 1.5px solid color-mix(in srgb, var(--nm-shadow-r) var(--nm-alpha), var(--bg-panel));
}
h1 { font-size: 1.05rem; font-weight: 800; color: var(--accent); }
.stage-tag { font-family: "JetBrains Mono", monospace; color: var(--text-dim); font-size: .8rem; }

/* two-column layout (mockup 4): doing on the left, context on the right */
.layout { flex: 1; display: flex; min-height: 0; }
.col {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 8px;
  min-height: 0;
  min-width: 0;
  overflow: hidden;
}
#left-col { flex: 0 0 44%; background: var(--bg-panel); border-right: 1.5px solid color-mix(in srgb, var(--nm-shadow-r) var(--nm-alpha), var(--bg-panel)); }
#right-col { flex: 1 1 56%; }

/* left: current activity over the activity grid */
#cur-act { flex: none; max-height: 42%; overflow-y: auto; }
#cur-act .ca-head { display: flex; align-items: center; gap: 8px; }
#cur-act .ca-head .a-icon { width: 24px; height: 24px; font-size: 20px; line-height: 24px; text-align: center; }
#cur-act .ca-head .a-icon .item-icon, #cur-act .ca-head .a-icon img { width: 100%; height: 100%; }
#cur-act .ca-head .name { flex: 1; }
#act-panel {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 6px;
  align-content: start;
  padding-bottom: 30px;
  padding-right: 8px; /* breathing room so the scrollbar doesn't cover cards */
}
#act-panel .ptabs, #act-panel .mat-row, #act-panel .inv-empty,
#act-panel .road-note { grid-column: 1 / -1; }
/* the on-the-road hint (act panel banner + craft bench note) */
.road-note { color: var(--accent-dim); font-size: .74rem; }
#act-panel .card { padding: 8px 9px; gap: 5px; }
#act-panel .act-card .name { font-size: .78rem; }
#act-panel .card-icon { width: 48px; height: 48px; }
#act-panel .act-card .detail { font-size: .68rem; }
#act-panel .recipe { font-size: .68rem; gap: 5px; }
#act-panel .act-card .btn { font-size: .72rem; padding: 3px 6px; }
#act-panel .cmb-big { font-size: 38px; line-height: 1.1; }

/* small panel tabs (activity tabs, center switcher, char card) */
.ptabs { display: flex; gap: 4px; flex: none; }
.ptab { flex: 1; font-size: .8rem; padding: 4px 6px; text-align: center; }
/* the show-all-recipes eye rides the tab row's right edge */
.ptabs .ptab.eye { flex: 0 0 auto; margin-left: auto; padding: 4px 9px; }
.ptab.selected { border-left: 3px solid var(--accent); color: var(--accent); background: var(--bg-elev); }
/* mid tabs (Crafting's skill row): one rung down from the main tabs and one
   up from .sub — a flat chip. Keeps the main tabs' filled, outlined body and
   their accent left edge, but drops the bevel. */
.ptabs.mid { gap: 4px; }
.ptabs.mid .ptab {
  flex: 0 1 auto;
  font-size: .86rem;
  padding: 6px 14px;
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: 5px;
  color: var(--text-dim);
}
.ptabs.mid .ptab:hover { color: var(--accent); background: var(--bg-elev); }
.ptabs.mid .ptab.selected {
  background: var(--bg-elev);
  border-color: var(--accent-dim);
  color: var(--accent);
  /* inset keeps the accent edge from resizing the chip like a border would */
  box-shadow: inset 2px 0 0 var(--accent);
}
/* subtabs (e.g. Processing's): flat underline style, subordinate to main tabs */
.ptabs.sub { gap: 2px; }
.ptabs.sub .ptab {
  flex: 0 0 auto;
  font-size: .8rem;
  padding: 4px 12px;
  background: transparent;
  border: none;
  border-bottom: 2px solid transparent;
  border-radius: 0;
  color: var(--text-dim);
}
.ptabs.sub .ptab:hover { background: transparent; color: var(--accent); }
.ptabs.sub .ptab.selected {
  background: transparent;
  border-bottom-color: var(--accent);
  color: var(--accent);
}

/* per-skill xp strip inside a section header */
.cat-header { display: flex; align-items: center; gap: 8px; }
.xp-strip { display: inline-flex; align-items: center; gap: 6px; margin-left: auto; }
.xp-strip .pbar { width: 70px; height: 4px; }

/* right column: quest strip · center tabs/body · char + sack band */
/* the quest strip floats OVER the top bar, centered — it can outgrow the
   34px bar (the claim button) without getting clipped */
#quest-bar {
  position: absolute;
  left: 50%;
  top: 3px;
  transform: translateX(-50%);
  width: min(560px, 46vw);
  z-index: 40;
  display: flex;
}
#quest-bar .quest-strip { flex: 1; min-width: 0; padding: 3px 12px; }
/* tab body on the left; the Location/Stockpile/Quests tabs stack
   vertically above the shared info panel in the side column */
/* fixed vertical split: the center area and the char/sack band keep the
   same share whatever tab is showing (no jumping panes) */
.center-wrap { flex: 1 1 0; min-height: 0; display: flex; gap: 8px; }
.center-main {
  flex: 1 1 auto;
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
.info-side {
  flex: 0 0 250px;
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
#info-panel { flex: 1 1 0; min-height: 0; overflow-y: auto; }
#info-panel .item-info-col { flex: none; }
.info-bar { display: flex; align-items: center; justify-content: space-between; }
.btn.info-close { font-size: .7rem; padding: 2px 8px; }
#center-tabs { flex: none; }
/* the vertical tab stack: chunky flat rows (these are the app's main
   navigation — they should read at a glance, not whisper); the accent
   edge + fill mark the selected one */
#center-tabs .ptabs { flex-direction: column; gap: 2px; }
#center-tabs .ptab {
  padding: 9px 12px;
  font-size: .95rem;
  font-weight: 700;
  color: var(--text-dim);
  background: var(--bg-raised);
  border: none;
  border-left: 3px solid transparent;
  border-radius: 0 var(--radius) var(--radius) 0;
  text-align: left;
}
#center-tabs .ptab:hover { color: var(--text); background: var(--bg-hover); }
#center-tabs .ptab.selected {
  border-left-color: var(--accent);
  color: var(--accent);
  background: var(--bg-elev);
}
#center-body {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding-bottom: 10px;
}
/* the map square wants every pixel — no tail padding on the location tab */
#center-body:has(.map-row) { padding-bottom: 0; }
.bottom-band { flex: 0 0 40%; min-height: 0; display: flex; gap: 8px; }
/* the sack gets the wider share: its slot grid will grow with upgrades */
#char-card { flex: 46 1 0; min-width: 0; overflow-y: auto; padding: 8px; gap: 6px; }
#sack-card { flex: 54 1 0; min-width: 0; overflow-y: auto; padding: 8px; gap: 6px; }
.char-body { display: flex; flex-direction: column; gap: 6px; min-height: 0; }
.gear-wrap { display: flex; gap: 10px; align-items: flex-start; }
.eq-mini-detail { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 6px; font-size: .84rem; }
.sk-row { display: flex; align-items: center; gap: 8px; font-size: .8rem; }
.sk-row .sk-nm { width: 110px; flex: none; }
/* subskills sit indented under their parent skill */
.sk-row.sub { padding-left: 16px; font-size: .74rem; }
.sk-row.sub .sk-nm { width: 94px; color: var(--text-dim); }
.sk-row .pbar { flex: 1; height: 5px; }
.sk-row .lvl { font-family: "JetBrains Mono", monospace; font-size: .76rem; color: var(--text-dim); width: 20px; text-align: right; }

/* stockpile view: the grid sits on its own lighter backdrop */
.stock-body {
  display: flex;
  flex-direction: column;
  gap: 10px;
  flex: 1 0 auto;
  background: var(--bg-stock);
  border-radius: var(--radius);
  padding: 10px;
}

/* raised neumorphic card. Bevel scheme (everywhere in this file): shadow
   edges are translucent --nm-lit-t blending with whatever is BEHIND the
   element (hence background-clip: padding-box), highlight edges mix
   opaquely with the element's own fill. */
.card {
  background: var(--bg-raised);
  background-clip: padding-box;
  border-top: 1.5px solid color-mix(in srgb, var(--nm-card-top) var(--nm-alpha), var(--bg-raised));
  border-left: 1.5px solid color-mix(in srgb, var(--nm-card-left) var(--nm-alpha), var(--bg-raised));
  border-bottom: 3.5px solid var(--nm-lit-t);
  border-right: 2.5px solid var(--nm-lit-t);
  border-radius: var(--radius);
  padding: 12px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.card.active { border-left: 2.5px solid var(--accent); }
.card .name { font-weight: 800; }
.card .detail { color: var(--text-dim); font-size: .8rem; }
.card .detail.req-missing { color: var(--danger-light); }

/* far-off tiered recipes (5–10 levels out, or eye-revealed): darker than a
   merely-locked card, with a lock silhouette laid over the face */
.card.ghost { position: relative; }
.card.ghost > *:not(.ghost-veil) { opacity: .3; filter: grayscale(.75); }
.ghost-veil {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  background: color-mix(in srgb, var(--bg) 45%, transparent);
  border-radius: var(--radius);
}
.ghost-veil .ghost-lock { width: 34px; height: 34px; opacity: .75; }

.cat-header {
  grid-column: 1 / -1;
  color: var(--accent-dim);
  font-size: .72rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: .08em;
  border-bottom: 1px solid var(--border);
  padding-bottom: 4px;
  margin-top: 6px;
}

.recipe { display: flex; flex-wrap: wrap; gap: 8px; font-size: .78rem; color: var(--text-dim); }
.ing { display: inline-flex; align-items: center; gap: 3px; }
.ing-count { font-family: "JetBrains Mono", monospace; font-size: .72rem; color: var(--text-dim); }
.ing-count.short { color: var(--danger-light); }

/* beveled button */
.btn {
  background: var(--bg-btn);
  background-clip: padding-box;
  color: var(--text);
  border-top: 1.5px solid color-mix(in srgb, var(--nm-shadow) var(--nm-alpha), var(--bg-btn));
  border-left: 1.5px solid color-mix(in srgb, var(--nm-shadow-r) var(--nm-alpha), var(--bg-btn));
  border-bottom: 3.5px solid var(--nm-lit-t);
  border-right: 2.5px solid var(--nm-lit-t);
  border-radius: 6px;
  padding: 6px 10px;
  font-family: inherit;
  cursor: pointer;
  transition: color .2s, background .2s;
}
.btn:hover { color: var(--accent); background: var(--bg-btn-hover); }
.btn:disabled { opacity: .4; cursor: not-allowed; }
.btn:disabled:hover { color: var(--text); background: var(--bg-btn); }
.btn.stop { color: var(--accent); }

/* inset progress bars */
.pbar {
  height: 8px;
  background: var(--bg-inset);
  background-clip: padding-box;
  border-top: 1px solid var(--nm-lit-t);
  border-bottom: 1px solid color-mix(in srgb, var(--nm-shadow) var(--nm-alpha), var(--bg-inset));
  border-radius: 4px;
  overflow: hidden;
}
.pbar-fill { height: 100%; width: 0; background: var(--progress); }

.item-icon { width: 18px; height: 18px; vertical-align: -3px; }
.ui-icon { width: 14px; height: 14px; vertical-align: -2px; }
/* stamina under the walk/run buttons: readout + live bar */
.stam-line { display: flex; align-items: center; gap: 8px; }
.stam-line .stam-bar { flex: 1; height: 6px; }
.stam-line .stam-fill { background: var(--warn-yellow); }
/* a tile's scavengeable finds: wrapping icon list under the Scavenge row */
.scav-finds { display: flex; flex-wrap: wrap; gap: 5px; padding-left: 24px; }
.scav-finds .ui-icon { width: 25px; height: 25px; }
.card-icon { width: 48px; height: 48px; }

/* composed icons (assembled tools): images stack, first on the bottom */
.icon-stack { position: relative; display: inline-block; }
.icon-stack img { position: absolute; inset: 0; width: 100%; height: 100%; }

/* modifiers on inventory slots: icon+tier chips down the left edge */
.slot-mods {
  position: absolute; left: 2px; top: 2px;
  display: flex; flex-direction: column; gap: 1px;
  font-size: .6rem; line-height: 1;
}
.mod-chip { display: inline-flex; align-items: center; gap: 1px; }
.mod-chip .mod-icon, .mod-line .mod-icon { width: 9px; height: 9px; vertical-align: -1px; }
.mod-line .mod-icon { width: 11px; height: 11px; }

/* skill page header: level + xp bar */
.skill-head {
  grid-column: 1 / -1;
  flex-direction: row;
  align-items: center;
  gap: 12px;
  padding: 10px 12px;
}
.skill-head .name { font-size: 1.05rem; }
.skill-head .pbar { flex: 1; height: 6px; }
.skill-head .xp-label { font-family: "JetBrains Mono", monospace; color: var(--text-dim); font-size: .75rem; min-width: 110px; text-align: right; }

/* activity cards: middle-aligned column — name, big icon, time, costs */
/* the card body is clickable: it opens the act's info in the cur-act slot */
.card.act-card {
  align-items: center;
  text-align: center;
  position: relative;
  background: var(--bg-act-card);
  background-clip: padding-box;
  /* different fill than .card, so the highlight self-blend re-mixes */
  border-top-color: color-mix(in srgb, var(--nm-card-top) var(--nm-alpha), var(--bg-act-card));
  border-left-color: color-mix(in srgb, var(--nm-card-left) var(--nm-alpha), var(--bg-act-card));
  cursor: pointer;
}
/* time + xp hug the left edge, mirroring the material ladder on the right */
.act-side {
  position: absolute;
  top: 40%;
  transform: translateY(-50%);
  left: 7px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
  font-size: .72rem;
  line-height: 1.35;
  text-align: left;
}
/* your actual cycle time, tucked under the base time's number */
.act-side .act-real { padding-left: 1.3em; }
/* template cards: the owned-material level ladder, top right */
.mat-reqs {
  position: absolute;
  top: 40%;
  transform: translateY(-50%);
  right: 7px;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 2px;
  font-size: .72rem;
  line-height: 1.35;
}
.mat-req { display: flex; gap: 4px; align-items: center; }
.mat-req .mr-icon, .mat-req .mr-icon img { width: 17px; height: 17px; }
.mat-req .mr-lvl { color: var(--text-dim); }
.mat-req .mr-lvl.unmet { color: var(--warn-orange); }
.card.act-card .pbar, .card.act-card .btn { align-self: stretch; }
.card.act-card .recipe { justify-content: center; }
/* the graphic sits in a lighter inset well, same treatment as a slot */
.card.act-card .icon {
  background: var(--bg-well);
  background-clip: padding-box;
  border-top: 1.5px solid var(--nm-lit-t);
  border-left: 1.5px solid var(--nm-lit-t);
  border-bottom: 1px solid color-mix(in srgb, var(--nm-shadow) var(--nm-alpha), var(--bg-well));
  border-right: 1px solid color-mix(in srgb, var(--nm-shadow-r) var(--nm-alpha), var(--bg-well));
  border-radius: 6px;
  padding: 5px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.card.act-card.locked { opacity: .55; }

/* thin available-tools bar above the activity grid */
.tool-bar {
  grid-column: 1 / -1;
  flex-direction: row;
  align-items: center;
  gap: 6px;
  padding: 5px 10px;
  flex-wrap: wrap;
}
.tool-bar .item-icon { width: 22px; height: 22px; }

.inv-empty { color: var(--text-dim); font-size: .85rem; font-style: italic; }

/* stockpile grid left, dedicated selected-item info box on the right */
.inv-wrap {
  display: flex;
  align-items: flex-start;
  gap: 12px;
}
.inv-wrap .inv-grid { flex: 1; min-width: 0; }
.inv-grid {
  display: grid;
  grid-template-columns: repeat(8, minmax(0, 1fr));
  gap: 8px;
}
.inv-grid.stock-grid { gap: 5px; } /* 8 columns from the .inv-grid base */
/* the sack: one 5-wide row */
.inv-grid.five-wide { grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 6px; }
.slot.equipped { border-color: var(--accent); }
.side-note { font-size: .72rem; margin-top: 6px; }
.stow-btn { margin-top: 8px; flex-wrap: wrap; }
/* the whole-slot Carry: big, full width, on top of the utility panel */
.btn.carry-btn {
  align-self: stretch;
  font-size: .88rem;
  font-weight: 700;
  padding: 5px 10px;
}
/* equip/discard: outside the card like Carry and dressed to match it;
   equip gets the wider share */
.stack-utils.eq-row .btn {
  flex: 1 1 0;
  font-size: .88rem;
  font-weight: 700;
  padding: 5px 8px;
}
.stack-utils.eq-row .btn:first-child { flex: 2 1 0; }
/* the split scissor reads tiny at chip size — scale just the glyph */
.scissor { font-size: 1.25em; line-height: 1; vertical-align: -1px; }
/* compact stack-management strip: small chips, none stretch */
.stack-utils { display: flex; flex-wrap: wrap; gap: 4px; align-items: center; }
.stack-utils .btn {
  flex: 0 0 auto;
  font-size: .72rem;
  padding: 3px 8px;
  white-space: nowrap;
  border-bottom-width: 2px;
  border-right-width: 1.5px;
}
.stack-utils .qty-input { width: 54px; padding: 3px 5px; font-size: .72rem; }
/* quality picker on the management panel */
.q-chip-row { display: flex; gap: 4px; flex-wrap: wrap; }
.q-chip { font-size: .74rem; padding: 3px 8px; color: var(--text-dim); }
.q-chip.q-good { color: var(--q-good); }
.q-chip.q-great { color: var(--q-great); }
.q-chip.selected { background: var(--bg-elev); box-shadow: inset 2px 0 0 var(--accent); }
.stow-btn .btn { white-space: nowrap; }
/* exact-amount field on the stack utility row */
.qty-input {
  width: 56px;
  flex: none;
  background: var(--bg-inset);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 4px 6px;
  font-family: inherit;
  font-size: .78rem;
}
.broken-box { grid-column: 1 / -1; display: flex; flex-direction: column; gap: 12px; }
/* material selectors & per-craft quality toggle */
.mat-row {
  grid-column: 1 / -1;
  flex-direction: row;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  padding: 6px 10px;
}
.btn.cand.selected { border-left: 3px solid var(--accent); color: var(--accent); }
.slot-dur { position: absolute; bottom: 3px; left: 5px; right: 5px; height: 4px; }
/* empty wells share the occupied well color so the grid reads as one
   uniform surface; borders alone mark the vacancy */
.slot.empty { opacity: .8; }
/* per-quality counts in a slot: gray normal, green good, blue great */
.slot-counts {
  position: absolute;
  bottom: 1px;
  right: 4px;
  display: flex;
  gap: 4px;
  font-family: "JetBrains Mono", monospace;
  font-size: .7rem;
}
.qcount.q-normal { color: var(--text-dim); }
/* quality boxes stacked up the right edge, bottom-anchored: normal at the
   bottom, good/great above it; box greys out at 0 */
.slot-counts.fixed {
  left: auto;
  right: 2px;
  bottom: 2px;
  display: flex;
  flex-direction: column-reverse;
  align-items: flex-end;
  gap: 0;
}
.qbox {
  min-width: 14px;
  padding: 0 2px;
  text-align: center;
  line-height: 12px;
  font-size: .62rem;
  border-radius: 4px;
  background: var(--scrim); /* faint dark fill, no outline */
}
.qbox.q0 { color: var(--text-dim); }
.qbox.q1 { color: var(--q-good); }
.qbox.q2 { color: var(--q-great); }
.qbox.zero { opacity: .25; }
.slot.drag-over { border-color: var(--accent); background: var(--bg-well-hover); }
.item-info { width: 250px; flex-shrink: 0; padding: 9px 10px; gap: 4px; }
.info-head { display: flex; gap: 8px; align-items: center; }
.info-head-txt { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
/* per-quality info cards stack in the dedicated box right of the grid */
.item-info-col {
  display: flex;
  flex-direction: column;
  gap: 4px;
  flex: 0 0 210px;
}
.item-info-col .item-info { width: auto; }
.info-icon { width: 48px; height: 48px; }

/* inventory slots: inset wells */
.slot {
  position: relative;
  aspect-ratio: 1;
  background: var(--bg-well);
  background-clip: padding-box;
  border-top: 1.5px solid var(--nm-lit-t);
  border-left: 1.5px solid var(--nm-lit-t);
  border-bottom: 1px solid color-mix(in srgb, var(--nm-shadow) var(--nm-alpha), var(--bg-well));
  border-right: 1px solid color-mix(in srgb, var(--nm-shadow-r) var(--nm-alpha), var(--bg-well));
  border-radius: 6px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.slot.selected { border-color: var(--accent-dim); background: var(--bg-well-sel); }
.slot:not(.empty):hover { background: var(--bg-well-hover); cursor: pointer; }
.slot-icon { width: 60%; height: 60%; }
.slot-count {
  position: absolute;
  bottom: 2px;
  right: 5px;
  font-family: "JetBrains Mono", monospace;
  font-size: .7rem;
  color: var(--text-dim);
}
.slot .q-pip {
  position: absolute;
  top: 3px;
  left: 5px;
  font-family: "JetBrains Mono", monospace;
  font-size: .62rem;
  font-weight: 800;
}
/* quality tints */
.q1, .q-good { color: var(--q-good); }
.q2, .q-great { color: var(--q-great); }
.q-fine { color: var(--q-fine); }
.q-masterful { color: var(--q-masterful); }
.q-legendary { color: var(--q-legendary); }
/* item-info modifier lines: bold + tier color (the title stays plain) */
.card .detail.mod-line { font-weight: 800; }
.card .detail.mod-line.q-fine { color: var(--q-fine); }
.card .detail.mod-line.q-masterful { color: var(--q-masterful); }
.card .detail.mod-line.q-legendary { color: var(--q-legendary); }

/* equipment tab: paper-doll grid + detail pane */
.equip-wrap {
  grid-column: 1 / -1;
  display: flex;
  gap: 16px;
  align-items: flex-start;
}
.eq-doll-card { flex-shrink: 0; }
.eq-doll {
  display: grid;
  grid-template-columns: repeat(3, 52px);
  gap: 6px;
  justify-content: center;
  padding: 4px;
}
.eq-slot { width: 52px; height: 52px; aspect-ratio: auto; cursor: pointer; }
.eq-slot:hover { background: var(--bg-hover); }
.eq-slot.selected { border-color: var(--accent); background: var(--bg-elev); }
.eq-ph { font-size: 22px; opacity: .3; }
.eq-slot.vacant.selected .eq-ph, .eq-slot:hover .eq-ph { opacity: .55; }
.eq-dur {
  position: absolute;
  bottom: 3px;
  left: 5px;
  right: 5px;
  height: 3px;
  background: var(--bg);
  border-radius: 2px;
  overflow: hidden;
}
.eq-dur-fill { height: 100%; background: var(--warn-yellow); }
.eq-detail { flex: 1; min-width: 0; }
.eq-detail-head {
  font-size: .72rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: .08em;
  color: var(--accent-dim);
  border-bottom: 1px solid var(--border);
  padding-bottom: 4px;
}
/* player stats + skill levels card */
.eq-stats { width: 240px; flex-shrink: 0; gap: 4px; }
.eq-stats .eq-detail-head { margin-top: 8px; }
.eq-stats .eq-detail-head:first-child { margin-top: 0; }
.stat-legend { font-size: .7rem; }
/* group heading inside the Stats tab (Combat / Travel / Workmanship) */
.stat-section {
  color: var(--accent-dim);
  font-size: .68rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: .08em;
  border-bottom: 1px solid var(--border);
  padding-bottom: 2px;
  margin-top: 6px;
}
.stat-section:first-of-type { margin-top: 2px; }
.stat-row { display: flex; justify-content: space-between; align-items: baseline; font-size: .82rem; }
.stat-label { color: var(--text-dim); }
.stat-vals { display: inline-flex; gap: 6px; align-items: baseline; }
.stat-base { font-family: "JetBrains Mono", monospace; font-size: .78rem; color: var(--text-dim); }
.stat-base::after { content: ' →'; }
.stat-full { font-family: "JetBrains Mono", monospace; font-size: .82rem; font-weight: 800; }
.stat-full.boosted { color: var(--accent); }
.skill-lvls { display: flex; flex-direction: column; gap: 2px; }
.equipped-item { display: inline-flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.btn.cand { font-size: .8rem; padding: 4px 8px; }
.tool-bar .item-icon { cursor: pointer; }
.item-icon.equipped { outline: 2px solid var(--accent); border-radius: 4px; }
.pool-locked { opacity: .45; }

/* broken tools */
.broken-row {
  grid-column: 1 / -1;
  flex-direction: row;
  align-items: center;
  gap: 10px;
  padding: 6px 12px;
}
.broken-row .name { flex: 1; }

/* durability bar */
.dur-bar { height: 5px; width: 90px; display: inline-block; vertical-align: middle; }
.dur-fill { background: var(--warn-yellow); }

.flavor { grid-column: 1 / -1; font-style: italic; color: var(--text-dim); opacity: .9; }

#toasts { position: fixed; bottom: 16px; right: 16px; display: flex; flex-direction: column; gap: 6px; max-width: 340px; }
.toast {
  background: var(--toast-bg);
  background-clip: padding-box;
  border-top: 1.5px solid color-mix(in srgb, var(--nm-card-top) var(--nm-alpha), var(--toast-bg));
  border-left: 3px solid var(--accent);
  border-bottom: 3px solid var(--nm-lit-t);
  border-right: 2px solid var(--nm-lit-t);
  border-radius: 6px;
  padding: 8px 12px;
  font-size: .85rem;
}
.toast.alert { border-left-color: var(--danger); }
.toast.rare { border-left-color: var(--q-masterful); }

::-webkit-scrollbar { width: 6px; height: 6px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }
::-webkit-scrollbar-thumb:hover { background: var(--text-dim); }

/* ---- world map (Location tab) ---- */
/* no container: the grid floats in the tab body, sized from JS every frame
   to the biggest square that fits the frame (locationPage.js) */
.flash { box-shadow: 0 0 0 2px var(--accent); }
.map-row { flex: 1; min-height: 0; display: flex; gap: 8px; }
.map-frame {
  flex: 1;
  min-width: 0;
  min-height: 0;
  display: flex;
  justify-content: center;
  align-items: flex-start;
}
.zoom-col { display: flex; flex-direction: column; gap: 4px; flex: none; }
.zoom-btn { padding: 2px 8px; font-size: .75rem; }
.map-grid {
  position: relative; /* the travel layer overlays it */
  flex: none;
  display: grid;
  gap: 2px;
  background: var(--map-fog);
  background-clip: padding-box;
  padding: 4px;
  border-radius: 6px;
  border-top: 1px solid var(--nm-lit-t);
  border-bottom: 1px solid color-mix(in srgb, var(--nm-shadow) var(--nm-alpha), var(--map-fog));
}
.tile {
  position: relative;
  aspect-ratio: 1;
  border-radius: 4px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1rem;
  cursor: pointer;
  border: 1px solid rgba(0, 0, 0, .35);
  transition: filter .1s, outline-color .1s;
}
.tile:hover { filter: brightness(1.25); }
.tile.selected { outline: 2px solid var(--accent); outline-offset: -1px; z-index: 2; }
.tile.player::after {
  content: '';
  position: absolute;
  inset: 3px;
  border: 2px solid var(--player-ring);
  border-radius: 50%;
}
/* fog of war (data/locations.js tileVis): visited/in-sight = full color;
   seen = biome only, dimmed; unknown = a flat dark grey (the biome tiles
   share one lightness, so killing saturation hides which biome it is).
   .lit is the walker's live sight during travel — full reveal wins. */
.tile.seen {
  filter: saturate(.45) brightness(.75);
  box-shadow: inset 0 0 8px 2px rgba(0, 0, 0, .3); /* vignette */
}
.tile.seen:hover { filter: saturate(.6) brightness(.9); }
.tile.unknown { filter: saturate(0) brightness(.42); }
.tile.unknown:hover { filter: saturate(0) brightness(.52); }
.tile.lit, .tile.lit:hover { filter: none; box-shadow: none; }
/* stored-item count on visited tiles — where the bases are */
.tile-n {
  position: absolute;
  right: 1px;
  bottom: 1px;
  font-family: "JetBrains Mono", monospace;
  font-size: .58rem;
  line-height: 1;
  padding: 1px 3px;
  border-radius: 4px;
  background: var(--scrim);
  color: var(--text);
}
.biome-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 2px 8px;
  border-radius: 10px;
  font-size: .78rem;
  background: var(--badge-bg);
  border: 1px solid var(--border);
}
.biome-chip .dot { width: 8px; height: 8px; border-radius: 50%; }
.kv { display: flex; justify-content: space-between; font-size: .8rem; }
.kv .k { color: var(--text-dim); }
.kv .v { font-family: "JetBrains Mono", monospace; font-size: .78rem; }
.node-row { display: flex; align-items: center; gap: 7px; padding: 2px 6px; border-radius: 6px; font-size: .84rem; }
.node-row.clickable { cursor: pointer; }
.node-row.clickable:hover { background: var(--bg-hover); color: var(--accent); }
.node-row .n-go { margin-left: auto; font-size: .66rem; color: var(--text-dim); font-family: "JetBrains Mono", monospace; }
.node-row .recipe { margin-left: auto; }

/* ---- combat (the Combat tab's fight panels + monster cards) ---- */
.cmb-big { font-size: 40px; line-height: 1.1; text-align: center; }
.cmb-bar-wrap { position: relative; }
.cmb-wrap { grid-column: 1 / -1; display: flex; gap: 12px; align-items: stretch; }
.cmb-panel { flex: 1; min-width: 0; border-top: 3px solid var(--q-good); }
.cmb-panel.enemy { border-top-color: var(--danger); }
.cmb-panel .cmb-big { font-size: 44px; }
.cmb-bar-label {
  display: flex; justify-content: space-between;
  font-family: "JetBrains Mono", monospace; font-size: .72rem;
  color: var(--text-dim); margin-bottom: 2px;
}
.cmb-respawn { text-align: center; color: var(--text-dim); font-size: .8rem; min-height: 18px; }
.cmb-stat-row { display: flex; justify-content: space-between; font-size: .8rem; color: var(--text-dim); }
.cmb-stat-row .val { font-family: "JetBrains Mono", monospace; color: var(--text); }
#act-panel .flavor { grid-column: 1 / -1; }
.cmb-atk { height: 4px; }
.cmb-atk .pbar-fill { background: var(--accent); transition: width .05s linear; }
.pbar-fill.hp-enemy { background: var(--danger); transition: width .1s linear; }
.pbar-fill.hp-me { background: var(--q-good); transition: width .1s linear; }
.cmb-splats { position: absolute; inset: 0; pointer-events: none; overflow: visible; }
.cmb-splat {
  position: absolute; top: -4px; font-family: "JetBrains Mono", monospace;
  font-weight: 800; font-size: .9rem; color: var(--danger-light);
  animation: cmbSplat .9s ease-out forwards;
}
.cmb-splat.miss { color: var(--text-dim); }
.cmb-splat.block { color: var(--q-great); }
.cmb-splat.heal { color: var(--q-good); }

/* ---- eating ---- */
.eat-wrap { margin-top: 6px; }
.eat-wrap .pbar { height: 6px; }
.pbar-fill.eat-fill { background: var(--q-good); transition: width .1s linear; }
.food-strip { margin-top: 6px; }
/* quick-eat minis: 8-up like the stockpile, just tighter */
.inv-grid.food-row { gap: 4px; margin-top: 4px; }
@keyframes cmbSplat {
  from { transform: translateY(0); opacity: 1; }
  to { transform: translateY(-24px); opacity: 0; }
}

/* ---- quests ---- */
.quest-glow { box-shadow: 0 0 0 1.5px var(--warn-orange); animation: qpulse 1.8s ease-in-out infinite; }
@keyframes qpulse { 50% { box-shadow: 0 0 8px 1px var(--warn-orange); } }
#quest-bar:empty { display: none !important; }
.quest-strip {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 2px 10px;
  border-radius: var(--radius);
  background: var(--bg-panel);
  background-clip: padding-box;
  border-top: 1.5px solid color-mix(in srgb, var(--nm-card-top) var(--nm-alpha), var(--bg-panel));
  border-bottom: 2px solid var(--nm-lit-t);
  box-shadow: 0 0 0 1.5px var(--accent-dim);
  cursor: pointer;
  font-size: .88rem;
}
.quest-strip:hover { background: var(--bg-hover); }
.quest-strip .q-label { font-size: .72rem; color: var(--accent-dim); font-weight: 800; text-transform: uppercase; letter-spacing: .08em; }
.quest-strip .q-name { font-weight: 800; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; display: inline-flex; align-items: center; gap: 6px; }
.quest-strip .q-name.ready { color: var(--accent); }
.quest-strip .pbar { width: 130px; flex: none; }
.q-count { font-family: "JetBrains Mono", monospace; font-size: .78rem; color: var(--text-dim); }
.btn.claim { color: var(--accent); font-weight: 800; }
.quest-strip .btn.claim { margin-left: auto; padding: 3px 12px; white-space: nowrap; }
/* the current-quest card gets a whisper of the strip's accent ring */
.cq-current {
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--accent-dim) 45%, transparent);
}
#quest-cur { flex: none; }
#quest-cur .btn.claim { align-self: flex-start; padding: 8px 14px; }
#quest-list { flex: none; gap: 3px; }
.cq-name { font-size: 1.02rem; font-weight: 800; display: flex; align-items: center; gap: 8px; }
.cq-goal { display: flex; align-items: center; gap: 10px; }
.cq-goal .pbar { flex: 1; max-width: 340px; }
.cq-reward { font-size: .8rem; display: flex; align-items: center; gap: 5px; flex-wrap: wrap; }
.cq-reward b { color: var(--warn-yellow); font-weight: 700; }
/* reward chips: the actual goods — icon ×count, grade-tinted; xp in blue */
.rw-chip {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  background: var(--badge-bg);
  border-radius: 5px;
  padding: 2px 6px;
  font-size: .8rem;
  white-space: nowrap;
}
.rw-chip .rw-n { font-family: "JetBrains Mono", monospace; font-size: .74rem; }
.rw-chip.q-good .rw-n { color: var(--q-good); }
.rw-chip.q-great .rw-n { color: var(--q-great); }
.rw-chip.rw-xp { color: var(--xp); font-size: .74rem; }
.qrow .q-rw .rw-chip { padding: 1px 4px; font-size: .72rem; }
.quest-strip .rw-strip { display: inline-flex; gap: 4px; min-width: 0; }
.qrow { display: flex; align-items: center; gap: 8px; padding: 2px 6px; border-radius: 6px; font-size: .85rem; cursor: pointer; }
.qrow.picked { box-shadow: inset 2px 0 0 var(--accent-dim); background: var(--bg-elev); }
.qrow .q-ic { width: 22px; text-align: center; flex: none; }
.qrow.done { color: var(--text-dim); }
.qrow.done .q-check { color: var(--q-good); }
.qrow.cur { background: var(--bg-elev); border-left: 3px solid var(--accent); }
.qrow.cur .q-nm { color: var(--accent); font-weight: 800; }
.qrow.future { color: var(--text-dim); opacity: .75; }
.qrow .q-check { font-family: "JetBrains Mono", monospace; font-size: .76rem; }
.qrow .q-rw { font-size: .7rem; color: var(--text-dim); margin-left: auto; text-align: right; }
.quest-done-banner { text-align: center; font-size: 1rem; color: var(--accent); padding: 18px 0; }

/* ---- craft setup (current-activity panel, ui/craftPanel.js) ---- */
/* tinkers-style bench: part squares (head over handle) — flow arrow
   through the catalyst — result preview, stats beside */
#cur-act.craft-setup { max-height: 42%; }
.craft-body { display: flex; align-items: center; gap: 10px; }
.craft-slots { display: flex; flex-direction: column; gap: 6px; flex: none; }
.slot-wrap { display: flex; flex-direction: column; align-items: center; gap: 2px; }
.cs-label {
  font-size: .62rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: .08em;
  color: var(--text-dim);
}
.craft-slot {
  position: relative;
  width: 62px;
  height: 62px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg-inset);
  border: 1.5px solid var(--border);
  border-radius: var(--radius);
  color: var(--text);
  cursor: pointer;
  font: inherit;
}
.craft-slot:hover { border-color: var(--accent); background: var(--bg-hover); }
.craft-slot.disabled { opacity: .45; cursor: default; }
.craft-slot.disabled:hover { border-color: var(--border); background: var(--bg-inset); }
/* picked grade colors the slot */
.craft-slot.q-good { border: 1.5px solid var(--q-good); }
.craft-slot.q-great { border: 1.5px solid var(--q-great); }
.craft-slot .cs-icon { width: 28px; height: 28px; }
.craft-slot .cs-blank { font-size: 18px; color: var(--text-dim); }
.craft-slot .cs-mat {
  position: absolute;
  bottom: 2px;
  left: 2px;
  right: 2px;
  text-align: center;
  font-size: .6rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.craft-slot .cs-cnt {
  position: absolute;
  top: 2px;
  right: 4px;
  font-size: .58rem;
  color: var(--text-dim);
}
.craft-slot .cs-cnt.req-missing { color: var(--danger-light); }
/* the flow arrow: starts right of the parts, runs through the catalyst
   square, points at the output */
.craft-flow {
  position: relative;
  flex: 0 0 92px;
  align-self: center;
  height: 62px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.craft-flow::before {
  content: '';
  position: absolute;
  left: 0;
  right: 8px;
  top: 50%;
  border-top: 2px solid var(--text-dim);
}
.craft-flow::after {
  content: '';
  position: absolute;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  border: 6px solid transparent;
  border-left: 9px solid var(--text-dim);
}
.craft-flow .craft-slot.catalyst { width: 46px; height: 46px; z-index: 1; }
.craft-out {
  flex: 0 0 auto;
  max-width: 130px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  text-align: center;
}
.craft-out-icon { width: 44px; height: 44px; }
.craft-out .name { font-size: .8rem; }
.craft-stats {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
  border-left: 1px solid var(--border);
  padding-left: 10px;
}
.btn.craft-start { font-weight: 800; }

/* ---- one-time welcome popup (ui/tutorial.js) ---- */
#tutorial-pop { position: fixed; inset: 0; z-index: 70; }
.tut-backdrop { position: absolute; inset: 0; background: var(--scrim); }
.tut-panel {
  position: absolute;
  left: 50%;
  top: 38%;
  transform: translate(-50%, -50%);
  width: min(440px, 92vw);
  display: grid;
  gap: 12px;
  padding: 18px 20px;
}
.tut-body { color: var(--text-dim); line-height: 1.45; }
.tut-go { justify-self: center; padding: 8px 22px; color: var(--accent); font-weight: 800; }

/* ---- bug report / feedback dialog (ui/feedback.js) ---- */
#feedback-pop { position: fixed; inset: 0; z-index: 70; }
.fb-panel {
  position: absolute;
  left: 50%;
  top: 34%;
  transform: translate(-50%, -50%);
  width: min(420px, 92vw);
  display: grid;
  gap: 10px;
  padding: 14px 16px;
}
.fb-text {
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 8px 10px;
  font: inherit;
  min-height: 110px;
  resize: vertical;
}
.fb-text:focus { outline: 1px solid var(--accent); }
.fb-btns { display: flex; justify-content: flex-end; gap: 8px; }
.fb-send { color: var(--accent); font-weight: 800; }

/* ---- material picker overlay (ui/matPicker.js) ---- */
#mat-picker { position: fixed; inset: 0; z-index: 60; }
#mat-picker .mp-backdrop { position: absolute; inset: 0; background: var(--scrim); }
#mat-picker .mp-panel {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 320px;
  max-width: 85vw;
  background: var(--bg-panel);
  background-clip: padding-box;
  border-right: 2.5px solid var(--nm-lit-t);
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 12px;
  overflow: hidden;
}
#mat-picker .mp-head { display: flex; align-items: center; }
#mat-picker .mp-head .name { flex: 1; }
#mat-picker .mp-close { padding: 2px 8px; }
#mat-picker .mp-list {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.mp-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 8px;
  background: var(--bg-raised);
  border: 1px solid var(--border);
  border-radius: 6px;
  color: var(--text);
  font: inherit;
  font-size: .82rem;
  text-align: left;
  cursor: pointer;
}
.mp-row:hover:not(:disabled) { background: var(--bg-hover); border-color: var(--accent); }
.mp-row:disabled { opacity: .5; cursor: default; }
.mp-row .mp-name { flex: 1; min-width: 0; }
.mp-row .mp-count { font-family: "JetBrains Mono", monospace; font-size: .76rem; color: var(--text-dim); }
.mp-row .mp-src { font-size: .8rem; }

/* walk/run travel buttons side by side */
.travel-btns { display: flex; gap: 8px; }
.travel-btns .btn { flex: 1; }

/* ---- juice (js/ui/fx.js) ---- */
/* a cycle completes: the bar flashes and the activity icon takes the hit */
.pbar.fx-pop { animation: fxPop .32s ease-out; }
@keyframes fxPop {
  0% { background: var(--fx-flash); box-shadow: 0 0 8px 2px var(--fx-glow); }
  100% { background: var(--bg-inset); box-shadow: 0 0 0 0 transparent; }
}
.fx-squash { display: inline-block; animation: fxSquash .3s ease-out; }
@keyframes fxSquash {
  0% { transform: none; }
  30% { transform: scale(1.28, .78); }
  62% { transform: scale(.9, 1.12); }
  100% { transform: none; }
}

/* the yield arcs from the bar into the stockpile tab, which pulses on landing */
.fx-fly {
  position: fixed;
  z-index: 60;
  width: 26px;
  height: 26px;
  pointer-events: none;
  filter: drop-shadow(0 2px 6px rgba(0, 0, 0, .6));
}
.fx-fly img, .fx-fly .item-icon { width: 100%; height: 100%; vertical-align: top; }
/* a reward stack in flight: icon with its ×count riding along */
.fx-fly .fx-fly-stack { position: relative; display: block; width: 100%; height: 100%; }
.fx-fly .fx-fly-n {
  position: absolute;
  right: -10px;
  bottom: -6px;
  font-family: "JetBrains Mono", monospace;
  font-size: .72rem;
  font-weight: 700;
  color: var(--text);
  text-shadow: 0 1px 3px rgba(0, 0, 0, .8);
}
.fx-fly.q-good { filter: drop-shadow(0 0 5px var(--q-good)); }
.fx-fly.q-great { filter: drop-shadow(0 0 5px var(--q-great)); }
.fx-fly.q-fine { filter: drop-shadow(0 0 5px var(--q-fine)); }
.fx-fly.q-masterful { filter: drop-shadow(0 0 6px var(--q-masterful)); }
.fx-fly.q-legendary { filter: drop-shadow(0 0 7px var(--q-legendary)); }
/* an empty pool roll drifts up off the activity bar */
.fx-nothing {
  position: fixed;
  z-index: 60;
  font-size: .78rem;
  color: var(--text-dim);
  pointer-events: none;
}
.fx-land { animation: fxLand .32s ease-out; }
@keyframes fxLand {
  0% { transform: scale(1); }
  40% { transform: scale(1.09); color: var(--accent); }
  100% { transform: scale(1); }
}

/* level-up: the one banner that interrupts, briefly */
.fx-level {
  position: fixed;
  top: 56px;
  left: 50%;
  z-index: 70;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 20px;
  background: var(--bg-elev);
  border: 1.5px solid var(--accent);
  border-radius: 10px;
  box-shadow: 0 8px 28px rgba(0, 0, 0, .55), 0 0 18px var(--fx-glow);
  pointer-events: none;
  animation: fxLevel 2.9s ease-out forwards;
}
.fx-level-icon { font-size: 26px; line-height: 1; }
.fx-level-title { font-weight: 800; font-size: .95rem; }
.fx-level-title .lvl {
  color: var(--accent);
  font-family: "JetBrains Mono", monospace;
  font-size: 1.15rem;
  font-weight: 800;
}
.fx-level-unlocks { color: var(--text-dim); font-size: .76rem; margin-top: 2px; }
@keyframes fxLevel {
  0% { opacity: 0; transform: translate(-50%, -18px) scale(.92); }
  8% { opacity: 1; transform: translate(-50%, 0) scale(1.05); }
  15% { transform: translate(-50%, 0) scale(1); }
  82% { opacity: 1; transform: translate(-50%, 0) scale(1); }
  100% { opacity: 0; transform: translate(-50%, -10px) scale(.98); }
}

/* ---- combat weight (ui/fx.js hit/kill) ---- */
/* the struck panel flashes and flinches; a block just rings */
.fx-hit { animation: fxHit .26s ease-out; }
@keyframes fxHit {
  0% { background: var(--fx-flash); transform: translateX(0); }
  25% { transform: translateX(-3px); }
  55% { transform: translateX(3px); }
  80% { transform: translateX(-1px); }
  100% { transform: translateX(0); }
}
.fx-block { animation: fxBlock .28s ease-out; }
@keyframes fxBlock {
  0% { box-shadow: 0 0 0 2px var(--q-great); }
  100% { box-shadow: 0 0 0 0 transparent; }
}
/* taking one shoves the whole board */
.fx-nudge { animation: fxNudge .26s ease-out; }
@keyframes fxNudge {
  0%, 100% { transform: translate(0, 0); }
  30% { transform: translate(4px, -2px); }
  65% { transform: translate(-3px, 2px); }
}
/* the corpse drops out of the panel */
.fx-slain { animation: fxSlain .62s ease-in forwards; }
@keyframes fxSlain {
  0% { transform: none; opacity: 1; filter: none; }
  20% { transform: scale(1.14) rotate(-6deg); filter: brightness(2.4); }
  100% { transform: translateY(26px) scale(.6) rotate(24deg); opacity: 0; }
}
/* chip damage: the pale bar the real one leaves behind */
.pbar.cmb-hp { position: relative; }
.pbar.cmb-hp .pbar-fill { position: absolute; top: 0; bottom: 0; left: 0; }
.pbar-fill.chip { background: var(--danger-light); opacity: .5; }

/* ---- animated travel (ui/locationPage.js) ---- */
/* clipped: a far destination's line/token must not spill past the map */
.map-travel { position: absolute; inset: 0; pointer-events: none; z-index: 3;
  overflow: hidden; border-radius: 6px; }
.travel-line { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.travel-line line {
  stroke: var(--accent);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-dasharray: 3 7;
  opacity: .75;
  animation: travelDash 1s linear infinite;
}
@keyframes travelDash { to { stroke-dashoffset: -20; } }
.travel-token {
  position: absolute;
  transform: translate(-50%, -50%);
  font-size: 15px;
  line-height: 1;
  filter: drop-shadow(0 0 5px var(--fx-glow));
  animation: travelBob .5s ease-in-out infinite alternate;
}
@keyframes travelBob { to { transform: translate(-50%, -62%); } }
/* the player ring, riding with the walker instead of the tile you left */
.travel-ring {
  position: absolute;
  transform: translate(-50%, -50%);
  box-sizing: border-box;
  border: 2px solid var(--player-ring);
  border-radius: 50%;
}
.map-grid.travelling .tile.player::after { display: none; }
.travel-dest {
  position: absolute;
  width: 14px;
  height: 14px;
  margin: -7px 0 0 -7px;
  border: 2px solid var(--accent);
  border-radius: 50%;
  animation: destPulse 1.2s ease-in-out infinite;
}
@keyframes destPulse {
  50% { transform: scale(1.55); opacity: .35; }
}

/* ---- offline return screen (ui/fx.js offline) ---- */
.fx-offline-scrim {
  position: fixed;
  inset: 0;
  z-index: 80;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--scrim);
  backdrop-filter: blur(2px);
  animation: fxFade .2s ease-out;
}
@keyframes fxFade { from { opacity: 0; } }
.fx-offline {
  width: min(440px, 92vw);
  max-height: 82vh;
  overflow-y: auto;
  padding: 18px 20px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  background: var(--bg-elev);
  border: 1.5px solid var(--accent);
  border-radius: 12px;
  box-shadow: 0 14px 44px rgba(0, 0, 0, .6), 0 0 20px var(--fx-glow);
  animation: fxRise .28s cubic-bezier(.2, .9, .3, 1.2);
}
@keyframes fxRise { from { opacity: 0; transform: translateY(16px) scale(.96); } }
.fx-off-head { font-size: 1.05rem; font-weight: 800; }
.fx-off-sub { color: var(--text-dim); font-size: .8rem; margin-top: -6px; }
.fx-off-items {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(64px, 1fr));
  gap: 6px;
}
.fx-off-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  padding: 7px 2px;
  border-radius: 8px;
  background: var(--bg-well);
  animation: fxRise .3s ease-out backwards;
}
.fx-off-icon { width: 26px; height: 26px; }
.fx-off-n { font-family: "JetBrains Mono", monospace; font-size: .8rem; }
.fx-off-item.q-good .fx-off-n { color: var(--q-good); }
.fx-off-item.q-great .fx-off-n { color: var(--q-great); }
.fx-off-xps { display: flex; flex-direction: column; gap: 3px; }
.fx-off-xp { display: flex; align-items: center; gap: 7px; font-size: .82rem; }
.fx-off-skill { color: var(--text-dim); }
.fx-off-gain {
  margin-left: auto;
  font-family: "JetBrains Mono", monospace;
  font-size: .78rem;
  color: var(--xp);
}
.fx-off-xp .lvl {
  font-family: "JetBrains Mono", monospace;
  font-size: .72rem;
  color: var(--accent);
  border: 1px solid var(--accent-dim);
  border-radius: 8px;
  padding: 0 5px;
}
.fx-off-collect { align-self: stretch; padding: 8px; font-size: .92rem; }

/* ---- living map tiles (ui/locationPage.js) ---- */
.tile { transition: filter .1s, outline-color .1s, transform .12s, box-shadow .12s; }
.tile:hover {
  transform: translateY(-2px) scale(1.05);
  box-shadow: 0 4px 10px rgba(0, 0, 0, .55);
  z-index: 4;
}
/* the player ring breathes so your own position never gets lost in the grid */
.tile.player::after { animation: playerBreathe 2.4s ease-in-out infinite; }
@keyframes playerBreathe {
  50% { inset: 1px; opacity: .6; box-shadow: 0 0 6px 1px var(--player-ring); }
}
/* what the tile offers, peeking out of its corner */
.tile-marks {
  position: absolute;
  top: 1px;
  left: 2px;
  font-size: .52rem;
  line-height: 1;
  letter-spacing: -1px;
  opacity: .7;
  pointer-events: none;
  text-shadow: 0 1px 2px rgba(0, 0, 0, .8);
}
.tile:hover .tile-marks { opacity: 1; }

/* ---- rare craft (ui/fx.js rare) ---- */
/* the edges of the screen take the tier color */
.fx-rare-glow {
  position: fixed;
  inset: 0;
  z-index: 65;
  pointer-events: none;
  animation: fxRareGlow 1.5s ease-out forwards;
}
.fx-rare-glow.q-fine { --rare: var(--q-fine); }
.fx-rare-glow.q-masterful { --rare: var(--q-masterful); }
.fx-rare-glow.q-legendary { --rare: var(--q-legendary); }
@keyframes fxRareGlow {
  0% { box-shadow: inset 0 0 0 0 var(--rare); opacity: 0; }
  18% { box-shadow: inset 0 0 120px 18px var(--rare); opacity: .85; }
  100% { box-shadow: inset 0 0 60px 4px var(--rare); opacity: 0; }
}
/* ...and the item itself slams down in the middle of it */
.fx-rare {
  position: fixed;
  top: 42%;
  left: 50%;
  z-index: 66;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  pointer-events: none;
  animation: fxRareSlam 1.25s cubic-bezier(.2, .8, .2, 1) forwards;
}
.fx-rare-icon { width: 72px; height: 72px; }
.fx-rare .fx-rare-name {
  font-weight: 800;
  font-size: 1rem;
  letter-spacing: .04em;
  text-shadow: 0 2px 10px #000;
}
.fx-rare.q-fine .fx-rare-name { color: var(--q-fine); }
.fx-rare.q-masterful .fx-rare-name { color: var(--q-masterful); }
.fx-rare.q-legendary .fx-rare-name { color: var(--q-legendary); }
.fx-rare.q-fine .fx-rare-icon { filter: drop-shadow(0 0 12px var(--q-fine)); }
.fx-rare.q-masterful .fx-rare-icon { filter: drop-shadow(0 0 14px var(--q-masterful)); }
.fx-rare.q-legendary .fx-rare-icon { filter: drop-shadow(0 0 18px var(--q-legendary)); }
@keyframes fxRareSlam {
  0% { opacity: 0; transform: translate(-50%, -140%) scale(2.6); }
  22% { opacity: 1; transform: translate(-50%, -50%) scale(1); }
  30% { transform: translate(-50%, -50%) scale(1.12); }
  38% { transform: translate(-50%, -50%) scale(1); }
  88% { opacity: 1; transform: translate(-50%, -50%) scale(1); }
  100% { opacity: 0; transform: translate(-50%, -56%) scale(.9); }
}

/* ---- breakage (ui/fx.js break/spare) ---- */
/* the screen bleeds at the edges for a moment */
.fx-vignette {
  position: fixed;
  inset: 0;
  z-index: 64;
  pointer-events: none;
  animation: fxVignette .7s ease-out forwards;
}
@keyframes fxVignette {
  0% { box-shadow: inset 0 0 0 0 var(--danger); opacity: 0; }
  15% { box-shadow: inset 0 0 90px 14px var(--danger); opacity: .9; }
  100% { box-shadow: inset 0 0 40px 2px var(--danger); opacity: 0; }
}
/* the tool comes apart inside its paperdoll slot */
.fx-shatter {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  animation: fxShatter .72s ease-in forwards;
}
@keyframes fxShatter {
  0% { transform: none; opacity: 1; filter: none; }
  12% { transform: scale(1.25) rotate(-9deg); filter: brightness(2.6) saturate(0); }
  30% { transform: scale(1.05) rotate(7deg); }
  100% { transform: translateY(20px) scale(.35) rotate(46deg); opacity: 0; }
}
/* the sack's save, made visible: the spare drops into the empty slot */
.fx-swapin { animation: fxSwapIn .62s cubic-bezier(.2, .9, .3, 1.3); }
@keyframes fxSwapIn {
  0% { box-shadow: 0 0 0 2px var(--accent); transform: translateY(-9px) scale(.8); }
  55% { box-shadow: 0 0 10px 2px var(--fx-glow); transform: translateY(0) scale(1.08); }
  100% { box-shadow: 0 0 0 0 transparent; transform: none; }
}
