/* =========================================================
   SKINS PANEL — Bridge Run                              2026-08-05

   A 4th nav tab + a slide-in panel: spend gems OR watch a rewarded video to
   unlock a random runner skin, revealed by a highlight "egg" that hops around
   the grid and slows to a stop.

   ⚠️ THIS FILE ADDS TO THE SHELL, IT DOES NOT FORK IT.
   Everything here is game-side. `shell.css` and `shell.js` stay byte-identical
   (CLAUDE.md §4) — the panel is a plain `.sh-ov` and the tab a plain `.tabb`, so
   the shell's own closeAll()/setTab() manage both for free.

   📐 SCALING — read UI Kit/UI-SCALING-STANDARD.md before editing.
   • Every size below is FIXED DESIGN-SPACE px. There is not one vw/vh/% -of-viewport
     in this file, and there must never be — the panel is scaled as a whole by the
     shell's --ui-scale, so anything reading the real viewport gets scaled TWICE.
   • The slide-in keyframe RESTS AT `scale(var(--ui-scale,1))`, never `transform:none`.
     `transform:none` would snap the panel to full raw size the instant the animation
     ended, silently undoing the scaling (TRAP #1). Same reason the shell's own
     sh-popIn ends the way it does.

   🎨 All colour comes from theme.css custom properties, so this panel re-skins with
      the rest of the game and never hard-codes the palette.
   🚫 No emoji anywhere — the tiles draw a real SVG runner, and the gem/ad/close
      artwork is the shell's own icon set (CLAUDE.md §4).
   ========================================================= */

/* ── the slide ───────────────────────────────────────────────────────────────
   The user asked for slide-in/out rather than the shell's default pop. Resting
   transform is the card scale — see the TRAP #1 note above. */
#brSkins .panel{
  width:340px; flex:none;
  transform: translateY(150px) scale(calc(var(--ui-scale,1) * .98));
  opacity:0;
}
#brSkins.show .panel{ animation: br-slideIn .42s cubic-bezier(.22,1,.36,1) forwards; }
@keyframes br-slideIn{ to{ transform: translateY(0) scale(var(--ui-scale,1)); opacity:1; } }

/* Slide back DOWN on close. JS adds .closing, waits for this, then drops .show. */
#brSkins.closing .panel{ animation: br-slideOut .26s ease-in forwards; }
@keyframes br-slideOut{
  from{ transform: translateY(0) scale(var(--ui-scale,1)); opacity:1; }
  to  { transform: translateY(170px) scale(calc(var(--ui-scale,1) * .98)); opacity:0; }
}
#brSkins.closing{ background:rgba(20,14,8,0); }

/* ── tier carousel ────────────────────────────────────────────────────────────
   Three pages side by side, translated by whole page widths. `.br-view` is the
   window; `.br-track` is the strip.

   📐 The track is moved in **%**, which is design-space and so never reads the real
   viewport (TRAP #3). Do not "fix" it to a px value from getBoundingClientRect() —
   inside the scaled card that is SCREEN px, and the paging distance would be wrong at
   every scale but 1.
   ⚠️ But note a percentage translate is a percentage of the ELEMENT'S OWN width, and
   that element is the 3-page-wide TRACK. One page is 100/3 %, not 100%. Using 100%
   jumped three pages at once and left the grid blank with nothing in the console.
   See PAGE_PCT in skins.js. */
/* ⚠️ THE WINDOW MUST BE TALLER AND WIDER THAN THE GRID, or the top row looks chopped.
   `overflow:hidden` clips at the PADDING edge, and three things deliberately overhang a
   tile: the equipped ring (3px all round), the gold tick badge (top/right −6px) and the
   reveal pop (scale 1.28 → ~12px past each edge). With the window sized to the grid
   exactly, all three were sliced off — read as a rendering fault on the top row rather
   than as clipping.
   Vertical breathing room comes from padding. Horizontal room comes from the window
   being WIDER than the 284px grid, which is safe because a page is the full window
   width and the grid is centred inside it — so the extra space belongs to that page and
   no neighbour can bleed into it. (Horizontal PADDING would not be safe: the track sits
   in the content box, so the padding strip would show the next page through it.) */
