/* THE LEADERBOARD — the corner plate and its overlay (HANDOFF-158 §5).

   The plate lives in the same corner language as the rank block (stage.css
   §6.22): position:fixed on the rail's own left edge, desktop only, and gone
   during a rip. Luke, 8 Sep: "an icon in the bottom left ... in between the
   rank at the bottom left and the info button", and — after the first attempt
   put it in the nav — "not connected to the header at all".

   NOT a rail row, twice over. The rail forces every row to one width, so
   LEADERBOARD widened the whole rail (INFO's right edge 163.5 -> 209.2 at
   1512x982) and ran under the leftmost pack; and stage.js:919 sizes the packs
   off RAIL_KEEP=170 to stop just clear of the rail, so fitting the word meant
   shrinking every pack on every screen. Off the rail there is no such rule.
   Measured: the gap between INFO's bottom and the rank's top is 217px at
   1147x655 and 405px at 1512x982; the packs never come further left than
   x~178, so a 150px plate on the rail's 26px edge cannot reach them.

   THE PANEL BORROWS THE SITE'S OWN CLASSES. .otabs/.otab and .orow already
   carry the stage skin — white pills, 2px keyline, 3px drop, pink when on
   (stage.css §the light sheet) — so the board wears them and only overrides
   the grid. Written from scratch it looked like a different product: the first
   pass assumed .ov__panel was dark navy, and it is the light blue sheet, so
   white-on-white was the result. */

/* ---- the way in ------------------------------------------------------
   A rail row under VAULT, called LEADERS (Luke, 8 Sep 11:26). It borrows
   .sl-link whole - the rail owns the type, the icon size, the hover and the
   active state - so there is nothing to style here but the button reset,
   because every other row in that rail is an <a> and this one is a <button>. */
/* NO `font: inherit` HERE. It reset the label to #nav's 16px while every other
   row renders .sl-link's own 23px (Luke, 8 Sep 12:00 - "Leaders is the wrong
   font size"). The Pokedex row is a <button> too and carries no font rule at
   all, which is exactly why it always matched. Reset only what a button brings
   with it that an <a> does not. */
html[data-layout="stage"] .sl-link--lb {
  appearance: none; background: none; border: 0; text-align: left; cursor: pointer;
  font-family: inherit;
}

/* ---- THE TOP THREE --------------------------------------------------
   Luke, 8 Sep 10:38, on the first podium: "they still look a bit boring.
   They're meant to be the three best on the site." So the plates carry weight
   the list does not: first place is taller, sits on a gold ground with a shine
   raked across it and wears a laurel, and every face is big enough to read.
   The place badge is INSIDE the plate — hung over the top edge on a negative
   margin it was clipped by the scrolling body, which is the cut-off "1" in his
   screenshot. Same treatment on all three boards; on BIGGEST PULLS the face is
   the card. */
/* THE PODIUM IS THE ONLY THING THAT STICKS (Luke, 11 Sep: "Just the top three
   should be sticky. They should scroll to the top and then stick to the top,
   and everything else should scroll behind them ... we're conscious of the fact
   that there are gaps in between the podiums, so we don't want to be able to
   see the sea behind them").
   THE GAPS ARE THE HARD PART. Three plates in a grid with a 10px gutter and
   rounded corners leave holes, and a row passing behind would show through
   every one of them. So the sticky band carries the PAGE'S OWN GROUND: the same
   plate, the same `center center/cover`, with background-attachment:fixed so it
   is anchored to the viewport exactly as .bg is (style.css:108, position:fixed
   inset:0 with the same sizing) — the band is a window onto the identical
   picture, and the seam is invisible by construction rather than by a tint that
   nearly matches.
   The negative side margins and matching padding let that ground run to the
   page's edges under the plates; without them a row would slide through the
   10px the grid leaves at each end.
   The 14px bottom margin is the gap Luke asked to keep ("we need that little gap
   between the podium and the number 4 to stay there") and it is INSIDE the
   sticky box, so it travels with the band and the gap never closes. */
