/* Pulse Jump — UI front (cartoon · Cyber Sky) */

/* ---------------------------------------------------------------------------
 * Police display — chaîne en rev9 (push 9.5/10) :
 *   1. Google Fonts CDN (link rel=stylesheet dans index.html) → Fredoka 600/700.
 *      Garantit le rendu cartoon dès le 1er chargement sans drop de woff2.
 *   2. `local()` reste branché → si Fredoka/Lilita One installé système, override.
 *   3. Phase 1 (action user) : drop `web/fonts/Fredoka-Bold.woff2` puis
 *      dé-commenter la ligne url() ci-dessous + bump cache. Le `<link>` Google
 *      Fonts dans index.html devient alors optionnel.
 *
 * Historique INCIDENT : docs/PROJECT-STATUS.md §14 (rev7) + §15 (rev8) + §18 (rev9).
 * --------------------------------------------------------------------------- */
@font-face {
  font-family: "Pulse Display";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: local("Fredoka Bold"), local("Fredoka SemiBold"), local("Lilita One");
  /* src: local("Fredoka Bold"), local("Fredoka SemiBold"), local("Lilita One"),
         url("../fonts/Fredoka-Bold.woff2") format("woff2"); */
}

:root {
  --zt-outline: #2a2420;
  --zt-shadow: rgba(42, 36, 32, 0.38);
  --sky: #5ec4f0;
  --btn-play: #ffca28;
  --btn-play-dark: #f9a825;
  --btn-secondary: #ffffff;
  --accent: #e85d3a;
  --lime: #43a047;
  --combo-hot: #ff6f00;
  --text: #2a2420;
  --bubble: #ffffff;
  --font-fallback: system-ui, -apple-system, "Segoe UI", BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif;
  /* rev9 : Fredoka via Google Fonts CDN en tête, puis Pulse Display
     (local), puis fallback système. Garantit le cartoon partout. */
  --font-display: "Fredoka", "Pulse Display", var(--font-fallback);
  --safe-top: max(12px, env(safe-area-inset-top));
  --safe-bottom: max(12px, env(safe-area-inset-bottom));
  --safe-x: max(14px, env(safe-area-inset-left), env(safe-area-inset-right));
}



* {

  box-sizing: border-box;

  margin: 0;

  padding: 0;

  -webkit-tap-highlight-color: transparent;

}



html, body {
  width: 100%;
  height: 100%;
  overflow: hidden;
  background: var(--sky);
  touch-action: none;
  overscroll-behavior: none;
  -webkit-overflow-scrolling: auto;
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
  font-family: var(--font-fallback);
  color: var(--text);
}



html {

  /* iOS Safari: collapsing address bar shrinks 100vh; dvh tracks the visible viewport. */

  height: 100dvh;

}



body {

  height: 100dvh;

}



#wrap {

  position: fixed;

  inset: 0;

  touch-action: none;

}



canvas#game {

  touch-action: none;

}



canvas {

  display: block;

  width: 100%;

  height: 100%;

}



/* —— HUD jeu —— */

#hud {

  position: absolute;

  left: 0;

  right: 0;

  top: 0;

  padding: var(--safe-top) var(--safe-x) 8px;

  pointer-events: none;

  display: flex;

  justify-content: space-between;

  align-items: flex-start;

  gap: 10px;

  z-index: 4;

}



#hud .scoreBlock {

  background: var(--bubble);

  border: 3px solid var(--zt-outline);

  border-radius: 16px;

  padding: 8px 16px 12px;

  box-shadow: 0 5px 0 var(--zt-shadow);

  min-width: 88px;

  flex: 0 1 auto;

}



#hud .scoreHead {

  display: flex;

  flex-direction: column;

  gap: 1px;

}



#hud .title {
  font-family: var(--font-display);
  font-size: 9px;
  font-weight: 900;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--accent);
  line-height: 1.2;
}



#hud .world {

  font-size: 10px;

  font-weight: 800;

  color: var(--zt-outline);

  opacity: 0.85;

  letter-spacing: 0.02em;

}



#hud .scoreRow {

  display: flex;

  align-items: baseline;

  gap: 8px;

  margin-top: 4px;

}



#hud .score {
  font-family: var(--font-display);
  font-size: clamp(36px, 11vw, 44px);
  font-weight: 900;
  line-height: 0.95;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
  color: var(--zt-outline);
}

#hud .score.score-pop {
  animation: scorePop 0.38s cubic-bezier(0.34, 1.4, 0.64, 1);
}

#hud .score.score-hero {
  animation: scoreHero 0.6s cubic-bezier(0.34, 1.55, 0.4, 1);
}

@keyframes scorePop {
  0% { transform: scale(1); }
  35% { transform: scale(1.14); color: var(--accent); }
  100% { transform: scale(1); }
}

/* Pop renforcé (rev9 push 9.5) : scale 1.5x, lime sur perfect events.
   Combo×2 atteint, record battu live, mission reward. */
@keyframes scoreHero {
  0% { transform: scale(1); color: var(--zt-outline); }
  16% { transform: scale(1.5) rotate(-3deg); color: var(--lime); text-shadow: 0 0 18px rgba(57, 255, 20, 0.85), 0 0 6px rgba(255, 202, 40, 0.5); }
  40% { transform: scale(1.22) rotate(2deg); color: var(--btn-play-dark); text-shadow: 0 0 10px rgba(255, 202, 40, 0.6); }
  72% { transform: scale(1.08) rotate(-1deg); color: var(--accent); }
  100% { transform: scale(1); color: var(--zt-outline); text-shadow: none; }
}