#brSkins .br-view{
  position:relative; width:304px; margin:-4px auto 0; overflow:hidden;
  padding:14px 0 10px;
}
#brSkins .br-grid{ margin:0 auto; }
#brSkins .br-track{ display:flex; width:300%; transition:transform .34s cubic-bezier(.22,1,.36,1); }
#brSkins .br-page{ position:relative; width:33.3333%; flex:0 0 33.3333%; }

/* Arrows + dots. `touch-action:none` on the track lets a horizontal drag be a swipe
   rather than a scroll gesture the browser steals. */
#brSkins .br-track{ touch-action:none; }

#brSkins .br-nav{
  display:flex; align-items:center; justify-content:space-between;
  width:284px; margin:0 auto 8px; gap:10px;
}
#brSkins .br-arrow{
  width:38px; height:38px; padding:0; flex:0 0 auto; cursor:pointer;
  border:3px solid var(--ink); border-radius:12px;
  background:linear-gradient(180deg, var(--gh-1), var(--gh-2));
  box-shadow:0 3px 0 var(--gh-3);
  color:var(--ink); display:flex; align-items:center; justify-content:center;
  transition:transform .1s, opacity .15s;
}
#brSkins .br-arrow svg{ width:20px; height:20px; display:block; }
#brSkins .br-arrow:active{ transform:translateY(2px); box-shadow:0 1px 0 var(--gh-3); }
#brSkins .br-arrow[disabled]{ opacity:.35; cursor:default; }

#brSkins .br-dots{ display:flex; gap:7px; align-items:center; }
#brSkins .br-dot{
  width:9px; height:9px; padding:0; border-radius:50%; cursor:pointer;
  border:2px solid var(--ink); background:var(--gh-2); transition:.18s;
}
#brSkins .br-dot.on{ background:var(--accent); transform:scale(1.35); }

/* ── the grid ─────────────────────────────────────────────────────────────── */
#brSkins .br-grid{
  position:relative;
  display:grid; grid-template-columns:repeat(3, 88px); gap:10px;
  justify-content:center;
}

#brSkins .br-tile{
  position:relative; width:88px; height:88px; padding:0;
  border:4px solid var(--ink); border-radius:22px;
  background:linear-gradient(180deg, var(--gh-1), var(--gh-2));
  box-shadow:0 4px 0 var(--gh-3);
  display:flex; align-items:center; justify-content:center;
  cursor:default; font-family:inherit; transition:transform .12s;
}
/* Locked: the accent ramp, so an unopened tile reads as "the prize" rather than furniture.
   Each tier gets its own locked colour so a swipe visibly changes WHERE you are, not just
   what's in the grid — the header alone was too quiet a signal. Gold for rare, violet for
   ultra: both climb away from the base accent rather than restating it. */
#brSkins .br-tile.locked{
  background:linear-gradient(180deg, var(--accent-lt), var(--accent));
  box-shadow:0 4px 0 var(--accent-base);
}
#brSkins .br-page:nth-child(2) .br-tile.locked{
  background:linear-gradient(180deg, var(--gd-1), var(--gd-2));
  box-shadow:0 4px 0 var(--gd-3);
}
#brSkins .br-page:nth-child(3) .br-tile.locked{
  background:linear-gradient(180deg, #c98bff, #8a3ddb);
  box-shadow:0 4px 0 #5c1f99;
}
/* ULTRA reads as lit-from-inside, matching what the 3D runner actually does on that
   tier (emissive material) rather than being a colour swap with a fancier name. */
#brSkins .br-page:nth-child(3) .br-tile.owned{
  box-shadow:0 4px 0 var(--gh-3), 0 0 14px 2px rgba(190,120,255,.55);
}
#brSkins .br-tile.locked .br-q{
  font-size:38px; font-weight:800; color:var(--pri-ink);
  text-shadow:0 2px 0 rgba(0,0,0,.22); line-height:1;
}
#brSkins .br-tile.owned{ cursor:pointer; }
#brSkins .br-tile.owned:active{ transform:translateY(2px); }

/* The runner drawn into each owned tile. Real SVG shapes — never an emoji. */
#brSkins .br-tile svg{ width:52px; height:52px; display:block; }

