/* =============================================================================
   trophy.css - Trophy component: catalogue list, filters, detail modal blocks.

   Reference: `js/UI/views/TrophiesView.js` (the catalogue), `js/UI/views/ProfileView.js` (the
   pinned tiles) and `js/UI/components/TrophyDetail.js` (the shared detail rendering).

   The trophy list used to live in `css/views/profile.css`. It is shared by two screens now — the
   "Trophées" destination and the pinned trophies of the profile — so it lives in a component
   stylesheet both of them load. Colors come exclusively from `css/themes.css` (including the
   `--color-trophy-*` medal palette).

   The catalogue itself is a CENTRED flex grid of small tiles (three per row on a phone, five from
   the tablet up), cut into a category heading and, under it, one heading per TYPE of trophy. The
   `.trophy-tile*` classes belong to it; `.trophy__track` / `.trophy__fill` / `.trophy__icon` /
   `.trophy__rarity` are shared with the pinned tiles of the profile and the detail modal.
   ============================================================================= */

/* --- Catalogue page --------------------------------------------------------- */

.trophies {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

.trophies__panel {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.trophies__summary {
  font-size: var(--font-size-sm);
  font-variant-numeric: tabular-nums;
  color: var(--color-text-muted);
}

.trophies__empty {
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
}

/* --- Filters ---------------------------------------------------------------- */

.trophy-filters {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: var(--space-3);
}

.trophy-filters__field {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

/* --- Groups ----------------------------------------------------------------- */

/* The category ("Par extension", "Global", "Collection"): the widest cut of the catalogue. */
.trophy-group {
  margin: var(--space-4) 0 0 0;
  font-size: var(--font-size-sm);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--color-text-muted);
}

/* The TYPE of trophy inside a category ("Complétion des extensions", "Boosters ouverts par
   extension"…): one step lighter than the category above it. */
.trophy-subgroup {
  margin: var(--space-3) 0 0 0;
  font-size: var(--font-size-xs);
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--color-text-muted);
}

/* --- Grid of tiles ---------------------------------------------------------- */

/* Flex rather than grid on purpose: a partial row (the last tiles of a group) stays CENTRED instead
   of hugging the left edge. Three tiles per row on a phone, five on a wide screen. */
.trophy-grid {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-3);
  margin: var(--space-3) 0 0 0;
  padding: 0;
  list-style: none;
}

.trophy-tile {
  position: relative;
  display: flex;
  flex: 0 0 calc((100% - 2 * var(--space-3)) / 3);
  max-width: 11rem;
  animation: trophy-tile-in var(--duration-base) var(--easing-standard) backwards;
  animation-delay: calc(var(--tile-index, 0) * 25ms);
}

/* A pinned trophy is flagged on the tile: the catalogue is where the three highlighted trophies
   are picked, and the top-right button below is what picks them. */
.trophy-tile[data-pinned="true"] .trophy-tile__open {
  border-color: var(--color-accent);
}

/* The pin toggle, in the top-right corner. It is a SIBLING of the tile button (nested buttons are
   invalid HTML), so it can be a real, focusable control instead of a dead marker. Unpinned it
   stays discreet; pinned it takes the accent, like the favourite heart of the collection. */
.trophy-tile__pin {
  position: absolute;
  top: calc(-1 * var(--space-1));
  right: calc(-1 * var(--space-1));
  z-index: 2;
  display: grid;
  place-items: center;
  width: 1.9rem;
  height: 1.9rem;
  padding: 0;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  background-color: var(--color-surface);
  box-shadow: var(--shadow-sm);
  cursor: pointer;
  touch-action: manipulation;
  transition: border-color var(--duration-fast) var(--easing-standard),
    background-color var(--duration-fast) var(--easing-standard),
    transform var(--duration-fast) var(--easing-standard);
}

.trophy-tile__pin img {
  width: 0.9rem;
  height: 0.9rem;
  object-fit: contain;
  filter: var(--icon-filter);
}

.trophy-tile__pin[aria-pressed="false"] {
  opacity: 0.65;
}

.trophy-tile__pin:hover,
.trophy-tile__pin:focus-visible {
  opacity: 1;
  border-color: var(--color-accent);
  transform: translateY(-2px);
}

.trophy-tile__pin:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
}

