/* ════════════════════════════════════════════
   top_likers/style.css — Figma Spec (exact)
   ════════════════════════════════════════════ */

@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+Thai:wght@700&display=swap');

/* ทุก overlay ต้องไม่แสดง scrollbar ใน OBS/CEF — ซ่อน scrollbar ทุก browser (ไม่แตะ overflow/layout).
   สำคัญเป็นพิเศษที่นี่: body เป็น overflow:visible โดยตั้งใจ (board โตเกิน viewport ได้) — จึงต้องซ่อน
   scrollbar แทนการ clip เพื่อไม่ให้เนื้อหาถูกตัด */
html, body { scrollbar-width: none; -ms-overflow-style: none; }
::-webkit-scrollbar { display: none; }

html,
body {
  margin: 0;
  padding: 0;
  background: transparent;
  font-family: 'Noto Sans Thai', 'Segoe UI', system-ui, sans-serif;
  /* NOT overflow:hidden — the board must be able to grow past the viewport and
     still be fully visible. In OBS the browser source is sized to the content
     anyway; in a plain browser window this is what lets a tall board (8 rows ×
     104px + header) be seen instead of being chopped at the bottom. */
  overflow: visible;
}

/* ── Root ──
   Sized BY the card, not by the viewport. `height: 100vh` used to pin this to
   the window, so anything taller than the window was simply cut off (with
   body{overflow:hidden} there wasn't even a scrollbar to reach it).
   min-height keeps the old full-window canvas for OBS, while `height: auto`
   lets the board extend when it needs more room. */
.tl-root {
  /* A small, even inset so the card's 1px border never sits on the very edge of
     the OBS source (where the source outline covers it and it reads as "cut
     off"). Even on all sides — the board no longer stretches, so there's no
     reason to bias one side. */
  padding: 14px;
  box-sizing: border-box;
  /* Shrink-wrap the card. NOT 100vw/100vh: OBS renders the page at the browser
     source's size (e.g. 1816×3229) and then scales that whole surface to fit,
     so forcing the page to fill the canvas made OBS scale a mostly-empty
     1800×805 area down — shrinking the card and pushing its right/bottom edges
     out of view (measured: 320px card inside an 1800px page = 1452px of dead
     space on the right alone). Sizing to the content lets OBS scale the CARD,
     so every edge stays visible whatever the source dimensions are. */
  width: max-content;
  height: max-content;
}

/* ── Outer card: Rectangle 411 ──
   Left free to size itself: no fixed/min width and NO overflow clipping. The
   card grows with however many columns .tl-rows produces, and nothing inside is
   cut off — `overflow: hidden` used to clip the podium ring/background, which
   deliberately extend past their own boxes. */
.tl-card {
  background: rgba(0, 0, 0, 0.5);
  border: 1px solid #FFE99F;
  border-radius: 20px;
  box-sizing: border-box;
  width: max-content;
  min-width: 318px;
}

/* ── Header: Rectangle 441 ── */
.tl-card-header {
  height: 70px;
  background: linear-gradient(90deg, #FFFAE8 0%, #FFE282 100%);
  border-radius: 20px 20px 0 0;
  display: flex;
  align-items: center;
  padding: 0 0 0 19px;
  box-sizing: border-box;
}

/* ── Title: "Top Liker" — color #C97800 ── */
.tl-title {
  font-family: 'Noto Sans Thai', sans-serif;
  font-size: 30px;
  font-weight: 700;
  color: #C97800;
  line-height: 45px;
}

/* ── Rows container ──
   Vertical column-fill, --rows-per-col rows per column: rows 1-5 fill the first
   column, 6-10 the next, and so on at the default 5 (matches the Ranking
   overlay's 'vertical' order).

   Done in pure CSS rather than by chunking in JS: `flex-wrap: wrap` on a
   column-direction flexbox breaks to a NEW COLUMN once the fixed height is
   full, so render() keeps emitting one flat list of .tl-row and the DOM diffing
   / bump animation stay untouched.

   --rows-per-col drives the height (N rows × 90px + (N-1) gaps × 10px). The
   value here is only the fallback: script.js re-sets the var inline on every
   render, seeded from ?rows=N and then following live top_likers_rows_per_col
   pushes from the Console's "Per column" input.

   90px also keeps the row comfortably TALLER than the podium ring (50px avatar
   + 9px each side = 69px), so the ring never sits against the row edge. */
.tl-rows {
  --row-h: 90px;
  --row-gap: 10px;
  --rows-per-col: 5;
  display: flex;
  flex-direction: column;
  flex-wrap: wrap;
  align-content: flex-start;
  gap: var(--row-gap);
  padding: 10px 9px 15px;
  /* n rows + (n-1) gaps — the exact height that fits --rows-per-col rows. */
  max-height: calc(
    (var(--rows-per-col) * var(--row-h)) +
    ((var(--rows-per-col) - 1) * var(--row-gap))
  );
}

/* The empty state is a lone child of the wrapping flex column — let it span the
   full width instead of being squeezed to a column's worth. */
.tl-rows > .tl-empty {
  flex: 1 1 auto;
  width: 300px;
}

/* ── Individual row: Rectangle 442/505/506/507/508 ──
   Fixed width on purpose. These rows live in a WRAPPING FLEX COLUMN: the
   container sizes itself from its columns, so a row allowed to grow (min-width)
   does not widen the card — it just spills out the right-hand side (measured: a
   long name pushed every row past the card edge). Fixed box + the name's
   ellipsis keeps each column truthful, and the card grows by COLUMN instead. */
.tl-row {
  height: 90px;
  width: 300px;
  border-radius: 10px;
  display: grid;
  /* Avatar column is 76px for a 50px picture: the ring adds 9px a side (68px
     total) and the rest keeps it off the name. Ranks without a ring simply
     centre in the same column, so every row keeps one consistent grid. */
  grid-template-columns: 62px 76px 1fr;
  align-items: center;
  box-sizing: border-box;
  /* no background for ranks 4-5 */
}

/* Top-3 rows: rgba(245, 217, 125, 0.3) */
.tl-row.rank-1,
.tl-row.rank-2,
.tl-row.rank-3 {
  background: rgba(245, 217, 125, 0.3);
  /* Positioning context for the row background below (the row itself is a grid,
     so the bg must be taken out of flow or it would claim a grid cell). */
  position: relative;
}

/* Podium row background (ranks 1-3) — fills the row, behind every cell.
   border-radius: inherit so a square asset can't square off the row's corners;
   the tier tint above still shows through a transparent asset. */
.tl-row-bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: inherit;
  pointer-events: none;
  z-index: 0;
}

