/* ===== FONTS — auto-hébergées (cf. § 10.2) ===== */
/* Fraunces : variable font (opsz 9..144, wght 300..600) — un fichier par style */
@font-face {
  font-family: 'Fraunces';
  font-style: normal;
  font-weight: 300 600;
  font-display: swap;
  src: url('/assets/fonts/fraunces-roman.48282a415e.woff2') format('woff2');
}
@font-face {
  font-family: 'Fraunces';
  font-style: italic;
  font-weight: 300 600;
  font-display: swap;
  src: url('/assets/fonts/fraunces-italic.4af9c759c8.woff2') format('woff2');
}
/* Inter : variable font (wght 400..700) — un seul fichier latin */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/assets/fonts/inter.c940764593.woff2') format('woff2');
}
/* Fallbacks calibrés (cf. § 10.3) — réduisent le CLS avant chargement woff2 */
@font-face {
  font-family: 'Fraunces Fallback';
  src: local('Times New Roman'), local('Times');
  size-adjust: 100%;
  ascent-override: 96%;
  descent-override: 24%;
  line-gap-override: 0%;
}
@font-face {
  font-family: 'Inter Fallback';
  src: local('Arial');
  size-adjust: 107.4%;
  ascent-override: 90.5%;
  descent-override: 22.5%;
  line-gap-override: 0%;
}

/* ===== RESET & BASE ===== */
:root {
  /* ─── Variables canoniques (§ 5.1) ─────────────────────────────────────
     Nomenclature unifiée GoStudio — utilisée en priorité par les nouveaux
     composants. Les anciennes variables (--accent, --text, --gold, etc.)
     sont conservées comme aliases ci-dessous pour ne pas casser le CSS
     historique de la page. ──────────────────────────────────────────── */
  --color-primary: #6d4dff;               /* violet GoTombola — primaire */
  --color-primary-rgb: 109, 77, 255;      /* pour rgba(var(--color-primary-rgb), …) */
  --color-accent: #d4af37;                /* or — usage homéopathique */
  --color-accent-soft: #c9a961;           /* or atténué (eyebrows featured) */
  --color-bg: #fafaf8;                    /* crème de fond — base du dégradé body */
  --color-surface: rgba(0, 0, 0, 0.04);   /* glassmorphic clair */
  --color-surface-muted: rgba(0, 0, 0, 0.03);
  --color-text: #1a1a2e;                  /* texte principal — contraste WCAG AA */
  --color-text-muted: #5a5a72;            /* texte secondaire */
  --color-border: rgba(0, 0, 0, 0.08);
  --color-border-strong: rgba(0, 0, 0, 0.18);

  --font-display: 'Fraunces', 'Fraunces Fallback', 'Times New Roman', Georgia, serif;
  --font-body: 'Inter', 'Inter Fallback', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;

  --radius: 12px;
  --shadow-xl: 0 24px 60px rgba(0, 0, 0, 0.45);
  --ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);
  --font-scale: 1;                        /* posé par a11y.js (réservé) */

  /* ─── Aliases compat (utilisés par le CSS historique de cette page) ── */
  --accent: var(--color-primary);
  --accent-glow: rgba(109, 77, 255, 0.25);
  --surface: var(--color-surface);
  --surface-border: var(--color-border);
  --bg-card: var(--color-surface-muted);
  --text: var(--color-text);
  --text-muted: var(--color-text-muted);
  --text-dim: #9999aa;
  --gold: var(--color-accent);
  --gold-subtle: var(--color-accent-soft);
  --gold-glow: rgba(212, 175, 55, 0.2);
}
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html { scroll-behavior: smooth; }
body {
  font-family: 'Inter', 'Inter Fallback', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  background: linear-gradient(160deg, #fafaf8 0%, #f4f2ef 100%) fixed;
  color: var(--text);
  min-height: 100vh;
  line-height: 1.6;
}
/* Display — Fraunces pour tous les titres éditoriaux */
h1, h2 {
  font-family: 'Fraunces', 'Fraunces Fallback', 'Times New Roman', Georgia, serif;
  font-weight: 300;
  font-style: normal;
}
/* UI subheadings — Inter reste sur h3 */
h3 {
  font-family: 'Inter', 'Inter Fallback', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  font-weight: 600;
  font-style: normal;
}
a { color: inherit; text-decoration: none; }

/* ===== SKIP LINK — a11y § 13.8 / R12 =====
   Lien « Aller au contenu » masqué hors focus clavier, glisse vers le bas
   en 280 ms à la prise de focus. Premier élément du <body> pour précéder
   tout contenu navigable au clavier. */
.skip-link {
  position: absolute;
  top: -100px;
  left: 16px;
  z-index: 10000;
  padding: 12px 20px;
  background: var(--color-primary);
  color: #ffffff;
  font-family: 'Inter', 'Inter Fallback', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  font-weight: 600;
  font-size: 0.95rem;
  text-decoration: none;
  border-radius: 8px;
  box-shadow: 0 8px 24px rgba(var(--color-primary-rgb), 0.35);
  transition: top 280ms var(--ease-out-expo);
}
.skip-link:focus,
.skip-link:focus-visible {
  top: 16px;
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
  .skip-link { transition: none; }
}

/* ===== LAYOUT ===== */
/* Padding latéral protégé contre la safe-area iOS (notch en paysage) — voir
   request-2026-05-29-0047 · item-006. max() = la valeur native gagne sur
   desktop (env() = 0) ; en iOS landscape l'inset gagne et le contenu reste
   en zone visible. Décliné aux breakpoints 768/640 pour rester cohérent
   avec les paddings responsive. */
.container {
  max-width: 1440px;
  margin: 0 auto;
  padding-left: max(32px, env(safe-area-inset-left));
  padding-right: max(32px, env(safe-area-inset-right));
}

/* ===== HEADER — Premium 5 étoiles (request-2026-05-29-0000 · item-002) =====
   Objectif : ressenti immédiat « marque de luxe ».
   - Hauteur respirée clamp(72→88px), condensée −4px au scroll
   - Glassmorphism renforcé : blur(18px) saturate(140%) + voile crème 0.94
   - Ligne or 30 % en bas, révélée uniquement au scroll (>8px) via
     `html.is-scrolled` posé par le bootstrap FX inline
   - Ombre douce + transition smooth quand on a quitté le haut de la page
   - Logo : drop-shadow doré + scale(1.02) au hover (plus d'opacity .78)
   - Nav links : tracking +0.015em, ss01/cv11 (Inter stylistic), underline
     or animé centre→bords (plus raffiné)
   - CTA bouton : dégradé violet → or subtil + inner-shadow chaud,
     halo or au hover, suppression de l'animation pulse (« cheap »)
========================================================================= */
header[role="banner"] {
  position: sticky;
  top: 0;
  z-index: 100;
  background: rgba(250, 250, 248, 0.94);
  -webkit-backdrop-filter: blur(18px) saturate(140%);
  backdrop-filter: blur(18px) saturate(140%);
  /* En haut de page : pas de bordure visible — la ligne or apparaît au scroll. */
  border-bottom: 1px solid transparent;
  /* Safe-area iOS (request-2026-05-29-0047 · item-006) — le viewport est
     déclaré viewport-fit=cover, on pousse donc le voile crème + le contenu
     en-dessous du notch / Dynamic Island en portrait sur iPhone Pro. */
  padding-top: env(safe-area-inset-top);
  transition: background 320ms cubic-bezier(.25,.46,.45,.94),
              box-shadow 320ms cubic-bezier(.25,.46,.45,.94),
              border-bottom-color 320ms cubic-bezier(.25,.46,.45,.94);
}
/* Fine ligne or en dégradé — invisible en haut, révélée au scroll */
header[role="banner"]::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 1px;
  background: linear-gradient(90deg,
    transparent 0%,
    rgba(212, 175, 55, 0.30) 22%,
    rgba(212, 175, 55, 0.55) 50%,
    rgba(212, 175, 55, 0.30) 78%,
    transparent 100%);
  opacity: 0;
  transition: opacity 360ms cubic-bezier(.25,.46,.45,.94);
  pointer-events: none;
}
/* État scrollé — voile plus dense, ombre douce, ligne or révélée. */
html.is-scrolled header[role="banner"] {
  background: rgba(250, 250, 248, 0.96);
  box-shadow:
    0 10px 28px -16px rgba(26, 26, 46, 0.20),
    0  4px 12px  -6px rgba(26, 26, 46, 0.10);
}
html.is-scrolled header[role="banner"]::after { opacity: 1; }

.header-inner {
  display: flex;
  align-items: center;
  /* request-2026-05-29-0047 · item-013 — bascule en layout `gap` + auto-margins
     pour accueillir le CTA en sibling direct du logo / burger / nav (et plus
     comme dernier enfant du <nav>). `space-between` retiré : avec 3 enfants
     visibles sur desktop (logo + CTA + nav) ça aurait centré le CTA entre
     logo (à gauche) et nav (à droite). Le grouping desktop est désormais
     piloté par `margin-left: auto` sur la nav (cf. règle `min-width: 768px`)
     et l'ordre flex (CTA en order: 1 → après les liens nav visuellement). */
  gap: 6px;
  /* Respiration premium : 72 → 88 px en repos */
  height: clamp(72px, 8vh, 88px);
  transition: height 320ms cubic-bezier(.25,.46,.45,.94);
}
/* État condensé : −4 px (subtil mais perceptible) */
html.is-scrolled .header-inner {
  height: clamp(68px, 7.4vh, 84px);
}

.logo {
  display: flex;
  align-items: center;
  transition: transform 0.35s cubic-bezier(.25,.46,.45,.94),
              filter 0.35s cubic-bezier(.25,.46,.45,.94);
}
.logo-img-header {
  height: 32px;                /* +4 px vs ancien 28 px — gain de prestance */
  width: auto;
  display: block;
  transition: filter 0.35s cubic-bezier(.25,.46,.45,.94);
}
/* Hover : léger scale + halo doré (signature lux), plus d'opacity .78 */
.logo:hover {
  transform: scale(1.02);
  filter: drop-shadow(0 0 12px rgba(212, 175, 55, 0.38));
}
.logo:hover .logo-img-header { opacity: 1; }

nav {
  display: flex;
  align-items: center;
  gap: 6px;                    /* respiration nav (4 → 6) */
}
nav a {
  padding: 10px 16px;          /* respiration verticale & horizontale */
  border-radius: 9px;
  font-size: 14px;
  font-weight: 500;
  letter-spacing: 0.015em;     /* tracking légèrement accru */
  font-feature-settings: 'ss01', 'cv11';  /* Inter stylistic — `a` curseur, `g` single-storey */
  color: var(--text-muted);
  transition: color .18s ease, background .18s ease;
  white-space: nowrap;
  position: relative;
}
nav a:hover {
  color: var(--text);
  background: rgba(0, 0, 0, 0.025);
}
/* Underline OR raffiné — apparition centre→bords (scaleX origin center) */
nav a:not(.btn-nav-cta)::after {
  content: '';
  position: absolute;
  bottom: 6px;
  left: 16px;                  /* aligne sur le padding horizontal */
  right: 16px;
  height: 1px;
  background: linear-gradient(90deg,
    transparent 0%,
    rgba(212, 175, 55, 0.65) 28%,
    #f4d77a 50%,
    rgba(212, 175, 55, 0.65) 72%,
    transparent 100%);
  transform: scaleX(0);
  transform-origin: center;
  transition: transform 0.32s cubic-bezier(.16, 1, 0.3, 1);
}
nav a:not(.btn-nav-cta):hover::after { transform: scaleX(1); }

/* ── CTA nav — gradient violet → or subtil + inner-shadow + halo or hover ──
   Plus d'animation pulse infinite : la marque doit ressentir « luxe »,
   pas « SaaS qui sollicite votre attention ». */
.btn-nav-cta {
  padding: 10px 22px !important;          /* respiration premium */
  border-radius: 10px !important;
  /* Dégradé violet riche, basculant vers une touche or en fin de course. */
  background: linear-gradient(135deg,
    #6d4dff 0%,
    #7a5cff 50%,
    #9a7be0 88%,
    #b59538 130%) !important;
  background-size: 180% 100% !important;
  background-position: 0% 50% !important;
  color: #fff !important;
  font-weight: 600 !important;
  letter-spacing: 0.018em !important;
  font-feature-settings: 'ss01', 'cv11' !important;
  position: relative;
  z-index: 0;
  /* Inner-shadow chaud + ombre extérieure soft (relief premium) */
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.24),
    inset 0 -1px 0 rgba(0, 0, 0, 0.18),
    0 6px 18px -6px rgba(109, 77, 255, 0.42) !important;
  transition: transform .28s cubic-bezier(.25,.46,.45,.94),
              box-shadow .35s cubic-bezier(.25,.46,.45,.94),
              background-position .65s cubic-bezier(.25,.46,.45,.94),
              filter .25s ease !important;
  /* Plus de pulse infini — la lecture « luxe » l'exige. */
  animation: none !important;
}
.btn-nav-cta:hover {
  transform: scale(1.035) !important;
  /* Glisse vers la zone or du dégradé */
  background-position: 100% 50% !important;
  filter: brightness(1.05);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.30),
    inset 0 -1px 0 rgba(0, 0, 0, 0.20),
    /* Halo or premium proche + diffus, puis halo violet de profondeur */
    0  0 18px rgba(212, 175, 55, 0.48),
    0  0 38px rgba(212, 175, 55, 0.22),
    0 14px 36px -8px rgba(109, 77, 255, 0.52) !important;
}
.btn-nav-cta::before {
  content: '';
  position: absolute;
  inset: 0;
  padding: 1.5px;
  border-radius: 10px;
  /* Liseré conic — bascule lilas → or → blanc nacré pour cohérence luxe */
  background: conic-gradient(
    from var(--btn-angle),
    transparent 0%,   transparent 22%,
    rgba(244, 215, 122, .52) 36%,
    rgba(255, 255, 255, .82) 50%,
    rgba(244, 215, 122, .52) 64%,
    transparent 78%,  transparent 100%
  );
  -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  mask-composite: exclude;
  animation: btn-border-rotate 4s linear infinite;
  pointer-events: none;
}

/* ===== HERO ===== */




/* ── CTA premium — border beam + pulse ── */
@property --btn-angle {
  syntax: '<angle>';
  initial-value: 0deg;
  inherits: false;
}
@keyframes btn-border-rotate { to { --btn-angle: 360deg; } }
@keyframes btn-pulse {
  0%, 60%  { box-shadow: 0 12px 40px -8px rgba(109,77,255,.45), 0 0 0 0   rgba(109,77,255,.38); }
  80%      { box-shadow: 0 12px 40px -8px rgba(109,77,255,.45), 0 0 0 20px rgba(109,77,255,0);  }
  100%     { box-shadow: 0 12px 40px -8px rgba(109,77,255,.45), 0 0 0 0   rgba(109,77,255,0);  }
}
/* @keyframes btn-nav-pulse supprimé (item-002 / 2026-05-29) :
   l'animation pulse infinite donnait un ressenti « SaaS générique ».
   Le CTA nav garde maintenant un état stable + halo or au hover. */

.btn-primary {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 15px 30px;
  border-radius: 13px;
  background: linear-gradient(135deg, #6d4dff 0%, #8b6dff 100%);
  color: #fff;
  font-weight: 700;
  font-size: 16px;
  position: relative;
  z-index: 0;
  transition: transform .25s cubic-bezier(.25,.46,.45,.94),
              box-shadow .35s cubic-bezier(.25,.46,.45,.94),
              filter .25s ease;
  animation: btn-pulse 3s ease-out 2s infinite;
}
.btn-primary:hover {
  transform: scale(1.05);
  /* Glow violet riche, double-couche : halo proche + diffuse profonde */
  box-shadow: 0 12px 40px -8px rgba(109, 77, 255, 0.55),
              0 22px 60px -10px rgba(109, 77, 255, 0.65) !important;
  filter: brightness(1.05);
  animation-play-state: paused;
}
/* Border beam ring — conic-gradient animée via @property, pas de transform overflow */
.btn-primary::before {
  content: '';
  position: absolute;
  inset: 0;
  padding: 2px;
  border-radius: 14px;
  background: conic-gradient(
    from var(--btn-angle),
    transparent 0%,   transparent 22%,
    rgba(196,181,253,.48) 38%,
    rgba(255,255,255,.84) 50%,
    rgba(196,181,253,.48) 62%,
    transparent 78%,  transparent 100%
  );
  -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  mask-composite: exclude;
  animation: btn-border-rotate 4s linear infinite;
  pointer-events: none;
}

.btn-secondary {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 15px 30px;
  border-radius: 13px;
  background: var(--surface);
  border: 1px solid var(--surface-border);
  color: var(--text);
  font-weight: 600;
  font-size: 16px;
  transition: transform .2s, background .15s;
}
.btn-secondary:hover { transform: translateY(-2px); background: rgba(0, 0, 0, 0.06); }

.target-pills {
  display: flex;
  justify-content: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-bottom: 24px;
}
.target-pill {
  padding: 4px 12px;
  border-radius: 999px;
  font-size: 12px;
  background: rgba(0, 0, 0, 0.04);
  border: 1px solid rgba(0, 0, 0, 0.10);
  color: var(--text-muted);
}
.trust-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: #6ee7b7;
  flex-shrink: 0;
}