.trophy-tile__pin[aria-pressed="true"] {
  border-color: var(--color-accent);
  background-color: var(--color-accent);
}

/* From the tablet up there is room for five tiles per row. */
@media (min-width: 768px) {
  .trophy-tile {
    flex-basis: calc((100% - 4 * var(--space-3)) / 5);
  }
}

/* A locked trophy stays readable but clearly recessed. */
.trophy-tile[data-unlocked="false"] {
  opacity: 0.72;
}

/* The tile is ONE button: the medal, the name and the bar with its percentage, nothing else. */
.trophy-tile__open {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  align-items: center;
  gap: var(--space-1);
  width: 100%;
  min-height: var(--touch-target);
  padding: var(--space-3) var(--space-2);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background-color: var(--color-surface-alt);
  color: var(--color-text);
  cursor: pointer;
  touch-action: manipulation;
  transition: transform var(--duration-fast) var(--easing-standard),
    border-color var(--duration-fast) var(--easing-standard),
    background-color var(--duration-fast) var(--easing-standard);
}

.trophy-tile__open:hover,
.trophy-tile__open:focus-visible {
  border-color: var(--color-accent);
  background-color: var(--color-surface);
  transform: translateY(-2px);
}

/* A keyboard focus must be unmistakable, so it does not rely on the default ring alone. */
.trophy-tile__open:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
}

.trophy-tile__icon {
  width: 2.75rem;
  height: 2.75rem;
  object-fit: contain;
  /* Halo of the medal, keyed by the rarity of the trophy: bronze has none, silver and gold are
     light, diamond and emerald are medium. The RADIUS is the rarity's; the STRENGTH is
     `--trophy-glow-scale` (0-2.5), published on <html> by `GlowManager` from the settings slider.
     Level 2, the default, is a factor of 1 - the intensity these radii were tuned at. */
  --trophy-glow-color: transparent;
  --trophy-glow-radius: 0px;
  filter: drop-shadow(
    0 0 calc(var(--trophy-glow-radius) * var(--trophy-glow-scale, 1)) var(--trophy-glow-color)
  );
}

.trophy-tile[data-rarity="silver"] .trophy-tile__icon {
  --trophy-glow-color: rgba(255, 255, 255, 0.75);
  --trophy-glow-radius: 4px;
}

.trophy-tile[data-rarity="gold"] .trophy-tile__icon {
  --trophy-glow-color: rgba(255, 205, 80, 0.85);
  --trophy-glow-radius: 5px;
}

.trophy-tile[data-rarity="diamond"] .trophy-tile__icon {
  --trophy-glow-color: rgba(150, 225, 255, 0.9);
  --trophy-glow-radius: 8px;
}

.trophy-tile[data-rarity="emerald"] .trophy-tile__icon {
  --trophy-glow-color: rgba(53, 224, 138, 0.9);
  --trophy-glow-radius: 8px;
}

/* A locked medal stays legible but reads as "not earned yet": greyed out and WITHOUT the halo.
   The glow is a reward, not a property of the rarity, so a trophy the player has not unlocked
   must not shine. The full filter is repeated here because a `filter` declaration replaces the
   one above instead of adding to it. */
.trophy-tile[data-unlocked="false"] .trophy-tile__icon {
  --trophy-glow-color: transparent;
  --trophy-glow-radius: 0px;
  filter: grayscale(1);
  opacity: 0.7;
}

.trophy-tile__title {
  display: -webkit-box;
  overflow: hidden;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  font-size: var(--font-size-xs);
  font-weight: 700;
  text-align: center;
}

/* `margin-top: auto` keeps the bars of a row aligned even when one title wraps to two lines. */
.trophy-tile__progress {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  width: 100%;
  margin-top: auto;
  padding-top: var(--space-1);
}

.trophy-tile__track {
  flex: 1 1 auto;
  height: 0.5rem;
  border-radius: var(--radius-pill);
  background-color: var(--color-surface);
  overflow: hidden;
}

.trophy-tile__percent {
  flex: 0 0 auto;
  font-size: var(--font-size-xs);
  font-variant-numeric: tabular-nums;
  color: var(--color-text-muted);
}

/* An unlocked trophy shows a full, accented bar: the percentage is what it earned. */
.trophy-tile[data-unlocked="true"] .trophy-tile__percent {
  font-weight: 700;
  color: var(--color-accent);
}

