/* ============================================================
   PRISM POP — candy-arcade on deep ink
   ============================================================ */
:root {
  --ink: #141233;
  --ink-2: #221d44;
  --card: #2c2658;            /* brighter, more saturated indigo (was a muddy dark navy) */
  --card-edge: rgba(180, 170, 255, 0.22);   /* a visible, coloured frame edge */
  --text: #f7f5ff;
  --text-dim: #b9b2e0;
  --coral: #ff5e7a;
  --coral-deep: #d63a58;
  --amber: #ffb648;
  --gold: #ffc83d;
  --gold-deep: #c98a00;
  --mint: #4dde8b;
  --sky: #4dc4ff;
  --rar-common: #35c368;
  --rar-rare: #4dc4ff;
  --rar-epic: #b07aff;
  --rar-legendary: #ffc83d;
  --rar-mythic: #ff6ec7;
  --cell-empty: rgba(255, 255, 255, 0.045);
  --radius: 20px;
  --safe-top: env(safe-area-inset-top, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  /* emerald-cut gem silhouette shared by board gems, tray gems and shatter phantoms */
  --gem-clip: polygon(29% 0%, 71% 0%, 100% 29%, 100% 71%, 71% 100%, 29% 100%, 0% 71%, 0% 29%);
}

* { margin: 0; padding: 0; box-sizing: border-box; -webkit-tap-highlight-color: transparent; }

html, body {
  height: 100%;
  min-height: 100dvh;
  /* owner T97 : le fond d'écran remplit TOUT l'écran dès le 1er boot (iOS : la hauteur se stabilise tard + un
     strip sous le layout viewport) -> plus de bande NOIRE en bas. On peint la racine avec le fond sunset du jeu. */
  background: var(--dp-bg, #2a1a4d);
  overscroll-behavior: none;
}

body {
  background: var(--dp-bg, #2a1a4d);
  color: var(--text);
  font-family: 'Nunito', system-ui, sans-serif;
  font-weight: 700;
  overflow: hidden;
  touch-action: manipulation;
  user-select: none;
  -webkit-user-select: none;
}

input {
  user-select: text;
  -webkit-user-select: text;
}

/* ---------- ambient backdrop ---------- */
.ambient { position: fixed; inset: 0; z-index: 0; pointer-events: none; }
/* readability veil over the wallpaper, TINTED with its hue so it harmonises (vs a flat black filter). Moderate
   — the art still shows far more than the old heavy scrim, but text + cards stay legible on bright wallpapers. */
.ambient::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: rgba(12, 10, 28, 0.3);   /* LIGHT veil — readability now comes from the coloured element frames, not a dark filter */
  transition: background 0.25s ease;
}
/* in-game: barely any veil so the board's wallpaper is showcased */
body[data-view="game"] .ambient::after { background: rgba(12, 10, 28, 0.16); }
/* HOME menu: wallpaper at the top fading into a darker menu area lower down — no hard cut (owner ask) */
body[data-view="home"] .ambient::after {
  background: linear-gradient(180deg, rgba(10, 8, 24, 0.12) 0%, rgba(10, 8, 24, 0.1) 22%, rgba(10, 8, 24, 0.34) 46%, rgba(10, 8, 24, 0.5) 64%, rgba(10, 8, 24, 0.72) 100%);
}
/* floating text (no card behind it) keeps a strong dark OUTLINE so it stays legible on a light OR dark wallpaper */
.view-title, .home-id-name, .hud-value, .hud-label, .mode-caption, .best-banner, .tro-total,
#ovTierUp .panel-title, #ovTierUp .tu-tier, #ovCosmetic .panel-title, #ovCosmetic .card-foot, .champ-standing, .champ-hint {
  text-shadow: -1.2px -1.2px 0 rgba(0, 0, 0, 0.6), 1.2px -1.2px 0 rgba(0, 0, 0, 0.6), -1.2px 1.2px 0 rgba(0, 0, 0, 0.6), 1.2px 1.2px 0 rgba(0, 0, 0, 0.6), 0 2px 0 rgba(0, 0, 0, 0.6);
}
.blob {
  position: absolute; width: 60vmax; height: 60vmax; border-radius: 50%;
  filter: blur(55px); opacity: 0.13;   /* owner T70 : blur 90->55px (le flou géant coûtait cher au GPU ; les blobs sont désormais cachés EN JEU, ça n'allège que la home) */
}
/* image wallpapers: the picture fills the ambient layer and the drifting blobs/grain step aside */
body.wp-image .ambient { background-image: var(--wp-img); background-size: cover; background-position: center; }
/* a TILED pattern wallpaper (the default jewel backdrop): small, repeated -> responsive on phone/tablet/desktop */
body.wp-tile .ambient { background-image: var(--wp-img); background-size: 200px auto; background-position: center; background-repeat: repeat; }
body.wp-image .blob, body.wp-image .grain { display: none; }
.blob-a { background: var(--blob-a, var(--coral)); top: -30vmax; right: -20vmax; animation: drift 26s ease-in-out infinite alternate; }
.blob-b { background: var(--blob-b, var(--sky)); bottom: -32vmax; left: -22vmax; animation: drift 31s ease-in-out infinite alternate-reverse; }
@keyframes drift { from { transform: translate(0, 0) scale(1); } to { transform: translate(6vmax, 4vmax) scale(1.15); } }
.grain {
  position: absolute; inset: 0; opacity: 0.05; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='0.6'/%3E%3C/svg%3E");
}

/* owner : verrou PORTRAIT — téléphone en paysage (paysage + hauteur courte) : on masque le jeu et on invite à tourner */
#rotateLock { display: none; }
@media (orientation: landscape) and (max-height: 520px) {
  #rotateLock { display: flex; position: fixed; inset: 0; z-index: 99999; background: linear-gradient(160deg, #2a1a4d, #14102a); align-items: center; justify-content: center; text-align: center; padding: 24px; }
  #rotateLock .rl-inner { max-width: 340px; }
  #rotateLock .rl-phone { width: 66px; height: auto; display: inline-block; animation: rl-tilt 1.8s ease-in-out infinite; }   /* owner : vraie image phone.webp */
  #rotateLock p { color: #fff; font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 21px; line-height: 1.3; margin-top: 16px; }
  #app, .ambient { display: none !important; }
}
@keyframes rl-tilt { 0%, 100% { transform: rotate(0deg); } 55% { transform: rotate(-90deg); } }

/* owner : écran de CHARGEMENT (fini l'écran blanc). Visible par défaut, game.js ajoute .hide quand prêt. */
/* T124 : écran de chargement = la cover 1290×2796 (9:19.5, ratio iPhone) en PLEIN ÉCRAN.
   object-fit: cover -> remplit tout l'écran bord à bord ; le logo est centré avec des marges
   décoratives, donc sur un ratio différent (iPad…) seules ces marges sont rognées, jamais le logo.
   Fond #c99fd9 (= splash NATIF iOS) au cas où un ratio extrême laisserait un liseré. */
#splash {
  position: fixed; inset: 0; z-index: 100000; overflow: hidden;
  background: #101b9c;   /* owner : bleu profond = couleur des BORDS de la cover -> les bandes du letterbox portrait se fondent dans la cover (plus de bandes visibles) */
  transition: opacity 0.45s ease;
}
#splash.hide { opacity: 0; pointer-events: none; }
#splash .sp-cover { position: absolute; inset: 0; }   /* <picture> : paysage 16:9 (cover_1920x1080) / tablette (cover_square) / téléphone (cover_1290x2796, plein cadre) selon l'aspect */
#splash .sp-cover img { width: 100%; height: 100%; object-fit: cover; object-position: center; display: block; }
/* owner : la cover téléphone est désormais au format téléphone (1290×2796) -> `cover` la remplit PILE, plus besoin de `contain`/bandes (aucun zoom, aucun recadrage sur un écran au même aspect) */
#splash .sp-dots { position: absolute; left: 0; right: 0; bottom: calc(8% + env(safe-area-inset-bottom, 0px)); display: flex; gap: 9px; justify-content: center; z-index: 2; }
#splash .sp-dots i { width: 11px; height: 11px; border-radius: 50%; background: #fff; box-shadow: 0 2px 7px rgba(40, 20, 70, 0.55); animation: sp-bounce 1s ease-in-out infinite; }
#splash .sp-dots i:nth-child(2) { animation-delay: 0.15s; }
#splash .sp-dots i:nth-child(3) { animation-delay: 0.3s; }
@keyframes sp-bounce { 0%, 100% { transform: translateY(0); opacity: 0.55; } 50% { transform: translateY(-9px); opacity: 1; } }

#app {
  position: relative; z-index: 1;
  height: 100dvh;
  height: var(--app-h, 100dvh);   /* JS sets --app-h = innerHeight (reliable on iOS) */
  display: flex; flex-direction: column;
  max-width: 520px; margin: 0 auto;
  padding: calc(10px + var(--safe-top)) 16px calc(10px + var(--safe-bottom));
}

/* ---------- top bar ---------- */
#topbar {
  display: flex; align-items: center; gap: 10px;
  padding-bottom: 6px;
}
.chip {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--card);
  border: 1px solid var(--card-edge);
  border-radius: 999px;
  color: var(--text);
  font-family: 'Nunito', sans-serif; font-weight: 900; font-size: 15px;
  padding: 8px 14px;
  cursor: pointer;
}
button.chip:active { transform: scale(0.93); }
.coin-chip { margin-left: auto; letter-spacing: 0.5px; position: relative; }
.coin-chip.claimable::after {
  content: ''; position: absolute; top: -2px; right: -2px;
  width: 11px; height: 11px; border-radius: 50%;
  background: var(--coral);
  box-shadow: 0 0 8px var(--coral);
  animation: claim-pulse 1.4s ease-in-out infinite;
}
@keyframes claim-pulse { 50% { transform: scale(1.35); } }
.jewel-chip { letter-spacing: 0.5px; }
#btnBack, #btnSettings { padding: 8px 10px; }
#btnBack { display: none; }
#btnSettings { display: none; }
body[data-view="home"] #btnSettings,
body[data-view="game"] #btnSettings { display: inline-flex; }   /* settings reachable mid-run too (right of Back) */
body[data-view="collection"] #btnBack,
body[data-view="board"] #btnBack,
body[data-view="goals"] #btnBack,
body[data-view="shop"] #btnBack,
body[data-view="profile"] #btnBack,
body[data-view="loadout"] #btnBack,
body[data-view="craft"] #btnBack,
body[data-view="game"] #btnBack { display: inline-flex; }
.ic { width: 18px; height: 18px; display: block; }
.coin-ic { display: inline-block; width: 18px; height: 18px; background: url(assets/ui/coin.webp) center/contain no-repeat; }
.coin-ic.big { width: 30px; height: 30px; }
.coin-mini {
  display: inline-block; width: 13px; height: 13px;
  background: url(assets/ui/coins.webp) center/contain no-repeat;   /* owner : image "tas de pièces" pour les récompenses/prix/boutique (la topbar garde .coin-ic = coin.webp) */
  vertical-align: -2px;
}

/* ---------- views ---------- */
.view { display: none; flex: 1; min-height: 0; flex-direction: column; }
body[data-view="home"] #view-home { display: flex; }
body[data-view="game"] #view-game { display: flex; }
/* overflow-x:hidden on every scrolling view: a y-only scroller computes overflow-x to `auto`, so any
   sub-pixel child overflow rubber-bands horizontally on iOS. Clipping x kills the phantom sideways scroll. */
body[data-view="collection"] #view-collection { display: flex; overflow-x: hidden; overflow-y: auto; }
body[data-view="board"] #view-board { display: flex; overflow-x: hidden; overflow-y: auto; }
body[data-view="goals"] #view-goals { display: flex; overflow-x: hidden; overflow-y: auto; }
body[data-view="shop"] #view-shop { display: flex; overflow-x: hidden; overflow-y: auto; }
body[data-view="profile"] #view-profile { display: flex; overflow-x: hidden; }
body[data-view="loadout"] #view-loadout { display: flex; overflow: hidden; }
body[data-view="craft"] #view-craft { display: flex; overflow: hidden; }
/* owner : AUCUN ascenseur visible dans l'app (feeling jeu, pas « page web ») — le scroll reste au doigt */
::-webkit-scrollbar { width: 0 !important; height: 0 !important; background: transparent; }
* { scrollbar-width: none; -ms-overflow-style: none; }
/* le profil est une vraie page : titre fixe en haut + zone scrollable dessous (comme les autres vues) */
#view-profile .profile-scroll { flex: 1; min-height: 0; overflow-y: auto; overflow-x: hidden; display: flex; flex-direction: column; gap: 10px; padding-bottom: 12px; }

/* ---------- HOME ----------
   top-aligned with a comfortable gap; the footer nav is pushed to the bottom
   (margin-top:auto) so the screen fills its height instead of centring with a
   black band below the content (notably under the iPhone home indicator) */
#view-home { align-items: center; justify-content: flex-start; gap: 10px; padding-top: 10px; padding-bottom: 6px; overflow-y: auto; }
.home-foot { margin-top: auto; }

/* segmented pickers (home mode/difficulty + leaderboard tabs) */
.seg-row {
  display: flex; gap: 4px;
  background: var(--card);
  border: 1px solid var(--card-edge);
  border-radius: 999px;
  padding: 4px;
  width: min(340px, 100%);
}
.seg {
  flex: 1; min-width: 0;
  border: none; background: transparent;
  color: var(--text-dim);
  font-family: 'Lilita One', 'Trebuchet MS', sans-serif;
  font-size: 13px; letter-spacing: 1px; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;   /* hard safety: a too-long label clips with … rather than overlapping its neighbour */
  padding: 8px 6px; border-radius: 999px;
  cursor: pointer;
  transition: color 0.15s;
}
/* the active segment is never coral — that's reserved for the PLAY/CONTINUE CTA.
   Mode = orange, difficulty = traffic-light (green/yellow/red), collection = purple. */