#hud .metaBlock {

  text-align: right;

  display: flex;

  flex-direction: column;

  align-items: flex-end;

  gap: 6px;

  flex-shrink: 0;

}



#hud .best {

  font-size: 10px;

  font-weight: 800;

  text-transform: uppercase;

  letter-spacing: 0.06em;

  background: var(--bubble);

  border: 2px solid var(--zt-outline);

  border-radius: 999px;

  padding: 6px 12px;

  box-shadow: 0 3px 0 var(--zt-shadow);

  display: inline-flex;

  align-items: center;

  gap: 4px;

}



#hud .best span {

  font-size: 15px;

  font-weight: 900;

  font-variant-numeric: tabular-nums;

  letter-spacing: -0.02em;

}



#hud .combo {

  font-size: 13px;

  font-weight: 900;

  color: var(--lime);

  min-height: 1.2em;

  padding: 4px 10px;

  border-radius: 10px;

  border: 2px solid transparent;

  transition: transform 0.15s, background 0.15s, border-color 0.15s;

}



#hud .combo.active {

  background: rgba(67, 160, 71, 0.15);

  border-color: var(--lime);

  animation: comboPulse 0.5s ease-out;

}



#hud .combo.hot {

  color: #fff;

  background: linear-gradient(135deg, #ff9800, #e65100);

  border-color: var(--zt-outline);

  box-shadow: 0 3px 0 var(--zt-shadow);

  animation: comboHot 0.6s ease-in-out infinite alternate;

}



@keyframes comboPulse {

  0% { transform: scale(0.85); opacity: 0.5; }

  60% { transform: scale(1.08); }

  100% { transform: scale(1); opacity: 1; }

}



@keyframes comboHot {

  from { transform: scale(1); }

  to { transform: scale(1.04); }

}



#hookLine {

  font-size: 9px;

  font-weight: 700;

  opacity: 0.75;

  max-width: 140px;

  line-height: 1.25;

}



/* —— BEATS meter (HTML) —— */

#beatsHud {

  position: absolute;

  right: var(--safe-x);

  top: calc(var(--safe-top) + 52px);

  width: min(120px, 28vw);

  z-index: 5;

  pointer-events: none;

  display: flex;

  flex-direction: column;

  align-items: stretch;

  gap: 3px;

}



#beatsHud.hidden {

  display: none;

}



#beatsHud .beatsLabel {

  font-size: 8px;

  font-weight: 900;

  letter-spacing: 0.14em;

  text-align: right;

  color: #fff;

  text-shadow: 1px 1px 0 var(--zt-outline);

}



#beatsHud .beatsTrack {

  height: 10px;

  background: rgba(255, 255, 255, 0.45);

  border: 2px solid var(--zt-outline);

  border-radius: 8px;

  overflow: hidden;

  box-shadow: 0 2px 0 var(--zt-shadow);

}



#beatsHud .beatsTrack i {

  display: block;

  height: 100%;

  width: 0%;

  border-radius: 6px;

  background: linear-gradient(90deg, #00deff, #39ff14);

  transition: width 0.2s ease-out, background 0.25s;

}



#beatsHud.ship-mode .beatsTrack i {

  background: linear-gradient(90deg, #ff0066, #ffca28);

  animation: shipPulse 0.8s ease-in-out infinite alternate;

}



@keyframes shipPulse {

  from { filter: brightness(1); }

  to { filter: brightness(1.15); }

}



#beatsHud .beatsMeta {

  font-size: 10px;

  font-weight: 800;

  text-align: right;

  color: #fff;

  text-shadow: 1px 1px 0 var(--zt-outline);

  font-variant-numeric: tabular-nums;

}



/* —— Écran d’accueil —— */

#startScreen {

  position: absolute;

  inset: 0;

  z-index: 12;

  display: flex;

  flex-direction: column;

  align-items: center;

  justify-content: space-between;

  padding: calc(var(--safe-top) + 20px) var(--safe-x) calc(var(--safe-bottom) + 8px);

  pointer-events: none;

  background: linear-gradient(180deg, rgba(94, 196, 240, 0.15) 0%, transparent 35%);

}



#startScreen > * {

  pointer-events: auto;

}



.logoBlock {

  text-align: center;

  pointer-events: none;

  animation: logoIn 0.6s ease-out both;

}



@keyframes logoIn {

  from { opacity: 0; transform: translateY(-12px); }

  to { opacity: 1; transform: translateY(0); }

}



.logoBlock h1 {
  font-family: var(--font-display);
  font-size: clamp(44px, 12vw, 62px);
  font-weight: 900;
  letter-spacing: 0.04em;
  color: #fff;
  text-shadow:
    4px 4px 0 var(--zt-outline),
    -1px -1px 0 var(--zt-outline),
    0 5px 0 var(--zt-shadow);
  line-height: 0.92;
  /* rev9 §18 push 9.5 : pulse subtil au tempo (≈ 145 BPM → 0.83 s, 2 beats).
     Conserve l'animation `logoIn` de la parent en cohérence (logoIn = entrée,
     puis logoPulse en boucle). */
  animation: logoPulse 0.83s 0.6s ease-in-out infinite alternate;
}