/* Shared by the profile strip and the detail modal (the catalogue tiles have their own track). */
.trophy__track {
  height: 0.6rem;
  border-radius: var(--radius-pill);
  background-color: var(--color-surface);
  overflow: hidden;
}

.trophy__fill {
  height: 100%;
  border-radius: var(--radius-pill);
  background-color: var(--color-accent);
  transition: width var(--duration-base) var(--easing-standard);
}

/* --- Medals ----------------------------------------------------------------- */

/* Only the recurring tiers ship an image today; a missing file is hidden by the view. */
.trophy__icon {
  flex: 0 0 auto;
  width: 2.25rem;
  height: 2.25rem;
  object-fit: contain;
}


/* --- Rarity badges ---------------------------------------------------------- */

.trophy__rarity {
  flex: 0 0 auto;
  padding: 2px var(--space-2);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  font-size: var(--font-size-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--color-text-muted);
}

.trophy__rarity[data-rarity="bronze"] {
  border-color: var(--color-trophy-bronze);
  color: var(--color-trophy-bronze);
}

.trophy__rarity[data-rarity="silver"] {
  border-color: var(--color-trophy-silver);
  color: var(--color-trophy-silver);
}

.trophy__rarity[data-rarity="gold"] {
  border-color: var(--color-trophy-gold);
  color: var(--color-trophy-gold);
}

.trophy__rarity[data-rarity="diamond"] {
  border-color: var(--color-trophy-diamond);
  color: var(--color-trophy-diamond);
}

.trophy__rarity[data-rarity="emerald"] {
  border-color: var(--color-trophy-emerald);
  color: var(--color-trophy-emerald);
}

/* --- Detail modal ----------------------------------------------------------- */

/* The pin toggle of an unlocked trophy: it lives at the bottom of the detail, not on the tile. */
.trophy-modal__actions {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding-top: var(--space-2);
  border-top: 1px solid var(--color-border);
}

.trophy-modal__pin {
  display: grid;
  place-items: center;
  width: 2.25rem;
  height: 2.25rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  background-color: transparent;
  cursor: pointer;
  touch-action: manipulation;
  transition: transform var(--duration-fast) var(--easing-standard),
    border-color var(--duration-fast) var(--easing-standard),
    background-color var(--duration-fast) var(--easing-standard);
}

.trophy-modal__pin:hover {
  border-color: var(--color-accent);
  background-color: var(--color-surface-alt);
  transform: translateY(-2px);
}

.trophy-modal__pin[aria-pressed="true"] {
  border-color: var(--color-accent);
  box-shadow: var(--glow-accent);
}

.trophy-modal__pin .profile__icon {
  width: 1rem;
  height: 1rem;
}

.trophy-modal__pin-label {
  font-size: var(--font-size-xs);
  color: var(--color-text-muted);
}

.modal.is-opening .modal__dialog {
  /* Slightly springier than the shared modal: this one opens from a tap on a small tile. */
  animation: trophy-modal-in var(--duration-base) var(--easing-standard);
}

.trophy-modal__header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
}

.trophy-modal__medal {
  width: 4rem;
  height: 4rem;
  object-fit: contain;
  /* The halo of an EARNED trophy, keyed by its rarity and scaled by the settings slider, exactly
     like the catalogue tile. A locked medal has no `data-unlocked="true"` and therefore no halo. */
  --trophy-glow-color: transparent;
  --trophy-glow-radius: 0px;
  filter: drop-shadow(
    0 0 calc(var(--trophy-glow-radius) * var(--trophy-glow-scale, 1)) var(--trophy-glow-color)
  );
}

.trophy-modal__medal[data-unlocked="true"][data-rarity="silver"] {
  --trophy-glow-color: rgba(255, 255, 255, 0.75);
  --trophy-glow-radius: 4px;
}

.trophy-modal__medal[data-unlocked="true"][data-rarity="gold"] {
  --trophy-glow-color: rgba(255, 205, 80, 0.85);
  --trophy-glow-radius: 5px;
}

.trophy-modal__medal[data-unlocked="true"][data-rarity="diamond"] {
  --trophy-glow-color: rgba(150, 225, 255, 0.9);
  --trophy-glow-radius: 8px;
}

