/* =============================================
   BINÔME — DESIGN SYSTEM (APPLE-LIKE REFRESH)

   SOMMAIRE
     1. TOKENS — socle sémantique
     2. RESET & BASE
     ... (sections historiques à la suite)

   RÈGLE DE COULEUR — à retenir avant toute modification :
     --brand       s'utilise en APLAT (fond de bouton, pastille). Reste #0055FF
                   dans les deux thèmes : blanc sur #0055FF donne 5,6:1, conforme AA.
     --brand-text  s'utilise en TEXTE ou en ICÔNE posée sur une surface. S'éclaircit
                   en thème sombre, car #0055FF sur fond sombre tombe à 3,4:1 (échec AA).
   Confondre les deux est la seule façon de casser le contraste du site.
   ============================================= */

:root {
    color-scheme: light dark;
    /* Indique au navigateur que la page gère les deux thèmes : il accorde
       alors barres de défilement, contrôles de formulaire et menus <select>
       natifs, sans une ligne de CSS supplémentaire. */

    /* ── Marque ─────────────────────────────────────────────── */
    --brand: #0055FF;
    /* Composantes séparées : permet rgb(var(--brand-rgb) / <alpha>) sans
       redéclarer la couleur à chaque opacité. */
    --brand-rgb: 0 85 255;
    /* Valeur héritée de .btn-helloasso:hover — conservée telle quelle pour ne
       pas modifier le rendu ; c'est le seul bleu de survol du site. */
    --brand-hover: #0044CC;
    --brand-contrast: #FFFFFF;
    --brand-text: #0055FF;
    --brand-soft: #EBF3FF;
    --brand-grad: linear-gradient(135deg, #0055FF 0%, #3D8BFD 50%, #0DCAF0 100%);

    /* ── Surfaces ───────────────────────────────────────────── */
    --surface-0: #FFFFFF;
    --surface-1: #FFFFFF;
    --surface-2: #F5F5F7;
    --surface-3: #ECEEF2;
    --surface-glass: rgb(255 255 255 / 0.92);
    --surface-glass-dim: rgb(255 255 255 / 0.85);
    --surface-panel: rgb(255 255 255 / 0.70);
    --surface-panel-2: rgb(255 255 255 / 0.75);
    /* Liseré interne haut : discret en clair, indispensable en sombre pour
       que les cartes ne se fondent pas dans le fond. */
    --edge-hilite: rgb(255 255 255 / 0.9);
    /* Masques de dégradé qui estompent les chiffres du compteur : doivent
       toujours correspondre au fond de la carte qui les porte. */
    --slot-fade: rgb(248 249 255 / 0.85);
    --field-bg: #F9F9FB;
    --field-border: #E0E0E0;
    --support-tint: rgb(235 243 255 / 0.5);
    /* Remplissages des emplacements visuels — remplacés en Phase 5. */
    --fill-1: #F0F2F5;
    --fill-2: #E4E6EA;

    /* ── Texte ──────────────────────────────────────────────── */
    --text: #1A1A1A;
    --text-muted: #666666;
    --text-subtle: #5F6673;   /* 4,6:1 mini sur toutes les surfaces claires — AA */
    --text-invert: #FFFFFF;

    /* ── Traits ─────────────────────────────────────────────── */
    --border: rgb(0 0 0 / 0.07);
    --border-strong: rgb(0 0 0 / 0.12);
    --hairline: rgb(0 0 0 / 0.05);

    /* ── Ombres ─────────────────────────────────────────────
       La géométrie reste écrite sur place (34 ombres distinctes, chacune
       accordée à son composant). Seul le CANAL COULEUR est centralisé :
         --shadow-rgb  la teinte de l'ombre
         --shadow-k    multiplicateur d'opacité, 1 en clair.
       En thème sombre, une ombre noire sur un fond noir ne se voit pas :
       --shadow-k monte pour compenser, sans toucher aux 34 déclarations. */
    /* ── Décor ── */
    --dot: rgb(0 0 0 / 0.055);
    --grain-o: 0.035;
    --aurora-o: 0.11;

    --shadow-rgb: 0 0 0;
    --shadow-k: 1;

    /* ── Espacement ─────────────────────────────────────────── */
    --sp-1: 4px;
    --sp-2: 8px;
    --sp-3: 12px;
    --sp-4: 16px;
    --sp-5: 24px;
    --sp-6: 32px;
    --sp-7: 48px;
    --sp-8: 64px;
    --sp-9: 96px;
    --sp-10: 128px;
    --section-padding: 120px 5%;
    --section-padding-mobile: 70px 5%;

    /* ── Rayons ─────────────────────────────────────────────── */
    --r-sm: 10px;
    --r-md: 16px;
    --r-lg: 22px;
    --r-xl: 32px;
    --r-pill: 999px;
    --border-radius-card: 20px;

    /* ── Durées & courbes ───────────────────────────────────
       Asymétrie volontaire : on entre vite, on sort lentement, on appuie
       le plus vite. C'est ce qui distingue une interface vive d'une molle. */
    --dur-1: 110ms;
    --dur-2: 180ms;
    --dur-3: 320ms;
    --dur-4: 520ms;
    --dur-5: 820ms;
    --transition-smooth: cubic-bezier(0.25, 0.46, 0.45, 0.94);
    --transition-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
    /* Easing « expo out » : démarre vite, atterrit en douceur.
       Le standard des interfaces premium (Apple, Linear, Stripe). */
    --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
    --ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);
    /* Repli ; remplacé par un vrai ressort linear() plus bas si le
       navigateur le supporte. */
    --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
    --ease-out: cubic-bezier(0.2, 0.8, 0.3, 1);

    /* ── Plans ──────────────────────────────────────────────── */
    --z-grain: 1;
    --z-sticky-rail: 90;
    --z-menu: 199;
    --z-nav: 200;
    --z-overlay: 300;

    /* ── Chrome ─────────────────────────────────────────────
       Hauteur de la navbar. Le menu mobile et scroll-margin-top s'y calent :
       cette variable remplace les « 64px » et « 84px » codés en dur. */
    --nav-h: 64px;

}

/* =============================================
   1b. THÈME SOMBRE

   Le bloc est écrit deux fois volontairement : une fois pour la préférence
   système, une fois pour un futur réglage manuel (data-theme="dark").
   On n'utilise PAS light-dark() : la fonction n'atteint « Baseline widely
   available » qu'en novembre 2026, et si elle n'est pas comprise à
   l'intérieur d'une custom property, la propriété qui la consomme devient
   invalide — soit une page sans style. Ce site sort justement d'un incident
   où il servait une page sans style ; le risque n'est pas acceptable.
   ============================================= */
:root[data-theme="dark"] {
        color-scheme: dark;

        --brand-text: #6AA5FF;
        --brand-hover: #2B6EFF;
        --brand-soft: #16233D;

        --surface-0: #0B0D12;
        --surface-1: #14171F;
        --surface-2: #0F1218;
        --surface-3: #1B1F29;
        --surface-glass: rgb(14 17 23 / 0.80);
        --surface-glass-dim: rgb(14 17 23 / 0.72);
        --surface-panel: rgb(20 23 31 / 0.70);
        --surface-panel-2: rgb(20 23 31 / 0.75);
        --edge-hilite: rgb(255 255 255 / 0.06);
        --slot-fade: rgb(20 23 31 / 0.85);
        --field-bg: #12151C;
        --field-border: rgb(255 255 255 / 0.14);
        --support-tint: rgb(22 35 61 / 0.55);
        --fill-1: #171B24;
        --fill-2: #1E2330;

        --text: #E6E9EF;
        --text-muted: #9AA1AE;
        --text-subtle: #8B93A1;   /* 5,1:1 mini sur toutes les surfaces sombres — AA */

        --border: rgb(255 255 255 / 0.09);
        --border-strong: rgb(255 255 255 / 0.16);
        --hairline: rgb(255 255 255 / 0.06);

        --dot: rgb(255 255 255 / 0.07);

        --grain-o: 0.05;

        --aurora-o: 0.20;

        

        --shadow-k: 3.5;
}

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
        color-scheme: dark;

        --brand-text: #6AA5FF;
        --brand-hover: #2B6EFF;
        --brand-soft: #16233D;

        --surface-0: #0B0D12;
        --surface-1: #14171F;
        --surface-2: #0F1218;
        --surface-3: #1B1F29;
        --surface-glass: rgb(14 17 23 / 0.80);
        --surface-glass-dim: rgb(14 17 23 / 0.72);
        --surface-panel: rgb(20 23 31 / 0.70);
        --surface-panel-2: rgb(20 23 31 / 0.75);
        --edge-hilite: rgb(255 255 255 / 0.06);
        --slot-fade: rgb(20 23 31 / 0.85);
        --field-bg: #12151C;
        --field-border: rgb(255 255 255 / 0.14);
        --support-tint: rgb(22 35 61 / 0.55);
        --fill-1: #171B24;
        --fill-2: #1E2330;

        --text: #E6E9EF;
        --text-muted: #9AA1AE;
        --text-subtle: #8B93A1;   /* 5,1:1 mini sur toutes les surfaces sombres — AA */

        --border: rgb(255 255 255 / 0.09);
        --border-strong: rgb(255 255 255 / 0.16);
        --hairline: rgb(255 255 255 / 0.06);

        --dot: rgb(255 255 255 / 0.07);

        --grain-o: 0.05;

        --aurora-o: 0.20;

        

        --shadow-k: 3.5;
    }
}

/* Courbe élastique réelle, en amélioration progressive.
   Les navigateurs qui ignorent linear() gardent le cubic-bezier du :root. */
@supports (transition-timing-function: linear(0, 1)) {
    :root {
        --ease-spring: linear(0, .006, .025 2.8%, .101 6.1%, .539 18.9%, .721 25.3%,
                .849 31.5%, .937 38.1%, .968 41.8%, .991 45.7%, 1.006 50.1%, 1.015 55%,
                1.017 63.9%, 1.001 79%, 1);
    }
}

/* Propriétés personnalisées animables. Non enregistrées, elles n'animent
   simplement pas : aucune casse, l'effet se dégrade en état statique. */
@property --mx {
    syntax: '<percentage>';
    inherits: false;
    initial-value: 50%;
}

@property --my {
    syntax: '<percentage>';
    inherits: false;
    initial-value: 50%;
}

@property --angle {
    syntax: '<angle>';
    inherits: false;
    initial-value: 0deg;
}

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

html {
    /* La pile est posée ici plutôt que sur « * » : le sélecteur universel
       obligeait chaque champ de formulaire à redéclarer font-family: inherit. */
    /* Pile 100 % système. « Inter » y figurait en 5ᵉ position, chargée depuis
       Google Fonts par un <link> bloquant le rendu sur les 7 pages. Sur
       matériel Apple elle ne s'affichait jamais — SF Pro passe avant — mais
       sur Windows et Android elle passait devant Segoe UI et Roboto, pour deux
       allers-retours réseau sur le chemin critique. Le <link> et la police ont
       été retirés ensemble : garder le nom sans le fichier aurait laissé la
       police s'appliquer chez les rares personnes qui l'ont installée, donc
       deux rendus différents sans moyen de le savoir. */
    font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text", "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
    scroll-behavior: smooth;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

/* font-family est la seule propriété que « * » apportait réellement : elle
   hérite partout SAUF sur les contrôles de formulaire, qui retombent sinon
   sur la police du système. On reproduit exactement ce périmètre — pas plus,
   sous peine de changer la line-height des boutons. */
input,
select,
textarea,
button {
    font-family: inherit;
}

body {
    min-height: 100svh;
    display: flex;
    flex-direction: column;
    /* Couleur de fond explicite et opaque : Safari 26 ne lit plus la balise
       theme-color et déduit la teinte de sa barre d'outils depuis cette
       propriété (et depuis les éléments sticky en bord d'écran). */
    background-color: var(--surface-0);
    color: var(--text);
    overflow-x: hidden;
    line-height: 1.6;
}

/* Lien d'évitement : invisible tant qu'il n'a pas le focus, puis
   parfaitement lisible. Permet à un utilisateur clavier de sauter la
   navigation, répétée à l'identique sur les 7 pages. */
.skip-link {
    position: absolute;
    left: 8px;
    top: 8px;
    z-index: var(--z-overlay);
    padding: 12px 20px;
    border-radius: var(--r-sm);
    background: var(--brand);
    color: var(--brand-contrast);
    font-weight: 600;
    text-decoration: none;
    translate: 0 -150%;
    transition: translate var(--dur-2) var(--ease-out);
}

.skip-link:focus-visible {
    translate: 0 0;
}

/* Confort de lecture : équilibre les titres courts, évite les lignes
   orphelines dans les paragraphes. Ignoré si non supporté. */
h1,
h2,
h3 {
    text-wrap: balance;
}

p,
li {
    text-wrap: pretty;
}

/* .line-reveal découpe déjà le titre en blocs : on laisse chaque ligne se
   replier normalement sur petit écran. Surtout pas nowrap, qui provoquerait
   un débordement horizontal sur mobile. */
.line-reveal .line>* {
    text-wrap: auto;
}

/* ── Zones sûres & confort de défilement ──
   env(safe-area-inset-top) n'est PAS ajouté à la navbar : il vaut 0 en
   Safari classique et créerait un vide de 47 px pour rien. Ce sont les
   côtés (paysage sur appareil à encoche) et le bas qui comptent. */
html {
    scrollbar-gutter: stable;
    /* Empêche le rebond élastique de la page derrière les panneaux fixes. */
    overscroll-behavior-y: none;
}

.navbar {
    padding-left: max(5%, env(safe-area-inset-left));
    padding-right: max(5%, env(safe-area-inset-right));
}

footer {
    margin-top: auto;
    padding-bottom: calc(40px + env(safe-area-inset-bottom));
}

/* Barre de défilement discrète, accordée au thème.
   color-scheme fait déjà l'essentiel ; ceci n'est que du raffinement. */
@supports (scrollbar-color: auto) {
    html {
        scrollbar-color: var(--border-strong) transparent;
        scrollbar-width: thin;
    }
}

::-webkit-scrollbar {
    width: 10px;
    height: 10px;
}

::-webkit-scrollbar-thumb {
    background: var(--border-strong);
    border-radius: var(--r-pill);
    border: 3px solid var(--surface-0);
    background-clip: padding-box;
}

/* Cases à cocher, sélecteurs, curseurs natifs : à la couleur de la marque. */
:root {
    accent-color: var(--brand);
}

::selection {
    background-color: var(--brand);
    color: var(--brand-contrast);
}

/* Ancres (#contact…) : la cible ne se cache plus sous la navbar sticky */
section[id],
[id].contact-section {
    scroll-margin-top: calc(var(--nav-h) + 20px);
}

/* Pas de flash gris au tap sur iOS/Android */
a,
button {
    -webkit-tap-highlight-color: transparent;
}

/* Focus clavier visible et propre sur tous les éléments interactifs */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
.hamburger:focus-visible {
    outline: 2px solid var(--brand-text);
    outline-offset: 3px;
    border-radius: 6px;
}

/* =============================================
   NAVBAR — FROSTED GLASS
   ============================================= */
.navbar {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 16px 5%;
    background-color: var(--surface-glass);
    backdrop-filter: saturate(180%) blur(20px);
    -webkit-backdrop-filter: saturate(180%) blur(20px);
    box-shadow: 0 1px 0 rgb(var(--shadow-rgb) / calc(0.08 * var(--shadow-k)));
    position: sticky;
    top: 0;
    z-index: var(--z-nav);
    transition: background-color 0.3s ease, box-shadow 0.3s ease;
    min-height: 64px;
}

.logo {
    height: 40px;
    width: auto;
}

/* ─────────────────────────────────────────────────────────────
   BOUTONS — 4 NIVEAUX

   Auparavant chaque bouton faisait le même translateY(-6px) + ombre.
   Un aplat de couleur qui saute fait « bon marché » ; on lui donne du
   poids plutôt que du saut. Règle générale du système :
     survol   entrée rapide  (--dur-2, 180 ms)
     sortie   lente          (--dur-3, 320 ms)
     appui    le plus rapide (--dur-1, 110 ms)
   ───────────────────────────────────────────────────────────── */

/* NIVEAU 1 — plein : le bouton prend du poids, il ne bondit pas. */
.btn-nav {
    background-color: var(--brand);
    color: var(--brand-contrast);
    padding: 10px 24px;
    border-radius: var(--r-pill);
    text-decoration: none;
    font-weight: 600;
    position: relative;
    overflow: hidden;
    isolation: isolate;
    box-shadow: 0 6px 20px -4px rgb(var(--brand-rgb) / 0.3);
    transition:
        transform var(--dur-3) var(--ease-out),
        box-shadow var(--dur-3) var(--ease-out),
        filter var(--dur-3) var(--ease-out);
}

/* Le survol a été accentué après le retrait de l'effet magnétique : c'est
   désormais le seul retour au pointeur, il doit donc se voir. La levée passe
   à 2 px, un léger grossissement l'accompagne, et l'ombre fleurit franchement
   plus loin. Le tout reste en transform + filter, jamais en géométrie. */
.btn-nav:hover {
    transform: translateY(-2px) scale(1.02);
    filter: brightness(1.09) saturate(1.05);
    box-shadow:
        0 18px 42px -10px rgb(var(--brand-rgb) / 0.55),
        0 0 0 1px rgb(var(--brand-rgb) / 0.18);
    transition-duration: var(--dur-2);
    transition-timing-function: var(--ease-spring);
}

/* Balayage de brillance : transform seul, donc compositeur pur.
   Bande plus étroite et deux fois plus lumineuse qu'à l'origine — à 18 % sur
   une bande large, le reflet se devinait sans se voir. */
.btn-nav::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: -1;
    background: linear-gradient(100deg,
            transparent 38%,
            rgb(255 255 255 / 0.30) 50%,
            transparent 62%);
    translate: -140% 0;
}