/* Equipped: a gold cuff, matching "currency/owned" gold used everywhere else. */
#brSkins .br-tile.equipped{
  border-color:var(--gold-dk);
  box-shadow:0 0 0 3px var(--gold), 0 4px 0 var(--gh-3);
}
#brSkins .br-tile .br-tick{
  position:absolute; right:-6px; top:-6px; width:24px; height:24px; border-radius:50%;
  background:linear-gradient(var(--gd-1), var(--gd-2)); border:3px solid var(--ink);
  display:none; align-items:center; justify-content:center;
}
#brSkins .br-tile.equipped .br-tick{ display:flex; }
#brSkins .br-tile .br-tick::after{
  content:''; width:7px; height:11px; margin-top:-3px;
  border:solid var(--gd-ink); border-width:0 3px 3px 0; transform:rotate(42deg);
}

/* ── the "egg": the hopping selector ──────────────────────────────────────────
   Sits ABOVE the tiles and is moved by JS via left/top. offsetLeft/offsetTop are
   pre-transform, so they're already in design space — no --ui-scale maths needed. */
#brSkins .br-egg{
  position:absolute; width:88px; height:88px; border-radius:22px;
  border:5px solid var(--gold); box-shadow:0 0 0 4px var(--gold-dk), 0 0 22px 4px var(--gold);
  pointer-events:none; opacity:0; transition:opacity .18s;
  left:0; top:0;
}
/* Only the page being rolled shows its egg — each page owns one, so without this the
   other two would light up off-screen and be visible mid-swipe. */
#brSkins.spinning .br-page:nth-child(1) .br-egg,
#brSkins.spinning .br-page:nth-child(2) .br-egg,
#brSkins.spinning .br-page:nth-child(3) .br-egg{ opacity:0; }
#brSkins.spinning .br-page.rolling .br-egg{ opacity:1; }

/* The unveil. Deliberately a beat LONGER than the egg's last hop so the landing
   reads as "it stopped HERE" before the reveal fires. */
#brSkins .br-tile.reveal{ animation: br-reveal .62s cubic-bezier(.34,1.56,.64,1); z-index:2; }
@keyframes br-reveal{
  0%  { transform:scale(1)    rotate(0deg); }
  35% { transform:scale(1.28) rotate(-7deg); }
  60% { transform:scale(1.14) rotate(5deg); }
  100%{ transform:scale(1)    rotate(0deg); }
}

/* ── footer buttons ──────────────────────────────────────────────────────────
   .row2 / .btn / .green / .gold / .ghost are all the SHELL's classes, so these
   match every other button in the game and re-theme automatically. */
/* Share the row evenly — and let the gem button take the FULL width on its own when
   the ad button is feature-detected away (no SDK). Without this the lone button sits
   narrow and left-aligned, which reads as a broken layout rather than a deliberate one.

   Taller and more rounded than the shell default: these two are the panel's call to
   action and were reading as thin strips under a heavy grid. Scoped to #brSkins so the
   shell's own buttons everywhere else are untouched — this is a per-game tweak, not a
   change to the button language. */
#brSkins .row2 .btn{
  flex:1 1 0; min-width:0;
  height:56px; border-radius:20px; font-size:18px;
}
#brSkins .row2 .btn .br-cost{ gap:8px; }
#brSkins .row2 .btn img{ width:26px; height:26px; }

#brSkins .br-cost{ display:flex; align-items:center; justify-content:center; gap:6px; }
#brSkins .br-cost img{ width:22px; height:22px; object-fit:contain; }
#brSkins .btn[disabled]{ filter:grayscale(.85) brightness(.97); cursor:default; }

#brSkins .br-note{
  font-size:12px; font-weight:700; color:var(--text); opacity:.72;
  text-align:center; line-height:1.35; min-height:16px;
}

/* ── the nav tab's icon ──────────────────────────────────────────────────────
   The shell sizes .tabb img itself; this only colours the drawn runner so the tab
   sits in the same visual language as the shop/home/cup icons. */
#shNav .tabb[data-t="skins"] svg{ width:44px; height:44px; display:block;
  filter:drop-shadow(0 2px 2px rgba(0,0,0,.3)); pointer-events:none; }
#shNav .tabb.on[data-t="skins"] svg{ width:46px; height:46px; }
