/* Site-wide rank mascot — bottom-right floating companion, see js/mascot.js.
   Shows the viewer's selected collection character (or the plain ArenaElite
   badge if none picked) and doubles as the picker on click. Only ever shows
   your own pick, never anyone else's, so it can't clutter no matter how many
   guildmates use it. */
.rank-mascot {
  position: fixed;
  right: 20px;
  bottom: 20px;
  z-index: 500;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 10px;
  opacity: 0;
  transform: translateY(12px);
  transition: opacity 0.25s ease, transform 0.25s ease;
  pointer-events: none;
}

.rank-mascot.ready {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}

/* The editor/counter-editor's #paletteDock (css/style.css's .palette-dock,
   toggled open via js/editor.js + js/counter.js) is also fixed to the
   bottom-right area of the viewport, and on short screens its own last row
   (ตัวละคร/สัตว์เลี้ยง/แหวน/เซ็ตไอเกม items) lands right under this widget's
   100–150px corner footprint (z-index 500 > the dock's 200, so it's the
   dock's content that gets hidden). Simplest fix: get out of the way
   entirely while the dock is actually open — the dock already occupies
   that whole strip, and nobody needs the mascot mid-edit. Scoped to
   ".palette-dock" existing AND not collapsed, rather than always hiding
   near an editor page, so it still shows once the dock is tucked away.
   (js/mascot.js appends .rank-mascot as the last child of body, after the
   dock — so this has to be a body-level :has(), not a ~ sibling selector,
   to match regardless of DOM order.) */
body:has(.palette-dock:not(.collapsed)) .rank-mascot {
  display: none;
}

/* Speech bubble — "[ชื่อ] ได้แต้มเพิ่ม X แต้ม!" (js/mascot.js's queueSpeech),
   anchored above the mascot via absolute positioning rather than sitting in
   the flex flow, so it doesn't push the button down while hidden. Every
   message shown here also lands in the 🔔 notifications popover further
   down this file, so a bubble that's already faded isn't gone for good. */
.rank-mascot-speech {
  position: absolute;
  bottom: calc(100% + 10px);
  right: 0;
  width: max-content;
  max-width: 220px;
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: 14px;
  padding: 10px 14px;
  font-size: 13px;
  font-weight: 700;
  color: var(--text);
  box-shadow: var(--shadow);
  text-align: center;
  opacity: 0;
  transform: translateY(6px);
  transition: opacity 0.25s ease, transform 0.25s ease;
  pointer-events: none;
}

.rank-mascot-speech.show {
  opacity: 1;
  transform: translateY(0);
}

/* Unread-notification signal — small red dot, base styling shared by both
   places it can appear (js/mascot.js's updateNotifBadge picks one via the
   wrap's data-unread attribute below): on the 🔔 quick-menu icon while the
   menu is open, or directly on the avatar itself while it's collapsed (the
   icon isn't visible then), so the reminder is never simply hidden away. */
.rank-mascot-badge-dot {
  display: none;
  position: absolute;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: #ef4444;
  border: 2px solid var(--bg-page);
  z-index: 3;
}

.rank-mascot-avatar-badge-wrap {
  position: absolute;
  right: 0;
  bottom: 0;
  width: 150px;
  height: 150px;
  pointer-events: none;
}

.rank-mascot-avatar-badge-wrap .rank-mascot-badge-dot {
  top: 10px;
  right: 10px;
}

#rankMascotNotifMenuBtn .rank-mascot-badge-dot,
#rankMascotFavMenuBtn .rank-mascot-badge-dot {
  top: 2px;
  right: 2px;
}

.rank-mascot[data-unread="true"]:not(.menu-open) .rank-mascot-avatar-badge-wrap .rank-mascot-badge-dot,
.rank-mascot[data-unpicked="true"]:not(.menu-open) .rank-mascot-avatar-badge-wrap .rank-mascot-badge-dot {
  display: block;
}

.rank-mascot[data-unread="true"].menu-open #rankMascotNotifMenuBtn .rank-mascot-badge-dot {
  display: block;
}

/* Unlike the 🔔 dot (which toggles via wrap[data-unread]), this one's
   presence in the DOM is already conditional — js/mascot.js's
   favMenuBtnHtml only renders the span at all when nothing's picked yet —
   so it's shown unconditionally here rather than gated by another
   attribute selector. */
#rankMascotFavMenuBtn .rank-mascot-badge-dot {
  display: block;
}