@keyframes logoPulse {
  from { transform: scale(1); }
  to   { transform: scale(1.025); }
}

.logoBlock .subtitle {
  display: inline-block;
  font-family: var(--font-display);
  font-size: 14px;
  font-weight: 900;
  color: var(--zt-outline);
  background: var(--btn-play);
  padding: 5px 16px;
  border-radius: 999px;
  border: 3px solid var(--zt-outline);
  margin-top: 12px;
  letter-spacing: 0.08em;
  box-shadow: 0 4px 0 var(--zt-shadow);
}



.hookLines {

  list-style: none;

  margin-top: 14px;

  display: flex;

  flex-direction: column;

  gap: 6px;

  pointer-events: none;

}



.hookLines li {

  font-size: 12px;

  font-weight: 800;

  color: #fff;

  text-shadow: 1px 1px 0 var(--zt-outline);

  padding: 4px 0;

}



.hookLines li::before {

  content: "▸ ";

  color: var(--btn-play);

}



.menuCard {

  width: min(360px, 94vw);

  background: var(--bubble);

  border: 4px solid var(--zt-outline);

  border-radius: 22px;

  padding: 18px 16px 16px;

  box-shadow: 0 10px 0 var(--zt-shadow);

  display: flex;

  flex-direction: column;

  gap: 14px;

  align-items: stretch;

  animation: cardUp 0.55s 0.1s ease-out both;

}



@keyframes cardUp {

  from { opacity: 0; transform: translateY(20px); }

  to { opacity: 1; transform: translateY(0); }

}



.menuStats {

  display: flex;

  justify-content: space-between;

  align-items: center;

  gap: 10px;

  padding: 10px 12px;

  background: linear-gradient(135deg, #e3f2fd 0%, #fff9c4 100%);

  border: 2px solid var(--zt-outline);

  border-radius: 14px;

}



.menuStats .menuRecord {

  font-size: 11px;

  font-weight: 800;

  text-transform: uppercase;

  letter-spacing: 0.04em;

  color: var(--zt-outline);

}



.menuStats .menuRecord strong {

  font-size: 22px;

  font-weight: 900;

  font-variant-numeric: tabular-nums;

  display: block;

  line-height: 1.1;

  margin-top: 2px;

}



.menuStats .menuDelta {

  font-size: 11px;

  font-weight: 800;

  text-align: right;

  color: var(--accent);

  line-height: 1.3;

}



.menuStats .menuDelta.neutral {

  color: #546e7a;

}



.menuStats .menuDelta.win {

  color: var(--lime);

}



#charSwitch {
  display: flex;
  gap: 8px;
  justify-content: center;
}

#charSwitch button {
  flex: 1;
  font: 800 14px inherit;
  font-family: var(--font-display);
  padding: 12px 8px;
  border-radius: 12px;
  border: 3px solid var(--zt-outline);
  background: #eceff1;
  color: var(--zt-outline);
  cursor: pointer;
  box-shadow: 0 4px 0 var(--zt-shadow);
  transition: transform 0.08s, background 0.12s, box-shadow 0.08s;
  touch-action: manipulation;
  -webkit-appearance: none;
  appearance: none;
}

/* Buddy reste caché tant que la récompense missions n'est pas débloquée. */
#charSwitch #btnBuddy[data-locked="1"] {
  display: none;
}

#charSwitch #btnBuddy {
  background: linear-gradient(135deg, #fff176, #ffca28);
  position: relative;
}

#charSwitch #btnBuddy::after {
  content: "★";
  position: absolute;
  top: 2px;
  right: 5px;
  font-size: 9px;
  color: var(--accent);
}



#charSwitch button:active {

  transform: translateY(3px);

  box-shadow: 0 1px 0 var(--zt-shadow);

}



#charSwitch button.active {

  background: #80deea;

  box-shadow: 0 4px 0 var(--zt-shadow), inset 0 0 0 2px rgba(255, 255, 255, 0.5);

}



#menuLinks {

  display: flex;

  flex-direction: column;

  gap: 10px;

}



#menuLinks .ctaRow {

  display: flex;

  gap: 10px;

  align-items: stretch;

}



#menuLinks a {
  text-align: center;
  text-decoration: none;
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 800;
  padding: 16px 12px;
  border-radius: 16px;
  border: 3px solid var(--zt-outline);
  background: var(--btn-secondary);
  color: var(--zt-outline);
  box-shadow: 0 5px 0 var(--zt-shadow);
  transition: transform 0.08s, box-shadow 0.08s;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}



#menuLinks a:active {

  transform: translateY(4px);

  box-shadow: 0 1px 0 var(--zt-shadow);

}



#menuLinks a.primary {

  flex: 1;

  background: linear-gradient(180deg, #ffe082 0%, var(--btn-play) 45%, var(--btn-play-dark) 100%);

  font-size: 20px;

  letter-spacing: 0.04em;

  padding: 18px 16px;

  position: relative;

  overflow: hidden;

}



#menuLinks a.primary::after {

  content: "";

  position: absolute;

  inset: 0;

  background: linear-gradient(105deg, transparent 40%, rgba(255, 255, 255, 0.35) 50%, transparent 60%);

  transform: translateX(-100%);

  animation: ctaShine 3s ease-in-out infinite;

}



@keyframes ctaShine {

  0%, 70% { transform: translateX(-100%); }

  100% { transform: translateX(100%); }

}



