/* === En Zistoir Design System v5.0 — « Kolaz Vakans » (La Réunion) ===
   Direction « carnet de vacances / scrapbook » : papier kraft #f3e9d7 à texture
   pointillée, encre brun chaud #33302a, accent rouge (rouge dominant du logo) #a02a1a + jaune washi #ffe082.
   Photos « scotchées » légèrement inclinées, ruban adhésif (washi tape), bords
   pointillés, notes manuscrites (Caveat), ombres DOUCES (pas d'ombre dure). Typo :
   Bricolage Grotesque (titres/corps) + Caveat (accents manuscrits : notes, CTA, scores).

   ┌─────────────────────────────────────────────────────────────────────┐
   │  FICHIER DE THÈME — ne pas éditer la copie active `css/app.css`.     │
   │  Source de vérité : `css/themes/kolaz-vakans/app.css`.               │
   │  Bascule / retour arrière :  scripts/switch-theme.sh <thème>         │
   │  Thèmes archivés : arcade-tropikal · zournal-kreol (Web) · tizor (Maui) │
   └─────────────────────────────────────────────────────────────────────┘

   Architecture de tokens conservée : les noms existants (--bg/--ink/--ember/--tz-*…)
   sont remis à la palette Kolaz Vakans → propagation automatique. Couleurs de marque
   brutes sous --tz-* ; tokens spécifiques Kolaz sous --kv-* ; traitements de surface
   des primitives sous --ui-*. */

/* ── Palette Kolaz Vakans (default) ── */
:root {
  /* Brand ramp — accent rouge (rouge dominant du logo) + jaune washi, secondaires pastel/sauge */
  --tz-teal-d:  #5b7a6e;   /* sauge profonde */
  --tz-teal:    #7a8f85;   /* sauge (tampons « VALIDÉ ») */
  --tz-green:   #2e5243;   /* vert profond (rareté « commune ») */
  --tz-green-d: #2e5243;
  --tz-coral:   #a02a1a;   /* ROUGE (logo) — accent primaire : CTA, liens, scores */
  --tz-coral-d: #7c1c14;
  --tz-gold:    #ffe082;   /* JAUNE washi tape / surligneur */
  --tz-amber:   #e0a54d;
  --tz-purple:  #5b3f6e;   /* prune (rareté « épique ») */
  --tz-sky:     #6aa9c0;

  /* Surfaces — papier kraft + cartes/photos blanches */
  --bg:         #f3e9d7;
  --bg-soft:    #ede1cb;
  --bg-card:    #ffffff;

  /* Ink / text — brun chaud */
  --ink:        #33302a;
  --ink-soft:   #6b6559;   /* corps */
  --muted:      #a39a87;   /* notes manuscrites, méta discrète */
  --muted-2:    #b8ae99;

  /* Lines — filets kraft & bords pointillés */
  --line:        #efe6d2;
  --line-strong: #d9cbb2;  /* couleur des bords pointillés */

  /* Semantic accents (legacy aliases) */
  --canopy:      #7a8f85;
  --canopy-soft: #e5ede9;
  --ember:       #a02a1a;  /* rouge (logo) — accent signature */
  --ember-soft:  #f4e0da;

  /* Typography — Kolaz Vakans */
  --font-sans:  'Bricolage Grotesque', system-ui, -apple-system, sans-serif; /* corps 500, titres 800 */
  --font-serif: 'Bricolage Grotesque', system-ui, sans-serif;                /* display = grotesque gras */
  --font-hand:  'Caveat', 'Bricolage Grotesque', cursive;                    /* accents manuscrits */
  --font-mono:  ui-monospace, 'Spline Sans Mono', SFMono-Regular, monospace; /* data légère */

  /* Radii — Kolaz est « papier découpé » : coins nets */
  --r-sm: 3px;
  --r:    4px;
  --r-lg: 5px;
  --r-xl: 6px;

  /* Elevation — ombres DOUCES (photo soulevée), teintées encre chaude */
  --tz-shadow:    0 14px 32px -16px rgba(51,48,42,.45);
  --tz-shadow-lg: 0 18px 44px -20px rgba(51,48,42,.55);
  --tz-grad-brand: linear-gradient(120deg,#a02a1a,#c04a34);
  --tz-grad-page:  #f3e9d7;  /* fond uni ; la texture pointillée est posée sur <body> */

  /* ── Tokens spécifiques Kolaz Vakans (--kv-*) ── */
  --kv-paper:   #f3e9d7;
  --kv-ink:     #33302a;
  --kv-rose:    #a02a1a;
  --kv-jaune:   #ffe082;
  --kv-sage:    #7a8f85;
  --kv-dash:    #d9cbb2;
  --kv-note:    #a39a87;   /* gris des notes manuscrites */
  /* Ruban adhésif (washi tape) — rectangles semi-transparents posés sur les cartes */
  --kv-tape-jaune: rgba(255,224,130,.85);
  --kv-tape-rose:  rgba(160,42,26,.40);
  --kv-tape-mint:  rgba(205,228,218,.90);
  /* Aplats pastel des vignettes/photos (dégradés hachurés posés en ligne dans les pages) */
  --kv-mint:    #cde4da;
  --kv-peach:   #f4d9c2;
  --kv-lavender:#e4d2ec;
  --kv-aqua:    #c9e6ef;
  /* Ombres */
  --kv-shadow-photo: 0 18px 38px -16px rgba(51,48,42,.55);
  --kv-shadow-soft:  0 12px 28px -12px rgba(51,48,42,.40);
  --kv-shadow-tab:   3px 3px 0 rgba(51,48,42,.20);   /* petite ombre nette des chips/icônes bordées */
  /* Texture pointillée du papier */
  --kv-dots: radial-gradient(rgba(51,48,42,.05) 1.2px, transparent 1.2px);

  /* ── Traitements de surface consommés par les primitives (--ui-*) ──
     En Kolaz, les éléments bordés portent une fine bordure encre + une petite
     ombre nette (3px), pas l'ombre dure décalée d'Arcade. Repli = rendu legacy. */
  --ui-stroke:            var(--kv-ink);
  --ui-btn-border:        2px solid var(--kv-ink);
  --ui-btn-shadow:        var(--kv-shadow-tab);
  --ui-btn-shadow-active: 1px 1px 0 rgba(51,48,42,.20);
  --ui-chip-border:       2px solid var(--kv-ink);
  --ui-chip-shadow:       3px 3px 0 rgba(51,48,42,.16);
  --ui-badge-border:      none;
  --ui-badge-shadow:      0 4px 10px -6px rgba(51,48,42,.4);
}

/* ── Palette Cirques (variante fraîche) ── */
[data-palette="cirques"] {
  --canopy:     #5b7a86;
  --canopy-soft:#e2edf0;
  --ember:      #6aa9c0;
  --ember-soft: #e4f1f5;
}

/* ── Palette Volcan (variante chaude) ── */
[data-palette="volcan"] {
  --canopy:     #c2694a;
  --canopy-soft:#f6e3d8;
  --ember:      #a02a1a;
  --ember-soft: #f4e0da;
}

/* ── Reset & Base ── */
*, *::before, *::after { box-sizing: border-box; }
html, body, #root { height: 100%; }

body {
  background-color: var(--bg);
  background-image: var(--kv-dots);
  background-size: 22px 22px;
  background-attachment: fixed;
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: 14px;
  font-weight: 600;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  margin: 0;
  padding: 0;
}

button { font: inherit; color: inherit; cursor: pointer; }
a { color: inherit; }
input, textarea, select { font: inherit; color: inherit; }
input:focus, select:focus, textarea:focus { outline: none; border-color: var(--ember) !important; }

/* Focus scripté (FocusOnNavigate) — pas de cadre autour du titre de page.
   `<FocusOnNavigate Selector="h1">` (Routes.razor) déplace le focus sur le <h1>
   à chaque navigation, afin que les lecteurs d'écran annoncent la nouvelle page.
   Blazor pose pour cela un `tabindex="-1"` sur l'élément puis appelle `.focus()` :
   comme aucune interaction ne précède ce focus scripté, les navigateurs le classent
   « visible » (:focus-visible) et peignent leur anneau par défaut — d'où le cadre
   bleu autour du titre, qui ne s'efface qu'au premier clic ailleurs.
   Un élément `tabindex="-1"` n'est jamais atteignable au Tab : l'anneau n'y indique
   aucune position de navigation. On le retire donc pour ces seules cibles de focus
   scriptées ; liens, boutons et champs conservent le leur. */
[tabindex="-1"]:focus { outline: none; }

/* ── Typography ──
   .display rend Bricolage Grotesque (gras 800, serré). L'emphase <em> devient un
   surlignage jaune washi (façon feutre), sans italique. Un utilitaire .hand rend
   les accents manuscrits en Caveat. */
.display {
  font-family: var(--font-serif);
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.03;
  color: var(--ink);
}
.display em {
  font-style: normal;
  background: var(--kv-jaune);
  box-decoration-break: clone;
  -webkit-box-decoration-break: clone;
  padding: 0 .16em;
}

.hand { font-family: var(--font-hand); font-weight: 700; color: var(--kv-rose); }

.mono {
  font-family: var(--font-mono);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.eyebrow {
  font-family: var(--font-sans);
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.hairline { background: var(--line); height: 1px; width: 100%; }

/* ── Responsive visibility ── */
.th-hide-desktop { display: none; }
.th-hide-mobile { display: initial; }
.th-brand-sub { display: inline; }
@media (max-width: 1180px) { .th-brand-sub { display: none; } }
@media (max-width: 1024px) { .th-conn-label { display: none; } }

/* ── Page sections fill the column-flex <main> ──
   MainLayout's <main> is a column flex container (display:flex; flex-direction:column).
   Page section wrappers use `max-width:…; margin:0 auto` to cap-and-center their content.
   In flexbox, horizontal `auto` margins disable the default `align-items:stretch`, so such
   a wrapper collapses to its content's max-content width instead of spanning the row — e.g.
   the home "À la une" flex card (flex bases 280px + 320px) shrank to ~600px and centered,
   while the 3 concept cards above it (a grid with wide text) stayed near full width, leaving
   them visibly misaligned. The same caused the Pro "formules" grid to shrink under its hero.
   Forcing width:100% restores full-width behavior — still capped by each wrapper's own
   max-width and centered by its margin:auto. Targets only MainLayout (AuthLayout uses a div). */
main > * { width: 100%; }

/* ── Layout utilities ── */
.th-row-stack { display: grid; gap: 64px; align-items: end; }
.th-row-stack.cols-58 { grid-template-columns: 1.4fr 1fr; }
.th-row-stack.cols-eq { grid-template-columns: 1fr 1fr; }

.th-stats { display: grid; gap: 24px; }
.th-stats.cols-5 { grid-template-columns: repeat(5, 1fr); }
.th-stats.cols-4 { grid-template-columns: repeat(4, 1fr); }

.th-grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.th-grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
@media (max-width: 640px) { .th-grid-3 { grid-template-columns: 1fr; } }
.th-grid-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 20px; }
.th-home-popular { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; }
@media (max-width: 900px) { .th-home-popular { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .th-home-popular { grid-template-columns: 1fr; } }
.th-editor-split { display: grid; grid-template-columns: 380px 1fr 320px; flex: 1; min-height: 0; }
.th-recap-grid { display: grid; grid-template-columns: 1.2fr 1fr 1fr 1fr; }
.th-recap-bottom { display: grid; grid-template-columns: 1.2fr 1fr; gap: 24px; }
.th-pad-page { padding: 0 28px 80px; }

/* ── Fluid headline sizes ── */
.th-hero-headline { font-size: clamp(36px, 6.4vw, 64px); }
.th-detail-headline { font-size: clamp(32px, 5.5vw, 56px); }
.th-section-headline { font-size: clamp(26px, 3.6vw, 48px); }
.th-play-headline { font-size: clamp(26px, 3.6vw, 42px); }
.th-recap-headline { font-size: clamp(34px, 5.6vw, 64px); }
/* Page indice mobile : titre d'étape un peu plus discret que le clamp desktop ci-dessus. */
@media (max-width: 900px) {
  .th-play-headline { font-size: clamp(19px, 5.2vw, 24px); }
}

/* ── Shell row ── */
.th-shell-row {
  max-width: 1440px;
  margin: 0 auto;
  height: 60px;
  padding: 0 20px;
  display: flex;
  align-items: center;
  gap: 16px;
}

/* ── Chasse "mode jeu" (mobile ET desktop) ──
   /chasse/{id} une fois la session du joueur démarrée : le hero + le contenu de consultation
   cèdent la place au shell immersif dédié carte/collection/photo (voir GameModeState +
   ChasseDetail.razor), quelle que soit la largeur d'écran — comme le mode traversée, qui
   retire déjà son propre header sur toutes les tailles (IsImmersiveGameRoute). Les ajustements
   propres au desktop (coque plein écran, overlays agrandis) vivent dans le bloc
   .th-play2-chasse plus bas, scoped pour ne jamais déborder sur le mode traversée. */
.th-game-hide-mobile { display: none !important; }
.th-game-shell {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
}
/* Verrouillage de la racine à 100dvh (voir .th-game-root) : le header/footer/barre du bas
   globaux sont masqués pendant le jeu, le shell remplit donc tout l'écran. Une hauteur
   *définitive* remonte ainsi la chaîne flex (root → main → .th-game-shell → .th-play2-shell →
   conteneur carte), ce qui permet à la carte Leaflet de prendre MapHeight="100%" sans rester à
   hauteur 0.
   min-height:0 !important — MainLayout pose un `min-height:100vh` EN LIGNE dès que la route
   n'est pas une route de jeu, et /collection/{id} n'en est pas une. Sur mobile, 100vh (barre
   d'URL masquée) est PLUS GRAND que 100dvh (barre visible) : ce min-height l'emportait, la
   coque dépassait le bas de l'écran et il fallait faire défiler pour atteindre le déclencheur. */
.th-game-root { height: 100dvh; min-height: 0 !important; overflow: hidden; }

/* ── Menu mobile : bouton hamburger + tiroir latéral ──
   Remplace l'ancienne barre de navigation du bas. Hors jeu, la navigation mobile
   passe désormais par un tiroir classique qui s'ouvre/se ferme (menu à trois barres).
   Le bouton (.th-burger) et le tiroir (.th-drawer) n'apparaissent que sur mobile
   (≤ 900px) ; sur desktop la nav horizontale de l'en-tête reste seule (.th-hide-mobile). */
.th-burger {
  display: none;
  align-items: center;
  justify-content: center;
  background: var(--bg-soft);
  border: 1px solid var(--line-strong);
  color: var(--ink);
  cursor: pointer;
  padding: 9px;
  border-radius: 10px;
  flex-shrink: 0;
}

/* Tiroir : toujours présent dans le DOM (pour animer l'ouverture/fermeture),
   masqué sur desktop, hors écran tant qu'il n'est pas ouvert (.th-drawer--open). */
.th-drawer { display: none; }

@media (max-width: 900px) {
  .th-burger { display: inline-flex; }

  .th-drawer { display: block; }

  .th-drawer__scrim {
    position: fixed;
    inset: 0;
    z-index: 300;
    background: color-mix(in oklch, var(--ink) 45%, transparent);
    opacity: 0;
    pointer-events: none;
    transition: opacity .2s ease;
  }

  /* position:fixed → le panneau hors écran (translateX(100%)) ne crée pas de
     débordement horizontal : il est borné par le viewport. */
  .th-drawer__panel {
    position: fixed;
    top: 0; right: 0; bottom: 0;
    z-index: 301;
    width: min(84vw, 340px);
    display: flex;
    flex-direction: column;
    background: var(--bg-card);
    border-left: 1px solid var(--line-strong);
    box-shadow: -18px 0 44px -22px rgba(36, 28, 18, .5);
    transform: translateX(100%);
    transition: transform .24s ease;
    padding-bottom: env(safe-area-inset-bottom);
    overflow-y: auto;
  }

  .th-drawer--open .th-drawer__scrim { opacity: 1; pointer-events: auto; }
  .th-drawer--open .th-drawer__panel { transform: translateX(0); }

  .th-drawer__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 16px 16px 12px;
    border-bottom: 1px solid var(--line);
  }
  .th-drawer__title {
    font-family: var(--font-serif);
    font-weight: 700;
    font-size: 17px;
    color: var(--ink);
  }
  .th-drawer__close {
    display: flex;
    background: var(--bg-soft);
    border: 1px solid var(--line-strong);
    color: var(--ink);
    cursor: pointer;
    padding: 8px;
    border-radius: 10px;
  }
  .th-drawer__links {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 12px;
  }
  .th-drawer__link {
    display: flex;
    align-items: center;
    gap: 13px;
    width: 100%;
    text-align: left;
    background: transparent;
    border: none;
    cursor: pointer;
    padding: 13px 14px;
    border-radius: 12px;
    color: var(--ink-soft);
    font-family: var(--font-sans);
    font-weight: 800;
    font-size: 15px;
    transition: background .15s ease, color .15s ease;
  }
  .th-drawer__link:hover { background: var(--bg-soft); }
  .th-drawer__link.is-active {
    background: var(--ember-soft);
    color: var(--ember);
  }
}

/* ── Footer (liens légaux + copyright) ──
   Une seule rangée sur desktop : les liens « Informations » (mentions légales,
   CGU, confidentialité, cookies, hébergement) à gauche, le copyright manuscrit
   à droite. Sur mobile (≤ 640px) la rangée passe en COLONNE CENTRÉE : les liens
   s'enroulaient sur deux lignes collées au bord gauche, ce qui donnait un bloc
   visuellement bancal sous le contenu centré de la page.
   Ces règles vivent ici (et non en style inline dans MainLayout.razor) parce
   qu'un style inline `justify-content:space-between` l'emporterait sur la media
   query. */
.th-footer__inner {
  max-width: 1400px;
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px 30px;
  flex-wrap: wrap;
}
.th-footer__nav {
  display: flex;
  align-items: center;
  gap: 12px 26px;
  flex-wrap: wrap;
}
.th-footer__copy {
  font-family: var(--font-hand);
  font-weight: 700;
  font-size: 19px;
  color: var(--muted);
  flex-shrink: 0;
}
@media (max-width: 640px) {
  .th-footer__inner {
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
  }
  .th-footer__nav { justify-content: center; }
}

/* ── Tabbed editor mobile ── */
.th-editor-pane-map { min-height: 360px; }

@media (max-width: 900px) {
  .th-editor-split[data-active-tab="list"] .th-editor-pane-map,
  .th-editor-split[data-active-tab="list"] .th-editor-pane-inspect { display: none !important; }
  .th-editor-split[data-active-tab="map"] .th-editor-pane-list,
  .th-editor-split[data-active-tab="map"] .th-editor-pane-inspect { display: none !important; }
  .th-editor-split[data-active-tab="inspect"] .th-editor-pane-list,
  .th-editor-split[data-active-tab="inspect"] .th-editor-pane-map { display: none !important; }
  .th-editor-pane-list, .th-editor-pane-inspect { border: none !important; }
  .th-editor-pane-map { min-height: calc(100vh - 220px); }
}

/* ── Editor toolbar ── */
.th-editor-toolbar {
  padding: 12px 20px;
  border-bottom: 1px solid var(--line);
  background: var(--bg);
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}

/* ── Editor tabs mobile ── */
.th-editor-tabs {
  display: flex;
  border-bottom: 1px solid var(--line);
  background: var(--bg-soft);
}

/* ── Modal bottom-sheet mobile ── */
@media (max-width: 640px) {
  .th-modal-overlay { align-items: flex-end !important; }
  .th-modal {
    width: 100% !important;
    max-width: 100% !important;
    border-radius: 16px 16px 0 0 !important;
    animation: th-slide-up 0.22s ease-out;
  }
}

/* ── Animations ── */
@keyframes th-pulse {
  0%, 100% { transform: scale(1); opacity: 0.18; }
  50% { transform: scale(1.8); opacity: 0; }
}
@keyframes th-fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}
@keyframes th-slide-up {
  from { transform: translateY(24px); opacity: 0.5; }
  to { transform: translateY(0); opacity: 1; }
}
@keyframes th-pulse-ring {
  0%, 100% { box-shadow: 0 0 0 0 rgba(255, 59, 48, 0.45); }
  50% { box-shadow: 0 0 0 14px rgba(255, 59, 48, 0); }
}
/* Éclair de déclencheur : flash blanc bref au moment où l'on prend la photo,
   pour un retour visuel immédiat pendant que la capture haute qualité se traite. */
@keyframes th-shutter-flash {
  0% { opacity: 0.85; }
  100% { opacity: 0; }
}
@keyframes th-spin {
  to { transform: rotate(360deg); }
}

/* ── Scrollbar ── */
::-webkit-scrollbar { width: 9px; height: 9px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: rgba(36,28,18,.22);
  border-radius: 9px;
}

/* ── Responsive breakpoints ── */
@media (max-width: 900px) {
  .th-row-stack.cols-58,
  .th-row-stack.cols-eq { grid-template-columns: 1fr; gap: 28px; }
  .th-stats.cols-5 { grid-template-columns: repeat(3, 1fr); }
  .th-stats.cols-4 { grid-template-columns: repeat(2, 1fr); }
  .th-grid-2 { grid-template-columns: 1fr; }
  .th-editor-split { grid-template-columns: 1fr; }
  .th-recap-grid { grid-template-columns: repeat(2, 1fr); }
  .th-recap-bottom { grid-template-columns: 1fr; }
  .th-pad-page { padding: 0 18px 96px; }
  .th-hide-mobile { display: none !important; }
  .th-hide-desktop { display: initial; }
}

@media (max-width: 640px) {
  .th-stats.cols-5,
  .th-stats.cols-4 { grid-template-columns: repeat(2, 1fr); gap: 16px; }
  .th-grid-cards { grid-template-columns: 1fr; gap: 16px; }
  .th-pad-page { padding: 0 14px 96px; }
}

/* ── Accessibility ── */
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0; }