/* Notifications popover — toggled from the quick-menu's 🔔 icon via the
   wrap's "notif-open" class (same pattern as "เลือกตัวโปรด"/atk search).
   Opening it marks everything read (js/mascot.js's notifMenuBtn click
   handler), clearing the red dot above. */
.rank-mascot-notif-popover {
  display: none;
  flex-direction: column;
  gap: 10px;
  width: 260px;
  max-height: 60vh;
  overflow-y: auto;
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: 16px;
  padding: 14px 16px;
  box-shadow: var(--shadow);
}

.rank-mascot.notif-open .rank-mascot-notif-popover {
  display: flex;
}

.rank-mascot-notif-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.rank-mascot-notif-empty {
  font-size: 12px;
  color: var(--muted);
  text-align: center;
  padding: 10px 4px;
}

.rank-mascot-notif-clear-all {
  align-self: flex-end;
  border: none;
  background: none;
  padding: 0;
  color: var(--accent);
  font-size: 11px;
  font-weight: 700;
  cursor: pointer;
}

.rank-mascot-notif-item {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 4px 8px;
  background: var(--bg-page);
  border: 1px solid var(--card-border);
  border-radius: 10px;
  padding: 8px 8px 8px 12px;
  font-size: 12px;
  font-weight: 700;
  color: var(--text);
}

.rank-mascot-notif-text {
  flex: 1 1 auto;
  min-width: 0;
  line-height: 1.4;
  text-align: left;
}

.rank-mascot-notif-time {
  flex-shrink: 0;
  font-size: 10px;
  font-weight: 600;
  color: var(--muted);
}

.rank-mascot-notif-close {
  flex-shrink: 0;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  border: none;
  background: var(--card-bg);
  color: var(--muted);
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}

.rank-mascot-notif-close:hover {
  color: var(--text);
}

/* ติดต่อผู้ดูแล — toggled from the quick-menu's ✉️ icon via the wrap's
   "contact-open" class (same pattern as the other popovers). Relays into a
   private Discord channel server-side, see functions/contact/send.js. */
.rank-mascot-contact-popover {
  display: none;
  flex-direction: column;
  gap: 10px;
  width: 260px;
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: 16px;
  padding: 14px 16px;
  box-shadow: var(--shadow);
}

.rank-mascot.contact-open .rank-mascot-contact-popover {
  display: flex;
}

.mascot-contact-input {
  width: 100%;
  box-sizing: border-box;
  resize: vertical;
  border: 1px solid var(--card-border);
  border-radius: 10px;
  background: var(--bg-page);
  color: var(--text);
  font-family: inherit;
  font-size: 13px;
  padding: 8px 10px;
  outline: none;
}

.mascot-contact-input:focus {
  border-color: var(--accent);
}

