/* =============================================================================
   profile.css - Profile page: identity (name, avatar), level, pinned trophies and favourites.

   The trophy catalogue moved to its own destination and its styles now live in
   `css/components/trophy.css` (shared with the catalogue page). What stays here is the page
   itself: identity, the avatar picker, the level bar, the pinned strips and the favourites grid.

   Colors come exclusively from `css/themes.css` (including `--icon-filter`, which flips the black
   pin/unpin/edit glyphs on the dark theme). The panels reuse `.panel` and `.stats__title` from
   `css/base.css` / `css/views/stats.css`.
   ============================================================================= */

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

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

.profile__panel--wide {
  grid-column: 1 / -1;
}

.profile__help,
.profile__empty {
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
}

/* --- Identity -------------------------------------------------------------- */

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

.profile__avatar {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 5.5rem;
  height: 5.5rem;
  border: 1px solid var(--color-border);
  border-radius: 50%;
  background-color: var(--color-surface-alt);
  overflow: hidden;
}

.profile__avatar-image {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* The icons are pixel art (several ship as 6x6 or 8x8): a smooth upscale would turn them
     into a blur, so the browser must repeat the pixels instead. */
  image-rendering: pixelated;
}

.profile__avatar-fallback {
  font-size: var(--font-size-2xl);
  font-weight: 700;
  color: var(--color-accent);
}

.profile__identity-fields {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  flex: 1 1 auto;
  min-width: 0;
}

/* The pseudo is the identity of the page (and the NAME of the profile card below): it is set a step
   above the rest of the screen, while the worn title under it is set a step below. */
.profile__display-name {
  font-size: var(--font-size-2xl);
  font-weight: 700;
  line-height: 1.1;
  overflow-wrap: anywhere;
  /* Set inline by `ProfileView` when the pseudo colour was bought; the theme colour otherwise. */
  color: var(--profile-name-color, var(--color-text));
}

/* Pseudo-colour picker of the identity form: it reuses the swatches of the profile card panel. */
.profile__colors {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  justify-content: center;
}

.profile__colors .profile-card-panel__color {
  padding: 0.35rem 0.5rem;
}

/* The player TITLE: the line under the pseudo, in the pixel face of the card Styles ("Press Start
   2P") and in the yellow of `--color-title`. It is the reward the player chose to wear, so it
   keeps the reward's tone in every palette. `hidden` is enough to take it away: no space is left
   behind when no title is selected. */
.profile__title {
  font-family: var(--font-family-title);
  /* One step below the smallest text size: the pixel face is wide and tall for its point size, so
     the title has to be a notch smaller than the pseudo to read as a subtitle under it. */
  font-size: 0.625rem;
  line-height: 1.7;
  color: var(--color-title);
  overflow-wrap: anywhere;
  text-shadow: 0 0 10px rgba(255, 213, 74, 0.25);
}

.profile__title[hidden] {
  display: none;
}

/* The pencil: the ONLY way to change the name or the avatar, so a stray tap can never edit them. */
/* The two actions of the identity (rename, copy the player code) share one row under the pseudo on
   a phone, and form the last column of the identity band on a wide screen. */
.profile__identity-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-self: flex-start;
}

.profile__edit,
.profile__copy {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  align-self: flex-start;
  min-height: var(--touch-target);
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  background-color: var(--color-surface-alt);
  color: var(--color-text);
  font-size: var(--font-size-sm);
  font-weight: 600;
  cursor: pointer;
  touch-action: manipulation;
  transition: transform var(--duration-fast) var(--easing-standard),
    border-color var(--duration-fast) var(--easing-standard),
    color var(--duration-fast) var(--easing-standard),
    background-color var(--duration-fast) var(--easing-standard);
}

.profile__edit:hover,
.profile__copy:hover {
  border-color: var(--color-accent);
  color: var(--color-accent);
  transform: translateY(-2px);
}

.profile__edit.is-active {
  border-color: var(--color-accent);
  background-color: var(--color-accent);
  color: var(--color-accent-contrast);
}

.profile__edit-icon {
  width: 1.125rem;
  height: 1.125rem;
  object-fit: contain;
  filter: var(--icon-filter);
}