#btnMenuMore {

  flex: 0 0 56px !important;

  padding: 16px 8px !important;

  font-size: 22px !important;

  line-height: 1;

  align-self: stretch;

  display: flex;

  align-items: center;

  justify-content: center;

}



#menuPanel {

  display: none;

  flex-direction: column;

  gap: 8px;

  padding-top: 4px;

  border-top: 2px dashed rgba(42, 36, 32, 0.2);

}



body.menu-open #menuPanel {

  display: flex;

  animation: panelIn 0.2s ease-out;

}



@keyframes panelIn {

  from { opacity: 0; transform: translateY(-6px); }

  to { opacity: 1; transform: translateY(0); }

}



#menuPanel a {

  text-decoration: none;

  font-size: 13px;

  font-weight: 700;

  padding: 12px 14px;

  border-radius: 12px;

  border: 2px solid var(--zt-outline);

  background: #f5f5f5;

  color: var(--zt-outline);

  text-align: center;

  transition: background 0.1s;

  touch-action: manipulation;

  -webkit-tap-highlight-color: transparent;

}



#menuPanel a:active {

  background: #e0e0e0;

}



/* —— Carte résultat (game over / niveau) —— */

#resultCard {

  position: absolute;

  left: 50%;

  top: 50%;

  transform: translate(-50%, -50%) scale(0.92);

  z-index: 18;

  width: min(320px, 88vw);

  padding: 22px 20px 18px;

  background: var(--bubble);

  border: 4px solid var(--zt-outline);

  border-radius: 22px;

  box-shadow: 0 12px 0 var(--zt-shadow);

  text-align: center;

  pointer-events: none;

  opacity: 0;

  visibility: hidden;

  transition: opacity 0.2s, transform 0.25s cubic-bezier(0.34, 1.3, 0.64, 1), visibility 0.2s;

}



#resultCard.visible {

  opacity: 1;

  visibility: visible;

  transform: translate(-50%, -50%) scale(1);

}



#resultCard .resultTitle {
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--accent);
  margin-bottom: 6px;
}



#resultCard .resultStars {

  font-size: 36px;

  letter-spacing: 4px;

  line-height: 1.2;

  margin: 4px 0 8px;

  filter: drop-shadow(2px 2px 0 var(--zt-outline));

}



#resultCard .resultScore {
  font-family: var(--font-display);
  font-size: 50px;
  font-weight: 900;
  font-variant-numeric: tabular-nums;
  color: var(--zt-outline);
  line-height: 1;
  letter-spacing: -0.02em;
}



#resultCard .resultBreakdown {

  margin-top: 12px;

  display: flex;

  flex-direction: column;

  gap: 6px;

  font-size: 12px;

  font-weight: 700;

  color: #455a64;

}



#resultCard .resultBreakdown span {

  display: flex;

  justify-content: space-between;

  padding: 6px 10px;

  background: #f5f5f5;

  border-radius: 8px;

  border: 1px solid rgba(42, 36, 32, 0.12);

}



#resultCard .resultBreakdown strong {

  font-variant-numeric: tabular-nums;

  color: var(--zt-outline);

}



#resultCard .resultHint {

  margin-top: 14px;

  font-size: 11px;

  font-weight: 800;

  color: var(--accent);

  text-transform: uppercase;

  letter-spacing: 0.06em;

}



body.level-complete #resultCard .resultTitle {

  color: var(--lime);

}



body.game-over #resultCard .resultTitle {

  color: var(--accent);

}



/* —— Bandeau bas —— */

#bottomUi {

  position: absolute;

  left: 0;

  right: 0;

  bottom: 0;

  padding: 0 var(--safe-x) var(--safe-bottom);

  z-index: 8;

  pointer-events: none;

  display: flex;

  flex-direction: column;

  gap: 10px;

  align-items: center;

}



#beatBar {

  width: 100%;

  max-width: min(420px, 92vw);

  height: 10px;

  background: rgba(255, 255, 255, 0.55);

  border: 2px solid var(--zt-outline);

  border-radius: 10px;

  overflow: hidden;

  box-shadow: 0 3px 0 var(--zt-shadow);

  position: relative;

}



#beatBar::before {

  content: "";

  position: absolute;

  left: 50%;

  top: 0;

  bottom: 0;

  width: 3px;

  margin-left: -1.5px;

  background: var(--zt-outline);

  opacity: 0.35;

  z-index: 1;

}



#beatBar i {

  display: block;

  height: 100%;

  width: 22%;

  border-radius: 8px;

  background: linear-gradient(90deg, #ffca28, #e85d3a);

  box-shadow: 0 0 8px rgba(255, 202, 40, 0.6);

  transition: transform 0.05s linear, opacity 0.1s;

  will-change: transform;

}



#banner {
  text-align: center;
  font-family: var(--font-display);
  font-size: 14px;
  font-weight: 800;
  padding: 14px 22px;
  max-width: 92%;
  border-radius: 16px;
  border: 3px solid var(--zt-outline);
  background: var(--bubble);
  color: var(--zt-outline);
  box-shadow: 0 6px 0 var(--zt-shadow);
  pointer-events: none;
  line-height: 1.35;
  transition: background 0.18s, color 0.18s, box-shadow 0.18s, border-color 0.18s;
}

#banner.hidden {
  display: none;
}