.lbpod {
  display: grid; grid-template-columns: 1fr 1.2fr 1fr; gap: 10px; align-items: end;
  margin: 0 0 14px;
}
html[data-layout="stage"] .pg .lbpod {
  position: sticky; top: 0; z-index: 4;
  margin: 0 -14px 14px; padding: 0 14px 14px;
  background: url(../bg-plate.png) center center/cover fixed no-repeat;
}
@media (max-width: 1023px) {
  /* the phone's plate is the portrait crop, the same swap .bg makes */
  html[data-layout="stage"] .pg .lbpod {
    margin: 0 -10px 12px; padding: 0 10px 12px;
    background-image: url(../bg-plate-mobile.png);
  }
}
/* the two tab strips are the body's first child now and scroll away with it */
.lbhead { position: relative; z-index: 1; }
.lbp {
  position: relative; overflow: hidden; text-align: center;
  background: #fff; border: 2px solid var(--key); border-radius: 18px;
  box-shadow: 0 4px 0 var(--key); padding: 14px 10px 13px;
}
.lbp--1 { padding: 40px 12px 16px; background: linear-gradient(178deg, #FFEFB8 0, #FFF8E2 42%, #fff 100%); }
.lbp--2 { background: linear-gradient(178deg, #EEF1F6 0, #fff 62%); }
.lbp--3 { background: linear-gradient(178deg, #F7E7D6 0, #fff 62%); }
.lbp--me { outline: 3px solid var(--acc); outline-offset: -3px; }
/* the shine the RIP PACK button wears, raked across first place.
   BACKWARDS, NOT none (Luke, 12 Sep, on the clan boards: "the shiny thing that
   swipes across is stuck over the crown as soon as you click the boards button
   ... that little sweeping motion shouldn't begin until you've been on the board
   section for a second. It should begin off the button and then go on to the
   button").
   The delay was doing the opposite of what it looks like it does. With
   fill-mode `none` an element waits out its delay wearing its OWN style, not the
   animation's first frame — and this element's own transform is nothing at all,
   which parks the white band at the middle of its box, which is the middle of
   the plate, which is where .lbp__crown is. Measured on the clan BOARDS panel:
   transform `none` at +60ms, +400ms and +900ms, then `translateX(-260.9px)` at
   +1400ms. So it sat across the crown for 1.2s and snapped away.
   `backwards` hands it the 0% keyframe for the whole delay instead, and 0% is
   translateX(-58%) — outside the plate, which is overflow:hidden, so nothing
   shows at all until the sweep enters from the left edge and crosses. That is
   both halves of what he asked for, and the timing is the keyframes' own: the
   1.2s delay plus the 0-62% hold, so the first sweep lands ~4s in and nothing
   is visible before it. */
.lbp--1::after {
  content: ""; position: absolute; inset: -40% -60%; pointer-events: none;
  background: linear-gradient(104deg, transparent 42%, rgba(255,255,255,.85) 50%, transparent 58%);
  animation: lbShine 4.6s ease-in-out 1.2s infinite backwards;
}
@keyframes lbShine { 0%, 62% { transform: translateX(-58%); } 88%, 100% { transform: translateX(58%); } }
@media (prefers-reduced-motion: reduce) { .lbp--1::after { animation: none; opacity: 0; } }
/* the box is the viewBox (-3 -1 62 42) at the crown's drawn scale, 0.893px a
   unit, so the outer jewels are inside it (Luke, 10 Sep 01:11: clipped) */
.lbp__crown { position: absolute; top: 5px; left: 50%; transform: translateX(-50%); width: 55.4px; height: 37.5px; }
.lbp__pl {
  position: absolute; top: 9px; left: 12px; width: 26px; height: 26px; border-radius: 50%;
  border: 2px solid var(--key); display: grid; place-items: center;
  font-family: var(--display); font-weight: 900; font-size: 14px; color: var(--key); line-height: 1;
}
.lbp--1 .lbp__pl { background: #FDC107; }
.lbp--2 .lbp__pl { background: #D7DCE4; }
.lbp--3 .lbp__pl { background: #E0A96B; }
.lbp__face { display: grid; place-items: center; margin: 8px 0 8px; position: relative; z-index: 1; }
.lbp--1 .lbp__face { margin-top: 2px; }
.lbp__face .lbav { width: 56px; height: 56px; font-size: 21px; }
.lbp--1 .lbp__face .lbav { width: 68px; height: 68px; font-size: 26px; }
.lbp--1 .lbp__face .lbav { box-shadow: 0 0 0 3px #FDC107, 0 3px 0 var(--key); }
.lbp--2 .lbp__face .lbav { box-shadow: 0 0 0 3px #C3CAD6, 0 3px 0 var(--key); }
.lbp--3 .lbp__face .lbav { box-shadow: 0 0 0 3px #D6A273, 0 3px 0 var(--key); }
.lbp__face .lbcard { width: 62px; height: auto; }
.lbp--1 .lbp__face .lbcard { width: 76px; height: auto; }
.lbp__u {
  font-family: var(--display); font-weight: 800; font-size: 16px; color: var(--key);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; position: relative; z-index: 1;
}
.lbp--1 .lbp__u { font-size: 19px; }
.lbp__v {
  font-family: var(--display); font-weight: 900; font-style: italic; font-size: 24px;
  color: var(--acc-lo, #B8256B); transform: var(--slant); margin-top: 2px;
  font-variant-numeric: tabular-nums; position: relative; z-index: 1;
}
.lbp--1 .lbp__v { font-size: 31px; }
.lbp__s {
  font-size: 11.5px; font-weight: 600; color: var(--ink-dim, #3A4354); margin-top: 3px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; position: relative; z-index: 1;
}
@media (max-width: 1023px) {
  .lbpod { grid-template-columns: 1fr 1fr 1fr; gap: 7px; }
  .lbp, .lbp--1 { padding: 28px 6px 11px; border-radius: 14px; }
  .lbp__face .lbav, .lbp--1 .lbp__face .lbav { width: 46px; height: 46px; font-size: 17px; }
  .lbp__face .lbcard { width: 44px; height: auto; }
  .lbp--1 .lbp__face .lbcard { width: 52px; height: auto; }
  .lbp__u, .lbp--1 .lbp__u { font-size: 13px; }
  .lbp__v { font-size: 18px; } .lbp--1 .lbp__v { font-size: 22px; }
}

/* ---- the face, on the podium and in the list ------------------------- */
.lbav {
  width: 36px; height: 36px; border-radius: 50%; border: 2px solid var(--key);
  display: grid; place-items: center; flex: 0 0 auto; overflow: hidden;
  font-family: var(--display); font-weight: 900; font-size: 15px; color: #fff; line-height: 1;
}
.lbav--pic { object-fit: cover; }
/* THE SLAB, WHOLE, ON NOTHING (Luke, 8 Sep 11:20 "the slabs are cropped, and
   they shouldn't be", then 11:45 "why are the slabs in a black box?").
   object-fit was cover, which ate the case and the grade label - the two things
   that make it a slab. Changing it to contain uncropped it but boxed it: the
   partner's photos are 679x1136, aspect 0.59, and the box was 0.73, so contain
   letterboxed and my navy ground painted the bars black. Measured five of them
   (Tyranitar, the Spanish base set, three demo cards): every one fills its
   frame edge to edge at 0.587-0.598, so there is no margin to hide - the box
   just has to BE that shape. aspect-ratio does it from the width alone, and
   with no ground and no keyline the slab sits on the plate as itself, with the
   same soft shadow the live feed's tiles wear. */
.lbcard {
  width: 32px; aspect-ratio: 679 / 1136; border: 0; background: none;
  flex: 0 0 auto; display: block; padding: 0; cursor: pointer;
  transition: transform .12s; filter: drop-shadow(0 3px 5px rgba(11, 15, 24, .38));
}
.lbcard > img { width: 100%; height: 100%; object-fit: contain; display: block; }
.lbcard:hover { transform: translateY(-2px) scale(1.05); }
.lbcard:active { transform: translateY(1px); }
/* the middle of a row was empty (Luke: "loads of empty space in the middle").
   It carries the share of the leader now — the reason the number matters. */
.lbbar { height: 8px; border-radius: 6px; background: rgba(11, 15, 24, .10); overflow: hidden; min-width: 40px; }
.lbbar i { display: block; height: 100%; border-radius: 6px; background: var(--acc); }
.lblist { display: block; }

/* ---- the board rows ------------------------------------------------- */
/* .orow gives the pill, the keyline and the radius; only the columns change:
   place | who | what they did. */
/* THE SELECTOR CARRIES html[data-layout="stage"] ON PURPOSE. stage.css:1497
   re-columns every .orow on the phone for the ODDS sheet — and at (0,2,1) it
   beat a bare .lbrow.orow, so the name column collapsed to 46px and every
   handle read "kant…" (measured at 390: columns 64/135/46/59). Matching the
   layout prefix puts this at (0,3,1) and the board keeps its own grid. */
/* THE BAR TAKES THE SLACK (Luke, 11 Sep, picking option A off the layout mocks).
   The grid used to read `34px auto minmax(0,1fr) 116px auto` — the only flexible
   column was the HANDLE, so at 1512x982 a row of 1167px gave .lbrow__u 850 of
   them to hold a name and a clan chip, about 180px of ink. 57% of every row was
   a hole in the middle, and the share bar that shows the shape of the race was a
   token 116px. The 1fr moves to the bar: the name sizes to its content and the
   thing worth looking at gets the width.
   The name still needs a ceiling — `auto` on a 20-character handle with a clan
   chip would push the bar out — so it is capped and keeps its ellipsis. The
   phone block below is untouched: it hides the bar and gives the 1fr back to the
   name, which is right on a 390px screen. */
html[data-layout="stage"] .lbrow.orow {
  grid-template-columns: 34px auto auto minmax(0, 1fr) auto;
  gap: 11px; padding: 7px 14px 7px 10px; margin-bottom: 7px; align-items: center;
}
html[data-layout="stage"] .lbrow.orow .lbrow__u { max-width: min(38vw, 420px); }
/* min-width:40px was the floor while the bar had a fixed 116px track; as the
   flexible column it must be free to be whatever is left */
html[data-layout="stage"] .lbrow.orow .lbbar { min-width: 0; }
@media (max-width: 1023px) {
  html[data-layout="stage"] .lbrow.orow { grid-template-columns: 26px auto minmax(0, 1fr) auto; gap: 9px; }
  html[data-layout="stage"] .lbrow.orow .lbbar { display: none; }
  html[data-layout="stage"] .lbrow.orow .lbrow__v { font-size: 17px; }
}
.lbrow__n {
  font-family: var(--display); font-weight: 900; font-style: italic; font-size: 21px;
  color: var(--ink-faint, #5A6478); text-align: center; transform: var(--slant);
  font-variant-numeric: tabular-nums;
}
/* the top three read as places, not as list indices. Darkened off the badge
   colours: #FDC107 on a white pill fails contrast, these do not. */
.lbrow--1 .lbrow__n { color: #B07D06; }
.lbrow--2 .lbrow__n { color: #6B7280; }
.lbrow--3 .lbrow__n { color: #9C5620; }
.lbrow__u {
  font-family: var(--display); font-weight: 800; font-size: 18px; color: var(--key);
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; line-height: 1.15;
}
.lbrow__s {
  display: block; font-family: var(--body, inherit); font-weight: 600; font-size: 12.5px;
  color: var(--ink-dim, #3A4354); overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.lbrow__v {
  font-family: var(--display); font-weight: 900; font-size: 20px; color: var(--acc-lo);
  white-space: nowrap; font-variant-numeric: tabular-nums;
}

/* A SHORT TOP RAMP ON THIS BOARD. Luke, 8 Sep 10:08: "the way the scrollbar
   fades out at the top is a bit rubbish" — that was stage.css §6.24's 64px
   ramp with 64px of padding, which dissolved the top of the board AT REST and
   cost 64px of the empty middle. Then 10 Sep 01:11: rows scrolling up were
   "cut flat" under the tab rows; he wants them to fade out under that header
   the way the foot already fades. So: a 24px ramp and exactly 24px of padding.
   At rest the podium starts where the ramp ends, fully opaque; once scrolled,
   a row passes through the fade on its way under the tabs. The bottom fade is
   the one every sheet wears (stage.css §6.9). */
html[data-layout="stage"] .ov--lb .ov__body{
  padding-top: 24px;
  -webkit-mask-image: linear-gradient(180deg, transparent 0, #000 24px, #000 calc(100% - 40px), transparent 100%);
  mask-image: linear-gradient(180deg, transparent 0, #000 24px, #000 calc(100% - 40px), transparent 100%);
}

/* CLOSE THE SPACE OVER THE TABS (Luke, 11 Sep: "on the leaders page, it seems
   like there's loads of space between the actual header of the website ... and
   the tabs. Can we clear that space? No, get rid of that space").
   Measured at 1512x982: the header cluster's pills end at y48 and the tabs
   started at y144 — 96px of nothing. Two insets stacked again: the frame's
   --pg-pad (the header's bottom + 58) and this body's own 24.
   THE FRAME'S 58 IS THERE FOR BACK, and this page has none (Luke, 10 Sep: a
   page with its own rail row wears neither BACK nor an X). page.css pins BACK
   at --pg-hdr + 7 with a 40px box, so a panel page that HAS one cannot start
   its content above 109 — but this one can, and the same goes for /clans. The
   inset drops to 16, the body's ramp to 10, and the tabs land at y88: 40px under
   the pills instead of 96.
   The ramp is GONE from the top, and the podium is pulled up over where it was
   (Luke, 11 Sep 01:55: "just on top of the podium, it doesn't meet the header
   properly when it's sticky because of that. You can see the rows swipe above
   it as you scroll").
   Measured at 1512x982 with the board scrolled 600px: the body's border box
   starts at y78, and .lbpod pinned at y88 — dead on its padding box, because a
   sticky top is measured from the scrollport, and this body's padding-top is
   10. That 10px band is the "ramp" this comment used to defend, and it cannot
   do the job it was given: a row is 54px tall, so ten pixels of gradient
   dissolve almost none of it, and what the eye gets is a half-lit row sitting
   ABOVE the plate. A mask fades a row and a sticky cover EQUALLY, so no plate
   painted inside the band can hide one either — the band itself has to go.
   top:-10px pins the podium on the body's own top edge, where content is
   clipped by overflow, so nothing can ever be above it. At rest sticky still
   clamps to the flow position (y193 measured), so nothing moved; the tabs keep
   their y88 and the plate is background-attachment:fixed, so pulling the box
   up 10px does not shift its texture off the page's. The bottom 40px fade
   stays. How rows should meet the podium's BOTTOM edge is Luke's call. */
html[data-layout="stage"] .pg--panel.ov--lb .pg__panel{
  padding-top: calc(var(--pg-hdr, 62px) + 16px);
}
/* THE TOP RAMP IS BACK, BUT DRIVEN (Luke, 11 Sep, of the tab strip: "I don't
   like how they just cut behind the header. They should fade behind the header
   nicely ... let's make sure that that fade is nice and small so it doesn't
   affect the buttons before we start scrolling").
   The block above removed the ramp outright, which is why the strip cuts flat
   today — measured at 1147x655: the body's top edge is y63 and .otabs starts at
   y73, so it is inside any ramp deeper than the 10px of padding, and a static
   one would wash out the tab buttons on a board nobody has touched. --lb-fade
   is written per frame by leaderboard.js: 0 at rest, up to 14px while the strip
   crosses, back to 0 as the podium pins and takes the edge. So the ramp only
   exists during the travel it is there for, and the sticky band never wears it. */
html[data-layout="stage"] .pg--panel.ov--lb .ov__body{
  padding-top: 10px;
  -webkit-mask-image: linear-gradient(180deg, transparent 0, rgba(0,0,0,.5) calc(var(--lb-fade, 0px) / 2), #000 var(--lb-fade, 0px), #000 calc(100% - 40px), transparent 100%);
  mask-image: linear-gradient(180deg, transparent 0, rgba(0,0,0,.5) calc(var(--lb-fade, 0px) / 2), #000 var(--lb-fade, 0px), #000 calc(100% - 40px), transparent 100%);
}
html[data-layout="stage"] .pg--panel.ov--lb .lbpod{ top: -10px; }

/* YOU, in the FOOT — outside the scrolling body. `me` matters more than the
   top ten (someone sitting 47th wants to see 47th), so it is always in view;
   as a sticky child of the body it covered whichever row sat under it, which
   at 1147x655 permanently hid row 9 of 13. Yellow is the site's own "this one
   is you" (stage .clad--you). */
/* the foot is empty now - YOU is a marked row, not a footer */
.ov--lb .ov__foot { display: none; }
html[data-layout="stage"] .lbrow.orow.lbrow--me { background: var(--yellow); box-shadow: 0 3px 0 var(--key); }
html[data-layout="stage"] .lbrow.orow.lbrow--me .lbbar { background: rgba(11, 15, 24, .18); }
.lbme { margin: 0; }
.lbme .lbrow.orow { background: var(--yellow); margin-bottom: 10px; }
.lbme__tag {
  font-family: var(--display); font-weight: 900; font-style: italic; font-size: 13px;
  letter-spacing: .14em; color: var(--key); transform: var(--slant); padding: 0 0 5px 4px;
}
.lbnote { padding: 4px 2px 10px; font-size: 14px; color: var(--ink-dim, #3A4354); }
.lbnote b { color: var(--key); }

/* the opt-out, quiet on purpose: it is a right, not a call to action */
.lbhide {
  display: inline-flex; align-items: center; gap: 9px; cursor: pointer;
  margin: 2px 0 14px; padding: 7px 12px; border-radius: 10px;
  background: rgba(255, 255, 255, .55); border: 2px solid rgba(11, 15, 24, .30);
  font-size: 13.5px; font-weight: 600; color: var(--ink-dim, #3A4354);
}
.lbhide:hover { color: var(--key); border-color: var(--key); }
.lbhide input { accent-color: var(--acc); width: 15px; height: 15px; }

/* the period row is secondary to the board row: same stickers, smaller, and
   tucked up under it rather than paying a second full row of margin */
html[data-layout="stage"] .lbtabs--sub { margin-top: 2px; padding: 2px 0 6px; }
html[data-layout="stage"] .lbtabs--sub .otab {
  font-size: 14px; padding: 6px 11px; box-shadow: 0 2px 0 var(--key);
}

/* ---- the phone: a row in the profile sheet -------------------------- */
/* Same shape as View Crate Odds / View Pack Odds (stage.js dressProfile), so
   the sheet keeps one row language. */
.mrow .lbrose { width: 22px; height: 22px; flex: 0 0 auto; }

/* THE BOARD IS A FULL SCREEN ON THE PHONE (Luke, 9 Sep 22:31: "it shouldn't be
   a pop-up or a slide-up of half the tab ... a full window on mobile, like it
   is on desktop"). The stage's phone card is content-height; this one fills. */
@media (max-width: 1023px) {
  html[data-layout="stage"] .ov--lb .ov__panel { height: 100%; }
}
