/* ═══════════════════════════════════════════════════════════════════════════
   GRID SATCHEL — the Inventory panel as a slot grid (design concept 3).

   Loaded AFTER interface.css and scoped to `body.inv-grid`, so removing the
   class (☰ menu → "Classic pack list") drops every rule here and restores the
   original list with no other change. Pre-change files are backed up in
   backups/ui-pre-gridsatchel-2026-07-28/.

   Only the Inventory panel is touched. Character, Skills, Shop and Map keep
   their existing rendering — the grid is the wrong shape for row content.

   Design language, from the approved mock-up:
     • the pack is 30 discrete SLOTS, so it is drawn as slots, not as a list
     • forged iron: dark slate cells, a rivet lip, 2px rarity-coloured frames
     • the tile carries identity + state (rarity, qty, lock, upgrade, under-req)
     • everything else lives in one detail card, opened by tapping a tile
   ═══════════════════════════════════════════════════════════════════════════ */

body.inv-grid {
  --gsl-ink: #e6ecf2;
  --gsl-dim: #9aa8b6;
  --gsl-cell: linear-gradient(#232830, #171b21);
  --gsl-cell-edge: #3d444e;
  --gsl-frame: linear-gradient(#333a44, #20252c);
  --gsl-gold: #c9a227;
  --gsl-gold-lt: #e8c65a;
}

/* ── the head row: Sell All + sort, unchanged in behaviour, tightened up ──── */
body.inv-grid #panel-body .inv-head {
  display: flex; align-items: center; gap: 6px;
  margin: 0 0 clamp(6px, calc(1.6 * var(--u)), 12px);
}
body.inv-grid #panel-body .inv-head .inv-sellall { flex: none; }
body.inv-grid #panel-body .inv-head select { flex: none; }

/* ── the grid ─────────────────────────────────────────────────────────────
   6 columns on a phone. `auto-fill` with a floor rather than a hard count, so
   a tablet or landscape gets more columns instead of six enormous tiles. */
body.inv-grid .gsl-grid {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: clamp(4px, calc(1.2 * var(--u)), 9px);
  margin-bottom: clamp(6px, calc(1.6 * var(--u)), 12px);
}
@media (min-width: 560px) {
  body.inv-grid .gsl-grid { grid-template-columns: repeat(auto-fill, minmax(clamp(52px, 9vw, 84px), 1fr)); }
}

/* a slot */
body.inv-grid .gsl-cell {
  position: relative;
  aspect-ratio: 1;
  border-radius: clamp(5px, calc(1.4 * var(--u)), 10px);
  display: grid; place-items: center;
  background: var(--gsl-cell);
  border: 2px solid var(--rar, var(--gsl-cell-edge));
  box-shadow: inset 0 1px 0 #ffffff10;
  cursor: pointer;
  /* the whole tile is the tap target — never shrink it below a comfortable one */
  min-height: 44px;
  -webkit-tap-highlight-color: transparent;
}
body.inv-grid .gsl-cell img {
  width: 74%; height: 74%; object-fit: contain;
  image-rendering: pixelated;
  pointer-events: none;
}
/* consumables have no bespoke art — the glyph stands in, sized to the tile */
body.inv-grid .gsl-glyph {
  font-size: clamp(18px, calc(4.6 * var(--u)), 34px);
  line-height: 1; pointer-events: none;
}
body.inv-grid .gsl-dhead .gsl-glyph { font-size: clamp(22px, calc(5.6 * var(--u)), 40px); }
/* empty pack slots: the affordance the list could never show. A player can SEE
   they are about to start auto-selling drops. */
body.inv-grid .gsl-cell.gsl-empty {
  background: #0e1116; border: 2px dashed #333a44; cursor: default;
}
body.inv-grid .gsl-cell.gsl-sel {
  border-color: var(--gsl-gold-lt);
  box-shadow: 0 0 0 2px #f0cd7c55, inset 0 1px 0 #ffffff20;
}

/* ── tile badges ─────────────────────────────────────────────────────────── */
body.inv-grid .gsl-q {          /* stack quantity */
  position: absolute; right: 2px; bottom: 1px;
  font-size: clamp(9px, calc(2.3 * var(--u)), 14px); font-weight: 800; color: #fff;
  text-shadow: 0 1px 2px #000, 0 0 3px #000; pointer-events: none;
}
body.inv-grid .gsl-up {         /* beats what you're wearing */
  position: absolute; left: 2px; top: 2px;
  font-size: clamp(8px, calc(2 * var(--u)), 12px); font-weight: 800;
  color: #0d1a0a; background: #93d68c; border-radius: 3px; padding: 0 2px;
  line-height: 1.35; pointer-events: none;
}
body.inv-grid .gsl-lk {         /* locked — protected from Sell All */
  position: absolute; right: 2px; top: 1px;
  font-size: clamp(9px, calc(2.3 * var(--u)), 13px);
  text-shadow: 0 1px 2px #000; pointer-events: none;
}
/* under-req gear is wearable but at reduced power — an amber floor bar says so
   without needing the detail card open */
body.inv-grid .gsl-cell.gsl-under::after {
  content: ""; position: absolute; inset: auto 0 0 0; height: 3px;
  border-radius: 0 0 3px 3px;
  background: linear-gradient(90deg, #e0a05a00, #e0a05a, #e0a05a00);
  pointer-events: none;
}
/* perishable stock about to spoil */
body.inv-grid .gsl-cell.gsl-spoil::before {
  content: ""; position: absolute; left: 3px; bottom: 3px;
  width: 6px; height: 6px; border-radius: 50%;
  background: #e8801f; box-shadow: 0 0 5px #e8801f;
  pointer-events: none;
}

/* ── the detail card ──────────────────────────────────────────────────────
   Sits in the flow under the grid rather than floating over the world, so it
   can never cover the tiles you are choosing between. */
body.inv-grid .gsl-detail {
  background: linear-gradient(#232830f2, #14171cfb);
  border: 1px solid #3a424c;
  border-top: 2px solid var(--rar, #7d8590);
  border-radius: clamp(6px, calc(1.6 * var(--u)), 12px);
  padding: clamp(7px, calc(1.8 * var(--u)), 13px);
  margin-bottom: clamp(6px, calc(1.6 * var(--u)), 12px);
  box-shadow: 0 3px 14px #0007;
}
body.inv-grid .gsl-dhead { display: flex; align-items: center; gap: clamp(7px, calc(1.8 * var(--u)), 13px); }
body.inv-grid .gsl-dhead img {
  width: clamp(34px, calc(9 * var(--u)), 58px); height: clamp(34px, calc(9 * var(--u)), 58px);
  flex: none; border-radius: 6px; padding: 1px;
  background: #0000004d; border: 2px solid var(--rar, #3d444e);
  image-rendering: pixelated;
}
body.inv-grid .gsl-dbody { flex: 1; min-width: 0; }
body.inv-grid .gsl-dname {
  font-size: clamp(14px, calc(3.6 * var(--u)), 24px); font-weight: 700; line-height: 1.2;
  color: var(--rarInk, var(--gsl-ink));
}
body.inv-grid .gsl-dsub {
  font-size: clamp(11px, calc(2.9 * var(--u)), 18px); color: var(--gsl-dim);
  line-height: 1.35; margin-top: 2px;
}
/* the stat comparison colours from the list view still apply inside the sub-line */
body.inv-grid .gsl-dsub .stat-better { color: #93d68c; }
body.inv-grid .gsl-dsub .stat-worse { color: #e08a7a; }
body.inv-grid .gsl-dsub .req-unmet { color: #e0a05a; }
body.inv-grid .gsl-dsub .hat-flavour { color: #b9a9d8; }
body.inv-grid .gsl-dsub .ii-spoil { color: #cbbf9a; }
body.inv-grid .gsl-dsub .ii-spoil.soon { color: #e8801f; }
body.inv-grid .gsl-dclose {
  flex: none; width: clamp(28px, calc(7 * var(--u)), 44px); height: clamp(28px, calc(7 * var(--u)), 44px);
  display: grid; place-items: center; border-radius: 6px;
  font-size: clamp(13px, calc(3.4 * var(--u)), 20px);
  color: var(--gsl-dim); background: #20252c; border: 1px solid #3a424c; cursor: pointer;
}
/* actions: same set the list row offered, never fewer */
body.inv-grid .gsl-dacts { display: flex; gap: clamp(5px, calc(1.4 * var(--u)), 9px); margin-top: clamp(7px, calc(1.8 * var(--u)), 12px); }
body.inv-grid .gsl-dacts button {
  flex: 1; min-height: clamp(34px, calc(8.6 * var(--u)), 52px);
  border-radius: 6px; cursor: pointer;
  font-size: clamp(12px, calc(3.1 * var(--u)), 19px); font-weight: 700; font-family: inherit;
  color: var(--gsl-ink); background: var(--gsl-frame);
  border: 1px solid #0006; box-shadow: inset 0 1px 0 #ffffff14;
}
body.inv-grid .gsl-dacts button.gsl-primary {
  color: #1a1408; background: linear-gradient(#f0cd7c, #c39633);
  border-color: #7d5a17; box-shadow: inset 0 1px 0 #fff8;
}
body.inv-grid .gsl-dacts button.gsl-danger { color: #e79a8a; border-color: #7a3a30; }

/* nothing selected — a one-line nudge instead of an empty gap */
body.inv-grid .gsl-hint {
  font-size: clamp(11px, calc(2.9 * var(--u)), 18px); color: var(--gsl-dim);
  text-align: center; padding: clamp(5px, calc(1.4 * var(--u)), 10px) 0;
  margin-bottom: clamp(4px, calc(1.2 * var(--u)), 9px);
}

/* section captions between the grids (Consumables / Gear / Materials) */
body.inv-grid .gsl-cap {
  font-size: clamp(9px, calc(2.3 * var(--u)), 14px); font-weight: 800;
  letter-spacing: 1.4px; text-transform: uppercase; color: var(--gsl-dim);
  margin: 0 0 clamp(4px, calc(1.1 * var(--u)), 8px);
  display: flex; align-items: center; gap: 7px;
}
body.inv-grid .gsl-cap::after {
  content: ""; flex: 1; height: 1px; background: #ffffff14;
}

/* the full-pack warning keeps working, just tightened */
body.inv-grid #panel-body .inv-full-hint { margin-bottom: clamp(6px, calc(1.6 * var(--u)), 12px); }

/* ── panel header ─────────────────────────────────────────────────────────
   Concept 3 spent almost nothing on a header; the live panel spends ~68px on a
   34px title before the first item appears. Reclaim most of it, but ONLY on the
   Inventory panel — :has() scopes this to the panel that actually holds a grid,
   so Character/Skills/Shop keep their normal heading. Browsers without :has()
   simply keep the large header; nothing breaks. */
body.inv-grid #panel:has(#panel-body .gsl-grid) .panel-head,
body.inv-grid #panel:has(#panel-body .gsl-hint) .panel-head {
  padding-top: clamp(6px, calc(1.6 * var(--u)), 12px);
  padding-bottom: clamp(6px, calc(1.6 * var(--u)), 12px);
}
body.inv-grid #panel:has(#panel-body .gsl-grid) #panel-title,
body.inv-grid #panel:has(#panel-body .gsl-hint) #panel-title {
  font-size: clamp(15px, calc(3.9 * var(--u)), 26px);
}

/* The card STICKS to the TOP of the scrolling panel, directly under the header, so the
   Equip / Lock / Sell row never scrolls away: pick a slot, keep scrolling the pack, and
   the actions for it are still there. The grid passes underneath, so the background has
   to be fully opaque — a translucent card would ghost tiles through it. */
body.inv-grid .gsl-detail {
  position: sticky; top: 0; z-index: 3;
  background: linear-gradient(#242a33, #171b21);
  box-shadow: 0 6px 18px #000a, 0 1px 0 #ffffff0d inset;
}
/* `top: 0` pins to the scrollport's PADDING box, so .panel-body's own top padding leaves a
   strip above the card where grid rows scroll past in the open. Move that padding off the
   scroll container and onto the head row, and the card pins flush under the panel header. */
body.inv-grid #panel:has(#panel-body .gsl-grid) #panel-body,
body.inv-grid #panel:has(#panel-body .gsl-hint) #panel-body { padding-top: 0; }
body.inv-grid #panel-body .inv-head { padding-top: clamp(10px, calc(2.6 * var(--u)), 16px); }

/* ═══════════════════════════════════════════════════════════════════════════
   VIEW SWITCH — deliberately NOT scoped to body.inv-grid.

   Every other rule in this file is scoped, so dropping the class restores the
   original list exactly. This one block must not be, because the switch is how
   a player gets BACK from list mode to grid mode: if it only existed while the
   grid was on, list mode would be a one-way door with no visible way out.
   ═══════════════════════════════════════════════════════════════════════════ */
.inv-head .inv-skin {
  display: flex; flex: none;
  margin: 0 auto;            /* equal auto margins => centred between its two neighbours */
  border: 1px solid #314733; border-radius: 8px; overflow: hidden;
  background: #0e130d;
}
.inv-head .inv-skin button {
  min-width: clamp(34px, calc(8.4 * var(--u)), 52px);
  min-height: clamp(34px, calc(8.4 * var(--u)), 52px);
  padding: 0 clamp(6px, calc(1.6 * var(--u)), 11px);
  display: grid; place-items: center;
  font-size: clamp(14px, calc(3.6 * var(--u)), 24px); line-height: 1;
  font-family: inherit; cursor: pointer;
  background: transparent; border: 0; color: #7f8d78;
}
.inv-head .inv-skin button + button { border-left: 1px solid #314733; }
.inv-head .inv-skin button.on {
  background: linear-gradient(#3d5a2c, #27401c);
  color: #e8f0d8; box-shadow: inset 0 1px 0 #ffffff1c;
}
.inv-head .inv-skin button:active { background: #1a2416; }