/* ===== SECTION SHARED ===== */
.section-header { text-align: center; margin-bottom: 48px; }
.section-label {
  display: inline-block;
  padding: 4px 12px;
  border-radius: 999px;
  background: rgba(212, 175, 55, 0.07);
  border: 1px solid rgba(212, 175, 55, 0.28);
  font-family: 'Inter', 'Inter Fallback', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: #7d5a0a;           /* or foncé : contraste ~5.7:1 sur fond clair — WCAG AA */
  margin-bottom: 14px;
}
.section-title {
  font-family: 'Fraunces', 'Fraunces Fallback', 'Times New Roman', Georgia, serif;
  font-weight: 600;                       /* éditorial plus dense — contraste affirmé */
  /* item-009 (request-2026-05-29-0047) — typo plus dynamique sur petits écrans :
     clamp(1.6rem, 6.5vw, 2.5rem) → ~24 px à 375 px (vs 28 px avant), plus respirant
     en Fraunces light wrap. La borne haute (2.5rem) reste atteinte ~600 px et le
     desktop est strictement inchangé (clamp plafonné en grand). */
  font-size: clamp(1.6rem, 6.5vw, 2.5rem);
  line-height: 1.08;
  letter-spacing: -0.038em;               /* tracking serré — rendu haut-de-gamme */
  margin-bottom: 12px;
}
.section-desc {
  font-size: 16px;
  color: var(--text-muted);
  max-width: 520px;
  margin: 0 auto;
  line-height: 1.6;
}

/* ===== CARD GRID — 9:16 portrait ===== */
.section-tombolas { padding: 90px 0 160px; }

/* ——— Filter pills ——— */
/* item-005 (request-2026-05-29-0047) — affordance scroll horizontal :
   1. mask-image fade-gradient sur les bords gauche/droit (s'auto-active dès
      qu'il y a débordement, neutre quand tout tient sans scroll) → indice
      visuel que la zone est scrollable, plus de pills coupés net.
   2. scroll-snap-type: x mandatory sur le conteneur + scroll-snap-align:start
      sur chaque pill → snap doux quand on scrolle.
   3. justify-content: safe center → centré quand tout tient, bascule
      automatiquement en flex-start dès qu'on déborde (révèle naturellement
      le fade-droit et garde « Tous » ancré à gauche en début de scroll).
   4. scroll-padding-inline: 8px → quand on snap au début, on aligne « Tous »
      au bord gauche du conteneur (légère respiration avec le mask). */
.filter-pills {
  display: flex;
  align-items: center;
  justify-content: safe center;
  gap: 8px;
  margin-bottom: 44px;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  padding-bottom: 2px;
  mask-image: linear-gradient(to right, transparent 0, #000 16px, #000 calc(100% - 16px), transparent 100%);
  -webkit-mask-image: linear-gradient(to right, transparent 0, #000 16px, #000 calc(100% - 16px), transparent 100%);
  scroll-snap-type: x mandatory;
  scroll-padding-inline: 8px;
}
.filter-pills::-webkit-scrollbar { display: none; }

.filter-pill {
  flex-shrink: 0;
  scroll-snap-align: start;
  padding: 7px 20px;
  border-radius: 999px;
  font-family: 'Inter', 'Inter Fallback', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  color: var(--text-muted);
  background: rgba(255, 255, 255, 0.42);
  backdrop-filter: blur(10px) saturate(140%);
  -webkit-backdrop-filter: blur(10px) saturate(140%);
  border: 1px solid rgba(0, 0, 0, 0.10);
  cursor: pointer;
  transition: color 0.2s, background 0.2s, border-color 0.2s, box-shadow 0.25s,
              transform 0.18s cubic-bezier(.25,.46,.45,.94);
  white-space: nowrap;
  -webkit-appearance: none;
  appearance: none;
  line-height: 1;
}
.filter-pill:hover {
  color: var(--text);
  background: rgba(255, 255, 255, 0.72);
  border-color: rgba(0, 0, 0, 0.18);
  transform: scale(1.06);
  box-shadow: 0 6px 20px -10px rgba(109, 77, 255, 0.32);
}
.filter-pill[aria-pressed="true"] {
  color: #1a1a2e;
  background: rgba(255, 255, 255, 0.78);
  border: 1px solid var(--gold);          /* or franc — état pressé bijou */
  box-shadow: 0 0 18px -3px var(--gold-glow),
              inset 0 0 0 1px rgba(212, 175, 55, 0.55);
}
.filter-pill:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 3px;
}

.card-grid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  grid-auto-rows: auto;
  gap: 24px;
}

/* ——— Card wrapper (interactive link) ——— */
.card {
  aspect-ratio: 9 / 16;
  /* Borne la hauteur en desktop (~iPhone) quel que soit le nb. de colonnes */
  max-height: clamp(420px, 60vh, 720px);
  border-radius: 24px;
  position: relative;
  overflow: hidden;
  display: block;
  cursor: pointer;
  text-decoration: none;
  color: inherit;
  transform-origin: center;
  /* item-003 (request-2026-05-29-0000) : glow externe or PERMANENT au repos —
     très subtil, signe la qualité haut-de-gamme avant même le hover. */
  box-shadow:
    0  0 24px      rgba(212, 175, 55, 0.18),     /* halo or doux permanent — signature premium au repos */
    0 12px 50px -10px rgba(109, 77, 255, 0.18),   /* halo violet subtil — signature premium */
    0  8px 40px  -8px rgba(0, 0, 0, 0.18),
    0  2px  8px  -2px rgba(0, 0, 0, 0.10);
  border: 1px solid transparent;                   /* le ring or ::before prend la relève au repos */
  transition: box-shadow 0.55s cubic-bezier(.25, .46, .45, .94),
              border-color 0.45s ease,
              border-radius 0.55s cubic-bezier(.25, .46, .45, .94);
  -webkit-transform-style: preserve-3d;
  transform-style: preserve-3d;
  /* Var pilotée par card-tilt.js — 0 (repos) → 1 (hover) */
  --tilt: 0;
}
.card:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 6px;
  border-radius: 28px; /* suit le border-radius hover (24→28) */
}
/* ——— Bordure OR MASSIF — PERMANENTE au repos, intensifiée au hover ————
   item-003 (request-2026-05-29-0000) : la bordure or n'est plus seulement
   révélée au hover. Au repos, ring or 1.6px en mask-composite, dégradé
   doux 3-stops `#d4af37 → #f4d77a → #d4af37` à opacité modérée (~0.7)
   avec shimmer 2.8s d'amplitude réduite (pas de pic crème blanc dans
   le dégradé de repos → balayage discret).
   Au hover, le pseudo passe à padding 2.5px, opacité pleine et bascule
   sur la version riche 5-stops avec pic crème blanc → shimmer cinématique. ——— */
.card::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  padding: 1.6px;
  /* Repos : dégradé or chic 3-stops, sans pic crème → amplitude shimmer atténuée */
  background: linear-gradient(135deg,
    #d4af37 0%,
    #f4d77a 50%,
    #d4af37 100%);
  background-size: 300% 300%;
  background-position: 0% 50%;
  -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
          mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
          mask-composite: exclude;
  opacity: 0.7;                                          /* ring or massif visible au repos, modéré */
  animation: card-gold-shimmer 2.8s linear infinite;     /* shimmer permanent — amplitude réduite via le gradient 3-stops */
  transition: opacity 0.5s cubic-bezier(.25, .46, .45, .94),
              padding 0.4s cubic-bezier(.25, .46, .45, .94),
              background 0.5s cubic-bezier(.25, .46, .45, .94);
  pointer-events: none;
  z-index: 4;
}
/* Shimmer keyframes — balayage du dégradé or sur la bordure */
@keyframes card-gold-shimmer {
  0%   { background-position:   0% 50%; }
  100% { background-position: 300% 50%; }
}
/* ——— Spotlight radial suivant la souris — signature premium —————
   --mx / --my sont mis à jour par le RAF du tilt 3D. Au repos, le
   spot reste centré et opacité 0. Au hover, un voile or chaud se
   superpose pour renforcer la sensation « luxe ». ——— */