/* —— Banner slots distincts par mode ——
 * - default / data-mode="menu" : bubble blanc (accueil)
 * - data-mode="hint"            : pill orange contour (in-game gameplay hint)
 * - data-mode="reward"          : doré attention (mission unlock)
 * - body.game-over              : pas de bulle, texte ombré
 * - body.level-complete         : pas de bulle, vert lime
 * - data-mode="continue"        : rouge urgence
 */
#banner[data-mode="hint"] {
  background: linear-gradient(135deg, #fff8e1, #ffe082);
  border-color: var(--btn-play-dark);
  color: var(--zt-outline);
  font-size: 13px;
  padding: 10px 18px;
  box-shadow: 0 5px 0 rgba(249, 168, 37, 0.45);
}

#banner[data-mode="reward"] {
  background: linear-gradient(135deg, #fff176, #ffca28);
  border-color: var(--accent);
  color: var(--zt-outline);
  box-shadow: 0 6px 0 var(--zt-shadow), 0 0 24px rgba(255, 202, 40, 0.55);
  animation: bannerReward 0.55s cubic-bezier(0.34, 1.5, 0.64, 1);
}

@keyframes bannerReward {
  0% { transform: scale(0.85) translateY(8px); opacity: 0.4; }
  100% { transform: scale(1) translateY(0); opacity: 1; }
}

#banner[data-mode="continue"] {
  background: linear-gradient(135deg, #ffccbc, #ff8a65);
  border-color: var(--accent);
  color: #fff;
  text-shadow: 1px 1px 0 var(--zt-outline);
}

body.game-over #banner {
  background: transparent;
  border: none;
  box-shadow: none;
  color: #fff;
  text-shadow: 2px 2px 0 var(--zt-outline);
  font-size: 13px;
  padding: 8px 16px;
  max-width: 100%;
}

body.level-complete #banner {
  background: transparent;
  border: none;
  box-shadow: none;
  color: #fff8e1;
  text-shadow: 2px 2px 0 var(--zt-outline), 0 0 18px rgba(57, 255, 20, 0.45);
  font-size: 13px;
  padding: 8px 16px;
  max-width: 100%;
}



/* —— FX —— */

#perfect {

  position: absolute;

  left: 50%;

  top: 38%;

  transform: translate(-50%, -50%) scale(0.7);

  font-size: clamp(28px, 8vw, 36px);

  font-weight: 900;

  color: #fff;

  opacity: 0;

  pointer-events: none;

  z-index: 15;

  text-shadow: 4px 4px 0 var(--zt-outline);

  letter-spacing: 0.06em;

  transition: opacity 0.1s, transform 0.15s cubic-bezier(0.34, 1.4, 0.64, 1);

}



#perfect.show {

  opacity: 1;

  transform: translate(-50%, -50%) scale(1.08);

}



#milestone {

  position: absolute;

  left: var(--safe-x);

  right: var(--safe-x);

  top: calc(var(--safe-top) + 72px);

  height: 8px;

  background: rgba(255, 255, 255, 0.5);

  border: 2px solid var(--zt-outline);

  border-radius: 8px;

  overflow: hidden;

  pointer-events: none;

  z-index: 5;

  box-shadow: 0 2px 0 var(--zt-shadow);

}



#milestone i {

  display: block;

  height: 100%;

  width: 0%;

  background: linear-gradient(90deg, #ffca28, #66bb6a);

  border-radius: 6px;

  transition: width 0.2s ease-out;

}



#milestone::after {

  content: "COMBO ×2";

  position: absolute;

  right: 0;

  top: -16px;

  font-size: 8px;

  font-weight: 900;

  letter-spacing: 0.08em;

  color: #fff;

  text-shadow: 1px 1px 0 var(--zt-outline);

  opacity: 0;

  transition: opacity 0.2s;

}



body.combo-active #milestone::after {

  opacity: 1;

}



#tutorialOverlay {

  position: absolute;

  inset: 0;

  z-index: 20;

  display: flex;

  align-items: center;

  justify-content: center;

  background: rgba(42, 36, 32, 0.28);

  pointer-events: none;

}



#tutorialOverlay.hidden {

  display: none;

}



#tutorialOverlay strong {

  font-size: clamp(40px, 12vw, 52px);

  font-weight: 900;

  color: #fff;

  text-shadow: 4px 4px 0 var(--zt-outline);

  animation: tapBounce 0.85s ease-in-out infinite;

}



@keyframes tapBounce {

  0%, 100% { transform: scale(1); }

  50% { transform: scale(1.08); }

}



#continueBar {

  width: 100%;

  max-width: min(420px, 92vw);

  height: 10px;

  background: rgba(255, 255, 255, 0.45);

  border: 2px solid var(--zt-outline);

  border-radius: 8px;

  overflow: hidden;

  pointer-events: none;

  box-shadow: 0 2px 0 var(--zt-shadow);

}



#continueBar.hidden {

  display: none;

}



#continueBar i {

  display: block;

  height: 100%;

  width: 100%;

  background: linear-gradient(90deg, #e85d3a, #ffca28);

  transform-origin: left center;

}



#retentionHud {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  justify-content: center;
  pointer-events: none;
  margin-top: -4px;
}



#retentionHud span {

  font-size: 10px;

  font-weight: 800;

  padding: 6px 10px;

  border-radius: 10px;

  border: 2px solid var(--zt-outline);

  background: var(--bubble);

  box-shadow: 0 3px 0 var(--zt-shadow);

}