/* ── Legacy compat shim (form-control for InputText in auth pages) ── */
.form-control { width: 100%; }

/* ── Play page — mode jeu (/jeu/{id}) : menu à 4 éléments fixes (boussole,
   points, temps + étapes, action de validation), en bas de page. Un seul menu,
   quelle que soit la taille d'écran — remplace l'ancienne sub-bar desktop et la
   barre du bas mobile à onglets (voir MainLayout.IsGameRoute, qui masque la nav
   globale sur cette route, et JeuSession.razor). ── */
.th-play-menu {
  display: flex;
  align-items: stretch;
  flex: 0 0 auto;
  border-top: 1px solid var(--line);
  background: var(--bg);
  /* Pas de padding-bottom safe-area ici : <main> (MainLayout) le fournit déjà
     via son propre padding-bottom, et ce menu est un enfant de flux normal
     (contrairement à l'ancienne .th-play-gamebar, position:fixed). */
}
.th-play-menu > *:not(:last-child) { border-right: 1px solid var(--line); }
.th-play-menu-item {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  min-width: 0;
  padding: 10px 6px;
  border: none;
  background: none;
  color: var(--ink);
  font-family: var(--font-sans);
  cursor: default;
}
button.th-play-menu-item { cursor: pointer; }
button.th-play-menu-item:disabled { cursor: default; opacity: .55; }
.th-play-menu-value {
  font-size: 15px;
  font-weight: 700;
  max-width: 100%;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.th-play-menu-label { font-size: 9.5px; }
.th-play-compass { display: flex; align-items: center; justify-content: center; color: var(--ember); }
.th-play-compass svg { transition: transform .25s ease; }
.th-play-menu-cta {
  flex: 1.15;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  padding: 10px 6px;
  border: none;
  background: var(--ember);
  color: #fff;
  font-family: var(--font-sans);
  cursor: pointer;
}
.th-play-menu-cta .th-play-menu-value { color: #fff; font-size: 12px; font-weight: 800; white-space: normal; text-align: center; }

/* ── Corps de jeu : carte (2/6 de la hauteur) fusionnée à l'indice (4/6) —
   toujours affichées ensemble, quelle que soit la taille d'écran (plus de
   bascule carte/indice mobile). ── */
.th-play-body {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
}
.th-play-clue-panel {
  flex: 4 1 0%;
  min-height: 0;
  overflow-y: auto;
  padding: 20px clamp(16px, 4vw, 32px) 28px;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

/* ── Titre de l'étape — au-dessus de la carte (voir JeuSession.razor). ── */
.th-play-title-bar {
  flex: 0 0 auto;
  padding: 16px clamp(16px, 4vw, 32px) 4px;
}

/* ── Badges (type/points/zone/hors-ligne) — overlay en haut de la carte, plutôt
   que dans l'indice (voir JeuSession.razor). Fond translucide flouté : certains
   badges (Tone="outline") ont un fond transparent, illisible sur les tuiles de
   la carte sans ce bandeau. Leaflet garde son control de zoom en bottomright et
   son attribution désactivée (voir leaflet-route-map.js) : rien en haut ne peut
   entrer en conflit avec ce bandeau. ── */
.th-play-map-badges {
  position: absolute;
  top: 0; left: 0; right: 0;
  padding: 12px 14px;
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  background: color-mix(in oklch, var(--bg-card) 85%, transparent);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  pointer-events: none;
}

/* ── Indice principal — pleine largeur, sans encadré ni libellé. ── */
.th-play-clue-text {
  font-family: var(--font-serif);
  font-style: italic;
  font-size: clamp(17px, 2.6vw, 20px);
  color: var(--ink);
  margin: 0;
  line-height: 1.55;
}

/* ── Bouton média — incite au clic (pulsation tz-pulse), ouvre le média en
   grand (lightbox plein écran, voir JeuSession.razor) plutôt que de l'intégrer
   directement dans l'indice. ── */
.th-play-media-btn {
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 10px 18px;
  border: none;
  border-radius: 999px;
  background: var(--ember);
  color: #fff;
  font-family: var(--font-sans);
  font-weight: 800;
  font-size: 13.5px;
  cursor: pointer;
  animation: tz-pulse 2.4s infinite;
}

/* ── Objectif de l'étape — fixe juste au-dessus du menu, ne défile jamais avec
   l'indice (contrairement au reste du contenu de .th-play-clue-panel). ── */
.th-play-objective {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 12px clamp(16px, 4vw, 32px);
  border-top: 1px solid var(--line);
  background: var(--bg-soft);
}
.th-play-objective-icon {
  width: 34px;
  height: 34px;
  border-radius: 10px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg-card);
  border: 1px solid var(--line-strong);
  color: var(--tz-teal-d);
}
.th-play-objective-title { font-size: 12.5px; font-weight: 800; color: var(--ink); }
.th-play-objective-desc { font-size: 12.5px; color: var(--ink-soft); font-weight: 600; line-height: 1.45; margin-top: 3px; }

/* ══════════════════════════════════════════════════════════════════════
   RÈGLE GLOBALE — Leaflet ne doit JAMAIS passer au-dessus du menu/header
   ou des fenêtres modales. Ce bug est revenu à CHAQUE nouvelle intégration
   Leaflet (voir CLAUDE.md, section "Bugs UI résolus") car le correctif était
   appliqué au cas par cas sur certains composants (isolation:isolate en
   inline style) et oublié sur d'autres.
   `.leaflet-container` est la classe posée PAR Leaflet lui-même sur le div
   de la carte (L.map(...)) : cette règle protège donc AUTOMATIQUEMENT toute
   nouvelle carte Leaflet ajoutée à l'app, sans qu'il soit nécessaire d'y
   penser composant par composant. Ne pas retirer, ne pas la limiter à une
   classe de wrapper spécifique. ── */
.leaflet-container {
  isolation: isolate;
}

/* ══════════════════════════════════════════════════════════════════════
   Cartes d'ÉDITION (créateur) — les contrôles Leaflet des coins HAUT ne
   doivent jamais passer sous les pastilles flottantes de l'éditeur.
   Bug : sur l'éditeur de quête, la pastille « Vue parcours » (coin haut
   gauche) recouvrait le zoom +/- et la pastille « Étape N » / « Départ »
   (coin haut droit) recouvrait le sélecteur de calques (Plan / Satellite /
   Repères) — les deux contrôles devenaient inaccessibles au clic.
   Ces pastilles sont posées en position:absolute (inset 14px, z-index 500)
   PAR-DESSUS la carte, hors du contexte d'empilement de `.leaflet-container`
   (isolation:isolate ci-dessus) : elles gagnent donc toujours.
   Correctif : décaler les DEUX coins hauts de la carte sous la rangée de
   pastilles (pastille ≈ 33px + inset 14px ≈ 47px ; marge Leaflet 10px déjà
   comprise dans le total). Appliqué via la classe `.th-editor-map` posée par
   le composant de carte lui-même, donc valable pour tous ses usages
   (desktop étape 1 / étape 2, et carte plein écran mobile). ── */
.th-editor-map .leaflet-top.leaflet-left,
.th-editor-map .leaflet-top.leaflet-right {
  margin-top: 48px;
}

/* ══════════════════════════════════════════════════════════════════════
   Appareil photo plein écran (joueur) — mise en page PAYSAGE.
   Bug : sur mobile web, une fois le téléphone tourné en paysage, la barre
   de titre, le curseur « Qualité » et la barre de déclenchement s'empilent
   verticalement et écrasent l'aperçu caméra en une fine bande — on ne voit
   plus ce qu'on photographie, quelle que soit l'activité (traversée, quête
   ET collection).
   Correctif GLOBAL (comme la règle Leaflet ci-dessus) : en paysage sur écran
   bas (téléphones), on sort ces éléments de « chrome » du flux vertical et on
   les superpose en overlay. L'aperçu (flex:1, seul enfant restant dans le
   flux) reprend alors tout l'écran. Toute future page caméra qui réutilise
   ces classes en hérite automatiquement.
   Les styles inline des composants l'emportant sur la feuille de style, les
   surcharges sont marquées !important.
   Composants : MediaValidator.razor (photo/vidéo d'étape) et
   SpotCaptureModal.razor (collection). Seuil ~600px : les tablettes en
   paysage (hauteur > 600px) gardent la mise en page verticale normale. ── */
@media (orientation: landscape) and (max-height: 600px) {
  /* Barre de titre : overlay en haut, largeur réduite pour ne pas passer
     sous la colonne de contrôles ancrée à droite. */
  .th-cam-head {
    position: absolute !important;
    top: 0;
    left: 0;
    right: 116px;
    z-index: 3;
    padding-top: calc(6px + env(safe-area-inset-top)) !important;
    padding-bottom: 8px !important;
    background: linear-gradient(to bottom, rgba(0, 0, 0, .6), transparent) !important;
  }

  /* Colonne de contrôles (déclencheur, valider, compteur…) : bande verticale
     ancrée à droite, plutôt qu'une barre horizontale en bas. */
  .th-cam-controls {
    position: absolute !important;
    top: 0;
    bottom: 0;
    right: 0;
    left: auto !important;
    flex-direction: column !important;
    gap: 18px !important;
    width: auto;
    padding: 10px 14px calc(10px + env(safe-area-inset-bottom)) !important;
    background: linear-gradient(to left, rgba(0, 0, 0, .55), transparent) !important;
    z-index: 3;
  }

  /* Curseur qualité (avant capture) et champs titre/commentaire (après
     capture, collection) : overlay en bas à gauche, dégagé de la colonne de
     droite. Les deux sont mutuellement exclusifs (qualité si aucune photo,
     champs sinon), ils peuvent donc partager la même zone. */
  .th-cam-quality,
  .th-cam-fields {
    position: absolute !important;
    left: 0;
    right: 116px;
    bottom: 0;
    z-index: 3;
    background: linear-gradient(to top, rgba(0, 0, 0, .6), transparent) !important;
  }

  .th-cam-fields {
    max-height: 42vh !important;
  }
}

/* ── Lien e-mail protégé contre le moissonnage (spam / phishing) ──────────
   Composant EmailLink.razor. Le « @ » n'est pas dans le texte du DOM :
   il est injecté ici via ::before, donc absent du textContent lu par les
   robots collecteurs. Utiliser l'échappement Unicode \0040 pour ne pas
   écrire non plus le caractère « @ » littéral dans la feuille de style. ── */
.th-eml {
  cursor: pointer;
  white-space: nowrap;
}
.th-eml__at::before {
  content: "\0040"; /* @ */
}

/* ── Impression de la fiche QR Code (ParcoursEditor) ──────────────────────
   Isole #qr-fiche-print du reste de la page à l'impression via `visibility`
   (préserve la mise en page, contrairement à `display:none`). ── */
@media print {
  body * {
    visibility: hidden;
  }
  #qr-fiche-print,
  #qr-fiche-print * {
    visibility: visible;
  }
  #qr-fiche-print {
    position: fixed;
    inset: 0;
    margin: auto;
    box-shadow: none !important;
  }
  .qr-fiche-no-print {
    display: none !important;
  }
}

/* ── Impression de la fiche parcours (ParcoursPrintSheet) ─────────────────
   Même principe que la fiche QR Code ci-dessus : isole #parcours-print-sheet
   du reste de la page à l'impression via `visibility`. ── */
@media print {
  body * {
    visibility: hidden;
  }
  #parcours-print-sheet,
  #parcours-print-sheet * {
    visibility: visible;
  }
  #parcours-print-sheet {
    position: absolute;
    inset: 0;
    margin: 0;
  }
  /* La zone de défilement de l'écran ne doit plus rien rogner à l'impression. */
  .th-print-scroll {
    overflow: visible !important;
  }
  .th-print-no-print {
    display: none !important;
  }
}

/* La route /creator/parcours/{id}/imprimer est une « editor route » : le shell
   (MainLayout) fige la hauteur à 100dvh avec overflow:hidden. Sans conteneur de
   défilement dédié, une fiche plus haute que l'écran est tronquée et impossible à
   faire défiler. On reproduit donc le patron de l'éditeur : colonne flex, barre
   d'outils figée en haut, fiche dans une zone qui scrolle. */
.th-print-page {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

.th-print-scroll {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
}

.th-print-toolbar {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  padding: 14px 20px;
  border-bottom: 1.5px solid var(--line);
  background: var(--bg-card);
}

.th-print-mode-toggle {
  display: inline-flex;
  border: 1.5px solid var(--line-strong);
  border-radius: var(--r);
  overflow: hidden;
}

.th-print-mode-toggle button {
  border: none;
  background: transparent;
  padding: 8px 16px;
  font-family: var(--font-sans);
  font-size: 13px;
  font-weight: 800;
  color: var(--muted);
  cursor: pointer;
}

.th-print-mode-toggle button.is-active {
  background: var(--tz-teal);
  color: #fff;
}

#parcours-print-sheet {
  max-width: 900px;
  margin: 0 auto;
  padding: 24px;
  background: #fff;
  color: #111;
}

.th-print-header h1 {
  font-size: 24px;
  margin: 0 0 4px;
}

.th-print-lieu {
  margin: 0 0 8px;
  color: #555;
  font-weight: 700;
}

.th-print-mode-banner {
  display: inline-block;
  padding: 4px 10px;
  border-radius: 8px;
  font-size: 12px;
  font-weight: 800;
  margin-bottom: 16px;
}

.th-print-mode-banner.is-organisateur {
  background: #fde8e4;
  color: #b3392a;
}