/* Drawn inline rather than shipped as a PNG: the copy glyph has to follow the ink of the theme on
   the two dark palettes and on the three light ones, which a bitmap cannot do. */
.profile__copy-icon {
  flex: 0 0 auto;
  width: 1.125rem;
  height: 1.125rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.profile__form {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  animation: profile-panel-in var(--duration-base) var(--easing-standard);
}

.profile__form[hidden] {
  display: none;
}

.profile__form-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

/* --- Avatar picker --------------------------------------------------------- */

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

.profile__icons {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(3.25rem, 1fr));
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.profile__icon-option {
  display: flex;
}

.profile__icon-choice {
  position: relative;
  display: grid;
  place-items: center;
  width: 100%;
  aspect-ratio: 1;
  padding: var(--space-1);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background-color: var(--color-surface-alt);
  cursor: pointer;
  touch-action: manipulation;
  transition: transform var(--duration-fast) var(--easing-standard),
    border-color var(--duration-fast) var(--easing-standard),
    box-shadow var(--duration-fast) var(--easing-standard);
}

.profile__icon-choice:hover:not(:disabled) {
  border-color: var(--color-accent);
  transform: translateY(-2px);
}

/* The selected avatar, and the one the form would store on save. */
.profile__icon-choice[aria-checked="true"] {
  border-color: var(--color-accent);
  box-shadow: var(--glow-accent);
}

/* An avatar a trophy still has to grant: visible, but clearly out of reach. */
.profile__icon-choice[data-locked="true"] {
  opacity: 0.45;
  filter: grayscale(1);
  cursor: not-allowed;
}

/* A paid avatar the level already allows: it stays clickable (the click opens the purchase), so it
   must not look like a trophy-gated one. */
.profile__icon-choice[data-purchasable="true"] {
  opacity: 0.8;
  filter: none;
  cursor: pointer;
  border-style: dashed;
}

.profile__icon-choice[data-purchasable="true"]:hover {
  border-color: var(--color-accent);
  opacity: 1;
}

.profile__icon-price {
  position: absolute;
  right: 0.15rem;
  bottom: 0.15rem;
  display: inline-flex;
  align-items: center;
  gap: 0.1rem;
  padding: 0.05rem 0.25rem;
  border-radius: var(--radius-pill);
  background-color: var(--color-surface);
  color: var(--color-warning);
  font-size: var(--font-size-xs);
  font-weight: 700;
  line-height: 1;
}

.profile__icon-price .profile-card-panel__price-icon {
  width: 0.7rem;
  height: 0.7rem;
}

.profile__icon-image {
  width: 100%;
  height: 100%;
  object-fit: contain;
  /* Same as the avatar: the source images are tiny pixel art, shown without interpolation. */
  image-rendering: pixelated;
}

.profile__icon-none {
  font-size: var(--font-size-lg);
  color: var(--color-text-muted);
}

/* --- Level ----------------------------------------------------------------- */

.profile__level {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
}

.profile__level-value {
  font-size: var(--font-size-2xl);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--color-accent);
}

.profile__level-label {
  font-size: var(--font-size-sm);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--color-text-muted);
}

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

.profile__xp-track {
  height: 0.9rem;
  border-radius: var(--radius-pill);
  background-color: var(--color-surface-alt);
  overflow: hidden;
}

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

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

/* --- Pinned rows (featured trophies, favourite cards) ---------------------- */

/* ONE row, scrolling sideways: the pins never push the page down, however many there are. */
.profile__strip {
  display: flex;
  gap: var(--space-2);
  margin: 0;
  padding: 0 var(--space-1) var(--space-2) 0;
  list-style: none;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  -webkit-overflow-scrolling: touch;
}

/* Favourite cards: one column per allowed favourite, so they all fit without any scrolling. */
.profile__strip--cards {
  display: grid;
  grid-template-columns: repeat(var(--favorite-columns, 5), minmax(0, 1fr));
  padding-right: 0;
  overflow: visible;
  scroll-snap-type: none;
}

.profile__tile {
  position: relative;
  flex: 0 0 auto;
  width: 6.5rem;
  scroll-snap-align: start;
  /* `backwards` + the index-based delay stagger the entry of the row, left to right. */
  animation: profile-tile-in var(--duration-base) var(--easing-standard) backwards;
  animation-delay: calc(var(--tile-index, 0) * 45ms);
}