#retentionHud .streak { color: #e65100; }

#retentionHud .daily { color: #0277bd; }



#missionStrip {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  justify-content: center;
  pointer-events: none;
  font-family: var(--font-display);
}

#missionStrip > div {
  font-size: 11px;
  font-weight: 800;
  padding: 6px 11px;
  border-radius: 999px;
  border: 2px solid var(--zt-outline);
  background: #fafafa;
  color: var(--zt-outline);
  box-shadow: 0 2px 0 var(--zt-shadow);
  letter-spacing: 0.02em;
}

#missionStrip .done {
  background: linear-gradient(135deg, #a5d6a7, #66bb6a);
  color: #1b5e20;
  border-color: #2e7d32;
}



/* —— États jeu —— */

body.playing #startScreen {

  opacity: 0;

  visibility: hidden;

  pointer-events: none;

  transition: opacity 0.18s, visibility 0.18s;

}



body.playing #hud .scoreHead,

body.playing #hud .metaBlock .best,

body.playing #retentionHud,

body.playing #missionStrip {

  opacity: 0;

  max-height: 0;

  overflow: hidden;

  margin: 0;

  padding: 0;

  transition: opacity 0.15s, max-height 0.15s;

}



body.playing #hud .scoreBlock {

  padding: 12px 20px 14px;

  border-width: 3px;

  min-width: 100px;

}



body.playing #hud .score {

  font-size: clamp(44px, 13vw, 52px);

}



body.playing #hud .metaBlock {

  position: absolute;

  right: var(--safe-x);

  top: calc(var(--safe-top) + 4px);

}



body.playing #hud .combo {

  font-size: 15px;

}



body.playing #milestone {

  opacity: 0.55;

  pointer-events: none;

}



body.playing.combo-active #milestone {

  display: block !important;

  opacity: 1;

}



body.playing.combo-active #milestone i {

  background: linear-gradient(90deg, #ff9800, #e85d3a);

}



body.playing #beatBar {

  opacity: 1;

}



body.playing #beatsHud:not(.hidden) {

  display: flex;

}



body:not(.playing) #beatBar,

body:not(.playing) #beatsHud {

  display: none;

}



/* rev11 §19 — masque la #beatBar quand le joueur a choisi le mode "halo" ou
 * "aucun" dans les settings. Le DOM existe toujours (updateBeatBar continue
 * d'écrire dedans côté JS, sans coût visible) mais reste invisible. C'est
 * la solution la moins invasive : zéro touche à la game loop, juste un
 * toggle CSS class sur <body>. */

body.rhythm-mode-halo #beatBar,

body.rhythm-mode-off #beatBar {

  display: none !important;

}



body:not(.playing) #banner {

  margin-top: 0;

  background: transparent;

  border: none;

  box-shadow: none;

  color: #fff;

  text-shadow: 2px 2px 0 var(--zt-outline);

  font-size: 13px;

  font-weight: 700;

  padding: 0;

  max-width: 90%;

}



body.playing #banner:not(.hidden) {

  display: block;

}



body.playing #bottomUi #continueBar:not(.hidden) {

  display: block;

}



body.game-over #startScreen,

body.level-complete #startScreen {

  opacity: 0;

  visibility: hidden;

}



body.game-over.playing #hud,

body.level-complete.playing #hud {

  opacity: 0.3;

}



body.game-over #resultCard.visible,

body.level-complete #resultCard.visible {

  pointer-events: none;

}

/* --------------------------------------------------------------------------
 * rev9 §18 — push 9.5/10 finitions
 * -------------------------------------------------------------------------- */

/* Live record bar : ligne mince en haut de l'écran, visible en run quand
   `bestAtRunStart > 0`. Hidden via data-attr (et hors phase playing). */
#recordTrack {
  position: absolute;
  left: var(--safe-x);
  right: var(--safe-x);
  top: calc(var(--safe-top) + 86px);
  height: 4px;
  border-radius: 6px;
  background: rgba(255, 255, 255, 0.35);
  border: 1.5px solid var(--zt-outline);
  pointer-events: none;
  z-index: 5;
  display: none;
  box-shadow: 0 2px 0 rgba(42, 36, 32, 0.18);
  overflow: visible;
}

body.playing #recordTrack:not([data-hidden]) {
  display: block;
}

#recordTrack i {
  display: block;
  height: 100%;
  width: 0%;
  border-radius: 4px;
  background: linear-gradient(90deg, #ffca28, #66bb6a);
  transition: width 0.25s cubic-bezier(0.34, 1.2, 0.64, 1);
}

#recordTrack i[data-state="close"] {
  background: linear-gradient(90deg, #ffca28, #ff6f00);
  animation: recordPulseSoft 0.7s ease-in-out infinite alternate;
}

#recordTrack i[data-state="beat"] {
  background: linear-gradient(90deg, #66bb6a, #39ff14);
  animation: recordPulseSoft 0.5s ease-in-out infinite alternate;
}

@keyframes recordPulseSoft {
  from { filter: brightness(1); box-shadow: 0 0 0 0 rgba(255, 202, 40, 0); }
  to   { filter: brightness(1.18); box-shadow: 0 0 8px 1px rgba(255, 202, 40, 0.55); }
}

#recordTrack #recordTag {
  position: absolute;
  right: 0;
  top: -14px;
  font-family: var(--font-display);
  font-size: 9px;
  font-weight: 800;
  letter-spacing: 0.08em;
  color: #fff;
  text-shadow: 1.5px 1.5px 0 var(--zt-outline);
  font-variant-numeric: tabular-nums;
}