.th-print-mode-banner.is-joueur {
  background: #e2f4ef;
  color: #0b4f5a;
}

.th-print-map {
  border: 1.5px solid #ccc;
  border-radius: 12px;
  overflow: hidden;
  margin-bottom: 24px;
  break-inside: avoid;
}

.th-print-etape {
  display: flex;
  gap: 14px;
  padding: 16px 0;
  border-top: 1.5px solid #e5e5e5;
  break-inside: avoid;
}

.th-print-etape-num {
  flex-shrink: 0;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: #1a1a1a;
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-mono);
  font-weight: 800;
  font-size: 14px;
}

.th-print-etape-body h2 {
  margin: 0 0 8px;
  font-size: 16px;
}

.th-print-media-badge {
  display: inline-block;
  padding: 5px 10px;
  border-radius: 8px;
  background: #fff6e0;
  color: #7a5a00;
  font-weight: 800;
  font-size: 12.5px;
  margin-bottom: 8px;
}

.th-print-photo {
  max-width: 260px;
  max-height: 200px;
  object-fit: cover;
  border-radius: 8px;
  border: 1.5px solid #ddd;
  display: block;
  margin-bottom: 8px;
}

.th-print-qr {
  width: 90px;
  height: 90px;
}

.th-print-qr-caption {
  font-size: 11.5px;
  color: #777;
  margin: 4px 0 8px;
}

.th-print-indice-texte {
  margin: 0 0 10px;
  font-size: 14px;
  line-height: 1.5;
}

.th-print-lettres {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}

.th-print-mot {
  display: flex;
  gap: 5px;
}

.th-print-case {
  width: 28px;
  height: 34px;
  border: 1.5px solid #999;
  border-radius: 6px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-mono);
  font-weight: 800;
  font-size: 15px;
}

.th-print-consigne {
  margin: 0;
  font-size: 14px;
  font-weight: 700;
  color: #333;
}

/* ── Livret plié A4 (ParcoursBookletSheet) ────────────────────────────────────
   Une feuille A4 (210×297mm) recto/verso pliée en quatre = 8 panneaux A6
   (105×148,5mm). Chaque face A4 porte une grille 2×2 ; la rangée haute est
   pivotée de 180° pour se lire dans l'ordre une fois la feuille pliée.
   Le format de page A4 est confiné aux feuilles du livret via une page nommée
   (`@page booklet`), pour ne pas affecter les autres impressions de l'app. ── */
@page booklet {
  size: A4 portrait;
  margin: 0;
}

.th-bk-toolbar {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  padding: 14px 20px;
  border-bottom: 1.5px solid var(--line);
  background: var(--bg-card);
}

.th-bk-toolbar-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

.th-bk-instructions {
  max-width: 900px;
  margin: 16px auto 0;
  padding: 14px 18px;
  background: #eef7f4;
  border: 1.5px solid #bfe3da;
  border-radius: 12px;
  color: #0b4f5a;
  font-size: 13.5px;
}

.th-bk-instructions p {
  margin: 0 0 6px;
}

.th-bk-instructions ol {
  margin: 0;
  padding-left: 20px;
}

.th-bk-instructions li {
  margin: 2px 0;
  line-height: 1.45;
}

#parcours-booklet {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 24px;
  padding: 24px 12px 48px;
  background: var(--bg);
}

.th-bk-sheet {
  page: booklet;
  position: relative;
  box-sizing: border-box;
  width: 210mm;
  height: 297mm;
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 1fr 1fr;
  background: #fff;
  color: #111;
  box-shadow: 0 4px 18px rgba(0, 0, 0, 0.18);
}

.th-bk-sheet-label {
  position: absolute;
  top: -22px;
  left: 0;
  font-size: 12px;
  font-weight: 800;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.th-bk-panel {
  box-sizing: border-box;
  width: 105mm;
  height: 148.5mm;
  overflow: hidden;
  border: 1px dashed #cfcfcf; /* repères de pli / découpe */
}

.th-bk-panel.is-rotated {
  transform: rotate(180deg);
}

/* Mode paysage : A4 couché (297 × 210 mm), zones A6 larges (148,5 × 105 mm). */
.th-bk-landscape .th-bk-sheet {
  width: 297mm;
  height: 210mm;
}

.th-bk-landscape .th-bk-panel {
  width: 148.5mm;
  height: 105mm;
}

/* Pages blanches : lignes espacées pour l'écriture (notes des enfants). */
.th-bk-notes-label {
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: #b8b8b8;
  margin-bottom: 4mm;
}

.th-bk-notes-lines {
  flex: 1;
  background-image: repeating-linear-gradient(
    to bottom,
    transparent 0,
    transparent 10mm,
    #d6d6d6 10mm,
    #d6d6d6 calc(10mm + 1px)
  );
}

/* Page « contenu débloqué » du livret : la mention identifie sans ambiguïté l'étape
   qui l'a débloquée, une fois le livret découpé, plié et relié. */
.th-bk-carnet-mention {
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: #fff;
  background: #1a1a1a;
  border-radius: 3px;
  padding: 3mm 3.5mm;
  margin-bottom: 4mm;
  line-height: 1.35;
}

.th-bk-carnet-texte {
  flex: 1;
  font-size: 12.5px;
  line-height: 1.6;
  color: #1e1e1e;
  white-space: pre-wrap;
  overflow: hidden;
}

.th-bk-fin-site {
  margin: 6px 0 0;
  font-size: 11px;
  color: #777;
  text-align: center;
  word-break: break-all;
}

.th-bk-page {
  box-sizing: border-box;
  width: 100%;
  height: 100%;
  padding: 10mm 9mm;
  display: flex;
  flex-direction: column;
  position: relative;
}

.th-bk-page-num {
  position: absolute;
  top: 4px;
  right: 6px;
  font-size: 10px;
  font-weight: 800;
  color: #b8b8b8;
}

/* Couverture & fin — centrées */
.th-bk-cover,
.th-bk-fin {
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: 8px;
}

.th-bk-cover-emoji {
  font-size: 52px;
  line-height: 1;
}

.th-bk-cover h1,
.th-bk-fin h1 {
  margin: 4px 0;
  font-size: 21px;
  line-height: 1.2;
}

.th-bk-cover-lieu {
  margin: 0;
  font-weight: 700;
  color: #555;
  font-size: 13px;
}

.th-bk-cover-lore {
  margin: 6px 0 0;
  font-size: 12.5px;
  line-height: 1.5;
  color: #444;
  display: -webkit-box;
  -webkit-line-clamp: 8;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.th-bk-cover-meta {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin-top: 12px;
  font-weight: 800;
  font-size: 13px;
  color: #0b4f5a;
}

.th-bk-fin-message {
  margin: 4px 0 0;
  font-size: 13px;
  line-height: 1.5;
  color: #444;
}

.th-bk-fin-score {
  margin-top: 16px;
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: 800;
  font-size: 14px;
}

.th-bk-fin-box {
  width: 46px;
  height: 34px;
  border: 1.5px solid #999;
  border-radius: 6px;
}

.th-bk-fin-total {
  color: #777;
}

/* Étape */
.th-bk-etape-head {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 8px;
}

.th-bk-etape-num {
  flex-shrink: 0;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: #1a1a1a;
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-mono);
  font-weight: 800;
  font-size: 13px;
}

.th-bk-etape-head h2 {
  margin: 0;
  font-size: 15px;
  line-height: 1.2;
}

.th-bk-media-badge {
  align-self: flex-start;
  padding: 4px 8px;
  border-radius: 8px;
  background: #fff6e0;
  color: #7a5a00;
  font-weight: 800;
  font-size: 11px;
  margin-bottom: 6px;
}

.th-bk-qr {
  width: 96px;
  height: 96px;
  align-self: center;
}

.th-bk-qr-caption {
  font-size: 10.5px;
  color: #777;
  text-align: center;
  margin: 4px 0 6px;
}

.th-bk-photo {
  max-width: 100%;
  max-height: 46mm;
  object-fit: cover;
  border-radius: 8px;
  border: 1.5px solid #ddd;
  display: block;
  margin-bottom: 6px;
}

.th-bk-indice {
  margin: 0 0 8px;
  font-size: 13px;
  line-height: 1.5;
}

.th-bk-consigne {
  margin: 0 0 6px;
  font-size: 12.5px;
  font-weight: 700;
  color: #333;
}

.th-bk-lettres {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: auto;
}

.th-bk-mot {
  display: flex;
  gap: 4px;
}

.th-bk-case {
  width: 22px;
  height: 28px;
  border: 1.5px solid #999;
  border-radius: 5px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-mono);
  font-weight: 800;
  font-size: 13px;
}

/* Impression : n'afficher que le livret ; chaque feuille A4 sur une page. */
@media print {
  body * {
    visibility: hidden;
  }
  #parcours-booklet,
  #parcours-booklet * {
    visibility: visible;
  }
  #parcours-booklet {
    position: absolute;
    inset: 0;
    margin: 0;
    padding: 0;
    gap: 0;
    background: #fff;
  }
  #parcours-booklet .th-print-no-print {
    display: none !important;
  }
  .th-bk-sheet {
    box-shadow: none;
    margin: 0;
    break-after: page;
  }
  .th-bk-sheet:last-child {
    break-after: auto;
  }
  .th-bk-panel {
    border-color: #e6e6e6;
  }
}

/* ── Map panel (mode jeu) — 2/6 de la hauteur du corps, voir .th-play-body. ── */
.th-play-map-panel {
  flex: 2 1 0%;
  /* Filet de sécurité : garantit une hauteur visible même si un ancêtre venait à
     perdre sa hauteur définitive (voir MainLayout.IsGameRoute → height:100dvh),
     sans quoi ce panneau flex (flex-basis:0%, sans contenu en flux normal —
     PlayerPlayMap est en position:absolute) s'effondre à 0px et la carte disparaît. */
  min-height: 140px;
  position: relative;
  overflow: hidden;
  border-bottom: 1px solid var(--line);
  /* Confine les z-index internes de Leaflet (tuiles, marqueurs, contrôles ~1000)
     dans un contexte d'empilement local, sinon la carte passe AU-DESSUS des
     fenêtres modales (overlay z-index 1000+). */
  isolation: isolate;
}
/* Filet de sécurité : borne les z-index des panes/contrôles Leaflet afin
   qu'ils restent toujours sous les fenêtres modales du jeu. */
.th-play-map-panel .leaflet-pane,
.th-play-map-panel .leaflet-top,
.th-play-map-panel .leaflet-bottom,
.th-play-map-panel .leaflet-control { z-index: 1 !important; }

/* ══════════════════════════════════════════════════════════════════════
   Écran de jeu — template "2a" (import Claude Design, ADR-0004,
   docs/adr/0004-templates-ux-jeu-session.md). Colonne pleine hauteur :
   en-tête d'étape pleine largeur (aide « ? » + quitter), carte GPS sur la
   moitié du corps (boussole chaud/froid en overlay), corps défilant pour
   l'indice/consigne, barre d'actions fixe en bas (média, indice
   supplémentaire, CTA de validation).
   Classes distinctes (.th-play2-*) du template figé .th-play-* utilisé par
   JeuSessionInitial.razor (/jeu/{id}/initial) — ne jamais faire converger
   les deux jeux de classes, elles partagent la même feuille de style
   globale mais doivent pouvoir évoluer indépendamment.
   ══════════════════════════════════════════════════════════════════════ */

.th-play2-shell {
  position: relative;
  flex: 1;
  min-height: 0;
  overflow: hidden;
  background: var(--bg);
  display: flex;
  flex-direction: column;
}
@media (min-width: 640px) {
  .th-play2-shell {
    width: 100%;
    max-width: 560px;
    margin: 0 auto;
    box-shadow: 0 0 0 1px var(--line), 0 30px 70px -30px rgba(11, 79, 90, 0.35);
  }
}

/* Carte GPS : 52 % du corps (itération 2a « la carte respire ») ; overlays (chips, polaroid,
   boussole minimaliste) confinés */
.th-play2-map {
  position: relative;
  flex: 0 0 52%;
  min-height: 0;
  overflow: hidden;
  isolation: isolate; /* confine les z-index Leaflet, comme .th-play-map-panel */
}
.th-play2-map .leaflet-pane,
.th-play2-map .leaflet-top,
.th-play2-map .leaflet-bottom,
.th-play2-map .leaflet-control { z-index: 1 !important; }

/* ── En-tête d'étape — pleine largeur, en flux au-dessus de la carte ── */
.th-play2-objective {
  position: relative;
  z-index: 25;
  flex-shrink: 0;
  width: 100%;
  background: var(--bg-card);
  border-bottom: 1.5px solid var(--line);
  box-shadow: 0 14px 30px -20px rgba(11, 79, 90, 0.5);
  padding: 5px 12px 6px;
  animation: tz-pop 0.3s ease;
}
.th-play2-objective-btns {
  display: inline-flex;
  gap: 8px;
  margin-left: auto;
}
.th-play2-icon-btn {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  border: 1.5px solid var(--line-strong);
  background: var(--bg-soft);
  color: var(--tz-teal-d);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  flex-shrink: 0;
  padding: 0;
}
.th-play2-objective-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  flex-wrap: wrap;
}
.th-play2-objective-meta {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font: 800 12px var(--font-sans);
  color: var(--ink);
  white-space: nowrap;
}
/* Titre de l'étape + boutons (aide « ? », quitter « × ») sur la même ligne,
   sans zone blanche : header compact. */
.th-play2-objective-titlerow {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-top: 2px;
}
.th-play2-objective-title {
  font-family: var(--font-serif);
  font-weight: 600;
  font-size: clamp(16px, 4vw, 19px);
  line-height: 1.15;
  color: var(--tz-teal-d);
  min-width: 0;
  flex: 1;
}

/* ── Légende zone / hors-ligne (chips flottants) ── */
.th-play2-zone-chip {
  position: absolute;
  left: 16px;
  z-index: 24;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font: 800 10px var(--font-sans);
  letter-spacing: 0.04em;
  color: var(--tz-teal-d);
  background: color-mix(in oklch, var(--bg-card) 92%, transparent);
  padding: 4px 9px;
  border-radius: 7px;
  box-shadow: 0 6px 14px -10px rgba(11, 79, 90, 0.5);
}