/* A favourite card fills its column, and stays small: only its illustration identifies it. */
.profile__tile--card {
  width: 100%;
  min-width: 0;
}

.profile__tile-open {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-1);
  width: 100%;
  min-height: var(--touch-target);
  padding: var(--space-2);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background-color: var(--color-surface-alt);
  color: var(--color-text);
  font-size: var(--font-size-xs);
  text-align: center;
  cursor: pointer;
  touch-action: manipulation;
  transition: transform var(--duration-fast) var(--easing-standard),
    border-color var(--duration-fast) var(--easing-standard),
    box-shadow var(--duration-fast) var(--easing-standard);
}

.profile__tile--card .profile__tile-open {
  padding: var(--space-1);
}

.profile__tile-open:hover,
.profile__tile-open:focus-visible {
  border-color: var(--color-accent);
  box-shadow: var(--shadow-md);
  /* A small tilt makes the row feel like a hand of cards. */
  transform: translateY(-3px) rotate(-1.5deg);
}

.profile__tile-open:active {
  transform: translateY(-1px) scale(0.97);
}

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

/* The name of a pinned trophy, clamped to THREE lines. A trophy name can be a sentence ("Le premier
   booster d'une vie"), and letting one of them take five lines made its tile taller than the
   others: the strip stretches every tile to the tallest of the row, so one long name pushed the
   whole panel down and moved the "+ buy a slot" tile out of line. With the clamp AND the reserved
   height below, every tile of the row is exactly the same box whatever its name. */
.profile__tile-title {
  display: -webkit-box;
  overflow: hidden;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  /* Spelled out instead of inherited: the reserved height below is expressed in `em`, so the line
     height has to be the one the clamp counts with. */
  line-height: 1.3;
}

.profile__tile--trophy .trophy__icon {
  width: 2.5rem;
  height: 2.5rem;
  /* Same halo as the trophy catalogue: the radius belongs to the rarity, the strength to the
     `--trophy-glow-scale` the settings slider publishes (`js/utils/GlowManager.js`). */
  --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)
  );
}

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

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

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

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

/* Every pinned-trophy box has the same size. The strip stretches its items on the cross axis, and
   the tile is a flex box so the button fills that stretched height; the medal and the rarity badge
   are fixed, so only the name varies, and reserving THREE lines there makes a one-line and a
   three-line title end on the same edge. */
.profile__tile--trophy {
  display: flex;
}

.profile__tile--trophy .profile__tile-open {
  flex: 1 1 auto;
}

.profile__tile--trophy .profile__tile-title {
  /* Three lines of `line-height: 1.3` (the value is set on `.profile__tile-title`, in `em`). */
  min-height: 3.9em;
}

/* The empty and the for-sale slots are the two other kinds of tile of that row. They must fill the
   height the tallest trophy gives the strip, otherwise the row shows three boxes of three different
   sizes - the very thing a fixed card size is supposed to avoid. */
.profile__tile--slot {
  display: flex;
}

.profile__tile--slot .profile__tile-open {
  flex: 1 1 auto;
}

/* The unpin button of a pinned trophy: pinned to the TOP-RIGHT corner of the tile. */
.profile__tile-action {
  position: absolute;
  top: calc(-1 * var(--space-1));
  right: calc(-1 * var(--space-1));
  display: grid;
  place-items: center;
  width: 1.75rem;
  height: 1.75rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  background-color: var(--color-surface);
  cursor: pointer;
  touch-action: manipulation;
  transition: transform var(--duration-fast) var(--easing-standard),
    border-color var(--duration-fast) var(--easing-standard);
}

.profile__tile-action:hover {
  border-color: var(--color-error);
  transform: scale(1.12) rotate(6deg);
}

/* Shared sizing of the black pin/unpin/edit glyphs, flipped on the dark theme. */
.profile__icon {
  display: block;
  width: 0.9rem;
  height: 0.9rem;
  object-fit: contain;
  filter: var(--icon-filter);
}

/* --- Favourite detail ------------------------------------------------------ */

.profile-modal__card {
  align-self: center;
  width: min(100%, 15rem);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  animation: profile-tile-in var(--duration-base) var(--easing-standard);
}