/* Combo border pulse — quand combo×2 actif, le bloc score PULSE pour qu'on
   ne puisse PAS rater le state actif. Spec §push 9.5 : "impossible à rater". */
body.combo-active #hud .scoreBlock {
  border-color: var(--combo-hot);
  animation: comboBorderPulse 0.45s ease-in-out infinite alternate;
}

@keyframes comboBorderPulse {
  from {
    box-shadow: 0 5px 0 var(--zt-shadow), 0 0 0 0 rgba(255, 111, 0, 0);
  }
  to {
    box-shadow: 0 5px 0 var(--zt-shadow), 0 0 0 6px rgba(255, 111, 0, 0.32),
                0 0 18px rgba(255, 142, 0, 0.45);
  }
}

body.combo-active #hud .score {
  color: var(--combo-hot);
  text-shadow: 0 0 8px rgba(255, 111, 0, 0.45);
}

/* Result card : micro-animation d'entrée renforcée (au-delà du transition CSS) :
   wobble léger après que la carte ait "popped". */
#resultCard.visible {
  animation: resultCardSettle 0.55s 0.18s cubic-bezier(0.34, 1.4, 0.64, 1) both;
}

@keyframes resultCardSettle {
  0%   { transform: translate(-50%, -50%) scale(0.94) rotate(-1.2deg); }
  50%  { transform: translate(-50%, -50%) scale(1.025) rotate(0.6deg); }
  100% { transform: translate(-50%, -50%) scale(1) rotate(0deg); }
}

/* Score-hero : un peu plus long pour absorber le scale 1.5x. */
#hud .score.score-hero {
  animation: scoreHero 0.72s cubic-bezier(0.34, 1.55, 0.4, 1);
}

/* Tutorial overlay : flèche TAP au lieu d'un texte plat (plus iconographique). */
#tutorialOverlay strong::after {
  content: "";
  display: block;
  width: 0;
  height: 0;
  margin: 12px auto 0;
  border-left: 14px solid transparent;
  border-right: 14px solid transparent;
  border-top: 18px solid #fff;
  filter: drop-shadow(2px 2px 0 var(--zt-outline));
}

/* --------------------------------------------------------------------------
 * rev11-fix2 — sélecteur audio 5 modes (off / classic / sfx / sfx-tick / perc).
 * `classic` (SFX originaux mélodiques courts) est le NOUVEAU DEFAULT au 1er
 * install — cf. précision PO du 21 mai (docs/AUDIO-STRATEGY.md §9). Les 3
 * modes halal restent disponibles, marqués par le chip `.amTag` inline.
 * Bloc dans #menuPanel, style cohérent ZT / cartoon (outline noir + shadow).
 * Doc test : docs/AUDIO-SAMPLES-TEST.md.
 * -------------------------------------------------------------------------- */
.settingsBlock {
  border: 2px solid var(--zt-outline);
  border-radius: 14px;
  padding: 10px 12px 12px;
  margin: 4px 0;
  background: #fafafa;
  box-shadow: 0 3px 0 var(--zt-shadow);
}

.settingsBlock legend {
  font-family: var(--font-display);
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--zt-outline);
  padding: 0 6px;
  background: var(--bubble);
  border: 2px solid var(--zt-outline);
  border-radius: 999px;
  margin-left: 4px;
}

.settingsBlock legend .halalTag {
  display: inline-block;
  margin-left: 4px;
  padding: 1px 6px;
  font-size: 9px;
  font-weight: 800;
  letter-spacing: 0.04em;
  text-transform: lowercase;
  color: #1b5e20;
  background: linear-gradient(135deg, #c8e6c9, #a5d6a7);
  border: 1.5px solid #2e7d32;
  border-radius: 8px;
  vertical-align: middle;
}

.audioModeGrid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 6px;
  margin-top: 8px;
}

/* 5 boutons en grille 2-col : Silence + Classic (row 1), SFX + SFX+Tick
 * (row 2), Daff loop full-width (row 3). On span le 5ᵉ pour éviter une
 * cellule orpheline qui aurait l'air d'un bug. */
.audioModeBtn[data-audio-mode="perc"] {
  grid-column: 1 / -1;
}

.audioModeBtn {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  padding: 10px 6px;
  border-radius: 12px;
  border: 2.5px solid var(--zt-outline);
  background: #eceff1;
  color: var(--zt-outline);
  cursor: pointer;
  box-shadow: 0 3px 0 var(--zt-shadow);
  transition: transform 0.08s, background 0.12s, box-shadow 0.08s;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  -webkit-appearance: none;
  appearance: none;
  font-family: inherit;
  text-align: center;
}

.audioModeBtn .amLabel {
  font-family: var(--font-display);
  font-size: 12px;
  font-weight: 900;
  letter-spacing: 0.02em;
  line-height: 1.1;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  flex-wrap: wrap;
  justify-content: center;
}

.audioModeBtn .amHint {
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.04em;
  opacity: 0.68;
  line-height: 1.1;
}

/* Chip "halal" inline dans le label des 3 modes halal (sfx / sfx-tick / perc).
 * Repris du style .halalTag du legend mais en taille réduite pour tenir dans
 * un bouton compact. Mode 'classic' n'a PAS ce chip (cf. AUDIO-STRATEGY §9). */