/* ── Boussole chaud/froid — en overlay au bas de la carte ── */
.th-play2-compass-float {
  position: absolute;
  bottom: 14px;
  left: 14px;
  z-index: 26;
  display: flex;
  align-items: center;
  gap: 10px;
}
.th-play2-dial {
  width: 96px;
  height: 96px;
  min-width: 96px;
  position: relative;
  display: block;
  filter: drop-shadow(0 12px 22px rgba(11, 79, 90, 0.35));
}
.th-play2-dial:disabled { cursor: default; }
.th-play2-dial-ring {
  position: absolute; inset: 0; border-radius: 50%;
  background: var(--bg-card); border: 2px solid var(--line);
}
.th-play2-dial-ring2 { position: absolute; inset: 11px; border-radius: 50%; border: 2px solid var(--line); }
.th-play2-dial-ring3 { position: absolute; inset: 23px; border-radius: 50%; border: 2px solid var(--line); }
.th-play2-dial-arc {
  position: absolute; inset: -1px; border-radius: 50%;
  -webkit-mask: radial-gradient(circle, transparent 44px, #000 46px);
  mask: radial-gradient(circle, transparent 44px, #000 46px);
  transition: background 0.4s ease;
}
.th-play2-dial-sweep {
  position: absolute;
  top: 2px; left: 50%;
  width: 2px; height: 46px;
  transform-origin: bottom center;
  animation: tz-spin 4s linear infinite;
  transition: opacity 0.4s ease;
}
.th-play2-dial-needle {
  position: absolute;
  left: 50%; top: 50%;
  transform-origin: bottom center;
  height: 38px;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  transition: transform 0.4s ease;
}
.th-play2-dial-center {
  position: absolute;
  left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  width: 11px; height: 11px;
  border-radius: 50%;
  border: 2px solid var(--bg-card);
  transition: background 0.4s ease;
}
.th-play2-proximity-card {
  background: var(--bg-card);
  border: 1.5px solid var(--line);
  border-radius: var(--r);
  box-shadow: 0 12px 24px -16px rgba(11, 79, 90, 0.5);
  padding: 9px 13px;
  min-width: 0;
  transition: background 0.4s ease, border-color 0.4s ease, box-shadow 0.4s ease;
}
/* Signalisation d'approche « Tu brûles » : le bloc « Proximité » remplace l'ancien
   bandeau — fond dégradé corail/ambre + textes blancs (voir ProximityAccentColor). */
.th-play2-proximity-card--hot {
  background: linear-gradient(120deg, var(--tz-coral), var(--tz-amber));
  border-color: transparent;
  box-shadow: 0 14px 28px -14px rgba(242, 84, 61, 0.7);
  animation: tz-pop 0.3s ease;
}

/* Boussole matérielle : bouton d'activation (permission device) + état actif.
   L'aiguille pointe alors la cible relativement à l'orientation réelle du téléphone. */
.th-play2-compass-enable {
  margin-top: 6px;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4px 9px;
  border: 1.5px solid var(--line);
  border-radius: 999px;
  background: var(--bg-soft);
  color: var(--ink-soft);
  font: 800 10px var(--font-sans);
  cursor: pointer;
  transition: background 0.2s ease, border-color 0.2s ease;
}
.th-play2-compass-enable:hover {
  background: var(--bg-card);
  border-color: var(--line-strong);
}
.th-play2-compass-state {
  margin-top: 6px;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font: 800 10px var(--font-sans);
}
.th-play2-compass-state--on {
  color: var(--canopy);
}

/* ── Corps défilant (indice, consigne, feedback) — sous la carte ── */
.th-play2-sheet {
  position: relative;
  z-index: 30;
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  background: var(--bg-card);
  box-shadow: 0 -14px 34px -22px rgba(11, 79, 90, 0.5);
  padding: 14px 20px 16px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.th-play2-clue-box {
  padding: 14px 16px;
  border: 1px solid var(--line);
  border-left: 3px solid var(--ember);
  background: var(--bg-soft);
  border-radius: var(--r);
  box-shadow: 0 10px 24px -20px rgba(11, 79, 90, 0.4);
}
.th-play2-clue-box--clickable { cursor: pointer; }
.th-play2-clue-box p {
  font-family: var(--font-serif);
  font-size: 16px;
  font-weight: 400;
  line-height: 1.5;
  color: var(--ink);
  margin: 0;
  /* Tronque au-delà de 4 lignes — la zone devient alors cliquable et ouvre
     l'indice complet en modale (voir th.isTextClamped / JeuSession.razor). */
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 4;
  line-clamp: 4;
  overflow: hidden;
}
.th-play2-clue-more {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  margin-top: 6px;
  font: 800 11px var(--font-sans);
  color: var(--ember);
}

.th-play2-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.th-play2-action-btn {
  flex: 1 1 140px;
  min-height: 42px;
  border-radius: 12px;
  border: 1.5px solid var(--line-strong);
  background: var(--bg-card);
  color: var(--tz-teal-d);
  font: 800 12px var(--font-sans);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  cursor: pointer;
  padding: 8px 10px;
}
/* Onglet actif (Carte / Collection) de la barre d'actions du mode jeu chasse : seul le
   contour est mis en évidence (liseré teal + texte teal), le fond reste clair — un remplissage
   plein contrastait trop avec le bouton inactif. */
.th-play2-action-btn--active {
  border-color: var(--tz-teal-d);
  color: var(--tz-teal-d);
  box-shadow: inset 0 0 0 1px var(--tz-teal-d);
}
.th-play2-hint-btn {
  border-style: dashed;
  background: var(--bg-soft);
  color: var(--ink-soft);
}
.th-play2-media-btn { animation: tz-pulse 2.4s infinite; }

.th-play2-cta {
  width: 100%;
  min-height: 52px;
  border: none;
  border-radius: 16px;
  background: var(--ember);
  color: #fff;
  font: 800 15.5px var(--font-sans);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  box-shadow: 0 14px 26px -12px rgba(242, 84, 61, 0.55);
  cursor: pointer;
}

/* ── Barre d'actions — fixe en bas de l'écran, jamais sous le pli ── */
.th-play2-actionbar {
  flex-shrink: 0;
  z-index: 31;
  background: var(--bg-card);
  border-top: 1.5px solid var(--line);
  box-shadow: 0 -14px 34px -22px rgba(11, 79, 90, 0.5);
  padding: 10px 16px calc(12px + env(safe-area-inset-bottom));
  display: flex;
  flex-direction: column;
  gap: 8px;
}

/* ── Lightbox audio : gros bouton lecture/pause centré ── */
.th-play2-audio-toggle {
  width: 92px;
  height: 92px;
  border-radius: 50%;
  border: none;
  cursor: pointer;
  background: var(--ember);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 18px 40px -14px rgba(242, 84, 61, 0.7);
}

/* ══════════════════════════════════════════════════════════════════════
   Écran de jeu — itération 2a « Polaroid + boussole minimaliste » (ADR-0004).
   Le cadran à 3 anneaux + la grosse carte « Proximité » sont remplacés par une
   boussole minimaliste (pastille flèche + pilule distance) ; l'indice photo est
   « scotché » en polaroid sur la carte ; l'indice texte défile dans sa carte
   (fondu de débordement) au lieu d'ouvrir une modale.
   Classes ADDITIVES : les anciennes (.th-play2-dial*, .th-play2-proximity-card*)
   restent définies — encore utilisées par la coque Maui et les thèmes archivés.
   ══════════════════════════════════════════════════════════════════════ */

/* Conteneur boussole : pile verticale (pastille au-dessus, pilule distance dessous) */
.th-play2-compass-float--mini {
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
}

/* Pastille flèche — 58 px, fond clair, repère N discret, flèche orientée vers la cible */
.th-play2-mini-pastille {
  width: 58px;
  height: 58px;
  min-width: 58px;
  border-radius: 50%;
  background: color-mix(in oklch, var(--bg-card) 96%, transparent);
  border: 1.5px solid var(--line);
  box-shadow: 0 10px 20px -10px rgba(11, 79, 90, 0.45);
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  cursor: pointer;
  transition: border-color 0.4s ease, box-shadow 0.4s ease;
}
.th-play2-mini-pastille:disabled { cursor: default; }
.th-play2-mini-pastille--hot {
  border-color: transparent;
  box-shadow: 0 12px 24px -10px rgba(242, 84, 61, 0.6);
}
.th-play2-mini-n {
  position: absolute;
  top: 3px;
  left: 50%;
  transform: translateX(-50%);
  font: 800 8px var(--font-sans);
  color: var(--muted);
}
.th-play2-mini-needle {
  display: flex;
  align-items: center;
  justify-content: center;
  transition: transform 0.4s ease;
}

/* Pilule distance — libellé « Proximité » + valeur + précision GPS + tendance chaud/froid */
.th-play2-dist-pill {
  display: flex;
  flex-direction: column;
  gap: 2px;
  background: var(--bg-card);
  border: 1.5px solid var(--line);
  border-radius: 12px;
  box-shadow: 0 10px 20px -10px rgba(11, 79, 90, 0.45);
  padding: 5px 12px 6px;
  white-space: nowrap;
  transition: background 0.4s ease, border-color 0.4s ease, box-shadow 0.4s ease;
}
/* Approche « Tu brûles » : la pilule passe au dégradé corail/ambre, textes en blanc. */
.th-play2-dist-pill--hot {
  background: linear-gradient(120deg, var(--tz-coral), var(--tz-amber));
  border-color: transparent;
  box-shadow: 0 14px 28px -14px rgba(242, 84, 61, 0.7);
  animation: tz-pop 0.3s ease;
}
.th-play2-dist-eyebrow { font-size: 8.5px; margin: 0; }
.th-play2-dist-row { display: inline-flex; align-items: baseline; gap: 5px; }
.th-play2-dist-value { font-size: 15px; line-height: 1; }
.th-play2-dist-unit { font-size: 10px; }
.th-play2-dist-acc { font: 700 10px var(--font-sans); color: var(--ink-soft); }
.th-play2-dist-trend { font: 700 10px var(--font-sans); color: var(--muted); }
.th-play2-dist-pill--hot .th-play2-dist-eyebrow,
.th-play2-dist-pill--hot .th-play2-dist-acc,
.th-play2-dist-pill--hot .th-play2-dist-trend { color: rgba(255, 255, 255, 0.9); }

/* Polaroid « scotché » — indice photo épinglé en haut à droite de la carte, incliné,
   ruban washi jaune, légende manuscrite ; un toucher l'agrandit (lightbox). */
.th-play2-polaroid {
  position: absolute;
  top: 12px;
  right: 14px;
  /* Largeur de la photo = source unique : le cadre (photo + 2×8px de padding) et la légende
     en dérivent, pour qu'un agrandissement responsive (desktop → 180px) ne puisse pas
     désynchroniser les trois largeurs et faire déborder la photo hors du cadre photomaton. */
  --th-polaroid-photo-w: 128px;
  width: calc(var(--th-polaroid-photo-w) + 16px);
  box-sizing: border-box;
  z-index: 26;
  transform: rotate(-4deg);
  background: #fff;
  padding: 8px 8px 6px;
  border: none;
  cursor: pointer;
  box-shadow: 0 18px 38px -16px rgba(51, 48, 42, 0.55);
  transition: transform 0.18s ease, box-shadow 0.18s ease;
}
.th-play2-polaroid:hover { transform: rotate(-2deg) scale(1.02); }
.th-play2-polaroid-tape {
  position: absolute;
  top: -9px;
  left: 50%;
  transform: translateX(-50%) rotate(3deg);
  width: 64px;
  height: 18px;
  background: color-mix(in oklch, var(--tz-gold) 85%, transparent);
  box-shadow: 0 1px 3px rgba(51, 48, 42, 0.15);
}
.th-play2-polaroid-photo {
  display: block;
  position: relative;
  width: var(--th-polaroid-photo-w);
  height: 104px;
  overflow: hidden;
  background: var(--bg-soft);
}
.th-play2-polaroid-photo img,
.th-play2-polaroid-photo video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
/* Tuile média (audio, ou vidéo embarquée sans vignette exploitable) : icône centrée sur fond papier. */
.th-play2-polaroid-mediaicon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  color: var(--ember);
  background: var(--bg-soft);
}
/* Pastille « lecture » en superposition (coin bas-droit) pour l'indice audio/vidéo. */
.th-play2-polaroid-playbadge {
  position: absolute;
  right: 6px;
  bottom: 6px;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--ember);
  color: #fff;
  box-shadow: 0 2px 6px rgba(51, 48, 42, 0.35);
}
.th-play2-polaroid-caption {
  display: block;
  width: var(--th-polaroid-photo-w);
  text-align: center;
  padding-top: 4px;
  font: 700 16px var(--font-hand, cursive);
  color: var(--ink);
}

/* Carte d'indice — en-tête « Indice », corps défilant, fondu de débordement en bas */
.th-play2-clue-card {
  position: relative;
  flex: 1 1 auto;
  min-height: 96px;
  display: flex;
  flex-direction: column;
  border: 1px solid var(--line);
  border-left: 3px solid var(--ember);
  background: var(--bg-soft);
  border-radius: var(--r);
  box-shadow: 0 10px 24px -20px rgba(11, 79, 90, 0.4);
  overflow: hidden;
}
.th-play2-clue-head {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  gap: 5px;
  padding: 12px 16px 0;
  font: 800 10px var(--font-sans);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--tz-coral-d);
}
.th-play2-clue-scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: 8px 16px 12px;
}
.th-play2-clue-scroll p {
  font-family: var(--font-serif);
  font-size: 16px;
  font-weight: 400;
  line-height: 1.5;
  color: var(--ink);
  margin: 0;
}
.th-play2-clue-fade {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 22px;
  background: linear-gradient(to bottom, transparent, var(--bg-soft));
  pointer-events: none;
}

/* ══════════════════════════════════════════════════════════════════════
   Parcours editor — TI'ZOR (assistant 2 étapes · desktop 3-pane · mobile)
   Step 1 « Le parcours » (identité + départ) → Step 2 « Les étapes »
   ══════════════════════════════════════════════════════════════════════ */

/* Shell */
.tz-ed-root {
  flex: 1; min-height: 0;
  display: flex; flex-direction: column;
  background: var(--tz-grad-page);
}