.profile-modal__remove {
  align-self: flex-start;
}

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

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

@keyframes profile-panel-in {
  from {
    opacity: 0;
    transform: translateY(8px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

@media (min-width: 768px) {
  .profile {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    align-items: start;
  }

  .profile__identity {
    flex-direction: row;
    align-items: flex-start;
  }
}

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

/* --- Profile card --------------------------------------------------------- */

/* The card itself is a shadow tree (`js/UI/components/ProfileCard.js`, styled by
   `css/components/profile-card.css`): what these rules size is only its STAGE and the controls
   around it. The stage is where the card is fitted to the panel, and where the enlargement modal
   moves it to. */

.profile-card-panel {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  min-width: 0;
}

.profile-card-panel__rarity {
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
  text-align: center;
}

.profile-card-panel__rarity strong {
  color: var(--color-accent);
}

.profile-card-panel__stage {
  /* The card keeps its authored size and is scaled as a whole: on a narrow screen its layout box is
     therefore wider than the panel, and the overflow is clipped on both sides (it is centered). */
  position: relative;
  display: flex;
  justify-content: center;
  align-items: flex-start;
  width: 100%;
  overflow: hidden;
}

/* The tilt surface: sized to the card (its shadow content is 360 px wide), never to the panel.
   Rotating the stage instead would carry the empty strip and its shadow around the card. */
.profile-card-panel__card {
  position: relative;
  flex: 0 0 auto;
  /* The shadow content is authored at 360 px: `fit-content` makes the tilt surface the card's own
     footprint instead of the full width of the panel. It is NOT capped at the width of the panel:
     the card is scaled as a whole and keeps its own box, so capping it would leave the scaled
     picture hanging on the right of a narrower surface (and the stage would clip it there). The
     stage centres it instead, and `ProfileCard.applyStage()` leaves a small inset on each side. */
  width: fit-content;
}

.profile-card-panel__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  width: 100%;
}

.profile-card-panel__layouts {
  display: inline-flex;
  gap: 0.25rem;
  padding: 0.2rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  background-color: var(--color-surface-alt);
}

/* The active layout reads as the selected one of a two-choice switch. */
.profile-card-panel__layouts .btn {
  border-color: transparent;
  background-color: transparent;
  border-radius: var(--radius-pill);
}

.profile-card-panel__layouts .btn[aria-pressed="true"] {
  border-color: var(--color-accent);
  background-color: var(--color-surface);
  color: var(--color-accent);
  box-shadow: var(--glow-accent);
}

.profile-card-panel__buttons {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-2);
}

.profile-card-panel__feedback {
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
  text-align: center;
}

.profile-card-panel__feedback[data-tone="error"] {
  color: var(--color-error);
}

.profile-card-modal__body {
  display: flex;
  justify-content: center;
  align-items: flex-start;
  /* The card is 500px tall: the modal body scrolls rather than pushing the actions off screen. */
  max-height: min(70vh, 560px);
  overflow-y: auto;
}

/* Host of the icon-preview sample. The card fits itself to the width of its host, so the sample
   simply gets the card's own width: a real card, not a stretched one. */
.profile-card-preview__host {
  width: 100%;
  /* The card is authored 360 px wide and SCALED, so its layout box stays 360 px wide: without this
     clip, the samples push a horizontal scrollbar into the purchase dialog on a phone. */
  overflow: hidden;
}

/* --- Profile card: rarity picker ------------------------------------------ */

/* One option per card rarity. The unlocked ones are selectable and show their symbol and name; the
   locked ones are disabled and show the trophy medal with the count the account has against the
   count the threshold asks for ("22 / 30"), in the colour of a refusal: the picker is also the list
   of what there is to earn, exactly like the avatar picker. */

.profile-card-panel__rarities {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-2);
  width: 100%;
}

.profile-card-panel__rarity {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.15rem;
  min-width: 4.75rem;
  padding: var(--space-2);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background-color: var(--color-surface-alt);
  color: var(--color-text-muted);
  font: inherit;
  cursor: pointer;
  transition: border-color 0.2s ease, transform 0.2s ease, box-shadow 0.2s ease;
}

.profile-card-panel__rarity:hover:not(:disabled) {
  border-color: var(--color-accent);
  transform: translateY(-2px);
}