.btn-nav:hover::before {
    animation: btn-sheen 520ms var(--ease-out);
}

@keyframes btn-sheen {
    to {
        translate: 140% 0;
    }
}

/* État « scrolled » : ombre portée + fond légèrement plus opaque,
   piloté par une classe (script.js) plutôt qu'en style inline */
.navbar.scrolled {
    background-color: var(--surface-glass-dim);
    box-shadow: 0 2px 20px rgb(var(--shadow-rgb) / calc(0.08 * var(--shadow-k)));
}

/* Feedback d'appui : le bouton « cède » sous le doigt/clic */
.btn-nav:active,
.btn-hero-secondary:active,
.btn-email:active,
.btn-helloasso:active,
.btn-submit-large:active,
.insta-button:active {
    transform: translateY(0) scale(0.96);
    filter: brightness(0.98);
    transition-duration: var(--dur-1);
    transition-timing-function: var(--ease-out);
}

/* ─────────────────────────────────────────────────────────────
   TACTILE — indispensable, pas un détail.

   Sur iOS et Android, un tap déclenche :hover et l'état RESTE COLLÉ
   après le retrait du doigt : la carte demeure soulevée, le bouton
   éclairci. C'est le bug « pourquoi ça reste allumé » classique.
   On neutralise donc tout survol dès que le pointeur n'est pas fin,
   et on le remplace par un retour d'appui immédiat.
   ───────────────────────────────────────────────────────────── */
@media (hover: none) {

    /* ⚠ Cette règle a longtemps été cassée : la liste de sélecteurs se
       poursuivait jusqu'à « .btn-nav:hover::before », si bien que le bloc
       entier ne déclarait qu'« animation: none ». Le soulèvement, le
       brightness et la floraison d'ombre restaient donc parfaitement collés
       après un tap — exactement le bug que ce bloc existe pour empêcher.
       Deux règles distinctes désormais, et surtout pas une virgule de plus.

       On neutralise le MOUVEMENT, pas l'ombre : mettre « box-shadow: none »
       ici aplatirait la carte tant que le survol reste collé, ce qui se voit
       bien davantage qu'une ombre un peu plus marquée. */
    .btn-nav:hover,
    .btn-hero-secondary:hover,
    .btn-email:hover,
    .btn-helloasso:hover,
    .btn-submit-large:hover,
    .insta-button:hover,
    .step-card:hover,
    .stat-card:hover,
    .info-card:hover,
    .testimonial-card:hover,
    .gallery-card:hover,
    .support-content:hover,
    .hype-counter-card:hover {
        transform: none;
        translate: none;
        scale: none;
        filter: none;
    }

    .btn-nav:hover::before {
        animation: none;
    }

    .btn-nav:active,
    .btn-hero-secondary:active,
    .btn-email:active,
    .btn-helloasso:active,
    .btn-submit-large:active,
    .insta-button:active {
        transform: scale(0.97);
    }

    .step-card:active,
    .stat-card:active,
    .info-card:active,
    .testimonial-card:active,
    .gallery-card:active {
        transform: scale(0.985);
        transition-duration: var(--dur-1);
    }
}

/* =============================================
   DÉCOR — COUCHES DE FOND

   Principe directeur : AUCUN filter: blur().
   Un blur(80px) sur un élément de 500 px force un tampon hors écran, des
   passes de flou à la densité de l'appareil et une recomposition à chaque
   frame de scroll — première cause de saccade sur Android milieu de gamme.
   Un radial-gradient aux arrêts doux donne la même tache, pour un coût de
   rastérisation nul, et s'anime en transform seul.

   Trois couches, jamais toutes sur la même section :
     .bg-dots    trame de points, masquée en radial (hero, CTA)
     .bg-aurora  taches colorées en dérive lente (hero, CTA)
     body::after grain, une tuile fixe sur tout le site
   ============================================= */

.bg-decor {
    position: relative;
    isolation: isolate;
    /* L'aurore est posée en « inset: -20% » pour que ses taches entrent dans
       le cadre sans laisser voir leurs bords : elle déborde donc de 20 % de
       chaque côté, par construction. Sans clip ici, ce débordement devient un
       défilement horizontal de la page entière — constaté sur la 404, dont le
       décor couvre toute la hauteur du <main>.
       « clip » et non « hidden » : il ne crée pas de conteneur de
       défilement, donc il ne casse ni les ancres ni position: sticky. */
    overflow: clip;
}

.bg-decor>* {
    position: relative;
    z-index: 1;
}

/* ── Trame de points ─────────────────────────────────────────
   Une tuile de 26 px répétée par le GPU, masquée en radial pour
   qu'elle ne rencontre jamais de bord franc. Coût quasi nul. */