.mascot-contact-attach-row {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

.mascot-contact-attach-btn {
  border: 1px solid var(--card-border);
  border-radius: 8px;
  background: var(--bg-page);
  color: var(--text);
  font-size: 12px;
  font-weight: 700;
  padding: 6px 10px;
  cursor: pointer;
}

.mascot-contact-attach-btn:hover {
  border-color: var(--accent);
}

/* Thumbnail + remove — shown once js/mascot.js's file input change handler
   picks a valid image, in place of the attach button's row (not replacing
   it, since re-attaching just swaps the file). */
.mascot-contact-preview {
  display: flex;
  align-items: center;
  gap: 6px;
}

.mascot-contact-preview img {
  width: 40px;
  height: 40px;
  object-fit: cover;
  border-radius: 8px;
  border: 1px solid var(--card-border);
}

.mascot-contact-preview-remove {
  width: 20px;
  height: 20px;
  border-radius: 50%;
  border: none;
  background: var(--card-bg);
  color: var(--muted);
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}

.mascot-contact-preview-remove:hover {
  color: var(--text);
}

.mascot-contact-status {
  min-height: 14px;
  font-size: 11px;
  font-weight: 600;
  color: var(--muted);
  text-align: center;
}

.mascot-contact-send {
  border: none;
  border-radius: 10px;
  background: var(--accent);
  color: #fff;
  font-size: 13px;
  font-weight: 800;
  padding: 9px 12px;
  cursor: pointer;
  transition: opacity 0.15s ease;
}

.mascot-contact-send:hover {
  opacity: 0.9;
}

.mascot-contact-send:disabled {
  opacity: 0.6;
  cursor: default;
}

/* Update-announcement pill — sits above the mascot button (flex column,
   align-items: flex-end), see js/mascot.js's checkAnnouncement(). Only shown
   at all while unread; once read it disappears from here entirely and lives
   on as one more icon in .rank-mascot-menu instead. */
.rank-announcement-btn {
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: 40px;
  width: max-content;
  max-width: min(240px, calc(100vw - 40px));
  padding: 8px 16px;
  border-radius: 20px;
  border: none;
  background: linear-gradient(135deg, #ef4444, #f97316);
  box-shadow: 0 4px 14px rgba(239, 68, 68, 0.45);
  color: #fff;
  font-size: 13px;
  font-weight: 700;
  cursor: pointer;
  transition: padding 0.2s ease, width 0.2s ease;
  animation: announcement-pulse 1.6s ease-in-out infinite;
}

.rank-announcement-btn:hover {
  animation-play-state: paused;
  transform: scale(1.08);
}

@keyframes announcement-pulse {
  0%, 100% { transform: scale(1); box-shadow: 0 4px 14px rgba(239, 68, 68, 0.45); }
  50%      { transform: scale(1.05); box-shadow: 0 6px 22px rgba(239, 68, 68, 0.75); }
}

.rank-announcement-icon {
  font-size: 16px;
  line-height: 1;
  flex-shrink: 0;
}

.rank-announcement-text {
  line-height: 1.3;
  text-align: left;
}

/* No circle/card chrome here on purpose — just the art floating free, so it
   reads as a character standing in the corner rather than a UI button. */
.rank-mascot-btn {
  position: relative;
  width: 150px;
  height: 150px;
  border: none;
  background: none;
  padding: 0;
  cursor: pointer;
  transition: transform 0.15s ease;
}

.rank-mascot-btn:hover {
  transform: scale(1.05);
}

/* Quick-menu — tapping the avatar (.rank-mascot-btn) fans these round icon
   buttons out in an orbit AROUND it (not just stacked above) instead of
   jumping straight into any one feature; see js/mascot.js's
   closeMascotPanels/"menu-open". Each icon then opens its own popover
   (favorite picker / atk search / notifications) or, for the already-read
   announcement, just opens the doc link directly.
   Positioned absolute + sized to exactly overlay the avatar (150×150, see
   the matching #rankMascotBtn size) so every button's --mx/--my arc offset
   (below) is measured from the avatar's own center, letting the orbit pass
   above/left/below it instead of only ever sitting above. pointer-events:
   none on the wrapper itself — it fully overlaps the avatar box, and
   without this it would eat clicks meant for the avatar underneath even
   while visually empty; only the individual buttons re-enable it, and only
   once open. */
.rank-mascot-menu {
  position: absolute;
  right: 0;
  bottom: 0;
  width: 150px;
  height: 150px;
  pointer-events: none;
}

.rank-mascot-menu-btn {
  --mx: 0px;
  --my: 0px;
  position: absolute;
  right: 51px; /* (150 - 48) / 2 — centered on the avatar at rest */
  bottom: 51px;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  border: 1px solid var(--card-border);
  background: var(--card-bg);
  box-shadow: var(--shadow);
  padding: 0;
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  /* No overflow:hidden here — the favorite icon's img already clips itself
     to a circle via its own border-radius (below), and clipping at this
     level was cutting off part of the badge dot (top:2px/right:2px sits
     outside the circle inscribed in this 48px square, since a corner-ish
     offset is further from center than the circle's radius). */
  opacity: 0;
  transform: translate(0, 0) scale(0.4);
  pointer-events: none;
  transition: transform 0.2s ease, opacity 0.15s ease, background 0.2s ease, border-color 0.2s ease;
}

.rank-mascot.menu-open .rank-mascot-menu-btn {
  opacity: 1;
  pointer-events: auto;
  transform: translate(var(--mx), var(--my)) scale(1);
}

/* Pointing at any one icon grows + accent-colors it (below) and shrinks the
   rest — makes the hovered action read as "picked" instead of the whole row
   just sitting there uniform, and any of the five can be the one that
   stands out rather than always the same button. :has() lets a sibling's
   :hover reach back up to style the others; :not(:hover) on the shrink rule
   keeps it from ever fighting the grow rule below on the one button
   actually under the pointer. */
.rank-mascot-menu:has(.rank-mascot-menu-btn:hover) .rank-mascot-menu-btn:not(:hover) {
  transform: translate(var(--mx), var(--my)) scale(0.82);
}

.rank-mascot-menu-btn:hover {
  transform: translate(var(--mx), var(--my)) scale(1.22);
  background: var(--accent);
  border-color: var(--accent);
}

/* Arc positions, equal radius (105px) from the avatar's center, sweeping
   120° down the left side in five evenly-spaced 30° steps — straight up,
   past straight-left, to lower-left — instead of only ever fanning out
   above it. Radius has to clear the avatar's own 75px half-width plus each
   button's 24px half-width (75+24=99px) with room to spare, hence 105. The
   lower-left button is deliberately NOT swung any further down than this
   (e.g. straight-down, 270°) — the avatar already sits flush against the
   viewport's bottom edge (.rank-mascot's bottom:20px), so anything much
   past ~210° would render partly off-screen. */
#rankMascotFavMenuBtn { --mx: 0px; --my: -105px; }
#rankMascotAtkMenuBtn { --mx: -52.5px; --my: -90.9px; }
#rankMascotNotifMenuBtn { --mx: -90.9px; --my: -52.5px; }
#rankMascotContactMenuBtn { --mx: -105px; --my: 0px; }
#rankMascotAnnMenuBtn { --mx: -90.9px; --my: 52.5px; }

/* The favorite-picker icon shows the current pick's actual portrait
   (js/mascot.js's favMenuBtnHtml) rather than a generic glyph. */
.rank-mascot-menu-btn img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 50%;
}

/* Rank aura — glow behind the mascot, strength/size set per-tier by
   js/mascot.js's render() (--aura-opacity/--aura-scale). Painted first
   (::before, no z-index needed) so it sits behind the badge/character
   images that follow it in the DOM. */
.rank-mascot-btn::before {
  content: "";
  position: absolute;
  inset: 8%;
  border-radius: 50%;
  background: radial-gradient(circle, var(--frame-color, var(--accent)) 0%, transparent 72%);
  opacity: var(--aura-opacity, 0.25);
  transform: scale(var(--aura-scale, 1));
  filter: blur(12px);
  pointer-events: none;
  animation: rank-mascot-aura-pulse 2.6s ease-in-out infinite;
}

@keyframes rank-mascot-aura-pulse {
  0%, 100% { opacity: var(--aura-opacity, 0.25); }
  50% { opacity: calc(var(--aura-opacity, 0.25) * 0.55); }
}

@media (prefers-reduced-motion: reduce) {
  .rank-mascot-btn::before { animation: none; }
  .rank-announcement-btn { animation: none; }
}

/* Current ArenaElite tier badge, behind the character as a crest — only
   rendered when a character is actually picked (see js/mascot.js's
   mascotBtnHtml). */
.rank-mascot-bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  opacity: 0.5;
  filter: drop-shadow(0 0 18px var(--frame-glow, transparent));
}