/* Cells paint over the background layer. */
.tl-row > .tl-rank-col,
.tl-row > .tl-avatar,
.tl-row > .tl-user-info {
  position: relative;
  z-index: 1;
}

/* Ranks 4+ recede so the podium reads first. render() gives ONLY ranks 1-3 a
   rank-N class, so :not() is what identifies the rest — no markup change.
   Opacity (not a colour change) keeps this working on any background and dims
   the avatar/name/count together as one unit. */
.tl-row:not(.rank-1):not(.rank-2):not(.rank-3) {
  opacity: 0.65;
}

/* ── LEFT col: rank badge / number ── */
.tl-rank-col {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
}

/* Rank badge — base box for ranks 4+ (plain number, no crown). */
.tl-rank-badge {
  position: relative;
  width: 42px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Rank number text — 24px, white + shadow */
.tl-rank-num {
  font-family: 'Noto Sans Thai', sans-serif;
  font-size: 24px;
  font-weight: 700;
  color: #FFFFFF;
  text-shadow: 0 0 6px #000000;
  line-height: 1;
}

/* ── Jewelled SVG crown as the rank badge (top 1-3) ──────────────────────────
   Mirrors the Console preview (.tlk-rank-badge--crown in
   src/assets/css/top-likers-page.css), scaled to 52×45 so it sits inside this
   overlay's 62px rank column with a little breathing room (the Console's own
   table is wider and uses 60×52).

   The crown SVG ships with NO width/height attributes, so THESE RULES are the
   only thing giving it a size — an unsized SVG defaults to ~300px and swallows
   the row. Never remove the sizing here without adding it to the markup. */
.tl-rank-badge--crown {
  position: relative;
  width: 52px;
  height: 45px;
  border: none;
  background: none;
  border-radius: 0;
  display: block;
}

.tl-rank-badge--crown svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  filter: drop-shadow(0 3px 4px rgba(0, 0, 0, 0.5));
  animation: tl-crown-drop 0.55s cubic-bezier(0.18, 1.5, 0.5, 1) both;
}

/* Number sits low, inside the crown's jewelled base band. */
.tl-rank-badge--crown .tl-rank-num {
  position: absolute;
  z-index: 2;
  left: 0;
  right: 0;
  bottom: 6px;
  text-align: center;
  font-size: 13px;
  font-weight: 900;
  color: #fff;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.95), 0 0 4px rgba(0, 0, 0, 0.75);
}

/* Soft circular tier glow behind each crown — fades fully to transparent so no
   square edge shows on the stream. */
.tl-rank-badge--crown::after {
  content: '';
  position: absolute;
  inset: -12px;
  z-index: 0;
  opacity: 0.6;
}

.tl-rank-badge--1::after { background: radial-gradient(circle at 50% 55%, rgba(255, 210, 90, 0.55), transparent 60%); }
.tl-rank-badge--2::after { background: radial-gradient(circle at 50% 55%, rgba(180, 214, 230, 0.5), transparent 60%); }
.tl-rank-badge--3::after { background: radial-gradient(circle at 50% 55%, rgba(224, 150, 120, 0.5), transparent 60%); }