/* Wizard top bar (shared by both steps) */
.tz-ed-bar {
  flex-shrink: 0;
  display: flex; align-items: center; gap: 14px;
  padding: 10px clamp(13px, 3vw, 24px);
  background: var(--bg-card);
  border-bottom: 1.5px solid var(--line);
  box-shadow: 0 8px 22px -20px rgba(11,79,90,.65);
  flex-wrap: wrap;
}
.tz-ed-back {
  flex-shrink: 0;
  display: inline-flex; align-items: center; gap: 6px;
  padding: 8px 14px 8px 11px;
  background: var(--bg-soft);
  border: 1.5px solid var(--line-strong); border-radius: 999px;
  color: var(--tz-teal-d); font-weight: 800; font-size: 12.5px;
  cursor: pointer; transition: background .15s ease, transform .15s ease;
}
.tz-ed-back:hover { background: var(--canopy-soft); transform: translateX(-2px); }
.tz-ed-titlewrap { flex: 1 1 220px; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.tz-ed-eyebrow {
  font-family: var(--font-mono); font-size: 9.5px; font-weight: 800;
  letter-spacing: .12em; text-transform: uppercase; color: var(--muted-2);
  display: inline-flex; align-items: center; gap: 5px;
}
.tz-ed-title {
  width: 100%;
  border: 1.5px solid transparent; background: transparent;
  border-radius: 11px; padding: 3px 9px; margin-left: -2px;
  font-family: var(--font-serif); font-weight: 600; font-size: 21px;
  color: var(--tz-teal-d); outline: none;
}
.tz-ed-title::placeholder { color: var(--muted-2); }
.tz-ed-title:hover { background: var(--bg-soft); }
.tz-ed-title:focus { background: var(--bg-soft); border-color: var(--line-strong); }
.tz-ed-actions { display: flex; align-items: center; gap: 8px; flex-shrink: 0; flex-wrap: wrap; }

/* Stepper */
.tz-stepper { display: inline-flex; align-items: center; gap: 8px; }
.tz-step {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 6px 14px 6px 7px; border-radius: 999px;
  border: 1.5px solid var(--line-strong); background: var(--bg-card);
  color: var(--ink-soft); font-weight: 800; font-size: 12.5px;
  cursor: pointer; transition: all .15s ease; white-space: nowrap;
}
.tz-step:hover:not(:disabled):not(.is-active) { background: var(--bg-soft); }
.tz-step:disabled { opacity: .5; cursor: not-allowed; }
.tz-step.is-active { background: var(--tz-teal); border-color: var(--tz-teal); color: #fff; box-shadow: 0 11px 22px -13px rgba(12,122,114,.85); }
.tz-step-num {
  width: 23px; height: 23px; border-radius: 50%; flex-shrink: 0;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 12px; font-weight: 800;
  background: var(--canopy-soft); color: var(--tz-teal);
}
.tz-step.is-active .tz-step-num { background: rgba(255,255,255,.24); color: #fff; }
.tz-step.is-done .tz-step-num { background: #e7f7ee; color: var(--tz-green); }
.tz-step-sep { width: 22px; height: 2.5px; border-radius: 2px; background: var(--line-strong); }
@media (max-width: 760px) { .tz-step-label { display: none; } .tz-step { padding: 6px; } .tz-step-sep { width: 12px; } }

/* ── Step 1 — identité & point de départ ── */
.tz-ed-step1 { flex: 1; min-height: 0; overflow-y: auto; }
.tz-ed-step1-inner {
  max-width: 1180px; margin: 0 auto;
  padding: clamp(16px,3vw,28px) clamp(14px,4vw,28px) 44px;
  display: grid; grid-template-columns: 1.02fr 0.98fr; gap: 22px; align-items: start;
}
.tz-ed-panel { padding: clamp(16px,2vw,22px); }
.tz-ed-panel-map { padding: 0; overflow: hidden; display: flex; flex-direction: column; min-height: 480px; }
.tz-ed-panel-maphd { padding: 13px 16px; border-bottom: 1.5px solid var(--line); display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.tz-ed-maptall { position: relative; flex: 1; min-height: 420px; }
@media (max-width: 1024px) { .tz-ed-step1-inner { grid-template-columns: 1fr; } .tz-ed-panel-map { min-height: 360px; } .tz-ed-maptall { min-height: 300px; } }

/* ── Step 2 — desktop 3-pane ── */
.tz-ed-grid {
  flex: 1; min-height: 0;
  display: grid; grid-template-columns: 344px minmax(0,1fr) 398px; gap: 0;
}
@media (max-width: 1180px) { .tz-ed-grid { grid-template-columns: 300px minmax(0,1fr) 360px; } }
.tz-ed-col { min-height: 0; min-width: 0; display: flex; flex-direction: column; }
.tz-ed-col-list { background: var(--bg-card); border-right: 1.5px solid var(--line); }
.tz-ed-col-map  { background: var(--bg-soft); position: relative; }
.tz-ed-col-insp { background: var(--bg-card); border-left: 1.5px solid var(--line); }
.tz-ed-listhead { flex-shrink: 0; padding: 16px 16px 11px; display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.tz-ed-list { flex: 1; min-height: 0; overflow-y: auto; padding: 2px 14px 16px; display: flex; flex-direction: column; gap: 8px; }
.tz-ed-row {
  display: flex; gap: 11px; align-items: center;
  padding: 11px 12px; width: 100%; text-align: left;
  background: var(--bg-card); border: 1.5px solid var(--line-strong); border-radius: var(--r);
  cursor: pointer; box-shadow: 0 8px 18px -17px rgba(11,79,90,.55);
  transition: background .12s ease, border-color .12s ease, transform .12s ease;
}
.tz-ed-row:hover { background: var(--bg-soft); transform: translateY(-1px); }
.tz-ed-row.is-active { border-color: var(--tz-teal); background: var(--canopy-soft); }

/* ── Éditeur de spots d'une collection (/creator/collections) ──────────────
   Desktop : carte à gauche, sélecteur d'affichage + liste à droite.
   Mobile  : la carte passe en PREMIER en pleine largeur (elle ne doit jamais
   sortir de l'écran ni être côte à côte avec la liste), suivie du sélecteur
   « Tous / Dans la carte » puis de la liste — cf. bug récurrent des cartes
   Leaflet et exigence UX mobile. */
.th-spots-editor {
  display: grid;
  grid-template-columns: minmax(300px, 1.4fr) minmax(260px, 1fr);
  gap: 16px;
  align-items: start;
}
.th-spots-editor-map { position: relative; height: 440px; }
.th-spots-editor-side {
  display: flex; flex-direction: column; gap: 10px; min-width: 0;
  /* Conteneur de requête : les lignes de spot s'adaptent à la largeur RÉELLE de
     la colonne liste (et non à celle de l'écran), donc le repli des boutons
     fonctionne aussi bien en portrait empilé qu'en paysage côte à côte. */
  container-type: inline-size;
}
.th-spots-filter {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
}
.th-spots-filter-label {
  font-size: 11px; font-weight: 700; color: var(--muted);
  text-transform: uppercase; letter-spacing: .05em;
}
.th-spots-editor-list {
  max-height: 386px; overflow-y: auto; overflow-x: hidden;
  display: flex; flex-direction: column; gap: 8px; padding-right: 2px;
}
/* Quand la colonne liste est trop étroite pour tenir « nom + coordonnées +
   boutons » sur une ligne, on fait passer les boutons Modifier/Supprimer SOUS le
   texte (ligne dédiée, alignée à droite). Le texte récupère toute la largeur et
   la ligne ne déborde plus — vrai en portrait (empilé) comme en paysage. */
@container (max-width: 440px) {
  .th-spots-editor-list .tz-ed-row { flex-wrap: wrap; }
  .th-spots-editor-list .tz-ed-row > span:last-child {
    flex-basis: 100%; justify-content: flex-end;
  }
}
@media (max-width: 720px) {
  /* align-items: stretch est OBLIGATOIRE ici. La règle de base ci-dessus pose
     `align-items: start` (utile pour le layout grid desktop). En repassant en
     flex COLONNE, cet `align-items: start` s'applique à l'axe transversal
     (= largeur) et empêche les enfants de s'étirer : ils prennent alors la
     largeur de leur CONTENU. La carte, dont l'unique enfant est en
     position:absolute (donc 0 largeur intrinsèque), se réduisait à 0 px de
     LARGE → carte blanche (impossible de peindre des tuiles sur 0 px), et la
     colonne liste se tassait à la largeur des boutons. C'était LA cause du bug
     « pas de carte en portrait » (indépendant de toute logique JS Leaflet). */
  .th-spots-editor { display: flex; flex-direction: column; align-items: stretch; }
  .th-spots-editor-map { height: 320px; }
  .th-spots-editor-list { max-height: 340px; }
}
/* Écran très bas (téléphone en paysage) : la carte ne doit pas monopoliser toute
   la hauteur visible. */
@media (max-height: 520px) {
  .th-spots-editor-map { height: 240px; }
  .th-spots-editor-list { max-height: 240px; }
}

.tz-ed-quickadd {
  padding: 13px; border: 1.5px dashed var(--line-strong); border-radius: var(--r);
  background: transparent; color: var(--tz-teal); font-weight: 800; font-size: 13px; width: 100%;
  display: flex; align-items: center; justify-content: center; gap: 8px; cursor: pointer;
  transition: background .15s ease;
}
.tz-ed-quickadd:hover { background: var(--canopy-soft); }

/* Map overlay pills */
.tz-ed-pill {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 8px 13px; border-radius: 999px;
  background: var(--bg-card); border: 1.5px solid var(--line-strong);
  color: var(--tz-teal-d); font-weight: 800; font-size: 12px;
  cursor: pointer; box-shadow: var(--tz-shadow);
}
.tz-ed-pill:hover { background: var(--bg-soft); }
.tz-ed-pill.is-on-teal  { background: var(--tz-teal);  border-color: var(--tz-teal);  color: #fff; }
.tz-ed-pill.is-on-coral { background: var(--tz-coral); border-color: var(--tz-coral); color: #fff; }

/* Inspector (step 2 right pane / mobile step) */
.tz-ed-insp-head { flex-shrink: 0; padding: 15px 18px 13px; border-bottom: 1.5px solid var(--line); display: flex; align-items: center; gap: 12px; }
.tz-ed-insp-body { flex: 1; overflow-y: auto; min-height: 0; padding: 17px 18px 26px; display: flex; flex-direction: column; gap: 16px; }
.tz-ed-insp-foot { flex-shrink: 0; padding: 12px 16px calc(12px + env(safe-area-inset-bottom)); border-top: 1.5px solid var(--line); background: var(--bg-card); display: flex; gap: 8px; align-items: center; }

/* ── Rubriques de l'éditeur d'étape : chaque bloc de données est nettement
      séparé, avec une couleur d'accent différente par rubrique. ── */
.th-ed-sec {
  border: 1.5px solid var(--th-sec-accent, var(--line-strong));
  border-left-width: 5px;
  border-radius: var(--r-lg);
  padding: 14px 16px;
  background: var(--th-sec-soft, var(--bg-card));
  display: flex;
  flex-direction: column;
  gap: 13px;
}
.th-ed-sec > .eyebrow { color: var(--th-sec-accent); margin: 0; }
/* Le trait de séparation interne (bordures top des sous-blocs) suit l'accent. */
.th-ed-sec .th-ed-subrule { border-top: 1.5px solid var(--th-sec-accent); opacity: .5; }

.th-ed-sec--capture    { --th-sec-accent: var(--tz-teal);   --th-sec-soft: var(--canopy-soft); border-style: dashed; }
.th-ed-sec--general    { --th-sec-accent: var(--tz-sky);    --th-sec-soft: #e6f5f9; }
.th-ed-sec--indice     { --th-sec-accent: var(--tz-purple); --th-sec-soft: #f1ebfb; }
.th-ed-sec--validation { --th-sec-accent: var(--tz-green);  --th-sec-soft: #e6f5ec; }
.th-ed-sec--fin        { --th-sec-accent: var(--tz-amber);  --th-sec-soft: #fdf3e3; }

/* Number pip */
.tz-pip {
  width: 28px; height: 28px; border-radius: 50%; flex-shrink: 0;
  display: inline-flex; align-items: center; justify-content: center;
  font-weight: 800; font-size: 12.5px;
  background: var(--canopy-soft); color: var(--tz-teal);
}
.tz-pip.is-active { background: var(--tz-coral); color: #fff; }

/* Waypoint type selector chips */
.tz-wtype {
  height: 34px; padding: 0 12px; display: inline-flex; align-items: center; gap: 6px;
  border-radius: 999px; font-size: 12.5px; font-weight: 800; cursor: pointer;
  border: 1.5px solid var(--line-strong); background: var(--bg-card); color: var(--ink-soft);
  transition: all .14s ease;
}
.tz-wtype:hover { background: var(--bg-soft); }
.tz-wtype.is-active { border-color: var(--tz-teal); background: var(--tz-teal); color: #fff; }

/* Reorder buttons */
.tz-ed-ord {
  width: 30px; height: 30px; border-radius: 9px; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1.5px solid var(--line-strong); background: var(--bg-card); color: var(--tz-teal-d);
}
.tz-ed-ord:disabled { opacity: .4; cursor: not-allowed; }
.tz-ed-ord:hover:not(:disabled) { background: var(--bg-soft); }

/* Inline message banner */
.tz-ed-msg { font-size: 12.5px; font-weight: 700; padding: 10px 13px; border-radius: 11px; }
.tz-ed-msg-ok  { background: #e7f7ee; color: #0b6b39; }
.tz-ed-msg-err  { background: var(--ember-soft); color: var(--tz-coral-d); }
.tz-ed-msg-warn { background: #fef9e7; color: #7a5c00; }

/* ── Mobile drill-down ── */
.tz-em-stage { position: relative; flex: 1; min-height: 0; width: 100%; overflow: hidden; display: flex; flex-direction: column; background: var(--bg); }
.tz-em-slide {
  position: absolute; inset: 0; display: flex; flex-direction: column;
  background: var(--tz-grad-page); overflow: hidden;
  transition: transform .3s cubic-bezier(.32,.72,.36,1), opacity .22s ease;
}
.tz-em-slide.is-active { transform: translateX(0); opacity: 1; pointer-events: auto; }
.tz-em-slide.out-left  { transform: translateX(-12%); opacity: 0; pointer-events: none; }
.tz-em-slide.out-right { transform: translateX(100%); opacity: 0; pointer-events: none; }
.tz-em-head {
  flex-shrink: 0; min-height: 56px; padding: 10px 12px;
  display: flex; align-items: center; gap: 10px;
  background: var(--bg-card); border-bottom: 1.5px solid var(--line);
}
.tz-em-iconbtn {
  width: 38px; height: 38px; border-radius: 12px; flex-shrink: 0; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--bg-soft); border: 1.5px solid var(--line-strong); color: var(--tz-teal-d);
}
.tz-em-iconbtn:disabled { opacity: .4; cursor: not-allowed; }
.tz-em-card {
  display: flex; gap: 12px; align-items: center; padding: 12px 14px; width: 100%; text-align: left;
  background: var(--bg-card); border: 1.5px solid var(--line-strong); border-radius: var(--r);
  cursor: pointer; box-shadow: 0 8px 18px -17px rgba(11,79,90,.55);
}
@keyframes tz-em-sheet-up { from { transform: translateY(16px); opacity: 0; } to { transform: translateY(0); opacity: 1; } }

/* ══════════════════════════════════════════════════════════════════════
   TI'ZOR — motion + reusable component layer
   ══════════════════════════════════════════════════════════════════════ */

@keyframes tz-pulse { 0%,100% { box-shadow: 0 0 0 0 rgba(242,84,61,.5); } 50% { box-shadow: 0 0 0 13px rgba(242,84,61,0); } }
@keyframes tz-pop   { from { transform: translateY(10px) scale(.99); opacity: 0; } to { transform: none; opacity: 1; } }
@keyframes tz-float { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-5px); } }
@keyframes tz-bar   { 0%,100% { transform: scaleY(.3); } 50% { transform: scaleY(1); } }
@keyframes tz-shine { 0% { background-position: -120% 0; } 100% { background-position: 220% 0; } }
@keyframes tz-fade  { from { opacity: 0; } to { opacity: 1; } }
@keyframes tz-spin  { to { transform: rotate(360deg); } }
@keyframes tz-banner-in { from { transform: translateY(-104%); opacity: 0; } to { transform: translateY(0); opacity: 1; } }

.tz-pop   { animation: tz-pop .3s ease; }
.tz-fade  { animation: tz-fade .2s ease; }
.tz-float { animation: tz-float 3s ease-in-out infinite; }

/* Page shell */
.tz-page { max-width: 1180px; margin: 0 auto; padding: clamp(24px,4vw,44px) clamp(16px,4vw,40px) 54px; }
.tz-page-narrow { max-width: 860px; }

/* Display heading helper (Spectral, éditorial) */
.tz-display { font-family: var(--font-serif); font-weight: 700; line-height: 1.05; color: var(--ink); letter-spacing: -0.01em; }
.tz-display em { font-style: italic; color: var(--ember); }

/* Card */
.tz-card {
  background: var(--bg-card);
  border: 1.5px solid var(--line);
  border-radius: var(--r-xl);
  box-shadow: var(--tz-shadow);
}
.tz-card-sm { border-radius: var(--r-lg); }
.tz-hover-rise { transition: transform .15s ease, box-shadow .15s ease, border-color .15s ease; }
.tz-hover-rise:hover { transform: translateY(-3px); box-shadow: var(--tz-shadow-lg); }

/* Pills / badges */
.tz-pill {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 13px; border-radius: 999px;
  font-weight: 800; font-size: 12.5px; line-height: 1;
  white-space: nowrap;
}
.tz-pill-teal   { background: var(--canopy-soft); color: var(--tz-teal); }
.tz-pill-coral  { background: var(--ember-soft);  color: var(--tz-coral-d); }
.tz-pill-gold   { background: #fff3e0;            color: #c2641a; }
.tz-pill-green  { background: #e7f7ee;            color: #0b6b39; }
.tz-pill-purple { background: #f3f0fb;            color: #5b3aa0; }

/* Buttons */
.tz-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  border: none; cursor: pointer;
  font-family: var(--font-sans); font-weight: 800; font-size: 15px;
  padding: 14px 22px; border-radius: var(--r);
  transition: transform .15s ease, filter .15s ease, background .15s ease;
  white-space: nowrap; user-select: none;
}
.tz-btn:disabled { opacity: .5; cursor: not-allowed; }
.tz-btn-sm  { padding: 9px 15px; font-size: 13.5px; border-radius: 12px; }
.tz-btn-lg  { padding: 15px 26px; font-size: 15.5px; border-radius: var(--r-lg); }
.tz-btn-coral { background: var(--tz-coral); color: #fff; box-shadow: 0 12px 24px -12px rgba(242,84,61,.55); }
.tz-btn-coral:hover:not(:disabled) { transform: translateY(-2px); }
.tz-btn-teal  { background: var(--tz-teal); color: #fff; }
.tz-btn-teal:hover:not(:disabled)  { filter: brightness(1.06); }
.tz-btn-green { background: linear-gradient(135deg,#16a06a,#0c7a72); color: #fff; box-shadow: 0 8px 18px -8px rgba(22,160,106,.6); }
.tz-btn-green:hover:not(:disabled) { transform: translateY(-2px); }
.tz-btn-ghost { background: var(--bg-card); color: var(--tz-teal-d); border: 1.5px solid var(--line-strong); }
.tz-btn-ghost:hover:not(:disabled) { transform: translateY(-2px); }

/* Form controls */
.tz-label {
  display: block; font-weight: 800; font-size: 12.5px;
  color: var(--ink-soft); margin-bottom: 7px; letter-spacing: .2px;
}
.tz-input, .tz-select, .tz-textarea {
  width: 100%; box-sizing: border-box;
  border: 1.5px solid var(--line-strong); border-radius: var(--r);
  padding: 12px 14px; background: #fbfdfc;
  font-family: var(--font-sans); font-weight: 700; font-size: 14px; color: var(--ink);
}
.tz-textarea { min-height: 74px; resize: vertical; line-height: 1.45; }

/* Faux map canvas (grid texture) used by player + editor */
.tz-map {
  position: relative; overflow: hidden;
  background: linear-gradient(135deg,#bfe6df,#dcefcf);
  border: 1.5px solid var(--line-strong);
}
.tz-map::before {
  content: ""; position: absolute; inset: 0;
  background-image:
    repeating-linear-gradient(90deg, rgba(255,255,255,.45) 0 1px, transparent 1px 28px),
    repeating-linear-gradient(0deg,  rgba(255,255,255,.45) 0 1px, transparent 1px 28px);
}

/* Ghost button for use on the brand gradient (hero band, etc.) */
.tz-hero-ghost {
  display: inline-flex; align-items: center; gap: 8px;
  height: 50px; padding: 0 24px;
  background: rgba(255,255,255,.15); border: 1.5px solid rgba(255,255,255,.45);
  border-radius: var(--r-lg); color: #fff;
  font-family: var(--font-sans); font-weight: 800; font-size: 15.5px;
  cursor: pointer; transition: background .15s ease, border-color .15s ease;
}
.tz-hero-ghost:hover { background: rgba(255,255,255,.24); border-color: rgba(255,255,255,.65); }

/* Brand logo tile */
.tz-logo {
  display: flex; align-items: center; justify-content: center;
  border-radius: 14px;
/*  background: linear-gradient(135deg,#ffc53d,#f2543d);
  box-shadow: 0 4px 12px rgba(242,84,61,.4);
*/
  font-family: var(--font-serif); font-weight: 700; color: #fff;
  flex: none;
}

/* ═══════════════════════════════════════════════════════════════════════
   Kolaz Vakans — surfaces & interactions
   Présent uniquement dans le thème Kolaz Vakans (n'affecte pas un thème
   réactivé au retour arrière). Donne aux primitives Razor partagées
   (Button → .th-btn, Chip → .th-chip) et aux cartes (.tz-card) le rendu
   « scrapbook » : coins nets, ombres douces, léger soulèvement/inclinaison
   au survol. Les !important ne priment que sur les états :hover/:active.
   ═══════════════════════════════════════════════════════════════════════ */

/* Boutons — appui doux (petit décalage, ombre nette réduite). */
.th-btn { transition: transform .14s ease, box-shadow .14s ease, filter .14s ease, background .14s ease; }
.th-btn:hover:not([disabled]):not(:active) { transform: translateY(-1px); filter: brightness(1.02); }
.th-btn:active:not([disabled]) {
  transform: translate(1px,1px) !important;
  box-shadow: var(--ui-btn-shadow-active, 1px 1px 0 rgba(51,48,42,.2)) !important;
}

/* Chips / filtres — micro-appui. */
.th-chip { transition: transform .14s ease, box-shadow .14s ease, background .14s ease; }
.th-chip:hover:not(:active) { transform: translateY(-1px); }
.th-chip:active { transform: translate(1px,1px) !important; }

/* Cartes — blanc net, ombre douce ; au survol, la « photo » se soulève et se
   redresse légèrement (comme collée de travers dans un album). */
.tz-card { border: none; box-shadow: var(--kv-shadow-soft); }
.tz-card-sm { border-radius: var(--r-lg); }
.tz-hover-rise { transition: transform .18s ease, box-shadow .18s ease; }
.tz-hover-rise:hover { transform: translateY(-4px) rotate(-.5deg); box-shadow: var(--kv-shadow-photo); }

/* Emphase surlignée jaune (comme .display em). */
.tz-display em { font-style: normal; background: var(--kv-jaune); padding: 0 .16em;
                 box-decoration-break: clone; -webkit-box-decoration-break: clone; }

/* ── Helpers scrapbook réutilisables ── */
.kv-hand { font-family: var(--font-hand); font-weight: 700; }              /* note manuscrite (Caveat) */
.kv-photo { background: var(--bg-card); box-shadow: var(--kv-shadow-photo); } /* carte-photo « polaroid » */
.kv-dashed { border: 2px dashed var(--kv-ink); }
.kv-dashed-soft { border: 3px dashed var(--kv-dash); }
/* Ruban adhésif (washi tape) posé en haut d'un conteneur en position:relative */
.kv-tape { position: relative; }
.kv-tape::before { content:""; position:absolute; top:-11px; left:50%; width:98px; height:25px;
                   transform:translateX(-50%) rotate(-4deg); background:var(--kv-tape-jaune);
                   box-shadow:0 2px 6px rgba(0,0,0,.12); }

@keyframes kv-wiggle { 0%,100% { transform:rotate(-2deg); } 50% { transform:rotate(1deg); } }
.kv-wiggle { animation: kv-wiggle 5s ease-in-out infinite; }

@media (prefers-reduced-motion: reduce) {
  .th-btn, .th-chip, .tz-hover-rise, .kv-wiggle { transition: none; animation: none; }
  .th-btn:hover, .th-chip:hover, .tz-hover-rise:hover { transform: none; }
}

/* ══════════════════════════════════════════════════════════════════════
   Écran de jeu — design « 2a affiné » (import Claude Design, Ecran Jeu 2a.dc.html).
   Évolution du template 2a « Polaroid + boussole minimaliste » :
   - panneau « Objectif » REPLIABLE (chevron) : replié, la carte respire plein écran ;
   - chips chrono / étape / tendance chaud-froid en haut de la carte (bandeau de titre épuré) ;
   - pilule de proximité HORIZONTALE consolidée (flèche + distance) en haut à gauche.
   Classes ADDITIVES : les anciennes (.th-play2-sheet, .th-play2-clue-card, .th-play2-mini-*,
   .th-play2-dist-*, .th-play2-zone-chip) restent définies (coque MAUI + thèmes archivés).
   Toutes les couleurs passent par les variables de thème → un seul bloc convient aux 3 thèmes.
   ══════════════════════════════════════════════════════════════════════ */

/* ── Rangée de chips en haut de la carte (zone, chrono, étape, tendance, hors-ligne) ── */
.th-play2-topchips {
  position: absolute;
  top: 10px;
  left: 12px;
  right: 172px;
  z-index: 24;
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  pointer-events: none; /* laisse la carte draggable entre les chips */
}
.th-play2-chip {
  pointer-events: auto;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font: 800 10.5px var(--font-sans);
  letter-spacing: 0.03em;
  color: var(--ink);
  background: color-mix(in oklch, var(--bg-card) 97%, transparent);
  padding: 5px 9px;
  border-radius: 7px;
  border: 1.5px solid var(--line);
  white-space: nowrap;
  box-shadow: 0 6px 14px -10px rgba(11, 79, 90, 0.5);
}
.th-play2-chip--step {
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted);
}
/* Bascule Plan ⇄ Satellite du fond de carte : pastille « calque » posée sur la ligne
   suivante (flex-basis:100% force le retour à la ligne dans .th-play2-topchips), donc
   juste SOUS le décompte des étapes. */
.th-play2-maplayer {
  flex-basis: 100%;
  display: flex;
}
.th-play2-chip--layer {
  padding: 5px 6px;
  cursor: pointer;
  color: var(--ink-soft);
  line-height: 0;
}
.th-play2-chip--layer.is-active {
  color: #fff;
  background: var(--tz-teal-d);
  border-color: var(--tz-teal-d);
}
/* Chip de tendance « Tu brûles / Tu chauffes » : fond corail plein quand ça chauffe. */
.th-play2-trend-chip--hot {
  color: #fff;
  background: var(--ember);
  border-color: var(--ember);
  box-shadow: 0 8px 18px -8px rgba(242, 84, 61, 0.6);
}

/* ── Pilule de proximité horizontale (bas-gauche de la carte) — consolide pastille flèche + distance ── */
.th-play2-compass-float--pill {
  top: auto;
  bottom: 14px;
  left: 12px;
  right: auto;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
  max-width: 62%;
}
.th-play2-prox-pill {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  background: color-mix(in oklch, var(--bg-card) 97%, transparent);
  border: 1.5px solid var(--line);
  border-radius: 10px;
  padding: 4px 10px;
  box-shadow: 0 10px 20px -10px rgba(11, 79, 90, 0.45);
  cursor: pointer;
  transition: background 0.4s ease, border-color 0.4s ease, box-shadow 0.4s ease;
}
.th-play2-prox-pill:disabled { cursor: default; }
/* Approche « Tu brûles » : dégradé corail/ambre, textes en blanc. */
.th-play2-prox-pill--hot {
  background: linear-gradient(120deg, var(--tz-coral), var(--tz-amber));
  border-color: transparent;
  box-shadow: 0 14px 28px -14px rgba(242, 84, 61, 0.7);
  animation: tz-pop 0.3s ease;
}
.th-play2-prox-dial {
  flex-shrink: 0;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  border: 2px solid var(--line);
  display: flex;
  align-items: center;
  justify-content: center;
}
.th-play2-prox-pill--hot .th-play2-prox-dial { border-color: rgba(255, 255, 255, 0.6); }
.th-play2-prox-needle {
  display: flex;
  align-items: center;
  justify-content: center;
  transition: transform 0.4s ease;
}
.th-play2-prox-text {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  line-height: 1.05;
}
.th-play2-prox-eyebrow {
  font: 800 8.5px var(--font-sans);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
}
.th-play2-prox-row {
  display: inline-flex;
  align-items: baseline;
  gap: 5px;
  white-space: nowrap;
}
.th-play2-prox-value { font: 800 15px var(--font-sans); line-height: 1; }
.th-play2-prox-unit { font-size: 10px; }
.th-play2-prox-acc { font: 700 10px var(--font-sans); color: var(--ink-soft); }
.th-play2-prox-pill--hot .th-play2-prox-eyebrow,
.th-play2-prox-pill--hot .th-play2-prox-acc { color: rgba(255, 255, 255, 0.9); }

/* ── Panneau « Objectif » repliable (remplace .th-play2-sheet dans le design 2a affiné) ── */
.th-play2-panel {
  position: relative;
  z-index: 30;
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  background: var(--bg-card);
  border-top: 1.5px solid var(--line);
  box-shadow: 0 -14px 34px -22px rgba(11, 79, 90, 0.5);
  overflow: hidden;
}
/* Replié : le panneau se réduit à son en-tête, la carte prend tout l'espace. */
.th-play2-shell--panel-collapsed .th-play2-panel { flex: 0 0 auto; }
.th-play2-shell--panel-collapsed .th-play2-map { flex: 1 1 auto; }
.th-play2-shell--panel-collapsed .th-play2-panel-head { border-bottom: none; }

.th-play2-panel-head {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 9px 14px 9px 18px;
  border-bottom: 1.5px solid var(--line);
}
.th-play2-panel-eyebrow {
  flex-shrink: 0;
  font: 800 10px var(--font-sans);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--tz-teal-d);
}
.th-play2-panel-objective {
  flex: 1;
  min-width: 0;
  font: 700 13.5px var(--font-sans);
  line-height: 1.3;
  color: var(--ink);
}
.th-play2-panel-toggle { flex-shrink: 0; margin-left: auto; }
.th-play2-panel-chev {
  display: flex;
  align-items: center;
  justify-content: center;
  transition: transform 0.2s ease;
}

.th-play2-panel-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: 10px 16px 14px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  scrollbar-width: thin;
  scrollbar-color: var(--tz-coral) transparent;
}
.th-play2-panel-body::-webkit-scrollbar { width: 11px; }
.th-play2-panel-body::-webkit-scrollbar-track { background: transparent; }
.th-play2-panel-body::-webkit-scrollbar-thumb {
  background: var(--tz-coral);
  border-radius: 7px;
  border: 3px solid var(--bg-card);
}
/* Indice — préfixe « L'indice · » coloré + corps serif (esprit carnet). */
.th-play2-clue-text {
  font-family: var(--font-serif);
  font-size: 16px;
  font-weight: 400;
  line-height: 1.55;
  color: var(--ink);
  margin: 0;
}
.th-play2-clue-prefix {
  font: 800 12px var(--font-sans);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--tz-coral-d);
}
/* Fondu de débordement en bas du panneau (signal « défile pour lire »). */
.th-play2-panel-fade {
  position: absolute;
  left: 0;
  right: 11px; /* laisse voir la barre de défilement */
  bottom: 0;
  height: 22px;
  background: linear-gradient(to bottom, transparent, var(--bg-card));
  pointer-events: none;
}

/* ══════════════════════════════════════════════════════════════════════
   Écran de jeu — mode DESKTOP / tablette large (design « Ecran Jeu Desktop.dc.html »).
   Le même écran « 2a affiné » bascule, à partir de 1024 px, d'une colonne empilée vers une
   carte PLEIN ÉCRAN surmontée d'un VOLET FLOTTANT (bas-droite) réunissant objectif, indice
   et actions. Piloté uniquement par media-query : markup partagé, le « dock » (.th-play2-dock)
   passe de display:contents (mobile) à carte flottante (desktop). Additif — aucune classe
   mobile n'est modifiée hors media-query.
   PORTÉE : toutes les règles desktop sont limitées à l'écran de jeu (.th-play2-jeu), car
   .th-play2-shell / .th-play2-objective / .th-play2-icon-btn sont AUSSI réutilisés par
   ChasseDetail.razor (mode chasse) — il ne faut surtout pas les toucher hors du jeu.
   ══════════════════════════════════════════════════════════════════════ */

/* Mobile (base) : le dock s'efface (panneau + barre d'actions empilés comme avant), le
   sous-titre d'en-tête est masqué. Ces deux classes sont propres à l'écran de jeu (absentes
   de ChasseDetail) : sûres même hors portée .th-play2-jeu. */
.th-play2-dock { display: contents; }
.th-play2-objective-sub { display: none; }

@media (min-width: 1024px) {
  /* La coque de jeu cesse d'être une colonne « téléphone » centrée (règle ≥ 640 px) : plein écran.
     Compound .th-play2-jeu.th-play2-shell = le même élément (le shell du jeu), pas la chasse. */
  .th-play2-jeu.th-play2-shell {
    max-width: none;
    margin: 0;
    box-shadow: none;
  }

  /* En-tête plus ample + sous-titre « jeu en cours » visible à côté du titre. */
  .th-play2-jeu .th-play2-objective { padding: 11px 24px 12px; }
  .th-play2-jeu .th-play2-objective-title { flex: 0 0 auto; white-space: nowrap; font-size: 22px; }
  .th-play2-jeu .th-play2-objective-sub {
    display: inline-flex;
    align-items: center;
    font: 800 11px var(--font-sans);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--muted);
    white-space: nowrap;
  }
  .th-play2-jeu .th-play2-icon-btn { width: 34px; height: 34px; }

  /* La carte occupe tout le corps sous l'en-tête (le dock flottant est hors-flux). */
  .th-play2-jeu .th-play2-map { flex: 1 1 auto; }
  /* Overlays légèrement agrandis / repositionnés comme le mock desktop. */
  .th-play2-jeu .th-play2-topchips { top: 16px; left: 16px; right: auto; }
  .th-play2-jeu .th-play2-chip { font-size: 12px; padding: 7px 13px; }
  .th-play2-jeu .th-play2-compass-float--pill { bottom: 24px; left: 24px; top: auto; max-width: 340px; }
  .th-play2-jeu .th-play2-polaroid { top: 16px; right: 24px; --th-polaroid-photo-w: 180px; }
  .th-play2-jeu .th-play2-polaroid-photo { height: 150px; }
  .th-play2-jeu .th-play2-polaroid-caption { font-size: 18px; }
  .th-play2-jeu .th-play2-polaroid-tape { width: 74px; height: 20px; }

  /* Volet flottant : panneau « Objectif » + barre d'actions réunis en une carte ancrée en
     bas à droite, superposée à la carte. Repli du panneau → la carte se réduit à son en-tête
     « Objectif » + la barre d'actions (le CTA « J'y suis » reste accessible). */
  .th-play2-jeu .th-play2-dock {
    display: flex;
    flex-direction: column;
    position: absolute;
    right: 24px;
    bottom: 24px;
    width: min(430px, calc(100% - 48px));
    max-height: calc(100% - 32px);
    background: var(--bg-card);
    border: 2px solid var(--line-strong);
    border-radius: 16px;
    box-shadow: 0 30px 60px -25px rgba(11, 79, 90, 0.5);
    overflow: hidden;
    z-index: 40;
  }
  /* Panneau et barre vivent DANS la carte flottante : pas de bordure/ombre propre, fond
     transparent (la carte porte le fond et l'ombre). */
  .th-play2-jeu .th-play2-dock .th-play2-panel {
    flex: 0 1 auto;
    min-height: 0;
    border-top: none;
    box-shadow: none;
    background: transparent;
  }
  .th-play2-jeu .th-play2-dock .th-play2-panel-body { max-height: 34vh; }
  .th-play2-jeu .th-play2-dock .th-play2-panel-fade {
    background: linear-gradient(to bottom, transparent, var(--bg-card));
  }
  .th-play2-jeu .th-play2-dock .th-play2-actionbar {
    background: transparent;
    border-top: 1.5px solid var(--line);
    box-shadow: none;
    padding: 10px 16px 12px;
  }
}

/* ══════════════════════════════════════════════════════════════════════
   Correctifs 2a affiné (revue rendu mobile).
   ══════════════════════════════════════════════════════════════════════ */

/* Barre d'actions : « Indice supp. » et le CTA de validation CÔTE À CÔTE (mockup 2a),
   au lieu d'être empilés pleine largeur. Le média audio/vidéo garde sa propre rangée au-dessus.
   Sans indice supplémentaire, seul le CTA occupe la rangée (donc pleine largeur). */
.th-play2-actionrow {
  display: flex;
  align-items: stretch;
  gap: 8px;
}
.th-play2-actionrow > .th-play2-hint-btn {
  flex: 1 1 0;
  min-width: 0;
  flex-direction: column;
  gap: 1px;
  line-height: 1.15;
}
.th-play2-hint-main { display: inline-flex; align-items: center; gap: 5px; }
.th-play2-hint-pts { font: 700 10px var(--font-sans); color: var(--muted); }
/* Le CTA prend 2 parts (le double de l'indice supp.) et abandonne son width:100% en rangée. */
.th-play2-actionrow > .th-play2-cta { flex: 2 1 0; width: auto; }

/* ── Overlay carte EN COLONNE : chips au-dessus de la pilule de proximité ──
   Robuste anti-chevauchement : quel que soit le nombre de chips (zone/chrono/étape/tendance/
   hors-ligne) ou la largeur d'écran, la pilule suit toujours SOUS les chips (flux vertical),
   au lieu d'être positionnée en absolu et de passer derrière une 2ᵉ ligne de chips.
   Le polaroid reste indépendant (absolu, haut-droite). */
.th-play2-map-overlay {
  position: absolute;
  top: 10px;
  left: 12px;
  right: 12px;
  z-index: 26;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
  pointer-events: none; /* laisse la carte draggable ; seuls les chips/pilule captent le pointeur */
}
.th-play2-map-overlay > * { pointer-events: auto; max-width: 100%; }
/* Chips + pilule repassent EN FLUX dans la colonne (annule leur ancienne position absolue). */
.th-play2-map-overlay .th-play2-topchips {
  position: static;
  top: auto;
  left: auto;
  right: auto;
  z-index: auto;
  width: 100%;
}
.th-play2-map-overlay .th-play2-compass-float--pill {
  position: static;
  top: auto;
  left: auto;
  right: auto;
  bottom: auto;
}

@media (min-width: 1024px) {
  /* Desktop : l'overlay se cale en haut à gauche, un peu plus grand (comme le mock desktop). */
  .th-play2-jeu .th-play2-map-overlay {
    top: 16px;
    left: 16px;
    right: auto;
    max-width: 60%;
    gap: 10px;
  }
}

/* ══════════════════════════════════════════════════════════════════════
   Mode joueur « collection » (/collection/{id}, shell immersif de ChasseDetail.razor).
   Le volet « Objectif » du mode traversée est réutilisé tel quel (.th-play2-panel*) mais posé
   AU-DESSUS de la carte ; la carte reçoit ses propres overlays (flèches de boussole, précision
   GPS, photomaton de collection) et la barre du bas se réduit au déclencheur rond précédé du
   mini-aperçu caméra pré-chargé.
   ══════════════════════════════════════════════════════════════════════ */

/* Volet « Objectif » posé AU-DESSUS de la carte : le panneau du mode traversée retourné
   (bordure et ombre côté bas), et qui ne prend jamais la hauteur restante — c'est la carte
   qui respire. */
.th-play2-panel--top {
  flex: 0 0 auto;
  border-top: none;
  border-bottom: 1.5px solid var(--line);
  box-shadow: 0 14px 34px -22px rgba(11, 79, 90, 0.5);
}
.th-play2-panel--top .th-play2-panel-body { max-height: 30vh; }
/* Replié, l'objectif tient sur une ligne (le texte complet s'ouvre d'un toucher sur le chevron). */
.th-play2-panel-objective--clamped {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 1;
  line-clamp: 1;
  overflow: hidden;
}

/* Carte plein écran du mode collection : hauteur résolue par le flex du shell, z-index Leaflet
   confinés (même raison que .th-play2-map / .th-play-map-panel). */
.th-chasse-map {
  position: relative;
  flex: 1;
  min-height: 0;
  overflow: hidden;
  isolation: isolate;
  /* Gabarit de la rangée de commandes, SOURCE UNIQUE : le déclencheur en dérive sa taille, et
     tout ce qui est posé au-dessus de la rangée (.th-chasse-compass, contrôles Leaflet du coin
     bas droit) en dérive sa marge basse. Un seul chiffre à changer pour
     redimensionner le déclencheur sans que rien ne vienne se poser dessus.
     --th-chasse-row-h = déclencheur + libellé sous le bouton + marge basse + dégagement. */
  --th-chasse-shutter-size: 144px;
  --th-chasse-row-h: calc(var(--th-chasse-shutter-size) + 42px);
}

/* Interfaces à caméra plein écran (v1b/v1c) : le déclencheur redescend à 76 px — à peine plus
   gros que les deux commandes qui l'encadrent (58 px), assez pour rester le geste principal sans
   manger le décor réel qui est ici tout l'intérêt de l'écran. Comme --th-chasse-row-h en dérive,
   TOUT ce qui se cale sur la rangée (médaillon de carte, flèches de boussole, contrôles Leaflet)
   descend d'autant : la carte se retrouve automatiquement plus basse, sans second réglage. */
.th-chasse-map--cam {
  --th-chasse-shutter-size: 76px;
  /* Les commandes ne sont plus une rangée mais une COLONNE (collection au-dessus du
     déclencheur) : la hauteur à dégager n'est plus « un bouton + son libellé » mais les deux
     empilés — 58 + libellé, gouttière, 76 + libellé, marge basse. Ce qui se cale dessus (les
     flèches de boussole) monte d'autant. Valeur littérale plutôt que dérivée : elle additionne
     deux boutons de tailles différentes et leurs libellés, une formule ne la rendrait pas plus
     lisible. */
  --th-chasse-row-h: 214px;
}

/* ── Flèches de boussole en bordure de carte ──
   Posées sur l'ellipse inscrite dans la carte, à l'azimut du spot (la carte est orientée nord en
   haut). Le conteneur laisse passer le pointeur pour ne pas geler le pan/zoom ; seules les
   flèches le captent. */
.th-chasse-compass {
  position: absolute;
  /* Marge basse = hauteur de la rangée de capture (--th-chasse-row-h) : une flèche plein sud ne
     peut pas venir se poser sur le déclencheur. L'ellipse se décale de quelques dizaines de
     pixels vers le haut, sans conséquence sur la lecture des directions. */
  inset: 8px 8px var(--th-chasse-row-h) 8px;
  z-index: 28;
  pointer-events: none;
}
.th-chasse-compass-arrow {
  position: absolute;
  transform: translate(-50%, -50%);
  pointer-events: auto;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 7px 3px 5px;
  border: 1.5px solid var(--th-arrow-color, var(--tz-teal-d));
  border-radius: 999px;
  background: color-mix(in oklch, var(--bg-card) 92%, transparent);
  color: var(--th-arrow-color, var(--tz-teal-d));
  box-shadow: 0 6px 16px -10px rgba(11, 79, 90, 0.6);
  cursor: pointer;
  white-space: nowrap;
}
.th-chasse-compass-needle {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.th-chasse-compass-dist {
  font: 800 10.5px var(--font-sans);
  color: var(--ink);
}

/* ── Précision GPS courante, DANS la rangée de légende en haut de la carte ──
   Rendue par ChasseSpotsMap (paramètre LegendExtra), à la suite de la dernière pastille
   (« Trouvé ») : elle se lit avec les autres compteurs de la partie et ne dispute plus le bas de la
   carte aux commandes ni aux flèches de boussole. Le bandeau de légende ne capte pas le pointeur —
   la pastille le rétablit pour elle seule (infobulle), la carte reste manipulable tout autour. */
.th-chasse-gps-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 9px;
  border-radius: 999px;
  background: rgba(8, 20, 24, 0.62);
  color: #fff;
  font: 800 11px var(--font-sans);
  white-space: nowrap;
  pointer-events: auto;
}
/* Précision suffisante pour collecter sans se poser de question (GpsPrecision.AcceptableAccuracyM). */
.th-chasse-gps-chip--ok { background: rgba(16, 185, 129, 0.9); }

/* ── Alerte de proximité ──
   REPREND LE PHOTOMATON (.th-play2-polaroid, le polaroid scotché du mode traversée) à
   l'emplacement qu'il occupait, en haut à droite de la carte : l'alerte n'en redéfinit que la
   position, l'anneau ambre et le clignotement — cadre, ruban adhésif et légende manuscrite
   viennent du polaroid. Elle n'apparaît QUE lorsqu'un spot repéré par un autre joueur, encore
   collectable, est à portée, et montre alors LE CLICHÉ DU SPOT (couverture, sinon premier cliché
   de sa galerie — voir AlertPreviewUrl côté page) : le joueur voit ce qu'il cherche.
   Clignotement LÉGER (l'opacité ne descend jamais bas, et l'anneau respire) : la carte reste
   lisible, l'œil est attiré sans être agressé.
   Le décalage vertical la pose sous la LÉGENDE du bandeau de la carte (ChasseSpotsMap), à la
   hauteur de la pastille de score : celle-ci étant ancrée à GAUCHE et l'alerte à DROITE, elles
   partagent la même ligne sans se recouvrir, et l'alerte gagne les ~24 px de la pastille — elle
   remonte donc d'autant, plus près du haut de la carte. */
.th-chasse-alert {
  top: 48px;
  right: 14px;
  z-index: 27;
  box-shadow: 0 0 0 2px var(--ember), 0 18px 38px -16px rgba(51, 48, 42, 0.55);
  animation: th-chasse-alert-pulse 1.8s ease-in-out infinite;
}
/* Légende du polaroid : intitulé de l'alerte + distance, empilés dans la largeur du cliché. */
.th-chasse-alert-caption {
  display: flex;
  flex-direction: column;
  gap: 1px;
}
.th-chasse-alert-title {
  font: 800 11px var(--font-sans);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ember);
}
.th-chasse-alert-dist { font: 800 14px var(--font-sans); color: var(--ink); }

/* Aperçu d'un spot de RÉALITÉ AUGMENTÉE : le sprite du fantasti à attraper, faute de photo (un
   spot RA n'en a jamais — cf. FantastiSpriteUrl). Contenu ENTIER dans le cadre (`contain`, marge
   autour) et non rogné comme une photo : la créature doit se reconnaître d'un coup d'œil. Le halo
   teal la détache du papier du polaroid. */
.th-chasse-alert-fantasti {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  background: radial-gradient(circle at 50% 45%, color-mix(in oklch, var(--tz-teal-d) 20%, transparent), var(--bg-soft) 72%);
}
.th-chasse-alert-fantasti img {
  width: 80%;
  height: 80%;
  object-fit: contain;
  display: block;
}
/* Même sprite en tête de la fiche du spot (celle qu'ouvre l'alerte), quand il n'y a aucun cliché. */
.th-chasse-fiche-fantasti {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 190px;
  background: radial-gradient(circle at 50% 45%, color-mix(in oklch, var(--tz-teal-d) 20%, transparent), var(--bg-soft) 72%);
}
.th-chasse-fiche-fantasti img {
  width: 168px;
  height: 168px;
  object-fit: contain;
  display: block;
}

@keyframes th-chasse-alert-pulse {
  0%, 100% { box-shadow: 0 0 0 2px var(--ember), 0 18px 38px -16px rgba(51, 48, 42, 0.55); opacity: 1; }
  50%      { box-shadow: 0 0 0 4px var(--ember), 0 18px 38px -16px rgba(51, 48, 42, 0.55); opacity: 0.88; }
}
/* Respect de « animations réduites » : l'alerte reste visible, elle cesse simplement de clignoter. */
@media (prefers-reduced-motion: reduce) {
  .th-chasse-alert { animation: none; }
}

/* ── Capture du mode collection : mini-aperçu + déclencheur rond, EN OVERLAY sur la carte ──
   Aucun bandeau sous la carte : celle-ci occupe tout le corps du shell, donc le déclencheur est
   toujours visible sans défilement. Le conteneur ne capte pas le pointeur (la carte reste
   manipulable entre les deux boutons) ; le déclencheur est centré indépendamment de l'aperçu,
   qui est ancré à gauche. */
.th-chasse-capture-row {
  position: absolute;
  left: 0;
  right: 0;
  bottom: calc(14px + env(safe-area-inset-bottom));
  z-index: 29;
  display: flex;
  /* Alignement PAR LE BAS : les trois libellés se posent alors sur la même ligne, quelle que
     soit la taille du bouton qui les surmonte (le déclencheur est 2,5× plus haut que ses
     voisins). */
  align-items: flex-end;
  justify-content: center;
  gap: 20px;
  pointer-events: none;
}
.th-chasse-capture-row > * { pointer-events: auto; }

/* Interfaces v1b/v1c — les commandes deviennent une COLONNE plaquée dans un coin bas, du côté de
   la main dominante (droitier par défaut). « Ma collection » passe AU-DESSUS du déclencheur :
   l'ordre du DOM est déjà celui-là, seul l'axe change. Empilées d'un seul côté, les deux
   commandes se prennent sans traverser l'écran d'un pouce, et libèrent le coin opposé pour le
   médaillon de carte. align-items est ramené à `center` : dans une colonne, c'est l'axe
   HORIZONTAL, et le `flex-end` de la rangée décalerait les deux boutons contre le bord. */
.th-chasse-capture-row--stack {
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
  gap: 14px;
  left: auto;
  right: 14px;
}
.th-chasse-capture-row--stack.th-chasse-capture-row--left {
  right: auto;
  left: 14px;
}

/* Une commande = un bouton + son libellé, empilés. Le libellé nomme l'action explicitement
   (« Ma collection », « Capture », « Affichage ») : trois pictogrammes seuls ne disaient pas au
   joueur ce qu'il allait déclencher. Il ne capte pas le pointeur — la carte reste manipulable
   entre les boutons — et il est aria-hidden côté balisage, le bouton portant déjà le même nom
   accessible. */
.th-chasse-cmd {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
}
.th-chasse-cmd-label {
  font: 800 11.5px var(--font-sans);
  letter-spacing: 0.02em;
  color: #fff;
  white-space: nowrap;
  /* Ombre portée plutôt qu'un fond : le libellé reste lisible sur le plan clair comme sur
     l'imagerie satellite, sans ajouter une pastille de plus par-dessus la carte. */
  text-shadow: 0 1px 4px rgba(8, 20, 24, 0.9), 0 0 3px rgba(8, 20, 24, 0.7);
  pointer-events: none;
}

/* Mini-fenêtre d'aperçu de l'objectif : le flux caméra est déjà ouvert (pré-chargement), le
   joueur voit donc ce que verra la capture avant même de la déclencher. */
/* Accès à la collection — CÔTE À CÔTE avec le déclencheur : ICÔNE (jamais la vignette du dernier
   spot, qui se confondait avec le déclencheur et l'alerte de proximité, tous deux porteurs d'une
   image) plus une pastille de comptage. Le bouton lui-même ne rogne pas (overflow visible) pour
   que la pastille déborde du cercle. */
.th-chasse-collection-btn {
  position: relative;
  border: none;
  background: none;
  padding: 0;
  cursor: pointer;
  flex-shrink: 0;
}
.th-chasse-collection-thumb {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 58px;
  height: 58px;
  border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, 0.85);
  background: var(--bg-card);
  color: var(--tz-teal-d);
  box-shadow: 0 8px 22px -8px rgba(8, 20, 24, 0.65);
}
.th-chasse-collection-count {
  position: absolute;
  right: -5px;
  top: -5px;
  min-width: 23px;
  height: 23px;
  padding: 0 6px;
  border-radius: 999px;
  background: var(--ember);
  color: #fff;
  font: 800 12px var(--font-sans);
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 3px 8px rgba(51, 48, 42, 0.35);
}

/* Options de fond de carte — troisième bouton de la rangée, symétrique de la collection. Le
   sélecteur natif de Leaflet est désactivé sur la carte du jeu (ShowLayerControl="false") pour que
   les trois commandes vivent au même endroit. */
.th-chasse-layers {
  position: relative;
  flex-shrink: 0;
}
.th-chasse-layers-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 58px;
  height: 58px;
  padding: 0;
  border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, 0.85);
  background: var(--bg-card);
  color: var(--tz-teal-d);
  box-shadow: 0 8px 22px -8px rgba(8, 20, 24, 0.65);
  cursor: pointer;
}
.th-chasse-layers-btn.is-open {
  background: var(--tz-teal-d);
  color: #fff;
}
/* Panneau d'options, ouvert AU-DESSUS du bouton et aligné sur son bord droit (il ne peut donc
   jamais déborder de la carte du côté opposé au déclencheur). */
.th-chasse-layers-panel {
  position: absolute;
  right: 0;
  bottom: calc(100% + 10px);
  z-index: 2;
  min-width: 178px;
  padding: 10px;
  border: 1.5px solid var(--line-strong);
  border-radius: 14px;
  background: var(--bg-card);
  box-shadow: 0 18px 40px -18px rgba(8, 20, 24, 0.7);
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.th-chasse-layers-seg {
  display: flex;
  gap: 4px;
  padding: 3px;
  border-radius: 999px;
  background: var(--bg-soft);
}
.th-chasse-layers-seg button {
  flex: 1;
  border: none;
  border-radius: 999px;
  padding: 7px 10px;
  background: transparent;
  color: var(--ink-soft);
  font: 800 12px var(--font-sans);
  cursor: pointer;
}
.th-chasse-layers-seg button.is-active {
  background: var(--tz-teal-d);
  color: #fff;
}
.th-chasse-layers-check {
  display: flex;
  align-items: center;
  gap: 8px;
  font: 700 12.5px var(--font-sans);
  color: var(--ink);
  cursor: pointer;
}
.th-chasse-layers-check input { accent-color: var(--tz-teal-d); cursor: pointer; }

/* Déclencheur rond façon appareil photo (remplace l'ancien bouton « Prendre une photo »). Bien
   plus gros que les deux commandes qui l'encadrent : c'est le geste du jeu, et il doit rester
   atteignable au pouce sans viser. Taille pilotée par --th-chasse-shutter-size (posée sur
   .th-chasse-map) : ce qui est posé au-dessus de la rangée (.th-chasse-compass, contrôles Leaflet
   du coin bas droit) dérive sa marge basse de cette même variable, si bien qu'un redimensionnement
   du déclencheur ne peut pas le laisser passer dessous. */
.th-chasse-shutter {
  width: var(--th-chasse-shutter-size);
  height: var(--th-chasse-shutter-size);
  border-radius: 50%;
  /* Anneau blanc translucide plutôt qu'ambre : le déclencheur flotte désormais sur la carte, et
     doit rester lisible aussi bien sur le plan clair que sur l'imagerie satellite sombre. */
  border: 6px solid rgba(255, 255, 255, 0.82);
  background: rgba(8, 20, 24, 0.28);
  padding: 6px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}
.th-chasse-shutter-core {
  position: relative;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  overflow: hidden;
  /* Fond ambre visible tant que le flux caméra n'est pas arrivé (permission en attente, refusée,
     ou desktop) : le bouton ne devient jamais un disque vide. */
  background: var(--ember);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 14px 26px -12px rgba(242, 84, 61, 0.55);
  transition: transform 0.12s ease;
}
/* Aperçu caméra EN FOND du déclencheur : le joueur voit ce que verra la photo à l'endroit même où
   il appuie. */
.th-chasse-shutter-core video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
/* Pictogramme photo par-dessus le flux, sur un voile sombre qui lui garantit son contraste quelle
   que soit la scène cadrée. */
.th-chasse-shutter-glyph {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(8, 20, 24, 0.3);
  color: #fff;
  filter: drop-shadow(0 2px 6px rgba(0, 0, 0, 0.55));
}
.th-chasse-shutter:active .th-chasse-shutter-core { transform: scale(0.92); }

/* Interfaces v1b/v1c — déclencheur SANS aperçu caméra en fond (aucun <video> n'y est monté : le
   flux plein écran est déjà derrière le bouton). Le voile sombre du pictogramme n'a alors plus
   rien à contraster : il assombrissait le disque ambre pour rien. Anneau et rembourrage sont
   resserrés à l'échelle du bouton réduit. */
.th-chasse-map--cam .th-chasse-shutter {
  border-width: 4px;
  padding: 4px;
}
.th-chasse-map--cam .th-chasse-shutter-glyph { background: transparent; }

/* Déclencheur MIS EN ÉVIDENCE à proximité d'un spot repéré (même condition que le photomaton
   d'alerte, cf. NearbyAlert) : anneau ambre + halo qui se propage en boucle. L'alerte signale
   « il y a quelque chose ici », ce clignotement dit « c'est ici qu'on appuie » — les deux
   battent au même rythme (1,8 s) pour se lire comme un seul signal, pas comme deux alarmes.
   Le halo passe par box-shadow (aucune incidence sur la mise en page, donc pas de saccade sur
   la rangée de commandes) et le fond du bouton reste le flux caméra. */
.th-chasse-shutter--alert {
  border-color: var(--ember);
  animation: th-chasse-shutter-pulse 1.8s ease-out infinite;
}
@keyframes th-chasse-shutter-pulse {
  0%       { box-shadow: 0 0 0 0 color-mix(in oklch, var(--ember) 65%, transparent); }
  70%, 100% { box-shadow: 0 0 0 18px color-mix(in oklch, var(--ember) 0%, transparent); }
}
/* « Animations réduites » : le déclencheur garde son anneau ambre — la mise en évidence subsiste,
   seul le battement disparaît (même traitement que .th-chasse-alert). */
@media (prefers-reduced-motion: reduce) {
  .th-chasse-shutter--alert { animation: none; box-shadow: 0 0 0 5px color-mix(in oklch, var(--ember) 35%, transparent); }
}

/* ── Collection en overlay (ouverte par le photomaton) ── */
.th-chasse-collection-overlay {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  background: color-mix(in oklch, var(--ink) 45%, transparent);
  animation: th-fade-in 0.18s;
}
.th-chasse-collection-sheet {
  width: 100%;
  max-width: 560px;
  max-height: 82vh;
  display: flex;
  flex-direction: column;
  background: var(--bg-card);
  border: 1.5px solid var(--line);
  border-radius: var(--r-lg) var(--r-lg) 0 0;
  box-shadow: 0 -24px 60px -24px rgba(11, 79, 90, 0.5);
}
@media (min-width: 640px) {
  .th-chasse-collection-overlay { align-items: center; }
  .th-chasse-collection-sheet { border-radius: var(--r-lg); }
}
.th-chasse-collection-head {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 16px 10px;
  border-bottom: 1.5px solid var(--line);
}
.th-chasse-collection-head .th-play2-icon-btn { margin-left: auto; }

/* Contrôles Leaflet du coin bas droit du mode collection : le zoom +/-, et au-dessus de lui le
   sélecteur de fond (Plan / Satellite / Repères) quand il est actif (voir leafletSpotsMap.init) — le
   coin haut droit est pris par le photomaton de l'alerte de proximité. Ils sont REMONTÉS de toute la
   hauteur de la rangée de commandes (--th-chasse-row-h, comme les flèches de boussole) : au ras du
   bord, ils passaient sous le bouton « Affichage » et son libellé. */
.th-chasse-map .leaflet-bottom.leaflet-right {
  margin-bottom: calc(var(--th-chasse-row-h) + env(safe-area-inset-bottom));
}
.th-chasse-collection-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: 14px 16px calc(16px + env(safe-area-inset-bottom));
}

/* ══════════════════════════════════════════════════════════════════════
   Écran de jeu collection — mode DESKTOP / tablette large.
   Même shell qu'en mobile (carte plein écran + panneau « Objectif » + overlays) : à partir
   de 1024 px, la coque cesse d'être une colonne « téléphone » (règle ≥ 640 px sur
   .th-play2-shell) et les overlays gagnent la même ampleur que ceux du mode traversée
   (cf. .th-play2-jeu). Porté par .th-play2-chasse, qui ne touche jamais .th-play2-shell /
   .th-play2-objective / .th-play2-icon-btn hors de cette portée : ces classes restent
   partagées avec le mode traversée (voir le commentaire au-dessus de .th-play2-jeu).
   ══════════════════════════════════════════════════════════════════════ */
@media (min-width: 1024px) {
  .th-play2-chasse.th-play2-shell {
    max-width: none;
    margin: 0;
    box-shadow: none;
  }

  .th-play2-chasse .th-play2-objective { padding: 11px 24px 12px; }
  .th-play2-chasse .th-play2-objective-title { font-size: 22px; }
  .th-play2-chasse .th-play2-icon-btn { width: 34px; height: 34px; }
  /* Le volet « Objectif » plafonne toujours plus bas que la carte : pas de dock flottant ici
     (le panneau reste un bandeau plein largeur au-dessus, déjà lisible à cette largeur). */
  .th-play2-chasse .th-play2-panel--top .th-play2-panel-body { max-height: 22vh; }

  /* Photomaton d'alerte agrandi, comme le polaroid d'indice du mode traversée. */
  .th-play2-chasse .th-play2-polaroid { --th-polaroid-photo-w: 170px; }
  .th-play2-chasse .th-play2-polaroid-photo { height: 140px; }
  .th-play2-chasse .th-play2-polaroid-caption { font-size: 17px; }
  .th-play2-chasse .th-play2-polaroid-tape { width: 70px; height: 20px; }

  /* Légende/score et précision GPS, un peu plus lisibles à distance de bureau. */
  .th-play2-chasse .th-chasse-gps-chip { font-size: 12.5px; padding: 4px 11px; }
}

/* ══ Interfaces v1b / v1c du mode joueur « collection » ══
   Le bouton « Affichage » ne règle plus seulement le FOND de carte (Plan / Satellite / Repères)
   mais aussi la PLACE que la carte occupe : masquée, normale, ou agrandie de moitié. L'interface
   historique (v1a) n'expose pas ce réglage et n'est donc touchée par AUCUNE des règles ci-dessous :
   elles ne s'appliquent qu'aux modificateurs posés par les deux nouvelles variantes.
   Le choix de l'interface servie est un réglage d'administration (« Paramètres généraux »). */

/* Séparateur + intitulé de la seconde section du panneau « Affichage » (taille de la carte) : le
   panneau porte désormais deux réglages de nature différente, il faut les distinguer d'un coup d'œil. */
.th-chasse-layers-sep {
  height: 1px;
  background: var(--line);
  margin: 2px 0;
}
.th-chasse-layers-title {
  font: 800 10.5px var(--font-sans);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
}

/* Carte masquée — le fond de carte, les marqueurs et les contrôles Leaflet disparaissent
   (visibility:hidden posé par ChasseSpotsMap, qui garde la carte MONTÉE pour ne pas la
   reconstruire au retour). Reste ce fond neutre sombre, sur lequel compteurs, flèches de boussole
   et commandes restent parfaitement lisibles. En v1c, c'est la caméra qui occupe déjà ce fond :
   pas de teinte à poser par-dessus. */
.th-chasse-map--nomap { background: #0d1b20; }
.th-chasse-map--cam.th-chasse-map--nomap { background: #000; }

/* ── v1c : caméra plein écran, carte en médaillon ──
   Le flux caméra (le MÊME que celui du déclencheur, simplement rebranché sur un second <video>)
   occupe tout le fond ; la carte se replie en médaillon posé en bas à gauche, au-dessus de la
   rangée de commandes. */
.th-chasse-cam-backdrop {
  position: absolute;
  inset: 0;
  z-index: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  background: #000;
}

/* Bandeau de compteurs de la v1c — posé sur la CAMÉRA : dans un médaillon de la taille d'une
   vignette, la légende et le score seraient illisibles. Même contenu et même dégradé que le
   bandeau interne de la carte (voir ChasseSpotsMap), ancré à gauche pour laisser le coin haut
   droit à l'alerte de proximité. Ne capte pas le pointeur, sauf ses pastilles à infobulle. */
.th-chasse-camhud {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  z-index: 26;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 7px;
  /* Marge droite élargie : la roue crantée « main dominante » occupe ce coin, et la rangée de
     légende ne doit pas venir passer dessous. */
  padding: 10px 56px 22px 12px;
  pointer-events: none;
  background: linear-gradient(180deg, rgba(8, 20, 24, 0.65), rgba(8, 20, 24, 0));
}
.th-chasse-camhud-row {
  display: flex;
  align-items: center;
  gap: 11px;
  flex-wrap: wrap;
}
.th-chasse-camhud-legend {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font: 700 11.5px var(--font-sans);
  color: #fff;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.55);
}
.th-chasse-camhud-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  flex-shrink: 0;
}
.th-chasse-camhud-score {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4px 10px;
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.4);
  font: 800 12.5px var(--font-sans);
  color: #fff;
}
.th-chasse-camhud-sep {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  border-left: 1px solid rgba(255, 255, 255, 0.3);
  padding-left: 6px;
}

/* Cadre de la carte — posé sur toute la zone de jeu (v1a/v1b). Il existe dans TOUTES les
   interfaces : la carte se dimensionne en % de ce cadre, un conteneur à hauteur automatique la
   laisserait à zéro. */
.th-chasse-mapframe {
  position: absolute;
  inset: 0;
}

/* ── Roue crantée « main dominante » (v1b/v1c) ──
   Tout en haut de la zone de jeu, dans le coin que le bandeau de compteurs laisse libre. C'est le
   seul réglage qui ne porte pas sur la carte mais sur la PRISE EN MAIN — de quel côté tombent les
   commandes — et il se règle une fois, en début de partie : il doit donc être atteignable sans
   être dans le chemin. Au-dessus du photomaton d'alerte (z-index 27), que son panneau recouvre le
   temps du choix. */
.th-chasse-handed {
  position: absolute;
  top: 8px;
  right: 12px;
  z-index: 28;
}
.th-chasse-handed-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  padding: 0;
  border-radius: 50%;
  border: 1.5px solid rgba(255, 255, 255, 0.9);
  background: rgba(8, 20, 24, 0.72);
  color: #fff;
  cursor: pointer;
  box-shadow: 0 4px 12px -4px rgba(8, 20, 24, 0.8);
}
.th-chasse-handed-btn.is-open {
  background: var(--tz-teal-d);
  border-color: #fff;
}
/* Panneau ouvert SOUS le bouton et aligné sur son bord droit : il ne peut donc pas déborder de
   l'écran du côté opposé. Même habillage que le panneau de calques de la v1a. */
.th-chasse-handed-panel {
  position: absolute;
  right: 0;
  top: calc(100% + 8px);
  z-index: 2;
  min-width: 178px;
  padding: 10px;
  border: 1.5px solid var(--line-strong);
  border-radius: 14px;
  background: var(--bg-card);
  box-shadow: 0 18px 40px -18px rgba(8, 20, 24, 0.7);
  display: flex;
  flex-direction: column;
  gap: 8px;
}

/* Médaillon de carte (v1b/v1c) — ancré dans le coin bas OPPOSÉ aux commandes : la main qui tient
   l'appareil ne doit pas masquer la carte qu'on vient consulter. Ce coin étant libre de tout
   bouton, le médaillon descend jusqu'au bas de l'écran — inutile de le remonter de la hauteur de
   la colonne de commandes, qui vit de l'autre côté. « ×1,5 » agrandit LE MÉDAILLON : grossir le
   rendu d'une carte déjà réduite à une vignette ne montrerait plus rien de son entourage. */
.th-chasse-minimap {
  inset: auto;
  bottom: calc(14px + env(safe-area-inset-bottom));
  z-index: 27;
  border: 2px solid rgba(255, 255, 255, 0.85);
  overflow: hidden;
  box-shadow: 0 10px 28px -12px rgba(8, 20, 24, 0.8);
  transition: width 0.16s ease, height 0.16s ease;
}
.th-chasse-minimap--anchor-left { left: 12px; }
.th-chasse-minimap--anchor-right { right: 12px; }

/* Les deux formes de médaillon — SEULE différence entre v1b (rond) et v1c (carré). Même côté,
   même ancrage, mêmes icônes : un diamètre unique (--th-minimap-d) sert de côté au carré comme
   au disque, pour que les deux interfaces occupent exactement la même empreinte à l'écran. */
.th-chasse-minimap--round,
.th-chasse-minimap--square {
  --th-minimap-d: min(52vw, 210px);
  width: var(--th-minimap-d);
  height: var(--th-minimap-d);
}
.th-chasse-minimap--round.th-chasse-minimap--zoom,
.th-chasse-minimap--square.th-chasse-minimap--zoom {
  --th-minimap-d: min(74vw, 300px);
}
/* Un disque se lit comme un instrument de bord (boussole, radar) plutôt que comme une fenêtre :
   il dit « repère-toi », pas « lis la carte ». Le carré, lui, garde le rayon des cartes du jeu. */
.th-chasse-minimap--round { border-radius: 50%; }
.th-chasse-minimap--square { border-radius: var(--r-lg, 12px); }
/* Le conteneur interne de ChasseSpotsMap porte son propre border-radius (Rounded) : il faut le
   rendre circulaire lui aussi, sinon les tuiles Leaflet débordent aux quatre coins du disque.
   Le carré n'a rien à corriger : le rayon posé par le composant est déjà le bon. */
.th-chasse-minimap--round > div { border-radius: 50% !important; }

/* Carte masquée : le médaillon disparaît entièrement — sans cette règle, son cadre blanc
   flotterait, vide, sur la caméra. */
.th-chasse-map--nomap .th-chasse-minimap { display: none; }

/* Contrôles natifs de Leaflet dans le médaillon : supprimés. Ils sont ancrés dans les COINS, où
   le rognage circulaire de la v1b n'en laisserait qu'un moignon et où, en v1c, ils tomberaient
   sous les icônes de bordure. Le médaillon est un instrument de bord — on s'y repère, on n'y
   navigue pas : le pincement zoome toujours, et l'icône « ×1,5 » agrandit la vignette. */
.th-chasse-map--cam .leaflet-control-container { display: none; }

/* Les TROIS icônes posées sur la LIMITE du médaillon : masquer la carte (coin haut), agrandir de
   moitié (à mi-hauteur) et basculer plan ⇄ satellite (coin bas). Elles remplacent entièrement le
   bouton « Affichage » de la rangée basse. Posées juste EN DEÇÀ du bord — le médaillon rogne
   (en cercle sur la v1b), une pastille à cheval sur le trait serait coupée en deux — et TOUJOURS
   du côté qui fait face au centre de l'écran (voir --anchor-*), jamais contre le bord où le
   pouce ne va pas. --th-rim-diag place les deux pastilles de coin, --th-rim-side celle du
   milieu ; le disque les rentre davantage que le carré, dont les coins sont pleins. */
.th-chasse-minimap--round { --th-rim-diag: 14%; --th-rim-side: 3%; }
.th-chasse-minimap--square { --th-rim-diag: 5%; --th-rim-side: 5%; }
.th-chasse-minimap-btn {
  position: absolute;
  z-index: 2;
  width: 30px;
  height: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border-radius: 50%;
  border: 1.5px solid rgba(255, 255, 255, 0.9);
  background: rgba(8, 20, 24, 0.72);
  color: #fff;
  cursor: pointer;
  box-shadow: 0 4px 12px -4px rgba(8, 20, 24, 0.8);
}
.th-chasse-minimap--anchor-left .th-chasse-minimap-btn--hide { top: var(--th-rim-diag); right: var(--th-rim-diag); }
.th-chasse-minimap--anchor-left .th-chasse-minimap-btn--layer { bottom: var(--th-rim-diag); right: var(--th-rim-diag); }
.th-chasse-minimap--anchor-left .th-chasse-minimap-btn--zoom {
  top: 50%;
  right: var(--th-rim-side);
  transform: translateY(-50%);
}
.th-chasse-minimap--anchor-right .th-chasse-minimap-btn--hide { top: var(--th-rim-diag); left: var(--th-rim-diag); }
.th-chasse-minimap--anchor-right .th-chasse-minimap-btn--layer { bottom: var(--th-rim-diag); left: var(--th-rim-diag); }
.th-chasse-minimap--anchor-right .th-chasse-minimap-btn--zoom {
  top: 50%;
  left: var(--th-rim-side);
  transform: translateY(-50%);
}
/* Réglage actif (fond satellite, médaillon agrandi) : l'icône s'allume. C'est le seul rappel de
   l'état courant — il n'y a plus de panneau où lire les trois options côte à côte. */
.th-chasse-minimap-btn.is-active {
  background: var(--ember);
  border-color: #fff;
}

/* Médaillon escamoté : une pastille prend sa place, dans le même coin, pour le rappeler. Sans
   elle, les trois icônes disparaîtraient avec la carte qu'elles portent — et « Affichage »
   n'existe plus pour la faire revenir. */
.th-chasse-minimap-show {
  position: absolute;
  left: 12px;
  bottom: calc(14px + env(safe-area-inset-bottom));
  z-index: 27;
  width: 44px;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, 0.85);
  background: rgba(8, 20, 24, 0.72);
  color: #fff;
  cursor: pointer;
  box-shadow: 0 10px 28px -12px rgba(8, 20, 24, 0.8);
}
.th-chasse-map--lefty .th-chasse-minimap-show {
  left: auto;
  right: 12px;
}

/* ── Écran de choix d'étape (mode challenge uniquement) ────────────────────────
   Même coquille que l'écran de jeu (.th-play2-shell / .th-play2-map) : seule la zone
   basse change — une liste d'étapes acceptables, triée par distance, surmontée par le
   bouton « Accepter l'étape ». En mode parcours cet écran n'existe pas : l'étape
   suivante est sélectionnée automatiquement.
   ─────────────────────────────────────────────────────────────────────────── */
.th-play2-choicesheet {
  flex: none;
  max-height: 46vh;
  overflow-y: auto;
  padding: 14px 16px calc(16px + env(safe-area-inset-bottom, 0px));
  display: flex;
  flex-direction: column;
  gap: 12px;
  background: var(--bg-card);
  border-top: 1.5px solid var(--line);
  box-shadow: 0 -8px 24px rgba(0, 0, 0, .08);
}
.th-play2-choice-empty {
  margin: 0;
  font: 700 13px var(--font-sans);
  color: var(--muted);
  line-height: 1.5;
  text-align: center;
}
.th-play2-choicelist { display: flex; flex-direction: column; gap: 8px; }

.th-play2-choice {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  text-align: left;
  padding: 11px 13px;
  border: 1.5px solid var(--line-strong);
  border-radius: var(--r);
  background: var(--bg);
  cursor: pointer;
  transition: border-color .15s ease, background .15s ease;
}
.th-play2-choice:hover { border-color: var(--canopy); }
.th-play2-choice.is-selected {
  border-color: var(--canopy);
  border-width: 2px;
  background: var(--canopy-soft);
}
.th-play2-choice-badge {
  flex: none;
  width: 30px; height: 30px;
  border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: var(--bg-soft);
  border: 2px solid var(--canopy);
  color: var(--canopy);
  font: 800 13px var(--font-sans);
}
.th-play2-choice.is-selected .th-play2-choice-badge { background: var(--canopy); color: #fff; }
.th-play2-choice-body { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.th-play2-choice-name {
  font: 800 13.5px var(--font-sans);
  color: var(--ink);
  line-height: 1.3;
}
.th-play2-choice-meta {
  display: flex; align-items: center; gap: 4px; flex-wrap: wrap;
  font: 700 11.5px var(--font-sans);
  color: var(--muted);
}
.th-play2-choice-locked {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 13px;
  border: 1.5px dashed var(--line-strong);
  border-radius: var(--r);
  background: var(--bg-soft);
  font: 700 12.5px var(--font-sans);
  color: var(--muted);
  line-height: 1.45;
}

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

/* Sur l'écran de choix, la carte prend toute la hauteur restante au-dessus du volet des
   étapes (qui, lui, se dimensionne sur son contenu) — au lieu des 52 % fixes de l'écran de
   jeu, où elle partage la place avec le panneau « Objectif ». */
.th-play2-shell--choix .th-play2-map { flex: 1 1 auto; }