.rank-mascot-char {
  position: relative;
  width: 100%;
  height: 100%;
  object-fit: contain;
  filter: drop-shadow(0 8px 16px rgba(0, 0, 0, 0.35));
}

.rank-mascot-popover {
  display: none;
  flex-direction: column;
  gap: 10px;
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: 16px;
  padding: 14px 16px;
  box-shadow: var(--shadow);
}

.rank-mascot.open .rank-mascot-popover {
  display: flex;
}

.rank-mascot-popover-title {
  font-size: 12px;
  font-weight: 800;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.03em;
  text-align: center;
}

/* Spells out what picking actually does — added because most people were
   never clicking "เลือกตัวโปรด" at all, having no reason to guess it puts
   anything on the public ranking list. Only the favorite-picker popover
   uses this (atk search/notifications are self-explanatory once opened). */
.rank-mascot-popover-subtitle {
  font-size: 11px;
  font-weight: 600;
  color: var(--muted);
  text-align: center;
  line-height: 1.4;
  max-width: 220px;
  margin: -4px auto 0;
}

/* Collection picker grid, inside the popover. Cumulative unlocks by tier,
   see js/mascot.js's TIER_COLLECTION. The art itself is animated webp, so no
   CSS motion is layered on top here — that would just fight the sprite's
   own animation. */
.my-collection-grid {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px;
  max-width: 260px;
}

.my-collection-item {
  border: none;
  background: none;
  padding: 0;
  cursor: pointer;
  line-height: 0;
  transition: transform 0.15s ease;
}

.my-collection-item:hover {
  transform: translateY(-3px);
}

.my-collection-item img {
  width: 64px;
  height: 64px;
  object-fit: contain;
  display: block;
  border-radius: 12px;
  transition: filter 0.2s ease;
}

.my-collection-item--selected img {
  filter: drop-shadow(0 0 8px var(--accent)) drop-shadow(0 0 16px var(--accent));
}