.profile-card-panel__rarity[aria-checked="true"] {
  border-color: var(--color-accent);
  box-shadow: var(--glow-accent);
}

.profile-card-panel__rarity:disabled {
  cursor: not-allowed;
  opacity: 0.85;
}

.profile-card-panel__rarity-symbol {
  font-size: var(--font-size-md);
  line-height: 1.1;
}

.profile-card-panel__rarity-name {
  font-size: var(--font-size-xs);
  color: var(--color-text-muted);
}

.profile-card-panel__rarity[aria-checked="true"] .profile-card-panel__rarity-name {
  color: var(--color-accent);
}

.profile-card-panel__rarity-count {
  display: inline-flex;
  align-items: center;
  gap: 0.2rem;
  font-size: var(--font-size-xs);
  font-weight: 600;
  color: var(--color-error);
}

.profile-card-panel__rarity-medal {
  width: 0.9rem;
  height: 0.9rem;
  object-fit: contain;
  image-rendering: pixelated;
}

/* --- Profile card: the title colour -------------------------------------- */

/* --- Profile card: the background ---------------------------------------- */

/* One tile per favourite card: the artwork is the label, the name is the accessible one. The
   first favourite is the default, marked like any other selection. */
.profile-card-panel__backgrounds-block {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  width: 100%;
}

.profile-card-panel__backgrounds {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-2);
}

.profile-card-panel__background {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.2rem;
  width: 5.4rem;
  padding: var(--space-1);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background-color: var(--color-surface-alt);
  color: var(--color-text-muted);
  font: inherit;
  cursor: pointer;
  transition: border-color 0.2s ease, box-shadow 0.2s ease, transform 0.2s ease;
}

.profile-card-panel__background:hover {
  border-color: var(--color-accent);
  transform: translateY(-2px);
}

.profile-card-panel__background[data-selected="true"] {
  border-color: var(--color-accent);
  box-shadow: var(--glow-accent);
}

.profile-card-panel__background-image {
  width: 100%;
  aspect-ratio: 3 / 2;
  object-fit: cover;
  border-radius: var(--radius-sm);
}

.profile-card-panel__background-name {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--font-size-xs);
}

.profile-card-panel__colors-block {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  width: 100%;
}

.profile-card-panel__colors-title {
  font-size: var(--font-size-xs);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-text-muted);
}

.profile-card-panel__colors {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-2);
}

.profile-card-panel__color {
  --swatch-color: var(--color-title);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.2rem;
  min-width: 4.5rem;
  padding: var(--space-2) var(--space-2);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background-color: var(--color-surface-alt);
  color: var(--color-text-muted);
  font: inherit;
  cursor: pointer;
  transition: border-color 0.2s ease, box-shadow 0.2s ease, transform 0.2s ease;
}

.profile-card-panel__color:hover {
  border-color: var(--swatch-color);
  transform: translateY(-2px);
}

.profile-card-panel__color-dot {
  width: 1.4rem;
  height: 1.4rem;
  border-radius: 50%;
  background: var(--swatch-color);
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.35);
}

.profile-card-panel__color-name {
  font-size: var(--font-size-xs);
}

/* The worn colour: a ring of its own colour, matching the rarity picker above. */
.profile-card-panel__color[data-selected="true"] {
  border-color: var(--swatch-color);
  box-shadow: 0 0 0 1px var(--swatch-color);
  color: var(--color-text);
}

.profile-card-panel__color[data-selected="true"] .profile-card-panel__color-name {
  color: var(--color-text);
  font-weight: 700;
}

/* A colour that was not bought yet: dashed, dimmed, with its price. It is still a button, because
   clicking it is how the purchase starts. */
.profile-card-panel__color[data-owned="false"] {
  border-style: dashed;
  color: var(--color-text-muted);
}

/* A locked swatch keeps its colour readable (it is what the player is buying): only a slight
   desaturation, plus the dashed border and the price, tells it apart. */
.profile-card-panel__color[data-owned="false"] .profile-card-panel__color-dot {
  filter: grayscale(0.35) brightness(0.8);
}