.seg.on {
  background: linear-gradient(180deg, #6b7290, #474c63);
  color: #fff;
  box-shadow: 0 2px 0 #2a2e40;
  text-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);
}
/* mode (chill / time attack) → orange */
.seg[data-mode].on, .seg[data-bmode].on {
  background: linear-gradient(180deg, #ffa53d, #e07c12);
  box-shadow: 0 2px 0 #95500a; color: #3a2200; text-shadow: none;
}
/* difficulty → green / amber / red */
.seg[data-diff="easy"].on, .seg[data-bdiff="easy"].on {
  background: linear-gradient(180deg, #5fd07a, #2fa84f); box-shadow: 0 2px 0 #1c7032; color: #06340f; text-shadow: none;
}
.seg[data-diff="medium"].on, .seg[data-bdiff="medium"].on {
  background: linear-gradient(180deg, #ffd23f, #e0a712); box-shadow: 0 2px 0 #9c7100; color: #3a2c00; text-shadow: none;
}
.seg[data-diff="hard"].on, .seg[data-bdiff="hard"].on {
  background: linear-gradient(180deg, #ff6a6a, #d63a3a); box-shadow: 0 2px 0 #8e2020; color: #fff;
}
/* collection tabs → purple (jewels vibe) */
.seg[data-coll].on {
  background: linear-gradient(180deg, #b07aff, #7b2cbf); box-shadow: 0 2px 0 #4c1d95; color: #fff;
}
.mode-caption {
  font-size: 12px; color: var(--text-dim);
  text-align: center; min-height: 16px;
  margin-top: 10px;   /* breathing room under the PLAY button */
}
.mode-caption .mode-name { font-weight: 900; color: var(--text); letter-spacing: 0.5px; }
/* mode dropdown on the PLAY button (Ascension / Survie / Libre) */
.play-wrap { position: relative; display: flex; justify-content: center; gap: 6px; }
.play-wrap .btn-play { flex: 0 1 auto; }
.play-caret {
  flex: 0 0 auto; width: 46px; min-width: 46px; padding: 0;
  font-size: 18px; line-height: 1; display: flex; align-items: center; justify-content: center;
}
.mode-menu {
  position: absolute; top: calc(100% + 8px); left: 50%; transform: translateX(-50%);
  z-index: 30; min-width: 200px;
  display: flex; flex-direction: column; gap: 4px; padding: 6px;
  background: var(--panel, #181a2e); border: 1px solid rgba(255,255,255,.12);
  border-radius: 14px; box-shadow: 0 12px 30px rgba(0,0,0,.45);
}
.mode-menu[hidden] { display: none; }
.mode-item {
  appearance: none; border: 0; cursor: pointer;
  font-family: inherit; font-weight: 800; font-size: 15px; color: var(--text, #fff);
  text-align: center; padding: 12px 14px; border-radius: 10px;
  background: rgba(255,255,255,.05);
}
.mode-item.on { background: linear-gradient(135deg, #6d5cff, #b07aff); color: #fff; }
.mode-item:active { transform: scale(.97); }

/* LIBRE clear gauge (tap to wipe the board when full) */
.free-bar {
  position: relative; width: 100%; height: 30px; margin: 4px 0 2px;
  border: 0; border-radius: 9px; overflow: hidden; cursor: default;
  background: rgba(255,255,255,.07); padding: 0;
  display: flex; align-items: center; justify-content: center;
}
.free-bar #freeFill {
  position: absolute; inset: 0 auto 0 0; width: 0%;
  background: linear-gradient(90deg, #4dc4ff, #6d5cff);
  transition: width .25s ease;
}
.free-bar #freeLabel {
  position: relative; z-index: 1;
  font-family: inherit; font-weight: 900; font-size: 12px; letter-spacing: .5px;
  color: #fff; text-shadow: 0 1px 0 rgba(0,0,0,.5);
}
.free-bar.ready {
  cursor: pointer;
  box-shadow: 0 0 0 2px #b07aff, 0 0 16px rgba(176,122,255,.6);
  animation: free-pulse 1.1s ease-in-out infinite;
}
.free-bar.ready #freeFill { background: linear-gradient(90deg, #b07aff, #ff5e7a); }
.free-bar.ready:active { transform: scale(.98); }
@keyframes free-pulse { 0%,100% { filter: brightness(1); } 50% { filter: brightness(1.25); } }

/* ASCENSION objective banner */
.asc-bar {
  width: 100%; margin: 2px 0 4px; padding: 7px 12px 8px;
  border-radius: 11px; background: rgba(109,92,255,.14);
  border: 1px solid rgba(176,122,255,.35);
}
/* goal line: the action phrase (left) + the difficulty tally stars (right) */
.asc-goal { font-size: 13px; font-weight: 800; color: var(--text, #fff); display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.asc-metric { letter-spacing: 0.3px; }
.asc-stars { display: inline-flex; gap: 4px; flex-shrink: 0; align-items: center; }
.asc-star {
  width: 15px; height: 15px; flex-shrink: 0;
  -webkit-mask: url(assets/ui/star.webp) center/contain no-repeat;
  mask: url(assets/ui/star.webp) center/contain no-repeat;
  background: rgba(255,255,255,0.18);   /* ghost = unreached */
}
.asc-star.on { background: var(--gold, #ffce3a); filter: drop-shadow(0 0 3px rgba(255,206,58,0.55)); }     /* easy/med/hard reached = gold */
.asc-star.blue { -webkit-mask: none; mask: none; background: url(assets/ui/star_blue.webp) center/contain no-repeat; filter: drop-shadow(0 0 3px rgba(90,176,255,0.7)); }
/* the big, bouncy pop when a star lights up (markers + tally) */
.asc-star.pop { animation: ascStarPop .5s cubic-bezier(.2,1.7,.4,1) both; }   /* the tally star "lights up" as the flying star lands */
@keyframes ascStarPop { 0% { transform: scale(.2); } 45% { transform: scale(1.55); } 72% { transform: scale(.88); } 100% { transform: scale(1); } }

/* in-level progress: ONE bar with every threshold marked (star + number), moves-left stacked on the right */
.asc-prog { display: flex; align-items: flex-start; gap: 10px; margin-top: 9px; }
.asc-bar-wrap { position: relative; flex: 1; padding: 2px 0; }
.asc-track { position: relative; display: block; height: 14px; border-radius: 999px; background: rgba(0,0,0,0.30); box-shadow: inset 0 0 0 1px rgba(255,255,255,0.14); overflow: hidden; }
.asc-track i { position: absolute; left: 0; top: 0; bottom: 0; width: 0; border-radius: 999px; background: linear-gradient(90deg, #b07aff, #e6d9ff); box-shadow: 0 0 9px rgba(185,130,255,0.75); transition: width 0.35s cubic-bezier(.34,0,.2,1); }
#ascProgNum { position: absolute; inset: 0; z-index: 1; display: flex; align-items: center; justify-content: center; font-size: 10.5px; font-weight: 800; color: #fff; text-shadow: 0 1px 0 rgba(0,0,0,0.95); letter-spacing: .3px; }
.asc-marks { position: absolute; left: 0; right: 0; top: 0; bottom: 0; pointer-events: none; }
.asc-mark { position: absolute; top: 50%; transform: translate(-50%, -50%); }   /* the (unreached) star sits AT its threshold on the bar */
.asc-mk-star { display: block; width: 16px; height: 16px;
  -webkit-mask: url(assets/ui/star.webp) center/contain no-repeat; mask: url(assets/ui/star.webp) center/contain no-repeat;
  background: rgba(255,255,255,0.9); filter: drop-shadow(0 1px 2px rgba(0,0,0,0.85)); }
/* the threshold number sits to the LEFT of the star, inside the bar (the current objective shows cur/target) */
.asc-mk-num { position: absolute; right: 100%; top: 50%; transform: translateY(-50%); margin-right: 3px;
  font-size: 10px; font-weight: 800; color: #fff; white-space: nowrap; text-shadow: 0 1px 0 rgba(0,0,0,0.95); }
.asc-moves { flex-shrink: 0; font-size: 11px; font-weight: 800; color: #c9b8ff; white-space: nowrap; padding-top: 1px; }

/* a star flying from a just-crossed marker over to the tally */
.asc-fly-star {
  position: fixed; z-index: 360; pointer-events: none;   /* size + position set inline; motion via Web Animations */
  -webkit-mask: url(assets/ui/star.webp) center/contain no-repeat; mask: url(assets/ui/star.webp) center/contain no-repeat;
  background: var(--gold, #ffce3a); filter: drop-shadow(0 0 16px rgba(255, 206, 58, 0.95));
}
.asc-fly-star.blue { -webkit-mask: none; mask: none; background: url(assets/ui/star_blue.webp) center/contain no-repeat; }

/* the 3-star "finish now" choice (appears once the hard star is reached) */
.asc-finish {
  display: block; width: 100%; margin-top: 9px; padding: 8px 10px; cursor: pointer; text-align: center;
  border: none; border-radius: 10px; font: inherit; font-weight: 900; font-size: 13.5px; color: #4a3500;
  background: linear-gradient(180deg, #ffd64a, #f4b327);
  box-shadow: 0 3px 0 #c98a08, 0 4px 10px rgba(0,0,0,.28);
  animation: ascFinishIn .35s cubic-bezier(.2,1.5,.4,1) both;
}
.asc-finish:active { transform: translateY(2px); box-shadow: 0 1px 0 #c98a08, 0 2px 6px rgba(0,0,0,.28); }
.asc-finish .af-sub { display: block; font-size: 10.5px; font-weight: 800; color: #6a4e08; margin-top: 1px; }
.asc-finish .coin-mini { vertical-align: -2px; }
@keyframes ascFinishIn { 0% { transform: scale(.7); opacity: 0; } 100% { transform: scale(1); opacity: 1; } }
/* the one-line teaching hint under the goal */
.asc-hint { margin-top: 4px; font-size: 11px; line-height: 1.3; color: var(--text-dim); }
/* (l'ancien système .gesture-hint / .gh-hand a été retiré au nettoyage v3.255 ; l'aide actuelle = .game-hint,
   plus bas. On supprime le CSS mort qui entrait en COLLISION avec la classe .gh-hand du nouveau système.) */

/* ---- Ascension level-end reward popup (4 tiers: easy/med/hard + masked hidden) ---- */
.asc-end { gap: 12px; }
.asc-end-sub { font-size: 13px; color: var(--text-dim); margin-top: -4px; }
.asc-tiers { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; width: 100%; }
.ae-tile {
  flex: 1; display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding: 10px 4px; border-radius: 14px; color: inherit; font: inherit; -webkit-appearance: none;
  background: rgba(255,255,255,0.04); border: 1.5px solid var(--card-edge);
  opacity: 0.5; transition: opacity 0.2s ease, transform 0.15s ease;
}
.ae-tile.got { opacity: 1; }
/* a freshly-earned reward is collectible: it gently pulses and is tappable to fly into your totals */
.ae-tile.ae-collectible { cursor: pointer; animation: ae-bob 1.2s ease-in-out infinite; }
.ae-tile.ae-collectible:active { transform: scale(0.94); }
.ae-tile.collected { animation: none; opacity: 0.4; }
.ae-tile.collected .ae-tier-rw { position: relative; }
.ae-tile.collected .ae-tier-rw::after { content: '\2713'; position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; color: var(--mint); font-size: 22px; }
@keyframes ae-bob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-3px); } }
.ae-saved { flex: 0 0 auto; min-width: 0; padding: 8px 18px; }   /* wraps to its own centered row */
.ae-saved-lbl { font-size: 9.5px; letter-spacing: 0.4px; color: var(--gold); font-weight: 800; }
.ae-fly { position: fixed; z-index: 200; transform: translate(-50%, -50%); transition: transform 0.6s ease, opacity 0.6s ease; pointer-events: none; font-family: 'Lilita One', 'Trebuchet MS', sans-serif; }
.ae-stars { display: inline-flex; gap: 3px; align-items: center; }
.ae-stars .asc-star { width: 13px; height: 13px; }
.ae-tier-rw { display: inline-flex; align-items: center; gap: 3px; font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 14px; min-height: 36px; }
.ae-easy.got { border-color: var(--rar-common); }
.ae-med.got  { border-color: var(--rar-rare);   box-shadow: 0 0 12px rgba(77,196,255,0.18); }
.ae-hard.got { border-color: var(--rar-epic);   box-shadow: 0 0 12px rgba(176,122,255,0.22); }
.ae-hidden.got { border-color: var(--sky, #5ab0ff); box-shadow: 0 0 16px rgba(90,176,255,0.4); }
.ae-tile.fresh { animation: ae-pop 0.5s cubic-bezier(0.34, 1.6, 0.5, 1); }
@keyframes ae-pop { 0% { transform: scale(0.6); } 55% { transform: scale(1.18); } 100% { transform: scale(1); } }
.ae-bonus { display: inline-flex; width: 22px; height: 22px; }
.ae-bonus .bonus-ic-img, .ae-bonus svg { width: 100%; height: 100%; object-fit: contain; }
/* an UNLOCK tile (1-star onboarding reward = a new power-up / hold slot): full opacity, gold glow, a bigger
   icon + the unlock's name -> reads as a celebrated milestone, not a coin payout */
.ae-tile.ae-unlock { opacity: 1; border-color: var(--gold, #ffce3a); box-shadow: 0 0 16px rgba(255, 206, 58, 0.35); }
.ae-unlock-ic { width: 34px !important; height: 34px !important; }
.ae-unlock-ic img { width: 100%; height: 100%; object-fit: contain; }
.ae-unlock-name { font-size: 11px; font-weight: 800; letter-spacing: 0.3px; color: var(--gold, #ffce3a); text-align: center; line-height: 1.1; }
.ae-hold { font-size: 9px; line-height: 1.1; color: var(--mint); text-align: center; }
/* level-end buttons: COLLECT ALL + NEXT (full width), then Main menu (ghost, left) | Replay (gold, right) */
.asc-end > .btn-primary { width: 100%; }
/* the 3-star "play on for the hidden star" choice (green, distinct from the red NEXT LEVEL) */
.ae-continue { width: 100%; display: inline-flex; align-items: center; justify-content: center; gap: 5px;
  background: linear-gradient(180deg, #4fd08a, #2fae6b); border: none; color: #06351f; font-weight: 900;
  box-shadow: 0 3px 0 #1f7d4c, 0 4px 10px rgba(0,0,0,.28); }
.ae-continue:active { transform: translateY(2px); box-shadow: 0 1px 0 #1f7d4c, 0 2px 6px rgba(0,0,0,.28); }
.ae-continue-ic { font-size: 15px; line-height: 1; }
.ae-collect-all { width: 100%; }
.ae-btn-row { display: flex; gap: 8px; width: 100%; }
/* min-width:0 lets each button shrink to its half instead of a long label (e.g. a translated
   "MAIN MENU") forcing its own width and pushing the sibling past the panel edge */
.ae-btn-row .btn { flex: 1 1 0; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.btn.ae-menu { background: transparent; border: 2px solid rgba(255, 255, 255, 0.85); color: #fff; }
.ae-replay { display: inline-flex; align-items: center; justify-content: center; gap: 5px; }
.ae-replay-ic { font-size: 18px; line-height: 1; }

.logo { text-align: center; }
/* home hero = player identity (avatar + name) instead of the game logo */
.home-identity { display: flex; flex-direction: column; align-items: center; gap: 9px; background: none; border: 0; padding: 6px 0 2px; width: 100%; cursor: pointer; }
.home-identity:active { transform: scale(0.97); }
.home-id-name { font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 30px; line-height: 1; color: var(--text); letter-spacing: 0.5px; text-shadow: 0 2px 0 rgba(0, 0, 0, 0.45); max-width: 86vw; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.logo-word {
  font-family: 'Lilita One', 'Trebuchet MS', sans-serif;
  font-size: clamp(44px, 13vw, 64px);
  line-height: 0.95;
  letter-spacing: 1px;
  display: flex; justify-content: center; flex-wrap: wrap;
}
.logo-word span {
  display: inline-block;
  text-shadow: 0 5px 0 rgba(0, 0, 0, 0.45);
  animation: logo-bob 2.6s ease-in-out infinite;
}
.logo-gap { width: 0.35em; }
.logo-word span:nth-child(1) { color: var(--coral);  animation-delay: 0s;   transform: rotate(-4deg); }
.logo-word span:nth-child(2) { color: var(--amber);  animation-delay: 0.1s; }
.logo-word span:nth-child(3) { color: #ffe14d;       animation-delay: 0.2s; transform: rotate(3deg); }
.logo-word span:nth-child(4) { color: var(--mint);   animation-delay: 0.3s; }
.logo-word span:nth-child(5) { color: var(--sky);    animation-delay: 0.4s; transform: rotate(-3deg); }
.logo-word span:nth-child(7) { color: #b07aff;       animation-delay: 0.5s; }
.logo-word span:nth-child(8) { color: var(--coral);  animation-delay: 0.6s; transform: rotate(4deg); }
.logo-word span:nth-child(9) { color: var(--amber);  animation-delay: 0.7s; transform: rotate(-2deg); }
@keyframes logo-bob { 0%, 100% { translate: 0 0; } 50% { translate: 0 -6px; } }
.tagline { color: var(--text-dim); font-size: 13px; letter-spacing: 4px; margin-top: 8px; text-transform: uppercase; }

.best-banner {
  display: flex; align-items: center; gap: 8px;
  color: var(--text-dim); font-size: 14px; letter-spacing: 1px;
}
.best-banner b { color: var(--gold); font-size: 17px; }

/* chunky toy buttons */
.btn {
  font-family: 'Lilita One', 'Trebuchet MS', sans-serif;
  font-size: 19px; letter-spacing: 1.5px;
  white-space: nowrap;
  color: #fff;
  border: none; border-radius: 18px;
  padding: 15px 30px;
  cursor: pointer;
  transition: transform 0.06s ease, box-shadow 0.06s ease;
}
.btn:active { transform: translateY(4px); }
.btn-primary {
  background: linear-gradient(180deg, var(--coral), var(--coral-deep));
  box-shadow: 0 6px 0 #8e1f37, 0 12px 30px rgba(255, 94, 122, 0.35);
  text-shadow: 0 2px 0 rgba(0, 0, 0, 0.25);
}
.btn-primary:active { box-shadow: 0 2px 0 #8e1f37; }
.btn-play { font-size: 26px; padding: 14px 60px; }
.btn-ghost {
  background: var(--card);
  border: 1px solid var(--card-edge);
  box-shadow: 0 5px 0 rgba(0, 0, 0, 0.4);
  font-size: 15px;
  color: var(--text);
}
.btn-ghost:active { box-shadow: 0 1px 0 rgba(0, 0, 0, 0.4); }
.btn-mini { font-size: 15px; padding: 10px 18px; border-radius: 14px; }
.btn-gold {
  background: linear-gradient(180deg, var(--gold), #e6a216);
  box-shadow: 0 5px 0 #8a5e00;
  color: #4a3200; text-shadow: none;
}
.btn-gold:active { box-shadow: 0 1px 0 #8a5e00; }
.btn-coral {
  background: linear-gradient(180deg, var(--coral), var(--coral-deep));
  box-shadow: 0 5px 0 #8e1f37;
}
.btn-coral:active { box-shadow: 0 1px 0 #8e1f37; }
.btn-ghost2 { background: transparent; border: 2px solid var(--card-edge); font-size: 15px; padding: 10px 18px; border-radius: 14px; }
.btn[disabled] { filter: grayscale(0.8) brightness(0.6); pointer-events: none; }

.count-pill {
  background: rgba(255, 255, 255, 0.1); border-radius: 999px;
  font-family: 'Nunito', sans-serif; font-weight: 900; font-size: 12px;
  padding: 3px 9px; margin-left: 6px; vertical-align: 2px;
}

/* home cards */
.home-cards { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; width: 100%; margin-top: auto; }   /* push the box cards + footer toward the bottom nav (fills the home view) */
.box-slot.is-locked { border-style: dashed; opacity: 0.75; }
.slot-lock { width: 34px; height: 34px; object-fit: contain; }
.card {
  position: relative;
  background: var(--card);
  border: 1px solid var(--card-edge);
  border-radius: var(--radius);
  padding: 14px;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05), 0 10px 24px rgba(0, 0, 0, 0.35);
}
.home-cards .card { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 9px; }
.card-head { display: flex; align-items: center; justify-content: space-between; width: 100%; }
.card-title { font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 13px; letter-spacing: 1.5px; color: var(--text-dim); }
.card-foot { font-size: 11px; color: var(--text-dim); text-align: center; line-height: 1.35; }

.home-foot { display: flex; gap: 8px; width: 100%; }
.home-foot .btn { flex: 1; min-width: 0; position: relative; padding-left: 8px; padding-right: 8px; font-size: 13px; letter-spacing: 1px; }

.legal-links { font-size: 11px; color: var(--text-dim); text-align: center; margin-top: -4px; }
.legal-links a { color: var(--text-dim); text-decoration: none; }
.legal-links a:active { color: var(--text); }

.streak-flame { font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 13px; color: var(--amber); }
.streak-dots { display: flex; gap: 5px; }
.streak-dots i {
  width: 10px; height: 10px; border-radius: 50%;
  background: rgba(255, 255, 255, 0.1);
}
.streak-dots i.lit { background: var(--amber); box-shadow: 0 0 8px var(--amber); }

.info-dot {
  width: 20px; height: 20px; border-radius: 50%;
  border: 1.5px solid var(--text-dim); background: none; color: var(--text-dim);
  font-family: Georgia, serif; font-style: italic; font-weight: 700; font-size: 12px;
  cursor: pointer;
}

/* box art (SVG injected by JS) */
.box-art { width: 74px; height: 60px; filter: drop-shadow(0 6px 14px rgba(255, 200, 61, 0.25)); }
.box-art svg { width: 100%; height: 100%; }

/* ---------- GAME ---------- */
#view-game { gap: 7px; padding-top: 1px; }
/* the game-view chrome keeps its height; only the board + the flexible gap absorb
   slack. Without this a too-tall board squished the flex items and the star bar
   (height 20px, overflow hidden) collapsed to nothing until a full reload. */
#view-game > *:not(#boardWrap):not(.game-gap) { flex-shrink: 0; }

/* separates the hold/bonus controls from the board so a finger aiming at the
   bottom row doesn't catch the hold slot; grows to use a tall (desktop)
   viewport but is capped so the controls never drift too far from play */
.game-gap { flex: 1 1 0; min-height: 14px; max-height: 96px; }

.hud { display: flex; align-items: flex-start; justify-content: space-between; min-height: 44px; }
.hud-score, .hud-best { display: flex; flex-direction: column; }
.hud-score { cursor: pointer; position: relative; }
/* Clean Sweep score-multiplier badge, sitting just right of the score value */
.sweep-badge {
  display: none; position: absolute; left: calc(100% + 8px); bottom: 1px; white-space: nowrap;
  font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 19px; font-weight: 900; color: #06351f;
  background: linear-gradient(180deg, #ffe14d, #ffb648); padding: 1px 9px; border-radius: 10px;
  box-shadow: 0 2px 0 rgba(0, 0, 0, 0.3), 0 0 14px rgba(255, 200, 61, 0.7);
}
.sweep-badge.on { display: inline-block; animation: sweepBadgePulse 0.9s ease-in-out infinite; }
@keyframes sweepBadgePulse { 50% { transform: scale(1.13); } }
.hud-score .hud-label::after { content: ' ⓘ'; opacity: 0.7; }   /* hints it opens the gem guide */
.hud-best { align-items: flex-end; }
.hud-label { font-size: 10px; letter-spacing: 2.5px; color: var(--text-dim); font-weight: 900; }
.hud-value { font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 34px; line-height: 1; }
.hud-help { cursor: pointer; text-decoration: underline dotted; text-underline-offset: 2px; }   /* owner B4 : compteur « coups qui scorent » cliquable (aide) */
.hud-value.small { color: var(--gold); }   /* owner : le nb de coups restants a la MEME taille que le score (plus de reduction) */
/* owner : SCORE / MOVES lisibles sur fond clair, sombre OU charge -> contour sombre + ombre (paint-order garde le remplissage net) */
body[data-view="game"] .hud-label { color: #fff; -webkit-text-stroke: 1.1px rgba(0, 0, 0, 0.6); paint-order: stroke fill; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.55); }
body[data-view="game"] .hud-value { -webkit-text-stroke: 1.4px rgba(0, 0, 0, 0.5); paint-order: stroke fill; text-shadow: 0 2px 3px rgba(0, 0, 0, 0.5); }
/* Ascension: drop the useless SCORE caption (the goal bar carries the objective) and show the
   LEVEL number top-right where BEST normally sits */
body.asc-play .hud-score .hud-label { display: none; }
body.asc-play .hud-best .hud-value { color: #c9b8ff; font-size: 26px; }
.hud-combo {
  font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 16px; color: var(--mint);
  align-self: center; min-height: 20px;
}

/* time-attack HUD */
.rush-bar {
  position: relative;
  height: 18px; border-radius: 999px;
  background: rgba(42, 26, 77, 0.42);   /* owner : track SOMBRE (encre translucide) -> le texte clair ressort partout (avant : blanc quasi transparent = blanc sur fond clair illisible) */
  border: 1px solid var(--card-edge);
  overflow: hidden;
  margin-top: -4px;
}
.rush-bar i {
  position: absolute; left: 0; top: 0; bottom: 0;
  display: block; width: 0%;
  background: linear-gradient(90deg, var(--sky), var(--mint));
  border-radius: 999px;
  transition: width 0.25s ease;
}
.rush-bar i.done { background: linear-gradient(90deg, var(--gold), var(--amber)); }
/* owner (tension) : COUPS RESTANTS en haut à droite (rouge + "bump" sous 10) ; le niveau n'est plus dans le HUD (il vit dans la pop-up du score) */
.hud-value.low-moves { color: #e23b3b; }
.hud-value.bump { animation: mbBump 0.3s ease; will-change: transform; }
@keyframes mbBump { 0% { transform: scale(1); } 38% { transform: scale(1.3); } 100% { transform: scale(1); } }
.rush-bar span {
  position: relative; z-index: 1;
  display: block; text-align: center;
  font-size: 10px; letter-spacing: 2px; font-weight: 900;
  color: #fff;
  -webkit-text-stroke: 2.2px var(--dp-ink); paint-order: stroke fill;   /* contour encre -> lisible sur barre claire, dorée ou enflammée */
  line-height: 17px;
}
.hud-value.urgent { color: var(--coral); animation: urgent-pulse 1s ease-in-out infinite; }
@keyframes urgent-pulse {
  50% { transform: scale(1.12); text-shadow: 0 0 14px var(--coral); }
}

/* ---- TIME ATTACK fuse bar: the fill is the remaining wick (left-aligned), so as it shrinks the burning
   tip travels right -> left. A glowing spark sits at the wick's tip; it pulses red when nearly out. ---- */
.rush-bar.fuse {
  overflow: visible;                 /* let the spark glow past the wick tip */
  height: 16px;
  background: rgba(0, 0, 0, 0.34);
  border-color: rgba(255, 255, 255, 0.16);
}
.rush-bar.fuse i {
  background: repeating-linear-gradient(45deg, #e6b35a 0 5px, #c0872f 5px 10px);   /* braided fuse rope */
  box-shadow: 0 0 8px rgba(255, 180, 70, 0.55), inset 0 0 0 1px rgba(0,0,0,0.2);
  transition: width 0.2s linear;
}
.rush-bar.fuse i::after {            /* the burning spark at the wick's right tip */
  content: ''; position: absolute; right: -5px; top: 50%;
  width: 16px; height: 16px; border-radius: 50%;
  background: radial-gradient(circle, #fff 0%, #ffe06a 35%, #ff8a2a 62%, rgba(255,120,40,0) 74%);
  transform: translateY(-50%);
  animation: fuseSpark 0.32s ease-in-out infinite alternate;
}
@keyframes fuseSpark {
  from { transform: translateY(-50%) scale(0.8); opacity: 0.85; }
  to   { transform: translateY(-50%) scale(1.25); opacity: 1; }
}
.rush-bar.fuse.low i {
  background: repeating-linear-gradient(45deg, #ff7a52 0 5px, #d8392a 5px 10px);
  box-shadow: 0 0 12px rgba(255, 70, 45, 0.85);
  animation: fuseLow 0.45s ease-in-out infinite;
}
@keyframes fuseLow { 50% { box-shadow: 0 0 18px 2px rgba(255, 60, 40, 0.95); } }
.rush-bar.fuse span { color: #fff; text-shadow: 0 1px 0 rgba(0, 0, 0, 0.95); letter-spacing: 1px; }
.rush-bar.fuse.boost { animation: fuseBoost 0.5s ease; }   /* fires when a big move adds a chunk of time */
@keyframes fuseBoost {
  25% { transform: scale(1.03); box-shadow: 0 0 18px 2px rgba(255, 210, 90, 0.85); }
}
.go-rush { font-size: 13px; color: var(--text-dim); text-align: center; }

.board-wrap { position: relative; align-self: center; }
.board-wrap.shake { animation: shake 0.25s ease; }
@keyframes shake {
  0%, 100% { transform: translate(0, 0); }
  25% { transform: translate(-4px, 2px); }
  50% { transform: translate(4px, -2px); }
  75% { transform: translate(-2px, -2px); }
}
/* old-VHS REWIND flicker (Undo power-up): scanlines + a tracking band sweeping upward */
#rewindFx { position: fixed; inset: 0; z-index: 9000; pointer-events: none; opacity: 0; mix-blend-mode: overlay; overflow: hidden;
  background: repeating-linear-gradient(0deg, rgba(0, 0, 0, 0) 0 3px, rgba(0, 0, 0, 0.22) 3px 4px), linear-gradient(110deg, rgba(120, 160, 255, 0.06), rgba(255, 120, 160, 0.06)); }
#rewindFx > i { position: absolute; left: -4%; width: 108%; height: 64px; background: linear-gradient(180deg, transparent, rgba(255, 255, 255, 0.55), transparent); filter: blur(1px); top: 100%; }
#rewindFx.go { animation: rewind-flick 0.58s linear; pointer-events: auto; }   /* bloque l'input pendant le rembobinage (le revert du plateau tombe à ~300 ms) */
#rewindFx.go > i { animation: rewind-band 0.145s linear 4; }
@keyframes rewind-flick { 0% { opacity: 0; } 8% { opacity: 1; transform: translateX(-3px); } 30% { transform: translateX(3px); } 55% { transform: translateX(-2px); } 90% { opacity: 1; } 100% { opacity: 0; } }
@keyframes rewind-band { 0% { top: 100%; } 100% { top: -64px; } }
/* (screen shake is now driven by the Web Animations API on #app — see screenShake() — to avoid the CSS
   animation-cascade conflict with the board's .boom zoom; this keyframe is kept for reference only) */
@keyframes screen-shake {
  0%, 100% { transform: translate(0, 0); }
  12%, 88% { transform: translate(calc(var(--shake-amp, 6px) * -.32), calc(var(--shake-amp, 6px) * .18)); }
  26%, 74% { transform: translate(calc(var(--shake-amp, 6px) * .62), calc(var(--shake-amp, 6px) * -.34)); }
  40%, 60% { transform: translate(calc(var(--shake-amp, 6px) * -1), calc(var(--shake-amp, 6px) * .42)); }
  50% { transform: translate(var(--shake-amp, 6px), calc(var(--shake-amp, 6px) * -.5)); }
}
/* slow-mo impact: a quick zoom-punch that settles, reads as emphasis */
.board-wrap.boom { animation: boom 0.34s cubic-bezier(.2, 1.4, .4, 1); }
@keyframes boom {
  0% { transform: scale(1); }
  30% { transform: scale(1.045); }
  100% { transform: scale(1); }
}
@media (prefers-reduced-motion: reduce) {
  .board-wrap.boom { animation: none; }
}
.board-wrap.glow { animation: board-glow 0.9s ease; }
@keyframes board-glow {
  0%, 100% { filter: none; }
  35% { filter: drop-shadow(0 0 26px rgba(255, 200, 61, 0.55)) brightness(1.12); }
}

#board {
  display: grid;
  grid-template-columns: repeat(8, var(--cell));
  grid-template-rows: repeat(8, var(--cell));
  gap: var(--gap);
  background: rgba(12, 13, 22, 0.72);   /* fallback */
  background: color-mix(in srgb, var(--board-tint, var(--wp-tint, #6a5acd)) 8%, rgba(12, 13, 22, 0.72));   /* the chosen board colour, else the wallpaper hue */
  /* a clear, bright frame so the board's limits read at a glance, even on a dark wallpaper */
  border: 2px solid rgba(255, 255, 255, 0.28);
  border-radius: 16px;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.45), 0 6px 22px rgba(0, 0, 0, 0.4), inset 0 0 0 1px rgba(255, 255, 255, 0.06);
  padding: var(--gap);
  touch-action: none;
}
/* a single faint light sweep across the whole board — ONE animated overlay (not
   per-cell), so it can't trip the iOS layer bug that made gems vanish. animates
   background-position only (no transform/mask/pseudo). */
#boardShine {
  position: absolute; inset: 0; z-index: 3; pointer-events: none;
  border-radius: 16px; overflow: hidden;
  background-image: linear-gradient(115deg, rgba(255, 255, 255, 0) 42%, rgba(255, 255, 255, 0.06) 47%, rgba(255, 255, 255, 0.13) 50%, rgba(255, 255, 255, 0.06) 53%, rgba(255, 255, 255, 0) 58%);
  background-repeat: no-repeat;
  background-size: 200% 100%;
  background-position: 150% 0;   /* parked off-screen while the player is active */
}
/* only sweep when idle — while interacting it stays hidden (no animation) */
body.idle #boardShine { animation: board-shine 11s ease-in-out infinite; }
@keyframes board-shine {
  0% { background-position: 150% 0; }
  12%, 100% { background-position: -50% 0; }
}
/* owner : le clean sweep est RARE et prestigieux -> flash DORÉ large et lumineux (plus valorisant que l'ancien vert) */
#boardShine.sweep-clean {
  background-image: linear-gradient(115deg, rgba(242,194,0,0) 28%, rgba(242,194,0,0.34) 44%, rgba(255,240,170,0.88) 50%, rgba(242,194,0,0.34) 56%, rgba(242,194,0,0) 72%);
  animation: board-sweep-clean 1.15s ease-out;
}
@keyframes board-sweep-clean { 0% { background-position: 150% 0; } 100% { background-position: -60% 0; } }
/* owner : plateau DORÉ tant que le boost clean-sweep est armé (les 2 prochains coups scorants = base ×10 puis ×5) -> prestige + on voit que le prochain coup va payer gros */
#board.sweep-armed { border-color: #F2C200; animation: board-armed-pulse 1.5s ease-in-out infinite; }
@keyframes board-armed-pulse {
  0%, 100% { box-shadow: 0 0 0 2px #F2C200, 0 0 20px 4px rgba(242,194,0,.42), inset 0 0 16px rgba(242,194,0,.14); }
  50%      { box-shadow: 0 0 0 2px #FFDD55, 0 0 34px 9px rgba(242,194,0,.62), inset 0 0 26px rgba(242,194,0,.22); }
}
@media (prefers-reduced-motion: reduce) { #board.sweep-armed { animation: none; box-shadow: 0 0 0 2px #F2C200, 0 0 18px 4px rgba(242,194,0,.5); } }
@media (prefers-reduced-motion: reduce) { #boardShine { animation: none; opacity: 0; } }
/* per-gem twinkle (spawned by tickGemSparkles): a 4-point star that pops + fades.
   transient (auto-removed) so it can't trip the iOS gem-cell layer bug. */
.gem-sparkle {
  position: absolute; width: 14px; height: 14px; z-index: 4; pointer-events: none;
  transform: translate(-50%, -50%) scale(0);
  background: #fff;
  clip-path: polygon(50% 0%, 58% 42%, 100% 50%, 58% 58%, 50% 100%, 42% 58%, 0% 50%, 42% 42%);
  filter: drop-shadow(0 0 3px var(--sc, #fff));
  animation: gem-sparkle 0.76s ease-out forwards;
}
@keyframes gem-sparkle {
  0% { opacity: 0; transform: translate(-50%, -50%) scale(0) rotate(0deg); }
  40% { opacity: 0.95; transform: translate(-50%, -50%) scale(1) rotate(25deg); }
  100% { opacity: 0; transform: translate(-50%, -50%) scale(0.35) rotate(50deg); }
}
@media (prefers-reduced-motion: reduce) { .gem-sparkle { display: none; } }
/* boxes are rendered from art now (see boxSVG in game.js) */
.box-img { display: inline-block; vertical-align: middle; object-fit: contain; }

/* developer dashboard (test tuning) — only ever shown via ?dev or PP.dev() */
#devFab {
  position: fixed; left: 8px; bottom: 8px; z-index: 200;
  font: 700 11px system-ui, sans-serif; letter-spacing: 0.5px;
  padding: 6px 11px; border: none; border-radius: 8px;
  background: #b14ad4; color: #fff; opacity: 0.82; cursor: pointer;
}
.dev-ov {
  position: fixed; inset: 0; z-index: 199; display: none;
  align-items: center; justify-content: center; padding: 14px;
  background: rgba(0, 0, 0, 0.62);
}
.dev-ov.show { display: flex; }
.dev-panel {
  width: 100%; max-width: 480px; max-height: 88vh;
  display: flex; flex-direction: column;
  background: #14151f; border: 1px solid #2a2c3a; border-radius: 14px; color: #e8e8ef;
}
.dev-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 11px 14px; border-bottom: 1px solid #2a2c3a; flex: none;
}
.dev-head b { font-size: 13px; letter-spacing: 0.4px; }
.dev-actions { display: flex; gap: 6px; }
.dev-body { overflow-y: auto; padding: 4px 14px 16px; }
.dev-sec h4 {
  margin: 14px 0 7px; font-size: 11px; font-weight: 700; letter-spacing: 0.5px;
  text-transform: uppercase; color: #b7a0e8;
}
.dev-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 6px 12px; }
.dev-field { display: flex; align-items: center; justify-content: space-between; gap: 6px; font-size: 12px; }
.dev-field span { color: #9aa; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dev-field input {
  width: 86px; flex: none; padding: 4px 6px; font-size: 12px;
  background: #0e0f17; border: 1px solid #2a2c3a; border-radius: 6px; color: #fff;
}
.dev-prof { display: flex; flex-wrap: wrap; gap: 6px; }
.dev-prof .btn { flex: 1 1 40%; }
/* dev buttons have no colour modifier -> were white text on the browser default grey. give them a dark surface. */
.dev-actions .btn:not(.btn-gold), .dev-prof .btn:not(.btn-gold) {
  background: #2a2c3a; color: #e8e8ef; border: 1px solid #3a3d4e; box-shadow: none;
}
.dev-actions .btn:not(.btn-gold):active, .dev-prof .btn:not(.btn-gold):active { background: #353849; transform: none; }

/* a small attention dot (e.g. Styles unlocked for the first time) */
.nav-dot {
  position: absolute; top: 4px; right: 5px;
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--coral, #ff5e6c);
  box-shadow: 0 0 6px rgba(255, 94, 108, 0.7);
}
/* achievements */
.nav-badge {
  position: absolute; top: 3px; right: 4px;            /* corner badge — never widens the button */
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 15px; height: 15px; padding: 0 3px;
  font: 800 9px/1 system-ui, sans-serif; color: #fff;
  background: var(--coral, #ff5e6c); border-radius: 999px;
}
.ach-panel { display: flex; flex-direction: column; gap: 10px; width: 100%; max-width: 460px; max-height: 86vh; }
.ach-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.ach-head .panel-title { margin: 0; }
.ach-list { display: flex; flex-direction: column; gap: 8px; width: 100%; overflow-y: auto; max-height: 64vh; }

/* ---- persistent bottom nav: icons desaturated to blend in; active = colour + grow + bounce + label ---- */
#navBar {
  display: flex; justify-content: space-around; align-items: flex-end; gap: 4px;
  flex-shrink: 0; padding: 0 2px 1px; overflow: visible;   /* tight top so a selected (enlarged) icon overflows upward; sits lower */
  /* ONE nav width on every scene (home + all list views): a centred bar so the 5 icons keep the same
     spacing everywhere instead of stretching wide on home and cramming tight on the wide lists. */
  width: 100%; max-width: 520px; margin: 4px auto 0;
}
body[data-view="game"] #navBar { display: none; }   /* the game owns the bottom (tray + bonuses) */
/* first run (before the very first game): the menu + meta are hidden so the ONLY action is PLAY */
body.first-run #navBar,
body.first-run #view-home .best-banner,
body.first-run #view-home .level-bar { display: none; }
.nav-item {
  position: relative; flex: 1; min-width: 0;
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  background: none; border: 0; cursor: pointer; padding: 1px 2px 3px;
  -webkit-tap-highlight-color: transparent;
}
.nav-ic {
  width: 34px; height: 34px; object-fit: contain;
  filter: grayscale(1) brightness(1.5) opacity(0.5);   /* desaturated, blends with the backdrop */
  transition: filter 0.2s ease, transform 0.18s ease;
}
.nav-item:active .nav-ic { transform: scale(0.9); }
.nav-label {
  font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 10px; letter-spacing: 0.5px;
  color: var(--text); max-height: 0; opacity: 0; overflow: hidden;
  transition: max-height 0.2s ease, opacity 0.2s ease;
}
.nav-item.active .nav-ic { filter: none; transform: scale(1.24) translateY(-2px); animation: nav-bounce 0.5s cubic-bezier(0.34, 1.7, 0.5, 1); }
.nav-item.active .nav-label { max-height: 16px; opacity: 1; }
@keyframes nav-bounce { 0% { transform: scale(0.78) translateY(0); } 45% { transform: scale(1.4) translateY(-3px); } 100% { transform: scale(1.24) translateY(-2px); } }
/* notification dot/badge sit on the icon's upper-right */
#navBar .nav-dot, #navBar .nav-badge { top: 2px; left: calc(50% + 9px); right: auto; }

/* ---- GOALS view (was an overlay; now a nav destination so the bar persists) ---- */
.goals-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 8px; flex-shrink: 0; }
.goals-head .view-title { margin: 0; }
/* the WHOLE goals view scrolls as ONE (daily challenges THEN achievements), instead of the daily box
   staying fixed while the achievements scroll in a cramped inner area */
#view-goals .daily-box, #view-goals .ach-list { flex: none; max-height: none; overflow: visible; }
.ach-sec-head { font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 15px; letter-spacing: .06em; color: var(--gold, #ffc83d); margin: 16px 0 8px; text-shadow: 0 2px 0 rgba(0, 0, 0, .5); }
.ach-row {
  display: flex; align-items: center; gap: 12px; text-align: left;
  background: rgba(44, 38, 88, 0.52); border: 1px solid var(--card-edge); border-radius: 14px; padding: 10px 12px;
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);   /* frosted glass: readable text, wallpaper softly behind */
}
.ach-row.locked { opacity: 1; }                 /* in progress — shown in full, not dimmed */
.ach-row.done { opacity: 0.6; }                 /* fully unlocked — greyed back */
.ach-row.ready { border-color: var(--gold, #ffc83d); box-shadow: inset 0 0 0 1px var(--gold, #ffc83d); }
.ach-status-ic { width: 24px; height: 24px; object-fit: contain; }
.ach-ic { flex: none; width: 30px; text-align: center; font-size: 23px; }
.ach-ic .ach-img { width: 30px; height: 30px; object-fit: contain; vertical-align: middle; }
.ach-pop-ic .ach-img { width: 26px; height: 26px; object-fit: contain; vertical-align: middle; }
.ach-info { flex: 1 1 auto; min-width: 0; }
.ach-name { font-weight: 800; font-size: 14px; }
.ach-desc { font-size: 12px; color: var(--text-dim); }
.ach-reward { font-size: 12px; margin-top: 2px; }
.ach-prog { height: 6px; border-radius: 999px; background: rgba(255, 255, 255, 0.1); overflow: hidden; margin: 5px 0 2px; }
.ach-prog i { display: block; height: 100%; border-radius: 999px; background: linear-gradient(90deg, var(--sky, #4dc4ff), var(--rar-epic, #b07aff)); }
.ach-prog-n { font-size: 11px; font-weight: 800; color: var(--text-dim); }

/* ---- daily challenges (top of the Goals view) ---- */
.nav-badge.dot { min-width: 9px; width: 9px; height: 9px; padding: 0; }   /* fresh dailies: a plain dot, no number */
.daily-box { display: flex; flex-direction: column; gap: 8px; width: 100%; margin-bottom: 14px; }
.daily-head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; margin-bottom: 2px; }
.daily-title { font-weight: 900; font-size: 13px; letter-spacing: .04em; color: var(--gold, #ffc83d); }
.daily-reset { font-size: 11px; color: var(--text-dim); }
.daily-card {
  display: flex; align-items: center; gap: 12px; text-align: left;
  background: rgba(70, 54, 30, 0.5); border: 1px solid var(--card-edge); border-radius: 14px; padding: 9px 12px;
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);   /* frosted glass, faint gold tint */
}
.daily-card.ready { border-color: var(--gold, #ffc83d); box-shadow: inset 0 0 0 1px var(--gold, #ffc83d); }
.daily-card.claimed { opacity: .55; }
.daily-info { flex: 1 1 auto; min-width: 0; }
.daily-name { font-weight: 800; font-size: 13.5px; }
.daily-desc { font-size: 12px; color: var(--text-dim); }
.daily-right { flex: none; display: flex; align-items: center; }
.daily-prog-n { font-size: 11px; font-weight: 800; color: var(--text-dim); }
.daily-bonus {
  display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap;
  background: rgba(176, 122, 255, .08); border: 1px dashed var(--card-edge); border-radius: 14px; padding: 9px 12px;
}
.daily-bonus.ready { border-style: solid; border-color: var(--rar-epic, #b07aff); box-shadow: inset 0 0 0 1px var(--rar-epic, #b07aff); }
.daily-bonus.done { opacity: .6; }
.daily-bonus-lbl { font-weight: 800; font-size: 12.5px; }
.daily-bonus-sub { font-size: 11px; color: var(--text-dim); }
.daily-bonus-btns { display: flex; gap: 6px; }
/* owner : la section "Défis du jour" façon Boutique de Styles — cadre blanc englobant + tag corail penché */
.daily-featured {
  position: relative; margin-top: 20px; padding: 27px 11px 11px;
  background: linear-gradient(180deg, #ffe9d2, #ffdcbb); border: 1.5px solid #ffcfa1; border-radius: 18px; box-shadow: 0 6px 16px rgba(55, 25, 100, .16);   /* owner T62 : cadre général des défis du jour = orange pastel */
  display: flex; flex-direction: column; gap: 8px;
}
.daily-featured .featured-ribbon { top: -12px; color: #fff !important; text-shadow: 0 1px 2px rgba(0, 0, 0, .35); }   /* le tag chevauche le haut du cadre ; owner : texte BLANC (!important car .ribbon-coral est déclaré plus bas) */
.daily-featured .daily-reset { position: absolute; top: 10px; right: 14px; font-size: 10.5px; }
/* cartes tintées pour ressortir DANS le cadre blanc (specificite > l'override blanc de #view-goals) */
#view-goals .daily-featured .daily-card { background: #fff !important; border-color: #fff !important; }   /* owner T62 : cartes BLANC PUR (comme les autres succès), sur le cadre orange pastel */
#view-goals .daily-featured .daily-bonus { background: #fff; border-color: #fff; }
/* ascenseur retiré (feeling page web) */
#view-goals::-webkit-scrollbar { width: 0; height: 0; }
#view-goals { scrollbar-width: none; }
/* daily streak (owner) — compteur de jours consécutifs + 7 pips du cycle, au-dessus des défis */
.streak-widget { margin-top: 14px; padding: 10px 12px 11px; background: #fff; border-radius: 16px; box-shadow: 0 5px 14px rgba(55, 25, 100, .14); display: flex; flex-direction: column; gap: 9px; }
.streak-head { display: flex; align-items: center; gap: 8px; }
.streak-flame { width: 22px; height: 22px; object-fit: contain; }
.streak-title { font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 15px; color: var(--dp-ink, #241640); letter-spacing: .02em; }
.streak-sub { margin-left: auto; font-size: 11px; font-weight: 800; color: #8a7bb0; }
.streak-track { display: grid; grid-template-columns: repeat(7, 1fr); gap: 5px; }
.streak-pip { display: flex; flex-direction: column; align-items: center; gap: 3px; padding: 6px 2px; border-radius: 11px; background: #f1ecfa; border: 1.5px solid transparent; }
.streak-pip .sp-day { font-size: 9px; font-weight: 800; color: #8a7bb0; }
.streak-pip .sp-amt { font-size: 11px; font-weight: 900; color: var(--dp-ink, #241640); display: inline-flex; align-items: center; gap: 1px; }
.streak-pip .sp-amt .jewel-mini { width: 11px; height: 11px; vertical-align: 0; }
.streak-pip.done { background: linear-gradient(180deg, #7be0a0, #4fc07d); border-color: #3ea86a; }
.streak-pip.done .sp-day, .streak-pip.done .sp-amt { color: #fff; }
.streak-pip.next { background: #fff6da; border-color: var(--gold, #ffc83d); box-shadow: 0 0 0 2px rgba(255, 200, 61, .35); }
/* owner B11 : le pip du jour gagné est CLIQUABLE pour collecter (plus de bouton à côté du titre) */
.streak-pip.claimable { cursor: pointer; background: linear-gradient(180deg, #ffe08a, #ffc83d); border-color: #e0a41e; box-shadow: 0 0 0 2px rgba(255, 200, 61, .55); animation: streakPulse 1.1s ease-in-out infinite; }
.streak-pip.claimable .sp-day, .streak-pip.claimable .sp-amt { color: #3a2600; }
@keyframes streakPulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.07); } }
.streak-collect-hint { color: #d99a1e; font-weight: 800; }
.ach-status { flex: none; }
.ach-status > * { vertical-align: middle; }
.cell {
  width: var(--cell); height: var(--cell);
  border-radius: calc(var(--cell) * 0.22);
  background: color-mix(in srgb, var(--board-tint, var(--cell-empty)) 24%, var(--cell-empty));   /* empty cells pick up the chosen board colour */
  position: relative;
}

/* ---------- gems ----------
   Filled cells, tray pieces and the drag ghost render as three natures
   of gem, each with its own silhouette and light play:
   k0 facet (emerald-cut octagon) · k1 orb (glossy cabochon, +1 bonus)
   k2 diamond (kite brilliant, +3 bonus). All twinkle on a desynced
   phase (--tw) so the board glitters like a jewellery tray. */
:root { --diamond-clip: polygon(50% 0%, 94% 36%, 50% 100%, 6% 36%); }   /* used by the phantom shatter only */

/* common (tier 0) cell: a solid material/colour block tile.
   radius is a % of the element's own size so tray-preview cells (smaller
   than board cells) stay rounded-square instead of turning into circles */
.cell.filled, .pcell {
  border-radius: 18%;
  background-color: var(--c);
  box-shadow: inset 0 2px 3px rgba(255, 255, 255, 0.28), inset 0 -3px 5px rgba(0, 0, 0, 0.24);
}
/* material tiles: the texture fills the cell over a base colour (brightness
   set inline per slot); the base shows if the texture hasn't loaded */
.cell.filled.material, .pcell.material {
  background-size: cover; background-position: center;
}
/* pronounced, almost caricatural cartoon bevel — the relief makes the material feel
   tactile/premium. Sized relative to the cell so it stays chunky on the board and in
   the tray. Light comes from the top-left (matches the sheen gradient in paintCommon). */
.cell.filled.material.flat {
  box-shadow:
    inset 0 calc(var(--cell) * 0.12 * var(--bevel, 1)) calc(var(--cell) * 0.04) rgba(255, 255, 255, 0.62),
    inset calc(var(--cell) * 0.09 * var(--bevel, 1)) 0 calc(var(--cell) * 0.045) rgba(255, 255, 255, 0.30),
    inset 0 calc(var(--cell) * -0.15 * var(--bevel, 1)) calc(var(--cell) * 0.055) rgba(0, 0, 0, 0.5),
    inset calc(var(--cell) * -0.09 * var(--bevel, 1)) 0 calc(var(--cell) * 0.055) rgba(0, 0, 0, 0.3);
}
.pcell.material.flat {
  box-shadow:
    inset 0 calc(var(--mcell) * 0.12 * var(--bevel, 1)) calc(var(--mcell) * 0.04) rgba(255, 255, 255, 0.62),
    inset 0 calc(var(--mcell) * -0.15 * var(--bevel, 1)) calc(var(--mcell) * 0.055) rgba(0, 0, 0, 0.5);
}
/* gem cells/pieces sit on a neutral socket, NOT their own colour — without the
   old clip-mask, a red orb on a red --c square read as a plain tile. The art
   carries the colour; the socket just gives every gem contrast on any skin. */
.cell.filled.gem {
  background-color: var(--cell-empty);   /* the socket gives a gem contrast / weight ON the board */
  box-shadow: none;
}
.pcell.gem {
  background-color: transparent;   /* in the hand / while dragging the orb floats cleanly (no socket square) */
  box-shadow: none;
}
/* sprite block skins: the motif (a 3x2 atlas cell, zoomed 1.2x) floats on a neutral
   socket — the cell reads as occupied (like gems) while the art stays airy. */
/* SPRITE block: the motif sits on a plain EMPTY-CELL socket (exactly like a gem - no tinted socle, so a
   filled sprite cell is indistinguishable from an empty cell underneath), with the art layered on top and
   zoomed a touch larger. The board cell carries the empty-cell colour; in the hand it floats cleanly. */
.cell.filled.sprite { background-color: var(--cell-empty); box-shadow: none; overflow: visible; }
.pcell.sprite { background: none; box-shadow: none; overflow: visible; }
.cell.filled.sprite::before, .pcell.sprite::before { content: none; }
.cell.filled.sprite .spr-art, .pcell.sprite .spr-art {
  position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background-repeat: no-repeat;
}
/* the lift shadow ONLY on the static board - never inside #dragPiece (a nested filter there makes WebKit
   drop the atlas texture, like the translateZ gotcha) */
.cell.filled.sprite .spr-art { filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.35)); }
/* DEMO (skin-driven FEEL): 3 random idle wing-flaps, triggered sparsely by tickButterflyFlap.
   flap1 = one slow deep fold · flap2 = two quick beats · flap3 = several slow beats. */
.cell.filled.butterfly.flap1 .spr-art,
.cell.filled.butterfly.flap2 .spr-art,
.cell.filled.butterfly.flap3 .spr-art { transform-origin: 50% 50%; }
.cell.filled.butterfly.flap1 .spr-art { animation: bfly-flap1 1.2s ease-in-out; }
.cell.filled.butterfly.flap2 .spr-art { animation: bfly-flap2 0.5s ease-in-out; }
.cell.filled.butterfly.flap3 .spr-art { animation: bfly-flap3 1.9s ease-in-out; }
@keyframes bfly-flap1 {   /* one slow, deep fold (wings nearly shut) */
  0% { transform: scaleX(1); } 45% { transform: scaleX(0.12) translateY(-1px); } 90% { transform: scaleX(1.04); } 100% { transform: scaleX(1); }
}
@keyframes bfly-flap2 {   /* two quick beats */
  0% { transform: scaleX(1); } 25% { transform: scaleX(0.2); } 50% { transform: scaleX(1); } 75% { transform: scaleX(0.2); } 100% { transform: scaleX(1); }
}
@keyframes bfly-flap3 {   /* several slow beats */
  0% { transform: scaleX(1); } 16% { transform: scaleX(0.18); } 33% { transform: scaleX(1); } 50% { transform: scaleX(0.18); } 66% { transform: scaleX(1); } 83% { transform: scaleX(0.18); } 100% { transform: scaleX(1); }
}
@media (prefers-reduced-motion: reduce) {
  .cell.filled.butterfly.flap1 .spr-art, .cell.filled.butterfly.flap2 .spr-art, .cell.filled.butterfly.flap3 .spr-art { animation: none; }
}
/* keep the HAND / HOLD sprite cells on their own GPU layer so a rotate (which repositions the cells in
   place) moves the cached texture instead of re-decoding the atlas. Scoped to .tray-piece ON PURPOSE:
   the drag piece (#dragPiece) is a single filtered layer (drop-shadow) moved by transform — promoting its
   cells into nested sub-layers makes WebKit re-flatten them against the filter every frame and drop the
   sprite textures (the block art vanished mid-drag). It must stay one un-fragmented layer. */
.tray-piece .pcell.sprite { transform: translateZ(0); }
/* rising-pressure junk: a clogged grey tile (clears with its line like any filled cell) */
.cell.filled.junk {
  background: repeating-linear-gradient(45deg, #3b3b46, #3b3b46 5px, #45454f 5px, #45454f 10px);
  box-shadow: inset 0 2px 3px rgba(255, 255, 255, 0.10), inset 0 -3px 5px rgba(0, 0, 0, 0.30);
}
/* Survival GARBAGE: breakable obstacle, art set inline (garbage01 intact / garbage02 cracked) per HP. */
.cell.filled.garbage {
  background-size: cover; background-position: center; background-repeat: no-repeat;
  /* a clear dark CONTOUR + a light outer ring so a garbage block never reads as an empty cell */
  border: 2px solid rgba(14, 16, 24, 0.92);
  box-shadow:
    0 0 0 1.5px rgba(255, 255, 255, 0.30),                 /* bright outer rim against the dark board */
    inset 0 2px 3px rgba(255, 255, 255, 0.20),
    inset 0 -3px 6px rgba(0, 0, 0, 0.5);
}
/* riveted corners (like the old unbreakable block) -> instantly reads as a hard obstacle */
.cell.filled.garbage::after {
  content: ''; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  background:
    radial-gradient(circle at 18% 18%, rgba(255, 255, 255, 0.65) 0 1.6px, rgba(0, 0, 0, 0.45) 2px, transparent 2.8px),
    radial-gradient(circle at 82% 18%, rgba(255, 255, 255, 0.65) 0 1.6px, rgba(0, 0, 0, 0.45) 2px, transparent 2.8px),
    radial-gradient(circle at 18% 82%, rgba(255, 255, 255, 0.65) 0 1.6px, rgba(0, 0, 0, 0.45) 2px, transparent 2.8px),
    radial-gradient(circle at 82% 82%, rgba(255, 255, 255, 0.65) 0 1.6px, rgba(0, 0, 0, 0.45) 2px, transparent 2.8px);
}
/* CRACKED garbage (1 HP, one hit from breaking) reads as DAMAGED: warm warning frame + red inner glow + a crack streak */
.cell.filled.garbage.g-hp1 {
  border-color: rgba(228, 112, 70, 0.95);
  box-shadow:
    0 0 0 1.5px rgba(255, 150, 100, 0.55),
    inset 0 0 10px rgba(220, 70, 45, 0.55),
    inset 0 -3px 6px rgba(0, 0, 0, 0.5);
}
.cell.filled.garbage.g-hp1::after {
  background:
    /* lightning-bolt crack across the middle */
    linear-gradient(115deg, transparent 46%, rgba(20, 8, 6, 0.85) 47.5%, rgba(255, 220, 200, 0.7) 49%, rgba(20, 8, 6, 0.85) 50.5%, transparent 52%),
    radial-gradient(circle at 18% 18%, rgba(255, 210, 180, 0.7) 0 1.6px, rgba(90, 20, 10, 0.5) 2px, transparent 2.8px),
    radial-gradient(circle at 82% 18%, rgba(255, 210, 180, 0.7) 0 1.6px, rgba(90, 20, 10, 0.5) 2px, transparent 2.8px),
    radial-gradient(circle at 18% 82%, rgba(255, 210, 180, 0.7) 0 1.6px, rgba(90, 20, 10, 0.5) 2px, transparent 2.8px),
    radial-gradient(circle at 82% 82%, rgba(255, 210, 180, 0.7) 0 1.6px, rgba(90, 20, 10, 0.5) 2px, transparent 2.8px);
}
/* UNBREAKABLE block: a heavy, riveted metal slab so it instantly reads as "you can't clear this".
   Placeholder look — drop a sprite onto .cell.filled.solid later (set background-image). */
.cell.filled.solid {
  background:
    radial-gradient(circle at 22% 22%, rgba(255, 255, 255, 0.5) 0 1.5px, transparent 2px),
    radial-gradient(circle at 78% 22%, rgba(255, 255, 255, 0.5) 0 1.5px, transparent 2px),
    radial-gradient(circle at 22% 78%, rgba(255, 255, 255, 0.5) 0 1.5px, transparent 2px),
    radial-gradient(circle at 78% 78%, rgba(255, 255, 255, 0.5) 0 1.5px, transparent 2px),
    linear-gradient(150deg, #6b7180 0%, #474d5b 45%, #333845 100%);
  box-shadow: inset 0 2px 2px rgba(255, 255, 255, 0.22), inset 0 -4px 6px rgba(0, 0, 0, 0.55), inset 0 0 0 2px rgba(0, 0, 0, 0.30);
}
/* confirm dialog + box-full popup */
.cd-panel, .cf-panel { gap: 12px; text-align: center; max-width: 360px; }
.cd-body, .cf-body { font-size: 14px; color: var(--text-dim); line-height: 1.5; margin: 2px 0; }
.cf-panel {
  position: relative;
  width: min(410px, 100%);
  max-width: 410px;
  max-height: min(92dvh, 760px);
  overflow-y: auto;
  padding: 24px 18px 20px;
  gap: 10px;
}
.cf-close {
  position: absolute; z-index: 2; top: 8px; right: 8px;
  width: 44px; height: 44px; padding: 0;
  display: grid; place-items: center;
  border: 0; border-radius: 50%;
  background: transparent; color: var(--text-dim);
  font: 400 30px/1 system-ui, sans-serif;
  cursor: pointer;
}
.cf-close:active { background: rgba(255, 255, 255, .08); transform: scale(.96); }
.cf-new { display: flex; flex-direction: column; align-items: center; gap: 3px; }
.cf-new img { width: 72px; height: 72px; }
.cf-kicker {
  color: var(--text-dim); font-size: 11px; font-weight: 800;
  letter-spacing: .09em; text-transform: uppercase;
}
.cf-body { max-width: 330px; }
.cf-rooms {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 9px;
  width: 100%;
  margin-top: 2px;
}
.cf-slot {
  min-width: 0; min-height: 164px; padding: 8px;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px;
  border: 1px solid var(--card-edge); border-radius: 17px;
  background: rgba(255, 255, 255, .035);
  transition: border-color .2s ease, background-color .2s ease;
}
.cf-slot.is-ready {
  border-color: rgba(255, 204, 76, .75);
  background: rgba(255, 204, 76, .08);
}
.cf-slot-rarity {
  width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: 10px;
}
.cf-slot-art { display: grid; place-items: center; height: 64px; }
.cf-slot-art .box-img { width: 64px; height: 64px; }
.cf-slot-time {
  min-height: 16px; color: var(--text-dim);
  font-size: 11px; font-weight: 700; line-height: 1.2;
}
.cf-slot.is-ready .cf-slot-time { color: var(--gold); }
.cf-open-now {
  width: 100%; min-height: 38px; padding: 5px 8px;
  display: flex; align-items: center; justify-content: center; gap: 8px; text-align: center;
  border: 1px solid rgba(42, 26, 77, .22); border-radius: 11px;
  background: rgba(42, 26, 77, .06); color: #2a1a4d;   /* owner : texte NOIR centré (avant : or sur blanc, illisible) */
  font: inherit; font-size: 11px; font-weight: 800; cursor: pointer;
}
.cf-open-now strong {
  display: inline-flex; align-items: center; gap: 3px;
  color: #2a1a4d; white-space: nowrap;   /* owner : prix en noir aussi (plus d'or illisible) */
}
.cf-slot.is-ready .cf-open-now { border-color: rgba(255, 204, 76, .55); }
.cf-slot-empty, .cf-slot-locked { color: var(--text-dim); gap: 10px; }
.cf-empty-mark {
  width: 52px; height: 52px; display: grid; place-items: center;
  border: 1px dashed var(--card-edge); border-radius: 15px;
  font-size: 28px; opacity: .6;
}
.cf-lock { width: 36px; height: 36px; object-fit: contain; opacity: .65; }
.cf-slot-name { font-size: 12px; font-weight: 800; }
/* owner B9 : le bouton d'achat d'emplacement est RENDU DANS le slot verrouillé (plus en bas) */
.cf-slot-buy { padding: 0; border: 0; background: none; }
.cf-buyslot {
  width: 100%; height: 100%; min-height: 148px;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px;
  border: 1px dashed rgba(255, 204, 76, .5); border-radius: 17px;
  background: rgba(255, 204, 76, .06); color: var(--text);
  font: inherit; cursor: pointer;
}
.cf-buyslot .cf-lock { opacity: .85; }
.cf-buyslot-cost { display: inline-flex; align-items: center; gap: 3px; color: var(--gold); font-weight: 800; font-size: 12px; }
.cf-actions { display: flex; flex-direction: column; gap: 8px; width: 100%; margin-top: 2px; }
@media (max-height: 690px) {
  .cf-panel { padding-top: 18px; gap: 7px; }
  .cf-new img { width: 56px; height: 56px; }
  .cf-slot { min-height: 142px; }
  .cf-slot-art, .cf-slot-art .box-img { width: 52px; height: 52px; }
}
.btn-abandon { color: #ff9a9a; }
/* in-run achievement bubble */
#achPops { position: fixed; top: calc(8px + var(--safe-top)); left: 50%; transform: translateX(-50%); z-index: 300; display: flex; flex-direction: column; gap: 8px; width: min(92vw, 380px); pointer-events: none; }
.ach-pop {
  display: flex; align-items: center; gap: 10px; pointer-events: auto;
  background: rgba(16, 14, 26, 0.95);
  background: color-mix(in srgb, var(--wp-tint, #6a5acd) 14%, rgba(16, 14, 26, 0.95));
  border: 1px solid var(--gold, #ffc83d); border-radius: 14px; padding: 8px 10px;
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.45);
  transform: translateY(-130%); opacity: 0; transition: transform 0.32s cubic-bezier(.2, 1.3, .4, 1), opacity 0.32s ease;
}
.ach-pop.in { transform: translateY(0); opacity: 1; }
.ach-pop.out { transform: translateY(-130%); opacity: 0; }
.ach-pop-ic { font-size: 24px; flex: none; }
.ach-pop-txt { flex: 1; min-width: 0; line-height: 1.2; }
.ach-pop-txt b { font-size: 14px; }
.ach-pop-txt small { display: block; font-size: 12px; color: var(--text-dim); }
.ach-pop-claim { flex: none; }

/* rarity gems are drawn from ONE 3x3 atlas (gems_atlas.webp): a single decoded
   buffer is kindest to iOS memory (large per-tier images were being evicted).
   --gem-pos picks the cell at 300% zoom. DELIBERATELY static — no animation or
   pseudo-element on a gem cell: iOS promotes an animated cell to a compositing
   layer it mishandles (gem vanished / leftover pseudo painted as a black box). */
.gem {
  box-shadow: none; border-radius: 0; background-color: transparent;
  background-image: url('assets/gems/gems_atlas.webp');
  background-size: 375% 375%;   /* 1.25x zoom — between exact-fit (300%, too small) and the old 450% (cropped) (keep in sync with GEM_AX in game.js) */
  background-position: var(--gem-pos, 50% 50%);
  background-repeat: no-repeat;
}
/* ultra-rare (pink / white diamonds): a soft STATIC halo following the cut.
   A non-animated filter is safe — the disappearing was caused by animation. */
.gem.ultra { filter: drop-shadow(0 0 3px var(--c)); }
/* owner B1 : mini-encart « gemmes débloquées à ce rang » sous la carte de déblocage des power-ups (échelle) */
.rt-gem-unlock { display: flex; flex-direction: column; align-items: center; gap: 4px; margin-top: 5px; padding-top: 5px; border-top: 1px solid rgba(255, 255, 255, .12); }   /* owner : gemmes centrées + phrase dessous */
.rt-gem-icons { display: inline-flex; gap: 3px; }
.rt-gem { width: 20px; height: 20px; display: inline-block; background-image: url('assets/gems/gems_atlas.webp'); background-size: 375% 375%; background-repeat: no-repeat; }
.rt-gem-lbl { font-family: 'Nunito', sans-serif; font-weight: 800; font-size: 10.5px; color: rgba(96, 64, 168, .9); text-align: center; line-height: 1.15; }   /* owner : même casse/couleur que .rt-fam-txt span (« désormais dans les écrins ») */

.cell.born { animation: born 0.32s cubic-bezier(.3, 1.5, .5, 1); }
@keyframes born {   /* squash & stretch : impact écrasé large -> rebond étiré -> repos */
  0%   { transform: scale(1.26, 0.72); }
  50%  { transform: scale(0.94, 1.07); }
  100% { transform: scale(1); }
}

/* §3.2 — dépassement : la barre d'objectif EXPLOSE et reste EN FEU (owner T66 : plus FORT + tenu plus longtemps) */
#rushBar.ov-fire { animation: ov-bar-pulse .46s cubic-bezier(.3, 1.7, .5, 1) 2, ov-bar-glow .5s ease-in-out infinite; position: relative; }
/* owner T49e/T66 : EXPLOSION depuis l'EXTRÉMITÉ DROITE de la barre — plus grosse encore */
#rushBar.ov-fire::after { content: ''; position: absolute; right: -10px; top: 50%; width: 78px; height: 78px; transform: translate(0, -50%); border-radius: 50%; background: radial-gradient(circle, rgba(255,236,130,1), rgba(255,130,45,.82) 36%, rgba(255,60,40,0) 72%); animation: ov-edge-burst 1s cubic-bezier(.2, .9, .3, 1) forwards; pointer-events: none; z-index: 3; }
@keyframes ov-edge-burst { 0% { transform: translate(0, -50%) scale(.2); opacity: 1; } 100% { transform: translate(0, -50%) scale(4.4); opacity: 0; } }
#rushBar.ov-fire #rushFill {
  background: linear-gradient(90deg, #fff2a0, #ffc23c, #ff6a2c, #ff3838, #ff6a2c, #ffc23c, #fff2a0) !important;
  background-size: 260% 100% !important;
  animation: ov-flame .34s linear infinite, ov-flame-throb .5s ease-in-out infinite;   /* dégradé qui file + pulsation de brillance -> feu VIVANT le temps que la barre reste enflammée */
}
@keyframes ov-flame { from { background-position: 0 0; } to { background-position: 260% 0; } }
@keyframes ov-flame-throb { 0%, 100% { filter: saturate(1.25) brightness(1.05); } 50% { filter: saturate(1.65) brightness(1.42); } }
@keyframes ov-bar-pulse { 0% { transform: scaleY(1); } 34% { transform: scaleY(1.92); } 100% { transform: scaleY(1); } }
@keyframes ov-bar-glow { 0%, 100% { box-shadow: 0 0 9px 2px rgba(255,150,45,.55); } 50% { box-shadow: 0 0 22px 8px rgba(255,120,35,.95), 0 0 46px 17px rgba(255,90,30,.45); } }

/* « CIBLE PULVÉRISÉE ×N » — jaillit au-dessus du plateau, escaladé par palier */
.board-wrap { position: relative; }
.ov-smash {
  position: absolute; left: 50%; top: 17%; z-index: 45; pointer-events: none;   /* T132 : remonté (était 30%) -> l'indicateur « CIBLE PULVÉRISÉE ×N » passe AU-DESSUS du calcul de score, juste sous la barre de progression */
  display: flex; flex-direction: column; align-items: center; gap: 1px; white-space: nowrap;
  font-family: 'Lilita One', sans-serif; text-align: center;
  transform: translate(-50%, -50%) scale(.2); opacity: 0;
}
.ov-smash.go { animation: ov-smash-life 2.6s cubic-bezier(.2, 1.4, .4, 1) forwards; }   /* owner T57 : tenu bien plus longtemps -> le joueur a le temps de voir « CIBLE PULVÉRISÉE » (le pop-in reste vif, seul le maintien s'allonge) */
@keyframes ov-smash-life {
  0%   { transform: translate(-50%, -50%) scale(.2);  opacity: 0; }
  10%  { transform: translate(-50%, -50%) scale(1.14); opacity: 1; }
  16%  { transform: translate(-50%, -50%) scale(1);    opacity: 1; }
  84%  { transform: translate(-50%, -52%) scale(1);    opacity: 1; }
  100% { transform: translate(-50%, -155%) scale(1.03); opacity: 0; }
}
.ov-smash .ovs-lab  { font-size: 20px; color: #fff;    -webkit-text-stroke: 3.6px var(--dp-ink); paint-order: stroke fill; letter-spacing: .5px; }
.ov-smash .ovs-mult { font-size: 54px; color: #ffd23b; -webkit-text-stroke: 5px var(--dp-ink);   paint-order: stroke fill; line-height: .92; }
.ov-smash.ov-t2 .ovs-mult { font-size: 64px; }
.ov-smash.ov-t3 .ovs-mult { font-size: 76px; color: #ff8a3c; }
.ov-smash.ov-t4 .ovs-mult { font-size: 88px; color: #ff5252; }
.ov-smash.ov-t5 .ovs-mult { font-size: 104px; color: #ff3ba7; }
@media (prefers-reduced-motion: reduce) { #rushBar.ov-fire, #rushBar.ov-fire #rushFill, .ov-smash.go { animation: none; } .ov-smash.go { opacity: 1; transform: translate(-50%, -50%) scale(1); } }
.cell.ghost {
  border-radius: calc(var(--cell) * 0.18);
  background-color: var(--c);
  opacity: 0.35;
  box-shadow: none;
}
.cell.ghost.gem { background-color: transparent; border-radius: 0; }   /* the gem art previews at the ghost's 0.35 opacity */
/* line about to pop: the gems glow from within */
.cell.flash { animation: gem-flash 0.45s ease-in-out infinite alternate; }
@keyframes gem-flash {
  from { filter: brightness(1.05); }
  to { filter: brightness(1.9) saturate(1.35) drop-shadow(0 0 6px rgba(255, 255, 255, 0.7)); }
}

#fx { position: absolute; inset: -40px; pointer-events: none; z-index: 5; }
#phantoms { position: absolute; inset: 0; pointer-events: none; z-index: 4; overflow: visible; }
/* the gem left behind on a cleared cell: a short, bright shatter flash
   (canvas shards + sparks fly out underneath it) */
.phantom {
  position: absolute;
  width: var(--cell); height: var(--cell);
  border-radius: calc(var(--cell) * 0.18);
  animation: gem-shatter 0.3s ease-out forwards;
}
.phantom.gem.orb { clip-path: circle(50% at 50% 50%); border-radius: 0; }
.phantom.gem.squ { clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%); border-radius: 0; }
.phantom.gem.diamond { clip-path: var(--diamond-clip); border-radius: 0; }
/* Exchangers (swap family): the first pick's highlight while the player chooses the second target */
.swap-mark {
  position: absolute; box-sizing: border-box; pointer-events: none;
  border: 3px solid var(--gold, #ffd54a);
  border-radius: calc(var(--cell) * 0.18);
  box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.28), 0 0 14px 3px rgba(255, 213, 74, 0.7);
  animation: swap-pulse 0.8s ease-in-out infinite;
}
.swap-mark.row { border-radius: 8px; }
.swap-mark.col { border-radius: 8px; }   /* Transposeur : colonne surlignée (vertical) */
/* Transposeur : flèche de direction au bout « fin » de la ligne (triangle vers la droite, tourné par le JS selon le sens du swipe) */
.swap-arrow {
  position: absolute; width: 0; height: 0; pointer-events: none; z-index: 6;
  border-top: 9px solid transparent; border-bottom: 9px solid transparent;
  border-left: 15px solid var(--gold, #ffd54a);
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.45));
  animation: swap-arrow-pulse 0.8s ease-in-out infinite;   /* opacité seule -> ne casse pas la rotation inline */
}
@keyframes swap-arrow-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } }
@keyframes swap-pulse {
  0%, 100% { transform: scale(1); opacity: 0.95; }
  50% { transform: scale(1.05); opacity: 0.65; }
}
/* PHASE 4 — piece-unlock reward: mini silhouettes of the newly unlocked shapes (inside #rrArt) */
.pu-shapes { display: flex; flex-wrap: wrap; gap: 10px 12px; justify-content: center; align-items: center; max-width: 250px; }
.pu-shape { display: grid; gap: 3px; }
.pu-shape i { width: 13px; height: 13px; border-radius: 3px; background: rgba(0, 0, 0, 0.07); }
.pu-shape i.on { background: var(--rc, #ffd54a); box-shadow: inset 0 -2px 0 rgba(0, 0, 0, 0.15), 0 1px 3px rgba(0, 0, 0, 0.22); }
/* owner : écran d'obtention de pièces/joyaux -> image PLURIELLE (coins/jewels.webp) + le nombre en PASTILLE sur l'image */
.rr-cur-art { position: relative; display: inline-block; }
.rr-cur-img { width: 118px; height: 118px; object-fit: contain; display: block; filter: drop-shadow(0 6px 10px rgba(0, 0, 0, 0.3)); }
.rr-cur-badge {
  position: absolute; right: -8px; bottom: 4px;
  background: linear-gradient(180deg, var(--coral, #ff5e7a), var(--coral-deep, #e23e5c));
  color: #fff; font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 21px; line-height: 1;
  padding: 4px 13px 5px; border-radius: 999px; border: 2.5px solid #fff;
  box-shadow: 0 3px 0 rgba(0, 0, 0, 0.22), 0 5px 10px rgba(0, 0, 0, 0.25); white-space: nowrap;
}
.bonus-pop {
  position: absolute; z-index: 7;
  transform: translate(-50%, -50%);
  font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 15px; color: var(--gold);
  text-shadow: 0 0 10px rgba(255, 200, 61, 0.9), 0 2px 0 rgba(0, 0, 0, 0.5);
  animation: bonus-pop 0.65s ease-out forwards;
  pointer-events: none;
}
@keyframes bonus-pop {
  0% { opacity: 0; margin-top: 4px; scale: 0.5; }
  25% { opacity: 1; scale: 1.2; }
  100% { opacity: 0; margin-top: -26px; scale: 1; }
}
@keyframes gem-shatter {
  0% { transform: scale(1); opacity: 1; filter: brightness(2.4) saturate(1.4); }
  55% { transform: scale(1.28); opacity: 0.75; filter: brightness(3); }
  100% { transform: scale(1.5); opacity: 0; filter: brightness(3.4); }
}
.score-pop {
  position: absolute; z-index: 6;
  font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 22px; color: #fff;
  text-shadow: 0 0 12px var(--gold), 0 2px 0 rgba(0,0,0,0.4);
  animation: score-pop 0.8s ease-out forwards;
  pointer-events: none; white-space: nowrap;
  transform: translate(-50%, 0);
}
@keyframes score-pop {
  0% { opacity: 0; translate: 0 8px; scale: 0.6; }
  20% { opacity: 1; scale: 1.15; }
  100% { opacity: 0; translate: 0 -44px; scale: 1; }
}

/* tray — each slot is a full-size touch target, not just the mini piece */
#tray {
  display: flex; gap: 8px;
  justify-content: space-between;
  padding: 6px 0 2px;
  touch-action: none;
  min-height: calc(var(--mcell) * 5 + 20px);
}
.tray-slot {
  flex: 1; display: flex; align-items: center; justify-content: center;
  border-radius: 16px;
  min-height: calc(var(--mcell) * 5 + 16px);
  background: rgba(12, 11, 20, 0.55);   /* fallback for no color-mix */
  background: color-mix(in srgb, var(--wp-tint, #6a5acd) 14%, rgba(12, 11, 20, 0.55));
  touch-action: none;
  cursor: grab;
}
.tray-piece { position: relative; transition: opacity 0.15s; pointer-events: none; }
.tray-piece.used { visibility: hidden; }
/* easy only: faint ghost of the piece arriving on the next deal — kept very
   low-contrast so it never reads like a real (possibly dark) piece */
.tray-piece.shadow { opacity: 0.22; filter: grayscale(0.9) brightness(0.78); }
/* flatten material/sprite textures on COMMON cells, but keep the gem orb on gem cells (and give them a
   coloured socket) so every cell of the upcoming piece is visible — a gem block used to fade to the dark
   socket and the ghost looked smaller than the real piece. */
.tray-piece.shadow .pcell:not(.gem) { background-image: none !important; }
.tray-piece.shadow .pcell.gem { background-color: var(--c); }
.tray-piece.shadow .pcell::after { animation: none; }
.pcell { position: absolute; }

#dragPiece {
  position: fixed; left: 0; top: 0; z-index: 50;
  pointer-events: none; display: none;
  filter: drop-shadow(0 14px 18px rgba(0, 0, 0, 0.5));
  will-change: transform;   /* keep the drag piece a stable compositing layer so an idle hold never demotes + re-rasterizes it (which dropped the sprite art for ~1s) */
}

.hint {
  text-align: center; color: var(--text-dim); font-size: 12.5px;
  padding: 4px 0; transition: opacity 0.4s, height 0.4s, padding 0.4s, margin 0.4s;
  overflow: hidden; white-space: pre-line; line-height: 1.5;
}
.hint.gone { opacity: 0; height: 0; padding: 0; margin: 0; }   /* collapse so the board reclaims the space */

/* combo burst */
#comboBurst {
  position: fixed; left: 50%; top: 34%; z-index: 60;
  transform: translate(-50%, -50%);
  font-family: 'Lilita One', 'Trebuchet MS', sans-serif;
  font-size: 44px;
  pointer-events: none;
  color: var(--mint);
  text-shadow: 0 0 24px var(--mint), 0 4px 0 rgba(0, 0, 0, 0.4);
  opacity: 0;
}
#comboBurst.go { animation: combo-burst 0.9s ease-out; }
@keyframes combo-burst {
  0% { opacity: 0; transform: translate(-50%, -50%) scale(0.4) rotate(-6deg); }
  18% { opacity: 1; transform: translate(-50%, -50%) scale(1.25) rotate(2deg); }
  32% { transform: translate(-50%, -50%) scale(1) rotate(0); }
  75% { opacity: 1; }
  100% { opacity: 0; transform: translate(-50%, -56%) scale(1.05); }
}

/* ---------- score milestones ---------- */
/* tier 1 — every 100: quick golden pop above the board */
#milestonePop {
  position: fixed; left: 50%; top: 22%; z-index: 70;
  transform: translate(-50%, -50%);
  font-family: 'Lilita One', 'Trebuchet MS', sans-serif;
  font-size: 30px; color: var(--gold);
  text-shadow: 0 0 18px rgba(255, 200, 61, 0.8), 0 3px 0 rgba(0, 0, 0, 0.4);
  pointer-events: none; opacity: 0;
}
#milestonePop.go { animation: milestone-pop 0.9s ease-out; }
@keyframes milestone-pop {
  0% { opacity: 0; transform: translate(-50%, -30%) scale(0.5); }
  20% { opacity: 1; transform: translate(-50%, -50%) scale(1.2); }
  40% { transform: translate(-50%, -50%) scale(1); }
  80% { opacity: 1; }
  100% { opacity: 0; transform: translate(-50%, -90%) scale(1); }
}

/* tier 2 — every 1,000: banner sweeping across the screen */
#milestoneBanner {
  position: fixed; left: 0; right: 0; top: 30%; z-index: 71;
  display: flex; align-items: center; justify-content: center;
  height: 76px;
  font-family: 'Lilita One', 'Trebuchet MS', sans-serif;
  font-size: 46px; color: #fff;
  text-shadow: 0 0 28px var(--gold), 0 4px 0 rgba(0, 0, 0, 0.45);
  background: linear-gradient(90deg, transparent, rgba(255, 200, 61, 0.16) 18%, rgba(255, 200, 61, 0.3) 50%, rgba(255, 200, 61, 0.16) 82%, transparent);
  pointer-events: none; opacity: 0;
}
#milestoneBanner.go { animation: milestone-banner 1.4s ease-out; }
@keyframes milestone-banner {
  0% { opacity: 0; transform: translateX(-40%) scaleY(0.4); }
  18% { opacity: 1; transform: translateX(0) scaleY(1); }
  70% { opacity: 1; transform: translateX(0); }
  100% { opacity: 0; transform: translateX(12%) scaleY(0.6); }
}

/* tier 3 — every 10,000: full takeover */
#celebration { position: fixed; inset: 0; z-index: 320; pointer-events: none; display: none; }
#celebration.go { display: block; }
#celebration .cel-flash {
  position: absolute; inset: 0;
  background: radial-gradient(circle at 50% 42%, rgba(255, 255, 255, 0.85), rgba(255, 200, 61, 0.3) 45%, transparent 75%);
  animation: cel-flash 1s ease-out forwards;
}
@keyframes cel-flash { 0% { opacity: 1; } 100% { opacity: 0; } }
#celebration .cel-text {
  position: absolute; left: 50%; top: 40%;
  transform: translate(-50%, -50%);
  font-family: 'Lilita One', 'Trebuchet MS', sans-serif;
  font-size: clamp(58px, 19vw, 92px);
  background: linear-gradient(90deg, var(--coral), var(--amber), #ffe14d, var(--mint), var(--sky), #b07aff);
  -webkit-background-clip: text; background-clip: text;
  color: transparent;
  filter: drop-shadow(0 0 26px rgba(255, 200, 61, 0.65)) drop-shadow(0 5px 0 rgba(0, 0, 0, 0.4));
  animation: cel-text 2.5s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}
@keyframes cel-text {
  0% { opacity: 0; transform: translate(-50%, -50%) scale(0.25) rotate(-7deg); }
  16% { opacity: 1; transform: translate(-50%, -50%) scale(1.18) rotate(2deg); }
  30% { transform: translate(-50%, -50%) scale(1) rotate(0); }
  78% { opacity: 1; transform: translate(-50%, -50%) scale(1.02); }
  100% { opacity: 0; transform: translate(-50%, -62%) scale(1.05); }
}

/* confetti rain (shared by tiers) */
#confettiLayer { position: fixed; inset: 0; z-index: 310; pointer-events: none; overflow: hidden; }
#confettiLayer i {
  position: absolute; top: -4vh; left: var(--x);
  width: 9px; height: 14px; border-radius: 2px;
  background: var(--c);
  transform: rotate(var(--r));
  animation: confetti-fall var(--d) cubic-bezier(0.2, 0.4, 0.6, 1) var(--delay) forwards;
  opacity: 0;
}
@keyframes confetti-fall {
  0% { opacity: 1; transform: translate(0, 0) rotate(var(--r)); }
  100% { opacity: 0.85; transform: translate(var(--sway), 110vh) rotate(calc(var(--r) + 540deg)); }
}

/* ---------- COLLECTION ---------- */
#view-collection { gap: 12px; padding-bottom: 30px; }
#view-collection .seg-row { margin: 0 auto; width: min(340px, 100%); }
.coll-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.coll-grid.one { grid-template-columns: 1fr; }

/* ---- BLOCK MIXER (Styles > Blocks): build a custom mix of up to 9 blocks that pieces are drawn from ---- */
.mix-bar {
  position: sticky; top: 0; z-index: 4;
  background: linear-gradient(180deg, rgba(22, 17, 32, 0.97) 70%, rgba(22, 17, 32, 0.78));
  -webkit-backdrop-filter: blur(7px); backdrop-filter: blur(7px);
  border-radius: 18px; padding: 11px 13px 13px; margin-bottom: 16px;
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.4); border: 1px solid rgba(255, 255, 255, 0.06);
}
.mix-head { font-size: 12px; letter-spacing: 1.2px; opacity: 0.72; margin-bottom: 9px; font-weight: 700; }
.mix-head b { color: #ffce54; margin-left: 5px; }
.mix-slots { display: grid; grid-template-columns: repeat(9, 1fr); gap: 6px; }
.mix-slot.empty { aspect-ratio: 1; border-radius: 22%; border: 1.5px dashed rgba(255, 255, 255, 0.15); background: rgba(255, 255, 255, 0.025); }
.block-chip {
  position: relative; width: 100%; aspect-ratio: 1; padding: 0; border: 0; background: none; cursor: pointer;
  line-height: 0; -webkit-tap-highlight-color: transparent; transition: transform 0.08s ease;
}
.block-chip:active { transform: scale(0.88); }
.bc-cell { --cell: 42px; display: block; width: 100%; height: 100%; }
.mix-slots .bc-cell { box-shadow: 0 0 0 2px #ffce54, 0 2px 7px rgba(0, 0, 0, 0.45); }
.block-sets { display: flex; flex-direction: column; gap: 17px; }
.block-set-head { font-size: 12px; opacity: 0.62; margin-bottom: 8px; letter-spacing: 0.5px; font-weight: 600; }
.block-row { display: grid; grid-template-columns: repeat(6, 1fr); gap: 8px; }
.block-chip.in-mix .bc-cell { box-shadow: 0 0 0 2px #ffce54; }
.block-chip.in-mix::after {
  content: '✓'; position: absolute; right: -3px; top: -3px;
  width: 17px; height: 17px; border-radius: 50%; background: #ffce54; color: #2a1f0a;
  font-size: 11px; font-weight: 900; line-height: 17px; text-align: center;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
}
@media (min-width: 620px) { .block-row { grid-template-columns: repeat(12, 1fr); } .bc-cell { --cell: 38px; } }
/* locked block: dimmed with a padlock; tapping opens the single-block buy popup */
.block-chip.locked .bc-cell { filter: grayscale(0.78) brightness(0.42); }
.block-chip.locked::after {
  content: ''; position: absolute; inset: 0; margin: auto; width: 46%; height: 46%;
  background: url(assets/ui/padlock.webp) center/contain no-repeat;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.65)); pointer-events: none;
}
/* single-block buy popup */
/* owner #97 : aperçu de bloc (appui long) REFONDU -> carte pastel claire (DA du jeu) + aperçu 2x + socle teinté rareté */
.block-buy-card {
  position: relative; width: min(322px, 88vw);
  background: linear-gradient(180deg, #fffdfb, #f3ecfb); border-radius: 26px; padding: 30px 24px 22px;
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  box-shadow: 0 20px 55px rgba(50, 25, 90, 0.4); border: 2.5px solid #fff;
  color: var(--dp-ink, #2a1a4d);
}
.bb-x {
  position: absolute; right: 13px; top: 13px; width: 32px; height: 32px; border: 0; border-radius: 50%;
  background: rgba(90, 60, 140, 0.12); color: var(--dp-ink, #2a1a4d); font-size: 14px; line-height: 32px; cursor: pointer;
}
.bb-x img { width: 13px; height: 13px; object-fit: contain; opacity: 0.55; vertical-align: middle; }
/* le bloc posé sur un socle arrondi (halo clair + bord de la couleur de rareté) */
.bb-prev-wrap {
  display: grid; place-items: center; padding: 18px; border-radius: 28px; margin-bottom: 4px;
  background: radial-gradient(circle at 50% 38%, #fffefe, #ece4f8 82%);
  border: 3px solid var(--rar-c, #d9cef0);
  box-shadow: inset 0 2px 0 rgba(255, 255, 255, 0.9), 0 9px 22px rgba(90, 60, 140, 0.2);
}
.bb-prev { --cell: 176px; width: 176px; height: 176px; margin: 0; filter: drop-shadow(0 6px 10px rgba(40, 20, 70, 0.28)); }
.bb-name { font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-weight: 400; font-size: 25px; color: var(--dp-ink, #2a1a4d); margin-top: 4px; }
.bb-sub { font-size: 13px; color: #7a6ba0; letter-spacing: 0.3px; }
.bb-rar { font-weight: 800; color: var(--rar-c, #7a6ba0); }
.bb-desc { font-size: 13px; color: #6a5a90; text-align: center; line-height: 1.45; margin-top: 3px; max-width: 250px; }
.bb-buy { margin-top: 14px; min-width: 170px; }
/* owner : bouton « Retirer du mix » (btn-ghost2) était blanc-sur-blanc sur la carte claire */
.block-buy-card .btn-ghost2 { color: var(--dp-ink) !important; border-color: rgba(42, 26, 77, 0.25) !important; }
.bb-set { background: none; border: 0; color: #9aa6ff; font-size: 13px; cursor: pointer; padding: 5px 4px 2px; }
/* category filter pill (blocks tab): a touch smaller so 4-5 categories fit */
.coll-filter { width: min(380px, 100%); margin: 2px auto 12px; }
.coll-filter .seg { font-size: 12px; padding: 7px 4px; letter-spacing: 0.3px; }
.coll-soon { display: flex; flex-direction: column; align-items: center; gap: 8px; text-align: center; padding: 26px 18px; }
.coll-soon-ic {
  font-size: 38px; color: var(--rar-epic);
  filter: drop-shadow(0 0 14px rgba(176, 122, 255, 0.5));
}
.view-title {
  font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 22px; letter-spacing: 2px;
  text-align: center; padding-top: 4px;
}

.featured-card { position: relative; padding-top: 22px; }
.bonus-card { margin-top: 18px; }
.featured-ribbon {
  position: absolute; top: -10px; left: 50%; transform: translateX(-50%) rotate(-2deg);
  background: linear-gradient(180deg, var(--gold), #e6a216);
  color: #4a3200;
  font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 12px; letter-spacing: 1.5px;
  padding: 5px 14px; border-radius: 999px;
  box-shadow: 0 3px 0 #8a5e00;
  white-space: nowrap;
}
/* coral variant for the Bonus shop ribbon (distinct from the gold Styles ribbon) */
.featured-ribbon.ribbon-coral {
  background: linear-gradient(180deg, var(--coral), #d8384f);
  color: #3a0610; box-shadow: 0 3px 0 #8a1f30;
}
.featured-body { display: flex; flex-direction: column; gap: 16px; }
.shelf-section { display: flex; flex-direction: column; gap: 9px; }
.shelf-head { font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 12px; letter-spacing: 1.5px; text-transform: uppercase; color: var(--text-dim); }
.shelf-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.featured-body .theme-card { align-items: center; text-align: center; padding: 12px 8px; }
.featured-body .theme-card .btn { width: 100%; white-space: nowrap; }
.featured-body .theme-name { font-size: 13px; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.shelf-empty { text-align: center; padding: 16px 14px; color: var(--text-dim); font-size: 13px; line-height: 1.4; }
/* an owned style stays in the rotation but shows an "Owned" badge instead of a price */
.featured-body .theme-card.owned { opacity: 0.8; }
.shop-owned-tag {
  display: inline-flex; align-items: center; justify-content: center;
  width: 100%; height: 30px; border-radius: 999px;
  font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 12px; letter-spacing: 0.5px;
  color: var(--mint);
  background: color-mix(in srgb, var(--mint) 14%, transparent);
  border: 1px solid color-mix(in srgb, var(--mint) 38%, transparent);
}
.featured-info { flex: 1; min-width: 0; }
.featured-name { font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 18px; }
.rotation-note { margin-top: 10px; }
.rotation-note b { color: var(--amber); }

/* #themeGrid behaves like #wallpaperGrid / #musicGrid: a plain block holding section heads + nested
   prev-grids (the .coll-grid{display:block} rule below). The old `display:grid; 1fr 1fr` here (an ID,
   so it beat that class rule) confined the block prev-grids to one column -> a permanent right gap. */
.theme-card { display: flex; flex-direction: column; gap: 8px; align-items: flex-start; transition: transform 0.16s ease, background 0.16s ease, outline-color 0.16s ease; }
/* equipped = unmistakable: a thick mint ring + a mint-tinted lift, so the active style
   clearly stands out from the rarity-coloured frames every card now has */
.theme-card.equipped { outline: 3px solid var(--mint); outline-offset: -3px; background: color-mix(in srgb, var(--mint) 16%, var(--card)); transform: translateY(-3px); }
/* rarity frame: the card border tints to the item's rarity (on top of the rar tag) */
.theme-card.rarity-common    { border-color: rgba(53, 195, 104, 0.45); }
.theme-card.rarity-rare      { border-color: var(--rar-rare);      box-shadow: inset 0 0 0 1px rgba(77, 196, 255, 0.35),  0 6px 18px rgba(77, 196, 255, 0.10); }
.theme-card.rarity-epic      { border-color: var(--rar-epic);      box-shadow: inset 0 0 0 1px rgba(176, 122, 255, 0.40), 0 6px 18px rgba(176, 122, 255, 0.12); }
.theme-card.rarity-legendary { border-color: var(--rar-legendary); box-shadow: inset 0 0 0 1px rgba(255, 200, 61, 0.40),  0 6px 18px rgba(255, 200, 61, 0.12); }
.theme-card.rarity-mythic    { border-color: var(--rar-mythic);    box-shadow: inset 0 0 0 1px rgba(255, 110, 199, 0.45), 0 6px 18px rgba(255, 110, 199, 0.14); }
.theme-name { font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 15px; }
.theme-state { font-size: 11px; color: var(--text-dim); }

.swatch-row { display: flex; gap: 4px; }
/* rounded squares so the preview matches the in-game block shape */
.swatch-row i {
  width: 18px; height: 18px;
  border-radius: 22%;
  background-color: var(--c);
  background-image: linear-gradient(160deg, rgba(255, 255, 255, 0.45), rgba(0, 0, 0, 0.15) 80%);
  background-size: cover; background-position: center;
}
.swatch-row i.spr { background-size: 300% 200%; background-repeat: no-repeat; background-color: var(--cell-empty); }
.swatch-row.locked i { filter: grayscale(0.85) brightness(0.55); }

.rar {
  font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 11px; letter-spacing: 1.5px;
  padding: 3px 9px; border-radius: 999px;
}
.rar.common { color: var(--rar-common); background: rgba(53, 195, 104, 0.13); }
.rar.rare { color: var(--rar-rare); background: rgba(77, 196, 255, 0.13); }
.rar.epic { color: var(--rar-epic); background: rgba(176, 122, 255, 0.13); }
.rar.legendary { color: var(--rar-legendary); background: rgba(255, 200, 61, 0.13); }
.rar.mythic { color: var(--rar-mythic); background: rgba(255, 110, 199, 0.14); }

/* ---------- LEADERBOARD ---------- */
#view-board { gap: 12px; padding-bottom: 30px; }
#view-board .seg-row { margin: 0 auto; width: min(340px, 100%); }
.profile-card { display: flex; flex-direction: column; gap: 12px; }
.profile-row { display: flex; align-items: center; gap: 10px; }
.profile-row .hud-label { flex-shrink: 0; }
.profile-name {
  font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 19px;
  flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* owner T90 : boutons SSO empilés, fond BLANC + logo de marque (Google/Apple/Facebook) */
.signin-row { display: flex; flex-direction: column; gap: 9px; }
/* owner G3 : Facebook login RÉACTIVÉ pour le test (l'owner voulait tester la photo d'avatar Facebook).
   ⚠ AVANT LE PUBLIC : Facebook App Review requise (email+public_profile) sinon les joueurs non-testeurs auront une erreur.
   Pour re-désactiver : décommenter la ligne ci-dessous. */
/* .btn-sso[data-provider="facebook"] { display: none; } */
.btn-sso {
  width: 100%; display: flex; align-items: center; justify-content: center; gap: 10px;
  background: #fff; border: 1.5px solid rgba(42,26,77,.16);
  font-family: 'Nunito', 'Trebuchet MS', sans-serif; font-weight: 800; font-size: 14px; letter-spacing: .2px;
  padding: 11px 12px; border-radius: 13px; color: #2a1a4d;
  box-shadow: 0 2px 7px rgba(40,20,70,.12);
}
.btn-sso:active { transform: translateY(1px); box-shadow: 0 1px 3px rgba(40,20,70,.16); }
.btn-sso .sso-ic { flex: 0 0 auto; width: 20px; height: 20px; display: inline-flex; }
.btn-sso .sso-ic svg { width: 100%; height: 100%; display: block; }
.btn-sso .sso-lb { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

#boardList { list-style: none; display: flex; flex-direction: column; gap: 8px; }
.board-row {
  display: flex; align-items: center; gap: 12px;
  background: var(--card); border: 1px solid var(--card-edge);
  border-radius: 14px; padding: 11px 14px;
}
.board-row.me { outline: 2px solid var(--mint); outline-offset: -1px; }
.board-row.tap { cursor: pointer; }
.board-row.tap:active { transform: scale(0.985); }
.board-rank {
  font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 16px;
  width: 28px; height: 28px; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.07); color: var(--text-dim);
}
.board-rank.rank-1 { background: linear-gradient(180deg, #ffe066, #e6a216); color: #4a3200; }   /* gold */
.board-rank.rank-2 { background: linear-gradient(180deg, #f4f6fb, #b9c0cc); color: #3a3f48; }   /* silver */
.board-rank.rank-3 { background: linear-gradient(180deg, #e3a063, #b06a2c); color: #3a210d; }   /* bronze */
/* owner : le RANG du joueur (badge dérivé du niveau) avec le numéro de position superposé */
.board-rank.has-badge { background: none !important; width: 34px; height: 34px; position: relative; }
.board-rank-badge { width: 34px; height: 34px; object-fit: contain; filter: drop-shadow(0 1px 2px rgba(0,0,0,0.35)); }
.board-rank-num { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 12px; color: #fff; text-shadow: 0 1px 2px rgba(0,0,0,0.85), 0 0 3px rgba(0,0,0,0.6); }
.board-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 900; }
.board-round {   /* Survie tab: the max round reached, beside the score */
  flex: none; font-size: 12px; font-weight: 800; color: var(--text-dim); white-space: nowrap;
  background: rgba(255, 255, 255, 0.07); border-radius: 999px; padding: 3px 10px; letter-spacing: 0.3px;
}
.board-score { font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 18px; color: var(--gold); -webkit-text-stroke: 2px #000; paint-order: stroke fill; text-shadow: 0 1px 1px rgba(0,0,0,.55); }   /* owner T93 : contour noir -> score lisible sur toutes les lignes (nôtre + autres) */
.board-ava { flex: none; }
#boardTabs { width: min(340px, 100%); margin: 0 auto 4px; }
.board-ava .avatar-pic { box-shadow: inset 0 0 0 1.5px rgba(255, 255, 255, 0.16); }

/* ---- profile + avatars ---- */
.chip-icon { padding: 7px 9px; }
.topbtn-ic { width: 22px; height: 22px; object-fit: contain; display: block; }
.topbar-profile { margin-left: auto; position: relative; padding: 4px; }
.topbar-profile .nav-dot { top: 0; right: 1px; }
.topbar-profile .avatar-pic { width: 30px !important; height: 30px !important; box-shadow: inset 0 0 0 1.5px rgba(255, 255, 255, 0.18); }
/* the persistent menu rendered inside the profile page (same look as #navBar) */
.profile-nav { display: flex; justify-content: space-around; align-items: flex-end; gap: 4px; width: 100%; max-width: 520px; margin: 10px auto 2px; padding-top: 12px; border-top: 1px solid rgba(255, 255, 255, 0.08); }
/* avatar art = the real webp as a CSS background (a 404 simply doesn't paint) over a gradient+emoji placeholder */
.avatar-pic { position: relative; display: inline-flex; border-radius: 50%; overflow: hidden; flex: none; vertical-align: middle;
  background: linear-gradient(135deg, var(--a1, #6c7bdc), var(--a2, #a6b0f5)); }
.avatar-emo { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; line-height: 1; }
.avatar-img { position: absolute; inset: 0; background-size: cover; background-position: center; }
/* owner : photo de compte peinte via <img> (referrerpolicy no-referrer) — remplit le cercle, masquée si le chargement échoue (le placeholder dessous reste) */
img.avatar-photo { width: 100%; height: 100%; object-fit: cover; border: 0; }
img.avatar-photo.load-fail { visibility: hidden; }
/* avatar FRAMES: a gradient reward ring shown through the wrapper's padding (no mask -> iOS-safe). The
   wrapper hugs the avatar-pic; the 3px padding reveals the gradient as a ring. */
.avatar-frame { display: inline-flex; align-items: center; justify-content: center; border-radius: 50%; padding: 3px; vertical-align: middle; flex: none; }
.frame-bronze  { background: linear-gradient(135deg, #e8b07a, #b87333 45%, #7a4a1e 70%, #cd8c4e); box-shadow: 0 0 8px rgba(205, 127, 50, 0.5); }
.frame-silver  { background: linear-gradient(135deg, #f2f4f8, #c4cad4 45%, #8a909c 70%, #e0e4ea); box-shadow: 0 0 8px rgba(207, 212, 220, 0.55); }
.frame-gold    { background: linear-gradient(135deg, #ffe9a8, #ffd34e 45%, #c9912a 70%, #ffe07a); box-shadow: 0 0 11px rgba(255, 211, 78, 0.6); }
.frame-init     { background: linear-gradient(135deg, #d6f4ff, #6fd6ff 45%, #3fa8d8 70%, #bdeeff); box-shadow: 0 0 8px rgba(111, 214, 255, 0.5); }
.frame-platinum { background: linear-gradient(135deg, #d6fffb, #37c6bf 45%, #1f9a94 70%, #a8f1ec); box-shadow: 0 0 10px rgba(55, 198, 191, 0.55); }
.frame-diamond  { background: linear-gradient(135deg, #e2e8ff, #7e92f6 45%, #4f63d8 70%, #c6cfff); box-shadow: 0 0 12px rgba(126, 146, 246, 0.6); }
.frame-challenger { background: linear-gradient(135deg, #efe4ff, #c9a9ff 45%, #8a5cf0 70%, #ddc9ff); box-shadow: 0 0 12px rgba(154, 107, 255, 0.6); }
/* Champion + Maître : anneau MULTICOLORE qui TOURNE. Le conic est sur un ::before qu'on fait pivoter
   (iOS-safe : on n'anime qu'un transform, pas le gradient). Le pic passe au-dessus (z-index). */
.frame-rainbow, .frame-champion, .frame-master { position: relative; background: none; }
.frame-rainbow .avatar-pic, .frame-champion .avatar-pic, .frame-master .avatar-pic { position: relative; z-index: 1; }
.frame-rainbow::before, .frame-champion::before, .frame-master::before {
  content: ''; position: absolute; inset: 0; border-radius: 50%; z-index: 0;
  animation: frameSpin 3.4s linear infinite;
}
.frame-rainbow::before, .frame-champion::before { background: conic-gradient(from 0deg, #ff5e7e, #ffb24e, #ffe24e, #5fe08a, #4ec8ff, #9a6bff, #ff5e7e); }
.frame-rainbow, .frame-champion { box-shadow: 0 0 13px rgba(150, 120, 255, 0.6); }
/* Maître = sommet : palette or+joyaux plus riche, halo plus fort, rotation inversée + plus rapide pour se distinguer du Champion. */
.frame-master::before { background: conic-gradient(from 0deg, #fff3c4, #ffd34e, #ff9a3e, #ff5e7e, #c56bff, #4ec8ff, #7cffcb, #fff3c4); animation-direction: reverse; animation-duration: 2.8s; }
.frame-master { box-shadow: 0 0 16px rgba(255, 200, 90, 0.7); }
@keyframes frameSpin { to { transform: rotate(1turn); } }
/* un cadre équipé REMPLACE le contour blanc du pic (pas de double anneau) -> owner */
.avatar-frame .avatar-pic { border: none !important; }
#topbar #btnProfile .avatar-frame .avatar-pic { border: none !important; box-shadow: 0 0 0 1px rgba(40, 20, 70, 0.25) !important; }
.frames-head { font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 13px; letter-spacing: 1.5px; text-transform: uppercase; color: var(--text-dim); margin: 16px 0 0; text-align: center; }
.frame-grid .avatar-cell.locked .avatar-frame { filter: grayscale(0.9) brightness(0.6); }
/* an avatar reward chip in a goal row / pop (preview + "themed avatar") */
.ach-av-rw { display: inline-flex; align-items: center; gap: 4px; vertical-align: middle; font-weight: 700; }
.ach-av-rw .avatar-pic { width: 20px !important; height: 20px !important; }

.profile-panel { text-align: center; max-height: 88vh; overflow-y: auto; }
/* PROFILE is a FULL SCREEN, not a floating popup (ID specificity beats the .panel popup rules) */
#ovProfile { padding: 0; align-items: stretch; }
#ovProfile .profile-panel {
  width: 100%; max-width: 540px; margin: 0 auto; height: 100%; max-height: 100%;
  border: 0; border-radius: 0; box-shadow: none; background: var(--ink, #15131c);
  justify-content: flex-start; gap: 16px; overflow: hidden;   /* only the stats area scrolls; the nav stays pinned */
  padding: calc(env(safe-area-inset-top, 0px) + 24px) 22px calc(env(safe-area-inset-bottom, 0px) + 14px);
  animation: prof-up 0.26s ease;
}
#ovProfile .profile-stats { width: 100%; flex: 1; overflow-y: auto; min-height: 0; }
#ovProfile .profile-nav { flex: none; position: sticky; bottom: 0; background: var(--ink, #15131c); margin-top: 0; }
#ovProfile .btn-ghost { margin-top: auto; }
@keyframes prof-up { from { transform: translateY(26px); opacity: 0; } to { transform: none; opacity: 1; } }
.profile-hero { display: flex; align-items: center; gap: 14px; justify-content: center; margin: 4px 0 14px; }
.profile-avatar-big .avatar-pic { box-shadow: 0 6px 18px rgba(0, 0, 0, 0.4), inset 0 0 0 3px rgba(255, 255, 255, 0.2); }
.profile-id { display: flex; flex-direction: column; align-items: flex-start; gap: 6px; }
.profile-name-big { font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 22px; color: var(--text); }
.profile-stats { display: flex; flex-direction: column; gap: 14px; margin-bottom: 12px; }   /* one block per game mode + General */
.pstat-group { display: flex; flex-direction: column; gap: 7px; }
.pstat-head { font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 12.5px; letter-spacing: 1.2px; text-transform: uppercase; color: var(--text-dim); text-align: left; }
.pstat-row { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.pstat-row > .pstat:only-child { grid-column: 1 / -1; }   /* a lone stat (Libre) fills the row instead of leaving a gap */
.pstat { background: rgba(255, 255, 255, 0.05); border: 1px solid var(--card-edge); border-radius: 12px; padding: 9px 10px;
  display: flex; flex-direction: column; align-items: center; gap: 2px; }
.pstat b { font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 18px; color: var(--text); }
.pstat span { font-size: 11px; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.3px; }
.avatar-grid { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 10px; margin: 8px 0 6px; }
.avatar-cell { display: flex; flex-direction: column; align-items: center; gap: 5px; padding: 10px 6px; cursor: pointer;
  background: rgba(255, 255, 255, 0.04); border: 1.5px solid var(--card-edge); border-radius: 14px; }
.avatar-cell:active { transform: scale(0.96); }
.avatar-cell.on { border-color: var(--mint); box-shadow: inset 0 0 0 1px var(--mint); }
.avatar-cell.locked { cursor: default; }
.avatar-cell.locked .avatar-pic { filter: grayscale(1) brightness(0.4); }
.avatar-cell.locked .avatar-emo { opacity: 0.3; }
.avatar-name { font-weight: 900; font-size: 12px; color: var(--text); }
.avatar-cell.locked .avatar-name { color: var(--text-dim); }
.avatar-hint { font-size: 10px; line-height: 1.2; color: var(--text-dim); min-height: 12px; }
.avatar-cell.on .avatar-hint { color: var(--mint); font-weight: 800; }
/* the big avatar is a button (tap to open the gallery) with a little pencil badge */
.profile-avatar-big { position: relative; border: none; background: none; padding: 0; cursor: pointer; line-height: 0; }
.profile-avatar-big:active { transform: scale(0.96); }
.avatar-edit { position: absolute; right: -2px; bottom: -2px; width: 27px; height: 27px; border-radius: 50%;
  background: var(--coral, #ff5e6c); border: 2px solid var(--card); box-shadow: 0 2px 6px rgba(0, 0, 0, 0.4);
  display: flex; align-items: center; justify-content: center; }
.avatar-edit svg { width: 13px; height: 13px; fill: #fff; }
/* a discreet pencil next to the name instead of a big RENAME button */
.profile-name-row { display: inline-flex; align-items: center; gap: 8px; }
.name-edit { background: none; border: none; padding: 4px; cursor: pointer; display: inline-flex; border-radius: 8px; }
.name-edit svg { width: 17px; height: 17px; fill: var(--text-dim); }
.name-edit:active { transform: scale(0.9); }
.profile-account { display: flex; flex-direction: column; align-items: center; gap: 8px; margin: 4px 0; }
.profile-account .signin-row { width: 100%; }
/* item 9 : badge « Connecté avec X » (logo du provider + libellé), pastille discrète lisible en clair comme en sombre */
.prov-badge { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; font-weight: 700; color: var(--text);
  padding: 4px 12px; border-radius: 999px; background: color-mix(in srgb, var(--text) 8%, transparent); }
.prov-badge .prov-ic { flex: 0 0 auto; width: 15px; height: 15px; display: inline-flex; }
.prov-badge .prov-ic svg { width: 100%; height: 100%; display: block; }
.board-empty {
  text-align: center; color: var(--text-dim); font-size: 13px;
  padding: 22px 10px;
  background: var(--card); border: 1px dashed var(--card-edge); border-radius: 14px;
}

/* ---------- OVERLAYS ---------- */
.overlay {
  position: fixed; inset: 0; z-index: 100;
  background: rgba(8, 9, 16, 0.82);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  display: none; align-items: center; justify-content: center;
  padding: 24px;
}
.overlay.show { display: flex; }
/* ── full-screen REWARD SHEET: edge-to-edge (no floating modal), with the owner background_pattern behind a
   readability scrim. Used for the progression/celebration screens (no more "long pop-up" look). ── */
.overlay.reward-sheet { padding: 0; background: var(--bg, #0e0f1a); backdrop-filter: none; -webkit-backdrop-filter: none; }
/* owner : le CHOIX pick-1-of-2 (#ovCosmetic) reprend le MÊME fond d'obtention, teinté par la rareté de l'item (--rr-bg posé en JS) ;
   la couleur TRANSITIONNE d'un choix à l'autre (le fond ne s'arrête pas entre 2 choix) */
#ovCosmetic { background: var(--rr-bg, var(--bg, #0e0f1a)) !important; transition: background .45s ease; }
.overlay.reward-sheet.show { display: block; }   /* shown -> block (beats .overlay.show's flex); unshown -> .overlay's display:none keeps it hidden */
.overlay.reward-sheet > .panel {
  position: absolute; top: 0; bottom: 0; left: 50%; transform: translateX(-50%);
  width: 100% !important; max-width: 640px !important; height: auto !important; max-height: none !important;
  border: none !important; border-radius: 0 !important; box-shadow: none !important; animation: none;
  background-color: #14101f;
  background-image: linear-gradient(180deg, rgba(18, 14, 32, .92), rgba(10, 9, 20, .97));   /* owner : pattern retiré (fichier supprimé) -> dégradé sombre plein */
  background-repeat: no-repeat; background-size: cover; background-position: center;
  display: flex; flex-direction: column; align-items: center;
  padding: calc(16px + env(safe-area-inset-top)) 16px calc(16px + env(safe-area-inset-bottom));
  overflow-y: auto; gap: 12px;
}
.overlay.reward-sheet > .panel > .panel-title { margin-top: 4px; }
.overlay.reward-sheet.center > .panel { justify-content: center; }   /* celebration / choice screens: vertically centred */
/* these open on TOP of another overlay (e.g. the profile) -> keep them above it */
#ovName, #ovAvatars { z-index: 150; }
/* the jewel/coin top-up can be opened from INSIDE another modal (box-full choice, style buy) - it must
   sit above everything, incl. the dynamically-appended #ovBoxFull, or it opens invisibly behind. */
#ovBuyJewels, #ovStreak { z-index: 200; }
.avatar-panel { max-height: 88vh; overflow-y: auto; }
/* the level-end reward screen drops the backdrop blur and keeps the scrim CLEAR over the topbar, so
   the real coin/jewel totals stay sharp and you can watch them climb as rewards fly into them */
#ovAscEnd {
  backdrop-filter: none; -webkit-backdrop-filter: none;
  background: linear-gradient(to bottom, rgba(8, 9, 16, 0.04) 0, rgba(8, 9, 16, 0.10) 52px, rgba(8, 9, 16, 0.86) 150px);
}
.panel {
  background: var(--card);
  border: 1px solid var(--card-edge);
  border-radius: 26px;
  padding: 26px 22px;
  width: min(360px, 100%);
  display: flex; flex-direction: column; align-items: center; gap: 14px;
  box-shadow: 0 30px 60px rgba(0, 0, 0, 0.55);
  animation: panel-in 0.28s cubic-bezier(0.34, 1.56, 0.64, 1);
}
@keyframes panel-in { from { transform: scale(0.85) translateY(16px); opacity: 0; } to { transform: none; opacity: 1; } }
.panel-title { font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 26px; letter-spacing: 2px; }
.panel-title.newbest { color: var(--gold); text-shadow: 0 0 22px rgba(255, 200, 61, 0.6); }

.go-score { display: flex; flex-direction: column; align-items: center; gap: 2px; }
.go-points { font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 52px; line-height: 1; }
.go-best { color: var(--text-dim); font-size: 13px; letter-spacing: 1px; }
.go-coins {
  display: flex; align-items: center; gap: 8px;
  font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 26px; color: var(--gold);
}
.go-trophies {
  display: flex; align-items: center; justify-content: center; gap: 7px; margin-top: 6px;
  font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 20px; color: #d9c2ff;
}
.go-trophies .go-tro-ic { width: 24px; height: 24px; object-fit: contain; vertical-align: middle; }

/* home progression bar (trophies + next-tier) — the shared progression spine */
.trophy-bar {
  display: flex; align-items: center; gap: 10px; width: 100%;
  background: linear-gradient(180deg, rgba(120, 90, 180, 0.18), rgba(80, 60, 130, 0.12));
  border: 1px solid rgba(190, 160, 255, 0.22); border-radius: 16px;
  padding: 10px 14px; margin: 4px 0 2px; cursor: pointer; color: #ece7ff;
}
.trophy-bar:active { transform: translateY(1px); }
.tb-ic { width: 38px; height: 34px; object-fit: contain; vertical-align: middle; filter: drop-shadow(0 2px 3px rgba(0, 0, 0, .4)); }
.trophy-bar .tb-ic { flex: 0 0 auto; }
.trophy-bar .tb-mid { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.trophy-bar .tb-top { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; }
.trophy-bar .tb-tier { font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 15px; }
.trophy-bar .tb-count { font-size: 13px; font-weight: 800; color: #d9c2ff; }
.trophy-bar .tb-bar { height: 8px; border-radius: 5px; background: rgba(255, 255, 255, 0.12); overflow: hidden; }
.trophy-bar .tb-bar i { display: block; height: 100%; border-radius: 5px; background: linear-gradient(90deg, #a07bff, #d9b3ff); transition: width 0.4s ease; }
.trophy-bar .tb-next { font-size: 11px; color: #b9a9d6; letter-spacing: 0.3px; }
.trophy-bar .tb-caret { font-size: 22px; color: #b9a9d6; }

/* progression overlay: the whole trophy ladder */
.panel-tall { max-height: 86vh; display: flex; flex-direction: column; }
.tro-total { font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 22px; color: #d9c2ff; margin-bottom: 4px; }
/* ── the trophy ROUTE: rank bands (ribbon header + a colour road with reward chips alternating sides) ── */
.tro-list { flex: 1; overflow-y: auto; display: flex; flex-direction: column; width: 100%; max-width: 460px; padding: 0 8px 24px; position: relative; }
/* post-run XP climb: a glowing pill that rides up the path while the fills rise + rewards pop */
.xp-rider { position: absolute; left: 50%; transform: translate(-50%, -50%); z-index: 6; display: inline-flex; align-items: center; gap: 5px;
  padding: 5px 13px 5px 9px; border-radius: 999px; background: linear-gradient(180deg, #ffe9a8, #ffcf4a); color: #5a3d00;
  font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 17px; white-space: nowrap;
  box-shadow: 0 4px 14px -2px rgba(255, 200, 70, .85), inset 0 0 0 3px rgba(255, 255, 255, .4); opacity: 0; transition: opacity .25s; pointer-events: none; }
.xp-rider.show { opacity: 1; }
.xp-rider img { width: 20px; height: 20px; object-fit: contain; }
.tro-list.xp-animating .tro-road::after { transition: none; }
.tro-node.xp-pop .tro-chip { animation: xp-pop .5s cubic-bezier(.2, 1.5, .4, 1); }
.tro-node.xp-pop .tro-art { animation: xp-pop-art .5s cubic-bezier(.2, 1.6, .4, 1); }
@keyframes xp-pop { 0% { transform: scale(1); } 30% { transform: scale(1.13); } 100% { transform: scale(1); } }
@keyframes xp-pop-art { 0% { transform: scale(1); } 30% { transform: scale(1.4) rotate(-7deg); } 100% { transform: scale(1); } }
.tro-band { position: relative; width: 100%; --r1: #6fd6ff; --r2: #bdeeff; }
/* the ribbon art is a 512² image with transparent vertical padding -> negative margins close the gap to the road/next band */
.tro-rankhead { position: relative; display: flex; justify-content: center; align-items: flex-start; margin: -34px 0 -22px; }
.tro-rank-badge { width: 50px; height: 50px; border-radius: 50%; display: grid; place-items: center; position: relative; z-index: 2; margin-bottom: -16px;
  background: linear-gradient(150deg, var(--r2, #fff), var(--r1, #888)); border: 3px solid rgba(255, 255, 255, 0.4);
  box-shadow: 0 5px 14px -3px var(--r1, #000), inset 0 2px 5px rgba(255, 255, 255, 0.45), inset 0 -3px 6px rgba(0, 0, 0, 0.25); }
.tro-rank-badge img { width: 26px; height: 26px; object-fit: contain; filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.35)); }
/* a real badge image: drop the gradient medallion, show the owner art at full size */
/* the rank badge perches on the upper scroll of the banner (absolute, over the ribbon art) */
.tro-rank-badge.img { position: absolute; top: 48px; left: 50%; transform: translateX(-50%); width: 60px; height: 60px; margin: 0; background: none; border: none; box-shadow: none; z-index: 3; }
.tro-rank-badge.img img { width: 60px; height: 60px; filter: drop-shadow(0 4px 7px rgba(0, 0, 0, 0.45)); }
.tro-ribbon { position: relative; display: block; margin: 0; }
.tro-ribbon-bg { display: block; width: 250px; height: auto; pointer-events: none; filter: drop-shadow(0 5px 8px rgba(0,0,0,.42)); }
.tro-ribbon-txt { position: absolute; left: 0; right: 0; top: 47%; transform: translateY(-50%); text-align: center; padding: 0 19%; box-sizing: border-box;
  font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 21px; letter-spacing: .03em; color: #fff; text-shadow: 0 2px 0 rgba(0,0,0,.6); white-space: nowrap; }
.tro-road { position: relative; padding: 6px 0 2px; }
/* the central path: a DIM base track, plus a coloured LIT fill that rises from the bottom up to --fill (the levels reached) */
.tro-road::before { content: ''; position: absolute; left: 50%; top: -10px; bottom: -10px; width: 8px; transform: translateX(-50%); border-radius: 999px; background: rgba(255, 255, 255, .085); }
.tro-road::after { content: ''; position: absolute; left: 50%; bottom: -10px; width: 8px; height: calc(var(--fill, 0%) + 0px); transform: translateX(-50%); border-radius: 999px; background: linear-gradient(0deg, var(--r1), var(--r2)); box-shadow: 0 0 16px var(--r1); opacity: .95; transition: height .5s ease; }
.tro-node { position: relative; display: flex; align-items: center; min-height: 48px; margin: 11px 0; }
.tro-node.left { justify-content: flex-start; } .tro-node.right { justify-content: flex-end; }
.tro-node::before { content: ''; position: absolute; left: 50%; top: 50%; width: 13px; height: 13px; transform: translate(-50%,-50%); border-radius: 50%; background: var(--r2); border: 3px solid var(--r1); z-index: 2; box-shadow: 0 0 8px var(--r1); }
.tro-node.got::before { background: var(--r1); }
.tro-chip { position: relative; width: 47%; display: flex; align-items: center; gap: 8px; padding: 7px 9px; border-radius: 14px; background: rgba(18, 14, 30, .74); border: 1.5px solid rgba(255, 255, 255, .08); }
.tro-chip::after { content: ''; position: absolute; top: 50%; width: 14px; height: 4px; background: var(--r1); transform: translateY(-50%); border-radius: 2px; }
.tro-node.left .tro-chip::after { right: -14px; } .tro-node.right .tro-chip::after { left: -14px; }
.tro-node:not(.got):not(.next) .tro-chip { opacity: .5; }
.tro-node.got .tro-chip { border-color: var(--r1); }
.tro-node.next .tro-chip { border-color: var(--gold, #ffc83d); box-shadow: 0 0 0 2px var(--gold, #ffc83d), 0 0 18px -4px var(--gold, #ffc83d); }
.tro-art { display: grid; place-items: center; width: 36px; height: 36px; flex: none; }
.tro-art img, .tro-art .tro-cosmetic { width: 32px; height: 32px; object-fit: contain; }
.tro-art .tro-hold svg { width: 26px; height: 26px; color: #cbb8ff; }
.tro-art .ae-bonus { font-size: 22px; }
.tro-chip-txt { min-width: 0; flex: 1; }
.tro-name { font-size: 12.5px; font-weight: 800; color: #ece7ff; line-height: 1.15; white-space: normal; word-break: break-word; }
.tro-at { display: flex; align-items: center; gap: 3px; font-weight: 800; font-size: 11px; color: #b9a9d6; }
.tro-at .tro-mini { width: 12px; height: 12px; object-fit: contain; }
.tro-state { flex: none; min-width: 18px; text-align: center; }
.tro-st-ic { width: 18px; height: 18px; object-fit: contain; }
.tro-node.major .tro-chip { background: rgba(160, 123, 255, .16); }
.tro-node.major .tro-name { font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-weight: 400; letter-spacing: .3px; }
.tro-node.major .tro-art { transform: scale(1.1); }
/* leaderboard "champions" segment at the summit */
.tro-band.rank-lb { --r1: #b07aff; --r2: #e8d4ff; text-align: center; }
.tro-band.rank-lb .tro-ribbon-txt { color: #ffe9a8; }
.tro-lb-hint { font-size: 12px; color: var(--text-dim); max-width: 290px; margin: 4px auto 6px; line-height: 1.42; }
.tro-band.rank-lb.active .tro-lb-hint { color: #ffe9a8; }
/* CHAMPIONS panel: the worldwide standing line + the 3 sub-rank tiers and their box rewards */
.champ-hint { font-size: 12px; color: var(--text-dim); max-width: 290px; margin: 4px auto 8px; line-height: 1.42; }
.tro-band.rank-lb.active .champ-hint { color: #ffe9a8; }
.champ-standing { display: inline-flex; align-items: baseline; gap: 7px; margin: 4px auto 10px; padding: 5px 16px; border-radius: 999px;
  background: rgba(255, 233, 168, 0.1); border: 1px solid rgba(255, 233, 168, 0.3); font-family: 'Lilita One', 'Trebuchet MS', sans-serif; }
.champ-rank { font-size: 22px; color: #ffe9a8; }
.champ-of { font-size: 12px; color: var(--text-dim); }
.champ-pct { font-size: 13px; color: #fff; background: rgba(255, 233, 168, 0.22); padding: 1px 8px; border-radius: 999px; }
.champ-tiers { display: flex; flex-direction: column; gap: 7px; max-width: 320px; margin: 6px auto 8px; }
.champ-tier { display: grid; grid-template-columns: auto 1fr auto auto; align-items: center; gap: 9px; padding: 7px 12px 7px 9px; border-radius: 13px;
  background: rgba(255, 255, 255, 0.045); border: 1px solid rgba(255, 255, 255, 0.08); opacity: 0.62; transition: opacity 0.2s; }
.champ-tier.on { opacity: 1; background: linear-gradient(100deg, color-mix(in srgb, var(--c1) 26%, transparent), color-mix(in srgb, var(--c2) 16%, transparent));
  border-color: color-mix(in srgb, var(--c1) 60%, transparent); box-shadow: 0 0 12px -3px var(--c1); }
.champ-tier-badge { width: 38px; height: 38px; object-fit: contain; filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.4)) grayscale(0.7) brightness(0.78); transition: filter 0.2s; }
.champ-tier.on .champ-tier-badge { filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.45)); }
.champ-tier-name { font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 14px; letter-spacing: 0.5px; color: var(--c2); text-align: left; }
.champ-tier-cond { font-size: 11px; color: var(--text-dim); white-space: nowrap; }
.champ-tier-rw { display: inline-flex; align-items: center; gap: 1px; font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 15px; color: #ffe9a8; }
.champ-box-ic { width: 26px; height: 26px; object-fit: contain; filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.4)); }

/* cosmetic choice (ladder reward): a full reward moment on the base pattern — two tiles pivot in, anchor, then float */
#ovCosmetic { background: #16121f; }   /* owner : pattern retiré */
#ovCosmetic.show { display: flex; align-items: center; justify-content: center; }   /* owner T64 : tout CENTRÉ au milieu de la page (titre + tuiles) */
#ovCosmetic::before { content: ''; position: absolute; inset: 0; background: linear-gradient(180deg, rgba(8, 9, 15, 0.4) 0%, transparent 18%, transparent 82%, rgba(8, 9, 15, 0.4) 100%); pointer-events: none; }
#ovCosmetic .panel { position: relative; left: auto; transform: none; z-index: 1; background: transparent; box-shadow: none; display: flex; flex-direction: column; align-items: center; justify-content: center; width: 100%; max-width: 460px; margin: auto; }   /* owner : left/transform remis à plat (le panneau est en flow relatif, centré par le flex parent) -> plus décalé à droite sur desktop */
.cos-row { display: flex; gap: 20px; justify-content: center; margin-top: 18px; perspective: 900px; }
/* owner : voile sombre derrière les 2 tuiles -> elles ressortent nettement même sur le fond d'obtention teinté par la rareté (C2) */
#ovCosmetic .cos-row { background: rgba(0, 0, 0, 0.26); border-radius: 24px; padding: 16px 14px; }
.cos-tile { display: flex; flex-direction: column; align-items: center; gap: 11px; width: min(158px, 41vw); padding: 10px; border: none; background: transparent; cursor: pointer;
  transform-style: preserve-3d; animation: cos-in 0.62s cubic-bezier(0.22, 0.9, 0.3, 1.35) both; }
.cos-tile .cos-art { width: 100%; aspect-ratio: 1; border-radius: 20%; overflow: hidden; border: 3px solid var(--rc, #888); box-shadow: 0 6px 16px rgba(0, 0, 0, 0.4), 0 0 18px var(--rc); display: grid; place-items: center; background: radial-gradient(circle at 50% 42%, color-mix(in srgb, var(--rc, #888) 42%, #1c1533), color-mix(in srgb, var(--rc, #888) 15%, #120e1f)); transition: transform 0.15s ease;   /* owner T84 : fond teinté par la rareté de l'item derrière le bloc (plus de fond transparent) */
  animation: cos-float 3.4s ease-in-out infinite; }
.cos-tile:nth-child(2) .cos-art { animation-delay: -1.7s; }   /* the two tiles bob out of phase */
.cos-tile:active .cos-art { transform: scale(0.95); animation-play-state: paused; }
.cos-tile .cos-art > * { width: 100%; height: 100%; display: block; }
.cos-tile .cos-wp, .cos-tile .cos-music { background-size: cover; background-position: center; }
.cos-tile .cos-name { font-size: 13.5px; font-weight: 800; color: #ece7ff; text-align: center; line-height: 1.2; }
.cos-tile .cos-set { font-size: 11px; font-weight: 700; color: var(--text-dim); text-align: center; margin-top: -3px; }
/* a TYPE tag (block / wallpaper / music) on each choice tile */
.cos-tile { position: relative; }
.cos-tag { position: absolute; top: 2px; left: 50%; transform: translateX(-50%); z-index: 3; font-size: 9.5px; font-weight: 900; letter-spacing: .08em; color: #fff; padding: 2px 9px; border-radius: 999px; box-shadow: 0 2px 5px rgba(0, 0, 0, .35); }
.cos-tag-block { background: linear-gradient(180deg, #8a6bff, #6a45d8); }
.cos-tag-wp { background: linear-gradient(180deg, #4dc4ff, #2b8fd0); }
.cos-tag-music { background: linear-gradient(180deg, #ff7eb3, #e0508b); }
/* collect: the chosen tile flies to the Styles nav (.flying via flyOrbToAnchor); the other shrinks away */
.cos-tile.flying { transition: transform .54s cubic-bezier(.5, -.25, .7, 1), opacity .5s ease; z-index: 5; }
.cos-tile.cos-discard { animation: cos-discard .45s cubic-bezier(.5, 0, .75, 0) forwards; }
@keyframes cos-discard { to { transform: scale(.15) translateY(40px); opacity: 0; } }
@keyframes cos-in { 0% { opacity: 0; transform: rotateY(-115deg) scale(0.55) translateY(26px); } 60% { opacity: 1; } 100% { opacity: 1; transform: rotateY(0) scale(1) translateY(0); } }
@keyframes cos-float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-9px); } }

/* tier-up celebration */
.tierup-panel { text-align: center; --r1: #ffc83d; --r2: #fff0b8; }
/* the star sits over a spinning rank-coloured sunburst, with a shockwave ring on entry */
.tu-star-wrap { position: relative; width: 150px; height: 150px; margin: 0 auto 4px; display: grid; place-items: center; }
/* WHITE rays from the centre of the SCREEN, very long (past the edges), faint + diffuse (fade out radially) */
/* same WebKit-safe recipe as .rays: no mask, black-painted fade + screen blend, circle, small box scaled */
.tu-rays { position: fixed; width: 105vmax; height: 105vmax; border-radius: 50%; left: 50%; top: 44%; transform: translate(-50%, -50%) scale(2); z-index: 0; opacity: .13; pointer-events: none; animation: tu-spin 24s linear infinite; mix-blend-mode: screen;
  background: radial-gradient(circle, rgba(0, 0, 0, .55) 0%, #000 42%, #000 100%),
    repeating-conic-gradient(from 0deg, rgba(255, 255, 255, 0.6) 0deg 5deg, transparent 5deg 16deg); }   /* owner (3e passe) : encore plus faibles, fondu plus tôt */
@keyframes tu-spin { to { transform: translate(-50%, -50%) scale(2) rotate(360deg); } }
.tu-ring { position: absolute; width: 86px; height: 86px; border-radius: 50%; border: 5px solid color-mix(in srgb, var(--r1) 80%, #fff); opacity: 0; }
.tu-ring.burst { animation: tu-ring 0.72s cubic-bezier(.2, .7, .3, 1); }
@keyframes tu-ring { 0% { opacity: .9; transform: scale(.3); } 100% { opacity: 0; transform: scale(2.5); } }
.tu-trophy { position: relative; z-index: 1; width: 96px; height: 96px; object-fit: contain; display: block; filter: drop-shadow(0 6px 18px color-mix(in srgb, var(--r1) 60%, transparent)); }
.tu-trophy.pop { animation: tuPop 0.7s cubic-bezier(.2, 1.7, .4, 1); }
@keyframes tuPop { 0% { transform: scale(0.2) rotate(-12deg); opacity: 0; } 60% { transform: scale(1.18) rotate(4deg); } 100% { transform: scale(1) rotate(0); opacity: 1; } }
.tu-tier { font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 26px; color: #ece7ff; margin-bottom: 4px; }
/* rank ribbon under the level number */
/* the ribbon + tiny rank name are gone (the big rank BADGE already shows the rank); only a clean "NEW RANK" pill remains */
.tu-rank { display: flex; align-items: center; justify-content: center; margin: 2px auto 10px; }
.tu-rank-up { font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 13px; letter-spacing: .08em; color: #fff; background: linear-gradient(180deg, #ff8a3d, #e0506b); padding: 4px 15px; border-radius: 999px; box-shadow: 0 2px 6px rgba(0,0,0,.4); white-space: nowrap; animation: tu-rankup-in .5s cubic-bezier(.34,1.7,.5,1) backwards .25s; }
@keyframes tu-rankup-in { 0% { transform: translateX(-50%) scale(.3); opacity: 0; } 100% { transform: translateX(-50%) scale(1); opacity: 1; } }
/* the reveal sits on the base pattern; rewards FLOAT in one by one as bobbing orbs (like box-open loot) */
#ovTierUp { background: #16121f; }   /* owner : pattern retiré */
#ovTierUp::before { content: ''; position: absolute; inset: 0; background: linear-gradient(180deg, rgba(8, 9, 15, 0.4) 0%, transparent 18%, transparent 82%, rgba(8, 9, 15, 0.4) 100%); pointer-events: none; }
#ovTierUp .tierup-panel { position: relative; z-index: 1; background: transparent; box-shadow: none; }
.tu-rewards { display: flex; flex-wrap: wrap; gap: 4px 16px; align-items: flex-start; justify-content: center; margin: 10px auto 14px; width: min(330px, 90vw); min-height: 100px; }
.tu-orb { animation: loot-rise .5s cubic-bezier(.2, 1.4, .5, 1) both; background: none; border: 0; padding: 4px; cursor: pointer; -webkit-tap-highlight-color: transparent; }   /* reuses .loot-bob / .loot-art / .loot-amt / .loot-name from the box loot */
.tu-orb:active .loot-bob { transform: scale(.9); }
.tu-orb.flying { transition: transform .52s cubic-bezier(.5, -.25, .7, 1), opacity .5s ease; }
.tu-orb .loot-art img, .tu-orb .loot-art .box-img { max-width: 66px; max-height: 66px; object-fit: contain; }
.tu-orb .loot-art .tu-rw-img { width: 52px; height: 52px; }
.tu-orb .loot-art .ae-bonus { font-size: 40px; line-height: 1; }
.tu-orb .loot-art .coin-mini.tu-coin { width: 54px; height: 54px; }
#btnTuDouble { margin-bottom: 8px; }
.tro-claim { margin: 4px auto 8px; }
.tro-claim.cta-pulse { animation: cta-pulse 1.1s ease-in-out infinite; }
@keyframes cta-pulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.05); } }

.go-trophies.pop { animation: goTroPop 0.5s ease; }
@keyframes goTroPop { 0% { transform: scale(0.6); opacity: 0; } 60% { transform: scale(1.13); } 100% { transform: scale(1); opacity: 1; } }

/* board-colour picker (settings) */
.board-color-row { align-items: center; }
.board-swatches { display: flex; flex-wrap: wrap; gap: 7px; flex: 1; justify-content: flex-end; }
.board-sw { width: 26px; height: 26px; border-radius: 8px; border: 2px solid rgba(255, 255, 255, 0.18); cursor: pointer; padding: 0; position: relative; }
.board-sw:active { transform: scale(0.92); }
.board-sw.on { border-color: #fff; box-shadow: 0 0 0 2px var(--gold); }
.board-sw.bc-default { background: #2a2c3e; }
.board-sw.bc-default::after { content: ''; position: absolute; inset: 4px; border-radius: 4px; background: linear-gradient(135deg, transparent 44%, #9aa0a8 46%, #9aa0a8 54%, transparent 56%); }

/* continue countdown */
.continue-bar {
  width: 100%; height: 10px; border-radius: 999px;
  background: rgba(255, 255, 255, 0.08);
  overflow: hidden;
}
.continue-bar i {
  display: block; height: 100%; width: 100%;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--gold), var(--coral));
  transition: width 0.1s linear;
}

/* text inputs (name, phone, OTP code) */
#nameInput, #phoneInput, #otpInput {
  width: 100%;
  background: var(--ink-2);
  border: 2px solid var(--card-edge);
  border-radius: 14px;
  color: var(--text);
  font-family: 'Nunito', sans-serif; font-weight: 900; font-size: 18px;
  text-align: center;
  padding: 12px 14px;
  outline: none;
}
#nameInput:focus, #phoneInput:focus, #otpInput:focus { border-color: var(--sky); }
#otpInput { letter-spacing: 8px; font-size: 24px; }
.phone-step { display: flex; flex-direction: column; align-items: center; gap: 14px; width: 100%; }

/* box overlay — the box floats in open dimmed space (no panel box) so loot can fly out */
.box-ceremony {
  display: flex; flex-direction: column; align-items: center;
}
/* the rarity light that blooms out of the open box (box stays visible on top of it) */
/* the box backdrop takes the rarity colour: the owner's per-rarity pattern behind a light vignette
   (kept light so the colour reads; the box's own glow blooms over the centre). */
#ovBox.rarity-bg {
  /* owner : fond PLEIN teinté par la rareté de l'écrin (--rr-bg, dégradé façon sunset coloré), cohérent avec les cérémonies de récompense */
  background: var(--rr-bg, var(--dp-bg, #0e0f1a));
  background-repeat: no-repeat; background-size: cover; background-position: center;
}
.box-light {
  position: absolute; left: 50%; top: 31%; transform: translate(-50%, -50%) scale(0.2);
  width: 440px; height: 440px; border-radius: 50%;
  pointer-events: none; opacity: 0; z-index: 0;
  background: radial-gradient(circle, color-mix(in srgb, var(--rc, #fff) 62%, transparent) 0%, color-mix(in srgb, var(--rc, #fff) 22%, transparent) 34%, transparent 68%);
  transition: opacity 0.5s ease, transform 0.7s cubic-bezier(0.2, 0.9, 0.3, 1);
}
.box-light.on { opacity: 1; transform: translate(-50%, -50%) scale(1); animation: light-breathe 3.2s ease-in-out 0.7s infinite; }
@keyframes light-breathe { 0%, 100% { opacity: 0.7; } 50% { opacity: 0.92; } }
/* anticipation: a faint rarity glow that swells while the box rattles, just before it bursts open */
.box-light.charging { opacity: 0.5; transform: translate(-50%, -50%) scale(0.62); transition: opacity 0.5s ease-in, transform 0.55s ease-in; animation: charge-pulse 0.18s ease-in-out infinite alternate; }
@keyframes charge-pulse { from { filter: brightness(1); } to { filter: brightness(1.35); } }
/* the OPEN BURST: a white core flash + an expanding rarity-tinted shockwave ring */
.box-flash {
  position: absolute; left: 50%; top: 31%; transform: translate(-50%, -50%) scale(0.3);
  width: 380px; height: 380px; border-radius: 50%; pointer-events: none; opacity: 0; z-index: 2; mix-blend-mode: screen;
  background: radial-gradient(circle, #fff 0%, color-mix(in srgb, var(--rc, #fff) 70%, #fff) 26%, transparent 62%);
}
.box-flash.burst { animation: box-flash 0.5s ease-out; }
@keyframes box-flash { 0% { opacity: 0; transform: translate(-50%, -50%) scale(0.3); } 16% { opacity: 1; transform: translate(-50%, -50%) scale(1); } 100% { opacity: 0; transform: translate(-50%, -50%) scale(1.55); } }
.box-shock {
  position: absolute; left: 50%; top: 31%; transform: translate(-50%, -50%) scale(0.2);
  width: 220px; height: 220px; border-radius: 50%; pointer-events: none; opacity: 0; z-index: 2;
  border: 6px solid color-mix(in srgb, var(--rc, #fff) 80%, #fff);
}
.box-shock.burst { animation: box-shock 0.72s cubic-bezier(0.2, 0.7, 0.3, 1); }
@keyframes box-shock { 0% { opacity: 0.9; transform: translate(-50%, -50%) scale(0.2); border-width: 7px; } 100% { opacity: 0; transform: translate(-50%, -50%) scale(2.7); border-width: 1px; } }
/* the box sits ABOVE the light (z:1) so it stays clearly visible; animations live on the inner img */
.box-stage {
  position: absolute; left: 50%; top: 31%; transform: translate(-50%, -50%);
  width: 248px; height: 210px; z-index: 1;   /* owner T92 : écrin ~2x plus grand pendant l'ouverture */
  transition: opacity 0.4s ease;
}
.box-stage.fade { opacity: 0; }
/* closed + open box are STACKED (both preloaded) so the lid "opens" with no swap gap,
   at the exact same spot/size; the shake plays on whichever is showing */
.box-stage .box-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; }
.box-stage .box-open { opacity: 0; }
.box-stage.shaking .box-cl { animation: box-shake 0.55s ease-in-out; }
.box-stage.opened .box-cl { opacity: 0; }
.box-stage.opened .box-open { opacity: 1; animation: box-open-pop 0.42s cubic-bezier(0.34, 1.5, 0.5, 1); }
@keyframes box-shake {
  0%, 100% { transform: rotate(0); }
  15% { transform: rotate(-7deg) scale(1.02); }
  30% { transform: rotate(6deg); }
  45% { transform: rotate(-5deg) scale(1.05); }
  60% { transform: rotate(4deg); }
  75% { transform: rotate(-2deg) scale(1.08); }
}
/* an epic squash-pop on opening: jolts UP with a big punch, then settles at scale 1 (same footprint) */
@keyframes box-open-pop { 0% { transform: scale(0.9) translateY(7px); } 32% { transform: scale(1.24) translateY(-12px); } 60% { transform: scale(0.97) translateY(3px); } 100% { transform: scale(1) translateY(0); } }

.reveal-card {
  display: flex; flex-direction: column; align-items: center; gap: 10px;
  border-radius: 20px; padding: 20px 26px;
  border: 2px solid var(--rc, var(--rar-rare));
  box-shadow: 0 0 34px color-mix(in srgb, var(--rc, var(--rar-rare)) 45%, transparent);
  animation: reveal-in 0.45s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.reveal-card.hiddenc { display: none; }
@keyframes reveal-in { from { transform: scale(0.3) rotate(-8deg); opacity: 0; } to { transform: none; opacity: 1; } }
.rarity-tag {
  font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 13px; letter-spacing: 3px;
  color: var(--rc, var(--rar-rare));
}
.reveal-name { font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 24px; }
.reveal-sub { font-size: 12.5px; color: var(--text-dim); text-align: center; }
.reveal-actions { display: flex; gap: 10px; margin-top: 4px; }
.pity-line { font-size: 12px; color: var(--text-dim); text-align: center; }

/* odds */
.odds-list { list-style: none; width: 100%; display: flex; flex-direction: column; gap: 9px; }
.odds-list li {
  display: flex; justify-content: space-between; align-items: center;
  background: rgba(255, 255, 255, 0.04); border-radius: 12px; padding: 9px 14px;
}
.odds-note { font-size: 12.5px; color: var(--text-dim); line-height: 1.5; }
.odds-sub { font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 12px; letter-spacing: 1px; color: var(--text-dim); align-self: flex-start; margin: 6px 0 2px; }
.odds-bonus li { gap: 10px; }
.odds-bonus-ic { display: inline-flex; width: 20px; height: 20px; color: var(--coral); flex-shrink: 0; }
.odds-bonus-ic svg { width: 100%; height: 100%; }
.odds-bonus-ic .bonus-ic-img { width: 100%; height: 100%; object-fit: contain; display: block; }
.odds-bonus-name { flex: 1; text-align: left; font-weight: 700; }
/* refreshed drop-rates panel: intro + item-type list + rarity grid + bonus list */
.odds-intro { font-size: 13px; color: var(--text); line-height: 1.4; align-self: flex-start; text-align: left; margin-bottom: 2px; }
.odds-mini { font-size: 11.5px; color: var(--text-dim); line-height: 1.35; align-self: flex-start; text-align: left; margin: -2px 0 4px; }
.odds-types li { gap: 10px; }
/* per-box drop-rate sections */
.odds-boxes { display: flex; flex-direction: column; gap: 12px; width: 100%; }
.odds-box { background: rgba(255, 255, 255, .04); border: 1px solid var(--card-edge); border-radius: 14px; padding: 10px 12px; }
.odds-box-head { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; }
.odds-box-ic { width: 30px; height: 30px; object-fit: contain; }
.odds-box-name { font-weight: 900; font-size: 14px; letter-spacing: .02em; }
.odds-rows { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 4px; }
.odds-rows > li { display: flex; align-items: center; gap: 10px; font-size: 13px; }
.odds-rows > li.odds-sub-wrap { flex-direction: column; align-items: stretch; gap: 0; }   /* head ABOVE the per-rarity list */
.odds-rows > li > b { margin-left: auto; font-weight: 800; }
.odds-type-img { width: 20px; height: 20px; object-fit: contain; flex: none; }   /* applies in the item-head too (not just .odds-type-ic) */
.odds-item-head { display: flex; align-items: center; gap: 6px; font-weight: 700; color: var(--text-dim); font-size: 12.5px; margin: 4px 0 2px; }
.odds-type-ic { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 22px; font-size: 17px; flex-shrink: 0; }
.odds-type-ic .odds-type-img { width: 20px; height: 20px; object-fit: contain; }
.odds-type-name { flex: 1; text-align: left; font-weight: 700; }
/* cosmetic-item breakdown: an icon-less indented sub-list under the "Cosmetic item" line */
.odds-sub-wrap { display: block; padding: 0; }
.odds-sub { list-style: none; margin: 2px 0 4px; padding: 0 6px 0 34px; display: flex; flex-direction: column; gap: 3px; }
.odds-sub li { display: flex; align-items: center; justify-content: space-between; font-size: 12px; color: var(--text-dim); }
.odds-sub-name { text-align: left; }
.odds-sub b { font-weight: 800; }
.odds-rar-grid { display: grid; grid-template-columns: auto repeat(5, 1fr); gap: 6px 4px; width: 100%; align-items: center; background: rgba(255, 255, 255, 0.04); border-radius: 12px; padding: 10px 12px; }
.odds-c { text-align: center; font-size: 12px; font-weight: 800; color: var(--text); }
.odds-c.z { color: var(--text-dim); opacity: 0.45; }
.odds-c.head { font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 13px; }
.odds-rl { font-size: 11px; font-weight: 800; text-align: left; white-space: nowrap; padding-right: 4px; }

/* toast */
#toast {
  position: fixed; left: 50%; bottom: calc(34px + var(--safe-bottom)); z-index: 200;
  transform: translateX(-50%) translateY(20px);
  background: var(--card); border: 1px solid var(--card-edge);
  border-radius: 999px; padding: 10px 20px;
  font-weight: 900; font-size: 14px;
  opacity: 0; pointer-events: none;
  transition: opacity 0.25s, transform 0.25s;
  white-space: nowrap;
}
#toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }

/* desktop niceties */
@media (min-width: 700px) {
  body { background: #090a12; }
  /* the column is mostly transparent so the wallpaper shows through it (not just in the margins); a
     light frost + a faint wallpaper-tinted scrim keep the UI readable. Cards/board/buttons keep their
     own backgrounds for contrast. */
  #app {
    border-left: 1px solid var(--card-edge);
    border-right: 1px solid var(--card-edge);
    background: rgba(10, 11, 20, 0.28);
    background: color-mix(in srgb, var(--ink) 26%, transparent);
    backdrop-filter: blur(2.5px);
    -webkit-backdrop-filter: blur(2.5px);
  }
  /* keep the floating HUD text legible where it sits directly on the see-through column */
  body[data-view="game"] .hud-value, body[data-view="game"] .hud-label { text-shadow: 0 1px 0 rgba(0, 0, 0, 0.55); }
}
/* tablet / desktop with room to breathe: a wider centred column (layout() bumps the board to match),
   floating over the full-bleed high-res wallpaper */
@media (min-width: 700px) and (min-height: 760px) {
  #app { max-width: 660px; box-shadow: 0 0 60px rgba(0, 0, 0, 0.5); }
}
/* DESKTOP / HORIZONTAL TABLET — every BROWSING scene (Home + Collection + Shop + Ranks + Goals) shares
   ONE stage width, so navigating between them never changes the frame and the wallpaper shows on the
   sides of all of them identically. The game keeps its own 660 play-column (the board is height-capped at
   520 regardless, so a wider frame wouldn't help it). */
@media (min-width: 900px) {
  body[data-view="home"] #app, body[data-view="collection"] #app, body[data-view="shop"] #app,
  body[data-view="board"] #app, body[data-view="goals"] #app { max-width: min(94vw, 1000px); }

  /* HOME: keep the hero (logo / best / level / PLAY / caption) a centred 560 column so it doesn't stretch
     into thin bars; let the four box cards span the stage in a single row. */
  #view-home .logo, #view-home .best-banner, #view-home .level-bar, #view-home .play-wrap, #view-home .mode-caption {
    max-width: 560px; margin-left: auto; margin-right: auto; width: 100%;
  }
  .home-cards { grid-template-columns: repeat(4, 1fr); }
  /* desktop 4-col = UNE rangée : on plafonne la hauteur des écrins (sinon 1fr les étire) et on ancre le bas */
  body[data-view="home"] .home-cards { flex: 0 1 auto; max-height: 190px; grid-auto-rows: minmax(120px, 174px); align-content: start; }
  body[data-view="home"] .play-wrap { margin-top: auto; }

  /* COLLECTION header rows stay compact + centred over the wide grid */
  #view-collection .seg-row, #view-collection .coll-total, #view-collection .coll-cat { max-width: 560px; margin-left: auto; margin-right: auto; }

  /* ONE tile size (~150px) for collection + shop. The collection fills rows / centres short rows via
     auto-fit; the shop forces a single row of six so its shelves fill the stage instead of floating in
     the middle. Both raise specificity above the base .prev-grid rule that appears later in the file. */
  body[data-view="collection"] .prev-grid { grid-template-columns: repeat(auto-fit, 150px); justify-content: center; }
  body[data-view="shop"] .featured-body .prev-grid { grid-template-columns: repeat(6, 1fr); }
  body[data-view="shop"] .shop-set-grid { grid-template-columns: repeat(6, 1fr); gap: 10px; }   /* one row of 6 on desktop */
  body[data-view="collection"] .prev-theme .board-prev, body[data-view="shop"] .prev-theme .board-prev { --cell: 18px; }
  /* coin / jewel / bonus packs: cap + centre so they don't balloon on the stage either */
  body[data-view="shop"] .shop-grid { grid-template-columns: repeat(auto-fit, minmax(190px, 230px)); justify-content: center; }
  /* leaderboard + achievement rows just fill the same stage as the other scenes (no separate cap) */
}

/* ---------- responsive hardening ---------- */
.home-cards .card { min-width: 0; }   /* let cards shrink below button min-content */

/* owner : DA CLAIRE pour la Collection (cadres fonds d'écran / musiques) + l'encadré TON MIX */
.mix-bar { background: linear-gradient(180deg, #fff, #f4f0fb) !important; border-color: #e7dff5 !important; box-shadow: 0 6px 16px rgba(55, 25, 100, .14) !important; }
.mix-head { color: var(--dp-ink, #2a1a4d); opacity: 1; }
.mix-head b { color: #e6a216; }
.mix-slot.empty { border-color: #d9cef0 !important; background: #f3eefb !important; }
#view-collection .style-prev { background: #fff; }
#view-collection .prev-name { color: var(--dp-ink, #2a1a4d); }

/* owner : accueil TABLETTE — les images d'écrins + le menu grandissent avec l'écran (avant : figés/petits) */
/* (l'image d'écrin responsive est gérée dans index.html, sélecteur .slot-art img, pour battre son !important) */
@media (min-width: 700px) {
  #navBar { max-width: 640px; }
  #navBar .nav-item .nav-ic { width: 44px !important; height: 44px !important; }
  #navBar .nav-label { font-size: 12px; }
}
@media (min-width: 900px) {
  #navBar { max-width: 720px; }
  #navBar .nav-item .nav-ic { width: 48px !important; height: 48px !important; }
  #navBar .nav-label { font-size: 13px; }
}

#toast {
  max-width: calc(100vw - 32px);
  white-space: normal;
  text-align: center;
}

@media (max-width: 360px) {
  .btn-mini, .btn-ghost2 { font-size: 13px; padding: 9px 12px; letter-spacing: 1px; }
  .btn-play { font-size: 24px; padding: 16px 54px; }
  .home-foot .btn { font-size: 13px; letter-spacing: 1px; }
}

/* short viewports (landscape phones): let views scroll instead of clipping */
.overlay { overflow-y: auto; }
.panel { max-height: calc(100dvh - 40px); overflow-y: auto; }
@media (max-height: 620px) {
  #view-game { overflow-y: auto; }
  #view-home { overflow-y: auto; justify-content: flex-start; padding-top: 8px; }
}

/* ============================================================
   META-GAME: jewels, bonuses, box slots, ceremony, shop, settings
   ============================================================ */

/* premium currency */
.jewel-mini {
  display: inline-block; width: 14px; height: 14px;
  background: url(assets/ui/jewel.webp) center/contain no-repeat;
  vertical-align: -3px;
}
.jewel-mini.big-pack, .coin-mini.big-pack { width: 30px; height: 30px; }
.bonus-mini { display: inline-flex; width: 14px; height: 14px; vertical-align: -3px; color: var(--coral); }
.bonus-mini svg { width: 100%; height: 100%; }

/* HUD stars */
.hud-stars { display: flex; gap: 2px; margin-top: 3px; }
.hud-stars i {
  font-style: normal; font-size: 13px; line-height: 1;
  color: rgba(255, 255, 255, 0.16);
  transition: color 0.2s, text-shadow 0.2s;
}
.hud-stars i.lit { color: var(--gold); text-shadow: 0 0 8px rgba(255, 200, 61, 0.8); }
.hud-stars i.mystery { color: rgba(176, 122, 255, 0.4); }
.hud-stars i.mystery.lit { color: var(--rar-epic); text-shadow: 0 0 10px var(--rar-epic); }

/* bonus bar */
#bonusBar {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  padding: 2px 0;
}
.bonus-btn {
  position: relative;
  flex: 1 1 0; min-width: 0; max-width: 92px; height: 46px;
  display: flex; align-items: center; justify-content: center;
  background: var(--card);
  border: 1px solid var(--card-edge);
  border-radius: 14px;
  color: var(--sky);
  cursor: pointer;
  box-shadow: 0 4px 0 rgba(0, 0, 0, 0.35);
}
.bonus-btn:active { transform: translateY(3px); box-shadow: 0 1px 0 rgba(0, 0, 0, 0.35); }
.bonus-btn svg { width: 24px; height: 24px; }
.bonus-btn .bonus-ic-img { width: 30px; height: 30px; object-fit: contain; display: block; }
/* owner : l'appui long sur une icône de Bonus (img) ne doit PAS ouvrir le menu image iOS (enregistrer l'image...) */
.bonus-ic-img { -webkit-touch-callout: none; -webkit-user-select: none; user-select: none; }
.bonus-btn[data-bonus="undo"] { color: var(--mint); }
.bonus-btn[data-bonus="gem"] { color: var(--coral); }
.bonus-btn[data-bonus="line"] { color: var(--amber); }
.bonus-btn[data-bonus="bomb"] { color: var(--rar-epic); }
.bonus-btn b {
  position: absolute; top: -6px; right: -4px;
  min-width: 18px; height: 18px; border-radius: 999px;
  background: var(--gold); color: #4a3200;
  font-family: 'Nunito', sans-serif; font-weight: 900; font-size: 11px;
  display: flex; align-items: center; justify-content: center;
  padding: 0 4px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.4);
}
.bonus-btn.off { opacity: 0.35; }
.bonus-btn.capped { opacity: 0.4; filter: saturate(0.35); }   /* Phase 4 §5.3 — Champion fairplay cap reached for this rarity */
.bonus-btn.armed {
  outline: 2px solid var(--gold);
  box-shadow: 0 0 14px rgba(255, 200, 61, 0.5);
  animation: armed-pulse 1s ease-in-out infinite;
}
@keyframes armed-pulse { 50% { transform: scale(1.05); } }

/* ---- home: Classé/Non-classé toggle + Loadout entry (phase 3) ---- */
.home-mode-opts { display: flex; flex-direction: column; align-items: center; gap: 10px; margin: 4px auto 2px; width: min(320px, 86%); }
.ranked-toggle { width: 100%; }
.btn-loadout { width: 100%; letter-spacing: 1.5px; }
.btn-loadout span { display: inline-flex; align-items: center; gap: 8px; }

/* ---- loadout selector overlay ---- */
.loadout-panel { max-width: 420px; }
.loadout-sub { text-align: center; opacity: 0.7; font-size: 13px; margin: 10px 0 18px; }   /* T129/T130 : plus d'air entre le titre et la phrase (loadout + craft) */
.loadout-slots { display: flex; gap: 10px; justify-content: center; margin-bottom: 16px; }
.loadout-slot {
  position: relative; width: 60px; height: 60px; border-radius: 16px;
  display: flex; align-items: center; justify-content: center; cursor: pointer;
  background: var(--card); border: 2px solid var(--card-edge);
}
.loadout-slot.empty { border-style: dashed; opacity: 0.55; }
.loadout-slot.empty span { font-size: 26px; font-weight: 900; color: var(--sky); opacity: 0.6; }
.loadout-slot.filled { border-color: var(--gold); box-shadow: 0 0 10px rgba(255, 200, 61, 0.28); }
.loadout-slot .bonus-ic-img { width: 38px; height: 38px; object-fit: contain; }
.loadout-slot b {
  position: absolute; top: -6px; right: -5px; min-width: 18px; height: 18px; border-radius: 999px;
  background: var(--gold); color: #4a3200; font-family: 'Nunito', sans-serif; font-weight: 900; font-size: 11px;
  display: flex; align-items: center; justify-content: center; padding: 0 4px;
}
.loadout-pool { max-height: 46vh; overflow-y: auto; margin-bottom: 14px; }
.loadout-cat { margin-bottom: 12px; }
.loadout-cat-name { display: block; font-size: 11px; letter-spacing: 1.5px; text-transform: uppercase; opacity: 0.55; margin: 0 0 6px 2px; }
.loadout-cat-row { display: flex; flex-wrap: wrap; gap: 8px; }
.loadout-item {
  position: relative; width: 52px; height: 52px; border-radius: 14px; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  background: var(--card); border: 1px solid var(--card-edge); transition: transform 0.08s, border-color 0.12s;
}
.loadout-item:active { transform: translateY(2px); }
.loadout-item.on { border-color: var(--gold); box-shadow: 0 0 10px rgba(255, 200, 61, 0.32); }
.loadout-item.on::after {
  content: '✓'; position: absolute; bottom: -4px; left: -4px; width: 16px; height: 16px; border-radius: 999px;
  background: var(--gold); color: #4a3200; font-size: 11px; font-weight: 900; display: flex; align-items: center; justify-content: center;
}
.loadout-item .bonus-ic-img { width: 32px; height: 32px; object-fit: contain; }
.loadout-item b {
  position: absolute; top: -5px; right: -4px; min-width: 16px; height: 16px; border-radius: 999px;
  background: var(--mint); color: #06321f; font-family: 'Nunito', sans-serif; font-weight: 900; font-size: 10px;
  display: flex; align-items: center; justify-content: center; padding: 0 3px;
}
.loadout-item .new-dot { top: -4px; left: -4px; right: auto; }   /* coin haut-GAUCHE : le compteur occupe le haut-droite */
.loadout-empty { text-align: center; opacity: 0.6; font-size: 13px; padding: 18px 0; }
.loadout-test { width: 100%; font-size: 12px; letter-spacing: 0.5px; opacity: 0.8; margin-bottom: 10px; border-style: dashed; }
.style-getinfo { text-align: center; font-size: 13px; opacity: 0.72; margin: 4px 0 12px; line-height: 1.4; }

/* ---- loadout footer (Fusion + Done) ---- */
.loadout-foot { display: flex; gap: 10px; }
.loadout-foot .btn { flex: 1 1 0; }
.btn-fusion span { display: inline-flex; align-items: center; gap: 6px; }

/* ---- fusion screen ---- */
.fusion-panel { max-width: 420px; }
.fusion-list { max-height: 56vh; overflow-y: auto; margin-bottom: 14px; }
.fusion-cat { margin-bottom: 14px; }
.fusion-cat-name { display: block; font-size: 11px; letter-spacing: 1.5px; text-transform: uppercase; opacity: 0.55; margin: 0 0 6px 2px; }
.fusion-row { display: flex; align-items: center; gap: 8px; padding: 6px 4px; }
.fusion-src, .fusion-tgt { position: relative; width: 42px; height: 42px; border-radius: 12px; display: flex; align-items: center; justify-content: center; background: var(--card); border: 1px solid var(--card-edge); flex: 0 0 auto; }
.fusion-src .bonus-ic-img, .fusion-tgt .bonus-ic-img { width: 28px; height: 28px; object-fit: contain; }
.fusion-tgt { border-color: var(--gold); }
.fusion-src b { position: absolute; top: -5px; right: -4px; min-width: 16px; height: 16px; border-radius: 999px; background: var(--mint); color: #06321f; font-family: 'Nunito', sans-serif; font-weight: 900; font-size: 10px; display: flex; align-items: center; justify-content: center; padding: 0 3px; }
.fusion-arrow { opacity: 0.5; font-weight: 900; }
.fusion-row .btn-mini { margin-left: auto; white-space: nowrap; }
.fusion-undo-sub { font-size: 12px; opacity: 0.65; margin: 2px 2px 8px; }
.fusion-undo-row { display: flex; flex-wrap: wrap; gap: 8px; }

/* ---- leaderboard: Classé/Non-classé split sits above the sub-tabs ---- */
#view-board .board-rank-tabs { margin-bottom: 8px; }
#view-board .board-rank-tabs .seg.on { background: linear-gradient(180deg, var(--gold), #d99b1a); color: #3a2700; }

/* ---- real-money jewel packs: value anchoring + daily deal ---- */
.pack-card { position: relative; }
/* owner : illustration dédiée par pack de joyaux (poignée -> multi-coffre). Plus grande que le glyphe gemme (30px). */
.pack-img { width: 68px; height: 68px; max-width: 100%; object-fit: contain; display: block; margin: 2px auto 0; filter: drop-shadow(0 3px 6px rgba(70, 40, 120, .28)); }
.pack-badge { position: absolute; top: -8px; left: 50%; transform: translateX(-50%); white-space: nowrap;
  font-size: 9px; font-weight: 900; letter-spacing: 0.5px; padding: 2px 8px; border-radius: 999px; color: #2a1c00; }
.badge-best { background: linear-gradient(180deg, var(--gold), #d99b1a); }
.badge-pop  { background: linear-gradient(180deg, var(--mint), #38b487); color: #052a1c; }
.pack-bonus { display: block; font-size: 12px; font-weight: 900; color: var(--mint); margin: 1px 0 5px; }
.pack-bonus-spacer { display: block; height: 14px; margin: 1px 0 5px; }
.deal-card { position: relative; border: 2px solid var(--gold); box-shadow: 0 0 14px rgba(255, 200, 61, 0.25); }
.deal-badge { position: absolute; top: -9px; left: 50%; transform: translateX(-50%); white-space: nowrap;
  font-size: 9px; font-weight: 900; letter-spacing: 0.5px; padding: 2px 9px; border-radius: 999px;
  background: linear-gradient(180deg, #ff7a59, #e24b4a); color: #fff; }
.deal-anchor { font-size: 11px; opacity: 0.7; margin: 2px 0; }
.deal-anchor s { opacity: 0.8; }
.deal-timer { font-size: 11px; font-weight: 800; color: var(--coral); margin-bottom: 6px; }

/* ---- Jewel Pass: home banner ---- */
.pass-banner { display: flex; align-items: center; gap: 10px; width: min(320px, 86%); margin: 4px auto 2px;
  padding: 10px 14px; border-radius: 16px; cursor: pointer; color: #fff; text-align: left;
  background: linear-gradient(110deg, #5b3aa6, #8b54d6 55%, #c06fd6); border: 1px solid rgba(255,255,255,0.18);
  box-shadow: 0 6px 16px rgba(120, 60, 200, 0.3); }
.pass-banner:active { transform: translateY(2px); }
.pass-banner-ic { width: 22px; height: 22px; object-fit: contain; vertical-align: middle; }
.pass-banner-txt { display: flex; flex-direction: column; line-height: 1.15; flex: 1; }
.pass-banner-txt b { font-size: 14px; letter-spacing: 1px; }
.pass-banner-sub { font-size: 11px; opacity: 0.85; }
.pass-banner-arrow { font-size: 22px; opacity: 0.7; font-weight: 700; }

/* ---- Jewel Pass: screen ---- */
.pass-panel { max-width: 440px; }
.pass-season { text-align: center; opacity: 0.7; font-size: 13px; margin: -4px 0 10px; }
.pass-prog { height: 10px; border-radius: 999px; background: var(--card); overflow: hidden; border: 1px solid var(--card-edge); }
.pass-prog i { display: block; height: 100%; background: linear-gradient(90deg, #8b54d6, #c06fd6); border-radius: 999px; transition: width 0.4s; }
.pass-prog-txt { text-align: center; font-size: 12px; opacity: 0.8; margin: 6px 0 10px; }
.pass-unlock { width: 100%; margin-bottom: 12px; font-size: 13px; }
.pass-lanes-head { display: grid; grid-template-columns: 34px 1fr 1fr; gap: 8px; padding: 0 2px 6px; }
.pass-lane-lbl { grid-column: 2; font-size: 10px; letter-spacing: 1.5px; opacity: 0.55; text-align: center; }
.pass-lane-lbl.prem { grid-column: 3; color: #c79bf0; opacity: 0.9; }
.pass-track { max-height: 50vh; overflow-y: auto; display: flex; flex-direction: column; gap: 8px; padding: 2px; }
.pass-row { display: grid; grid-template-columns: 34px 1fr 1fr; gap: 8px; align-items: stretch; }
.pass-tier-no { display: flex; align-items: center; justify-content: center; font-weight: 900; font-size: 13px; opacity: 0.5; }
.pass-row.reached .pass-tier-no { opacity: 1; color: var(--mint); }
.pass-cell { position: relative; min-height: 52px; border-radius: 12px; display: flex; align-items: center; justify-content: center;
  background: var(--card); border: 1px solid var(--card-edge); cursor: default; }
.pass-cell.prem { background: linear-gradient(160deg, rgba(139,84,214,0.18), var(--card)); border-color: rgba(139,84,214,0.4); }
.pass-cell.claimable { cursor: pointer; border-color: var(--gold); box-shadow: 0 0 8px rgba(255,200,61,0.25); }
.pass-cell.claimed { opacity: 0.45; }
.pass-cell.locked { opacity: 0.5; }
.pass-rw { display: inline-flex; align-items: center; gap: 4px; font-weight: 800; font-size: 13px; position: relative; }
.pass-rw .bonus-ic-img { width: 26px; height: 26px; object-fit: contain; }
.pass-rw b { position: absolute; top: -6px; right: -8px; font-size: 10px; background: var(--mint); color: #06321f; border-radius: 999px; padding: 0 3px; }
.pass-rw.pass-box { font-size: 22px; }
.pass-check { position: absolute; top: 3px; right: 5px; width: 13px; height: 13px; object-fit: contain; }
.pass-lock { position: absolute; top: 3px; right: 5px; width: 12px; height: 12px; object-fit: contain; opacity: 0.7; }
.pass-foot { display: flex; gap: 10px; margin-top: 12px; }
.pass-foot .btn { flex: 1; }

/* ---- round clear (cash in / continue) ---- */
.round-panel { max-width: 360px; text-align: center; }
.round-sub { font-size: 13px; opacity: 0.7; margin: -4px 0 14px; }
.round-rewards { display: flex; justify-content: center; gap: 14px; margin-bottom: 18px; }
.round-rw { display: inline-flex; align-items: center; gap: 5px; font-size: 18px; font-weight: 900; }
/* owner T28 — décorticage de l'XP de victoire : chaque source glisse en séquence, séparateur, puis TOTAL plus gros */
.round-rewards.xpb { flex-direction: column; gap: 9px; align-items: stretch; margin: 4px 0 16px; }
.xpb-row { display: flex; align-items: baseline; justify-content: space-between; gap: 14px;
  opacity: 0; transform: translateY(9px) scale(.96);
  transition: opacity .26s ease, transform .36s cubic-bezier(.22, 1.25, .36, 1); }
.xpb-row.in { opacity: 1; transform: none; }
.xpb-label { font-weight: 800; color: var(--dp-ink, #2a1a4d); font-size: 15px; text-align: left; }
/* owner T49c : sous-lignes indentées du détail de « Finesse » (multi-lignes / combos) */
.xpb-sub { margin-top: -2px; }
.xpb-sub .xpb-label { padding-left: 16px; font-size: 12.5px; font-weight: 700; opacity: 0.72; }
.xpb-sub .xpb-label::before { content: '↳'; margin-right: 5px; opacity: 0.6; }
.xpb-sub .xpb-amt { font-size: 13px; opacity: 0.8; }
.xpb-amt { font-weight: 900; color: var(--dp-coral-lip, #d24467); font-size: 16px; font-variant-numeric: tabular-nums; white-space: nowrap; }
.xpb-sep { height: 2px; width: 100%; border-radius: 2px; background: rgba(42, 26, 77, .14);
  opacity: 0; transform: scaleX(.35); transform-origin: center;
  transition: opacity .2s ease, transform .3s ease; margin: 1px 0; }
.xpb-sep.in { opacity: 1; transform: none; }
.xpb-total { opacity: 0; transform: translateY(11px) scale(.9);
  transition: opacity .3s ease, transform .44s cubic-bezier(.22, 1.5, .36, 1); }
.xpb-total.in { opacity: 1; transform: none; }
.xpb-total .xpb-label { font-size: 20px; font-weight: 900; }
.xpb-total .xpb-amt { font-size: 27px; color: var(--dp-ink, #2a1a4d); }
#ovRound .btn { width: 100%; margin-top: 8px; }
#ovRound .btn-gold { box-shadow: 0 4px 0 rgba(0,0,0,0.3); }

/* ---- mode/ranked switch warning ---- */
.switch-msg { text-align: center; font-size: 14px; line-height: 1.5; opacity: 0.85; margin: 4px 0 16px; }
.switch-msg b { color: var(--gold); }
#ovModeSwitch .btn { width: 100%; margin-top: 8px; }

.bonus-uses { display: flex; gap: 4px; align-items: center; padding: 0 4px; }
.bonus-uses i { width: 8px; height: 8px; border-radius: 50%; background: rgba(255, 255, 255, 0.12); }
.bonus-uses i.lit { background: var(--mint); box-shadow: 0 0 6px var(--mint); }
.bonus-uses.refill {
  font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 11px; letter-spacing: 1px;
  color: var(--gold); cursor: pointer;
  background: rgba(255, 200, 61, 0.1);
  border: 1px solid rgba(255, 200, 61, 0.35);
  border-radius: 10px; padding: 6px 8px;
}
#board.targeting { outline: 2px dashed var(--gold); outline-offset: 4px; cursor: crosshair; }
/* PHASE 4 §5.5 — a whole-board power-up armed: the grid becomes a big yellow CONFIRM button (tap to fire, tap outside to cancel) */
#boardWrap.board-confirm { cursor: pointer; }
#boardWrap.board-confirm::after {
  content: ''; position: absolute; inset: 0; z-index: 8; pointer-events: none; border-radius: 16px;
  background: radial-gradient(circle at 50% 44%, rgba(255, 213, 74, 0.30), rgba(255, 190, 7, 0.12) 70%);
  box-shadow: inset 0 0 0 3px var(--gold, #ffd54a), 0 0 26px 5px rgba(255, 193, 7, 0.5);
  animation: board-confirm-pulse 1s ease-in-out infinite;
}
@keyframes board-confirm-pulse { 0%, 100% { opacity: 0.7; } 50% { opacity: 1; } }
/* thematic full-board flash when a whole-board power-up fires */
.board-flash {
  position: absolute; inset: 0; z-index: 9; pointer-events: none; border-radius: 16px;
  background: radial-gradient(circle at 50% 48%, var(--bf, #ffd54a), transparent 68%);
  animation: board-flash 0.5s ease-out forwards;
}
@keyframes board-flash { 0% { opacity: 0; transform: scale(0.6); } 30% { opacity: 0.82; } 100% { opacity: 0; transform: scale(1.14); } }

/* ===== Bonus (power-up) FX — T105 ==========================================
   One-shot, self-removing overlays anchored to the cell grid (phantoms layer).
   Every effect is a single CSS keyframe/transition then removed via setTimeout:
   NO infinite animation, NO rAF loop, NO will-change on board cells (the earlier
   bloom/rAF work overheated devices — these stay transient + GPU-cheap). */
.fx-ring {
  position: absolute; width: 0; height: 0; border-radius: 50%;
  transform: translate(-50%, -50%); pointer-events: none; z-index: 8;
  border: 3px solid var(--rc, #fff);
  box-shadow: 0 0 12px var(--rc, #fff), inset 0 0 8px var(--rc, #fff);
  animation: fx-ring var(--rd, 520ms) ease-out forwards;
}
@keyframes fx-ring {
  0% { width: 6px; height: 6px; opacity: 0.95; }
  100% { width: var(--rs, 150px); height: var(--rs, 150px); opacity: 0; }
}
/* glint pulse on an upgraded gem */
.fx-glint {
  position: absolute; pointer-events: none; z-index: 7; border-radius: 32%;
  background: radial-gradient(circle at 50% 42%, var(--gc, #fff), transparent 70%);
  mix-blend-mode: screen;
  animation: fx-glint 0.5s ease-out forwards;
}
@keyframes fx-glint {
  0% { opacity: 0; transform: scale(0.5); }
  35% { opacity: 0.9; transform: scale(1.18); }
  100% { opacity: 0; transform: scale(1.45); }
}
/* juicy squash-then-pop on a hatching / bursting cell */
.cell.fx-pop { animation: fx-pop 0.42s cubic-bezier(0.34, 1.6, 0.5, 1); }
@keyframes fx-pop { 0% { transform: scale(0.2); } 55% { transform: scale(1.18); } 100% { transform: scale(1); } }
/* crumble + dull on a lowered gem */
.cell.fx-crumble { animation: fx-crumble 0.4s ease-in; }
@keyframes fx-crumble {
  0% { transform: scale(1); filter: brightness(1); }
  40% { transform: scale(0.84) rotate(-4deg); filter: brightness(0.55) saturate(0.5); }
  100% { transform: scale(1) rotate(0); filter: brightness(1); }
}

/* box slots on home */
.box-slot {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 6px; min-height: 124px;
  position: relative;
}
.box-slot.is-empty { border-style: dashed; opacity: 0.75; }
/* owner : écrin EN COURS D'OUVERTURE -> cadre BLEU clair (accordé au compte à rebours dynamique #3fa2ff) */
.box-slot.is-opening { border-color: #5cb3ff !important; background: rgba(63, 162, 255, 0.14) !important; box-shadow: 0 0 0 1px #3fa2ff, 0 4px 16px rgba(63, 162, 255, 0.32), inset 0 0 24px rgba(63, 162, 255, 0.22) !important; }   /* owner : fond nettement plus BLEU pendant l'ouverture */
/* a freshly-collected box dropping into a just-freed slot (level-end open-to-make-room flow) */
@keyframes slotPop { 0% { transform: scale(0.35); opacity: 0; } 60% { transform: scale(1.1); opacity: 1; } 100% { transform: scale(1); } }
.box-slot.slot-pop { animation: slotPop 0.5s cubic-bezier(0.34, 1.6, 0.5, 1); }
.slot-empty { display: flex; flex-direction: column; align-items: center; gap: 6px; }
/* empty slot shows a GHOST box (faded + desaturated) so it doesn't look like a real,
   openable common box. (boxImg returns an <img> now, so target that, not svg.) */
.slot-empty .box-img { filter: grayscale(1) brightness(1.6) contrast(0.7); opacity: 0.3; }
.slot-empty p { font-size: 11px; color: var(--text-dim); text-align: center; line-height: 1.35; }
.slot-art { filter: drop-shadow(0 6px 12px rgba(0, 0, 0, 0.4)); }
.box-slot.rar-legendary .slot-art { filter: drop-shadow(0 0 16px rgba(255, 200, 61, 0.45)); }
.box-slot.rar-mythic .slot-art { filter: drop-shadow(0 0 18px rgba(255, 110, 199, 0.55)); }
.box-slot.rar-epic .slot-art { filter: drop-shadow(0 0 14px rgba(176, 122, 255, 0.4)); }
.box-slot.is-ready .slot-art { animation: ready-bounce 0.9s ease-in-out infinite; }
@keyframes ready-bounce { 50% { transform: translateY(-5px) rotate(-2deg); } }
.slot-timer {
  font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 17px;
  color: var(--sky); letter-spacing: 1px;
}
/* owner : carte d'écrin ÉPURÉE (image + rareté + temps, cliquable) + POP-UP de détail au clic */
.box-slot.box-clickable { cursor: pointer; }
.slot-time { font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 14px; color: var(--text-dim); letter-spacing: .5px; margin-top: 1px; }
.slot-time.ready { color: var(--gold, #ffc83d); }
.box-slot.rd-timed .slot-time { visibility: hidden; }   /* owner : on RÉSERVE la place du texte (au lieu de display:none) -> l'illustration garde la même taille ET la même position entre un écrin en attente et un écrin en cours d'ouverture ; la pastille rd-timer s'affiche par-dessus */
.boxdetail-panel { position: relative; overflow: visible; padding-top: 76px; text-align: center; max-width: 340px; width: 88vw; }
.boxdetail-panel .bd-art { position: absolute; top: -58px; left: 50%; transform: translateX(-50%); pointer-events: none; }
.boxdetail-panel .bd-art .box-img { filter: drop-shadow(0 10px 16px rgba(0, 0, 0, 0.45)); }
.bd-name { font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 20px; margin: 0 0 3px; }
.bd-time { font-size: 13px; font-weight: 800; color: var(--text-dim); margin-bottom: 14px; }
.bd-rows { display: flex; flex-direction: column; gap: 7px; margin-bottom: 16px; }
.bd-rows .ci-row { display: flex; align-items: center; gap: 8px; }
.bd-rows .ci-lbl { font-weight: 700; }
.ci-val { margin-left: auto; font-weight: 900; }
.bd-rows .ci-sub { font-size: 11px; opacity: 0.6; margin: -3px 0 1px; line-height: 1.3; }   /* owner T83b : rareté du cosmétique sous la ligne « Cosmétique X% » */
.bd-btns { display: flex; flex-direction: column; gap: 8px; }
.bd-full { width: 100%; }
.bd-two { display: grid; grid-template-columns: 1fr 1.2fr; gap: 8px; align-items: start; }
.bd-ad-col { display: flex; flex-direction: column; align-items: center; gap: 3px; }
.bd-ad-col .btn { width: 100%; }
.bd-ad-count { font-size: 11px; font-weight: 800; color: var(--text-dim); }
/* owner T55 : quota pub quotidien epuise -> bouton grise + petit compte a rebours de renouvellement */
.btn-ad.bd-ad-spent { filter: grayscale(0.9) brightness(0.9); opacity: 0.5; cursor: default; box-shadow: none; }
.bd-ad-count.bd-ad-renew { font-size: 9.5px; line-height: 1.15; text-align: center; }
.bd-price { display: inline-flex; align-items: center; gap: 3px; margin-left: 7px; font-size: 12.5px; opacity: .95; }
/* bouton « Ouvrir maintenant » (owner) : libellé petit en haut, prix gros à la ligne en bas */
.bd-nowbtn { display: flex; flex-direction: column; align-items: center; gap: 1px; line-height: 1.08; padding-top: 9px; padding-bottom: 9px; }
.bd-now-lbl { font-size: 11.5px; font-weight: 800; letter-spacing: .3px; opacity: .92; }
.bd-now-price { display: inline-flex; align-items: center; gap: 3px; font-size: 19px; }
.bd-now-price .jewel-mini { width: 15px; height: 15px; vertical-align: 0; }
.bd-close { position: absolute; top: 8px; right: 12px; background: none; border: none; font-size: 25px; line-height: 1; color: var(--text-dim); cursor: pointer; z-index: 3; padding: 0; }

/* box ceremony: spinning rays + loot */
.box-panel { position: relative; overflow: hidden; }
/* cartoon sunburst: hard-edged wedges alternating TWO tints of the rarity colour (--rc),
   radiating from the box and fading at the rim */
/* WebKit-safe rays: NO mask (iOS drops masks on animated/blended layers -> the "cut-off square").
   The donut fade is PAINTED as opaque black layers over the wedges; mix-blend-mode:screen makes black
   invisible on any backdrop. Geometric circle + small box scaled up keeps the texture under iOS limits. */
.rays {
  position: absolute; left: 50%; top: 35%;
  width: 100vmax; height: 100vmax; border-radius: 50%;
  transform: translate(-50%, -50%) scale(2);
  --ray-a: color-mix(in srgb, var(--rc, #b07aff) 78%, white 22%);
  background:
    radial-gradient(circle, rgba(0, 0, 0, .55) 0%, #000 42%, #000 100%),
    repeating-conic-gradient(from 0deg, var(--ray-a) 0deg 6deg, transparent 6deg 18deg);
  mix-blend-mode: screen;
  opacity: 0; transition: opacity 0.45s ease;
  animation: rays-spin2 22s linear infinite;
  pointer-events: none;
}
.rays.on { opacity: 0.22; }   /* owner (3e passe) : encore plus faibles, s'estompent tôt en s'éloignant du centre */
@keyframes rays-spin { to { transform: translate(-50%, -50%) rotate(360deg); } }
@keyframes rays-spin2 { to { transform: translate(-50%, -50%) scale(2) rotate(360deg); } }
.reveal-card { position: relative; z-index: 1; }
.wp-swatch {
  display: inline-block; width: 56px; height: 38px; border-radius: 9px;
  border: 1px solid rgba(255, 255, 255, 0.18);
}
.wp-swatch.locked { filter: grayscale(0.8) brightness(0.55); }
.bonus-swatch {
  display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; border-radius: 12px;
  background: rgba(255, 255, 255, 0.06);
  color: var(--gold); font-style: normal;
}
.bonus-swatch svg { width: 26px; height: 26px; }
.bonus-swatch .bonus-ic-img { width: 32px; height: 32px; object-fit: contain; display: block; }
.loot-line {
  display: inline-flex; align-items: center; gap: 4px;
  font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 17px;
  color: var(--gold);
}
.go-box {
  display: flex; align-items: center; gap: 10px;
  font-size: 13px; font-weight: 900;
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid var(--card-edge);
  border-radius: 14px; padding: 8px 14px;
  text-align: left; line-height: 1.3;
}
.go-box svg { flex-shrink: 0; }
.go-box.rar-rare { border-color: rgba(77, 196, 255, 0.4); }
.go-box.rar-epic { border-color: rgba(176, 122, 255, 0.4); }
.go-box.rar-legendary { border-color: rgba(255, 200, 61, 0.5); box-shadow: 0 0 16px rgba(255, 200, 61, 0.2); }
.go-box.rar-mythic { border-color: rgba(255, 110, 199, 0.55); box-shadow: 0 0 18px rgba(255, 110, 199, 0.25); }

/* loot flying to the topbar counters */
.fly-sprite {
  position: fixed; z-index: 400;
  width: 16px; height: 16px;
  pointer-events: none;
  transition: transform 0.55s cubic-bezier(0.4, -0.1, 0.7, 1), opacity 0.55s;
}
.fly-sprite.coin {
  border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, #ffe28a, var(--gold) 60%, var(--gold-deep));
  box-shadow: 0 0 8px rgba(255, 200, 61, 0.7);
}
.fly-sprite.jewel {   /* owner : vraie image de joyau (l'ancien diamant CSS violet = 1re version abandonnée depuis longtemps) + un peu plus grand */
  width: 22px; height: 22px;
  background: url(assets/ui/jewel.webp) center/contain no-repeat;
  filter: drop-shadow(0 0 5px rgba(150, 90, 255, 0.55));
}

/* ---- box loot: floating, clickable rewards that fly to their home ---- */
.loot-orb {
  position: absolute; z-index: 3;
  width: 76px; min-height: 84px; padding: 0;
  background: none; border: 0; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  -webkit-tap-highlight-color: transparent;
  animation: loot-rise 0.55s cubic-bezier(0.2, 1.4, 0.5, 1) both;
  transition: transform 0.52s cubic-bezier(0.5, -0.25, 0.7, 1), opacity 0.5s ease;
}
.loot-bob { display: flex; flex-direction: column; align-items: center; gap: 5px; animation: loot-bob 2.6s ease-in-out infinite; }
.loot-orb:active .loot-bob { transform: scale(0.9); }
@keyframes loot-rise { from { transform: translateY(64px) scale(0.2); opacity: 0; } to { transform: none; opacity: 1; } }
@keyframes loot-bob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-6px); } }
.loot-art { display: flex; align-items: center; justify-content: center; filter: drop-shadow(0 4px 10px rgba(0, 0, 0, 0.45)); }
.loot-ic { display: block; width: 60px; height: 60px; background: center/contain no-repeat; }
.loot-ic.coin-ic { background-image: url(assets/ui/coins.webp); }   /* owner : tas de pièces dans les écrans de récompense */
.loot-ic.jewel-ic { background-image: url(assets/ui/jewel.webp); }
.loot-tile {
  display: flex; align-items: center; justify-content: center;
  width: 64px; height: 64px; border-radius: 16px;
  background-size: cover; background-position: center;
  background-color: rgba(255, 255, 255, 0.06);
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.5), inset 0 0 0 1px rgba(255, 255, 255, 0.18);
}
.loot-tile.tile-bonus { background: rgba(255, 255, 255, 0.08); color: var(--gold); }
.loot-tile.tile-bonus .bonus-ic-img, .loot-tile.tile-bonus svg { width: 40px; height: 40px; object-fit: contain; }
.loot-tile.tile-theme { gap: 3px; flex-wrap: wrap; padding: 9px; }
.loot-tile.tile-theme .swatch-row { display: grid; grid-template-columns: 1fr 1fr; gap: 4px; margin: 0; }
.loot-tile.tile-theme .swatch-row i { width: 18px; height: 18px; border-radius: 5px; }
.loot-style.rarity-legendary .loot-tile { box-shadow: 0 6px 18px rgba(255, 200, 61, 0.4), inset 0 0 0 1px rgba(255, 200, 61, 0.6); }
.loot-style.rarity-mythic .loot-tile { box-shadow: 0 6px 18px rgba(255, 110, 199, 0.45), inset 0 0 0 1px rgba(255, 110, 199, 0.65); }
.loot-style.rarity-epic .loot-tile { box-shadow: 0 6px 16px rgba(176, 122, 255, 0.4), inset 0 0 0 1px rgba(176, 122, 255, 0.55); }
/* wallpaper reward: a REAL, portrait preview of the wallpaper, framed in its rarity colour */
.loot-tile.tile-wp {
  width: 58px; height: 86px; border-radius: 13px;
  border: 2.5px solid var(--rc, #fff);
}
.loot-amt {
  font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 17px;
  color: #fff; text-shadow: 0 2px 0 rgba(0, 0, 0, 0.6);
}
/* a style's name under its icon — gives the reward weight */
.loot-name {
  font-family: 'Nunito', sans-serif; font-weight: 800; font-size: 12.5px;
  color: #fff; text-shadow: 0 2px 0 rgba(0, 0, 0, 0.65);
  max-width: 104px; text-align: center; line-height: 1.12; white-space: normal;
}
.loot-hint {
  position: absolute; left: 50%; top: 66%; transform: translateX(-50%); z-index: 1;
  font-size: 13px; font-weight: 800; color: var(--text-dim);
  opacity: 0; transition: opacity 0.4s ease 0.2s;
  text-align: center; width: max-content; max-width: 86vw;
}
.loot-hint.show { opacity: 1; }
/* the "collect all" button sits between the floating rewards and the hint */
.loot-collect-all {
  position: absolute; left: 50%; top: 59%; transform: translateX(-50%); z-index: 4;
  padding: 11px 26px; font-size: 15px; white-space: nowrap;
  animation: loot-cta-in 0.4s ease 0.15s both;
}
@keyframes loot-cta-in { from { opacity: 0; transform: translateX(-50%) translateY(8px); } to { opacity: 1; transform: translateX(-50%) translateY(0); } }
/* the live "total" UI a reward flies into: mirrors the real counter/menu at its spot */
.loot-target {
  position: absolute; z-index: 2;
  display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 13px; border-radius: 999px;
  background: var(--card); border: 1px solid var(--card-edge);
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.45);
  font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 16px; color: var(--text);
  opacity: 0; transform: scale(0.8); transition: opacity 0.25s ease, transform 0.25s ease;
}
.loot-target.show { opacity: 1; transform: scale(1); }
.loot-target .coin-ic, .loot-target .jewel-mini { width: 20px; height: 20px; }
.loot-target .lt-bonus-ic { display: inline-flex; width: 22px; height: 22px; }
.loot-target .lt-bonus-ic .bonus-ic-img, .loot-target .lt-bonus-ic svg { width: 100%; height: 100%; object-fit: contain; }
.loot-target .lt-styles { font-size: 13px; letter-spacing: 1px; color: var(--coral); }
.loot-target.lt-bump { animation: loot-bump 0.42s ease; }
/* the target counter/button gives a little bump as a reward lands */
.loot-bump { animation: loot-bump 0.42s ease; }
@keyframes loot-bump { 40% { transform: scale(1.18); } 100% { transform: scale(1); } }

/* square rounded "tile" preview for styles with no swatch (soundtracks) */
.style-tile {
  display: inline-flex; align-items: center; justify-content: center;
  width: 54px; height: 54px; border-radius: 14px;
  background-size: cover; background-position: center;
  background-color: rgba(255, 255, 255, 0.06);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.16);
}
.style-tile.locked { filter: grayscale(0.85) brightness(0.5); }

/* collection sections: Owned first, then a clearly separated To-unlock block */
.coll-sec-head {
  grid-column: 1 / -1;
  display: flex; align-items: center; gap: 8px;
  font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 13px; letter-spacing: 1.5px;
  color: var(--text-dim); text-transform: uppercase;
  margin: 6px 2px 0;
}
.coll-sec-head b { color: var(--text); font-size: 12px; opacity: 0.75; }
.coll-sec-head.locked { color: var(--coral); margin-top: 14px; padding-top: 12px; border-top: 1px dashed var(--card-edge); }
.coll-sec-empty { grid-column: 1 / -1; font-size: 12.5px; color: var(--text-dim); padding: 2px 4px 6px; }
/* unowned styles read as "to get": faded preview, no equip tint */
.theme-card.is-locked { opacity: 0.94; background: rgba(255, 255, 255, 0.015); }
.theme-card.is-locked .swatch-row { filter: grayscale(0.7) brightness(0.62); }
.theme-card.is-locked .theme-name { color: var(--text-dim); }

/* ---- collection: 3-up style previews + tap-to-enlarge detail ---- */
.coll-grid, .coll-grid.one { display: block; }   /* now holds section heads + nested 3-up prev-grids */
.prev-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; margin: 8px 0 4px; }   /* owner : 3 covers/rangée sur mobile (minmax(0,1fr) empêche le débordement des tuiles) */

/* uniform SET / PACK shop cards (daily rotation) */
.shop-set-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin: 8px 0 4px; }
.shop-set {
  position: relative; display: flex; flex-direction: column; align-items: center; gap: 7px;
  padding: 14px 12px 13px; border-radius: 18px; background: var(--card, #1b1626);
  border: 1px solid rgba(255, 255, 255, 0.08); box-shadow: 0 6px 16px rgba(0, 0, 0, 0.35);
}
.ssc-badge { position: absolute; top: 9px; left: 9px; font-size: 9px; font-weight: 900; letter-spacing: 1px; padding: 2px 7px; border-radius: 999px; color: #2a1f0a; }
.ssc-badge.ssc-set { background: linear-gradient(180deg, #b0b6c4, #8a90a0); }
.ssc-badge.ssc-pack { background: linear-gradient(180deg, #ffce54, #e6a216); }
.ssc-prev { display: grid; grid-template-columns: repeat(3, 1fr); gap: 4px; width: 100%; margin-top: 8px; }
.ssc-chip { aspect-ratio: 1; }
.ssc-chip > i { display: block; width: 100%; height: 100%; }
.ssc-extras { display: flex; gap: 6px; margin-top: 2px; }
.ssc-ex { width: 26px; height: 26px; border-radius: 7px; background-size: cover; background-position: center; border: 1px solid rgba(255, 255, 255, 0.15); }
.ssc-name { font-size: 14px; font-weight: 800; text-align: center; line-height: 1.15; }
.ssc-sub { font-size: 10px; opacity: 0.6; text-align: center; margin-top: -3px; }
.ssc-buy { margin-top: 4px; min-width: 96px; }
.style-prev {
  position: relative;
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding: 8px 6px 9px; border: 0; cursor: pointer;
  background: var(--card); border-radius: 16px;
  box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--rc, #888) 55%, transparent), 0 6px 16px rgba(0, 0, 0, 0.35);
  -webkit-tap-highlight-color: transparent;
  transition: transform 0.12s ease;
}
.style-prev:active { transform: scale(0.96); }
.style-prev.equipped { box-shadow: inset 0 0 0 2.5px var(--mint), 0 6px 16px rgba(0, 0, 0, 0.35); }
.prev-art {
  display: block; width: 100%; border-radius: 11px; overflow: hidden;
  background: var(--cell-empty); background-size: cover; background-position: center;
}
.prev-wp { aspect-ratio: 1 / 1; }                 /* owner : cover CARRÉE (comme les musiques) */
.prev-music { aspect-ratio: 1 / 1; }              /* square music cover */
.prev-theme { display: flex; align-items: center; justify-content: center; padding: 6px; }
.prev-theme:empty { min-height: 84px; }   /* hold the slot while the lazy mini-board is being built */
.prev-art.locked { filter: none; }   /* unowned miniatures are fully clear (the padlock marks them locked); only the enlarged view blurs */
.prev-lock { position: absolute; top: 38%; left: 50%; width: 24px; height: 24px; transform: translate(-50%, -50%); opacity: 0.92; pointer-events: none; filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.6)); }
/* owner : titre sur 2 lignes (plus coupé) + hauteur réservée sous la cover pour l'aligner sur toutes les tuiles */
.prev-name { font-size: 11px; font-weight: 800; color: var(--text); text-align: center; line-height: 1.15; max-width: 100%; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; min-height: 2.3em; }
.style-prev.is-locked .prev-name { color: var(--text-dim); }
/* "new item" notification dots: a pulsing coral dot on the tile (cleared once seen) + on its tab */
.new-dot {
  position: absolute; top: 7px; right: 7px; width: 11px; height: 11px; border-radius: 50%; z-index: 3;
  background: var(--coral, #ff5e6c); box-shadow: 0 0 0 2px var(--card), 0 0 8px rgba(255, 94, 108, 0.85);
  animation: newdot-pulse 1.4s ease-in-out infinite;
}
@keyframes newdot-pulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.28); } }
.avatar-cell { position: relative; }                 /* anchor the per-avatar new-dot */
.avatar-cell .new-dot { top: 6px; right: 10px; }
.prof-av-dot { top: 4px; right: 4px; width: 16px; height: 16px; }   /* on the big profile avatar circle */
#collTabs .seg { position: relative; }
.tab-dot {
  position: absolute; top: 4px; right: 6px; width: 8px; height: 8px; border-radius: 50%;
  background: var(--coral, #ff5e6c); box-shadow: 0 0 6px rgba(255, 94, 108, 0.7);
  animation: newdot-pulse 1.4s ease-in-out infinite;
}
.prev-eq { font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 9px; letter-spacing: 1px; color: var(--mint); }
/* owner : tag « édition spéciale » (ex. Pawlight Purr = même piste + ronronnements) — pastille sur la cover */
.prev-edition { position: absolute; top: 7px; left: 7px; z-index: 3; background: rgba(20, 16, 34, 0.74); color: #ffe9a8; font-size: 8.5px; font-weight: 800; letter-spacing: 0.3px; padding: 2px 7px; border-radius: 99px; box-shadow: 0 2px 6px rgba(0, 0, 0, 0.35); pointer-events: none; }

/* the mini-board preview for block styles (reuses .cell/.gem, sized by --cell) */
.board-prev { display: grid; grid-template-columns: repeat(6, var(--cell)); gap: calc(var(--cell) * 0.14); }
.prev-theme .board-prev { --cell: 13px; }
/* live "in game" mix preview at the top of the collection Blocks page */
.mix-preview { display: flex; flex-direction: column; align-items: center; gap: 8px; margin: 2px 0 16px; padding: 13px; border-radius: 16px; background: rgba(255, 255, 255, 0.03); border: 1px solid rgba(255, 255, 255, 0.06); }
.mix-prev-cap { font-size: 10px; letter-spacing: 1.5px; text-transform: uppercase; opacity: 0.55; font-weight: 700; }
.mix-preview .board-prev { --cell: 32px; }
.hero-theme .board-prev { --cell: 40px; }
/* the shop sits in a narrower card than the collection; the block preview is a fixed-size board
   that won't shrink, so the 3-up block tiles overflowed the card on narrower phones. In the SHOP
   only, scale the block preview to the viewport (capped) + tighten the grid so 3 always fit. */
.featured-body .prev-grid { gap: 8px; }
.featured-body .prev-theme { padding: 5px; }
.featured-body .prev-theme .board-prev { --cell: min(10px, 2.5vw); }

/* the detail modal */
.style-panel { gap: 13px; }
.style-hero-wrap { display: flex; align-items: center; justify-content: center; min-height: 210px; margin-top: 2px; }
.style-hero {
  position: relative; border-radius: 16px; overflow: hidden;
  border: 3px solid var(--rc, #fff);
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.5), 0 0 26px color-mix(in srgb, var(--rc, #fff) 38%, transparent);
}
.hero-fill { position: absolute; inset: 0; background-size: cover; background-position: center; }
.hero-fill.locked { filter: blur(3px) brightness(0.92) saturate(0.95); transform: scale(1.04); }   /* the enlarged preview is only LIGHTLY blurred (still clearly recognizable) */
.hero-wp { width: 228px; aspect-ratio: 3 / 4; }
.btn-sub { display: block; font-size: 9.5px; font-weight: 700; letter-spacing: .04em; opacity: .72; text-transform: none; margin-top: 1px; }
.hero-music { width: 192px; aspect-ratio: 1 / 1; display: flex; align-items: center; justify-content: center; }
.hero-theme { background: var(--ink); }
.hero-theme .hero-fill { position: static; padding: 14px; }

/* play button (music preview) */
.prev-play {
  position: relative; z-index: 1; width: 64px; height: 64px; border-radius: 50%; border: 0; cursor: pointer;
  background: rgba(0, 0, 0, 0.42); box-shadow: 0 4px 14px rgba(0, 0, 0, 0.5), inset 0 0 0 2px rgba(255, 255, 255, 0.5);
  display: flex; align-items: center; justify-content: center;
}
.prev-play::before { content: ''; width: 0; height: 0; margin-left: 5px; border-left: 20px solid #fff; border-top: 12px solid transparent; border-bottom: 12px solid transparent; }
.prev-play.playing::before { width: 17px; height: 17px; margin: 0; border: 0; background: #fff; border-radius: 3px; }   /* stop square */

.style-actions { display: flex; flex-direction: column; gap: 8px; align-items: center; }   /* owner : le texte « Se trouve dans... » sur sa PROPRE ligne, au-dessus du bouton (avant : en ligne -> ils s'ecrasaient) */
.style-actions .btn { min-width: 150px; }

/* boutique COFFRES : tuiles d'achat d'écrin par rareté (owner Lot 3) */
.shop-box-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; margin: 4px 0 16px; }
.shop-box-tile { position: relative; display: flex; flex-direction: column; align-items: center; gap: 7px; padding: 12px 6px 10px; border-radius: 16px; cursor: pointer;
  background: rgba(255, 255, 255, 0.92); border: 2.5px solid #fff; color: var(--dp-ink);
  box-shadow: 0 4px 0 var(--dp-depth, rgba(42, 26, 77, 0.14)), 0 7px 12px var(--dp-ambient, rgba(50, 25, 90, 0.14)); transition: transform 0.08s; }
.shop-box-tile:active { transform: translateY(2px); }
.shop-box-tile .sb-art { display: flex; }
.shop-box-tile .sb-art img { width: 64px; height: 64px; object-fit: contain; filter: drop-shadow(0 4px 5px rgba(40, 20, 70, 0.3)); }
.shop-box-tile .sb-name { font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 12.5px; letter-spacing: 0.3px; color: var(--dp-ink); }
.shop-box-tile .sb-price { font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 14px; color: #fff; -webkit-text-stroke: 1.4px var(--dp-ink); paint-order: stroke fill;
  background: linear-gradient(180deg, #ffd24a 0%, #f4b52e 55%, #eea01e 100%); border-radius: 999px; padding: 3px 13px; display: inline-flex; align-items: center; gap: 4px;
  box-shadow: 0 3px 0 #bd760c, 0 5px 9px rgba(90, 50, 0, 0.22); }
.shop-box-tile .sb-price .jewel-mini { filter: none; -webkit-text-stroke: 0; }

/* PACKS en PLEINE LARGEUR (owner) : art | nom+contenu | prix ; sans titre, PLUS d'espace entre eux */
.shop-bundles { display: flex; flex-direction: column; gap: 18px; margin: 8px 0 18px; }
.bundle-full { position: relative; display: flex; align-items: center; gap: 12px; padding: 12px 14px; border-radius: 18px; color: var(--dp-ink);
  background: var(--rar-bg, rgba(255,255,255,0.92)); border: 2.5px solid var(--rar-edge, #fff);
  box-shadow: 0 4px 0 rgba(42,26,77,0.12), 0 7px 14px rgba(50,25,90,0.14); }
.bundle-full .bf-art { display: flex; flex-wrap: wrap; gap: 4px 8px; align-items: center; justify-content: center; flex: 0 0 auto; max-width: 42%; }
.bundle-full .bf-art .st-box { position: relative; }
.bundle-full .bf-info { flex: 1; min-width: 0; text-align: left; }
.bundle-full .bf-name { font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 16px; color: var(--dp-ink); line-height: 1.1; }
.bundle-full .bf-contents { font-family: 'Nunito', sans-serif; font-weight: 800; font-size: 12px; color: rgba(42,26,77,0.7); margin-top: 3px; }
.bundle-full .bf-buy { flex: 0 0 auto; display: flex; flex-direction: column; align-items: center; gap: 1px; }
.bundle-full .bundle-off { right: 8px; top: -9px; }   /* rentré dans la carte (ne dépasse plus à droite) */

/* OFFRES DU JOUR : grille d'items seuls (comme les écrins) */
.shop-deals-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; margin: 2px 0 6px; }
.shop-deal-tile { position: relative; min-width: 0; display: flex; flex-direction: column; align-items: center; justify-content: space-between; gap: 6px; min-height: 132px;
  padding: 12px 6px 10px; border-radius: 16px; background: rgba(255,255,255,0.92); border: 2.5px solid #fff; color: var(--dp-ink); box-shadow: 0 3px 8px rgba(50,25,90,0.14); }
/* 1er deal (écrin commun / 200 pièces via pub) : MÊME format que les écrins payants (owner), léger surlignage */
.shop-deal-tile.deal-free-tile { background: linear-gradient(180deg, #fff7de, #ffeeb0); border-color: #ffca3a; }
.shop-deal-tile .sd-buy { max-width: 100%; }
.shop-deal-tile .sd-free { background: linear-gradient(180deg, #7ed957 0%, #58c74a 55%, #46ac3c 100%) !important; box-shadow: 0 3px 0 #3a8c34, 0 5px 9px rgba(30, 90, 20, 0.22) !important; color: #fff !important; -webkit-text-stroke: 0 !important; text-shadow: 0 1px 1.5px rgba(20, 70, 15, 0.45); display: inline-flex; align-items: center; gap: 5px; }   /* owner : « gratuit » blanc SANS contour (le contour ajoutait du bruit) — juste une ombre douce pour la lisibilité sur le vert */
.shop-deal-tile .sd-free .ad-ic { width: 17px; height: 17px; }

/* OFFRE LIMITÉE mise en avant (owner) : pleine largeur, centrée en haut ; capée en largeur sur desktop */
#shopLimited { display: flex; justify-content: center; }
.shop-limited { position: relative; width: 100%; max-width: 420px; display: flex; align-items: center; gap: 12px; margin: 2px 0 14px;
  padding: 13px 15px; border-radius: 18px; color: #fff;
  background: linear-gradient(135deg, #7b3ff2 0%, #b24bd8 55%, #ff5e9a 100%); border: 2.5px solid #fff;
  box-shadow: 0 6px 0 rgba(60, 20, 110, 0.45), 0 10px 22px rgba(80, 30, 140, 0.35); }
.shop-limited .deal-badge { position: absolute; top: -10px; left: 12px; transform: none; background: linear-gradient(180deg, #ff6f8a, #d24467); color: #fff;
  font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 11px; letter-spacing: 0.4px; padding: 3px 10px; border-radius: 999px; box-shadow: 0 2px 0 rgba(150, 20, 50, 0.4); }
.shop-limited .sl-art { width: 40px; height: 40px; flex: 0 0 auto; filter: drop-shadow(0 3px 5px rgba(0,0,0,0.3)); }
.shop-limited .sl-info { flex: 1; min-width: 0; }
.shop-limited .sl-amount { font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 21px; color: #fff; text-shadow: 0 2px 0 rgba(60,20,110,0.5); }
.shop-limited .sl-timer { font-family: 'Nunito', sans-serif; font-weight: 800; font-size: 12px; color: #ffe6a0; margin-top: 1px; }
.shop-limited .sl-buy { flex: 0 0 auto; font-size: 15px; padding: 9px 16px; }
/* note de rotation des offres du jour, désormais sur le fond (plus dans une carte) -> encre lisible */
.dl-note { color: rgba(42, 26, 77, 0.72); text-align: center; margin: 8px 0 14px; }
.dl-note b { color: var(--dp-coral-lip, #d24467); }

/* ROUE DE LA FORTUNE (owner) */
.shop-wheel-card { position: relative; width: 100%; display: flex; align-items: center; gap: 12px; margin: 2px 0 14px; padding: 12px 15px; border-radius: 18px; cursor: pointer; color: #fff;
  background: linear-gradient(135deg, #ff9a3e 0%, #ff5e9a 52%, #b24bd8 100%); border: 2.5px solid #fff; box-shadow: 0 5px 0 rgba(120, 30, 90, 0.4), 0 9px 20px rgba(150, 40, 120, 0.3); transition: transform 0.08s; }
.shop-wheel-card:active { transform: translateY(2px); }
.shop-wheel-card .sw-emoji { width: 40px; height: 40px; object-fit: contain; flex: 0 0 auto; animation: sw-wobble 2.4s ease-in-out infinite; }
.shop-wheel-card .sw-txt { flex: 1; text-align: left; display: flex; flex-direction: column; min-width: 0; }
.shop-wheel-card .sw-txt b { font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 18px; }
.shop-wheel-card .sw-txt span { font-family: 'Nunito', sans-serif; font-weight: 800; font-size: 12px; color: #ffe6a0; }
.shop-wheel-card .sw-go { font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 26px; opacity: 0.85; flex: 0 0 auto; }
@keyframes sw-wobble { 0%, 100% { transform: rotate(-8deg); } 50% { transform: rotate(8deg); } }

.wheel-panel { text-align: center; max-width: 380px; overflow: visible; }
.wheel-stage { position: relative; display: inline-block; vertical-align: middle; width: 388px; height: 388px; max-width: 94vw; aspect-ratio: 1; margin: 10px 0 16px; }   /* owner : roue agrandie + CENTRÉE. En inline-block, le `text-align:center` du panneau la centre symétriquement même quand elle déborde (un bloc + margin:auto s'alignait à GAUCHE et débordait à droite). */
/* owner : la roue est intégrée dans le cadre 3D fortune_wheel_frame (moyeu + socle) ; l'index rouge est SÉPARÉ (posé dessus, animé) ; le disque tourne DERRIÈRE, ajusté au cercle intérieur du cadre */
.wheel-frame { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; z-index: 2; pointer-events: none; }
/* owner : index rouge séparé, calé sur la pointe du cadre (un poil plus grand pour la couvrir) -> il tressaute (cliquetis) à chaque tranche qui passe */
.wheel-index { position: absolute; top: -1.5%; left: 50%; width: 15%; transform: translateX(-50%); transform-origin: 50% 50%; z-index: 3; pointer-events: none; filter: drop-shadow(0 3px 4px rgba(0,0,0,.32)); }
.wheel-index.tick { animation: whIdxTick .13s cubic-bezier(.3,1.5,.5,1); }
/* owner : à chaque tenon/intersection qui croise l'index, il subit une légère rotation NÉGATIVE sur son axe central (la pointe du bas part vers la droite), comme percuté par la roue qui tourne dans le sens horaire */
@keyframes whIdxTick { 0% { transform: translateX(-50%) rotate(0deg); } 35% { transform: translateX(-50%) rotate(-7deg); } 100% { transform: translateX(-50%) rotate(0deg); } }
/* owner : le disque REMPLIT exactement le cercle interne du cadre (mesuré : centre 50.1%/47.2%, ~77%) -> plus de vide blanc ; le cadre (z-index 2) masque le léger débord */
.wheel-disc { position: absolute; width: 80%; height: 80%; left: 10.1%; top: 7.2%; border-radius: 50%; transform: rotate(0deg); z-index: 1; }
/* owner : effet 3D des tranches (dôme brillant + bord ombré), SOUS les icônes (::before, pas ::after) */
.wheel-disc::before { content: ''; position: absolute; inset: 0; border-radius: 50%; pointer-events: none; background: radial-gradient(circle at 50% 30%, rgba(255,255,255,.42), rgba(255,255,255,0) 52%), radial-gradient(circle at 50% 60%, rgba(0,0,0,0) 56%, rgba(0,0,0,.26) 100%); }
.wh-item { position: absolute; top: 50%; left: 50%; display: flex; flex-direction: column; align-items: center; width: 60px; z-index: 1; }
.wh-ic { font-size: 30px; line-height: 1; display: grid; place-items: center; width: 50px; height: 50px; }   /* owner : icône de prix agrandie, SANS fond blanc (image seule) */
.wh-ic .coin-mini, .wh-ic .jewel-mini { width: 34px; height: 34px; filter: drop-shadow(0 2px 3px rgba(0,0,0,.5)); }
.wh-ic .box-img, .wh-img { width: 44px; height: 44px; object-fit: contain; display: block; filter: drop-shadow(0 2px 3px rgba(0,0,0,.55)); }   /* owner : icônes du jeu (écrins / bombe), ombre portée pour la lisibilité sans cadre blanc */
.wh-lb { font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 13px; color: #2a1a4d; margin-top: 2px; text-shadow: 0 1px 0 rgba(255, 255, 255, 0.6); }
.wheel-hub { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 50px; height: 50px; border-radius: 50%; background: radial-gradient(circle, #fff, #ffe0b0); border: 3px solid #ffca3a; display: grid; place-items: center; font-size: 24px; z-index: 2; box-shadow: 0 3px 8px rgba(40, 20, 70, 0.35); }
/* owner T89 : re-tour au choix pub/joyaux (empilés, pleine largeur -> tient dans le panneau étroit) */
.wheel-again-lbl { font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 14px; color: var(--dp-ink); opacity: .82; margin: 0 0 8px; }
.wheel-choice { display: flex; flex-direction: column; gap: 8px; margin-bottom: 10px; }
.wheel-choice .bd-ad-col { width: 100%; gap: 3px; }
.wheel-choice .btn { width: 100%; min-height: 46px; }
.shop-deal-tile .sd-art { display: grid; place-items: center; height: 54px; }
.shop-deal-tile button.sd-art { background: none; border: 0; padding: 0; margin: 0; width: 100%; cursor: pointer; }   /* owner G5 : l'illustration est un bouton d'aperçu -> reset du style bouton */
.shop-deal-tile .sd-art img { width: 46px; height: 46px; object-fit: contain; }
.shop-deal-tile .sd-cos { font-size: 36px; }
/* owner : cover d'un item cosmétique (fond/musique) dans un cadre teinté par la rareté, à la place de l'emoji */
.shop-deal-tile .sd-cos-frame { display: grid; place-items: center; width: 52px; height: 52px; border-radius: 12px; overflow: hidden; border: 2.5px solid #c9a2ff; box-shadow: 0 2px 7px rgba(40, 20, 70, 0.20); background: #fff; }
.shop-deal-tile .sd-cos-frame .sd-cos-img { width: 100%; height: 100%; object-fit: cover; display: block; }
.shop-deal-tile .sd-myst { font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 44px; color: #b78bff; -webkit-text-stroke: 2.5px var(--dp-ink); paint-order: stroke fill; }
.shop-deal-tile .sd-name { font-family: 'Nunito', sans-serif; font-weight: 800; font-size: 11px; color: var(--dp-ink); line-height: 1.12; text-align: center; }
.shop-deal-tile .sd-buy, .shop-deal-tile .sd-timer { font-size: 12px; }
.shop-deal-tile .sd-timer { color: rgba(42,26,77,0.6); font-weight: 800; }
.shop-deal-tile .sd-done { width: 26px; height: 26px; object-fit: contain; }
.shop-deal-tile.is-done { opacity: 0.55; }

/* shop promo: a corner ribbon + struck-through original price */
.promo-tag {
  position: absolute; top: 8px; right: 8px; z-index: 2;
  font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 11px; letter-spacing: 0.5px;
  color: #fff; background: var(--coral);
  border-radius: 999px; padding: 2px 8px;
  box-shadow: 0 3px 8px rgba(0, 0, 0, 0.3);
}
.price-was { opacity: 0.6; font-size: 0.82em; margin-right: 1px; text-decoration: line-through; }

/* shop */
#view-shop { gap: 12px; padding-bottom: 30px; }
.shop-section {
  font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 14px; letter-spacing: 2px;
  color: var(--text-dim); margin-top: 6px;
}
.shop-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.shop-grid.three { grid-template-columns: 1fr 1fr 1fr; }
.shop-card {
  display: flex; flex-direction: column; align-items: center; gap: 7px;
  padding: 12px 8px;
  position: relative;
  text-align: center;
  min-width: 0;   /* let grid cells shrink instead of overflowing the row */
}
.shop-name { font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 14px; max-width: 100%; }
.shop-card .btn { max-width: 100%; }
.shop-buys { display: flex; flex-direction: column; gap: 5px; width: 100%; align-items: stretch; }
.shop-buys .btn { width: 100%; white-space: nowrap; }
.shop-desc { font-size: 11px; color: var(--text-dim); line-height: 1.3; min-height: 28px; }
.shop-owned { font-size: 11px; color: var(--text-dim); }
.shop-card.soon { opacity: 0.75; overflow: hidden; }
.soon-tag {
  position: absolute; top: 6px; right: 6px;
  background: linear-gradient(180deg, var(--rar-epic), #7b2cbf);
  color: #fff;
  font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 10px; letter-spacing: 1.5px;
  padding: 3px 9px; border-radius: 999px;
  transform: rotate(6deg);
  box-shadow: 0 2px 0 #4c1d95;
}

/* settings */
.setting-row { display: flex; align-items: center; gap: 10px; width: 100%; }
.setting-name {
  font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 13px; letter-spacing: 1.5px;
  color: var(--text-dim); width: 86px; flex-shrink: 0;
}
.setting-mute { padding: 6px 8px; font-size: 15px; }
.setting-mute.muted { opacity: 0.45; }
.setting-mute .vol-ic { width: 20px; height: 20px; object-fit: contain; display: block; }
.setting-val {
  font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 15px;
  color: var(--gold); width: 22px; text-align: center;
}
input[type="range"] {
  flex: 1; min-width: 0;
  -webkit-appearance: none; appearance: none;
  height: 8px; border-radius: 999px;
  background: rgba(255, 255, 255, 0.1);
  outline: none;
}
input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 22px; height: 22px; border-radius: 50%;
  background: linear-gradient(180deg, var(--coral), var(--coral-deep));
  box-shadow: 0 2px 0 #8e1f37, 0 0 8px rgba(255, 94, 122, 0.5);
  cursor: pointer;
}
input[type="range"]::-moz-range-thumb {
  width: 22px; height: 22px; border-radius: 50%; border: none;
  background: linear-gradient(180deg, var(--coral), var(--coral-deep));
  cursor: pointer;
}

/* ============================================================
   LEVEL SYSTEM, HOLD SLOTS, LEVEL-UP BANNER
   ============================================================ */

/* home level meter */
.level-bar {
  display: flex; align-items: center; gap: 8px;
  width: min(340px, 100%);
}
.level-bar.teaser { justify-content: center; }
.lvl-badge {
  font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 13px; letter-spacing: 1px;
  background: linear-gradient(180deg, var(--rar-epic), #7b2cbf); color: #fff;
  padding: 4px 10px; border-radius: 999px; flex-shrink: 0;
  box-shadow: 0 2px 0 #4c1d95;
}
.lvl-badge.max { background: linear-gradient(180deg, var(--gold), #e6a216); color: #4a3200; box-shadow: 0 2px 0 #8a5e00; }
.lvl-track {
  flex: 1; height: 10px; border-radius: 999px;
  background: rgba(255, 255, 255, 0.08); overflow: hidden;
}
.lvl-track i {
  display: block; height: 100%; border-radius: 999px;
  background: linear-gradient(90deg, var(--sky), var(--rar-epic));
  transition: width 0.4s ease;
}
.lvl-cap { font-size: 11px; color: var(--text-dim); white-space: nowrap; flex-shrink: 0; }
.level-bar.teaser .lvl-track { max-width: 160px; }

/* per-mode home meta above Play (Ascension level / Survival round+score / Free score) */
.home-header { width: min(340px, 100%); display: flex; justify-content: center; align-items: stretch; gap: 10px; min-height: 58px; }
.home-header.home-asc { align-items: center; flex: none; }   /* the rich Ascension block sizes to its content (no shrink) so the objective + reward + hint never clip */
.home-lv {
  display: flex; flex-direction: column; align-items: center; gap: 1px;
  background: linear-gradient(180deg, rgba(123, 44, 191, 0.30), rgba(123, 44, 191, 0.12));
  border: 1px solid rgba(176, 122, 255, 0.38); border-radius: 16px;
  padding: 6px 30px; cursor: pointer; color: #fff; -webkit-tap-highlight-color: transparent;
  transition: transform 0.08s ease;
}
.home-lv:active { transform: scale(0.97); }
.home-lv-cap { font-size: 10px; letter-spacing: 1.5px; text-transform: uppercase; opacity: 0.7; }
.home-lv-num { font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 30px; line-height: 1; }
.home-lv-hint { font-size: 10px; opacity: 0.6; margin-top: 5px; }
/* rich Ascension home block: level on the left, the current level's objective + reward on the right,
   "tap to pick a level" on its own line below (everything padded so nothing clips out of the box) */
.home-lv-rich { width: 100%; padding: 11px 16px 9px; gap: 0; }
.hlv-top { display: flex; align-items: center; gap: 14px; width: 100%; }
.hlv-left { display: flex; flex-direction: column; align-items: center; flex: none; min-width: 64px; padding-right: 14px; border-right: 1px solid rgba(176, 122, 255, 0.3); }
.hlv-right { display: flex; flex-direction: column; gap: 5px; flex: 1; min-width: 0; text-align: left; }
.hlv-line { display: flex; align-items: center; gap: 7px; min-width: 0; }
/* labels auto-size (no fixed width) so long words like FR "Récompense" never truncate or overlap the value */
.hlv-cap { font-size: 9px; letter-spacing: 0.5px; text-transform: uppercase; opacity: 0.55; flex: none; white-space: nowrap; }
.hlv-obj { font-size: 13px; font-weight: 800; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.hlv-rw { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.hlv-chip { display: inline-flex; align-items: center; gap: 2px; font-size: 12px; font-weight: 700; }
.hlv-chip img, .hlv-chip svg { width: 16px; height: 16px; vertical-align: middle; }
.home-stat {
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  background: rgba(255, 255, 255, 0.05); border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 16px; padding: 8px 22px; min-width: 100px;
}
.home-stat b { font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 24px; line-height: 1; }
.home-stat span { font-size: 10px; letter-spacing: 1px; text-transform: uppercase; opacity: 0.65; }

/* level-ladder: per-tier reward chips under each goal */
.lvl-row-rewards { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 5px; }
.lvl-rw { display: inline-flex; align-items: center; gap: 2px; font-size: 11px; font-weight: 700; padding: 2px 7px; border-radius: 8px; background: rgba(255, 255, 255, 0.06); color: #fff; border: 1px solid transparent; }
.lvl-rw .coin-mini, .lvl-rw .jewel-mini { width: 13px; height: 13px; }
.lvl-rw img { height: 18px; width: auto; vertical-align: middle; }
.lvl-rw.t-easy { border-color: rgba(53, 195, 104, 0.40); }   /* owner T78 : rareté commune = vert (palier facile) */
.lvl-rw.t-med { border-color: rgba(125, 200, 255, 0.40); }
.lvl-rw.t-hard { border-color: rgba(255, 200, 61, 0.45); }
.lvl-rw.t-hidden { border-color: rgba(122, 162, 255, 0.55); background: rgba(122, 162, 255, 0.12); }
.lvl-rw.got { opacity: 0.5; }

/* hold slots (parking) — sits between tray and bonus bar */
#holdBar {
  display: flex; gap: 8px; justify-content: center;
  padding: 2px 0;
}
.hold-slot {
  width: 56px; height: 46px;
  display: flex; align-items: center; justify-content: center;
  background: rgba(12, 11, 20, 0.5);   /* fallback for no color-mix */
  background: color-mix(in srgb, var(--wp-tint, #6a5acd) 16%, rgba(12, 11, 20, 0.5));
  border: 1.5px dashed var(--card-edge);
  border-radius: 12px;
  cursor: grab; position: relative;
  touch-action: none;
  transition: transform 0.12s ease, box-shadow 0.12s ease, border-color 0.12s ease, background 0.12s ease;
}
.hold-slot.filled { border-style: solid; background: var(--card); }
/* a buyable hold slot: dashed gold frame + the coin price */
.hold-slot.hold-buy { width: auto; min-width: 56px; padding: 0 10px; cursor: pointer; border-color: rgba(255, 200, 61, 0.55); background: color-mix(in srgb, var(--gold, #ffc83d) 12%, rgba(12, 11, 20, 0.6)); }
.hold-slot.hold-buy:active { transform: scale(0.94); }
.hold-buy-cost { display: inline-flex; align-items: center; gap: 3px; font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 13px; color: var(--gold, #ffc83d); white-space: nowrap; }
.hold-buy-cost .coin-mini { width: 16px; height: 16px; }
.hold-plus { color: var(--text-dim); font-size: 22px; font-weight: 700; opacity: 0.5; }
.hold-slot .tray-piece { pointer-events: none; }
/* the slot the finger is hovering — grows + glows so it's obvious the piece lands here */
.hold-slot.drop-target {
  transform: scale(1.35);
  border-style: solid;
  border-color: var(--gold);
  background: rgba(255, 200, 61, 0.14);
  box-shadow: 0 0 18px rgba(255, 200, 61, 0.55);
  z-index: 60;
}
.hold-slot.drop-target .hold-plus { opacity: 1; color: var(--gold); }

/* level-up banner */
#levelUp {
  position: fixed; left: 50%; top: 32%; z-index: 320;
  transform: translate(-50%, -50%);
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  pointer-events: none; opacity: 0;
  text-align: center;
}
#levelUp .lvl-num {
  font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 52px;
  background: linear-gradient(90deg, var(--sky), var(--rar-epic), var(--coral));
  -webkit-background-clip: text; background-clip: text; color: transparent;
  filter: drop-shadow(0 0 22px rgba(176, 122, 255, 0.6)) drop-shadow(0 4px 0 rgba(0, 0, 0, 0.4));
}
#levelUp .lvl-reward {
  font-family: 'Nunito', sans-serif; font-weight: 900; font-size: 16px; color: #fff;
  background: rgba(25, 28, 48, 0.9); border: 1px solid var(--card-edge);
  padding: 7px 16px; border-radius: 999px;
  text-shadow: 0 1px 0 rgba(0, 0, 0, 0.5);
}
#levelUp.go { animation: levelup 1.7s cubic-bezier(0.34, 1.56, 0.64, 1); }
@keyframes levelup {
  0% { opacity: 0; transform: translate(-50%, -50%) scale(0.3) rotate(-6deg); }
  16% { opacity: 1; transform: translate(-50%, -50%) scale(1.15) rotate(2deg); }
  28% { transform: translate(-50%, -50%) scale(1) rotate(0); }
  80% { opacity: 1; transform: translate(-50%, -50%) scale(1); }
  100% { opacity: 0; transform: translate(-50%, -62%) scale(1.05); }
}

/* level ladder overlay */
.level-bar { cursor: pointer; }
.level-bar .lvl-badge::after { content: ' ›'; opacity: 0.7; }
.levels-panel { width: min(400px, 100%); gap: 10px; }
.levels-sub { font-size: 12.5px; color: var(--text-dim); text-align: center; }
.levels-list {
  width: 100%; max-height: min(56vh, 460px); overflow-y: auto;
  display: flex; flex-direction: column; gap: 8px;
  padding: 2px;
}
.lvl-row {
  display: flex; align-items: center; gap: 12px;
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid var(--card-edge);
  border-radius: 14px; padding: 10px 12px;
}
.lvl-row-badge {
  flex-shrink: 0; width: 30px; height: 30px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 14px;
  background: rgba(255, 255, 255, 0.08); color: var(--text-dim);
}
.lvl-row-icon {
  flex-shrink: 0; width: 38px; height: 38px; border-radius: 10px;
  display: flex; align-items: center; justify-content: center;
  background: rgba(255, 255, 255, 0.05);
}
.lvl-row-icon svg { width: 24px; height: 24px; }
.lvl-row-icon .bonus-ic-img, .lvl-row-icon img { width: 26px; height: 26px; object-fit: contain; }   /* bonus reward art was rendering at full size in reward rows */
.lvl-row.tone-bonus .lvl-row-icon { color: var(--mint); }
.lvl-row-info { flex: 1; min-width: 0; }
.lvl-row-label { font-weight: 900; font-size: 13.5px; line-height: 1.25; }
.lvl-row-thr { font-size: 11px; color: var(--text-dim); margin-top: 3px; }
.lvl-mini-track {
  display: inline-block; width: 110px; max-width: 100%; height: 6px;
  border-radius: 999px; background: rgba(255, 255, 255, 0.1); overflow: hidden; vertical-align: middle;
}
.lvl-mini-track i { display: block; height: 100%; border-radius: 999px; background: linear-gradient(90deg, var(--sky), var(--rar-epic)); }
.lvl-row-status {
  flex-shrink: 0; font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 12px;
  color: var(--text-dim);
}
.lvl-grand { font-size: 22px; }
.lvl-q { font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 20px; color: var(--text-dim); }
/* Ascension replay ladder rows: tappable, with the 4 tier pips */
.lvl-row.asc-row.tappable { cursor: pointer; transition: transform 0.12s ease, border-color 0.12s ease; }
.lvl-row.asc-row.tappable:active { transform: scale(0.98); }
.lvl-row.asc-row.next { border-color: var(--rar-epic); box-shadow: 0 0 12px rgba(176, 122, 255, 0.2); }
.lvl-row.asc-row .lvl-row-thr .asc-stars { display: inline-flex; gap: 4px; margin-top: 2px; }
.lvl-row.asc-row.done .lvl-row-status { color: var(--mint); }

/* reached */
.lvl-row.done { opacity: 0.62; }
.lvl-row.done .lvl-row-badge { background: linear-gradient(180deg, var(--mint), #2fa84f); color: #06340f; }
.lvl-row.done .lvl-row-status { color: var(--mint); }

/* the desirable next reward */
.lvl-row.next {
  background: rgba(176, 122, 255, 0.12);
  border-color: var(--rar-epic);
  box-shadow: 0 0 18px rgba(176, 122, 255, 0.28);
}
.lvl-row.next .lvl-row-badge { background: linear-gradient(180deg, var(--rar-epic), #7b2cbf); color: #fff; }
.lvl-row.next .lvl-row-icon { background: rgba(176, 122, 255, 0.2); animation: next-glow 1.6s ease-in-out infinite; }
@keyframes next-glow { 50% { transform: scale(1.08); } }
.lvl-row.next .lvl-row-status { color: var(--rar-epic); font-size: 13px; }

/* masked future */
.lvl-row.masked { opacity: 0.85; }
.lvl-row.masked .lvl-row-icon { background: rgba(255, 255, 255, 0.03); border: 1px dashed var(--card-edge); }
.lvl-row.masked .lvl-row-label { color: var(--text-dim); font-weight: 700; }

/* level-up celebration overlay */
.levelup-panel { position: relative; overflow: hidden; gap: 10px; max-height: 88vh; }
.levelup-burst {
  /* WebKit-safe: no mask (iOS drops it on animated layers) — the rim fade is painted to the panel's
     own white, and the shape is a geometric circle so no square edge can ever rotate into view */
  position: absolute; left: 50%; top: 30%; width: 460px; height: 460px; border-radius: 50%;
  transform: translate(-50%, -50%);
  background: radial-gradient(circle, transparent 0%, transparent 42%, #fff 68%, #fff 100%),
    conic-gradient(from 0deg, rgba(255,200,61,.14) 0deg, transparent 22deg, rgba(176,122,255,.14) 44deg, transparent 66deg,
    rgba(77,196,255,.14) 88deg, transparent 110deg, rgba(255,200,61,.14) 132deg, transparent 154deg, rgba(176,122,255,.14) 176deg,
    transparent 198deg, rgba(77,196,255,.14) 220deg, transparent 242deg, rgba(255,200,61,.14) 264deg, transparent 286deg,
    rgba(176,122,255,.14) 308deg, transparent 330deg, rgba(77,196,255,.14) 352deg);
  animation: rays-spin 11s linear infinite; pointer-events: none;
}
/* keep content above the burst, but don't knock the burst out of absolute
   positioning (that was stretching the panel to the burst's full height) */
.levelup-panel > *:not(.levelup-burst) { position: relative; z-index: 1; }
.levelup-num {
  font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 40px; letter-spacing: 1px;
  background: linear-gradient(90deg, var(--sky), var(--rar-epic), var(--coral));
  -webkit-background-clip: text; background-clip: text; color: transparent;
  filter: drop-shadow(0 0 18px rgba(176,122,255,.55));
}
.levelup-sub { font-size: 12px; letter-spacing: 2px; color: var(--text-dim); text-transform: uppercase; }
.levelup-rewards { display: flex; flex-direction: column; gap: 8px; width: 100%; max-height: 50vh; overflow-y: auto; }
.levelup-reward {
  display: flex; align-items: center; gap: 12px;
  background: rgba(255,255,255,.04); border: 1px solid var(--card-edge);
  border-radius: 14px; padding: 10px 14px;
}
.levelup-reward.tone-bonus .lvl-row-icon { color: var(--mint); }
.levelup-reward .lvl-row-icon {
  flex-shrink: 0; width: 38px; height: 38px; border-radius: 10px;
  display: flex; align-items: center; justify-content: center; background: rgba(255,255,255,.05);
}
.levelup-reward .lvl-row-icon svg { width: 24px; height: 24px; }
.levelup-reward-label { font-weight: 900; font-size: 14px; text-align: left; }

/* language selector */
.lang-select {
  flex: 1; min-width: 0;
  background: var(--ink-2); color: var(--text);
  border: 2px solid var(--card-edge); border-radius: 12px;
  font-family: 'Nunito', sans-serif; font-weight: 900; font-size: 14px;
  padding: 9px 12px; cursor: pointer; outline: none;
}
.lang-select:focus { border-color: var(--sky); }

/* leaderboard level filter note */
.board-level-note {
  text-align: center; font-size: 12px; color: var(--rar-epic);
  font-weight: 900; margin: -4px 0 2px;
}

/* ---------- Prism Pop: rarity toasts & ultra moment ---------- */
.gem-toast {
  position: fixed; transform: translate(-50%, 0); pointer-events: none;
  font-family: 'Lilita One', 'Trebuchet MS', sans-serif;
  font-weight: 900; font-size: 15px; z-index: 60;
  text-shadow: 0 1px 0 rgba(0, 0, 0, 0.65);
  animation: gem-rise 0.85s ease-out forwards;
}
@keyframes gem-rise {
  0% { opacity: 0; transform: translate(-50%, 4px) scale(0.7); }
  20% { opacity: 1; transform: translate(-50%, -6px) scale(1.12); }
  100% { opacity: 0; transform: translate(-50%, -34px) scale(1); }
}
.jewel-pop-toast {
  position: fixed; left: 50%; top: 38%; transform: translate(-50%, -50%);
  pointer-events: none; z-index: 61;
  font-family: 'Lilita One', 'Trebuchet MS', sans-serif;
  font-weight: 900; font-size: 30px; letter-spacing: 0.5px;
  padding: 8px 20px; border-radius: 999px;
  background: rgba(10, 8, 20, 0.72);
  text-shadow: 0 2px 0 rgba(0, 0, 0, 0.7);
  animation: jewel-pop 1.1s cubic-bezier(.2,1.3,.4,1) forwards;
}
@keyframes jewel-pop {
  0% { opacity: 0; transform: translate(-50%, -50%) scale(0.4); }
  18% { opacity: 1; transform: translate(-50%, -50%) scale(1.15); }
  32% { transform: translate(-50%, -50%) scale(1); }
  78% { opacity: 1; }
  100% { opacity: 0; transform: translate(-50%, -76%) scale(1); }
}
.ultra-flash {
  position: fixed; inset: 0; pointer-events: none; z-index: 55;
  opacity: 0; mix-blend-mode: screen;
  animation: ultra-flash 0.26s ease-out forwards;
}
@keyframes ultra-flash {
  0% { opacity: 0; }
  25% { opacity: 0.5; }
  100% { opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .ultra-flash { display: none; }
}

/* ---------- centre score tally (multiplier reveal) ---------- */
.score-tally {
  position: fixed; left: 50%; top: 38%; transform: translate(-50%, -50%);
  pointer-events: none; z-index: 62; text-align: center;
  opacity: 0; font-family: 'Lilita One', 'Trebuchet MS', sans-serif;
  transition: opacity 0.18s ease;
}
.score-tally.show { opacity: 1; }
.score-tally .st-num {
  font-size: 54px; font-weight: 900; color: #fff;
  text-shadow: 0 3px 0 rgba(0, 0, 0, 0.65);
}
.score-tally .st-mult {
  font-size: 28px; font-weight: 900; min-height: 32px; margin-bottom: 4px;
  text-shadow: 0 2px 0 rgba(0, 0, 0, 0.7);
  display: flex; align-items: center; justify-content: center; gap: 5px; color: #9fdcff;
}
.score-tally .st-mult.is-syn { color: #ffe14d; }
/* a mini gem pulled from the atlas, shown next to each gem/synergy step */
.tg-gem {
  display: inline-block; width: 26px; height: 26px; flex: none;
  background-image: url('assets/gems/gems_atlas.webp');
  background-size: 375% 375%; background-position: var(--gp, 50% 50%); background-repeat: no-repeat;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.5));
}
.score-tally .st-num.grow { animation: st-grow 0.24s ease; }
@keyframes st-grow { 0% { transform: scale(1); } 42% { transform: scale(1.3); } 100% { transform: scale(1); } }
.score-tally .st-mult.pop { animation: st-pop 0.24s ease; }
@keyframes st-pop {
  0% { opacity: 0; transform: scale(0.5) translateY(7px); }
  45% { opacity: 1; transform: scale(1.18); }
  100% { opacity: 1; transform: scale(1) translateY(0); }
}
.score-tally.to-hud {
  transition: transform 0.4s cubic-bezier(.55, 0, .8, .45), opacity 0.4s ease;
  transform: translate(-180%, -360%) scale(0.32); opacity: 0;
}
@media (prefers-reduced-motion: reduce) {
  .score-tally .st-num.grow, .score-tally .st-mult.pop { animation: none; }
  .score-tally.to-hud { transition: opacity 0.2s; transform: translate(-50%, -50%) scale(0.8); }
}

/* ---------- star progress bar (above the board) ---------- */
.star-bar {
  position: relative;
  height: 30px; border-radius: 999px;
  background: rgba(255, 255, 255, 0.07);
  border: 1px solid var(--card-edge);
  overflow: visible;     /* the head box pops a touch above the track */
  margin: 0 0 8px;
}
.star-fill {
  position: absolute; left: 0; top: 0; bottom: 0; width: 0;
  background: linear-gradient(90deg, #ff9f1c, #ffd54d);
  border-radius: 999px;
  transition: width 0.55s cubic-bezier(.34, 0, .2, 1);
  z-index: 0;
}
/* faint boxes for the rarities still ahead (the higher boxes you can still reach) */
.sb-ghost { position: absolute; top: 50%; transform: translate(-50%, -50%); z-index: 1; pointer-events: none; }
.sb-ghost img { width: 20px; height: 20px; object-fit: contain; display: block; filter: grayscale(0.9) brightness(0.5); opacity: 0.5; }
/* the single box you'll actually receive: travels right + upgrades rarity */
.sb-head {
  position: absolute; top: 50%; left: 0; transform: translate(-50%, -50%);
  z-index: 3; pointer-events: none;
  transition: left 0.55s cubic-bezier(.34, 0, .2, 1);
  filter: drop-shadow(0 2px 5px rgba(0, 0, 0, 0.55));
}
.sb-head-img { display: block; }
.sb-head img { width: 30px; height: 30px; object-fit: contain; display: block; }
.sb-head.pending { opacity: 0.55; filter: grayscale(0.55) brightness(0.85); }

/* ---------- star threshold celebration ---------- */
.star-pop {
  position: fixed; left: 50%; top: 50%;
  transform: translate(-50%, -50%) scale(0);
  z-index: 63; pointer-events: none;
  filter: drop-shadow(0 0 26px rgba(255, 200, 61, 0.7)) drop-shadow(0 6px 16px rgba(0, 0, 0, 0.5));
  animation: star-pop-in 0.62s cubic-bezier(.2, 1.5, .4, 1) forwards;
  transition: transform 0.5s cubic-bezier(.55, 0, .7, .4), opacity 0.5s ease;
}
.star-pop img { display: block; }
@keyframes star-pop-in {
  0% { transform: translate(-50%, -50%) scale(0) rotate(-45deg); }
  60% { transform: translate(-50%, -50%) scale(1.3) rotate(10deg); }
  100% { transform: translate(-50%, -50%) scale(1) rotate(0); }
}
.sb-head.just { animation: sb-just 0.5s ease; }
@keyframes sb-just {
  0% { transform: translate(-50%, -50%) scale(1); }
  40% { transform: translate(-50%, -50%) scale(1.6); }
  100% { transform: translate(-50%, -50%) scale(1); }
}

/* ---------- per-move praise (Nice / Great / Amazing ...) ---------- */
.praise-pop {
  position: fixed; left: 50%; top: 43%;
  transform: translate(-50%, -50%);
  font-family: 'Lilita One', 'Trebuchet MS', sans-serif;
  font-size: 42px; letter-spacing: 1px; color: #fff;
  text-shadow: 0 2px 0 #c98a00, 0 0 22px rgba(255, 200, 61, 0.75), 0 4px 0 rgba(0, 0, 0, 0.5);
  z-index: 82; pointer-events: none; white-space: nowrap;   /* ABOVE the score milestone banner (71)/pop (70)/combo (60), and lower on screen so they never overlap */
  animation: praise-in 0.42s cubic-bezier(.2, 1.7, .4, 1);
  transition: opacity 0.42s ease, transform 0.42s ease;
}
.praise-pop.out { opacity: 0; transform: translate(-50%, -120%); }
@keyframes praise-in { 0% { transform: translate(-50%, -50%) scale(0.3); opacity: 0; } 100% { transform: translate(-50%, -50%) scale(1); opacity: 1; } }
/* reduce-motion: keep the praise TEXT (it carries info), just drop the bouncy entrance/exit motion */
@media (prefers-reduced-motion: reduce) { .praise-pop { animation: none; } .praise-pop.out { transition: opacity 0.3s ease; transform: translate(-50%, -50%); } }
@media (prefers-reduced-motion: reduce) { .star-pop { display: none; } }

/* ---------- collection counts ---------- */
/* the standalone count lines are retired: the counts now live in the section heads
   (Owned X/total, To unlock Y/total) */
.coll-total, .coll-cat { display: none; }

/* ---------- gem guide legend ---------- */
.gemguide-sub { font-size: 12px; color: var(--text-dim); text-align: center; margin: -4px 0 6px; }
.gemguide-list { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px 8px; width: 100%; }
.gemguide-row { display: flex; flex-direction: column; align-items: center; gap: 5px; }
.gg-gem { width: 30px; height: 30px; position: relative; }
/* owner T91 : rim sombre TOUJOURS visible (bat .gem.ultra qui glow en var(--c) blanc -> invisible sur panneau clair) ; on garde le halo coloré par-dessus pour les gemmes vives */
#ovGemGuide .gg-gem { filter: drop-shadow(0 1px 2px rgba(26,13,48,.42)) drop-shadow(0 0 3px var(--c)); }
.gg-mult { font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 16px; -webkit-text-stroke: .85px rgba(26,13,48,.72); paint-order: stroke fill; text-shadow: 0 1px 1.5px rgba(26,13,48,.30); }   /* owner T91 : contour sombre -> le ×mult de la gemme blanche reste lisible (fill par-dessus le stroke) */
/* owner T101 : règles de score dans le guide des gemmes (lignes / combo / synergie) */
.gemguide-rules { width: 100%; margin: 14px 0 4px; padding-top: 12px; border-top: 1px solid rgba(42,26,77,.14); text-align: left; }
.gemguide-rules .ggr-title { font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 13px; letter-spacing: 1px; color: var(--dp-gem, #b07aff); text-align: center; margin-bottom: 9px; }
.gemguide-rules .ggr-formula { font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 13px; letter-spacing: .3px; text-align: center; color: var(--dp-ink, #2a1a4d); background: rgba(176,122,255,.12); border: 1px solid rgba(176,122,255,.30); border-radius: 10px; padding: 6px 8px; margin: 0 0 11px; }
.gemguide-rules .ggr-row { display: flex; gap: 9px; align-items: baseline; margin: 6px 0; }
.gemguide-rules .ggr-row b { flex: 0 0 60px; font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 13px; color: var(--dp-ink, #2a1a4d); }
.gemguide-rules .ggr-row span { flex: 1; min-width: 0; font-family: 'Nunito', sans-serif; font-weight: 700; font-size: 12px; color: rgba(42,26,77,.78); line-height: 1.3; }
/* owner T100/T101 : aide en jeu = main qui « tape » la zone + bulle (non-bloquant) */
.game-hint { position: fixed; z-index: 150; pointer-events: none; transform: translate(-50%, -50%); opacity: 0; transition: opacity .25s ease; }
.game-hint.show { opacity: 1; }
.game-hint .gh-hand { display: block; width: 48px; height: 48px; object-fit: contain; filter: drop-shadow(0 3px 6px rgba(0,0,0,.5)); animation: gh-tap 1.15s ease-in-out infinite; }
.game-hint .gh-bubble { position: absolute; left: 50%; bottom: 100%; transform: translateX(-50%); margin-bottom: 7px; background: #fff; color: #2a1a4d; font-family: 'Nunito', 'Trebuchet MS', sans-serif; font-weight: 900; font-size: 13px; padding: 7px 12px; border-radius: 12px; text-align: center; white-space: normal; width: max-content; max-width: min(56vw, 168px); box-shadow: 0 5px 16px rgba(40,20,70,.42); }
.game-hint.gh-below .gh-bubble { bottom: auto; top: 100%; margin-bottom: 0; margin-top: 7px; }
/* T114 : hint du score (en haut-À-GAUCHE) -> bulle ancrée à gauche de la main, s'étend vers la droite (ne sort plus de l'écran) */
.game-hint.gh-right .gh-bubble { left: 0; right: auto; transform: none; }
@keyframes gh-tap { 0%, 100% { transform: translateY(-3px); } 50% { transform: translateY(3px) scale(.9); } }

/* ---------- currency popups (buy coins / jewels) ---------- */
.jewel-chip { cursor: pointer; }
.buy-sep {
  font-size: 11px; letter-spacing: 1.5px; font-weight: 900;
  color: var(--text-dim); margin-top: 4px;
}
.pack-row { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 8px; width: 100%; }
.pack-row .card { min-width: 0; }

/* ---------- banniere de consentement tracking (tracker.js) ---------- */
#pp-consent {
  position: fixed; left: 50%; bottom: calc(12px + env(safe-area-inset-bottom));
  transform: translateX(-50%);
  z-index: 400; width: min(560px, calc(100vw - 24px));
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 12px 14px; border-radius: 16px;
  background: rgba(20, 22, 38, 0.96); border: 1px solid rgba(255, 255, 255, 0.12);
  box-shadow: 0 10px 34px rgba(0, 0, 0, 0.5);
  color: #eef0ff; font-size: 12.5px; line-height: 1.35;
  animation: ppConsentIn 0.35s cubic-bezier(.2, 1.1, .3, 1) both;
}
#pp-consent.out { animation: ppConsentOut 0.26s ease forwards; }
@keyframes ppConsentIn  { from { opacity: 0; transform: translate(-50%, 16px); } to { opacity: 1; transform: translate(-50%, 0); } }
@keyframes ppConsentOut { to { opacity: 0; transform: translate(-50%, 16px); } }
.pp-consent-txt { flex: 1 1 220px; }
.pp-consent-btns { display: flex; gap: 8px; margin-left: auto; }
.pp-consent-b {
  border: none; border-radius: 10px; padding: 8px 16px; cursor: pointer;
  font-weight: 800; font-size: 12.5px; color: #06351f;
  background: linear-gradient(180deg, #5bd9a0, #2fae6b);
  box-shadow: 0 3px 0 #1f7d4c;
}
.pp-consent-b:active { transform: translateY(2px); box-shadow: 0 1px 0 #1f7d4c; }
.pp-consent-b.ghost {
  background: transparent; color: #c9cdf0; box-shadow: none;
  border: 1px solid rgba(255, 255, 255, 0.22); font-weight: 700;
}

/* ---------- rewarded-ad "free continue" button + dev ad stub (ads.js) ---------- */
.btn-ad {
  background: linear-gradient(180deg, #4fd08a, #2fae6b); color: #06351f;
  box-shadow: 0 3px 0 #1f7d4c; font-weight: 900; border: none;
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;   /* owner : centrer l'icône (pub/cadeau) + le texte comme un bloc (avant : décalé à gauche) */
}
.btn-ad:active { transform: translateY(2px); box-shadow: 0 1px 0 #1f7d4c; }
.btn-ad .ad-ic { display: inline-block; margin-right: 0; top: 0; }   /* le gap gère l'espacement -> plus de décalage */
img.ad-ic { width: 17px; height: 17px; object-fit: contain; vertical-align: middle; position: relative; top: -1px; }   /* play glyph (owner art) on ad buttons — agrandi + aligné au texte */

/* Pocket-Champs style bonus prompt, shown over the box ceremony after the loot is collected */
.box-bonus { position: fixed; inset: 0; z-index: 30; display: grid; place-items: center; pointer-events: none; }
.box-bonus .cb-card { pointer-events: auto; width: min(320px, 84vw); background: rgba(20, 16, 31, 0.97); border: 1px solid rgba(255, 255, 255, 0.14); border-radius: 20px; padding: 22px 20px; text-align: center; color: #f4f1ff; opacity: 0; transform: translateY(10px) scale(0.96); transition: opacity 0.22s ease, transform 0.22s ease; box-shadow: 0 18px 50px rgba(0, 0, 0, 0.5); }
.box-bonus.show .cb-card { opacity: 1; transform: none; }
.cb-ghost { width: 70px; height: 70px; margin: 0 auto 12px; border-radius: 18px; display: grid; place-items: center; font-size: 36px; font-weight: 900; color: #ffd36b; background: rgba(255, 211, 107, 0.12); border: 2px dashed rgba(255, 211, 107, 0.5); animation: cbPulse 1.4s ease-in-out infinite; }
@keyframes cbPulse { 50% { transform: scale(1.07); } }
.cb-title { font-weight: 800; font-size: 16px; margin-bottom: 12px; }
/* the actual offered item (no more mystery "?"): art framed in its rarity colour + a type tag + set progress */
.cb-item { position: relative; width: 84px; height: 84px; margin: 0 auto 8px; border-radius: 20%; overflow: hidden; border: 3px solid var(--rc, #888); box-shadow: 0 4px 14px rgba(0, 0, 0, .4), 0 0 16px var(--rc); display: grid; place-items: center; background: rgba(255, 255, 255, .04); }
.cb-item .cb-art { width: 100%; height: 100%; display: block; }
.cb-item .cb-art > * { width: 100%; height: 100%; display: block; background-size: cover; background-position: center; }
.cb-item .cos-tag { top: 3px; }
.cb-name { font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 17px; margin-bottom: 2px; }
.box-bonus .cos-set { display: block; font-size: 11px; color: var(--text-dim); margin-bottom: 12px; }
.box-bonus .cb-watch { width: 100%; margin-bottom: 8px; }
.box-bonus .cb-buy { width: 100%; margin-bottom: 8px; }
.box-bonus .cb-skip { width: 100%; }

/* shop: free box claimable by watching a rewarded ad */
.free-box-card { display: flex; align-items: center; gap: 14px; padding: 14px 16px; }
/* Ad-Free pack offer (IAP) — a bright premium card */
.noads-card { padding: 14px 16px; background: linear-gradient(150deg, #6a3df0, #9a4ad8 60%, #c44ad0); border: 1px solid rgba(255, 255, 255, 0.22); box-shadow: 0 8px 26px -6px rgba(154, 74, 216, 0.6); }
.na-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.na-head b { font-family: 'Lilita One', 'Trebuchet MS', sans-serif; font-size: 18px; color: #fff; }
.na-head b ::after { content: ''; }
.na-active { font-size: 11px; font-weight: 900; letter-spacing: .08em; color: #1b1233; background: #ffd34e; padding: 2px 9px; border-radius: 999px; }
.na-grant { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; margin: 8px 0; font-weight: 800; color: #fff; }
.na-pill { display: inline-flex; align-items: center; gap: 3px; background: rgba(0, 0, 0, 0.22); padding: 3px 9px; border-radius: 999px; font-family: 'Lilita One', 'Trebuchet MS', sans-serif; }
.na-pill .coin-mini, .na-pill .jewel-mini { width: 16px; height: 16px; }
.na-benefits { display: flex; flex-direction: column; gap: 3px; font-size: 12.5px; font-weight: 700; color: rgba(255, 255, 255, 0.95); margin-bottom: 10px; }
.na-buy { width: 100%; }
.free-box-card .fc-art { flex: 0 0 auto; display: grid; place-items: center; }
.free-box-card .fc-body { flex: 1; display: flex; flex-direction: column; gap: 8px; align-items: flex-start; }
.free-box-card .fc-body .shop-name { margin: 0; }
.free-box-card .fc-timer { font-size: 13px; color: #a99fce; font-weight: 700; }
.free-box-card .btn-ad { width: auto; padding: 8px 18px; }

.ad-stub { position: fixed; inset: 0; z-index: 500; background: rgba(0, 0, 0, 0.82); display: grid; place-items: center; animation: adStubIn 0.2s ease; }
@keyframes adStubIn { from { opacity: 0; } }
.ad-stub-box { position: relative; width: min(320px, 86vw); background: #14101f; border: 1px solid rgba(255, 255, 255, 0.14); border-radius: 18px; padding: 28px 20px 20px; text-align: center; color: #f4f1ff; }
.ad-stub-tag { position: absolute; top: 10px; left: 12px; font-size: 10px; letter-spacing: 1px; color: #a99fce; }
.ad-stub-x { position: absolute; top: 6px; right: 8px; width: 28px; height: 28px; border: none; background: transparent; color: #a99fce; font-size: 15px; cursor: pointer; }
.ad-stub-art { width: 76px; height: 76px; margin: 4px auto; font-size: 54px; }   /* interim: owner art (ads.webp); ad-stub UI to be reworked */
.ad-stub-place { font-size: 12px; color: #9aa0c8; margin-bottom: 16px; }
.ad-stub-btn { width: 100%; padding: 12px; border: none; border-radius: 12px; cursor: pointer; font: inherit; font-weight: 900; font-size: 14px; color: #06351f; background: linear-gradient(180deg, #5bd9a0, #2fae6b); }
.ad-stub-btn:disabled { opacity: 0.5; cursor: default; color: #1b2a22; }

/* =====================================================================
   REDESIGN v1 — bright fixed home · flat-aplat buttons · zero board scrim
   (built live; iterate on the deployed game. Owner: bright + welcoming,
    no dark filter over the in-game wallpaper, legibility via outlines.)
   ===================================================================== */
:root { --pp-ink: #14110d; --pp-amber-lip: #b9740c; }

/* HOME gets its OWN fixed bright background — the custom wallpaper is for in-game only.
   No dark veil on the home either. */
body[data-view="home"] .ambient {
  background: linear-gradient(180deg, #8fd3ff 0%, #b9e6ff 36%, #e9f7ff 100%) !important;
}
body[data-view="home"] .ambient::after { background: transparent !important; }
body[data-view="home"] .blob, body[data-view="home"] .grain { display: none; }

/* GAME BOARD: NO dark filter over the wallpaper (not even a light one). The art shows
   untouched; readability comes from element outlines + their own frames. */
body[data-view="game"] .ambient::after { background: transparent !important; }
/* with no veil, every floating in-game text needs its own strong outline to read on any wallpaper */
.hud-combo, .hint, #milestoneBanner, .praise {
  text-shadow: -1.4px -1.4px 0 rgba(0,0,0,.7), 1.4px -1.4px 0 rgba(0,0,0,.7), -1.4px 1.4px 0 rgba(0,0,0,.7), 1.4px 1.4px 0 rgba(0,0,0,.7), 0 2px 0 rgba(0,0,0,.6);
}

/* PLAY button — flat APLATS (yellow face → orange base, hard edges), thick dark
   outline, bright top rim, and a 3D lip for the press. */
/* owner : le bouton Play/Continuer reprend le style STANDARD des autres boutons (.btn-primary corail 3D) — plus l'ancien look doré/image */
.btn-play:active { transform: translateY(3px); }
.play-wrap .play-caret {
  border: 4px solid var(--pp-ink); border-radius: 18px;
  background: linear-gradient(180deg, #f4c52e 0 50%, #ee8f2a 50% 100%) !important;
  box-shadow: inset 0 3px 0 rgba(255, 255, 255, 0.4), 0 6px 0 var(--pp-amber-lip) !important;
  -webkit-text-stroke: 2px var(--pp-ink); paint-order: stroke fill; color: #fff;
}

/* resource pills (coin / jewels) — dark pill, thick outline, outlined number */
.coin-chip, .jewel-chip {
  background: linear-gradient(180deg, #46464e, #26262d) !important;
  border: 3px solid #111 !important;
  box-shadow: inset 0 2px 0 rgba(255, 255, 255, 0.13);
}
.coin-chip > span, .jewel-chip > span {
  -webkit-text-stroke: 2.5px #111; paint-order: stroke fill; color: #fff;
}