/* #1 shimmers + its halo pulses. */
.tl-rank-badge--1 svg {
  animation: tl-crown-drop 0.55s cubic-bezier(0.18, 1.5, 0.5, 1) both,
             tl-crown-shimmer 2s ease-in-out infinite 0.6s;
}

.tl-rank-badge--1::after { animation: tl-crown-halo 2s ease-in-out infinite 0.6s; }

/* Sparkles twinkle. */
.tl-rank-badge--crown .cr-spark { transform-box: fill-box; transform-origin: center; }
.tl-rank-badge--crown .cr-spark-a { animation: cr-twinkle 1.8s ease-in-out infinite; }
.tl-rank-badge--crown .cr-spark-b { animation: cr-twinkle 1.8s ease-in-out infinite 0.9s; }

@keyframes cr-twinkle {
  0%, 100% { opacity: 0.2; transform: scale(0.6); }
  50%      { opacity: 1;   transform: scale(1.1); }
}

@keyframes tl-crown-drop {
  0%   { transform: translateY(-14px) scale(0.5) rotate(-12deg); opacity: 0; }
  60%  { transform: translateY(2px) scale(1.08) rotate(3deg); }
  100% { transform: translateY(0) scale(1) rotate(0); opacity: 1; }
}

@keyframes tl-crown-shimmer {
  0%, 100% { filter: drop-shadow(0 3px 4px rgba(0,0,0,.5)) drop-shadow(0 0 3px rgba(255,214,102,.6)); }
  50%      { filter: drop-shadow(0 3px 4px rgba(0,0,0,.5)) drop-shadow(0 0 13px rgba(255,230,150,1)); }
}

@keyframes tl-crown-halo {
  0%, 100% { opacity: 0.4; transform: scale(1); }
  50%      { opacity: 0.8; transform: scale(1.12); }
}

/* ── MIDDLE col: avatar — Ellipse 115-118 — 50px circle ──
   `position: relative` + visible overflow so a podium ring can be drawn AROUND
   the picture. The ring extends past this box, and the row's 60px avatar column
   (grid-template-columns) is wider than the 50px circle, which is exactly the
   slack the ring needs — so it never clips or shifts the layout. */
.tl-avatar {
  position: relative;
  width: 50px;
  height: 50px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.2);
  justify-self: center;
  align-self: center;
  flex: 0 0 50px;
}

/* The PICTURE only — :not(.tl-avatar-ring) matters: the ring is an <img> inside
   this same box, and a bare `.tl-avatar img` rule would override its size and
   snap it back to the avatar's 50px circle (no ring visible at all). */
.tl-avatar > img:not(.tl-avatar-ring) {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 50%;
}

/* Podium ring (ranks 1-3), scaled to the avatar so it reads as a frame around
   it rather than a sticker sitting on top — purely decorative, drawn over the
   picture.

   -9px matches the Console preview's ring gap, so the OBS board and the in-app
   preview read the same. The 68px avatar column + the 90px row leave room for
   it, so it never clips or pushes the name. */
.tl-avatar-ring {
  position: absolute;
  inset: -9px;
  width: calc(100% + 18px);
  height: calc(100% + 18px);
  object-fit: contain;
  border-radius: 0;
  pointer-events: none;
  z-index: 2;
}

/* ── RIGHT col: name + heart + count ── */
.tl-user-info {
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-width: 0;
  padding-left: 6px;
}

/* Name: 22px, white, Noto Sans Thai */
.tl-name {
  font-family: 'Noto Sans Thai', sans-serif;
  font-size: 22px;
  font-weight: 700;
  color: #FFFFFF;
  text-shadow: 0 0 6px #000000;
  line-height: 33px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Likes row: heart + count */
.tl-likes {
  display: flex;
  align-items: center;
  gap: 5px;
  line-height: 1;
}

/* Heart: Figma SVG — 25×22px */
.tl-heart {
  display: flex;
  align-items: center;
  flex: 0 0 auto;
  line-height: 0;
}

.tl-heart svg {
  width: 25px;
  height: 22px;
  display: block;
}

/* Count: 32px, white, Noto Sans Thai */
.tl-likes-count {
  font-family: 'Noto Sans Thai', sans-serif;
  font-size: 32px;
  font-weight: 700;
  color: #FFFFFF;
  text-shadow: 0 0 6px #000000;
  line-height: 48px;
  font-variant-numeric: tabular-nums;
}

/* ── Empty state ── */
.tl-empty {
  text-align: center;
  color: rgba(255, 255, 255, 0.5);
  font-size: 14px;
  padding: 20px 8px;
}

/* ── Pop animation on like count increase ── */
@keyframes tl-pop {
  0% {
    transform: scale(1);
  }

  40% {
    transform: scale(1.04);
  }

  100% {
    transform: scale(1);
  }
}

.tl-row.tl-bump {
  animation: tl-pop 0.45s ease-out;
}