/* "ตัวนี้ควรตีทีมไหน?" — its own popover (separate from "เลือกตัวโปรด"),
   toggled from the quick-menu's ⚔️ icon via the wrap's "atk-open" class. See
   js/mascot.js's initAtkSearch — that menu icon itself only appears once a
   guild context + access to it are confirmed. */
.rank-mascot-atk-popover {
  display: none;
  flex-direction: column;
  gap: 10px;
  width: 260px;
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: 16px;
  padding: 14px 16px;
  box-shadow: var(--shadow);
}

.rank-mascot.atk-open .rank-mascot-atk-popover {
  display: flex;
}

.mascot-atk-input-wrap {
  position: relative;
}

.mascot-atk-input {
  width: 100%;
  box-sizing: border-box;
  border: 1px solid var(--card-border);
  border-radius: 10px;
  background: var(--bg-page);
  color: var(--text);
  font-size: 13px;
  padding: 8px 10px;
  outline: none;
}

.mascot-atk-input:focus {
  border-color: var(--accent);
}

/* Autocomplete dropdown — floats above whatever's below it (results list)
   rather than pushing layout around as matches come and go. */
.mascot-atk-suggest {
  display: none;
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  z-index: 1;
  max-height: 220px;
  overflow-y: auto;
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: 10px;
  box-shadow: var(--shadow);
  padding: 4px;
}

.mascot-atk-suggest.show {
  display: block;
}

.mascot-atk-suggest-item {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  border: none;
  background: none;
  color: var(--text);
  font-size: 13px;
  text-align: left;
  padding: 6px 8px;
  border-radius: 8px;
  cursor: pointer;
}

.mascot-atk-suggest-item:hover {
  background: var(--bg-page);
}

.mascot-atk-suggest-item img {
  width: 26px;
  height: 26px;
  object-fit: cover;
  border-radius: 6px;
  flex-shrink: 0;
}

.mascot-atk-results {
  display: flex;
  flex-direction: column;
  gap: 8px;
  max-height: 280px;
  overflow-y: auto;
}

.mascot-atk-empty {
  font-size: 12px;
  color: var(--muted);
  text-align: center;
  padding: 10px 4px;
}

.mascot-atk-card {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px;
  border: 1px solid var(--card-border);
  border-radius: 10px;
  background: var(--bg-page);
  text-decoration: none;
  color: var(--text);
  transition: border-color 0.15s ease;
}

.mascot-atk-card:hover {
  border-color: var(--accent);
}

.mascot-atk-card-heroes {
  display: flex;
  gap: 3px;
  flex-shrink: 0;
}

.mascot-atk-slot {
  width: 32px;
  height: 32px;
  border-radius: 7px;
  overflow: hidden;
  border: 1px solid var(--card-border);
  background: var(--card-bg);
  flex-shrink: 0;
}

.mascot-atk-slot img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.mascot-atk-card-info {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.mascot-atk-castle {
  font-size: 11px;
  font-weight: 800;
  color: var(--accent);
}

.mascot-atk-castle--gone {
  color: var(--muted);
  font-weight: 600;
}

.mascot-atk-fp {
  font-size: 10px;
  font-weight: 700;
  color: #eab308;
}

.mascot-atk-counter-name {
  font-size: 11px;
  color: var(--muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

@media (max-width: 640px) {
  .rank-mascot { right: 10px; bottom: 10px; }
  .rank-mascot-btn { width: 100px; height: 100px; }
  .rank-announcement-btn { min-height: 34px; padding: 6px 12px; font-size: 12px; }
  .rank-mascot-atk-popover { width: 220px; }
  .rank-mascot-notif-popover { width: 220px; }
  .rank-mascot-avatar-badge-wrap { width: 100px; height: 100px; }
  .rank-mascot-menu { width: 100px; height: 100px; }
  .rank-mascot-menu-btn { width: 40px; height: 40px; right: 30px; bottom: 30px; } /* (100 - 40) / 2 */
  /* Same 120° left-side orbit as desktop, radius scaled down to 87px to
     match the smaller 100px avatar / 40px buttons. */
  #rankMascotFavMenuBtn { --mx: 0px; --my: -87px; }
  #rankMascotAtkMenuBtn { --mx: -43.5px; --my: -75.4px; }
  #rankMascotNotifMenuBtn { --mx: -75.4px; --my: -43.5px; }
  #rankMascotContactMenuBtn { --mx: -87px; --my: 0px; }
  #rankMascotAnnMenuBtn { --mx: -75.4px; --my: 43.5px; }
  .rank-mascot-contact-popover { width: 220px; }
}