/* "Auto" is not a colour but the rarity colour: a wheel of the five values it can take. */
.profile-card-panel__color[data-profile-card-title-color="auto"] .profile-card-panel__color-dot {
  background: conic-gradient(
    #cfd3dd 0 20%,
    #4dd0e1 20% 40%,
    #c084fc 40% 60%,
    #ffd54a 60% 80%,
    #ff6fae 80% 100%
  );
}

.profile-card-panel__color-price {
  display: inline-flex;
  align-items: center;
  gap: 0.15rem;
  font-size: var(--font-size-xs);
  font-weight: 600;
  color: var(--color-text-muted);
}

.profile-card-panel__color-price .profile-card-panel__price-icon {
  width: 0.75rem;
  height: 0.75rem;
}

.profile-card-panel__colors-help {
  font-size: var(--font-size-xs);
  color: var(--color-text-muted);
  text-align: center;
}

/* --- Profile card: a paid layout ----------------------------------------- */

.profile-card-panel__lock {
  width: 1rem;
  height: 1rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.profile-card-panel__price {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  font-weight: 600;
}

.profile-card-panel__price-icon {
  width: 0.9rem;
  height: 0.9rem;
  object-fit: contain;
}

/* The locked layout reads as a price tag, not as a switch that refuses to move. */
.profile-card-panel__layouts .btn[data-profile-card-layout="fullart"][data-locked="true"] {
  border-color: var(--color-border);
  color: var(--color-text-muted);
}

.profile-card-panel__layouts .btn[data-profile-card-layout="fullart"][data-locked="true"]:hover {
  border-color: var(--color-accent);
  color: var(--color-text);
}

/* --- Profile: the "+" tile that buys a slot ------------------------------ */

/* Same shape as the tiles of the strip, dashed and with a price: the next slot is visibly empty and
   visibly for sale, never mistaken for an empty pin. */
.profile__tile--buy .profile__tile-buy {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.2rem;
  border-style: dashed;
  color: var(--color-text-muted);
}

.profile__tile--buy .profile__tile-buy:hover {
  border-color: var(--color-accent);
  color: var(--color-accent);
}

.profile__tile-buy-plus {
  font-size: var(--font-size-2xl);
  font-weight: 700;
  line-height: 1;
}

.profile__tile-buy-price {
  display: inline-flex;
  align-items: center;
  gap: 0.15rem;
  font-size: var(--font-size-xs);
  font-weight: 700;
}

.profile__tile-buy-price .profile-card-panel__price-icon {
  width: 0.75rem;
  height: 0.75rem;
}

/* --- Profile card: buy modal --------------------------------------------- */

.profile-card-buy {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  text-align: center;
}

.profile-card-buy__feature {
  font-weight: 700;
}

.profile-card-buy__price,
.profile-card-buy__balance {
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
}

.profile-card-buy__message[data-tone="error"] {
  color: var(--color-error);
  font-weight: 600;
}

/* The sample of the purchase dialog: ONE card, on the layout the player wears, centred and capped.
   The cap matters: the card scales itself down to the width of its wrapper, so a sample left free
   to fill a 36rem dialog would look bigger than the real card. */
.profile-card-buy__previews {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  width: 100%;
}

.profile-card-buy__preview {
  display: flex;
  flex: 0 1 15rem;
  flex-direction: column;
  align-items: center;
  gap: var(--space-1);
  width: min(100%, 15rem);
  margin: 0;
}

.profile-card-buy__preview-label {
  font-size: var(--font-size-xs);
  color: var(--color-text-muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.profile-card-buy__preview-help {
  margin: 0;
  font-size: var(--font-size-xs);
  color: var(--color-text-muted);
}

/* --- Profile: empty and locked slots -------------------------------------- */

/* Every slot of both lists is drawn, even when nothing fills it: an empty owned slot invites a
   choice, a locked one shows its price. Both borrow the tile shape of the pinned entries. */
.profile__tile--slot .profile__tile-open {
  justify-content: center;
  gap: var(--space-1);
  min-height: 6.5rem;
  border-style: dashed;
  color: var(--color-text-muted);
}

.profile__tile-slot-plus {
  font-size: var(--font-size-xl);
  line-height: 1;
  color: var(--color-accent);
}

.profile__tile-slot-label {
  font-size: var(--font-size-xs);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.profile__tile-slot-empty:hover .profile__tile-slot-plus,
.profile__tile-slot-empty:focus-visible .profile__tile-slot-plus {
  transform: scale(1.15);
}

.profile__tile--slot-locked .profile__tile-open {
  border-style: solid;
  opacity: 0.6;
}

.profile__tile-slot-locked:disabled {
  cursor: not-allowed;
}

.profile__tile-slot-lock {
  font-size: var(--font-size-sm);
  line-height: 1;
  opacity: 0.75;
}

/* The favourite grid packs five slots per row: an empty tile keeps the ratio of a card so the row
   reads as one hand, not as cards followed by boxes. */
.profile__strip--cards .profile__tile--slot {
  /* A slot is a grid cell, not a fixed 6.5 rem tile: it must share the five columns with the
     cards without overflowing the panel. */
  width: 100%;
  min-width: 0;
}

.profile__strip--cards .profile__tile--slot .profile__tile-open {
  min-height: 0;
  aspect-ratio: var(--card-ratio);
}

/* --- Profile: slot picker ------------------------------------------------- */

.profile-picker {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(6.5rem, 1fr));
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.profile-picker__choice {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-1);
  width: 100%;
  padding: var(--space-2);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background-color: var(--color-surface-alt);
  color: var(--color-text);
  font-size: var(--font-size-xs);
  text-align: center;
  cursor: pointer;
  touch-action: manipulation;
  transition: border-color var(--duration-fast) var(--easing-standard),
    transform var(--duration-fast) var(--easing-standard);
}

.profile-picker__choice:hover,
.profile-picker__choice:focus-visible {
  border-color: var(--color-accent);
  transform: translateY(-2px);
}

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

.profile-picker__choice--trophy .trophy__icon {
  width: 2.5rem;
  height: 2.5rem;
}

.profile-picker__label {
  display: -webkit-box;
  overflow: hidden;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}

.profile-picker__empty {
  margin: 0;
  color: var(--color-text-muted);
  text-align: center;
}

/* =============================================================================
   Profile card: colour choosers, avatar options and the shared colour picker.
   The palette used to be printed under the card; it now lives in a dialog, so
   each line only shows the colour it wears plus a button to change it.
   ============================================================================= */
.profile-card-panel__chooser {
  --swatch-color: var(--color-title);
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background-color: var(--color-surface-alt);
  color: var(--color-text);
  font: inherit;
  font-size: var(--font-size-sm);
  cursor: pointer;
  transition: border-color 0.2s ease, transform 0.2s ease;
}

.profile-card-panel__chooser:hover {
  border-color: var(--swatch-color);
}

.profile-card-panel__chooser:focus-visible {
  outline: 2px solid var(--swatch-color);
  outline-offset: 2px;
}

.profile-card-panel__chooser .profile-card-panel__color-dot {
  width: 1.6rem;
  height: 1.6rem;
}

/* The avatar size and anchor: two rows of chips, the worn one ringed like a picker option. */
.profile-card-panel__chips {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-2);
}

.profile-card-panel__chip {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: var(--space-1) var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: 999px;
  background-color: var(--color-surface-alt);
  color: var(--color-text-muted);
  font: inherit;
  font-size: var(--font-size-xs);
  cursor: pointer;
  transition: border-color 0.2s ease, color 0.2s ease, box-shadow 0.2s ease;
}

.profile-card-panel__chip[data-selected="true"] {
  border-color: var(--color-accent, var(--color-title));
  box-shadow: 0 0 0 1px var(--color-accent, var(--color-title));
  color: var(--color-text);
  font-weight: 700;
}

.profile-card-panel__chip[data-owned="false"] {
  border-style: dashed;
}

/* The colour picker dialog: two strips of swatches, the bought ones first. */
.profile-color {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.profile-color__section {
  font-size: var(--font-size-xs);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-text-muted);
}

.profile-color__empty {
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
  text-align: center;
}

/* The pseudo of the profile and the title of the card may be painted with a gradient: the paint
   becomes a background clipped to the glyphs (the component sets the same pair of properties on
   the card element itself, which is why both sides read a custom property). */
[data-profile-display-name] {
  background-image: var(--profile-name-gradient, none);
  -webkit-background-clip: text;
  background-clip: text;
}
