.board-wrap { position: relative; padding: 10px; border-radius: 6px; width: max-content; max-width: 100%;
  background: radial-gradient(ellipse at 50% 40%, #1d1710, #0a0806 75%); box-shadow: inset 0 0 0 1px #000, inset 0 0 30px rgba(0,0,0,.8), 0 0 0 1px var(--edge); }
.board { position: relative; width: calc(var(--cell) * 9); height: calc(var(--cell) * 7); touch-action: none;
  background-image: none; }
/* no lattice on the empty board (only bag cells are slots); dots show only while a bag is dragged (drag.js body.drag-bag) */
body.drag-bag .board { background-image: radial-gradient(circle at center, rgba(201,162,74,.18) 1.2px, transparent 1.6px); background-size: var(--cell) var(--cell); }

.piece { position: absolute; pointer-events: none; }
.piece .cell { position: absolute; pointer-events: auto; touch-action: none; cursor: grab; }
.piece .frame { position: absolute; pointer-events: none; border-radius: 5px; }

/* bags: stitched leather with sunken WoW-style slots */
.piece.bag { z-index: 1; }
/* per-bag skins: boardView sets --bag-a/b/c (leather), --bag-trim, --bag-stitch, --bag-glow and a .pat-* class */
.piece.bag { --bag-a: #5a3d22; --bag-b: #3a2714; --bag-c: #2e1f10; --bag-trim: #8a6d3b; --bag-stitch: rgba(230,190,120,.28); --bag-glow: transparent; --pat: none; --pat-size: auto; }
.piece.bag.pat-studs { --pat: radial-gradient(circle at 5px 5px, #e4dccb 0 1.6px, #0008 2.3px, transparent 2.8px), radial-gradient(circle at calc(100% - 5px) 5px, #e4dccb 0 1.6px, #0008 2.3px, transparent 2.8px), radial-gradient(circle at 5px calc(100% - 5px), #e4dccb 0 1.6px, #0008 2.3px, transparent 2.8px), radial-gradient(circle at calc(100% - 5px) calc(100% - 5px), #e4dccb 0 1.6px, #0008 2.3px, transparent 2.8px); }
.piece.bag.pat-weave { --pat: repeating-linear-gradient(45deg, rgba(255,255,255,.09) 0 1px, transparent 1px 4px), repeating-linear-gradient(-45deg, rgba(0,0,0,.28) 0 1px, transparent 1px 4px); }
.piece.bag.pat-cloth { --pat: repeating-linear-gradient(0deg, rgba(255,255,255,.12) 0 1px, transparent 1px 3px), repeating-linear-gradient(90deg, rgba(0,0,0,.14) 0 1px, transparent 1px 3px); }
.piece.bag.pat-hide { --pat: radial-gradient(rgba(0,0,0,.35) 1px, transparent 1.6px) 0 0 / 7px 7px, radial-gradient(rgba(255,255,255,.1) 1px, transparent 1.6px) 3px 4px / 9px 9px; }
.piece.bag.pat-fletch { --pat: repeating-linear-gradient(115deg, rgba(235,215,170,.2) 0 2px, transparent 2px 9px), repeating-linear-gradient(65deg, rgba(0,0,0,.3) 0 1px, transparent 1px 9px); }
.piece.bag .cell { background: var(--pat), linear-gradient(160deg, var(--bag-a), var(--bag-b) 85%);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--bag-trim) 70%, transparent), inset 0 0 8px rgba(0,0,0,.35); }
.piece.bag { filter: drop-shadow(0 0 6px var(--bag-glow)); }
.piece.bag.loose { filter: none; }
.piece.bag .emblem { position: absolute; pointer-events: none; z-index: 0; border-radius: 3px; object-fit: cover; opacity: 1;
  box-shadow: 0 0 0 1px #000, 0 0 0 2px var(--bag-trim), 0 1px 4px #000; }
.piece.bag.glows .frame { box-shadow: 0 0 0 2px #1a0f06, 0 0 0 3px var(--bag-trim), 0 0 12px var(--bag-glow), 0 6px 14px rgba(0,0,0,.7); }
.piece.bag .cell::before { content: ""; position: absolute; inset: 13%; border-radius: 4px;
  background: radial-gradient(ellipse at 50% 35%, color-mix(in srgb, var(--bag-b) 55%, #0a0806), color-mix(in srgb, var(--bag-c) 40%, #030202)); box-shadow: inset 0 2px 4px #000, 0 1px 0 var(--bag-stitch), inset 0 0 0 1px rgba(0,0,0,.9); }
.piece.bag .frame { box-shadow: 0 0 0 2px #1a0f06, 0 0 0 4px var(--bag-trim), 0 6px 14px rgba(0,0,0,.7); z-index: -1; }
.piece.bag .frame::after { content: ""; position: absolute; inset: 1px; border: 1px dashed var(--bag-stitch); border-radius: 4px; }
.piece.bag .cell.fill { box-shadow: 0 0 0 1px var(--bag-trim), inset 0 0 8px rgba(0,0,0,.35); }
.piece .icon { position: absolute; pointer-events: none; object-fit: cover; }
.piece.bag .icon.badge { border-radius: 4px; border: 1px solid #000; box-shadow: 0 0 0 1px #c9a24a, 0 2px 4px #000; z-index: 3; }

/* items without a sprite (fallback only): one framed tile, rarity edge, icon centered; sprites live in sprites.css */
.piece.item { z-index: 2; }
.piece.item .frame { background: #0c0a08; overflow: hidden;
  box-shadow: inset 0 0 0 1px #000, inset 0 0 0 2px var(--qc), inset 0 0 12px color-mix(in srgb, var(--qc) 35%, transparent), 0 2px 5px rgba(0,0,0,.8); }
/* soft rarity glow behind the icon so tall items read as one object, not a dark card */
.piece.item .frame::after { content: ""; position: absolute; inset: 0; border-radius: 5px; box-shadow: inset 0 0 0 1px #000, inset 0 0 0 2px var(--qc);
  background: radial-gradient(closest-side, color-mix(in srgb, var(--qc) 30%, transparent), transparent),
  linear-gradient(180deg, rgba(255,255,255,.08), transparent 40%); }
.piece.item.long .frame::after { background: radial-gradient(closest-side, transparent 55%, rgba(0,0,0,.45)),
  linear-gradient(180deg, rgba(255,255,255,.10), transparent 35%); }
.piece.item.long .icon { box-shadow: 0 0 0 1px #000, 0 0 0 2px color-mix(in srgb, var(--qc) 70%, #000), 0 4px 10px rgba(0,0,0,.9); }
/* loose bags (shop shelf, storage): the bag's icon sits over its slots so it reads as a buyable bag */
.piece.bag.loose .icon.badge { z-index: 3; box-shadow: 0 0 0 1px #000, 0 0 0 2px var(--qc), 0 0 10px color-mix(in srgb, var(--qc) 50%, transparent), 0 3px 6px #000; }
.piece.bag.loose .cell::before { opacity: .7; }
/* bags with a sprite (sprites.js bagSpriteLayer): the bag itself fills its bbox UNDER the cells; the cells are
   translucent slots with a thin trim edge, so a bag reads as a bag with slots, not a framed box. Glow follows the bag's alpha. */
.piece.bag.has-sprite, .piece.bag.has-sprite.loose { filter: none; }
.piece.bag .bag-sprite { position: absolute; pointer-events: none; z-index: 0; line-height: 0; }
.piece.bag .bag-sprite .sprite { display: block; width: 100%; height: 100%; object-fit: fill; user-select: none; -webkit-user-drag: none;
  filter: drop-shadow(0 0 2px rgba(0,0,0,.8)) drop-shadow(0 4px 6px rgba(0,0,0,.55)); }
.piece.bag.has-sprite.glows .bag-sprite .sprite { filter: drop-shadow(0 0 2px var(--bag-glow)) drop-shadow(0 0 7px color-mix(in srgb, var(--bag-glow) 55%, transparent)) drop-shadow(0 4px 6px rgba(0,0,0,.55)); }
@media (hover: hover) { .piece.bag.has-sprite:has(.cell:hover) .bag-sprite .sprite { filter: drop-shadow(0 0 2px var(--gold)) drop-shadow(0 0 9px color-mix(in srgb, var(--gold) 55%, transparent)) drop-shadow(0 4px 6px rgba(0,0,0,.55)); } }
.piece.bag.has-sprite .cell { background: none; box-shadow: none; z-index: 1; }   /* wells paint OVER the bag sprite (z 0) */
/* slot wells (owner 11-04: "still reads as a tile grid"): no edge, no rounded square - only a faint feathered hollow
   in the bag's leather where an item can go, so the bag reads as one bag. While an ITEM is dragged (drag.js body.drag-active
   without drag-bag) the empty wells deepen and pick up a thin warm rim so the player can aim. */
/* owner 11-04 Ready Check: the slots must read at 1920 - a deeper hollow with a thin lit rim, still rounded (not a tile grid) */
.piece.bag.has-sprite .cell::before { inset: 8%; border-radius: 22%;
  background: radial-gradient(closest-side, rgba(4,3,2,.6), rgba(4,3,2,.44) 70%, rgba(4,3,2,.24) 100%);
  box-shadow: inset 0 0 0 1px rgba(255,214,150,.24), inset 0 2px 6px rgba(0,0,0,.6), 0 0 0 1px rgba(0,0,0,.35);
  transition: background .15s ease-out, box-shadow .15s ease-out; }
body.drag-active:not(.drag-bag) .piece.bag.has-sprite:not(.dragging) .cell::before { inset: 7%; border-radius: 22%;
  background: radial-gradient(closest-side, rgba(6,4,2,.5), rgba(6,4,2,.3) 70%, rgba(6,4,2,.08) 100%);
  box-shadow: inset 0 0 0 1px rgba(255,214,150,.18), inset 0 1px 6px rgba(0,0,0,.55); }
.piece.bag.has-sprite.loose .cell::before { opacity: .45; }
.piece.item .cell.fill { background: #15110c; box-shadow: inset 0 0 0 2px var(--qc); border-radius: 3px; }
.piece.item .icon { z-index: 1; border-radius: 4px; box-shadow: 0 0 0 1px #000, 0 3px 6px rgba(0,0,0,.8); }
@media (hover: hover) { .piece.item:hover .frame, .piece.item.selected .frame { filter: brightness(1.18); } }

.piece .star { position: absolute; width: var(--cell); height: var(--cell); display: none; align-items: center; justify-content: center;
  color: rgba(255, 209, 0, .5); font-size: calc(var(--cell) * .36); pointer-events: none; text-shadow: 0 0 4px #000; z-index: 4; }
.piece.item .star { display: flex; }
.piece.item:not(.dragging) .star:not(.on) { color: rgba(255, 209, 0, .3); }
.piece .star.on { color: var(--gold); text-shadow: 0 0 8px var(--gold), 0 0 2px #000; animation: twinkle 1.6s ease-in-out infinite; }
@keyframes twinkle { 50% { transform: scale(1.18); } }
.piece .buffed { position: absolute; right: 3px; top: 2px; font-size: 10px; color: #8fd6ff; text-shadow: 0 0 3px #000, 0 0 2px #000; pointer-events: none; z-index: 4;
  background: rgba(0,30,60,.7); border-radius: 3px; padding: 0 3px; line-height: 14px; }
.piece.selected .frame, .piece.selected .cell.fill { box-shadow: inset 0 0 0 2px var(--gold), 0 0 0 1px var(--gold), 0 0 14px rgba(255,209,0,.6); }
.piece.selected .frame::after { box-shadow: inset 0 0 0 2px var(--gold); }

.piece.dragging { z-index: 40; opacity: .95; position: fixed; filter: drop-shadow(0 10px 14px rgba(0,0,0,.8)); }
.piece.dragging .cell { pointer-events: none; }
.piece.ghost-src { opacity: .25; }
.preview { position: absolute; width: var(--cell); height: var(--cell); pointer-events: none; z-index: 30; border-radius: 4px; }
.preview.ok { background: rgba(63, 214, 90, .22); box-shadow: inset 0 0 0 2px rgba(63,214,90,.85); }
.preview.bad { background: rgba(224, 68, 58, .22); box-shadow: inset 0 0 0 2px rgba(224,68,58,.85); }
.piece.flash .frame, .piece.flash .cell.fill { animation: flash .32s ease-out; }
@keyframes flash { 0% { filter: brightness(1.9); } 100% { filter: none; } }

/* storage pieces are bodies in the bin (storage-bin.css): absolutely placed by transform */
.storage .piece { position: absolute; }
.board.cropped .star:not(.on) { display: none; }

/* custom-drawn items: frameless art spanning the whole shape, rarity as a soft glow */
.piece.item.has-art .art { position: absolute; pointer-events: none; z-index: 1; line-height: 0;
  filter: drop-shadow(0 4px 3px rgba(0,0,0,.75)) drop-shadow(0 0 5px color-mix(in srgb, var(--qc) 55%, transparent)); }
.piece.item.has-art .cell { border-radius: 4px; }
@media (hover: hover) { .piece.item.has-art:hover .art { filter: drop-shadow(0 4px 3px rgba(0,0,0,.75)) drop-shadow(0 0 8px var(--qc)) brightness(1.12); } }
.piece.item.has-art.selected .art { filter: drop-shadow(0 4px 3px rgba(0,0,0,.75)) drop-shadow(0 0 3px var(--gold)) drop-shadow(0 0 10px var(--gold)); }
.piece.item.has-art.selected .cell { box-shadow: inset 0 0 0 1px rgba(255,209,0,.35); }
.piece.has-art.flash .art { animation: flash .32s ease-out; }

/* pick-up / put-down feel */
.piece.dragging { transition: transform .09s ease-out; }
.piece.dragging .art, .piece.dragging .frame, .piece.dragging .icon { filter: drop-shadow(0 18px 14px rgba(0,0,0,.65)) drop-shadow(0 0 6px color-mix(in srgb, var(--qc) 60%, transparent)); }
.preview.swap { background: rgba(255, 196, 40, .22); box-shadow: inset 0 0 0 2px rgba(255,196,40,.9); }
.piece.land { animation: land .28s ease-out; }
@keyframes land { 0% { transform: translateY(-4px); filter: brightness(1.5); } 100% { transform: none; filter: none; } }
.piece.swap { animation: swapin .25s ease-out; }
@keyframes swapin { 0% { opacity: .3; } 100% { opacity: 1; } }
.piece.bounce { animation: bounce .3s ease-out; }
@keyframes bounce { 0% { transform: translateY(-6px); opacity: .6; } 100% { transform: none; opacity: 1; } }
.slot .art.art-svg { box-shadow: none; width: auto; height: 66px; display: flex; align-items: center; justify-content: center;
  filter: drop-shadow(0 3px 3px rgba(0,0,0,.7)) drop-shadow(0 0 5px color-mix(in srgb, var(--qc) 60%, transparent)); }
.slot .art.art-svg svg { display: block; }
@media (hover: hover) { .piece.bag:has(.cell:hover) .frame { box-shadow: 0 0 0 2px #1a0f06, 0 0 0 3px var(--gold), 0 0 14px rgba(255,209,0,.45), 0 6px 14px rgba(0,0,0,.7); } }

/* weapon sockets: dark empty sockets, gem icons when filled */
.piece .sockets { position: absolute; z-index: 3; display: flex; gap: 2px; pointer-events: none; }
.piece .sock { display: block; width: 13px; height: 13px; border-radius: 50%; background: radial-gradient(circle at 40% 35%, #3a3a48, #0a0a10); box-shadow: 0 0 0 1.5px #c9a24a, 0 1px 2px #000; }
.piece img.sock.full { object-fit: cover; box-shadow: 0 0 0 1.5px #ffd34a, 0 0 6px #ffd34a; }
/* a star that has the right item on it lights up */
.piece .star.on { color: #ffe27a; opacity: 1; text-shadow: 0 0 6px #ffd34a, 0 0 14px #ffb000; animation: staron 1.4s ease-in-out infinite; z-index: 4; }
@keyframes staron { 50% { text-shadow: 0 0 10px #ffe27a, 0 0 22px #ffb000; transform: scale(1.25); } }
/* sockets ON the item: hollow silver rings over the art; filled = round gem */
.piece .sock { position: absolute; z-index: 5; display: block; pointer-events: none; border-radius: 50%; box-sizing: border-box;
  background: radial-gradient(circle, rgba(20,20,28,.35) 0 48%, transparent 50%);
  border: 2.5px solid rgba(235,238,245,.9); box-shadow: 0 0 0 1px rgba(0,0,0,.55), inset 0 0 0 1px rgba(0,0,0,.45), 0 1px 3px rgba(0,0,0,.6); }
.piece .sock::after { content: ""; position: absolute; inset: 22%; border-radius: 50%; border: 1.5px solid rgba(235,238,245,.55); }
.piece img.sock.full { object-fit: cover; border-color: #ffe27a; box-shadow: 0 0 0 1px #000, 0 0 8px rgba(255,211,74,.9); }

/* non-rect items: one continuous rounded outline (SVG path from the cell mask), rarity edge + glow, art clipped to the shape */
.piece.item .frame.shape { background: none; box-shadow: none; overflow: visible; border-radius: 0; filter: drop-shadow(0 2px 3px rgba(0,0,0,.8)); }
.piece.item .frame.shape::before, .piece.item .frame.shape::after { content: none; }
.piece.item .frame.shape .shape-svg { display: block; overflow: visible; }
.piece.item .shape-glow { fill: color-mix(in srgb, var(--qc) 6%, transparent); }
.piece.item .shape-inglow { fill: none; stroke: var(--qc); stroke-width: 7px; opacity: .32; }
.piece.item.shaped .icon { box-shadow: 0 0 0 1px #000, 0 0 0 2px color-mix(in srgb, var(--qc) 70%, #000), 0 3px 8px rgba(0,0,0,.9); }
@media (hover: hover) { .piece.item.shaped:hover .frame.shape { filter: brightness(1.18) drop-shadow(0 2px 3px rgba(0,0,0,.8)); } }
.piece.item.shaped.selected .frame.shape { box-shadow: none; filter: drop-shadow(0 0 5px var(--gold)) drop-shadow(0 0 2px var(--gold)); }
.piece.item.shaped.selected .shape-edge { stroke: var(--gold); }
.piece.item.shaped.flash .frame.shape { animation: flash .32s ease-out; }
.piece.item .shape-rim { fill: none; stroke: #000; stroke-width: 4px; }
.piece.item .shape-edge { fill: none; stroke: var(--qc); stroke-width: 3px; }

/* drop settle: short spring when the piece lands in its cell (drag.js reveals it after the ghost glides in) */
.piece.settle { animation: settle .3s cubic-bezier(.2,1.5,.4,1); }
@keyframes settle { 0% { transform: scale(1.1); filter: brightness(1.35); } 55% { transform: scale(.97); } 100% { transform: none; filter: none; } }
.piece.dragging { transition: none; opacity: 1; filter: drop-shadow(0 14px 12px rgba(0,0,0,.6)); }
@media (prefers-reduced-motion: reduce) { .piece.settle { animation: none; } }


/* touch / pressed equivalents of the hover-only highlights above (synergy lane) */
.piece.bag.has-sprite.selected .bag-sprite .sprite, .piece.bag.has-sprite:has(.cell:active) .bag-sprite .sprite { filter: drop-shadow(0 0 2px var(--gold)) drop-shadow(0 0 9px color-mix(in srgb, var(--gold) 55%, transparent)); }
.piece.item:active .frame { filter: brightness(1.18); }
.piece.item.has-art:active .art, .piece.item.has-art.selected .art { filter: drop-shadow(0 4px 3px rgba(0,0,0,.75)) drop-shadow(0 0 8px var(--qc)) brightness(1.12); }
.piece.bag.selected .frame, .piece.bag:has(.cell:active) .frame { box-shadow: 0 0 0 2px #1a0f06, 0 0 0 3px var(--gold), 0 0 14px rgba(255,209,0,.45), 0 6px 14px rgba(0,0,0,.7); }
.piece.item.shaped:active .frame.shape, .piece.item.shaped.selected .frame.shape { filter: brightness(1.18) drop-shadow(0 2px 3px rgba(0,0,0,.8)); }