.audioModeBtn .amTag {
  display: inline-block;
  padding: 0 5px;
  font-family: inherit;
  font-size: 8.5px;
  font-weight: 800;
  letter-spacing: 0.04em;
  text-transform: lowercase;
  color: #1b5e20;
  background: linear-gradient(135deg, #c8e6c9, #a5d6a7);
  border: 1.2px solid #2e7d32;
  border-radius: 6px;
  line-height: 1.5;
  vertical-align: middle;
}

/* Étoile "défaut" sur le bouton Classic — marqueur visuel discret rappelant
 * que c'est le nouveau default au 1er install. N'interfère pas avec l'état
 * .active (qui change le fond du bouton complet). */
.audioModeBtn .amDefault {
  display: inline-block;
  color: var(--btn-play-dark);
  font-size: 12px;
  line-height: 1;
  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.6);
}

.audioModeBtn:active {
  transform: translateY(2px);
  box-shadow: 0 1px 0 var(--zt-shadow);
}

.audioModeBtn.active {
  background: linear-gradient(135deg, #fff8e1, #ffe082);
  border-color: var(--btn-play-dark);
  box-shadow: 0 3px 0 var(--zt-shadow), inset 0 0 0 2px rgba(255, 255, 255, 0.55);
}

.audioModeBtn.active .amHint {
  opacity: 0.85;
  color: var(--accent);
}

/* Mode 'classic' (nouveau default) — pastille ambre chaude pour rappel
 * "c'est le mode recommandé par défaut". Légère mise en avant statique :
 * fond ivoire même sans .active pour attirer l'œil au 1er coup d'œil. */
.audioModeBtn.am-default {
  background: linear-gradient(135deg, #fffde7, #fff9c4);
  border-color: #f9a825;
}
.audioModeBtn.am-default:not(.active) .amHint {
  color: #6d4c00;
  opacity: 0.78;
}
.audioModeBtn[data-audio-mode="classic"].active {
  background: linear-gradient(135deg, #fff3a3, #ffd54f);
  border-color: #f57f17;
  box-shadow: 0 3px 0 var(--zt-shadow), inset 0 0 0 2px rgba(255, 255, 255, 0.65);
}
.audioModeBtn[data-audio-mode="classic"].active .amHint {
  color: #6d4c00;
}

/* Tag visuel doux pour le mode 'perc' : pastille daff-rose. */
.audioModeBtn[data-audio-mode="perc"].active {
  background: linear-gradient(135deg, #fce4ec, #f8bbd0);
  border-color: var(--accent);
}
.audioModeBtn[data-audio-mode="perc"].active .amHint {
  color: var(--accent);
}

/* Mode 'off' = pastille neutre grise quand actif (calme). */
.audioModeBtn[data-audio-mode="off"].active {
  background: linear-gradient(135deg, #eceff1, #cfd8dc);
  border-color: #455a64;
}
.audioModeBtn[data-audio-mode="off"].active .amHint {
  color: #455a64;
}

/* --------------------------------------------------------------------------
 * rev11 §19 — Sélecteur "Indicateur rythme" (Halo / Barre / Aucun).
 * Reprend les styles `.settingsBlock` partagés. 3 boutons → grid 3 colonnes.
 * Default actif : "Halo" (cf. localStorage `pulsejump.rhythmMode`).
 * -------------------------------------------------------------------------- */
.rhythmModeGrid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 6px;
  margin-top: 8px;
}

.rhythmModeBtn {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  padding: 10px 6px;
  border-radius: 12px;
  border: 2.5px solid var(--zt-outline);
  background: #eceff1;
  color: var(--zt-outline);
  cursor: pointer;
  box-shadow: 0 3px 0 var(--zt-shadow);
  transition: transform 0.08s, background 0.12s, box-shadow 0.08s;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  -webkit-appearance: none;
  appearance: none;
  font-family: inherit;
  text-align: center;
}

.rhythmModeBtn .rmLabel {
  font-family: var(--font-display);
  font-size: 12px;
  font-weight: 900;
  letter-spacing: 0.02em;
  line-height: 1.1;
}

.rhythmModeBtn .rmHint {
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.04em;
  opacity: 0.68;
  line-height: 1.1;
}

.rhythmModeBtn:active {
  transform: translateY(2px);
  box-shadow: 0 1px 0 var(--zt-shadow);
}

.rhythmModeBtn.active {
  background: linear-gradient(135deg, #e0f7fa, #80deea);
  border-color: #00838f;
  box-shadow: 0 3px 0 var(--zt-shadow), inset 0 0 0 2px rgba(255, 255, 255, 0.55);
}

.rhythmModeBtn.active .rmHint {
  opacity: 0.85;
  color: #006064;
}

.rhythmModeBtn[data-rhythm-mode="halo"].active {
  background: linear-gradient(135deg, #e0f7fa, #80deea);
  border-color: #00838f;
}

.rhythmModeBtn[data-rhythm-mode="bar"].active {
  background: linear-gradient(135deg, #fff8e1, #ffe082);
  border-color: var(--btn-play-dark);
}

.rhythmModeBtn[data-rhythm-mode="off"].active {
  background: linear-gradient(135deg, #eceff1, #cfd8dc);
  border-color: #455a64;
}
.rhythmModeBtn[data-rhythm-mode="off"].active .rmHint {
  color: #455a64;
}