.card::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 2;
  opacity: 0;
  transition: opacity 0.45s cubic-bezier(.25, .46, .45, .94);
  background:
    radial-gradient(
      circle 320px at var(--mx, 50%) var(--my, 50%),
      rgba(255, 243, 184, 0.22) 0%,
      rgba(255, 243, 184, 0.08) 35%,
      transparent 70%
    ),
    radial-gradient(
      circle 260px at var(--mx, 50%) var(--my, 50%),
      rgba(255, 255, 255, 0.20) 0%,
      rgba(255, 255, 255, 0.06) 35%,
      transparent 70%
    );
  mix-blend-mode: soft-light;
}
@media (hover: hover) {
  .card:hover,
  .card.is-hover {
    border-radius: 28px;                              /* effet « luxueux » 24→28 */
    border-color: transparent;                        /* le dégradé or prend la relève */
    box-shadow:
      0  0 60px      rgba(212, 175,  55, 0.50),       /* GLOW EXTERNE OR — signature premium */
      0  0 120px     rgba(212, 175,  55, 0.18),       /* halo or large + diffus */
      0 30px 80px -16px rgba(109,  77, 255, 0.35),    /* halo violet conservé en profondeur */
      0 20px 60px -12px rgba(0,    0,   0,  0.32),
      0  4px 16px  -4px rgba(0,    0,   0,  0.16);
  }
  .card:hover::before,
  .card.is-hover::before {
    opacity: 1;                                       /* bordure or intensifiée */
    padding: 2.5px;                                   /* renflement cinématique */
    /* Hover : bascule sur le dégradé riche 5-stops avec pic crème blanc →
       amplitude shimmer maximale, sensation hologramme. */
    background: linear-gradient(135deg,
      #d4af37 0%,
      #f4d77a 22%,
      #fff3b8 50%,
      #f4d77a 78%,
      #d4af37 100%);
    background-size: 300% 300%;
    /* L'animation continue (déjà active au repos) — pas besoin de la redéclarer */
  }
  .card:hover::after,
  .card.is-hover::after { opacity: 1; }               /* voile or + spotlight blanc */
}

/* ——— Featured cards — même format 9/16 que les autres cartes ;
   seuls l'eyebrow doré « ✦ » et la typo amplifiée les distinguent ——— */

/* ——— Background layer ———
   item-008 (request-2026-05-29-0000) : on ajoute un clip propre sur
   `.card__bg` (overflow hidden + border-radius hérité) pour éviter que
   l'image agrandie au hover ne déborde des coins arrondis de la carte.
   Le bug venait du contexte `transform-style: preserve-3d` posé sur
   `.card` qui peut casser le clipping border-radius sur les enfants
   transformés (visible surtout sur Safari/WebKit). Pour fiabiliser, on
   déplace en plus le `scale(1.04)` sur `.card__bg img` (l'image est ainsi
   agrandie À L'INTÉRIEUR du clip de `.card__bg`, lui-même non transformé). */
.card__bg {
  position: absolute;
  inset: 0;
  overflow: hidden;
  border-radius: inherit;
  transition: filter 0.8s cubic-bezier(.25, .46, .45, .94);
  /* item-004 : images mises en valeur — saturation + luminosité douces au repos */
  filter: saturate(1.10) brightness(1.05);
  background-size: cover;
  background-position: center;
}
.card:hover .card__bg {
  /* Hover : on pousse encore très légèrement la chaleur sans flasher */
  filter: saturate(1.15) brightness(1.08);
  /* Le scale est désormais porté par `.card__bg img` (voir plus bas) — il est
     ainsi clippé proprement par l'overflow:hidden + border-radius:inherit
     de `.card__bg`, sans déborder des coins arrondis (item-008). */
}

/* Unique gradient per card */
.card__bg--taniere {
  background:
    radial-gradient(ellipse 72% 58% at 38% 28%, rgba(80, 168, 90, 0.52) 0%, transparent 58%),
    radial-gradient(ellipse 42% 32% at 72% 65%, rgba(30, 90, 40, 0.36) 0%, transparent 50%),
    linear-gradient(175deg, #091a0c 0%, #142b1c 45%, #07130a 100%);
}
.card__bg--chatel {
  background:
    radial-gradient(ellipse 67% 52% at 50% 30%, rgba(55, 110, 210, 0.46) 0%, transparent 58%),
    radial-gradient(ellipse 37% 27% at 70% 70%, rgba(20, 50, 120, 0.32) 0%, transparent 50%),
    linear-gradient(175deg, #080f1e 0%, #102038 45%, #050a16 100%);
}
.card__bg--table-ronde {
  background:
    radial-gradient(ellipse 62% 50% at 50% 28%, rgba(190, 135, 42, 0.42) 0%, transparent 58%),
    radial-gradient(ellipse 42% 32% at 30% 70%, rgba(100, 50, 20, 0.32) 0%, transparent 50%),
    linear-gradient(175deg, #180508 0%, #300c18 45%, #0e0306 100%);
}
.card__bg--imagine {
  background:
    radial-gradient(ellipse 67% 57% at 50% 32%, rgba(210, 120, 230, 0.40) 0%, transparent 60%),
    radial-gradient(ellipse 37% 32% at 70% 72%, rgba(100, 40, 160, 0.30) 0%, transparent 50%),
    linear-gradient(175deg, #160826 0%, #2e1150 45%, #0d0619 100%);
}
.card__bg--accesijeux {
  background:
    radial-gradient(ellipse 67% 57% at 50% 30%, rgba(125, 58, 228, 0.52) 0%, transparent 60%),
    radial-gradient(ellipse 37% 32% at 72% 70%, rgba(60, 20, 140, 0.38) 0%, transparent 50%),
    linear-gradient(175deg, #0d0322 0%, #1c0844 45%, #080218 100%);
}
.card__bg--helm {
  background:
    radial-gradient(ellipse 62% 42% at 50% 25%, rgba(190, 190, 210, 0.20) 0%, transparent 55%),
    radial-gradient(ellipse 42% 37% at 35% 65%, rgba(100, 100, 130, 0.16) 0%, transparent 50%),
    linear-gradient(175deg, #06060e 0%, #111124 45%, #030308 100%);
}
.card__bg--unicef {
  background:
    radial-gradient(ellipse 67% 52% at 50% 30%, rgba(0, 160, 220, 0.50) 0%, transparent 58%),
    radial-gradient(ellipse 42% 32% at 30% 70%, rgba(0, 80, 140, 0.34) 0%, transparent 50%),
    linear-gradient(175deg, #010b18 0%, #042b50 45%, #010c1e 100%);
}
.card__bg--arsla {
  background:
    radial-gradient(ellipse 67% 52% at 50% 28%, rgba(40, 80, 160, 0.50) 0%, transparent 58%),
    radial-gradient(ellipse 42% 32% at 70% 65%, rgba(20, 50, 110, 0.34) 0%, transparent 50%),
    linear-gradient(175deg, #060c1a 0%, #0f1e38 45%, #030810 100%);
}
.card__bg--equiaction {
  background:
    radial-gradient(ellipse 67% 52% at 40% 28%, rgba(160, 90, 40, 0.46) 0%, transparent 58%),
    radial-gradient(ellipse 42% 32% at 70% 65%, rgba(80, 40, 15, 0.34) 0%, transparent 50%),
    linear-gradient(175deg, #180a03 0%, #2e1808 45%, #0f0503 100%);
}
.card__bg--psg {
  background:
    radial-gradient(ellipse 62% 47% at 50% 30%, rgba(30, 60, 120, 0.52) 0%, transparent 58%),
    radial-gradient(ellipse 37% 32% at 70% 70%, rgba(180, 20, 30, 0.26) 0%, transparent 50%),
    linear-gradient(175deg, #010516 0%, #05102c 45%, #01030c 100%);
}
.card__bg--swiss-ski {
  background:
    radial-gradient(ellipse 67% 52% at 50% 25%, rgba(160, 200, 240, 0.34) 0%, transparent 58%),
    radial-gradient(ellipse 42% 32% at 30% 70%, rgba(80, 130, 180, 0.28) 0%, transparent 50%),
    linear-gradient(175deg, #050a14 0%, #0c1930 45%, #030610 100%);
}
.card__bg--apel-st-jean {
  background:
    radial-gradient(ellipse 62% 47% at 50% 28%, rgba(100, 60, 200, 0.42) 0%, transparent 58%),
    radial-gradient(ellipse 42% 32% at 30% 68%, rgba(50, 20, 120, 0.30) 0%, transparent 50%),
    linear-gradient(175deg, #0a0618 0%, #1a0e36 45%, #070410 100%);
}
.card__bg--apel-ste-ursule {
  background:
    radial-gradient(ellipse 67% 52% at 50% 30%, rgba(180, 80, 160, 0.42) 0%, transparent 58%),
    radial-gradient(ellipse 42% 32% at 72% 68%, rgba(90, 30, 80, 0.30) 0%, transparent 50%),
    linear-gradient(175deg, #14040c 0%, #2e0c30 45%, #0c0308 100%);
}
.card__bg--ls-vaud {
  background:
    radial-gradient(ellipse 67% 52% at 40% 28%, rgba(30, 100, 180, 0.48) 0%, transparent 58%),
    radial-gradient(ellipse 42% 32% at 70% 65%, rgba(15, 55, 120, 0.34) 0%, transparent 50%),
    linear-gradient(175deg, #000c1c 0%, #031830 45%, #000810 100%);
}
.card__bg--solthis {
  background:
    radial-gradient(ellipse 67% 52% at 50% 28%, rgba(20, 150, 140, 0.44) 0%, transparent 58%),
    radial-gradient(ellipse 42% 32% at 30% 68%, rgba(10, 70, 65, 0.30) 0%, transparent 50%),
    linear-gradient(175deg, #011412 0%, #052c28 45%, #010d0b 100%);
}
.card__bg--mecenat-cc {
  background:
    radial-gradient(ellipse 62% 47% at 50% 28%, rgba(220, 60, 80, 0.44) 0%, transparent 58%),
    radial-gradient(ellipse 40% 32% at 68% 68%, rgba(130, 20, 40, 0.34) 0%, transparent 50%),
    linear-gradient(175deg, #160308 0%, #2e0a14 45%, #0d0103 100%);
}
.card__bg--chu-lille {
  background:
    radial-gradient(ellipse 67% 52% at 50% 25%, rgba(60, 100, 160, 0.42) 0%, transparent 58%),
    radial-gradient(ellipse 42% 32% at 30% 65%, rgba(30, 50, 100, 0.30) 0%, transparent 50%),
    linear-gradient(175deg, #060a14 0%, #0f1a30 45%, #030610 100%);
}
.card__bg--alexis-gruss {
  background:
    radial-gradient(ellipse 67% 52% at 50% 28%, rgba(200, 60, 30, 0.46) 0%, transparent 58%),
    radial-gradient(ellipse 42% 32% at 28% 65%, rgba(180, 140, 20, 0.34) 0%, transparent 50%),
    linear-gradient(175deg, #160402 0%, #2e0b06 45%, #0e0202 100%);
}

/* ——— Screenshot layer — <picture> + lazy loading ——————————————
   Pipeline WebP (AVIF désactivé — non généré côté pipeline,
   les <source type="image/avif"> ont été retirés pour éviter les
   404 qui produisaient des cartes noires sur Chrome) :
     1. Générer <slug>.webp via Puppeteer
     2. Le déposer dans public/screenshots/ — le <source> WebP
        s'active, sinon fallback <img> (PNG/WebP).
   Le gradient CSS reste en background-color fallback (placeholder
   coloré pendant le chargement + si l'image échoue).
—————————————————————————————————————————————————————————————— */
/* Couleurs dominantes — placeholder visible avant chargement */
.card__bg--taniere        { background-color: #0a1b0d; }
.card__bg--chatel         { background-color: #0b1528; }
.card__bg--table-ronde    { background-color: #1a0710; }
.card__bg--imagine        { background-color: #160828; }
.card__bg--accesijeux     { background-color: #0e0428; }
.card__bg--helm           { background-color: #07070f; }
.card__bg--unicef         { background-color: #001a3a; /* bleu profond ONU */ }
.card__bg--arsla          { background-color: #0f1a2e; /* bleu nuit solidarité */ }
.card__bg--equiaction     { background-color: #1a0f0a; /* terre/cheval brun sombre */ }
.card__bg--psg            { background-color: #001535; /* bleu PSG */ }
.card__bg--swiss-ski      { background-color: #0a1520; /* bleu hivernal */ }
.card__bg--apel-st-jean   { background-color: #100820; }
.card__bg--apel-ste-ursule{ background-color: #0d0d1f; }
.card__bg--ls-vaud        { background-color: #001020; /* bleu sport */ }
.card__bg--solthis        { background-color: #001810; /* vert santé */ }
.card__bg--mecenat-cc     { background-color: #1a0010; /* carmin cardiaque */ }
.card__bg--chu-lille      { background-color: #001228; /* bleu hospitalier */ }
.card__bg--alexis-gruss   { background-color: #12050a; /* bordeaux cirque */ }

/* Image positionnée en cover dans le conteneur absolu.
   item-008 : le scale hover est porté ici (plutôt que sur `.card__bg`) pour
   être clippé par l'overflow:hidden + border-radius:inherit du parent →
   plus de débordement aux coins arrondis. */
.card__bg img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center top;
  display: block;
  transform-origin: center;
  transition: transform 0.8s cubic-bezier(.25, .46, .45, .94);
}
@media (hover: hover) {
  .card:hover .card__bg img,
  .card.is-hover .card__bg img {
    transform: scale(1.04);   /* zoom cinématique, clippé proprement par .card__bg */
  }
}

/* ——— Gradient overlay — bottom-only soft scrim (item-004) ———
   Plus de voile noir plein cadre : on garde uniquement un dégradé navy
   très bas, suffisant pour ancrer le texte sans assombrir l'image. */
.card__overlay {
  position: absolute;
  inset: 0;
  background: linear-gradient(
    to top,
    rgba(8, 8, 24, 0.78) 0%,
    rgba(8, 8, 24, 0.42) 20%,
    rgba(8, 8, 24, 0.12) 38%,
    transparent 52%
  );
  z-index: 1;
  opacity: 1;
  transition: opacity 0.65s cubic-bezier(.25, .46, .45, .94);
  pointer-events: none;
}
/* Hover : on allège encore le scrim pour révéler la photo */
@media (hover: hover) {
  .card:hover .card__overlay { opacity: 0.72; }
}

/* ——— Shine sweep — balayage gauche→droite 1.1s, intensifié or+blanc ——— */
.card__shine {
  position: absolute;
  inset: -10%;
  width: 120%;
  height: 120%;
  background: linear-gradient(
    105deg,
    transparent 38%,
    rgba(255, 243, 184, 0.18) 47%,
    rgba(255, 255, 255, 0.42) 50%,
    rgba(255, 243, 184, 0.18) 53%,
    transparent 62%
  );
  transform: translateX(-130%) skewX(-10deg);
  transition: transform 0s;
  pointer-events: none;
  z-index: 2;
  mix-blend-mode: screen;
}
@media (hover: hover) {
  .card:hover .card__shine,
  .card.is-hover .card__shine {
    transform: translateX(130%) skewX(-10deg);
    transition: transform 1.15s cubic-bezier(.25, .46, .45, .94);
  }
}

/* ——— Text content ——— */
/* item-004 : glassmorphism localisé — backdrop-filter blur derrière le texte +
   léger scrim navy translucide pour garantir le contraste WCAG AA sur images
   très claires. Masque dégradé : la zone floutée fond doucement vers le haut
   pour éviter la cassure rectangulaire au-dessus du bloc texte. */
.card__content {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  padding: 36px 28px 30px;
  z-index: 3;
  background: linear-gradient(
    to top,
    rgba(8, 8, 24, 0.40) 0%,
    rgba(8, 8, 24, 0.18) 65%,
    transparent 100%
  );
  -webkit-backdrop-filter: blur(8px) saturate(118%);
  backdrop-filter: blur(8px) saturate(118%);
  -webkit-mask-image: linear-gradient(to top, #000 55%, transparent 100%);
  mask-image: linear-gradient(to top, #000 55%, transparent 100%);
  transition: transform 0.45s cubic-bezier(.25, .46, .45, .94),
              backdrop-filter 0.45s cubic-bezier(.25, .46, .45, .94);
}
@media (hover: hover) {
  .card:hover .card__content,
  .card.is-hover .card__content {
    transform: translateY(-4px);
    transition-delay: 120ms; /* décalage doux = sentiment de profondeur */
  }
}

.card__eyebrow {
  display: block;
  font-family: 'Inter', 'Inter Fallback', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: #e8c66a;                              /* or chaud lisible (WCAG AA sur scrim allégé) */
  margin-bottom: 10px;
  /* item-004 : double shadow — netteté de proximité + halo diffus pour WCAG AA */
  text-shadow:
    0 1px 2px rgba(0, 0, 0, 0.55),
    0 2px 10px rgba(0, 0, 0, 0.45);
  transition: color 0.4s cubic-bezier(.25, .46, .45, .94),
              transform 0.45s cubic-bezier(.25, .46, .45, .94),
              letter-spacing 0.45s cubic-bezier(.25, .46, .45, .94);
}
@media (hover: hover) {
  .card:hover .card__eyebrow,
  .card.is-hover .card__eyebrow {
    color: #f4d77a;                       /* or chaud au hover */
    letter-spacing: 0.22em;               /* respiration éditoriale */
  }
}
.card__title {
  font-family: 'Fraunces', 'Fraunces Fallback', 'Times New Roman', Georgia, serif;
  font-size: clamp(18px, 1.6vw, 27px);
  font-weight: 200;                       /* éditorial ultra-light — rendu magazine */
  line-height: 1.12;
  background: linear-gradient(145deg, #ffffff 30%, rgba(196, 181, 253, 0.88) 100%);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
  font-style: normal;
  letter-spacing: -0.035em;               /* tracking serré haut-de-gamme */
  /* Fallback pour les navigateurs ne supportant pas bg-clip text */
  color: #fff;
  /* item-004 : double halo (proximité + diffus) — WCAG AA garanti sur images
     très claires maintenant que l'overlay noir plein cadre a disparu */
  text-shadow:
    0 1px 3px  rgba(0, 0, 0, 0.65),
    0 2px 16px rgba(0, 0, 0, 0.55),
    0 0 24px   rgba(8, 8, 24, 0.35);
  transition: background 0.5s cubic-bezier(.25, .46, .45, .94),
              text-shadow 0.5s cubic-bezier(.25, .46, .45, .94);
}
/* Titre — bascule vers un dégradé blanc→or chaud au hover */
@media (hover: hover) {
  .card:hover .card__title,
  .card.is-hover .card__title {
    background: linear-gradient(145deg, #ffffff 20%, #fff3b8 60%, #d4af37 100%);
    -webkit-background-clip: text;
    background-clip: text;
    /* Halo or chaud au hover, on garde la proximity-shadow pour la lisibilité */
    text-shadow:
      0 1px 3px  rgba(0, 0, 0, 0.55),
      0 2px 24px rgba(212, 175, 55, 0.35);
  }
}

/* ——— Link arrow — apparition au hover, animation magnétique haut-droite ——— */
.card__arrow {
  position: absolute;
  top: 18px;
  right: 18px;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.12);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border: 1px solid rgba(255, 255, 255, 0.18);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 15px;
  color: #fff;
  opacity: 0;
  transform: scale(0.7) translate(0, -5px);
  transition: opacity 0.35s cubic-bezier(.25, .46, .45, .94),
              transform 0.45s cubic-bezier(.34, 1.56, .64, 1), /* léger overshoot magnétique */
              background 0.35s cubic-bezier(.25, .46, .45, .94),
              border-color 0.35s cubic-bezier(.25, .46, .45, .94),
              color 0.35s cubic-bezier(.25, .46, .45, .94),
              box-shadow 0.45s cubic-bezier(.25, .46, .45, .94);
  z-index: 3;
}
@media (hover: hover) {
  .card:hover .card__arrow,
  .card.is-hover .card__arrow {
    opacity: 1;
    /* Magnétique : translation +6px / -6px (haut-droite) + scale subtle */
    transform: scale(1.05) translate(6px, -6px);
    background: linear-gradient(135deg,
      rgba(255, 243, 184, 0.95) 0%,
      rgba(244, 215, 122, 0.95) 50%,
      rgba(212, 175,  55, 0.95) 100%);
    border-color: rgba(255, 243, 184, 0.85);
    color: #1a1a2e;                                   /* contraste fort sur fond or */
    box-shadow:
      0  0 18px rgba(212, 175, 55, 0.55),
      0  4px 12px rgba(0, 0, 0, 0.25);
  }
}

/* ——— Featured card — badge doré + typo amplifiée ——— */
.card--featured .card__eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 5px 13px 5px 10px;
  border-radius: 999px;
  background: rgba(212, 175, 55, 0.13);
  border: 1px solid rgba(212, 175, 55, 0.30);
  color: var(--gold-subtle);
  font-size: 10px;
  letter-spacing: 0.14em;
  margin-bottom: 14px;
}
.card--featured .card__eyebrow::before {
  content: '✦';
  font-size: 7px;
  color: var(--gold);
  flex-shrink: 0;
}
.card--featured .card__title {
  font-size: clamp(22px, 2.0vw, 32px);
  letter-spacing: -0.03em;
}
.card--featured .card__content {
  padding: 38px 32px;
}

/* ===== STATS ===== */
/* padding réduit ≈ −30 % (160px → clamp 72/9vw/112px) — request-2026-05-29-0000 · item-004 */
.section-stats { padding: clamp(72px, 9vw, 112px) 0; }
.stats-wrapper {
  background: rgba(0, 0, 0, 0.03);
  border: 1px solid var(--surface-border);
  border-radius: 24px;
  overflow: hidden;
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
}
.stats-band {
  background: rgba(0, 0, 0, 0.02);
  border-bottom: 1px solid rgba(212, 175, 55, 0.15);
  /* padding interne compacté (32px → 26px 40px 24px) — pas de trou entre titre & grille */
  padding: 26px 40px 24px;
  text-align: center;
}
/* surtitre rapproché de la grille — réduit le margin-bottom par défaut */
.stats-band .section-title { margin-bottom: 8px; }
.stats-band .section-desc { font-size: 15px; }
.stats-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
}
.stat-item {
  /* padding vertical réduit (36px → 28px) — densité éditoriale 2026 */
  padding: 28px 24px;
  text-align: center;
  border-right: 1px solid var(--surface-border);
  transition: background .2s;
}
.stat-item:last-child { border-right: none; }
.stat-item:hover { background: var(--surface); }
.stat-number {
  font-size: clamp(28px, 4vw, 44px);
  font-weight: 700;
  font-family: 'Inter', 'Inter Fallback', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  background: linear-gradient(135deg, #1a1a2e 0%, #6d4dff 100%);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
  line-height: 1.1;
  margin-bottom: 8px;
}
.stat-label {
  font-size: 13px;
  color: var(--text-muted);
  line-height: 1.45;
}

/* ===== CTA BAND ===== */
/* item-005 (2026-05-29) — section resserrée : 160px → clamp(72,9vw,112) (≈-30 %).
   Halo violet + cercle or conservés via .section-cta::before plus bas. */
.section-cta { padding: clamp(72px, 9vw, 112px) 0; }
.cta-band {
  background: rgba(0, 0, 0, 0.03);
  border: 1px solid var(--surface-border);
  border-radius: 24px;
  padding: 48px 40px 44px;
  text-align: center;
  position: relative;
  overflow: hidden;
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
}
.cta-band::before {
  content: '';
  position: absolute;
  top: -40%;
  left: 50%;
  transform: translateX(-50%);
  width: 600px;
  height: 600px;
  background: radial-gradient(circle, rgba(109,77,255,.10) 0%, transparent 65%);
  pointer-events: none;
}
.cta-band::after {
  content: '';
  position: absolute;
  bottom: -1px;
  left: 15%;
  right: 15%;
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(212,175,55,.35), transparent);
  pointer-events: none;
}
.cta-band .section-label { margin-bottom: 16px; }
.cta-band h2 { font-size: clamp(24px, 3.5vw, 36px); margin-bottom: 10px; position: relative; }
.cta-desc {
  font-size: 16px;
  color: var(--text-muted);
  max-width: 520px;
  margin: 0 auto 26px;
  line-height: 1.65;
  position: relative;
}
.cta-actions { display: flex; gap: 14px; justify-content: center; flex-wrap: wrap; position: relative; }

/* ===== FOOTER ===== */
footer[role="contentinfo"] {
  /* transparent → #f0ede8 over the first 120px — shows body bg, fades to warm cream */
  background: linear-gradient(to bottom, transparent 0%, #f0ede8 120px, #f0ede8 100%);
  /* Safe-area iOS (request-2026-05-29-0047 · item-006) — on ajoute la
     hauteur de la barre home iOS au padding bottom pour que la signature
     « Powered by GoStudio » + les liens légaux ne soient pas mangés par
     la barre home sur iPhone X+. env() vaut 0 hors iOS. */
  padding: 80px 0 calc(52px + env(safe-area-inset-bottom));
  text-align: center;
}
.footer-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0;
}
/* ── Signature de marque ── */
.footer-sig {
  display: inline-flex;
  align-items: center;
  gap: 16px;
  margin-bottom: 14px;
  color: inherit;
  transition: opacity 0.2s;
}
.footer-sig:hover { opacity: 0.72; }
.footer-sig-logo {
  height: clamp(36px, 5.5vw, 60px);
  width: auto;
  display: block;
  margin-bottom: 6px;
}
/* Logo inline dans les titres de section */
.inline-logo {
  height: 0.9em;
  width: auto;
  display: inline-block;
  vertical-align: middle;
  position: relative;
  top: -0.06em;
  margin: 0 0.06em;
}
.footer-sig-tagline {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(0, 0, 0, 0.35);
  margin-bottom: 56px;
}
/* ── Séparateur vertical ── */
.footer-sep {
  width: 1px;
  height: 40px;
  background: linear-gradient(to bottom,
    rgba(0, 0, 0, 0),
    rgba(0, 0, 0, 0.12),
    rgba(0, 0, 0, 0));
  margin: 0 auto 40px;
}
/* ── Liens essentiels ── */
.footer-links {
  display: flex;
  gap: 28px;
  justify-content: center;
  flex-wrap: wrap;
  margin-bottom: 36px;
}
.footer-links a {
  font-size: 13px;
  color: rgba(0, 0, 0, 0.38);
  display: inline-block;    /* requis pour transform */
  transition: color 0.18s ease, transform 0.18s ease;
}
.footer-links a:hover {
  color: rgba(0, 0, 0, 0.80);
  transform: translateX(4px);
}
/* ── Copyright ── */
.footer-copy {
  font-size: 11px;
  color: rgba(0, 0, 0, 0.30);
  letter-spacing: 0.04em;
}

/* ===== SCROLL REVEAL ===== */
.reveal {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity 400ms cubic-bezier(0.4, 0, 0.2, 1),
              transform 400ms cubic-bezier(0.4, 0, 0.2, 1);
  will-change: opacity, transform;
}
.reveal--visible {
  opacity: 1;
  transform: translateY(0);
  will-change: auto;
}
@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; transform: none; transition: none; will-change: auto; }
  .btn-primary,
  .btn-nav-cta,
  .btn-primary::before,
  .btn-nav-cta::before { animation: none !important; }
}

/* ===== ACCESSIBILITÉ ===== */

/* ── Focus ring — couvre tous les éléments interactifs ──
   .card:focus-visible et .filter-pill:focus-visible sont déjà définis plus haut */
nav a:focus-visible,
.btn-secondary:focus-visible,
.btn-primary:focus-visible,
.btn-nav-cta:focus-visible,
.logo:focus-visible,
.footer-links a:focus-visible,
.footer-sig:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 4px;
}

/* ── prefers-reduced-motion — cartes & micro-interactions CSS ──
   (Parallaxe, curseur custom et tilt 3D sont déjà gardés côté JS) */
@media (prefers-reduced-motion: reduce) {
  /* Stopper toutes les transitions des cartes */
  .card,
  .card__bg,
  .card__shine,
  .card__overlay,
  .card__content,
  .card__eyebrow,
  .card__title,
  .card__arrow,
  .card::before,
  .card::after               { transition: none !important; animation: none !important; }
  /* item-003 : on conserve la bordure or permanente même en reduced-motion
     (plus de shimmer, mais le ring or massif reste visible — sensation
     premium permanente). */
  .card::before              { opacity: 0.7 !important; padding: 1.6px !important; }
  .card:hover::before,
  .card.is-hover::before     { opacity: 1 !important; padding: 2.5px !important; }
  /* Neutraliser les transforms hover des cartes */
  .card:hover .card__content { transform: none !important; }
  .card:hover .card__shine   { transform: translateX(-130%) skewX(-10deg) !important; }
  .card:hover .card__bg img  { transform: none !important; transition: none !important; } /* item-008 */
  .card:hover               { border-radius: 24px !important; }
  /* Micro-interactions secondaires */
  .logo-img-header                  { transition: none !important; }
  nav a:not(.btn-nav-cta)::after    { transition: none !important; }
  .footer-links a                   { transition: none !important;
                                      transform: none !important; }
  .filter-pill                      { transition: none !important;
                                      transform: none !important; }
  .footer-sig                       { transition: none !important; }
}

/* ===== STELLAR CURSOR TRAIL (request-2026-05-28-2315 · item-003) =====
   Trainée stellaire derrière la souris : étoiles 4/6 branches + micro-points
   scintillants, dégradé or → blanc nacré → violet, rotation, fade, scale animé,
   glow subtil. PAS de cercle / halo / dot autour du pointeur — le curseur
   système reste visible. Actif uniquement souris desktop + motion autorisé. */
@media (pointer: fine) and (prefers-reduced-motion: no-preference) {

  /* Cycle de vie commun à toutes les particules : spawn (scale 0 → 1.15) puis
     fade-out vers (dx, dy) avec rotation continue r0 → r1 et scale → 0. */
  @keyframes stellar-life {
    0%   { transform: translate(-50%, -50%) rotate(var(--r0, 0deg)) scale(0.25);
           opacity: 0; }
    18%  { transform: translate(-50%, -50%) rotate(var(--r0, 0deg)) scale(1.15);
           opacity: 1; }
    100% { transform: translate(calc(-50% + var(--dx, 0px)), calc(-50% + var(--dy, 0px)))
                     rotate(var(--r1, 360deg)) scale(0);
           opacity: 0; }
  }

  .cursor-sparkle {
    position: fixed;
    width:  var(--sx, 10px);
    height: var(--sx, 10px);
    pointer-events: none;
    z-index: 9998;
    background: radial-gradient(circle,
                  var(--c, #fff8dc) 0%,
                  var(--c, #fff8dc) 28%,
                  rgba(255, 255, 255, 0.55) 55%,
                  transparent 78%);
    filter: drop-shadow(0 0 4px var(--c, #fff8dc)) blur(0.35px);
    transform: translate(-50%, -50%) rotate(var(--r0, 0deg)) scale(0.25);
    opacity: 0;
    will-change: transform, opacity;
    animation: stellar-life forwards cubic-bezier(.22, .61, .36, 1);
  }

  /* Étoile 4 branches — sparkle classique, branches fines */
  .cursor-sparkle--star4 {
    clip-path: polygon(
      50% 0%, 56% 44%, 100% 50%, 56% 56%,
      50% 100%, 44% 56%, 0% 50%, 44% 44%
    );
  }

  /* Étoile 6 branches — sparkle plus dense, type étoile filante */
  .cursor-sparkle--star6 {
    clip-path: polygon(
      50% 0%,   55% 36%, 95% 25%,
      62% 50%,  95% 75%, 55% 64%,
      50% 100%, 45% 64%,  5% 75%,
      38% 50%,   5% 25%, 45% 36%
    );
    filter: drop-shadow(0 0 6px var(--c, #fff8dc)) blur(0.4px);
  }

  /* Micro-point scintillant — petit rond avec glow appuyé */
  .cursor-sparkle--micro {
    border-radius: 50%;
    filter: drop-shadow(0 0 5px var(--c, #fff8dc))
            drop-shadow(0 0 12px var(--c, #fff8dc))
            blur(0.5px);
  }
}

/* ===== RESPONSIVE ===== */

/* ── 1279px : grille cartes → 4 colonnes (desktop intermédiaire) ── */
@media (max-width: 1279px) {
  .card-grid { grid-template-columns: repeat(4, 1fr); gap: 24px; }
}

/* ── 1024px : grille cartes → 2 colonnes + normalisation featured ── */
@media (max-width: 1024px) {
  .card-grid { grid-template-columns: repeat(2, 1fr); gap: 24px; }
  /* Featured cards : annuler span-2 + aspect-ratio auto dès la tablette
     (évite hauteurs incohérentes / débordement sur grille 2 col) */
  .card.card--featured          { grid-row: span 1; aspect-ratio: 9 / 16; }
  .card--featured .card__eyebrow {
    display: block; padding: 0; background: none;
    border: none; font-size: 11px; margin-bottom: 10px;
  }
  .card--featured .card__eyebrow::before { display: none; }
  .card--featured .card__title   { font-size: clamp(18px, 2.2vw, 26px); }
  .card--featured .card__content { padding: 32px 28px; }
}

/* ── 768px : padding container réduit pour tablette portrait ── */
@media (max-width: 768px) {
  /* Safe-area iOS (item-006) — le max() applique l'inset paysage si > 24px */
  .container {
    padding-left: max(24px, env(safe-area-inset-left));
    padding-right: max(24px, env(safe-area-inset-right));
  }
  /* item-005 — CTA finale resserrée dès la tablette (cf. item-004 pour stats) */
  .section-cta { padding: 64px 0; }
  .cta-band { padding: 40px 32px 36px; }
}

/* ── 900px : stats & steps s'adaptent ── */
@media (max-width: 900px) {
  .stats-grid { grid-template-columns: repeat(2, 1fr); }
  /* item-010 (request-2026-05-29-0047) — bordures internes 2×2 passent en or signature
     (rgba(212,175,55,.20)) au lieu du gris neutre var(--surface-border). */
  .stat-item { border-right-color: rgba(212, 175, 55, 0.20); }
  .stat-item:nth-child(2) { border-right: none; }
  .stat-item:nth-child(3) { border-top: 1px solid rgba(212, 175, 55, 0.20); }
  .stat-item:nth-child(4) { border-top: 1px solid rgba(212, 175, 55, 0.20); }
}

/* ── 640px : mobile ── */
@media (max-width: 640px) {
  /* Safe-area iOS (item-006) — l'inset paysage iPhone Pro vaut ≈ 47-50 px */
  .container {
    padding-left: max(20px, env(safe-area-inset-left));
    padding-right: max(20px, env(safe-area-inset-right));
  }
  /* item-015 (request-2026-05-29-0047) — rythme mobile affiné :
     gap 20 → 24 px pour mieux séparer chaque tuile (combiné à l'aspect-ratio
     réduit de l'item-003, on garde une densité confortable sans tassement).
     content-visibility: auto + contain-intrinsic-size sur les .card non-featured
     → Chrome rasterise paresseusement les cartes hors viewport (gain perf
     rendering mobile notable sur les grandes listes). Featured cards exclues
     car above-the-fold et toujours visibles au premier paint. */
  .card-grid { grid-template-columns: 1fr; gap: 24px; }
  .card:not(.card--featured) {
    content-visibility: auto;
    contain-intrinsic-size: auto 470px;
  }
  .stats-band { padding: 22px 20px 20px; }
  /* item-010 (request-2026-05-29-0047) — hiérarchie valeur ↔ label rééquilibrée :
     padding cellule 22×16 → 24×12 (un peu plus d'air vertical pour aérer la lecture),
     en-tête de section plus discret (clamp 20-26 vs hérité ~28), .stat-number en
     vedette (clamp 32-40, ~33 px sur 375 px → vraie « claque » du chiffre),
     .stat-label volontairement effacé (12 px, opacity 0.78). */
  .stats-band .section-title { font-size: clamp(20px, 5.5vw, 26px); }
  .stat-item { padding: 24px 12px; }
  .stat-number { font-size: clamp(32px, 9vw, 40px); }
  .stat-label { font-size: 12px; line-height: 1.35; opacity: 0.78; }
  /* item-008 (request-2026-05-29-0047) — cta-band mobile resserré (36×22×32 → 28×20×24),
     pendant des paddings de sections compactés en-dessous. */
  .cta-band { padding: 28px 20px 24px; }
  /* item-004 (request-2026-05-29-0047) — CTA finale : boutons pleine largeur
     empilés sur mobile. Côte-à-côte ils tombaient à ~150 px de large chacun
     (peu engageant, zone tactile sous-dimensionnée). On passe en colonne avec
     boutons width:100%, padding plus généreux (16/22) et min-height 52 px pour
     atteindre la cible AAA WCAG 2.2 — ressenti app mobile premium, hiérarchie
     primaire→secondaire préservée par l'ordre du DOM. */
  .cta-actions { flex-direction: column; align-items: stretch; gap: 12px; }
  .cta-actions .btn-primary,
  .cta-actions .btn-secondary {
    width: 100%;
    justify-content: center;
    padding: 16px 22px;
    min-height: 52px;
  }
  /* NOTE: la règle `nav a:not(.btn-nav-cta) { display: none; }` qui masquait
     Exemples + Contact sans alternative a été retirée (item-001 / request
     -2026-05-29-0047). La navigation passe désormais par un menu hamburger
     CSS-only qui ouvre un drawer plein écran — cf. bloc « MOBILE HAMBURGER
     MENU » en bas de fichier. */
  .footer-sig-logo { height: clamp(28px, 8vw, 44px); }
  /* item-014 (request-2026-05-29-0047) — Footer mobile : hiérarchie et respiration.
     Le footer empilait sur mobile : logo + tagline + séparateur + liens + copyright
     + powered-by. Cumul des margins (14/56/40/40/36) ≈ 170 px de hauteur pour très
     peu d'info → disproportionné. On rééquilibre 5 éléments :
       - `footer[role="contentinfo"]` : 80×0×52 → 56×0×32 (+ safe-area bottom).
       - `.footer-sig-tagline`        : margin 14/56 → 14/32, font 11 → 10,
                                        letter-spacing 0.18em → 0.14em (plus serré
                                        pour compenser la baisse de taille).
       - `.footer-sep`                : height 40 + margin 0/40 → height 24 + 0/24
                                        (séparateur visuel plus discret cohérent
                                         avec la densité globale).
       - `.footer-links`              : gap 28 → 18, font 13 → 12, `flex-direction`
                                        reste `row` (3 liens courts tiennent même
                                        sur 360 px). Le wrap par flex-wrap reste
                                        actif en safety net (très petits écrans).
       - `.footer-copy`               : font 11 → 10.
     `.footer-sig-logo` (déjà clamp 28-44) conservé tel quel (cf. spec).
     Le touch-target des liens (44 px via padding+line-height, item-007) reste
     intact — les overrides agissent uniquement sur l'écriture et la respiration,
     pas sur la hauteur cliquable. */
  footer[role="contentinfo"] {
    padding: 56px 0 calc(32px + env(safe-area-inset-bottom));
  }
  .footer-sig-tagline {
    margin-bottom: 32px;
    font-size: 10px;
    letter-spacing: 0.14em;
  }
  .footer-sep {
    height: 24px;
    margin: 0 auto 24px;
  }
  .footer-links {
    gap: 18px;
    font-size: 12px;
  }
  .footer-links a {
    font-size: 12px;
  }
  .footer-copy {
    font-size: 10px;
  }
  /* item-008 (request-2026-05-29-0047) — densité éditoriale type Instagram/Linear/Stripe
     mobile : sections séparées par 40–48 px (vs 64–80 px précédemment). Le hero étant
     supprimé, la grille démarre direct → on n'a plus besoin d'air en haut.
       - tombolas    80 → 48 (item-004/005 → item-008)
       - stats       64 → 48
       - cta         64 → 52 (un cran de plus pour ancrer la dernière section visuelle)
     section-header passe aussi à 32 px (vs 48 px global) pour resserrer titre + desc
     + filter-pills sur mobile. */
  .section-header { margin-bottom: 32px; }
  .section-tombolas { padding: 48px 0; }
  .section-stats { padding: 48px 0; }
  .section-cta { padding: 52px 0; }
  /* item-003 (request-2026-05-29-0047) — aspect-ratio mobile portrait-friendly :
     en grille 1-col à 375 px de large, la version desktop 9/16 produisait ~666 px
     de hauteur par tuile (capée par max-height clamp), soit 1 carte par viewport
     et un scroll interminable. On bascule à 4/5 pour TOUTES les tuiles (incluant
     featured) → gain ~1.5 carte par viewport sans cropper les mockups (object-
     position center top conservé hérité de .card__bg img).
     ─── request-2026-05-29-XXXX (fix featured non centrées / plus petites) ───
     Avant : featured = 3/4 (plus haut que 4/5) → height calculée dépassait
     `max-height: clamp(420, 60vh, 720)` sur iPhone Mini/SE/standard (60vh
     ≈ 400 px sur 667 px de viewport). Lorsque la height est clampée, la
     règle `aspect-ratio` recalcule la WIDTH = height × 3/4, ce qui rétrécit
     la carte sous la largeur de track → `justify-self: stretch` ne stretch
     plus (l'item a déjà une width résolue plus petite) → 1ère carte tombe
     en alignement « start » (à gauche) et apparaît plus petite. Fix :
     (a) unifier l'aspect-ratio sur 4/5 (parité visuelle parfaite avec les
         16 cartes standard) → hauteur calculée = width × 5/4 = 419 px à
         375 px de viewport, sous la borne 420 du clamp, plus de clamping.
     (b) lever `max-height` sur mobile : en grille 1-col, l'aspect-ratio
         pilote seul la hauteur. Le clamp était utile en desktop (multi-col)
         pour éviter des cartes immenses, pas en mono-col mobile. */
  .card { aspect-ratio: 4 / 5; max-height: none; }
  /* Featured cards → aspect uniforme 4/5 (vs 3/4 avant fix) pour parité mobile */
  .card.card--featured { grid-row: span 1; aspect-ratio: 4 / 5; }
  .card--featured .card__eyebrow { display: block; padding: 0; background: none; border: none; font-size: 11px; margin-bottom: 10px; }
  .card--featured .card__eyebrow::before { display: none; }
  .card--featured .card__title { font-size: clamp(18px, 5vw, 24px); }
  .card--featured .card__content { padding: 32px 28px; }
  /* item-005 (request-2026-05-29-0047) — zones tactiles agrandies sur mobile :
     desktop 7×20 (~28 px de haut) passait sous la cible Apple HIG. On monte
     à min-height 36 px + padding 9×22 → hauteur effective ≈ 38 px (encore
     sous 44 px AAA, mais nettement plus confortable au pouce sans casser
     la hiérarchie visuelle d'une rangée de pills filtre). */
  .filter-pill { min-height: 36px; padding: 9px 22px; }
  /* item-009 (request-2026-05-29-0047) — raffinage typo des .section-title mobile :
     - line-height 1.08 → 1.18 : le h1 « Un aperçu de la communauté des tombolas
       solidaires [logo] » wrap sur 3 lignes en mobile ; à 1.08, les descendantes
       (g, p, q) collaient la ligne suivante (effet « titres écrasés »). 1.18 rend
       le tracking vertical respirant sans casser la densité éditoriale.
     - letter-spacing -0.038em → -0.024em : aux petites tailles, un tracking aussi
       serré ferme les lettres en Fraunces light → on relâche d'un cran (toujours
       en négatif pour garder l'allure haut-de-gamme).
     - .inline-logo : height 0.9em → 0.78em + top -0.06em → -0.04em : le logo posé
       inline dans le h1 doit s'asseoir plus bas sur la baseline de Fraunces light
       pour éviter qu'il « saute » par-dessus la ligne quand le titre wrap autour. */
  .section-title { line-height: 1.18; letter-spacing: -0.024em; }
  .inline-logo { height: 0.78em; top: -0.04em; }
}

/* ===== MODAL — Premium detail dialog (R28 / a11y dialog pattern) =============
   Full-screen modal opened on card click by `modal-detail.<sha10>.gostudio.js`.
   - role="dialog" + aria-modal="true" + Esc + backdrop click + close button
   - Panel transitions in via opacity + translateY; backdrop in via opacity+blur
   - Sticky CTA bar at the bottom — always visible on tall content (scrollable
     body region above keeps gallery + context within reach)
   - 3 "shot" frames per modal : hero photo + selector mock + lot/prize mock,
     all branded via inline --brand / --accent CSS vars passed by the JS module
   - Locks body scroll via html.has-modal { overflow: hidden } below
============================================================================== */
html.has-modal { overflow: hidden; }
.modal[hidden] { display: none; }
.modal {
  position: fixed;
  inset: 0;
  z-index: 9990;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  opacity: 0;
  transition: opacity 240ms cubic-bezier(.25,.46,.45,.94);
}
.modal.is-open { opacity: 1; }
.modal__backdrop {
  position: absolute;
  inset: 0;
  background: radial-gradient(ellipse at 50% 30%, rgba(26, 26, 46, 0.72) 0%, rgba(10, 10, 22, 0.86) 100%);
  -webkit-backdrop-filter: blur(18px) saturate(140%);
  backdrop-filter: blur(18px) saturate(140%);
  cursor: pointer;
}
.modal__panel {
  --brand:  #6d4dff;
  --accent: #d4af37;
  position: relative;
  width: min(1080px, 100%);
  max-height: calc(100vh - 48px);
  background: linear-gradient(160deg, #ffffff 0%, #fafaf6 100%);
  border-radius: 24px;
  box-shadow:
    0  40px 120px -20px rgba(109, 77, 255, 0.45),
    0  24px  60px -12px rgba(0, 0, 0, 0.40),
    0   2px  10px  -2px rgba(0, 0, 0, 0.20);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  transform: translateY(24px) scale(0.96);
  opacity: 0;
  transition: transform 360ms cubic-bezier(.16, 1, 0.3, 1),
              opacity 240ms cubic-bezier(.25, .46, .45, .94);
}
.modal.is-open .modal__panel {
  transform: translateY(0) scale(1);
  opacity: 1;
}
/* Gold border accent — dégradé violet→or signature */
.modal__panel::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  padding: 1.5px;
  background: linear-gradient(135deg,
    rgba(109, 77, 255, 0.55) 0%,
    rgba(212, 175, 55, 0.62) 50%,
    rgba(109, 77, 255, 0.55) 100%);
  -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
          mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
          mask-composite: exclude;
  pointer-events: none;
  z-index: 5;
}
.modal__close {
  position: absolute;
  top: 14px;
  right: 14px;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  border: 1px solid rgba(0, 0, 0, 0.10);
  background: rgba(255, 255, 255, 0.85);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  color: var(--text);
  cursor: pointer;
  z-index: 6;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: transform .18s, background .15s, border-color .15s;
}
.modal__close:hover {
  background: #ffffff;
  border-color: rgba(0, 0, 0, 0.22);
  transform: scale(1.06) rotate(90deg);
}
.modal__close:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 3px;
}

/* Drag affordance — visible only on mobile (≤ 640px) via the @media block
   below. Sits at the top of the panel, in the safe-area zone on notched
   iPhones, hints that the panel can be pulled down to close. The actual
   gesture is captured by modal-detail.gostudio.js at .modal__panel level. */
.modal__drag-handle { display: none; }

.modal__header {
  padding: 28px 36px 18px;
  border-bottom: 1px solid rgba(0, 0, 0, 0.06);
  flex-shrink: 0;
}
.modal__org { display: flex; align-items: center; gap: 16px; }
.modal__org-avatar {
  --brand: #6d4dff;
  --accent: #d4af37;
  width: 56px;
  height: 56px;
  border-radius: 16px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'Fraunces', 'Fraunces Fallback', 'Times New Roman', Georgia, serif;
  font-weight: 600;
  font-size: 26px;
  color: #fff;
  background: linear-gradient(135deg, var(--brand) 0%, var(--accent) 100%);
  box-shadow:
    0 10px 30px -8px color-mix(in srgb, var(--brand) 65%, transparent),
    inset 0 1px 0 rgba(255, 255, 255, 0.25);
  flex-shrink: 0;
  text-transform: uppercase;
}
.modal__org-meta { min-width: 0; }
.modal__eyebrow {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: #7d5a0a;
  margin-bottom: 4px;
}
.modal__title {
  font-family: 'Fraunces', 'Fraunces Fallback', 'Times New Roman', Georgia, serif;
  font-weight: 500;
  font-size: clamp(22px, 2.6vw, 30px);
  letter-spacing: -0.025em;
  line-height: 1.15;
  color: var(--text);
  margin: 0 0 4px;
}
.modal__op {
  font-size: 14px;
  color: var(--text-muted);
  line-height: 1.4;
}

.modal__body {
  padding: 24px 36px 16px;
  overflow-y: auto;
  flex: 1 1 auto;
  -webkit-overflow-scrolling: touch;
}

.modal__gallery {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 18px;
  margin-bottom: 28px;
}
.modal__shot { margin: 0; }
.modal__shot-frame {
  --brand:  #6d4dff;
  --accent: #d4af37;
  position: relative;
  aspect-ratio: 9 / 16;
  border-radius: 22px;
  background: #0e0e1a;
  overflow: hidden;
  box-shadow:
    0 12px 30px -10px rgba(0, 0, 0, 0.40),
    0  2px  8px  -2px rgba(0, 0, 0, 0.18),
    inset 0 0 0 2px rgba(0, 0, 0, 0.85);
  border: 1px solid rgba(0, 0, 0, 0.10);
}
.modal__shot-notch {
  position: absolute;
  top: 8px;
  left: 50%;
  transform: translateX(-50%);
  width: 70px;
  height: 14px;
  background: #0e0e1a;
  border-radius: 0 0 12px 12px;
  z-index: 3;
}
.modal__shot-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center top;
  display: block;
}
.modal__shot-img--fallback { background: var(--brand); }
.modal__shot-caption {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  padding: 18px 14px 12px;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.72) 0%, transparent 100%);
  color: #fff;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  z-index: 3;
  display: flex;
  align-items: center;
  gap: 8px;
}
.modal__shot-caption span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--gold);
  color: #1a1a2e;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0;
}

/* ── In-modal SVG/CSS mockups (shots 2 & 3) ── */
.modal__mock {
  position: absolute;
  inset: 22px 12px 38px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  font-family: 'Inter', 'Inter Fallback', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  color: #1a1a2e;
}
.modal__mock--selector {
  background: linear-gradient(160deg, #ffffff 0%, #f4f2ef 100%);
  border-radius: 14px;
  padding: 14px 12px;
  align-items: stretch;
}
.mock__top { display: flex; align-items: center; gap: 8px; }
.mock__avatar {
  width: 28px;
  height: 28px;
  border-radius: 8px;
  background: linear-gradient(135deg, var(--brand) 0%, var(--accent) 100%);
  color: #fff;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 13px;
  text-transform: uppercase;
  flex-shrink: 0;
}
.mock__org {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: #1a1a2e;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.mock__h {
  font-family: 'Fraunces', 'Fraunces Fallback', 'Times New Roman', Georgia, serif;
  font-weight: 500;
  font-size: 14px;
  color: #1a1a2e;
  margin-top: 4px;
}
.mock__counter {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
  background: #fafaf8;
  border: 1px solid rgba(0, 0, 0, 0.08);
  border-radius: 10px;
  padding: 6px;
  margin-top: 2px;
}
.mock__btn {
  width: 22px;
  height: 22px;
  border-radius: 6px;
  background: var(--brand);
  color: #fff;
  border: none;
  font-weight: 700;
  font-size: 12px;
  line-height: 1;
}
.mock__qty {
  font-family: 'Fraunces', 'Fraunces Fallback', 'Times New Roman', Georgia, serif;
  font-weight: 600;
  font-size: 18px;
}
.mock__price {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  font-size: 11px;
  color: var(--text-muted);
}
.mock__price strong {
  font-family: 'Fraunces', 'Fraunces Fallback', 'Times New Roman', Georgia, serif;
  color: var(--text);
  font-size: 16px;
  font-weight: 600;
}
.mock__cta {
  text-align: center;
  background: linear-gradient(135deg, var(--brand) 0%, var(--accent) 100%);
  color: #fff;
  border-radius: 10px;
  padding: 9px 8px;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.02em;
  box-shadow: 0 6px 18px -4px color-mix(in srgb, var(--brand) 55%, transparent);
}
.mock__cta--ghost {
  background: transparent;
  color: var(--brand);
  border: 1.5px solid color-mix(in srgb, var(--brand) 35%, transparent);
  box-shadow: none;
}
.mock__chip {
  align-self: center;
  font-size: 9.5px;
  letter-spacing: 0.08em;
  color: color-mix(in srgb, var(--accent) 65%, #1a1a2e);
  text-transform: uppercase;
  font-weight: 600;
}
.modal__mock--lot {
  background: linear-gradient(160deg, #ffffff 0%, #f4f2ef 100%);
  border-radius: 14px;
  padding: 0 12px 14px;
  overflow: hidden;
}
.mock__lot-img {
  position: relative;
  margin: 0 -12px;
  aspect-ratio: 5 / 3;
  background: #0a0a16;
  overflow: hidden;
}
.mock__lot-img svg { width: 100%; height: 100%; display: block; }
.mock__lot-tag {
  position: absolute;
  top: 8px;
  left: 8px;
  background: var(--accent);
  color: #1a1a2e;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  padding: 3px 7px;
  border-radius: 6px;
}
.mock__lot-title {
  font-family: 'Fraunces', 'Fraunces Fallback', 'Times New Roman', Georgia, serif;
  font-weight: 500;
  font-size: 14px;
  color: var(--text);
  margin-top: 10px;
}
.mock__lot-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  font-size: 10.5px;
  color: var(--text-muted);
  padding: 4px 0;
  border-bottom: 1px dashed rgba(0, 0, 0, 0.08);
}
.mock__lot-row strong {
  color: var(--text);
  font-weight: 600;
  font-family: 'Fraunces', 'Fraunces Fallback', 'Times New Roman', Georgia, serif;
}

.modal__context {
  background: rgba(212, 175, 55, 0.05);
  border: 1px solid rgba(212, 175, 55, 0.18);
  border-radius: 16px;
  padding: 20px 24px;
}
.modal__context-eyebrow {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: #7d5a0a;
  margin-bottom: 8px;
}
.modal__context-body {
  font-size: 15px;
  line-height: 1.65;
  color: var(--text);
}

.modal__cta-bar {
  flex-shrink: 0;
  /* Safe-area iOS (request-2026-05-29-0047 · item-006) — sticky CTA bar :
     sur iPhone Pro en portrait, sans cette protection, le CTA passe
     sous la barre home et devient non-tappable. max() garde le padding
     natif sur desktop et bascule sur la zone safe-area dès qu'elle
     dépasse (≈34 px sur iPhone 14/15/16 Pro). */
  padding: 16px 24px max(18px, env(safe-area-inset-bottom));
  background: linear-gradient(to top, #ffffff 65%, rgba(255, 255, 255, 0));
  border-top: 1px solid rgba(0, 0, 0, 0.06);
  display: flex;
  justify-content: center;
}
.modal__cta {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 15px 32px;
  border-radius: 14px;
  background: linear-gradient(135deg, var(--brand, #6d4dff) 0%, var(--accent, #d4af37) 100%);
  color: #fff !important;
  font-weight: 700;
  font-size: 16px;
  letter-spacing: 0.01em;
  box-shadow:
    0 14px 36px -10px color-mix(in srgb, var(--brand, #6d4dff) 60%, transparent),
    0  4px 12px  -2px rgba(0, 0, 0, 0.18);
  transition: transform .22s cubic-bezier(.25,.46,.45,.94), box-shadow .25s, filter .2s;
  position: relative;
  overflow: hidden;
}
.modal__cta:hover {
  transform: scale(1.045);
  filter: brightness(1.06);
  box-shadow:
    0 18px 44px -10px color-mix(in srgb, var(--brand, #6d4dff) 70%, transparent),
    0  6px 16px  -2px rgba(0, 0, 0, 0.22);
}
.modal__cta:focus-visible {
  outline: 2px solid #fff;
  outline-offset: 3px;
}
.modal__cta-arrow {
  font-size: 18px;
  transition: transform .2s ease;
}
.modal__cta:hover .modal__cta-arrow { transform: translate(2px, -2px); }

/* ── Mobile / tablet adjustments ── */
@media (max-width: 820px) {
  .modal { padding: 12px; }
  .modal__panel { max-height: calc(100vh - 24px); border-radius: 18px; }
  .modal__header { padding: 22px 22px 14px; }
  .modal__body { padding: 18px 22px 12px; }
  .modal__gallery { grid-template-columns: repeat(3, 1fr); gap: 10px; }
  .modal__shot-frame { border-radius: 16px; }
  .modal__org-avatar { width: 48px; height: 48px; font-size: 22px; }
  .modal__context { padding: 16px 18px; }
  .modal__context-body { font-size: 14px; }
  .modal__cta-bar { padding: 12px 18px max(14px, env(safe-area-inset-bottom)); }
  .modal__cta { padding: 13px 22px; font-size: 14.5px; width: 100%; justify-content: center; }
}

/* ── Mobile fullscreen + swipe-to-close (request-2026-05-29-0047 · item-011) ──
   Sur ≤ 640 px, le modal détail passe en plein écran (padding 0, coins droits,
   100dvh) : les 12 px de padding hérités de la règle 820 px ne servent à rien
   sur petit écran et coûtent de la surface utile. Affordance « poignée drag »
   visible en haut du panel (40×4 px). Bouton fermeture remonté sous le notch
   via env(safe-area-inset-top). Entrée du panel modifiée en « sheet » qui
   monte du bas (translateY 100% → 0) pour matcher le pattern attendu mobile
   (Apollo, Instagram, native iOS sheets). Le geste swipe-down-to-close est
   gardé en JS (modal-detail.gostudio.js, gated sur pointer:coarse).            */
@media (max-width: 640px) {
  .modal { padding: 0; }
  .modal__panel {
    width: 100%;
    max-width: 100%;
    height: 100vh;             /* fallback */
    height: 100dvh;            /* iOS dynamic viewport — évite la barre home  */
    max-height: 100vh;
    max-height: 100dvh;
    border-radius: 0;
    /* Sheet entry : panneau qui monte du bas plutôt que fade + scale ; plus
       cohérent visuellement avec le geste swipe-down-to-close. */
    transform: translateY(100%);
  }
  .modal.is-open .modal__panel {
    transform: translateY(0);
  }
  /* Gold border accent : sans intérêt sur fullscreen (ligne sur les bords
     de l'écran) → masqué pour rester sobre. */
  .modal__panel::before { display: none; }

  /* Poignée drag — sits dans la safe-area-top sur iPhone à notch ; sur les
     non-notched, padding-top = 10 px par défaut (max(10, 0)). Le `::after`
     porte la barre visible 40×4 px arrondie. `touch-action: none` empêche
     le navigateur de récupérer le geste avant le module JS. */
  .modal__drag-handle {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    padding-top: max(10px, env(safe-area-inset-top));
    padding-bottom: 8px;
    flex-shrink: 0;
    z-index: 7;
    cursor: grab;
    touch-action: none;
    -webkit-tap-highlight-color: transparent;
  }
  .modal__drag-handle::after {
    content: '';
    width: 40px;
    height: 4px;
    border-radius: 999px;
    background: rgba(26, 26, 46, 0.18);
    transition: background-color .15s ease, transform .15s ease;
  }
  .modal__drag-handle:active::after {
    background: rgba(26, 26, 46, 0.32);
    transform: scaleX(0.85);
  }

  /* Bouton fermeture — respecte la Dynamic Island / notch iPhone : valeur
     dynamique calée à 14 px sur Android & iPhone non-notched, ≈ 47 px sur
     iPhone 14/15/16 Pro portrait. Pas de chevauchement horizontal avec la
     poignée drag (centrée). */
  .modal__close {
    top: max(14px, env(safe-area-inset-top));
  }

  /* Header : la poignée drag couvre déjà la zone safe-area-top, le header
     peut se rapprocher (− 12 px en haut) pour densifier le rendu mobile. */
  .modal__header { padding-top: 10px; }
}

@media (max-width: 520px) {
  .modal__gallery { grid-template-columns: 1fr; gap: 14px; }
  .modal__shot-frame { aspect-ratio: 16 / 10; }
  .modal__shot-img { object-position: center 25%; }
  .modal__title { font-size: 20px; }
}
@media (prefers-reduced-motion: reduce) {
  .modal,
  .modal__panel,
  .modal__cta,
  .modal__cta-arrow,
  .modal__close { transition: none !important; }
  .modal.is-open .modal__panel { transform: none; }
}

/* ===== HUB FX — html.fx-static / html.fx-light (§ 6.2 / R28) =================
   Refonte request-2026-05-29-0047 · item-002 : la garde monolithique
   `html.fx-static` (qui coupait TOUS les effets dès `pointer:coarse` ou
   `max-width:767px`) est découpée en deux modes par le bootstrap inline :

     - html.fx-static  ←  prefers-reduced-motion: reduce  → TOUT coupé
                          (et également posé sur mobile/coarse pour
                          conserver les bail JS existants sans toucher
                          aux 8 modules FX hashés — voir bootstrap)
     - html.fx-light   ←  mobile/coarse SANS reduced-motion → seuls les
                          effets coûteux (tilt 3D, shine sweep, parallax,
                          sparkle, mesh-drift, count-up) restent OFF ;
                          les effets CSS GPU-cheap (bordure or shimmer,
                          glow or de repos, dégradés titre/stat, halos
                          de section, modal animation) REPRENNENT vie.
     - html.fx-motion  ←  desktop sans reduced-motion → tout activé.

   Les modules FX JS continuent à bail sur la classe `fx-static` (présente
   dans les deux cas restrictifs) → aucune recalcul SRI sur les 8 modules.
   Les règles de neutralisation ci-dessous utilisent donc :
     - `html.fx-static .X`                  → cible RM + mobile (effet coûteux off)
     - `html.fx-static:not(.fx-light) .X`   → cible RM uniquement (effet cheap
                                              préservé sur mobile)                  */

/* .reveal — JS bail sous fx-static (RM + mobile) → fallback : éléments
   visibles immédiatement sans animation pour ne pas rester invisibles. */
html.fx-static .reveal {
  opacity: 1 !important;
  transform: none !important;
  transition: none !important;
  will-change: auto !important;
}
/* Cartes — blanket transitions/animations off uniquement en reduced-motion ;
   sur mobile (fx-light), on conserve les transitions/animations CSS GPU-cheap
   (shimmer or permanent .card::before notamment). */
html.fx-static:not(.fx-light) .card,
html.fx-static:not(.fx-light) .card__bg,
html.fx-static:not(.fx-light) .card__shine,
html.fx-static:not(.fx-light) .card__overlay,
html.fx-static:not(.fx-light) .card__content,
html.fx-static:not(.fx-light) .card::before,
html.fx-static:not(.fx-light) .card::after {
  transition: none !important;
  animation: none !important;
  will-change: auto !important;
}
/* Tilt 3D + hover scale image + shine sweep : COÛTEUX → off sur mobile ET RM. */
html.fx-static .card:hover .card__bg,
html.fx-static .card.is-hover .card__bg            { transform: none !important; filter: none !important; }
/* item-008 : le scale hover est désormais sur l'image — on le neutralise ici aussi en fx-static. */
html.fx-static .card:hover .card__bg img,
html.fx-static .card.is-hover .card__bg img       { transform: none !important; }
html.fx-static .card:hover .card__content,
html.fx-static .card.is-hover .card__content      { transform: none !important; }
html.fx-static .card:hover .card__shine,
html.fx-static .card.is-hover .card__shine        { transform: translateX(-130%) skewX(-10deg) !important; transition: none !important; }
html.fx-static .card:hover .card__overlay,
html.fx-static .card.is-hover .card__overlay     { opacity: 1 !important; }
/* item-003 : la bordure or permanente + shimmer est CHEAP (GPU-only) → on la
   conserve sur mobile. Seul le mode reduced-motion (fx-static SANS fx-light)
   coupe l'animation shimmer. Le spotlight ::after reste off partout (couplé tilt). */
html.fx-static:not(.fx-light) .card::before                  { opacity: 0.7 !important; padding: 1.6px !important; animation: none !important; }
html.fx-static:not(.fx-light) .card:hover::before,
html.fx-static:not(.fx-light) .card.is-hover::before         { opacity: 1 !important; padding: 2.5px !important; }
html.fx-static:not(.fx-light) .card::after                   { opacity: 0 !important; animation: none !important; }
/* Cinématique hover (border-radius 28 + gold glow 60px/120px) : CHEAP → mobile
   garde l'intensification au tap ; seul reduced-motion neutralise. */
html.fx-static:not(.fx-light) .card:hover,
html.fx-static:not(.fx-light) .card.is-hover {
  border-radius: 24px !important;
  box-shadow:
    0  0 24px      rgba(212, 175, 55, 0.18),
    0 12px 50px -10px rgba(109, 77, 255, 0.18),
    0  8px 40px  -8px rgba(0, 0, 0, 0.18),
    0  2px  8px  -2px rgba(0, 0, 0, 0.10) !important;
}
/* Titre & eyebrow gradient or au hover (cheap CSS gradient) : kept on mobile.  */
html.fx-static:not(.fx-light) .card:hover .card__title,
html.fx-static:not(.fx-light) .card.is-hover .card__title {
  background: linear-gradient(145deg, #ffffff 30%, rgba(196, 181, 253, 0.88) 100%) !important;
  -webkit-background-clip: text;
          background-clip: text;
  text-shadow:
    0 1px 3px  rgba(0, 0, 0, 0.65),
    0 2px 16px rgba(0, 0, 0, 0.55),
    0 0 24px   rgba(8, 8, 24, 0.35) !important;
}
html.fx-static:not(.fx-light) .card:hover .card__eyebrow,
html.fx-static:not(.fx-light) .card.is-hover .card__eyebrow {
  color: #e8c66a !important;
  letter-spacing: 0.18em !important;
}
/* Flèche or magnétique (cheap CSS transform + bg) : kept on mobile.            */
html.fx-static:not(.fx-light) .card:hover .card__arrow,
html.fx-static:not(.fx-light) .card.is-hover .card__arrow {
  transform: scale(1) translate(0, 0) !important;
  background: rgba(255, 255, 255, 0.12) !important;
  border-color: rgba(255, 255, 255, 0.18) !important;
  color: #fff !important;
  box-shadow: none !important;
}
/* CTAs — animations infinies (border-rotate, halo or, etc.) : cheap CSS → kept mobile. */
html.fx-static:not(.fx-light) .btn-primary,
html.fx-static:not(.fx-light) .btn-primary::before,
html.fx-static:not(.fx-light) .btn-nav-cta,
html.fx-static:not(.fx-light) .btn-nav-cta::before {
  animation: none !important;
}
/* Micro-interactions secondaires (logo, nav-underline, footer, pills) : cheap → kept mobile. */
html.fx-static:not(.fx-light) .logo-img-header,
html.fx-static:not(.fx-light) nav a:not(.btn-nav-cta)::after,
html.fx-static:not(.fx-light) .footer-links a,
html.fx-static:not(.fx-light) .filter-pill,
html.fx-static:not(.fx-light) .footer-sig {
  transition: none !important;
  transform: none !important;
}
/* Backdrop-filter GPU-coûteux : neutralisé sur mobile ET RM (sauf header[role=banner]
   qui n'est pas ciblé ici → voile crème + ligne or préservés sur mobile).         */
html.fx-static .nav-wrap,
html.fx-static .filter-pill,
html.fx-static .stats-band,
html.fx-static .cta-band {
  backdrop-filter: none !important;
  -webkit-backdrop-filter: none !important;
}
/* Trainée stellaire — neutralisation défensive (le module bail sur fx-static
   ET sur pointer:coarse en amont). */
html.fx-static .cursor-sparkle {
  display: none !important;
}
/* Modal — animations d'entrée CHEAP (opacity + translateY) → kept on mobile pour
   ressentir le geste premium ; seul reduced-motion les neutralise. */
html.fx-static:not(.fx-light) .modal,
html.fx-static:not(.fx-light) .modal__panel,
html.fx-static:not(.fx-light) .modal__cta,
html.fx-static:not(.fx-light) .modal__close {
  transition: none !important;
}
html.fx-static:not(.fx-light) .modal.is-open .modal__panel {
  transform: none !important;
}

/* ===================================================================
   MESH GRADIENT + PARALLAX + NOISE OVERLAY + SECTION THEMES
   (request-2026-05-28-2315 · item-005)
   -------------------------------------------------------------------
   Trois couches d'ambiance « du futur » servies en GPU-only :
     1. body::before  → 5 radial-gradients aux couleurs marque (violet
        #6d4dff + or #d4af37 + crème), filter blur 40px, dérive 60s
        infinie, parallax au scroll via --parallax-y posé par
        parallax.gostudio.js. transform + animation uniquement → pas
        de reflow, LCP préservé.
     2. body::after   → générateur SVG fractalNoise inline, opacity
        0.035, mix-blend-mode multiply → grain éditorial magazine sur
        toutes les zones claires.
     3. Sections      → palette propre par bloc :
        - .section-tombolas  → palette claire (héritée du body crème)
        - .section-stats     → voile contrasté navy léger
        - .section-cta       → halo violet + or saturé (focus final)
   Neutralisé en fx-static / pointer:coarse / prefers-reduced-motion.
   =================================================================== */

/* ---- 1. Mesh gradient animé (parallax au scroll) ---- */
body::before {
  content: '';
  position: fixed;
  inset: -12% -12% -12% -12%;
  z-index: -2;
  background:
    radial-gradient(ellipse 1100px 720px at 12% 18%, rgba(109, 77, 255, 0.20) 0%, transparent 58%),
    radial-gradient(ellipse 900px 700px at 88% 22%, rgba(212, 175, 55, 0.16) 0%, transparent 62%),
    radial-gradient(ellipse 1200px 820px at 25% 78%, rgba(212, 175, 55, 0.12) 0%, transparent 60%),
    radial-gradient(ellipse 1000px 720px at 78% 82%, rgba(109, 77, 255, 0.14) 0%, transparent 60%),
    radial-gradient(ellipse 900px 600px at 50% 50%, rgba(255, 248, 220, 0.22) 0%, transparent 60%);
  background-repeat: no-repeat;
  filter: blur(40px) saturate(118%);
  transform: translate3d(0, var(--parallax-y, 0px), 0);
  animation: mesh-drift 60s linear infinite;
  pointer-events: none;
  will-change: transform;
}

@keyframes mesh-drift {
  0%   { background-position:   0%   0%, 100%   0%,   0% 100%, 100% 100%,  50%  50%; }
  50%  { background-position:   8%  12%,  92%   8%,  12%  88%,  88%  92%,  52%  48%; }
  100% { background-position:   0%   0%, 100%   0%,   0% 100%, 100% 100%,  50%  50%; }
}

/* ---- 2. Generative noise overlay (grain éditorial) ---- */
body::after {
  content: '';
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 240 240'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 0 0.55 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
  background-size: 240px 240px;
  background-repeat: repeat;
  opacity: 0.035;
  mix-blend-mode: multiply;
}

/* ---- 3. Themes par section ---- */
.section-tombolas { position: relative; }   /* palette claire (héritée body crème) */

.section-stats { position: relative; isolation: isolate; }
.section-stats::before {
  content: '';
  position: absolute;
  inset: 0;
  background:
    radial-gradient(ellipse 70% 80% at 50% 50%, rgba(26, 26, 46, 0.05) 0%, transparent 70%),
    linear-gradient(180deg, rgba(109, 77, 255, 0.04) 0%, transparent 50%, rgba(212, 175, 55, 0.04) 100%);
  pointer-events: none;
  z-index: 0;
}
.section-stats > .container { position: relative; z-index: 1; }

.section-cta { position: relative; isolation: isolate; }
.section-cta::before {
  content: '';
  position: absolute;
  inset: 0;
  background:
    radial-gradient(ellipse 80% 100% at 50% 50%, rgba(109, 77, 255, 0.12) 0%, transparent 60%),
    radial-gradient(circle 600px at 50% 100%, rgba(212, 175, 55, 0.10) 0%, transparent 70%);
  pointer-events: none;
  z-index: 0;
}
.section-cta > .container { position: relative; z-index: 1; }

/* ---- 4. Neutralisations (perf / a11y / mobile) ----
   On garde le mesh visible (statique, sans animation ni parallax)
   pour conserver l'identité visuelle, mais on coupe ce qui coûte
   en GPU et tout ce qui violerait prefers-reduced-motion. */
@media (prefers-reduced-motion: reduce) {
  body::before {
    animation: none !important;
    transform: none !important;
    will-change: auto;
  }
}
@media (pointer: coarse), (max-width: 767px) {
  body::before {
    animation: none !important;
    transform: none !important;
    filter: blur(34px) saturate(112%);
    will-change: auto;
  }
  body::after {
    /* Le grain est peu visible sur petits écrans et coûteux à composer */
    opacity: 0.025;
  }
}
html.fx-static body::before {
  animation: none !important;
  transform: none !important;
  will-change: auto;
}

/* ===================================================================
   MOBILE HAMBURGER MENU — CSS-only drawer
   (request-2026-05-29-0047 · item-001)
   -------------------------------------------------------------------
   Pattern : <input type="checkbox" id="nav-toggle"> + <label for=…>
   + sélecteur :checked / :has() pour ouvrir un drawer right-side
   plein hauteur en < 768 px. Aucun script inline ajouté → la CSP
   stricte (sha256 FX bootstrap + sha256 idle-loader) reste intacte,
   aucun recalcul SRI nécessaire sur les modules JS hashés.

   Architecture :
     - .nav-toggle-checkbox : input visuellement masqué (sr-only)
       mais accessible au clavier (tab → space toggle). Pose l'état.
     - .nav-toggle-btn      : <label for="nav-toggle"> stylé en
       hamburger (3 barres → ✕ via :has(:checked)). 44×44 px (target
       WCAG AAA). Visible uniquement < 768 px.
     - nav.nav-primary      : devient un drawer fixed right-side
       (transform translateX 100% → 0). Sur desktop, reste un row
       inline classique.
     - .nav-backdrop        : <label for="nav-toggle"> overlay plein
       écran (blur + rgba(8,8,24,.62)) — clic ferme le drawer.
     - .nav-legal-link      : liens secondaires (mentions / privacy)
       visibles uniquement dans le drawer mobile.

   Lock scroll : `html:has(.nav-toggle-checkbox:checked) { overflow:
   hidden }`. `:has()` supporté Safari 15.4+ / Chrome 105+ / Firefox
   121+ → couverture > 95 % audience mobile 2026. Les rares browsers
   sans support gardent un menu fonctionnel (drawer s'ouvre/ferme),
   seul le scroll-lock body est dégradé.

   A11y : la valeur d'état est portée par l'input checkbox (annoncé
   par les lecteurs d'écran). Pas d'aria-expanded dynamique (CSS-only
   ne peut pas muter les attributs), mais le pattern `<input
   type="checkbox">` est standard et compris par les SR.
   =================================================================== */

/* Checkbox visuellement masquée mais focusable (sr-only standard) */
.nav-toggle-checkbox {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  pointer-events: none;
}

/* Bouton hamburger — masqué sur desktop, visible < 768 px */
.nav-toggle-btn {
  display: none;
  position: relative;
  width: 44px;
  height: 44px;
  cursor: pointer;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 5px;
  border-radius: 12px;
  background: transparent;
  z-index: 102;                      /* au-dessus du drawer pour rester clic-fermable */
  transition: background .25s ease;
  -webkit-tap-highlight-color: transparent;
}
.nav-toggle-btn:hover {
  background: rgba(26, 26, 46, 0.05);
}
.nav-toggle-bar {
  display: block;
  width: 22px;
  height: 2px;
  background: var(--text);
  border-radius: 2px;
  transform-origin: center;
  /* Animation ☰ → ✕ soyeuse, alignée sur le drawer (cubic-bezier .32 .72 0 1)
     mais avec une durée légèrement plus courte (380 ms vs 480 ms drawer) →
     les barres terminent leur rotation/disparition juste avant que le drawer
     finisse sa glisse, créant une cascade visuelle naturelle. */
  transition: transform .38s cubic-bezier(.32, .72, 0, 1),
              opacity .26s cubic-bezier(.32, .72, 0, 1);
}
/* Focus ring sur le label quand l'input est focus-clavier */
.nav-toggle-checkbox:focus-visible + .nav-toggle-btn {
  outline: 2px solid var(--gold);
  outline-offset: 4px;
}
/* Animation hamburger → ✕ quand le checkbox est checké */
html:has(.nav-toggle-checkbox:checked) .nav-toggle-bar:nth-child(1) {
  transform: translateY(7px) rotate(45deg);
}
html:has(.nav-toggle-checkbox:checked) .nav-toggle-bar:nth-child(2) {
  opacity: 0;
  transform: scaleX(0);
}
html:has(.nav-toggle-checkbox:checked) .nav-toggle-bar:nth-child(3) {
  transform: translateY(-7px) rotate(-45deg);
}

/* Backdrop — overlay plein écran (clic ferme via label[for]) */
.nav-backdrop {
  display: none;                     /* activé en mobile */
  position: fixed;
  inset: 0;
  background: rgba(8, 8, 24, 0.62);
  -webkit-backdrop-filter: blur(8px) saturate(115%);
  backdrop-filter: blur(8px) saturate(115%);
  z-index: 99;                       /* sous le drawer (101), au-dessus du contenu (sticky header 100) */
  opacity: 0;
  pointer-events: none;
  cursor: pointer;
  /* Easing aligné sur celui du drawer (cubic-bezier .32 .72 0 1, 480 ms) →
     fade backdrop et glisse drawer synchronisés visuellement. */
  transition: opacity .48s cubic-bezier(.32, .72, 0, 1);
}

/* Liens secondaires (mentions légales / privacy) — drawer-only */
.nav-legal-link {
  display: none;
}

/* ===== Breakpoint mobile / tablette portrait (< 768 px) ===== */
@media (max-width: 767px) {

  /* Le hamburger devient visible */
  .nav-toggle-btn {
    display: flex;
  }

  /* La nav devient un drawer right-side plein hauteur */
  header[role="banner"] nav[aria-label="Navigation principale"] {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    width: min(86vw, 360px);
    height: 100vh;
    height: 100dvh;                  /* dvh — gère la barre d'URL mobile */
    flex-direction: column;
    align-items: stretch;
    justify-content: flex-start;
    gap: 0;
    /* Safe-area iOS (request-2026-05-29-0047 · item-006) — drawer plein écran :
       en portrait, le top doit éviter notch/Dynamic Island ; en paysage avec
       notch côté droit (orientation home-left), le bord droit du drawer doit
       respecter inset-right ; le bottom doit éviter la barre home. env()
       vaut 0 hors iOS, on n'ajoute donc rien sur Android/desktop. */
    padding:
      calc(clamp(96px, 14vh, 120px) + env(safe-area-inset-top))
      max(24px, env(safe-area-inset-right))
      calc(clamp(32px, 6vh, 48px) + env(safe-area-inset-bottom))
      24px;
    background: linear-gradient(180deg,
                  rgba(250, 250, 248, 0.985) 0%,
                  rgba(248, 245, 238, 0.985) 100%);
    -webkit-backdrop-filter: blur(20px) saturate(140%);
    backdrop-filter: blur(20px) saturate(140%);
    box-shadow: -28px 0 64px -18px rgba(26, 26, 46, 0.28);
    border-left: 1px solid rgba(212, 175, 55, 0.20);
    transform: translateX(100%);
    /* ─── request-2026-05-29-XXXX (smooth drawer open/close) ───
       Animation soyeuse type iOS/Linear : cubic-bezier(.32, .72, 0, 1)
       (signature Linear) — courbe plus organique, moins « snap »
       qu'ease-out-expo (.16, 1, .3, 1). Durée légèrement allongée
       (420 → 480 ms) pour un ressenti plus haut-de-gamme. Le delay
       sur `visibility` reste calé sur la durée pour permettre au
       drawer de finir sa sortie avant de quitter le flow a11y. */
    transition: transform .48s cubic-bezier(.32, .72, 0, 1),
                box-shadow .48s cubic-bezier(.32, .72, 0, 1),
                visibility 0s linear .48s;
    z-index: 101;                    /* au-dessus du sticky header (100) */
    overflow-y: auto;
    overscroll-behavior: contain;
    visibility: hidden;              /* sortie du flow A11y quand fermé */
    /* Hint GPU pour une animation 60 fps sans repaint du contenu sous le drawer */
    will-change: transform;
  }

  /* Liens dans le drawer : pleine largeur, séparateurs subtils */
  header[role="banner"] nav[aria-label="Navigation principale"] a {
    width: 100%;
    padding: 16px 12px;
    font-size: 16px;
    line-height: 1.3;
    color: var(--text);
    border-radius: 10px;
    border-bottom: 1px solid rgba(26, 26, 46, 0.06);
    white-space: normal;
  }
  header[role="banner"] nav[aria-label="Navigation principale"] a:hover {
    background: rgba(109, 77, 255, 0.05);
    color: var(--text);
  }
  /* Désactivation de l'underline or animé (incompatible avec layout drawer) */
  header[role="banner"] nav[aria-label="Navigation principale"] a:not(.btn-nav-cta)::after {
    display: none;
  }

  /* CTA en mode drawer : pleine largeur, plus de respiration */
  header[role="banner"] nav[aria-label="Navigation principale"] .btn-nav-cta {
    width: 100%;
    margin-top: 22px;
    padding: 14px 22px !important;
    text-align: center;
    border-radius: 12px !important;
    border-bottom: none;
  }

  /* Liens légaux — visibles uniquement dans le drawer */
  .nav-legal-link {
    display: block;
    font-size: 13px !important;
    color: var(--text-muted) !important;
    letter-spacing: 0.02em;
    padding: 12px 12px !important;
    border-bottom: none !important;
  }
  .nav-legal-link:first-of-type {
    margin-top: 22px;
    padding-top: 18px !important;
    border-top: 1px solid rgba(26, 26, 46, 0.10);
  }

  /* Backdrop devient utilisable */
  .nav-backdrop {
    display: block;
  }

  /* ===== ÉTAT OUVERT (checkbox cochée) ===== */
  html:has(.nav-toggle-checkbox:checked) header[role="banner"] nav[aria-label="Navigation principale"] {
    transform: translateX(0);
    visibility: visible;
    /* Easing « Linear » + 480 ms (cf. règle fermée plus haut). Le delay
       sur visibility passe à 0s — le drawer doit être visible AVANT que
       la transition démarre. */
    transition: transform .48s cubic-bezier(.32, .72, 0, 1),
                box-shadow .48s cubic-bezier(.32, .72, 0, 1),
                visibility 0s linear 0s;
    /* Ombre intensifiée à l'ouverture — accentue la profondeur du drawer
       qui glisse au-dessus du contenu (subtil mais perceptible) */
    box-shadow: -32px 0 80px -16px rgba(26, 26, 46, 0.36);
  }
  html:has(.nav-toggle-checkbox:checked) .nav-backdrop {
    opacity: 1;
    pointer-events: auto;
  }
  /* Body scroll lock — :has() supporté sur tous browsers cibles 2026 */
  html:has(.nav-toggle-checkbox:checked),
  html:has(.nav-toggle-checkbox:checked) body {
    overflow: hidden;
  }
  /* Bouton hamburger : variante « ✕ » → fond légèrement creusé pour
     accentuer l'état actif sans changer de couleur (cohérence luxe) */
  html:has(.nav-toggle-checkbox:checked) .nav-toggle-btn {
    background: rgba(26, 26, 46, 0.06);
  }
}

/* prefers-reduced-motion — drawer apparaît instantanément (hard opt-out) */
@media (prefers-reduced-motion: reduce) {
  header[role="banner"] nav[aria-label="Navigation principale"],
  .nav-backdrop,
  .nav-toggle-bar {
    transition: none !important;
  }
}
/* ─── request-2026-05-29-XXXX (smooth drawer open/close) ───
   Les transitions du drawer (transform + opacity, 100 % GPU-cheap) doivent
   rester visibles sur mobile. Le sélecteur `html.fx-static` couvre RM ET
   mobile/coarse — on le restreint à `html.fx-static:not(.fx-light)` pour
   ne désactiver l'animation QUE dans le cas RM strict (cf. architecture
   item-002 de request-2026-05-29-0047 : `fx-light` est posé sur
   mobile-sans-RM, `fx-static` seul = RM). Avant ce fix, l'animation
   était instantanée sur mobile par défaut. */
html.fx-static:not(.fx-light) header[role="banner"] nav[aria-label="Navigation principale"],
html.fx-static:not(.fx-light) .nav-backdrop,
html.fx-static:not(.fx-light) .nav-toggle-bar {
  transition: none !important;
}

/* ===================================================================
   TOUCH TARGETS — WCAG 2.5.5 niveau AAA (≥ 44×44 px)
   (request-2026-05-29-0047 · item-007)
   -------------------------------------------------------------------
   Audit pré-fix :
     .btn-nav-cta        10×22 + font 14 → ~38 px      sous-dim.
     nav a               10×16 + font 14 → ~38 px      sous-dim.
     .filter-pill         7×20 + font 11 → ~28 px      très sous-dim.
     .footer-links a     font 13, pad 0  → quasi rien  sous-dim.
     .modal__close       38 × 38 px                    sous-dim.
     .card__arrow        38 × 38 px                    OK (cosmétique,
                                                        toute la carte
                                                        est cliquable)

   Activé sur viewport ≤ 768 px OU pointeur coarse (touch device) →
   couvre mobile, tablette, ChromeBook tactile sans pénaliser desktop
   souris. CSS-only, zéro script ajouté, CSP `script-src` strictement
   inchangée, aucun recalcul SRI sur les 8 modules FX.

   Notes spécificité :
     - `.filter-pill` à L1525 (`@media (max-width: 640px)`) — même
       spécificité, source order ici > donc remplace les 36 px.
     - `.modal__close` à L1602 — même spécificité, source order >.
     - `.btn-nav-cta` à L283 — !important sur padding/box-shadow ; on
       repique avec !important. En drawer mobile (< 767 px) la règle
       L2469 `header[role="banner"] nav[…] .btn-nav-cta` (spec 0,3,2 +
       !important) gagne — c'est désiré, son padding 14×22 + font 14
       donne déjà ~45 px.
     - `nav a` à L243 (spec 0,1,1) ; on cible avec une spec ≥ pour
       ne pas être supplanté par la règle drawer L2446 (spec 0,3,2),
       mais sans la concurrencer (le drawer fait déjà ~52 px de haut).
   =================================================================== */
@media (max-width: 768px), (pointer: coarse) {

  /* CTA nav header — 38 → 44 px (desktop touch + tablette landscape).
     Le drawer mobile (< 767 px) a sa propre règle L2469 prioritaire. */
  .btn-nav-cta {
    min-height: 44px !important;
    padding: 12px 22px !important;
    display: inline-flex !important;
    align-items: center;
    justify-content: center;
  }

  /* Liens nav (desktop touch + drawer mobile) — ≥ 44 px de haut.
     En drawer (< 767 px) la padding 16×12 + font 16 donne déjà ~52 px
     mais min-height garantit la cible AAA en toutes circonstances. */
  nav a {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
  }

  /* Filter pills — 28 px (desktop) / 36 px (mobile L1525) → 44 px AAA.
     Padding élargi 12×22 → cohérence verticale + cible confortable au
     pouce. La hiérarchie visuelle (font 11 px, uppercase, letter-
     spacing 0.10em) reste préservée — seule la zone tactile grandit. */
  .filter-pill {
    min-height: 44px;
    padding: 12px 22px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }

  /* Liens footer — quasiment aucune cible tactile sans padding.
     `display: inline-block` requis pour qu'un `<a>` accepte padding
     vertical + min-height. `line-height: 24px` + `padding: 10px 8px`
     → hauteur totale = 10 + 24 + 10 = 44 px exactement. */
  .footer-links a {
    display: inline-block;
    padding: 10px 8px;
    min-height: 44px;
    line-height: 24px;
  }

  /* Bouton fermeture modale — 38 → 44 px (cible AAA). Position top/
     right inchangée (14 px) — le bouton grandit symétriquement vers
     le centre de la modale, l'icône reste centrée via flex parent. */
  .modal__close {
    width: 44px;
    height: 44px;
  }
}

/* ===== ITEM-012 (request-2026-05-29-0047) — Tap-highlight & touch-callout =====
   Sur iOS / Android, taper une carte ou un lien fait apparaître par défaut
   un overlay gris ou orange via `-webkit-tap-highlight-color` — cassure
   visuelle pénible sur un site « ultra-stylé ». Et le long-press sur une
   image ouvre le menu système (sauvegarder, partager) — inutile ici.

   1. `html { -webkit-tap-highlight-color: transparent }` globalement.
      Le focus-visible (a11y clavier) reste pleinement opérationnel — on
      ne casse que l'overlay tactile.
   2. Renforcement explicite sur les composants interactifs principaux
      (.card, .filter-pill, .btn-nav-cta, .btn-primary, .btn-secondary,
      .footer-links a, nav a) — au cas où un user-agent ne propage pas la
      règle racine.
   3. `-webkit-touch-callout: none` + `user-select: none` sur le branding
      et les screenshots (.card__bg img, .footer-sig-logo, .logo-img-header,
      .inline-logo) → plus de menu « Enregistrer l'image » au long-press.
   4. Compensation visuelle : animation de tap subtile sur `.card` via
      `:active` (scale 0.985 + 100 ms) — feedback tactile premium qui
      remplace le highlight système. Scopée `pointer: coarse` pour ne
      pas perturber le clic souris desktop (l'effet hover s'en charge
      déjà). Le transform `.card` n'est pas dans la liste de transition
      au repos (cf. L593), donc pas de conflit avec le tilt 3D (qui de
      toute façon bail en `fx-static` mobile). */
html {
  -webkit-tap-highlight-color: transparent;
}
.card,
.filter-pill,
.btn-nav-cta,
.btn-primary,
.btn-secondary,
.footer-links a,
nav a {
  -webkit-tap-highlight-color: transparent;
}
.card__bg img,
.footer-sig-logo,
.logo-img-header,
.inline-logo {
  -webkit-touch-callout: none;
  -webkit-user-select: none;
     -moz-user-select: none;
          user-select: none;
}
/* Feedback tactile au tap — uniquement coarse pointer (mobile / tablette).
   Sur desktop souris, `:active` se déclencherait aussi au clic mais le
   hover gère déjà le feedback ; on évite tout doublon. */
@media (pointer: coarse) {
  .card:active {
    transform: scale(0.985);
    transition: transform 100ms cubic-bezier(.25, .46, .45, .94);
  }
}
/* Modes dégradés : on respecte `prefers-reduced-motion` et `html.fx-static`
   en désactivant la micro-animation tap. Les autres règles ci-dessus
   (tap-highlight / touch-callout / user-select) restent actives — elles
   sont CSS-only, sans coût, et améliorent l'ergonomie tactile dans tous
   les cas. */
@media (prefers-reduced-motion: reduce) {
  .card:active { transform: none; transition: none; }
}
html.fx-static .card:active { transform: none; transition: none; }

/* ===================================================================
   ITEM-013 (request-2026-05-29-0047) — Header mobile : équilibrage
   logo / CTA / burger
   -------------------------------------------------------------------
   Contexte : depuis item-001, le `.btn-nav-cta` était englouti dans le
   drawer mobile (nav fixe + translateX(100%) → off-screen). Sur petits
   écrans (~360–390 px), l'utilisateur ne voyait QUE logo + burger dans
   le header. Le CTA primaire (« visite gotombola.co ») était caché
   derrière un clic supplémentaire — perte de conversion mobile.

   Cette refonte CSS-only (zéro JS, aucun recalcul SRI sur les 8 modules
   FX, CSP `script-src` strictement inchangée) accompagne le HTML : le
   `.btn-nav-cta` est désormais un sibling direct dans `.header-inner`
   (placé entre l'input checkbox et le label burger), plus un dernier
   enfant du <nav>. Le drawer ne contient donc plus le CTA (il ne sert
   qu'à la nav secondaire : Exemples / Contact / Mentions / Privacy).

   Layout desktop (≥ 768 px) :
     logo --- [auto-space] --- Exemples Contact gotombola.co
     ↳ `nav { margin-left: auto }` pousse le cluster nav+CTA à droite
     ↳ `.btn-nav-cta { order: 1 }` place le CTA après la nav visuellement
        (sans bouger le DOM, qui garde CTA avant nav pour la cohérence du
        flow mobile).

   Layout mobile (< 768 px) :
     logo --- [auto-space] --- gotombola.co [gap] ☰
     ↳ `.btn-nav-cta { margin-left: auto }` pousse CTA + burger à droite
     ↳ nav (off-screen, transform translateX(100%)) ne participe pas au
        flow inline.

   Mobile ≤ 480 px (iPhone Mini, Galaxy A, anciens Android) :
     - Logo height 32 → 26 px (−20 % d'emprise horizontale)
     - `.header-inner { gap: 8 px }` (vs 6 px global — léger resserrement
       du cluster droit, marge entre logo et CTA suffisante grâce à
       l'auto-margin qui absorbe tout l'espace libre)
     - CTA : flèche `→` masquée (`<span class="btn-nav-cta__arrow">` rendu
       `display: none`) + padding horizontal 22 → 14 px (vs L2685 qui
       impose 12×22 sur ≤ 768 px ; on garde min-height 44 du même bloc,
       hauteur tactile AAA préservée). Texte visible « gotombola.co » sans
       flèche → ~95 px de large (vs ~130 px avant), gain ~27 %.
     - `html.is-scrolled .header-inner { height: clamp(56px, 6.4vh, 64px) }`
       (vs 68/7.4/84 hérité) → au scroll, le header descend à 56–64 px
       (plus de surface vidéo pour le contenu, ressenti « mobile-app »
       moderne type Stripe / Linear). Le repos reste à 72/8/88
       (`.header-inner` global) — l'effet de condensation est plus marqué
       qu'en desktop, signature « scroll-and-immerse ».
     - Centrage vertical du burger : `align-items: center` déjà actif sur
       `.header-inner` → logo image 26 px et burger 44 px se calent au
       milieu pixel-près, peu importe leur hauteur respective.

   Budget horizontal recalculé à 360 px de viewport (Galaxy A) :
     container padding (max(20, env)) ≈ 20 px chaque bord → utile 320 px
     logo (image 26 px height, aspect ~3.6 → ~94 px wide)
     gap 8 px
     [auto-space ≥ 40 px]
     CTA « gotombola.co » (font 14 + pad 10×14 ≈ 95 × ~44 px)
     gap 8 px
     burger 44 × 44 px
     ────────────────────────────────────────────────────────
     ≈ 94 + 8 + 40 + 95 + 8 + 44 = 289 px → tient dans 320 px ✓
=================================================================== */
@media (min-width: 768px) {
  /* Desktop : nav (Exemples + Contact) + CTA (avec order: 1) groupés à
     droite via auto-margin sur la nav. Le CTA reste après la nav
     visuellement (cohérence avec l'ordre historique). */
  .header-inner > nav[aria-label="Navigation principale"] {
    margin-left: auto;
  }
  .header-inner > .btn-nav-cta {
    order: 1;
  }
}
@media (max-width: 767px) {
  /* Mobile : nav devient drawer off-screen (cf. L2524+).
     ─── request-2026-05-29-XXXX (fix burger aligné à droite) ───
     Depuis item-002 (request-2026-05-29-0213), le `.btn-nav-cta` du
     header est `display: none !important` sur mobile (remplacé par le
     CTA fixed bas viewport). Conséquence : son `margin-left: auto`
     n'a plus aucun effet sur le flex flow (l'élément étant hors flow).
     Résultat : le burger (4ᵉ enfant flex) se collait contre le logo
     à gauche. Fix : on déplace l'auto-margin sur le burger lui-même
     → logo à gauche, burger à droite, parfaitement équilibré. */
  .header-inner > .btn-nav-cta {
    margin-left: auto;
  }
  .header-inner > .nav-toggle-btn {
    margin-left: auto;
  }
}
@media (max-width: 480px) {
  .header-inner {
    /* Resserrement du cluster droit (CTA + burger collés à 8 px) */
    gap: 8px;
  }
  .logo-img-header {
    /* −6 px (≈ −20 % d'emprise horizontale) */
    height: 26px;
  }
  html.is-scrolled .header-inner {
    /* Au scroll : header plus discret (vs 68/7.4/84 desktop hérité) */
    height: clamp(56px, 6.4vh, 64px);
  }
  /* CTA compacté — la flèche disparaît, le padding horizontal passe
     22 → 14 px. La règle touch-target L2685 (`min-height: 44 !important`,
     padding 12×22 !important) appliquée à ≤ 768 px reste partiellement
     active : `min-height: 44` garantit la cible AAA, on surchargage
     seulement le padding (source order plus récent → wins à spec égale).
     Note : on garde `padding: 10px 14px` (vertical 10, pas 12) — le
     min-height: 44 borne déjà la hauteur effective, donc on s'autorise
     un padding vertical plus serré au profit de la compacité visuelle. */
  .btn-nav-cta {
    padding: 10px 14px !important;
  }
  .btn-nav-cta__arrow {
    display: none;
  }
}

/* ===================================================================
   CTA FIXED MOBILE — bouton « Plus d'infos » bas viewport
   (request-2026-05-29-0213 · item-002)
   -------------------------------------------------------------------
   Le CTA `gotombola.co` du header (sibling logo depuis item-013) reste
   discret sur petits écrans (≤ 480 px : padding compacté, flèche
   masquée). Pour le convertir en réflexe « toujours visible »
   (pattern Stripe / Linear mobile), on le masque dans le header < 768 px
   et on le remplace par une barre fixée en bas du viewport, libellé
   explicite « Plus d'infos » + flèche.

   Spec :
     - Pill centrée (vs full-width) — choix premium en cohérence avec la
       ligne 5 étoiles du site (header voile crème, cartes or massif,
       trainée stellaire). Full-width signalerait « conversion », la
       pill signale « invitation ».
     - Visible UNIQUEMENT < 768 px (au-delà, le `.btn-nav-cta` du header
       reprend la main).
     - Masque le `.btn-nav-cta` du header sur mobile (override des règles
       touch-target item-007 L2745 qui forcent
       `display: inline-flex !important`).
     - Caché quand le drawer hamburger est ouvert
       (`html:has(.nav-toggle-checkbox:checked)`) — sinon il flotte
       par-dessus le backdrop + drawer.
     - Caché quand la modale détail est ouverte (`html.has-modal`, posé
       par `modal-detail.js` L421) — sinon empilement avec
       `.modal__cta-bar` sticky bas (item-011, request-2026-05-29-0047).
     - Safe-area iOS bottom respectée
       (`max(16px, env(safe-area-inset-bottom))`) — ne se loge pas sous
       la barre home iPhone 14/15/16 Pro.
     - Identité visuelle reprise du `.btn-nav-cta` (dégradé violet→or,
       inner-shadow chaud, halo or doux + ombre violet diffuse).
     - Tap-highlight transparent + micro-scale 0.985 au :active (bloc
       CSS-only item-012) — feedback tactile premium.
     - A11y : libellé explicite « Plus d'infos », min-height 44 px
       (WCAG AAA), focus-visible ring or (#f4d77a), pas d'aria-label
       redondant (le texte suffit). Le `target="_blank"` est annoncé
       nativement par les lecteurs d'écran.
     - Modes dégradés : `prefers-reduced-motion` et `html.fx-static`
       coupent les transitions / animations ; la barre reste 100 %
       fonctionnelle (display + position + box-shadow figés).

   Note item-013 : les overrides ≤ 480 px (logo 26 px, padding CTA
   10×14, flèche masquée, gap 8 px, `html.is-scrolled` condensé) sont
   conservés intacts. Ils deviennent inertes pour le CTA (qui est
   `display: none !important`) mais le logo 26 px + gap 8 px restent
   utiles pour le couple logo + burger ; ils servent aussi de filet
   de sécurité si un futur fallback (prefers-reduced-data, classe
   utilisateur) ré-affichait le CTA dans le header.
=================================================================== */
.cta-fixed-mobile { display: none; }

@media (max-width: 767px) {
  /* Masque le CTA header mobile — override des règles touch-target
     item-007 L2745 qui posent `display: inline-flex !important`. */
  .header-inner .btn-nav-cta { display: none !important; }

  /* Bouton fixed bas viewport — pill flottante quasi-full-width.
     ─── request-2026-05-29-XXXX (floating bar : marges + coins arrondis) ───
     L'utilisateur préfère le rendu « pill flottante » à l'edge-to-edge :
     - quasi pleine largeur (laisse respirer ~16 px de chaque côté → le
       fond crème du viewport apparaît sur les bords, ressenti premium)
     - coins arrondis prononcés (border-radius 18 px — vraie pill mobile)
     - décollé du bord bas (margin = 16 px + safe-area iOS)
     - identité visuelle préservée (dégradé violet→or, halo or + ombre
       violet diffuse en rayonnement autour de la pill).
     Hauteur tactile AAA préservée (min-height: 44 + padding 14). */
  .cta-fixed-mobile {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    position: fixed;
    left: 16px;
    right: 16px;
    bottom: max(16px, env(safe-area-inset-bottom));
    z-index: 50;
    min-height: 44px;            /* WCAG AAA (item-007) */
    padding: 14px 22px;
    border-radius: 18px;         /* pill flottante — coins prononcés */
    /* Dégradé violet → or repris du `.btn-nav-cta` */
    background: linear-gradient(135deg,
      #6d4dff 0%,
      #7a5cff 50%,
      #9a7be0 88%,
      #b59538 130%);
    background-size: 180% 100%;
    background-position: 0% 50%;
    color: #fff;
    font-size: 15px;
    font-weight: 600;
    letter-spacing: 0.018em;
    font-feature-settings: 'ss01', 'cv11';
    text-decoration: none;
    white-space: nowrap;
    /* Inner-shadow chaud + halo or doux + ombre violet diffuse (premium)
       — la pill flotte au-dessus du fond crème, ombres projetées rayonnent
       de tous les côtés (visibles grâce aux marges latérales 16 px). */
    box-shadow:
      inset 0 1px 0 rgba(255, 255, 255, 0.24),
      inset 0 -1px 0 rgba(0, 0, 0, 0.18),
      0  0 18px rgba(212, 175, 55, 0.32),
      0 10px 30px -8px rgba(109, 77, 255, 0.48);
    /* ─── request-2026-05-29-XXXX (apparition smooth au scroll) ───
       État initial = CACHÉ (translateY hors-viewport + opacité 0 +
       pointer-events: none → la pill ne bloque pas les clics ni la
       sélection même invisible). L'état VISIBLE est piloté par la
       classe `html.is-scrolled` (posée par le bootstrap FX inline
       quand scrollY > 8 px). Transitions allongées à .45s avec
       cubic-bezier(.32, .72, 0, 1) (signature Linear) → ressenti
       premium luxe, cohérent avec l'animation du drawer (item smooth).
       Le scale 0.985 du :active utilise la même durée (un poil plus
       lent qu'avant mais imperceptible vu l'amplitude minime). */
    transform: translateY(140%);
    opacity: 0;
    pointer-events: none;
    transition: transform .45s cubic-bezier(.32, .72, 0, 1),
                opacity .45s cubic-bezier(.32, .72, 0, 1),
                box-shadow .28s cubic-bezier(.25,.46,.45,.94),
                background-position .55s cubic-bezier(.25,.46,.45,.94),
                filter .22s cubic-bezier(.25,.46,.45,.94);
    -webkit-tap-highlight-color: transparent;
    -webkit-touch-callout: none;
    will-change: transform, opacity;
  }
  /* ─── État VISIBLE — déclenché par html.is-scrolled (scrollY > 8 px) ─── */
  html.is-scrolled .cta-fixed-mobile {
    transform: translateY(0);
    opacity: 1;
    pointer-events: auto;
  }
  /* :active scopé à l'état visible (.is-scrolled) — sinon le scale
     écraserait le translateY(140%) initial et la pill apparaîtrait
     soudainement quand la classe n'est pas encore posée.
     Combine translateY(0) (état visible) + scale(0.985) (micro-feedback). */
  html.is-scrolled .cta-fixed-mobile:active {
    transform: translateY(0) scale(0.985);
    background-position: 100% 50%;
    filter: brightness(1.04);
    box-shadow:
      inset 0 1px 0 rgba(255, 255, 255, 0.28),
      inset 0 -1px 0 rgba(0, 0, 0, 0.20),
      0  0 22px rgba(212, 175, 55, 0.48),
      0 12px 32px -8px rgba(109, 77, 255, 0.55);
  }
  .cta-fixed-mobile:focus-visible {
    outline: 2px solid #f4d77a;
    outline-offset: 3px;
  }

  /* ─── EFFETS PREMIUM (request-2026-05-29-XXXX) ───────────────────
     3 couches superposées pour signer le « haut-de-gamme » sans saturer :
     (1) Pulse halo or à l'extérieur (::before, z-index:-1) — anneau or
         qui se diffuse vers l'extérieur toutes les 3.4s, signe « call
         to action vivant » sans agressivité.
     (2) Shine sweep diagonal (::after) — reflet nacré 115° qui traverse
         la pill toutes les 5.2s, signature luxe type Apple / Cartier.
     (3) Box-shadow respiration sur la pill elle-même — halo or doux qui
         varie d'intensité (0.32 → 0.50) en synchronisation discrète avec
         le pulse. CSS-only, 100 % GPU-cheap (transform/opacity/background-
         position uniquement — box-shadow animé via @property pour rester
         compositable). Désactivé sous prefers-reduced-motion + fx-static
         strict (RM seul, conservé sur mobile via fx-light).
  ─────────────────────────────────────────────────────────────────── */

  /* Couche (1) — pulse halo or extérieur */
  .cta-fixed-mobile::before {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: inherit;
    pointer-events: none;
    z-index: -1;                 /* derrière la pill → seul l'anneau qui déborde est visible */
    box-shadow: 0 0 0 0 rgba(212, 175, 55, 0.55);
    animation: cta-fixed-pulse 3.4s cubic-bezier(.4, 0, .2, 1) infinite;
  }

  /* Couche (2) — reflet nacré diagonal qui traverse la pill */
  .cta-fixed-mobile::after {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: inherit;
    pointer-events: none;
    /* Bande diagonale 115° centrée sur un pic crème (255,243,184) entouré
       de transitions blanches → simule un reflet lumineux qui balaye la
       surface. Le mix-blend-mode screen donne un éclat lumineux additif
       sans étouffer le dégradé violet→or en dessous. */
    background: linear-gradient(115deg,
      transparent 30%,
      rgba(255, 255, 255, 0.20) 45%,
      rgba(255, 243, 184, 0.42) 50%,
      rgba(255, 255, 255, 0.20) 55%,
      transparent 70%);
    background-size: 220% 100%;
    background-position: 220% 50%;     /* point de départ hors champ à droite */
    mix-blend-mode: screen;
    animation: cta-fixed-shine 5.2s cubic-bezier(.4, 0, .2, 1) infinite;
  }

  /* Pause des animations au tap (feedback responsive : la pill « écoute » le clic) */
  .cta-fixed-mobile:active::before,
  .cta-fixed-mobile:active::after {
    animation-play-state: paused;
  }

  /* ─── Padding-bottom du body : empêche la pill fixed de masquer le
     contenu tout en bas (footer, dernière section) au scroll. La pill
     occupe ~52 px (padding 14×2 + texte ~21) + 16 px de margin bottom
     + safe-area iOS ~34 px max → on prévoit ~84 px + safe-area pour
     une marge de sécurité confortable (le contenu n'est jamais frôlé). */
  body { padding-bottom: calc(84px + env(safe-area-inset-bottom)); }

  /* Drawer hamburger ouvert → CTA masqué (sinon flotte au-dessus) */
  html:has(.nav-toggle-checkbox:checked) .cta-fixed-mobile {
    display: none;
  }
  /* Modale détail ouverte (modal-detail.js → html.has-modal) →
     CTA masqué pour éviter l'empilement avec .modal__cta-bar (item-011) */
  html.has-modal .cta-fixed-mobile {
    display: none;
  }
}

/* Keyframes des effets premium — hors du @media car les @keyframes ne se
   scope pas (toujours globaux). Les animations elles-mêmes sont scopées
   aux sélecteurs `.cta-fixed-mobile::before/::after` qui n'apparaissent
   qu'en mobile (la pill est `display: none` en desktop, les pseudos
   n'existent pas non plus). */
@keyframes cta-fixed-pulse {
  /* Anneau or qui se diffuse vers l'extérieur depuis le bord de la pill.
     Phase de repos prolongée (50-100 %) pour laisser respirer entre 2
     pulsations → ressenti « invitation » et non « alarme SaaS ». */
  0%, 50%, 100% { box-shadow: 0 0 0 0  rgba(212, 175, 55, 0.55); }
  25%           { box-shadow: 0 0 0 18px rgba(212, 175, 55, 0); }
}

@keyframes cta-fixed-shine {
  /* Reflet qui démarre hors champ à droite, traverse la pill, ressort à
     gauche. Pause longue (40-100 %) → 1 sweep toutes les 5.2s, pas plus,
     pour éviter l'effet « spotlight casino ». Easing ease-in-out → la
     pointe lumineuse glisse smooth, pas linéaire (plus organique). */
  0%, 40% { background-position: 220% 50%; }
  100%    { background-position: -120% 50%; }
}

/* ─── Modes dégradés ─────────────────────────────────────────────────
   Logique :
   - `prefers-reduced-motion` (hard opt-out) → toutes les animations
     (pulse, shine) et transitions OFF. La pill apparaît instantanément
     (translateY = 0, opacity = 1) dès que `is-scrolled` est posé.
   - `html.fx-static` SEUL (= RM strict — `fx-light` absent) → idem.
   - `html.fx-static.fx-light` (= mobile sans RM) → on garde les effets
     premium (pulse, shine, smooth fade-in) car ils sont GPU-cheap
     (transform/opacity/background-position). Pour ça on cible
     `html.fx-static:not(.fx-light)` (RM strict) au lieu de `html.fx-static`.
─────────────────────────────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  .cta-fixed-mobile,
  .cta-fixed-mobile::before,
  .cta-fixed-mobile::after {
    transition: none !important;
    animation: none !important;
  }
  /* État visible instantané (pas de fade-in/up animé sous RM) */
  html.is-scrolled .cta-fixed-mobile {
    transform: none !important;
    opacity: 1 !important;
  }
  html.is-scrolled .cta-fixed-mobile:active {
    transform: none !important;     /* pas de scale 0.985 */
    filter: none !important;
  }
}
html.fx-static:not(.fx-light) .cta-fixed-mobile,
html.fx-static:not(.fx-light) .cta-fixed-mobile::before,
html.fx-static:not(.fx-light) .cta-fixed-mobile::after {
  transition: none !important;
  animation: none !important;
}
html.fx-static:not(.fx-light).is-scrolled .cta-fixed-mobile {
  transform: none !important;
  opacity: 1 !important;
}
html.fx-static:not(.fx-light).is-scrolled .cta-fixed-mobile:active {
  transform: none !important;
  filter: none !important;
}