.bg-dots::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    background-image: radial-gradient(circle at 1px 1px, var(--dot) 1px, transparent 0);
    background-size: 26px 26px;
    -webkit-mask-image: radial-gradient(ellipse 90% 65% at 50% 8%, #000 30%, transparent 78%);
    mask-image: radial-gradient(ellipse 90% 65% at 50% 8%, #000 30%, transparent 78%);
}

/* ── Aurore ──────────────────────────────────────────────────
   Trois taches de couleur, animées en transform uniquement :
   une seule couche composée, zéro repeint au scroll. */
.bg-aurora::after {
    content: '';
    position: absolute;
    inset: -20%;
    z-index: 0;
    pointer-events: none;
    opacity: var(--aurora-o);
    background:
        radial-gradient(46% 38% at 18% 22%, var(--brand) 0%, transparent 62%),
        radial-gradient(40% 34% at 82% 12%, #0DCAF0 0%, transparent 64%),
        radial-gradient(52% 42% at 58% 88%, #3D8BFD 0%, transparent 66%);
    animation: aurora-drift 26s var(--ease-in-out) infinite alternate;
    will-change: transform;
}

@keyframes aurora-drift {
    from {
        transform: translate3d(-3%, -2%, 0) scale(1);
    }

    to {
        transform: translate3d(3%, 2%, 0) scale(1.08);
    }
}

/* ── Grain ───────────────────────────────────────────────────
   Une tuile feTurbulence de 160 px en data-URI (~700 octets),
   rastérisée une fois. position: fixed + will-change pour que le
   moteur promeuve la couche au lieu de repeindre un calque de
   fusion plein écran à chaque frame. */
body::after {
    content: '';
    position: fixed;
    inset: 0;
    z-index: var(--z-grain);
    pointer-events: none;
    opacity: var(--grain-o);
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.82' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='.5'/%3E%3C/svg%3E");
    background-size: 160px;
    mix-blend-mode: overlay;
    will-change: transform;
}

@media (prefers-color-scheme: dark) {
    body::after {
        mix-blend-mode: soft-light;
    }
}

/* Sur mobile : une seule tache et aucune dérive. Trois dégradés radiaux
   animés sur un GPU de téléphone d'entrée de gamme ne valent pas leur prix. */
@media (max-width: 768px) {
    .bg-aurora::after {
        background: radial-gradient(70% 46% at 50% 8%, var(--brand) 0%, transparent 66%);
        animation: none;
    }
}

@media (prefers-reduced-motion: reduce) {
    .bg-aurora::after {
        animation: none;
    }
}

/* =============================================
   HERO — APPLE STYLE (CENTRÉ, TYPOGRAPHIE XXL)
   ============================================= */
.hero-apple {
    min-height: 85vh;
    min-height: 85svh;
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    padding: 120px 5% 80px 5%;
    /* Fond plat : le dégradé vertical blanc → bleu → blanc a été retiré.
       Le relief vient désormais des couches .bg-dots et .bg-aurora. */
    background-color: var(--surface-0);
    position: relative;
    overflow: hidden;
}

.hero-apple-content {
    max-width: 900px;
    width: 100%;
    position: relative;
    z-index: 2;
}

.hero-overline {
    display: inline-block;
    background-color: rgba(0, 85, 255, 0.08);
    color: var(--brand-text);
    padding: 8px 20px;
    border-radius: 50px;
    font-weight: 600;
    font-size: 0.9rem;
    margin-bottom: 30px;
    letter-spacing: 0.02em;
}

.hero-apple h1 {
    font-size: 4.5rem;
    font-weight: 800;
    line-height: 1.08;
    letter-spacing: -2.5px;
    margin-bottom: 25px;
    color: var(--text);
}

.hero-gradient-text {
    background: linear-gradient(135deg, var(--brand) 0%, #3d8bfd 50%, #0dcaf0 100%);
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
}

.hero-subtitle {
    font-size: 1.25rem;
    color: var(--text-muted);
    max-width: 650px;
    margin: 0 auto 45px auto;
    line-height: 1.7;
    font-weight: 400;
}

.hero-cta-group {
    display: flex;
    gap: 16px;
    justify-content: center;
    align-items: center;
    flex-wrap: wrap;
}

.btn-hero-primary {
    font-size: 1.05rem;
    padding: 16px 36px;
}

.btn-hero-secondary {
    display: inline-block;
    color: var(--brand-text);
    font-weight: 600;
    font-size: 1.05rem;
    text-decoration: none;
    padding: 16px 36px;
    border-radius: 50px;
    background-color: var(--brand-soft);
    transition: background-color var(--dur-3) var(--ease-out), box-shadow var(--dur-3) var(--ease-out), transform var(--dur-3) var(--ease-out);
}

/* NIVEAU 2 — teinté : AUCUN mouvement. La teinte et un anneau interne
   portent tout l'effet ; un bouton secondaire qui saute vole la vedette
   au bouton principal placé juste à côté. */
.btn-hero-secondary:hover {
    background-color: rgb(var(--brand-rgb) / 0.16);
    box-shadow: inset 0 0 0 1px rgb(var(--brand-rgb) / 0.28);
    transition-duration: var(--dur-2);
}

/* =============================================
   VISUAL PLACEHOLDERS
   ============================================= */
.visual-showcase {
    padding: 40px 5% 100px 5%;
    /* Ceinture et bretelles : la grappe de téléphones est composée de marges
       négatives et de rotations 3D. Aucune régression future ne doit pouvoir
       la faire repartir en défilement horizontal. « clip » plutôt que
       « hidden » : il ne crée pas de conteneur de défilement, donc il ne
       casse ni les ancres ni position: sticky. */
    overflow-x: clip;
}

.visual-showcase-inner {
    max-width: 1100px;
    margin: 0 auto;
}





/* Visual section side-by-side */
.visual-section-full {
    padding: var(--section-padding);
}

.visual-section-full.bg-gray {
    background-color: var(--surface-2);
}

.visual-section-inner {
    max-width: 1200px;
    margin: 0 auto;
    display: flex;
    align-items: center;
    gap: 80px;
}

.visual-text-side {
    flex: 1;
    max-width: 500px;
}

.visual-text-side h2 {
    font-size: 2.8rem;
    font-weight: 700;
    letter-spacing: -1.5px;
    line-height: 1.15;
    margin-bottom: 20px;
    color: var(--text);
}

.visual-text-side p {
    font-size: 1.1rem;
    color: var(--text-muted);
    line-height: 1.7;
}



/* =============================================
   SECTION HEADERS (SHARED)
   ============================================= */
.section-header {
    text-align: center;
    margin-bottom: 60px;
}

.section-header h2 {
    font-size: 3rem;
    font-weight: 700;
    letter-spacing: -1.5px;
    color: var(--text);
    margin-bottom: 12px;
}

.section-subtitle {
    font-size: 1.15rem;
    color: var(--text-muted);
    font-weight: 400;
}

/* =============================================
   COMMENT ÇA MARCHE
   ============================================= */
.section-how-it-works {
    padding: var(--section-padding);
    background-color: var(--surface-0);
}

.steps-grid {
    display: flex;
    gap: 24px;
    max-width: 1200px;
    margin: 0 auto;
    flex-wrap: wrap;
    justify-content: center;
}

.step-card {
    flex: 1;
    min-width: 240px;
    max-width: 280px;
    background: var(--surface-1);
    border: 1px solid rgba(0, 0, 0, 0.06);
    border-radius: var(--border-radius-card);
    padding: 45px 30px;
    text-align: center;
    position: relative;
    transition: transform 0.4s var(--transition-smooth), box-shadow 0.4s var(--transition-smooth), border-color 0.4s var(--transition-smooth);
}

.step-card:hover {
    transform: translateY(-8px);
    box-shadow: 0 20px 50px rgb(var(--shadow-rgb) / calc(0.08 * var(--shadow-k)));
    border-color: rgb(var(--brand-rgb) / 0.18);
    transition-duration: var(--dur-2);
}

.step-card:hover .step-number {
    transform: translateX(-50%) scale(1.08);
}

.step-number {
    position: absolute;
    top: -16px;
    left: 50%;
    transform: translateX(-50%);
    width: 36px;
    height: 36px;
    background-color: var(--brand);
    color: white;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 700;
    font-size: 0.85rem;
    box-shadow: 0 4px 12px rgb(var(--brand-rgb) / 0.25);
}

.step-icon {
    font-size: 2.5rem;
    margin-bottom: 20px;
    margin-top: 10px;
}

.step-card h3 {
    font-size: 1.15rem;
    font-weight: 700;
    color: var(--text);
    margin-bottom: 12px;
}

.step-card p {
    font-size: 0.92rem;
    color: var(--text-muted);
    line-height: 1.6;
}

/* =============================================
   CHIFFRES CLÉS
   ============================================= */
.section-stats {
    padding: var(--section-padding);
    background-color: var(--surface-0);
}

.stats-grid {
    display: flex;
    gap: 30px;
    max-width: 1100px;
    margin: 0 auto;
    flex-wrap: wrap;
    justify-content: center;
}

.stat-card {
    flex: 1;
    min-width: 200px;
    max-width: 250px;
    text-align: center;
    padding: 40px 20px;
    border-radius: var(--border-radius-card);
    background: var(--surface-1);
    border: 1px solid var(--hairline);
    transition: transform 0.4s var(--transition-smooth), box-shadow 0.4s var(--transition-smooth), border-color 0.4s var(--transition-smooth);
    position: relative;
}

/* Les chiffres ne sautent pas : ils s'intensifient. */
.stat-card:hover {
    box-shadow: 0 15px 40px rgb(var(--brand-rgb) / 0.10);
    border-color: rgb(var(--brand-rgb) / 0.22);
}

.stat-number {
    font-size: 3.2rem;
    font-weight: 800;
    color: var(--brand-text);
    letter-spacing: -2px;
    line-height: 1;
    display: inline;
}

.stat-suffix {
    font-size: 2rem;
    font-weight: 700;
    color: var(--brand-text);
    display: inline;
    position: relative;
    top: -8px;
}

.stat-label {
    font-size: 0.95rem;
    color: var(--text-muted);
    margin-top: 10px;
    font-weight: 500;
}

/* =============================================
   TÉMOIGNAGES
   ============================================= */
.section-testimonials {
    padding: var(--section-padding);
}

.section-testimonials.bg-gray {
    background-color: var(--surface-2);
}

.testimonials-grid {
    display: flex;
    gap: 30px;
    max-width: 1100px;
    margin: 0 auto;
    flex-wrap: wrap;
    justify-content: center;
}

.testimonial-card {
    flex: 1;
    min-width: 280px;
    max-width: 350px;
    background: var(--surface-1);
    border-radius: var(--border-radius-card);
    padding: 40px 30px 30px 30px;
    box-shadow: 0 4px 20px rgb(var(--shadow-rgb) / calc(0.04 * var(--shadow-k)));
    border: 1px solid rgba(0, 0, 0, 0.04);
    transition: transform 0.4s var(--transition-smooth), box-shadow 0.4s var(--transition-smooth);
    position: relative;
}

/* Une citation ne bondit pas : c'est le guillemet décoratif qui s'anime. */
.testimonial-card:hover {
    box-shadow: 0 15px 45px rgb(var(--shadow-rgb) / calc(0.08 * var(--shadow-k)));
    border-color: rgb(var(--brand-rgb) / 0.18);
}

.testimonial-card .testimonial-quote {
    transition: opacity var(--dur-3) var(--ease-out), transform var(--dur-3) var(--ease-out);
}

.testimonial-card:hover .testimonial-quote {
    opacity: 0.3;
    transform: scale(1.06);
    transition-duration: var(--dur-2);
}

.testimonial-quote {
    font-size: 4rem;
    font-weight: 800;
    color: var(--brand-text);
    opacity: 0.15;
    line-height: 1;
    position: absolute;
    top: 15px;
    left: 25px;
}

.testimonial-text {
    font-size: 1rem;
    color: var(--text);
    line-height: 1.65;
    margin-bottom: 25px;
    position: relative;
    z-index: 2;
}

.testimonial-author {
    display: flex;
    align-items: center;
    gap: 14px;
}

.testimonial-avatar {
    width: 44px;
    height: 44px;
    border-radius: 50%;
    background: linear-gradient(135deg, var(--brand) 0%, #3d8bfd 100%);
    color: white;
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 700;
    font-size: 1rem;
    flex-shrink: 0;
}

.testimonial-name {
    font-weight: 600;
    font-size: 0.9rem;
    color: var(--text);
}

.testimonial-role {
    font-size: 0.8rem;
    color: var(--text-muted);
}

/* =============================================
   HELLOASSO SUPPORT SECTION
   ============================================= */
.support-section {
    padding: 80px 5%;
    display: flex;
    justify-content: center;
    align-items: center;
    background-color: var(--surface-0);
}

.support-content {
    background: linear-gradient(135deg, var(--support-tint) 0%, var(--surface-1) 100%);
    border: 1px solid rgba(0, 85, 255, 0.1);
    border-radius: 40px;
    padding: 60px;
    text-align: center;
    max-width: 800px;
    width: 100%;
    box-shadow: 0 20px 40px rgb(var(--brand-rgb) / 0.05);
    transition: transform 0.5s var(--transition-smooth), box-shadow 0.5s var(--transition-smooth);
}

.support-content:hover {
    transform: translateY(-5px);
    box-shadow: 0 30px 60px rgb(var(--brand-rgb) / 0.08);
}

.support-content h2 {
    font-size: 2.2rem;
    color: var(--brand-text);
    margin-bottom: 15px;
    letter-spacing: -0.5px;
}

.support-content p {
    font-size: 1.1rem;
    color: var(--text-muted);
    margin-bottom: 35px;
    line-height: 1.6;
}

.btn-helloasso {
    display: inline-flex;
    align-items: center;
    gap: 12px;
    background-color: var(--brand);
    color: white;
    padding: 18px 40px;
    border-radius: 50px;
    text-decoration: none;
    font-weight: 700;
    font-size: 1.15rem;
    transition: transform 0.3s var(--transition-smooth), box-shadow 0.3s var(--transition-smooth), background-color 0.3s var(--transition-smooth);
    box-shadow: 0 10px 25px rgb(var(--brand-rgb) / 0.3);
}

.btn-helloasso:hover {
    transform: translateY(-3px) scale(1.02);
    box-shadow: 0 15px 35px rgb(var(--brand-rgb) / 0.4);
    background-color: var(--brand-hover);
}

.btn-helloasso svg {
    transition: transform 0.3s ease;
}

.btn-helloasso:hover svg {
    transform: scale(1.1);
}

/* =============================================
   CONTACT SECTION
   ============================================= */
.contact-section {
    background-color: var(--brand-soft);
    padding: 100px 5%;
    text-align: center;
}

.contact-section h2 {
    font-size: 2.8rem;
    color: var(--brand-text);
    margin-bottom: 10px;
    letter-spacing: -1px;
}

.contact-section>p {
    color: var(--text-muted);
    margin-bottom: 50px;
    font-size: 1.1rem;
}

.info-grid {
    display: flex;
    justify-content: center;
    gap: 24px;
    max-width: 1000px;
    margin: 0 auto 60px auto;
    flex-wrap: wrap;
}

.info-card {
    background: var(--surface-1);
    padding: 35px 25px;
    border-radius: 18px;
    flex: 1;
    min-width: 250px;
    box-shadow: 0 4px 15px rgb(var(--shadow-rgb) / calc(0.05 * var(--shadow-k)));
    text-align: left;
    border-top: 4px solid var(--brand-text);
    transition: transform 0.4s var(--transition-smooth), box-shadow 0.4s var(--transition-smooth);
}

/* Le liseré supérieur s'épaissit et prend le dégradé de marque. */
.info-card:hover {
    transform: translateY(-4px);
    box-shadow: 0 15px 40px rgb(var(--shadow-rgb) / calc(0.08 * var(--shadow-k)));
    border-top-color: transparent;
    background-image: linear-gradient(var(--surface-1), var(--surface-1)), var(--brand-grad);
    background-origin: border-box;
    background-clip: padding-box, border-box;
}

.info-card h3 {
    color: var(--brand-text);
    margin-bottom: 15px;
    font-size: 1.2rem;
}

.info-card p {
    color: var(--text-muted);
    font-size: 0.95rem;
    line-height: 1.5;
}

.contact-box {
    background: var(--surface-1);
    max-width: 500px;
    margin: 0 auto;
    padding: 45px;
    border-radius: 18px;
    box-shadow: 0 4px 20px rgb(var(--shadow-rgb) / calc(0.05 * var(--shadow-k)));
}

.contact-box h3 {
    margin-bottom: 10px;
    color: var(--text);
    font-size: 1.3rem;
}

.contact-box p {
    margin-bottom: 25px;
    color: var(--text-muted);
}

.btn-email {
    display: inline-block;
    background-color: var(--brand-soft);
    color: var(--brand-text);
    padding: 15px 30px;
    border-radius: 50px;
    text-decoration: none;
    font-weight: 600;
    transition: background-color 0.3s var(--transition-smooth), color 0.3s var(--transition-smooth);
    font-size: 1.1rem;
}

.btn-email:hover {
    background-color: var(--brand);
    color: white;
}

/* =============================================
   COUNTDOWN RENTRÉE 2026
   ============================================= */
.countdown-wrapper {
    margin-top: 50px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 16px;
}

.countdown-label {
    font-size: 0.9rem;
    font-weight: 600;
    color: var(--text-muted);
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

.countdown-grid {
    display: flex;
    align-items: center;
    gap: 12px;
    background: var(--surface-panel);
    backdrop-filter: blur(20px);
    -webkit-backdrop-filter: blur(20px);
    border: 1px solid rgba(0, 85, 255, 0.12);
    border-radius: 20px;
    padding: 20px 32px;
    box-shadow: 0 8px 32px rgb(var(--brand-rgb) / 0.08);
}

.countdown-unit {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    min-width: 56px;
}

.countdown-number {
    font-size: 2.4rem;
    font-weight: 800;
    letter-spacing: -2px;
    color: var(--brand-text);
    line-height: 1;
    font-variant-numeric: tabular-nums;
    transition: transform 0.2s var(--transition-spring);
}

.countdown-number.tick {
    transform: scale(1.15);
}

.countdown-unit-label {
    font-size: 0.7rem;
    font-weight: 600;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

.countdown-separator {
    font-size: 2rem;
    font-weight: 800;
    color: var(--brand-text);
    opacity: 0.3;
    line-height: 1;
    margin-bottom: 18px;
}

.countdown-sublabel {
    font-size: 0.85rem;
    color: var(--text-muted);
    font-weight: 500;
}

/* =============================================
   HYPE SECTION — JE VEUX BINÔME
   ============================================= */
.hype-section {
    padding: 90px 5%;
    background-color: var(--surface-0);
    position: relative;
    overflow: hidden;
    display: flex;
    justify-content: center;
    align-items: center;
}

.hype-inner {
    text-align: center;
    max-width: 640px;
    width: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 20px;
}

.hype-eyebrow {
    display: inline-block;
    background-color: rgba(0, 85, 255, 0.08);
    color: var(--brand-text);
    padding: 6px 18px;
    border-radius: 50px;
    font-weight: 600;
    font-size: 0.85rem;
    letter-spacing: 0.02em;
}

.hype-title {
    font-size: 2.6rem;
    font-weight: 800;
    letter-spacing: -1.5px;
    color: var(--text);
    line-height: 1.1;
    margin: 0;
}

.hype-subtitle {
    font-size: 1.05rem;
    color: var(--text-muted);
    line-height: 1.65;
    max-width: 480px;
    margin: 0;
}

.btn-hype {
    display: inline-flex;
    align-items: center;
    gap: 12px;
    background: linear-gradient(135deg, var(--brand) 0%, #3d8bfd 100%);
    color: white;
    border: none;
    padding: 20px 48px;
    border-radius: 50px;
    font-size: 1.2rem;
    font-weight: 700;
    cursor: pointer;
    box-shadow: 0 12px 35px rgb(var(--brand-rgb) / 0.35);
    transition: transform 0.3s var(--transition-spring), box-shadow 0.3s var(--transition-smooth);
    position: relative;
    overflow: hidden;
    animation: hype-pulse 2.5s ease-in-out infinite;
}

@keyframes hype-pulse {

    0%,
    100% {
        box-shadow: 0 12px 35px rgb(var(--brand-rgb) / 0.35);
    }

    50% {
        box-shadow: 0 16px 50px rgb(var(--brand-rgb) / 0.55);
    }
}

.btn-hype:hover {
    transform: translateY(-4px) scale(1.04);
    box-shadow: 0 20px 50px rgb(var(--brand-rgb) / 0.45);
    animation: none;
}

.btn-hype:active {
    transform: scale(0.96);
}

.btn-hype.voted {
    background: linear-gradient(135deg, #22c55e 0%, #16a34a 100%);
    box-shadow: 0 12px 35px rgba(34, 197, 94, 0.35);
    animation: none;
    cursor: default;
}

.hype-btn-icon {
    font-size: 1.4rem;
    transition: transform 0.3s var(--transition-spring);
}

.btn-hype:hover .hype-btn-icon {
    transform: rotate(-10deg) scale(1.2);
}

/* Ripple effect */
.btn-hype::after {
    content: '';
    position: absolute;
    top: 50%;
    left: 50%;
    width: 0;
    height: 0;
    background: rgba(255, 255, 255, 0.3);
    border-radius: 50%;
    transform: translate(-50%, -50%);
    transition: width 0.4s ease, height 0.4s ease, opacity 0.4s ease;
    opacity: 0;
}

.btn-hype:active::after {
    width: 300px;
    height: 300px;
    opacity: 0;
}

/* ── Floating counter card ── */
.hype-counter-card {
    background: var(--surface-panel-2);
    backdrop-filter: blur(24px);
    -webkit-backdrop-filter: blur(24px);
    border: 1.5px solid rgba(0, 85, 255, 0.14);
    border-radius: 28px;
    padding: 36px 56px 28px 56px;
    box-shadow:
        0 20px 60px rgb(var(--brand-rgb) / 0.10),
        0 4px 16px rgb(var(--brand-rgb) / 0.06),
        inset 0 1px 0 var(--edge-hilite);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    transition: transform 0.4s var(--transition-smooth), box-shadow 0.4s var(--transition-smooth);
}

.hype-counter-card:hover {
    transform: translateY(-6px) scale(1.01);
    box-shadow:
        0 30px 80px rgb(var(--brand-rgb) / 0.15),
        0 6px 20px rgb(var(--brand-rgb) / 0.08),
        inset 0 1px 0 var(--edge-hilite);
}

.hype-counter-label {
    font-size: 0.8rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--brand-text);
    opacity: 0.7;
    margin: 0;
}

.hype-counter-sublabel {
    font-size: 0.82rem;
    color: var(--text-muted);
    font-weight: 500;
    margin: 0;
}

/* ── Slot-machine display ── */
.hype-slot-display {
    display: flex;
    align-items: center;
    gap: 4px;
}

.hype-slot-col {
    width: 52px;
    height: 80px;
    overflow: hidden;
    position: relative;
    border-radius: 12px;
    background: linear-gradient(145deg, rgba(0, 85, 255, 0.06) 0%, rgba(0, 85, 255, 0.03) 100%);
    border: 1px solid rgba(0, 85, 255, 0.10);
}

/* Top/bottom fade mask */
.hype-slot-col::before,
.hype-slot-col::after {
    content: '';
    position: absolute;
    left: 0;
    right: 0;
    height: 20px;
    z-index: 2;
    pointer-events: none;
}

.hype-slot-col::before {
    top: 0;
    background: linear-gradient(to bottom, var(--slot-fade), transparent);
}

.hype-slot-col::after {
    bottom: 0;
    background: linear-gradient(to top, var(--slot-fade), transparent);
}

.hype-slot-inner {
    display: flex;
    flex-direction: column;
    align-items: center;
    transition: transform 0.45s cubic-bezier(0.34, 1.20, 0.64, 1);
    will-change: transform;
}

.hype-slot-digit {
    width: 52px;
    height: 80px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 3.2rem;
    font-weight: 800;
    letter-spacing: -3px;
    color: var(--brand-text);
    line-height: 1;
    font-variant-numeric: tabular-nums;
    flex-shrink: 0;
}

.hype-slot-sep {
    font-size: 3rem;
    font-weight: 800;
    color: var(--brand-text);
    opacity: 0.20;
    line-height: 80px;
    padding-bottom: 8px;
    letter-spacing: -1px;
}

.hype-already {
    font-size: 0.95rem;
    color: #22c55e;
    font-weight: 600;
    margin: 0;
}

/* Message d'échec du vote. Il n'apparaît que si le serveur a refusé
   l'écriture — auquel cas le bouton redevient actionnable. */
.hype-status {
    margin: 0;
    font-size: 0.9rem;
    font-weight: 500;
    color: var(--text-subtle);
    max-width: 32ch;
    text-wrap: pretty;
}

/* ── LISTE DE LANCEMENT ──
   Greffée sur le bouton hype plutôt que posée dans une section à elle : on
   demande l'adresse à l'instant précis où la personne vient de manifester
   son intérêt, pas avant. */
.hype-notify {
    width: min(100%, 420px);
    margin-top: var(--sp-2);
    text-align: left;
}

.hype-notify-label {
    display: block;
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--text);
    margin-bottom: var(--sp-2);
}

.hype-notify-row {
    display: flex;
    gap: var(--sp-2);
}

.hype-notify-row input[type="email"] {
    flex: 1 1 auto;
    min-width: 0;
    padding: 12px 16px;
    border: 1px solid var(--field-border);
    border-radius: var(--r-pill);
    background: var(--field-bg);
    color: var(--text);
    font-size: 1rem;
}

.hype-notify-row input[type="email"]:focus-visible {
    outline: 2px solid var(--brand);
    outline-offset: 2px;
    border-color: transparent;
}

.hype-notify-row button {
    flex: 0 0 auto;
    /* 44 px minimum : c'est une cible tactile, pas une décoration. */
    min-width: 64px;
    min-height: 44px;
}

.hype-notify-check {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    margin-top: var(--sp-3);
    font-size: 0.9rem;
    color: var(--text-muted);
    cursor: pointer;
    /* Toute la ligne est cliquable, pas seulement la case de 16 px. */
    padding: 6px 0;
}

.hype-notify-legal {
    margin: var(--sp-2) 0 0;
    font-size: 0.78rem;
    line-height: 1.5;
    color: var(--text-subtle);
    text-wrap: pretty;
}

.hype-notify-legal a {
    color: inherit;
    text-decoration: underline;
    text-underline-offset: 0.18em;
}

.hype-notify-error {
    margin: var(--sp-2) 0 0;
    font-size: 0.85rem;
    font-weight: 500;
    color: #DC2626;
}

.hype-notify-done {
    margin: 0;
    font-size: 1rem;
    font-weight: 600;
    color: #22c55e;
    text-align: center;
}

.hype-share {
    margin-top: var(--sp-2);
    background: none;
    border: 0;
    color: var(--text-muted);
    font-size: 0.9rem;
    font-weight: 500;
    cursor: pointer;
    padding: 12px 16px;
    border-radius: var(--r-pill);
    transition: color var(--dur-2) var(--ease-out), background-color var(--dur-2) var(--ease-out);
}

@media (hover: hover) and (pointer: fine) {
    .hype-share:hover {
        color: var(--brand-text);
        background-color: var(--support-tint);
    }
}

/* =============================================
   FRISE D'AVANCEMENT

   Une <ol> : c'est une suite ordonnée d'étapes, et un lecteur d'écran doit
   l'annoncer comme telle. Le trait vertical et les pastilles sont dessinés
   en CSS, sur des ::before, donc invisibles aux technologies d'assistance.
   ============================================= */
.roadmap-section {
    padding: var(--section-padding);
    max-width: 720px;
    margin-inline: auto;
}

.roadmap {
    list-style: none;
    margin: var(--sp-7) 0 0;
    padding: 0;
}

.roadmap-step {
    position: relative;
    display: flex;
    gap: var(--sp-5);
    padding-bottom: var(--sp-7);
}

.roadmap-step:last-child {
    padding-bottom: 0;
}

/* Le trait qui relie les étapes. Il s'arrête à la dernière pastille au lieu
   de pendre dans le vide. */
.roadmap-step:not(:last-child)::before {
    content: '';
    position: absolute;
    left: 9px;
    top: 22px;
    bottom: 6px;
    width: 2px;
    background: var(--border-strong);
}

.roadmap-step.is-done:not(:last-child)::before {
    background: color-mix(in srgb, var(--brand) 45%, transparent);
}

.roadmap-marker {
    flex: 0 0 auto;
    width: 20px;
    height: 20px;
    margin-top: 2px;
    border-radius: 50%;
    border: 2px solid var(--border-strong);
    background: var(--surface-0);
    position: relative;
    z-index: 1;
}

.roadmap-step.is-done .roadmap-marker {
    border-color: var(--brand);
    background: var(--brand);
}

/* L'étape en cours : un anneau, et un point qui respire. */
.roadmap-step.is-current .roadmap-marker {
    border-color: var(--brand);
    background: var(--surface-0);
    box-shadow: 0 0 0 4px rgb(var(--brand-rgb) / 0.15);
}

.roadmap-step.is-current .roadmap-marker::after {
    content: '';
    position: absolute;
    inset: 3px;
    border-radius: 50%;
    background: var(--brand);
    animation: roadmap-pulse 2.4s var(--ease-in-out) infinite;
}

@keyframes roadmap-pulse {

    0%,
    100% {
        opacity: 1;
        scale: 1;
    }

    50% {
        opacity: 0.55;
        scale: 0.72;
    }
}

.roadmap-body h3 {
    margin: 0 0 4px;
    font-size: 1.05rem;
    font-weight: 650;
    color: var(--text);
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    flex-wrap: wrap;
}

.roadmap-body p {
    margin: 0;
    color: var(--text-muted);
    line-height: 1.65;
    text-wrap: pretty;
}

.roadmap-tag {
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--brand-text);
    background: var(--support-tint);
    border-radius: var(--r-pill);
    padding: 3px 10px;
}

/* Les étapes à venir sont là, mais en retrait : elles annoncent sans
   prétendre. */
.roadmap-step:not(.is-done):not(.is-current) .roadmap-body {
    opacity: 0.62;
}

/* =============================================
   FAQ

   <details name="faq"> donne l'accordéon exclusif nativement : ouvrir une
   question referme la précédente, sans une ligne de JavaScript. Les
   navigateurs sans le support du nom affichent simplement des blocs
   indépendamment repliables — un repli parfaitement acceptable.
   ============================================= */
.faq-section {
    padding: var(--section-padding);
    max-width: 780px;
    margin-inline: auto;
}

.faq-list {
    margin-top: var(--sp-7);
    display: flex;
    flex-direction: column;
    gap: var(--sp-3);
}

.faq-item {
    background: var(--surface-1);
    border: 1px solid var(--border);
    border-radius: var(--r-lg);
    overflow: hidden;
    transition: border-color var(--dur-2) var(--ease-out), box-shadow var(--dur-2) var(--ease-out);
}

.faq-item[open] {
    border-color: color-mix(in srgb, var(--brand) 28%, transparent);
    box-shadow: 0 10px 30px -14px rgb(var(--shadow-rgb) / calc(0.18 * var(--shadow-k)));
}

.faq-item summary {
    /* Retire le triangle par défaut sur Safari comme ailleurs. */
    list-style: none;
    cursor: pointer;
    padding: var(--sp-4) var(--sp-5);
    padding-inline-end: calc(var(--sp-5) + 28px);
    font-size: 1.05rem;
    font-weight: 600;
    color: var(--text);
    position: relative;
    /* 44 px de haut minimum, cible tactile. */
    min-height: 44px;
    display: flex;
    align-items: center;
    text-wrap: pretty;
}

.faq-item summary::-webkit-details-marker {
    display: none;
}

/* Chevron dessiné en CSS : deux traits qui pivotent. Aucun SVG, aucune
   police d'icônes, et il suit la couleur du texte. */
.faq-item summary::after {
    content: '';
    position: absolute;
    inset-inline-end: var(--sp-5);
    top: 50%;
    width: 10px;
    height: 10px;
    border-right: 2px solid var(--text-muted);
    border-bottom: 2px solid var(--text-muted);
    translate: 0 -70%;
    rotate: 45deg;
    transition: rotate var(--dur-2) var(--ease-out), border-color var(--dur-2) var(--ease-out);
}

.faq-item[open] summary::after {
    rotate: -135deg;
    translate: 0 -30%;
    border-color: var(--brand-text);
}

.faq-item summary:focus-visible {
    outline: 2px solid var(--brand);
    outline-offset: -2px;
}

.faq-answer {
    padding: 0 var(--sp-5) var(--sp-5);
    color: var(--text-muted);
    line-height: 1.7;
    text-wrap: pretty;
}

.faq-answer p {
    margin: 0;
}

.faq-answer a {
    color: var(--brand-text);
    text-decoration: underline;
    text-underline-offset: 0.18em;
}

/* =============================================
   BANDEAU DE CONSENTEMENT

   Construit par script.js, jamais présent dans le HTML : sans JavaScript,
   aucun traceur n'est chargé, donc aucun consentement n'a lieu d'être
   demandé.

   Non modal, volontairement : il informe et propose deux issues de poids
   strictement égal. « Refuser » et « Accepter » partagent la même taille, le
   même style et le même niveau — l'article 82 et les lignes directrices de la
   CNIL exigent que le refus soit aussi simple que l'accord.
   ============================================= */
.consent-banner {
    position: fixed;
    z-index: var(--z-overlay);
    inset-inline: var(--sp-3);
    bottom: calc(var(--sp-3) + env(safe-area-inset-bottom, 0px));
    background: var(--surface-glass);
    backdrop-filter: blur(14px);
    border: 1px solid var(--border-strong);
    border-radius: var(--r-lg);
    box-shadow: 0 24px 60px -18px rgb(var(--shadow-rgb) / calc(0.3 * var(--shadow-k)));
    padding: var(--sp-4);
    max-width: 620px;
    margin-inline: auto;
    animation: consent-in 320ms var(--ease-out-expo) both;
}

@keyframes consent-in {
    from {
        opacity: 0;
        transform: translateY(16px);
    }
}

.consent-inner {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-4);
}

.consent-text {
    flex: 1 1 300px;
    min-width: 0;
}

.consent-title {
    margin: 0 0 4px;
    font-weight: 700;
    font-size: 0.95rem;
    color: var(--text);
}

.consent-text p {
    margin: 0;
    font-size: 0.85rem;
    line-height: 1.55;
    color: var(--text-muted);
    text-wrap: pretty;
}

.consent-text a {
    color: var(--brand-text);
    text-decoration: underline;
    text-underline-offset: 0.18em;
}

.consent-actions {
    display: flex;
    gap: var(--sp-2);
    flex: 0 0 auto;
}

/* Les deux boutons sont rigoureusement identiques. Aucun n'est mis en avant
   par la couleur, la taille ou le contraste : c'est le point de conformité
   le plus souvent manqué, et le plus simple à tenir. */
.consent-btn {
    flex: 1 1 auto;
    min-height: 44px;
    padding: 11px 20px;
    border-radius: var(--r-pill);
    border: 1px solid var(--brand);
    background: transparent;
    color: var(--brand-text);
    font-size: 0.9rem;
    font-weight: 600;
    cursor: pointer;
    white-space: nowrap;
    transition: background-color var(--dur-2) var(--ease-out), color var(--dur-2) var(--ease-out);
}

@media (hover: hover) and (pointer: fine) {
    .consent-btn:hover {
        background-color: var(--brand);
        color: var(--brand-contrast);
    }
}

.consent-btn:active {
    transform: scale(0.97);
}

@media (max-width: 560px) {
    .consent-actions {
        width: 100%;
    }
}

/* Lien « Cookies » du pied de page : un <button>, parce qu'il ne navigue
   nulle part. Il doit néanmoins être indiscernable de ses voisins. */
.footer-consent-link {
    background: none;
    border: 0;
    font: inherit;
    cursor: pointer;
    color: var(--text-muted);
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 0.18em;
    text-decoration-color: color-mix(in srgb, currentColor 45%, transparent);
    display: inline-block;
    padding: 10px 6px;
    font-size: 0.85rem;
    transition: color var(--dur-2) var(--ease-out);
}

@media (hover: hover) and (pointer: fine) {
    .footer-consent-link:hover {
        color: var(--brand-text);
    }
}

/* =============================================
   PAGE 404

   L'idée sort de la marque : Binôme, c'est le partenaire — une 404, c'est
   donc le binôme qu'on ne trouve pas. Le zéro central devient un radar qui
   balaie, dessiné en conic-gradient sur la variable --angle déjà enregistrée
   plus haut par @property (sans cet enregistrement, un dégradé conique ne
   s'anime tout simplement pas : la valeur n'est pas interpolable).

   Aucune image, aucun script, et l'ensemble s'immobilise sous
   prefers-reduced-motion.
   ============================================= */
.notfound {
    /* svh et non vh : sur mobile, vh inclut la barre d'URL rétractable, ce
       qui décale la composition au premier défilement. */
    min-height: calc(100svh - var(--nav-h));
    display: grid;
    place-items: center;
    padding: var(--sp-9) 5% var(--sp-10);
    padding-bottom: calc(var(--sp-10) + env(safe-area-inset-bottom, 0px));
    text-align: center;
}

.notfound-inner {
    max-width: 720px;
    width: 100%;
}

/* ── Le glyphe 404 ── */
.notfound-code {
    margin: 0 0 var(--sp-5);
    line-height: 1;
}

/* Le « Erreur 404. » n'est lu que par les technologies d'assistance : le
   glyphe qui suit est décoratif, le message est porté par le <h1>. */
.notfound-sr {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

.notfound-glyphs {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.04em;
    font-size: clamp(5rem, 22vw, 11rem);
    font-weight: 800;
    letter-spacing: -0.04em;
    color: var(--text);
    /* Les chiffres n'ont pas à porter tout le poids visuel : c'est le radar
       qui doit accrocher l'œil. */
    opacity: 0.92;
}

/* ── Le radar ── */
.notfound-radar {
    position: relative;
    display: inline-block;
    /* Dimensionné en em : il suit le clamp() des chiffres à toutes les
       tailles d'écran, sans une seule media query. */
    width: 0.74em;
    height: 0.74em;
    border-radius: 50%;
    border: 0.045em solid color-mix(in srgb, var(--brand) 45%, transparent);
    isolation: isolate;
    overflow: hidden;
}

/* Anneau intérieur + point central : ce qui fait lire « radar » plutôt que
   « cercle qui tourne ». */
.notfound-radar::before {
    content: '';
    position: absolute;
    inset: 22%;
    border-radius: 50%;
    border: 0.03em solid color-mix(in srgb, var(--brand) 30%, transparent);
    box-shadow: inset 0 0 0 0.14em transparent;
}

/* Le balayage. Un secteur unique de 30°, qui tourne. */
.notfound-radar::after {
    content: '';
    position: absolute;
    inset: -1px;
    border-radius: 50%;
    background: conic-gradient(from var(--angle),
            rgb(var(--brand-rgb) / 0.7) 0deg,
            rgb(var(--brand-rgb) / 0.16) 24deg,
            transparent 36deg,
            transparent 360deg);
    animation: radar-sweep 4s linear infinite;
}

@keyframes radar-sweep {
    to {
        --angle: 360deg;
    }
}

.notfound h1 {
    font-size: clamp(1.75rem, 5vw, 2.75rem);
    font-weight: 700;
    letter-spacing: -0.02em;
    margin: 0 0 var(--sp-3);
    color: var(--text);
    text-wrap: balance;
}

.notfound-lead {
    font-size: clamp(1rem, 2.4vw, 1.15rem);
    line-height: 1.65;
    color: var(--text-muted);
    margin: 0 auto var(--sp-8);
    max-width: 46ch;
    text-wrap: pretty;
}

.notfound-exits-label {
    font-size: 0.8rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-subtle);
    margin: 0 0 var(--sp-4);
}

.notfound-exits {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--sp-3);
    text-align: left;
}

.notfound-exit {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: var(--sp-5);
    border-radius: var(--r-lg);
    background: var(--surface-1);
    border: 1px solid var(--border);
    text-decoration: none;
    color: inherit;
    position: relative;
    isolation: isolate;
    transition:
        transform var(--dur-3) var(--ease-out),
        box-shadow var(--dur-3) var(--ease-out),
        border-color var(--dur-3) var(--ease-out);
}

.notfound-exit-icon {
    font-size: 1.5rem;
    line-height: 1;
    margin-bottom: 4px;
}

.notfound-exit-title {
    font-weight: 650;
    color: var(--text);
}

.notfound-exit-desc {
    font-size: 0.85rem;
    line-height: 1.5;
    color: var(--text-muted);
    text-wrap: pretty;
}

@media (hover: hover) and (pointer: fine) {
    .notfound-exit:hover {
        transform: translateY(-3px);
        border-color: color-mix(in srgb, var(--brand) 32%, transparent);
        box-shadow: 0 18px 40px -16px rgb(var(--shadow-rgb) / calc(0.24 * var(--shadow-k)));
        transition-duration: var(--dur-2);
    }
}

.notfound-exit:active {
    transform: scale(0.985);
    transition-duration: var(--dur-1);
}

.notfound-aside {
    margin: var(--sp-7) 0 0;
    font-size: 0.85rem;
    color: var(--text-subtle);
}

.notfound-aside a {
    color: var(--brand-text);
    text-decoration: underline;
    text-underline-offset: 0.18em;
}

@media (max-width: 768px) {
    .notfound {
        padding-top: var(--sp-7);
    }

    /* Une seule colonne : trois cartes côte à côte à 390 px donnent des
       colonnes de 100 px, illisibles. */
    .notfound-exits {
        grid-template-columns: 1fr;
    }

    .notfound-exit {
        flex-direction: row;
        align-items: center;
        gap: var(--sp-4);
        flex-wrap: wrap;
        padding: var(--sp-4);
    }

    .notfound-exit-icon {
        margin-bottom: 0;
    }

    .notfound-exit-desc {
        flex-basis: 100%;
    }
}

/* =============================================
   FOOTER
   ============================================= */
footer {
    text-align: center;
    padding: 40px 20px;
    background-color: var(--surface-0);
    color: var(--text-muted);
    font-size: 0.9rem;
    border-top: 1px solid rgba(0, 0, 0, 0.05);
}

.footer-legal-links {
    margin-bottom: 12px;
    display: flex;
    justify-content: center;
    align-items: center;
    flex-wrap: wrap;
    gap: 6px;
}

.footer-legal-links a {
    color: var(--text-muted);
    /* Identifiable sans survol et sans dépendre de la couleur (WCAG 1.4.1). */
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 0.18em;
    text-decoration-color: color-mix(in srgb, currentColor 45%, transparent);
    /* Cible tactile : ces liens faisaient ~20 px de haut et se touchaient. */
    display: inline-block;
    padding: 10px 6px;
    transition: color var(--dur-2) var(--ease-out);
    font-size: 0.85rem;
}

.footer-legal-links a:hover {
    color: var(--brand-text);
}

.footer-separator {
    color: rgba(0, 0, 0, 0.2);
    font-size: 0.85rem;
    user-select: none;
}

/* =============================================
   PAGES LÉGALES
   ============================================= */
.legal-page {
    padding-top: 120px;
    padding-bottom: 80px;
    min-height: 70vh;
}

.legal-container {
    max-width: 780px;
    margin: 0 auto;
    padding: 0 5%;
}

.legal-container h1 {
    font-size: clamp(2rem, 4vw, 2.8rem);
    font-weight: 800;
    color: var(--text);
    margin-bottom: 8px;
    letter-spacing: -0.02em;
}

.legal-update {
    color: var(--text-muted);
    font-size: 0.9rem;
    margin-bottom: 48px;
    padding-bottom: 24px;
    border-bottom: 1px solid rgba(0, 0, 0, 0.08);
}

.legal-section {
    margin-bottom: 40px;
}

.legal-section h2 {
    font-size: 1.25rem;
    font-weight: 700;
    color: var(--text);
    margin-bottom: 12px;
    letter-spacing: -0.01em;
}

.legal-section h3 {
    font-size: 1.05rem;
    font-weight: 600;
    color: var(--text);
    margin-top: 20px;
    margin-bottom: 8px;
}

.legal-section p {
    color: var(--text-muted);
    font-size: 0.95rem;
    line-height: 1.7;
    margin-bottom: 12px;
}

.legal-section ul {
    list-style: none;
    padding-left: 0;
    margin-bottom: 12px;
}

.legal-section ul li {
    color: var(--text-muted);
    font-size: 0.95rem;
    line-height: 1.7;
    padding-left: 20px;
    position: relative;
    margin-bottom: 4px;
}

.legal-section ul li::before {
    content: "·";
    position: absolute;
    left: 4px;
    color: var(--brand-text);
    font-weight: 700;
    font-size: 1.2em;
}

/* Un lien noyé dans un paragraphe doit être identifiable SANS survol et
   SANS dépendre de la couleur seule (WCAG 1.4.1). Le soulignement n'est
   donc pas décoratif ici : il est obligatoire. */
.legal-section a {
    color: var(--brand-text);
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 0.18em;
    text-decoration-color: rgb(var(--brand-rgb) / 0.45);
    transition: text-decoration-color var(--dur-2) var(--ease-out), color var(--dur-2) var(--ease-out);
}

.legal-section a:hover {
    text-decoration-color: currentColor;
}

/* =============================================
   ANIMATIONS — APPLE-LIKE SCROLL REVEAL
   ============================================= */
@keyframes float {
    0% {
        transform: translateY(0px);
    }

    50% {
        transform: translateY(-20px);
    }

    100% {
        transform: translateY(0px);
    }
}

/* Gentle float for phone placeholders */
@keyframes floatGentle {
    0% {
        transform: translateY(0px);
    }

    50% {
        transform: translateY(-12px);
    }

    100% {
        transform: translateY(0px);
    }
}

@keyframes floatGentleReverse {
    0% {
        transform: translateY(-8px);
    }

    50% {
        transform: translateY(8px);
    }

    100% {
        transform: translateY(-8px);
    }
}

.float-gentle {
    animation: floatGentle 6s ease-in-out infinite;
}

.float-gentle-reverse {
    animation: floatGentleReverse 7s ease-in-out infinite;
}

/* Scroll reveal — distance courte + expo-out : l'élément « atterrit »
   avec précision au lieu de flotter longuement */
.fade-in {
    opacity: 0;
    transform: translateY(26px);
    transition: opacity 0.7s var(--ease-out-expo), transform 0.7s var(--ease-out-expo);
}

.fade-in.visible {
    opacity: 1;
    transform: translateY(0);
}

.fade-in.delay {
    transition-delay: 0.12s;
}

/* ── Décalage séquentiel ──
   L'ancien système reposait sur un attribut data-stagger écrit à la main,
   qui ne comptait que 4 valeurs : une 5e carte n'avait aucun délai. Ici le
   décalage vient du rang de l'élément dans son parent, donc il fonctionne
   quel que soit le nombre de cartes et sans rien écrire dans le HTML. */
.reveal-group>*,
.stagger[data-stagger="0"] {
    transition-delay: 0.05s;
}

.reveal-group> :nth-child(2),
.stagger[data-stagger="1"] {
    transition-delay: 0.13s;
}

.reveal-group> :nth-child(3),
.stagger[data-stagger="2"] {
    transition-delay: 0.21s;
}

.reveal-group> :nth-child(4),
.stagger[data-stagger="3"] {
    transition-delay: 0.29s;
}

.reveal-group> :nth-child(5) {
    transition-delay: 0.37s;
}

.reveal-group> :nth-child(6) {
    transition-delay: 0.45s;
}

.reveal-group> :nth-child(7) {
    transition-delay: 0.53s;
}

.reveal-group> :nth-child(n+8) {
    transition-delay: 0.61s;
}

/* ── HERO — cascade d'entrée au chargement ──
   Le contenu du hero n'attend plus l'observer : chaque élément
   monte en scène l'un après l'autre, dès le chargement.
   (Le h1 est géré à part par .line-reveal.) */
.hero-apple .hero-apple-content.fade-in,
.hero-apple .countdown-wrapper.fade-in,
.app-hero .app-hero-content.fade-in {
    opacity: 1;
    transform: none;
    transition: none;
}

@keyframes heroRise {
    from {
        opacity: 0;
        transform: translateY(22px);
    }

    to {
        opacity: 1;
        transform: translateY(0);
    }
}

.hero-apple .hero-overline {
    animation: heroRise 0.8s var(--ease-out-expo) 0.05s backwards;
}

.hero-apple .hero-subtitle {
    animation: heroRise 0.8s var(--ease-out-expo) 0.3s backwards;
}

.hero-apple .hero-cta-group {
    animation: heroRise 0.8s var(--ease-out-expo) 0.45s backwards;
}

.hero-apple .countdown-wrapper {
    animation: heroRise 0.8s var(--ease-out-expo) 0.6s backwards;
}

.app-hero .app-hero-icon {
    animation: heroRise 0.8s var(--ease-out-expo) 0.05s backwards, float 6s ease-in-out 0.9s infinite;
}

.app-hero .hero-subtitle {
    animation: heroRise 0.8s var(--ease-out-expo) 0.35s backwards;
}

/* ── STEP CARDS — le numéro « pop » après la carte ── */
.step-card.fade-in .step-number {
    transform: translateX(-50%) scale(0.3);
    opacity: 0;
    transition:
        transform 0.5s var(--transition-spring),
        opacity 0.25s ease;
}

.step-card.fade-in.visible .step-number {
    transform: translateX(-50%) scale(1);
    opacity: 1;
}

.step-card.stagger[data-stagger="0"] .step-number {
    transition-delay: 0.3s;
}

.step-card.stagger[data-stagger="1"] .step-number {
    transition-delay: 0.4s;
}

.step-card.stagger[data-stagger="2"] .step-number {
    transition-delay: 0.5s;
}

.step-card.stagger[data-stagger="3"] .step-number {
    transition-delay: 0.6s;
}

/* =============================================
   NAV LINKS
   ============================================= */
.nav-links {
    display: flex;
    align-items: center;
    gap: 30px;
}

.nav-item {
    text-decoration: none;
    color: var(--text);
    font-weight: 600;
    transition: color 0.3s ease;
    position: relative;
}

/* NIVEAU 3 — lien : le trait entre par la gauche et sort par la droite.
   scaleX est purement compositeur, là où animer width déclenchait un
   calcul de mise en page à chaque frame. */
.nav-item::after {
    content: '';
    position: absolute;
    bottom: -4px;
    left: 0;
    width: 100%;
    height: 2px;
    background-color: var(--brand-text);
    transform: scaleX(0);
    transform-origin: right center;
    transition: transform var(--dur-3) var(--ease-out);
}

.nav-item:hover::after,
.nav-item.active::after,
.nav-item[aria-current="page"]::after {
    transform: scaleX(1);
    transform-origin: left center;
    transition-duration: var(--dur-2);
}

.nav-item:hover,
.nav-item.active {
    color: var(--brand-text);
}

/* =============================================
   PAGES — HEADER, FORMS, SHOWCASE
   ============================================= */
.page-header {
    text-align: center;
    padding: 80px 5% 40px 5%;
    position: relative;
    overflow: hidden;
}

.page-header h1 {
    font-size: 3.5rem;
    color: var(--text);
    margin-bottom: 15px;
    letter-spacing: -1px;
}

.page-header p {
    font-size: 1.2rem;
    color: var(--text-muted);
}

.form-section {
    max-width: 800px;
    margin: 0 auto 100px auto;
    padding: 0 5%;
}

.apple-form {
    background: var(--surface-1);
    padding: 50px;
    border-radius: 20px;
    box-shadow: 0 10px 40px rgb(var(--shadow-rgb) / calc(0.06 * var(--shadow-k)));
    display: flex;
    flex-direction: column;
    gap: 25px;
}

.form-row {
    display: flex;
    gap: 20px;
}

.input-group {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 8px;
    text-align: left;
}

.input-group label {
    font-size: 0.9rem;
    font-weight: 600;
    color: var(--text);
}

.input-group input,
.input-group select,
.input-group textarea {
    width: 100%;
    padding: 16px;
    border: 1px solid var(--field-border);
    border-radius: 12px;
    font-size: 1rem;
    font-family: inherit;
    background-color: var(--field-bg);
    transition: border-color 0.3s ease, background-color 0.3s ease, box-shadow 0.3s ease;
}

.input-group input:focus,
.input-group select:focus,
.input-group textarea:focus {
    outline: none;
    border-color: var(--brand-text);
    background-color: var(--surface-1);
    box-shadow: 0 0 0 4px rgb(var(--brand-rgb) / 0.1);
}

.btn-submit-large {
    background-color: var(--brand);
    color: white;
    padding: 18px;
    border-radius: 12px;
    font-size: 1.1rem;
    font-weight: 600;
    border: none;
    cursor: pointer;
    margin-top: 10px;
    transition: transform 0.3s var(--transition-smooth), box-shadow 0.3s var(--transition-smooth);
}

.btn-submit-large:hover {
    transform: translateY(-2px);
    box-shadow: 0 10px 20px rgb(var(--brand-rgb) / 0.2);
}

/* =============================================
   INSTAGRAM BUTTON — WHITE TEXT
   ============================================= */
.insta-button {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 16px;
    border-radius: 50px;
    background: linear-gradient(45deg, #f09433 0%, #e6683c 25%, #dc2743 50%, #cc2366 75%, #bc1888 100%);
    color: white;
    font-weight: 700;
    text-decoration: none;
    font-size: 14px;
    transition: transform 0.3s ease, box-shadow 0.3s ease;
    box-shadow: 0 4px 15px rgba(220, 39, 67, 0.3);
}

.insta-button:hover {
    transform: translateY(-2px);
    box-shadow: 0 6px 20px rgba(220, 39, 67, 0.5);
}

/* =============================================
   HAMBURGER MENU
   ============================================= */
.hamburger {
    display: none;
    /* Cible tactile de 44 × 44 px : recommandation d'accessibilité et
       simple confort. Les barres restaient à 30 × 21 px auparavant. */
    width: 44px;
    height: 44px;
    align-items: center;
    justify-content: center;
    flex-direction: column;
    gap: 6px;
    cursor: pointer;
    background: none;
    border: 0;
    padding: 0;
    z-index: calc(var(--z-nav) + 1);
}

.hamburger span {
    width: 30px;
    height: 3px;
    background-color: var(--brand-text);
    border-radius: 5px;
    transition: transform 0.3s ease-in-out, opacity 0.3s ease-in-out;
}

.hamburger.active span:nth-child(1) {
    transform: translateY(9px) rotate(45deg);
}

.hamburger.active span:nth-child(2) {
    opacity: 0;
}

.hamburger.active span:nth-child(3) {
    transform: translateY(-9px) rotate(-45deg);
}

/* =============================================
   APP VISUELS PAGE — HERO
   ============================================= */
.app-hero {
    min-height: 70vh;
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    padding: 120px 5% 80px 5%;
    background-color: var(--surface-0);
    position: relative;
    overflow: hidden;
}

.app-hero::before {
    content: '';
    position: absolute;
    top: -20%;
    left: 50%;
    transform: translateX(-50%);
    width: 700px;
    height: 700px;
    background: radial-gradient(circle, rgba(0, 85, 255, 0.07) 0%, transparent 70%);
    border-radius: 50%;
    pointer-events: none;
}

.app-hero-content {
    position: relative;
    z-index: 2;
    max-width: 800px;
}

.app-hero-icon {
    height: 60px;
    margin-bottom: 25px;
    animation: float 6s ease-in-out infinite;
}

.app-hero h1 {
    font-size: 4rem;
    font-weight: 800;
    line-height: 1.1;
    letter-spacing: -2px;
    margin-bottom: 20px;
    color: var(--text);
}

.app-hero .hero-subtitle {
    max-width: 600px;
    margin: 0 auto;
}

/* =============================================
   FEATURE SECTIONS (VISUELS PAGE)
   ============================================= */
.feature-section {
    padding: var(--section-padding);
}

.feature-section.bg-gray {
    background-color: var(--surface-2);
}

.feature-inner {
    max-width: 1200px;
    margin: 0 auto;
    display: flex;
    align-items: center;
    gap: 80px;
}

.feature-inner.reverse {
    flex-direction: row-reverse;
}

.feature-text {
    flex: 1;
    max-width: 520px;
}

.feature-badge {
    display: inline-block;
    background-color: rgba(0, 85, 255, 0.07);
    color: var(--brand-text);
    padding: 6px 16px;
    border-radius: 50px;
    font-weight: 600;
    font-size: 0.85rem;
    margin-bottom: 18px;
    letter-spacing: 0.01em;
}

.feature-text h2 {
    font-size: 2.8rem;
    font-weight: 700;
    letter-spacing: -1.5px;
    line-height: 1.12;
    margin-bottom: 18px;
    color: var(--text);
}

.feature-text p {
    font-size: 1.1rem;
    color: var(--text-muted);
    line-height: 1.7;
    margin-bottom: 25px;
}

.feature-list {
    list-style: none;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.feature-list li {
    font-size: 0.95rem;
    color: var(--text-muted);
    padding-left: 28px;
    position: relative;
    line-height: 1.5;
}

.feature-list li::before {
    content: '✓';
    position: absolute;
    left: 0;
    color: var(--brand-text);
    font-weight: 700;
    font-size: 1rem;
}

/* Phone placeholder (portrait aspect ratio) */
.feature-visual {
    flex: 1;
    display: flex;
    justify-content: center;
    align-items: center;
}

/* ── Emplacement photo large ──
   Seul emplacement resté en paysage : il accueillera une VRAIE photo
   d'étudiants, qu'un cadre téléphone rendrait absurde. */
.photo-slot {
    width: 100%;
    aspect-ratio: 3 / 2;
    border-radius: var(--r-xl);
    background: linear-gradient(145deg, var(--fill-1) 0%, var(--fill-2) 100%);
    border: 1px solid var(--hairline);
    display: grid;
    place-items: center;
    overflow: hidden;
}

.photo-slot>img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.photo-slot:has(img) .photo-slot__label {
    display: none;
}

.photo-slot__label {
    color: var(--text-subtle);
    font-size: 0.92rem;
    font-weight: 500;
}

/* =============================================
   COMPOSANT .device — EMPLACEMENT DE CAPTURE D'ÉCRAN

   Ratio : 1179 / 2556, les dimensions natives d'un iPhone 15/16.
   En calant l'export sur un appareil précis, le ratio devient EXACT
   (0,4613, soit du 9:19,5 à 0,1 % près) et aucune capture n'est jamais
   rognée. L'ancien 280 × 560 valait 1:2 — un téléphone de 2015.

   L'aspect-ratio est porté par l'ÉCRAN et non par le cadre : avec
   box-sizing: border-box, l'appliquer au cadre inclurait le biseau et
   déformerait subtilement la proportion. On dimensionne donc de
   l'intérieur vers l'extérieur.
   ============================================= */
.device {
    --device-w: clamp(210px, 22vw, 290px);
    --bezel: 10px;
    --r-outer: 46px;
    --shot-ratio: 1179 / 2556;

    /* .device n'est qu'un conteneur : le châssis vit dans .device__frame,
       sinon la légende se retrouverait dessinée sur le biseau. */
    width: var(--device-w);
    flex: 0 0 auto;
    margin: 0;
}

.device__frame {
    padding: var(--bezel);
    border-radius: var(--r-outer);
    background: linear-gradient(150deg, #2A2E36 0%, #14161B 42%, #33383F 100%);
    box-shadow:
        0 32px 70px -20px rgb(var(--shadow-rgb) / calc(0.28 * var(--shadow-k))),
        0 0 0 1px rgb(var(--shadow-rgb) / calc(0.06 * var(--shadow-k)));
    isolation: isolate;
    transition: box-shadow var(--dur-4) var(--ease-out), transform var(--dur-4) var(--ease-out);
}

.device__screen {
    aspect-ratio: var(--shot-ratio);
    border-radius: calc(var(--r-outer) - var(--bezel));
    overflow: hidden;
    position: relative;
    /* grid superpose l'image et le squelette dans la même cellule :
       le squelette disparaît dès qu'une vraie capture est posée. */
    display: grid;
    background: var(--surface-3);
    box-shadow: inset 0 0 0 1px rgb(0 0 0 / 0.55);
}

.device__screen>img,
.device__skeleton {
    grid-area: 1 / 1;
}

.device__screen>img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: top center;
    display: block;
}

.device__screen:has(img) .device__skeleton {
    display: none;
}

/* Dynamic Island dessinée PAR-DESSUS la capture.
   iOS ne l'inclut pas dans ses captures d'écran : la zone est vide dans
   le PNG, la pastille tombe donc exactement au bon endroit. Dimensionnée
   en pourcentages, elle suit le cadre à tous les points de rupture. */
.device--island .device__screen::after {
    content: '';
    position: absolute;
    z-index: 2;
    top: 1.3%;
    left: 50%;
    translate: -50% 0;
    width: 32%;
    aspect-ratio: 125 / 36;
    background: #000;
    border-radius: var(--r-pill);
}

/* Reflet d'écran, très discret */
.device__screen::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 3;
    pointer-events: none;
    background: linear-gradient(118deg,
            rgb(255 255 255 / 0.10) 0%, transparent 34%,
            transparent 66%, rgb(255 255 255 / 0.05) 100%);
}

.device__caption {
    margin-top: var(--sp-3);
    text-align: center;
    font-size: var(--fs-sm, 0.92rem);
    color: var(--text-muted);
    font-weight: 500;
}

/* ── État vide : un squelette d'interface, pas une boîte grise ──
   « L'app, en cours de chargement » se lit infiniment mieux que
   « site inachevé ». */
.device__skeleton {
    position: relative;
    overflow: hidden;
    padding: 14% 8% 8%;
    display: flex;
    flex-direction: column;
    gap: 6%;
    background: var(--surface-3);
}

.device__skeleton i {
    display: block;
    background: var(--fill-2);
    border-radius: 8px;
}

.device__skeleton i:nth-child(1) { height: 5%; width: 46%; border-radius: 999px; }
.device__skeleton i:nth-child(2) { height: 9%; width: 78%; }
.device__skeleton i:nth-child(3) { height: 16%; width: 100%; }
.device__skeleton i:nth-child(4) { height: 16%; width: 100%; }
.device__skeleton i:nth-child(5) { height: 16%; width: 100%; }
.device__skeleton i:nth-child(6) { height: 8%; width: 100%; margin-top: auto; border-radius: 999px; }

.device__skeleton::after {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(100deg, transparent 20%, rgb(255 255 255 / 0.22) 50%, transparent 80%);
    translate: -100% 0;
    animation: skeleton-sweep 2.4s var(--ease-in-out) infinite;
}

@keyframes skeleton-sweep {
    to {
        translate: 100% 0;
    }
}

@media (prefers-reduced-motion: reduce) {
    .device__skeleton::after {
        animation: none;
    }
}

/* ── Grappe de téléphones (hero) ──

   ⚠ PIÈGE STRUCTUREL, à lire avant de toucher à ce bloc.

   Chaque téléphone est enveloppé dans un <a class="device-link"> qui alimente
   le portail de transition de page. C'est donc le LIEN qui est l'élément flex,
   pas la <figure class="device">. Deux conséquences, apprises à la dure :

     1. Tout combinateur « .device-cluster > .device » ne matche RIEN. C'est
        ainsi que la remise à plat mobile et le miroir du troisième téléphone
        se sont tus en silence, sans la moindre erreur.
     2. Une marge ou une rotation posée sur la figure s'échappe de la zone
        cliquable du lien : le téléphone débordait de sa propre cible tactile.

   D'où la répartition ci-dessous, à conserver :
     géométrie (marge, rotation, opacité, plan) → sur l'élément flex, « > * »
     --device-w                                 → sur .device lui-même, car le
        composant déclare cette variable dans sa propre règle, ce qui bat
        toute valeur héritée d'un ancêtre.

   « :is(.device--aside, :has(.device--aside)) » vise l'élément flex d'après le
   téléphone qu'il contient, qu'il soit enveloppé ou nu. :is() étant tolérant,
   la partie .device--aside continue de fonctionner même là où :has() manque. */
.device-cluster {
    display: flex;
    justify-content: center;
    align-items: flex-end;
    perspective: 1600px;
    margin-top: var(--sp-7);
}

.device-link {
    display: block;
    text-decoration: none;
    color: inherit;
    /* --r-outer est déclarée par .device, donc absente ici : une valeur en
       dur pour que l'anneau de focus épouse le cadre du téléphone. */
    border-radius: var(--r-xl);
}

.device-cluster>* {
    flex: 0 0 auto;
    z-index: 2;
}

.device-cluster> :is(.device--aside, :has(.device--aside)) {
    z-index: 1;
    translate: 0 30px;
    rotate: y -14deg;
    opacity: 0.88;
}

/* Le chevauchement se pose sur le côté INTÉRIEUR uniquement.
   « margin-inline: -34px » en raccourci paraît symétrique et propre, mais il
   tire aussi sur les bords extérieurs : flexbox compte alors ces marges dans
   la mesure de la ligne, la centre, puis chaque téléphone de bout déborde de
   34 px au-delà. La composition est plus large qu'elle n'en a l'air — mesuré
   à 398 px pour une grappe de 351 px sur un écran de 390. */
.device-cluster> :is(.device--aside, :has(.device--aside)):first-child {
    margin-inline-end: -34px;
}

.device-cluster> :is(.device--aside, :has(.device--aside)):last-child {
    rotate: y 14deg;
    margin-inline-start: -34px;
}

.device-cluster .device--aside {
    --device-w: clamp(160px, 17vw, 220px);
}

/* ── Rail horizontal (galerie) ── */
.device-rail {
    display: flex;
    gap: var(--sp-5);
    justify-content: center;
    flex-wrap: wrap;
}

.device-rail .device {
    --device-w: 190px;
    --r-outer: 34px;
    --bezel: 8px;
}

/* ── Dérive liée au défilement ──
   Remplace les animations flottantes infinies : aucun cycle CPU consommé
   quand le téléphone est hors écran, et le mouvement répond au geste de
   l'utilisateur au lieu d'être purement décoratif. */
@supports (animation-timeline: view()) {
    @media (prefers-reduced-motion: no-preference) {
        .feature-visual .device {
            animation: device-drift linear both;
            animation-timeline: view();
            animation-range: entry cover;
        }

        .feature-inner.reverse .feature-visual .device {
            animation-direction: reverse;
        }

        @keyframes device-drift {
            from { translate: 0 26px; }
            to   { translate: 0 -26px; }
        }
    }
}

@media (hover: hover) and (pointer: fine) {
    .device:hover .device__frame {
        box-shadow:
            0 42px 90px -22px rgb(var(--shadow-rgb) / calc(0.34 * var(--shadow-k))),
            0 0 0 1px rgb(var(--shadow-rgb) / calc(0.08 * var(--shadow-k)));
    }
}

/* =============================================
   GALLERY SECTION
   ============================================= */
.gallery-section {
    padding: var(--section-padding);
}

.gallery-section.bg-gray {
    background-color: var(--surface-2);
}

.gallery-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: 28px;
    max-width: 1100px;
    margin: 0 auto;
}

.gallery-card {
    background: var(--surface-1);
    border-radius: var(--border-radius-card);
    padding: 24px;
    border: 1px solid var(--hairline);
    transition: transform 0.4s var(--transition-smooth), box-shadow 0.4s var(--transition-smooth);
}

.gallery-card:hover {
    transform: translateY(-6px);
    box-shadow: 0 15px 45px rgb(var(--shadow-rgb) / calc(0.08 * var(--shadow-k)));
}


.gallery-card h3 {
    font-size: 1.1rem;
    font-weight: 700;
    color: var(--text);
    margin-bottom: 8px;
}

.gallery-card p {
    font-size: 0.9rem;
    color: var(--text-muted);
    line-height: 1.5;
}

/* =============================================
   CTA FINAL
   ============================================= */
.cta-final {
    padding: var(--section-padding);
    text-align: center;
    background-color: var(--surface-0);
    position: relative;
    overflow: hidden;
}

.cta-final-content {
    max-width: 700px;
    margin: 0 auto;
}

.cta-final h2 {
    font-size: 2.8rem;
    font-weight: 700;
    letter-spacing: -1.5px;
    color: var(--text);
    margin-bottom: 15px;
}

.cta-final p {
    font-size: 1.1rem;
    color: var(--text-muted);
    margin-bottom: 35px;
    line-height: 1.6;
}

/* =============================================
   PAGE MERCI — CONFIRMATION CANDIDATURE
   ============================================= */
.hero-section {
    /* Remplace un calc(100vh - 64px - 101px) où « 101px » était la hauteur
       du footer mesurée à la main : elle cassait au premier changement.
       Le layout flex du body place désormais le footer en bas tout seul. */
    min-height: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    padding: 100px 5% 80px 5%;
    background-color: var(--surface-0);
    position: relative;
    overflow: hidden;
}

.hero-text {
    max-width: 640px;
}

.badge {
    display: inline-block;
    background-color: rgba(0, 85, 255, 0.08);
    color: var(--brand-text);
    padding: 8px 20px;
    border-radius: 50px;
    font-weight: 600;
    font-size: 0.9rem;
    margin-bottom: 24px;
    animation: heroRise 0.8s var(--ease-out-expo) 0.05s backwards;
}

.hero-text h1 {
    font-size: 3rem;
    font-weight: 800;
    letter-spacing: -1.5px;
    line-height: 1.1;
    color: var(--text);
    margin-bottom: 18px;
    animation: heroRise 0.8s var(--ease-out-expo) 0.15s backwards;
}

.hero-text p {
    color: var(--text-muted);
    font-size: 1.1rem;
    line-height: 1.7;
    margin-bottom: 35px;
    animation: heroRise 0.8s var(--ease-out-expo) 0.3s backwards;
}

.hero-text .btn-submit-large {
    display: inline-block;
    text-decoration: none;
    border-radius: 50px;
    padding: 16px 36px;
    margin-top: 0;
    animation: heroRise 0.8s var(--ease-out-expo) 0.45s backwards;
}

/* =============================================
   RESPONSIVE — TABLET
   ============================================= */
@media (max-width: 1024px) {
    .hero-apple h1 {
        font-size: 3.5rem;
    }

    .section-header h2 {
        font-size: 2.5rem;
    }

    .visual-section-inner {
        gap: 50px;
    }

    .visual-text-side h2 {
        font-size: 2.3rem;
    }

    .app-hero h1 {
        font-size: 3.2rem;
    }

    .feature-inner {
        gap: 50px;
    }

    .feature-text h2 {
        font-size: 2.3rem;
    }

    .device {
        --device-w: 240px;
        --r-outer: 40px;
        --bezel: 9px;
    }

    .device-cluster .device--aside {
        --device-w: 180px;
    }

    .cta-final h2 {
        font-size: 2.3rem;
    }
}

/* =============================================
   RESPONSIVE — MOBILE
   ============================================= */
@media (max-width: 768px) {

    /* Hero */
    .hero-apple {
        min-height: auto;
        padding: 60px 4% 50px 4%;
    }

    .hero-apple h1 {
        font-size: 2.15rem;
        letter-spacing: -0.8px;
        word-break: break-word;
        overflow-wrap: break-word;
    }

    .hero-overline {
        font-size: 0.8rem;
        padding: 6px 14px;
        margin-bottom: 20px;
    }

    .hero-subtitle {
        font-size: 0.95rem;
        margin-bottom: 30px;
    }

    .hero-cta-group {
        flex-direction: column;
        gap: 12px;
        width: 100%;
    }

    .btn-hero-primary,
    .btn-hero-secondary {
        width: 100%;
        text-align: center;
        box-sizing: border-box;
    }

    /* Countdown — compact sur mobile */
    .countdown-wrapper {
        width: 100%;
        align-items: center;
    }

    .countdown-grid {
        padding: 14px 12px;
        gap: 6px;
        width: 100%;
        box-sizing: border-box;
        justify-content: center;
    }

    .countdown-unit {
        min-width: 40px;
    }

    .countdown-number {
        font-size: 1.6rem;
        letter-spacing: -1px;
    }

    .countdown-separator {
        font-size: 1.4rem;
        margin-bottom: 12px;
    }

    .countdown-unit-label {
        font-size: 0.6rem;
    }

    /* Sections */
    .section-header h2 {
        font-size: 2rem;
        letter-spacing: -1px;
    }

    .section-subtitle {
        font-size: 1rem;
        padding: 0 5%;
    }

    /* Steps */
    .steps-grid {
        flex-direction: column;
        align-items: center;
        gap: 30px;
    }

    .step-card {
        max-width: 100%;
        width: 100%;
    }

    /* Stats */
    .stats-grid {
        flex-direction: column;
        align-items: center;
    }

    .stat-card {
        max-width: 100%;
        width: 100%;
    }

    .stat-number {
        font-size: 2.5rem;
    }

    /* Testimonials */
    .testimonials-grid {
        flex-direction: column;
        align-items: center;
    }

    .testimonial-card {
        max-width: 100%;
        width: 100%;
    }

    .visual-section-inner {
        flex-direction: column;
        gap: 40px;
        text-align: center;
    }

    .visual-text-side {
        max-width: 100%;
    }

    .visual-text-side h2 {
        font-size: 2rem;
    }

    .visual-showcase {
        padding: 20px 5% 60px 5%;
    }

    /* Hamburger & Mobile Nav */
    .hamburger {
        display: flex;
    }

    /* ── MENU MOBILE ──

       Il fonctionnait par « max-height: 0 » + « overflow: hidden ». Deux
       défauts :
         · les liens d'un menu fermé restaient TABULABLES. Au clavier, on
           entrait dans un panneau invisible, hauteur zéro, sans aucun repère.
           « display: none » règle la question définitivement.
         · la hauteur s'animait vers un maximum et non vers la hauteur réelle
           du contenu, ce qui rendait la courbe d'ouverture imprévisible.

       Le couple @starting-style + transition-behavior: allow-discrete permet
       d'animer depuis et vers « display: none ». Les deux sont déclarés
       séparément à dessein : « transition: … display … allow-discrete » en
       raccourci deviendrait INVALIDE là où le mot-clé n'est pas connu, et
       emporterait avec lui les transitions d'opacité. Ici, un navigateur
       ancien ignore la seule ligne qu'il ne comprend pas et affiche le menu
       instantanément — un repli parfaitement acceptable. */
    .nav-links {
        display: none;
        position: fixed;
        top: var(--nav-h);
        left: 0;
        width: 100%;
        background-color: var(--surface-0);
        flex-direction: column;
        padding: 8px 0 16px;
        padding-bottom: calc(16px + env(safe-area-inset-bottom));
        box-shadow: 0 8px 32px rgb(var(--shadow-rgb) / calc(0.12 * var(--shadow-k)));
        max-height: calc(100dvh - var(--nav-h));
        overflow-y: auto;
        overscroll-behavior: contain;
        z-index: var(--z-menu);
        border-bottom: 1px solid rgba(0, 0, 0, 0.06);
        opacity: 0;
        translate: 0 -10px;
        transition:
            opacity var(--dur-3) var(--ease-out),
            translate var(--dur-3) var(--ease-out-expo),
            display var(--dur-3);
        transition-behavior: allow-discrete;
    }

    .nav-links.active {
        display: flex;
        opacity: 1;
        translate: 0 0;
    }

    /* L'état de départ de l'animation d'entrée. Sans ce bloc, le panneau
       apparaîtrait d'un coup : il n'y a pas de valeur « avant » à interpoler
       pour un élément qui vient de passer de display: none à display: flex. */
    @starting-style {
        .nav-links.active {
            opacity: 0;
            translate: 0 -10px;
        }
    }

    .nav-links .nav-item,
    .nav-links .btn-nav {
        margin: 8px 0;
        text-align: center;
        padding: 12px 24px;
        width: 100%;
        display: block;
    }

    .nav-links .btn-nav {
        margin: 8px 5%;
        width: calc(90%);
        box-sizing: border-box;
    }

    .nav-links .nav-item::after {
        display: none;
    }

    /* Hype — compteur compact, sans débordement */
    .hype-title {
        font-size: 2rem;
        letter-spacing: -1px;
    }

    .hype-counter-card {
        padding: 26px 20px 20px 20px;
        width: 100%;
        box-sizing: border-box;
        border-radius: 22px;
    }

    .hype-slot-col {
        width: 40px;
    }

    .hype-slot-digit {
        width: 40px;
        font-size: 2.4rem;
        letter-spacing: -2px;
    }

    .btn-hype {
        width: 100%;
        justify-content: center;
        padding: 18px 24px;
        font-size: 1.1rem;
        box-sizing: border-box;
    }

    /* Page merci */
    .hero-text h1 {
        font-size: 2.1rem;
        letter-spacing: -1px;
    }

    /* Contact */
    .contact-section {
        padding: 70px 5%;
    }

    .contact-section h2 {
        font-size: 2rem;
    }

    .info-grid {
        flex-direction: column;
    }

    .contact-box {
        padding: 30px 20px;
    }

    /* Support */
    .support-content {
        padding: 40px 25px;
        border-radius: 25px;
    }

    .support-content h2 {
        font-size: 1.7rem;
    }

    /* Form */
    .form-row {
        flex-direction: column;
        gap: 25px;
    }

    .page-header h1 {
        font-size: 2.5rem;
    }

    /* Instagram button mobile */
    .insta-button {
        padding: 6px;
        margin-right: 10px;
    }

    .insta-button span {
        display: none;
    }

    /* === VISUELS PAGE MOBILE === */
    .app-hero {
        min-height: auto;
        padding: 80px 5% 50px 5%;
    }

    .app-hero h1 {
        font-size: 2.4rem;
        letter-spacing: -1.2px;
    }

    .app-hero-icon {
        height: 45px;
    }

    .feature-section {
        padding: 70px 5%;
    }

    .feature-inner,
    .feature-inner.reverse {
        flex-direction: column;
        text-align: center;
        gap: 40px;
    }

    .feature-text {
        max-width: 100%;
    }

    .feature-text h2 {
        font-size: 2rem;
    }

    .feature-list {
        text-align: left;
    }

    /* Décision mobile la plus importante du composant : ON SUPPRIME LE CADRE.
       Un téléphone dessiné à l'intérieur d'un téléphone rétrécit la capture
       pour rien et fait « maquette de présentation ». À 72 vw la capture
       devient enfin LISIBLE, contre environ 55 % de la largeur une fois le
       biseau déduit. La Dynamic Island disparaît aussi : la barre d'état de
       la capture elle-même suffit à cette taille. */
    .device {
        --device-w: min(72vw, 320px);
        --bezel: 0px;
        --r-outer: 30px;
    }

    .device__frame {
        background: none;
        box-shadow: 0 28px 64px -16px rgb(var(--shadow-rgb) / calc(0.20 * var(--shadow-k)));
    }

    .device--island .device__screen::after {
        display: none;
    }

    .device__screen {
        box-shadow: inset 0 0 0 1px var(--border);
    }

    /* ── GRAPPE DU HERO : UN ÉVENTAIL QUI TIENT DANS L'ÉCRAN ──

       Elle a d'abord été un rail à défilement. Mauvaise idée : sur un hero,
       une zone qui part de côté se lit comme un bug, pas comme un geste. Les
       trois écrans tiennent donc désormais dans la largeur, sans le moindre
       défilement latéral.

       Le calcul, à refaire si l'une des trois valeurs bouge. Chaque écran
       latéral ne chevauche le lead que d'UN côté — donc deux chevauchements,
       pas quatre :
           50vw (lead) + 2 × 32vw (latéraux) − 2 × 15vw (chevauchement)
         = 50 + 64 − 30 = 84vw,  pour 90vw disponibles.
       Il reste 3vw de chaque côté pour absorber le débordement de la
       projection 3D.  ✓

       L'inclinaison tombe à ±10° et la perspective se resserre : à cette
       taille, ±14° écrasait trop les écrans latéraux. */
    .device-cluster {
        margin-top: var(--sp-5);
        perspective: 900px;
    }

    .device-cluster .device--lead {
        --device-w: 50vw;
    }

    .device-cluster .device--aside {
        --device-w: 32vw;
    }

    .device-cluster> :is(.device--aside, :has(.device--aside)) {
        translate: 0 18px;
        rotate: y -10deg;
        opacity: 0.8;
    }

    .device-cluster> :is(.device--aside, :has(.device--aside)):first-child {
        margin-inline-end: -15vw;
    }

    .device-cluster> :is(.device--aside, :has(.device--aside)):last-child {
        rotate: y 10deg;
        margin-inline-start: -15vw;
    }

    /* ── RAIL DE LA GALERIE ──
       Lui reste un rail, et c'est volontaire : quatre vignettes en rangée
       façon App Store, que l'on fait défiler au doigt. Ses enfants sont de
       vraies .device sans lien enveloppant, donc « > .device » y matche. */
    .device-rail {
        justify-content: flex-start;
        flex-wrap: nowrap;
        overflow-x: auto;
        gap: var(--sp-4);
        scroll-snap-type: x mandatory;
        overscroll-behavior-x: contain;
        padding-inline: calc(50% - 36vw);
        scrollbar-width: none;
    }

    .device-rail::-webkit-scrollbar {
        display: none;
    }

    .device-rail>.device {
        scroll-snap-align: center;
        scroll-snap-stop: always;
    }

    .gallery-section {
        padding: 70px 5%;
    }

    .gallery-grid {
        grid-template-columns: 1fr;
    }

    .cta-final {
        padding: 70px 5%;
    }

    .cta-final h2 {
        font-size: 2rem;
    }

    .cta-final .hero-cta-group {
        flex-direction: column;
        gap: 12px;
        align-items: center;
        width: 100%;
    }

    .cta-final .btn-hero-primary,
    .cta-final .btn-hero-secondary {
        width: 100%;
        text-align: center;
        box-sizing: border-box;
    }
}

/* =============================================
   PC — INSTAGRAM POSITIONING
   ============================================= */
@media (min-width: 992px) {
    /* Sur desktop, le bouton Instagram passe après les liens de navigation. */
    .insta-button {
        order: 3;
        margin-left: 15px;
    }
}


/* =============================================
   PREMIUM ANIMATIONS — BINÔME
   ============================================= */

/* ── 1. PAGE TRANSITION (Supprimé) ── */


/* ── 2. RÉVÉLATION LIGNE PAR LIGNE ──
   Les <span> sont écrits dans le HTML plutôt que générés en JS. L'ancienne
   version réécrivait innerHTML sur le h1 — c'est-à-dire sur l'élément LCP :
   provoquait un flash au premier rendu et détruisait tout élément inline
   à cheval sur un <br>. Ici, aucun JS n'intervient sur le titre. */
.line-reveal .line {
    display: block;
    overflow: hidden;
    padding-bottom: 0.06em;
    /* évite de rogner les jambages */
}

.line-reveal .line>* {
    display: block;
    animation: line-rise var(--dur-5) var(--ease-out-expo) both;
}

.line-reveal .line:nth-child(2)>* {
    animation-delay: 90ms;
}

.line-reveal .line:nth-child(3)>* {
    animation-delay: 180ms;
}

@keyframes line-rise {
    from {
        transform: translateY(105%);
        opacity: 0;
    }

    to {
        transform: translateY(0);
        opacity: 1;
    }
}

/* <em> sert uniquement de conteneur pour le dégradé : pas d'italique. */
.line-reveal em {
    font-style: normal;
}

/* ── 5. PROJECTEUR AU POINTEUR ──
   Remplace le tilt 3D, qui entrait tellement en conflit avec :hover qu'il
   avait fallu ajouter « .tilt-card:hover { transform: none } » pour le
   désamorcer, exigeait will-change sur une quinzaine d'éléments, et rendait
   le texte moins lisible en le faisant pivoter en perspective.
   Ici : un seul écouteur pointermove délégué, aucun calcul de mise en page. */
.card-spot {
    position: relative;
    isolation: isolate;
}

.card-spot::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: -1;
    border-radius: inherit;
    background: radial-gradient(420px circle at var(--mx) var(--my),
            rgb(var(--brand-rgb) / 0.16), transparent 64%);
    opacity: 0;
    transition: opacity var(--dur-3) var(--ease-out);
    pointer-events: none;
}

/* Second calque : un liseré qui s'allume du côté où se trouve le pointeur.
   C'est lui qui donne l'impression que la carte est éclairée plutôt que
   simplement teintée — et il ne coûte qu'un dégradé de plus. */
.card-spot::after {
    content: '';
    position: absolute;
    inset: 0;
    z-index: -1;
    border-radius: inherit;
    padding: 1px;
    background: radial-gradient(260px circle at var(--mx) var(--my),
            rgb(var(--brand-rgb) / 0.55), transparent 70%);
    -webkit-mask:
        linear-gradient(#000 0 0) content-box,
        linear-gradient(#000 0 0);
    -webkit-mask-composite: xor;
    mask:
        linear-gradient(#000 0 0) content-box,
        linear-gradient(#000 0 0);
    mask-composite: exclude;
    opacity: 0;
    transition: opacity var(--dur-3) var(--ease-out);
    pointer-events: none;
}

@media (hover: hover) and (pointer: fine) {

    .card-spot:hover::before,
    .card-spot:hover::after {
        opacity: 1;
    }
}

/* Ici vivait un bloc « BONUS: MAGNETIC BUTTONS » qui remettait
   « will-change: transform » sur quatre sélecteurs et, surtout, écrasait les
   transitions de boutons définies plus haut : arrivant plus loin dans la
   cascade à spécificité égale, il rétablissait un 0,3 s symétrique là où la
   chorégraphie voulait une entrée rapide et une sortie lente. Il est parti
   avec l'effet magnétique. Ne pas le réintroduire. */


/* ── DÉFILEMENT LIÉ (scroll-driven) ──
   Là où le navigateur le supporte, le mouvement est piloté par la position
   de défilement plutôt que par un écouteur JS : il tourne hors du fil
   principal et ne consomme rien quand l'élément est hors écran.
   Sans support, le repli rAF de animations.js prend le relais. */
@supports (animation-timeline: scroll()) {
    @media (prefers-reduced-motion: no-preference) {
        .hero-apple-content {
            animation: hero-drift linear both;
            animation-timeline: scroll();
            animation-range: 0 60vh;
        }

        @keyframes hero-drift {
            to {
                transform: translateY(60px);
            }
        }
    }
}

/* ── BARRE DE PROGRESSION DE LECTURE ──
   Zéro JavaScript. Les navigateurs sans support ne voient rien
   (scaleX reste à 0), ce qui est un repli parfaitement acceptable. */
.scroll-progress {
    position: fixed;
    top: var(--nav-h);
    left: 0;
    right: 0;
    height: 2px;
    z-index: var(--z-nav);
    background: var(--brand-grad);
    transform: scaleX(0);
    transform-origin: 0 50%;
    pointer-events: none;
}

@supports (animation-timeline: scroll()) {
    .scroll-progress {
        animation: scroll-progress linear both;
        animation-timeline: scroll(root block);
    }

    @keyframes scroll-progress {
        to {
            transform: scaleX(1);
        }
    }
}

/* =============================================
   TRANSITIONS DE PAGE — VIEW TRANSITIONS

   Chrome 126+/Edge et Safari 18.2+. Firefox retombe sur une navigation
   ordinaire : rien à prévoir, rien ne casse. Aucun impact SEO — ce sont
   de VRAIES navigations, pas du routage côté client.

   Piège n°1 : un view-transition-name DUPLIQUÉ annule silencieusement
   TOUTE la transition. Les trois noms ci-dessous sont présents une seule
   fois par page, ce qui est la condition à respecter.
   ============================================= */
@media (prefers-reduced-motion: no-preference) {
    @view-transition {
        navigation: auto;
    }
}

.logo-link {
    view-transition-name: site-logo;
}

.navbar {
    view-transition-name: site-nav;
}

footer {
    view-transition-name: site-footer;
}

/* ⚠ Ici, « .hero-apple, .app-hero, .page-header, .hero-section » portaient un
   « view-transition-name: page-hero ». L'intention était d'éviter la double
   exposition en nommant le CONTENEUR plutôt que le <h1>. Le raisonnement était
   faux : un groupe nommé ne fond pas son contenu, il superpose l'instantané
   d'avant et celui d'après. Comme les deux heros n'ont ni le même texte, ni la
   même hauteur, on lisait littéralement « Les rencontres et l'entraide
   étudiante » À TRAVERS « Pensée pour ta réussite ». Constaté en captant la
   transition au ralenti.

   Le hero fait donc désormais partie de la racine et se déplace avec la page.
   Ne nommer que ce qui occupe LA MÊME PLACE dans les deux documents — la barre
   de navigation, le pied, le logo — sans quoi le trou laissé dans
   l'instantané de la racine se met à bouger sans rien pour le couvrir. */

/* ── POUSSÉE EN PROFONDEUR ──

   La page entrante GLISSE PAR-DESSUS la sortante, qui recule d'un plan. C'est
   le geste des applications natives : on comprend immédiatement qu'on avance,
   et rien ne se superpose.

   ⚠ LE POINT QUI FAISAIT TOUT RATER, à ne jamais retirer :

   Le navigateur pose lui-même « mix-blend-mode: plus-lighter » sur les deux
   instantanés de la racine. C'est indispensable à SON fondu croisé par défaut,
   qui additionne les deux images. Mais dès qu'on remplace ce fondu par autre
   chose, ce mode additif délave tout : les deux pages deviennent translucides
   et se superposent. Au ralenti, on lisait le titre de l'ancienne page à
   travers celui de la nouvelle.

   En composition normale, l'instantané de la page entrante est OPAQUE — il
   contient le fond du document — et recouvre donc franchement la sortante.
   C'est ce qui fait la différence entre « deux images qui se mélangent » et
   « une page qui passe devant une autre ».

   Aucun « filter » ici : ce sont des textures de la taille du viewport, et une
   passe de filtre par frame sur pareille surface est exactement ce que l'on
   s'interdit partout ailleurs dans cette feuille. Tout tient en transform, donc
   sur le compositeur. */
::view-transition-old(root),
::view-transition-new(root) {
    mix-blend-mode: normal;
}

/* Un fond sous les instantanés : la page sortante recule et se rétrécit, ce
   qui découvrirait sinon du vide sur ses bords. */
::view-transition {
    background-color: var(--surface-0);
}

::view-transition-old(root) {
    animation: vt-recede 520ms var(--ease-out-expo) both;
    transform-origin: 50% 50%;
}

::view-transition-new(root) {
    animation: vt-enter 520ms var(--ease-out-expo) both;
    /* Le bord d'attaque. C'est cette ombre, et elle seule, qui fait lire une
       page qui passe DEVANT une autre plutôt qu'un simple remplacement. */
    box-shadow: -30px 0 70px -10px rgb(var(--shadow-rgb) / calc(0.34 * var(--shadow-k)));
}

@keyframes vt-recede {
    to {
        /* Elle s'éloigne sans disparaître : elle sera de toute façon
           entièrement recouverte. La garder opaque évite tout scintillement. */
        transform: translateX(-18%) scale(0.94);
    }
}

@keyframes vt-enter {
    from {
        transform: translateX(100%);
    }
}

/* La barre de navigation et le pied restent parfaitement immobiles pendant que
   les deux pages défilent dessous : c'est ce contraste — un cadre fixe, un
   contenu qui glisse — qui fait tout l'effet.

   Ils doivent aussi rester OPAQUES : leur instantané couvre le trou que leur
   propre nom a creusé dans la racine, et ce trou, lui, se déplace. */
::view-transition-group(site-nav),
::view-transition-group(site-footer) {
    animation-duration: 320ms;
}

::view-transition-old(site-nav),
::view-transition-new(site-nav),
::view-transition-old(site-footer),
::view-transition-new(site-footer) {
    mix-blend-mode: normal;
    /* Aucun fondu : la nav est identique d'une page à l'autre, la faire
       clignoter n'apporterait rien et laisserait passer le glissement. */
    animation: none;
}

/* Côté ARRIVÉE, le portail est nommé en CSS et non en JS.
   pagereveal se déclenche AVANT l'exécution des scripts de fin de <body> :
   un écouteur enregistré dans animations.js arrive systématiquement trop
   tard. :target, lui, est évalué au tout premier rendu — exactement au bon
   moment, et sans une ligne de JavaScript.
   Une seule section peut être :target à la fois, donc aucun risque de
   view-transition-name dupliqué (ce qui annulerait toute la transition). */
.feature-section:target .device {
    view-transition-name: shot-portal;
}

/* ⚠ Ici se trouvait « animation: none ».
   L'intention était d'éviter un scintillement ; l'effet réel était de
   supprimer l'animation de groupe du navigateur — celle-là même qui fait
   voler le téléphone d'une page à l'autre. Le portail SAUTAIT donc à sa
   nouvelle place, et le moment fort de la navigation ne s'est jamais vu.

   On garde l'animation du navigateur et on ne règle que son allure. Sa durée
   et sa courbe sont RIGOUREUSEMENT celles de la poussée de page : le téléphone
   était auparavant plus court et sur un ressort, il se posait donc avant que
   la page ne finisse d'arriver et les deux mouvements se contredisaient. Ils
   partent et s'arrêtent désormais ensemble.

   Le téléphone reste décollé pendant tout son vol : l'ombre raconte la
   trajectoire mieux que le déplacement lui-même. */
::view-transition-group(shot-portal) {
    animation-duration: 520ms;
    animation-timing-function: var(--ease-out-expo);
    z-index: 3;
    border-radius: var(--r-xl);
    box-shadow: 0 42px 90px -20px rgb(var(--shadow-rgb) / calc(0.42 * var(--shadow-k)));
}

/* Le téléphone est un objet solide qui vole : il ne doit surtout pas devenir
   translucide en chemin. Même piège que pour la racine — le mode additif du
   navigateur le ferait fondre à travers la page. */
::view-transition-old(shot-portal),
::view-transition-new(shot-portal) {
    mix-blend-mode: normal;
}

/* ── REDUCED MOTION — accessibility ── */
@media (prefers-reduced-motion: reduce) {

    /* 1. Éléments qui commencent invisibles et n'apparaissent QUE par
          l'animation : sans mouvement, il faut les rendre visibles. */
    .line-reveal .line>*,
    .fade-in,
    .navbar,
    .hero-apple .hero-overline,
    .hero-apple .hero-subtitle,
    .hero-apple .hero-cta-group,
    .hero-apple .countdown-wrapper,
    .app-hero .hero-subtitle,
    .step-card.fade-in .step-number,
    .badge,
    .hero-text h1,
    .hero-text p,
    .hero-text .btn-submit-large {
        transition: none !important;
        animation: none !important;
        transform: none !important;
        opacity: 1 !important;
    }

    /* 2. Éléments décoratifs déjà visibles, dont l'opacité est un choix de
          design : ils doivent s'immobiliser, surtout PAS devenir opaques.
          Les inclure dans la liste ci-dessus rendait les formes du hero
          totalement bleues — discret sur fond blanc, criant en thème sombre. */
    .float-gentle,
    .float-gentle-reverse,
    .btn-hype,
    .app-hero .app-hero-icon,
    .notfound-radar::after,
    .roadmap-step.is-current .roadmap-marker::after,
    .consent-banner {
        transition: none !important;
        animation: none !important;
        transform: none !important;
    }

    .step-card.fade-in .step-number {
        transform: translateX(-50%) scale(1) !important;
    }

    .line-reveal .line>* {
        transform: translateY(0) !important;
        opacity: 1 !important;
    }

    html {
        scroll-behavior: auto;
    }
}

/* =============================================
   AFFINAGES SELON L'APPAREIL ET LES PRÉFÉRENCES

   Tout ce bloc est en amélioration progressive : un navigateur qui ne
   comprend pas une de ces requêtes ne l'applique simplement pas, et rend
   exactement ce qu'il rendait avant.
   ============================================= */

/* ── GAMUT ÉTENDU (P3) ──
   #0055FF est collé au bord du gamut sRGB : c'est le bleu le plus saturé
   qu'on puisse y écrire. Les écrans P3 — iPhone, iPad et Mac récents, une
   bonne partie des Android haut de gamme — savent aller nettement plus loin.

   L'identité ne change pas : c'est le MÊME bleu, simplement rendu sur toute
   l'étendue dont l'écran est capable. Partout ailleurs, la requête ne
   s'applique pas et #0055FF reste la valeur exacte. */
@media (color-gamut: p3) {
    :root {
        --brand: color(display-p3 0 0.32 1);
        --brand-hover: color(display-p3 0 0.25 0.8);
    }
}

/* ── CONTRASTE ÉLEVÉ (Windows) ──
   Le mode contraste forcé remplace autoritairement les couleurs par la
   palette choisie par l'utilisateur, souvent pour raison de vision. Nos
   couches décoratives — trame de points, aurore, grain, projecteur —
   passeraient alors PAR-DESSUS cette palette et la rendraient illisible.
   On les éteint, et on rétablit des bordures que le mode ne peut pas
   deviner seul. */
@media (forced-colors: active) {

    .bg-dots::before,
    .bg-aurora::after,
    body::after,
    .card-spot::before,
    .card-spot::after,
    .btn-nav::before,
    .notfound-radar::after {
        display: none;
    }

    /* En contraste forcé, une couleur de fond ne distingue plus rien :
       seule une bordure subsiste. */
    .faq-item,
    .notfound-exit,
    .consent-banner,
    .device__frame {
        border: 1px solid ButtonBorder;
    }

    .consent-btn,
    .btn-nav,
    .btn-hype {
        border: 1px solid ButtonBorder;
        /* forced-color-adjust: auto est la valeur par défaut ; on s'assure
           surtout de ne rien forcer qui empêcherait la substitution. */
    }

    /* L'anneau de focus est vital ici, et le navigateur ne le dessine pas
       toujours au-dessus des fonds. */
    :focus-visible {
        outline: 2px solid Highlight;
        outline-offset: 2px;
    }
}

/* ── TRANSPARENCE RÉDUITE ──
   backdrop-filter est ce qui coûte le plus cher dans la navbar collante.
   Quand l'utilisateur demande moins de transparence, on gagne à la fois en
   confort et en performance. */
@media (prefers-reduced-transparency: reduce) {

    .navbar,
    .consent-banner {
        backdrop-filter: none;
        background-color: var(--surface-0);
    }
}

/* ── ÉTAT DE DÉFILEMENT EN CSS ──
   Là où il est disponible, le navigateur sait dire lui-même qu'un élément
   collant a « accroché » le haut du viewport. Cela remplace la sentinelle de
   1 px et son IntersectionObserver — script.js interroge le même @supports et
   n'installe l'observateur que si le CSS ne peut pas s'en charger. */
@supports (container-type: scroll-state) {
    .navbar {
        container-type: scroll-state;
    }

    @container scroll-state(stuck: top) {
        .navbar {
            background-color: var(--surface-glass-dim);
            box-shadow: 0 2px 20px rgb(var(--shadow-rgb) / calc(0.08 * var(--shadow-k)));
        }
    }
}

/* ── CHAMP QUI GRANDIT ──
   Le message de motivation est le champ le plus important du formulaire, et
   celui qu'on écrivait dans une fenêtre de cinq lignes. Il suit désormais son
   contenu. Sans support, la valeur de rows="5" reste la hauteur de départ. */
.apple-form textarea {
    field-sizing: content;
    min-height: 8lh;
    max-height: 24lh;
}

/* Mention d'information RGPD sous le formulaire. */
.form-legal {
    font-size: 0.8rem;
    line-height: 1.6;
    color: var(--text-subtle);
    margin: var(--sp-5) 0 var(--sp-4);
    text-wrap: pretty;
}

.form-legal a {
    color: inherit;
    text-decoration: underline;
    text-underline-offset: 0.18em;
}