.trophy-modal__medal[data-unlocked="true"][data-rarity="emerald"] {
  --trophy-glow-color: rgba(53, 224, 138, 0.9);
  --trophy-glow-radius: 8px;
}

.trophy-modal__category {
  font-size: var(--font-size-xs);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--color-text-muted);
}

.trophy-modal__text {
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
}

.trophy-modal__section {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.trophy-modal__section-title {
  margin: 0;
  font-size: var(--font-size-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--color-text-muted);
}

/* Required cards: in colour when owned, in black and white when still missing. */
.trophy-modal__cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(4.5rem, 1fr));
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.trophy-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-1);
  font-size: var(--font-size-xs);
  text-align: center;
  animation: trophy-tile-in 320ms var(--easing-standard) backwards;
  animation-delay: calc(var(--tile-index, 0) * 20ms);
}

.trophy-card__image {
  width: 100%;
  aspect-ratio: var(--card-ratio);
  object-fit: contain;
  border-radius: var(--radius-sm);
  background-color: var(--color-surface-alt);
}

.trophy-card[data-owned="false"] .trophy-card__image {
  filter: grayscale(1);
  opacity: 0.55;
}

.trophy-card__name {
  display: -webkit-box;
  overflow: hidden;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  color: var(--color-text-muted);
}

.trophy-card[data-owned="true"] .trophy-card__name {
  color: var(--color-text);
}

/* Avatars unlocked by the trophy: the locked ones stay visible, greyed out. */
.trophy-modal__icons {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(4.5rem, 1fr));
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.trophy-icon {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-1);
  font-size: var(--font-size-xs);
  text-align: center;
  animation: trophy-tile-in 320ms var(--easing-standard) backwards;
  animation-delay: calc(var(--tile-index, 0) * 20ms);
}

.trophy-icon__image {
  width: 4rem;
  height: 4rem;
  object-fit: contain;
  padding: var(--space-1);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background-color: var(--color-surface-alt);
  /* These are the AVATARS a trophy unlocks (`data/icon.json`): the same pixel art as the profile
     picker (6x6 to 192x192 sprites), so they are enlarged without interpolation here too. */
  image-rendering: pixelated;
}

.trophy-icon[data-owned="false"] .trophy-icon__image {
  filter: grayscale(1);
  opacity: 0.55;
}

.trophy-icon__name {
  color: var(--color-text-muted);
}

/* Player TITLES granted by the trophy: one per LINE, in the pixel face they are worn in
   (`css/fonts.css`). A locked one is greyed out and loses the yellow of `--color-title`: it is a
   promise, not a reward yet. */
.trophy-modal__titles {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.trophy-title {
  padding: var(--space-2);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background-color: var(--color-surface-alt);
  animation: trophy-tile-in 320ms var(--easing-standard) backwards;
  animation-delay: calc(var(--tile-index, 0) * 20ms);
}

.trophy-title__text {
  font-family: var(--font-family-title);
  font-size: var(--font-size-xs);
  line-height: 1.7;
  color: var(--color-title);
}

.trophy-title[data-owned="false"] {
  opacity: 0.6;
}

.trophy-title[data-owned="false"] .trophy-title__text {
  color: var(--color-text-muted);
}

/* --- Animations -------------------------------------------------------------- */

@keyframes trophy-tile-in {
  from {
    opacity: 0;
    transform: translateY(10px) scale(0.95);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

@keyframes trophy-modal-in {
  from {
    opacity: 0;
    transform: translateY(16px) scale(0.96);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* The "pop" played on a pin toggle, so the click is acknowledged without a toast. */
.is-popping {
  animation: trophy-pop 320ms var(--easing-standard);
}

@keyframes trophy-pop {
  0% {
    transform: scale(1);
  }
  45% {
    transform: scale(1.28) rotate(-8deg);
  }
  100% {
    transform: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .trophy__fill {
    transition: none;
  }

  /* The entry of the tiles, of the required cards and of the avatars is motion: the tiles are
     simply painted in place, and the hover of a tile stops lifting it. */
  .trophy-tile,
  .trophy-card,
  .trophy-icon {
    animation: none;
  }

  .trophy-tile__open:hover,
  .trophy-tile__open:focus-visible,
  .trophy-modal__pin:hover {
    transform: none;
  }
}
