/*
 * ==========================================================================
 * THÈME — l'identité visuelle de Mission Routine (PRP-08, ADR-027)
 * ==========================================================================
 *
 * Chargée AVANT toutes les autres feuilles, sur TOUTES les pages. C'est le seul
 * fichier où une couleur est DÉFINIE : partout ailleurs on consomme un jeton.
 * Un `#hex` écrit dans `app.css` ou `kid.css` est un défaut à corriger, pas un
 * raccourci — c'est ce qui garantit qu'un changement de palette est une ligne
 * ici et non une chasse dans cinq fichiers.
 *
 * Trois règles gouvernent ce fichier :
 *
 * 1. AUCUNE DÉPENDANCE EXTERNE (ADR-002). Pas de Google Fonts, pas de CDN,
 *    aucune police téléversée : la pile système arrondie fait le travail, et
 *    une feuille qui ne charge rien ne peut pas tomber en panne chez l'enfant.
 * 2. LA COULEUR N'EST JAMAIS LA SEULE INFORMATION. Un état se lit aussi à sa
 *    forme, son emoji ou son texte — l'application est utilisée par des enfants
 *    de 3 ans, dont certains distinguent mal le rouge du vert.
 * 3. TOUTE ANIMATION S'ÉTEINT SOUS `prefers-reduced-motion`. Le bloc est en fin
 *    de fichier et il est EXHAUSTIF : une `@keyframes` ajoutée plus haut sans
 *    son extinction en bas est un défaut. Les enfants sensibles au mouvement
 *    sont précisément le public visé.
 */

:root {
    /* --- Palette de marque -------------------------------------------------
       Six couleurs, pas douze. Chacune a un rôle et s'y tient : le violet
       porte l'action, le ciel porte le matin, la menthe porte la réussite, le
       soleil porte l'étoile, le corail porte l'erreur (côté ADULTE seulement),
       le raisin porte le soir. */
    --violet: #6c4bd8;
    --violet-deep: #4a2fa8;
    --violet-soft: #efeafd;
    --sky: #38b6f1;
    /* Le ciel CLAIR ne porte aucun texte : mesuré, du blanc dessus tombe à
       2,30:1 — et « Routine » en #38b6f1 sur blanc rend le MÊME 2,30:1, le
       contraste étant symétrique. Deux échecs AA francs, sur la marque
       elle-même. `--sky-deep` est la seule variante du ciel autorisée à porter
       ou recevoir du texte (5,39:1 contre blanc).
       ⚠️ CES TROIS CHIFFRES ONT ÉTÉ CORRIGÉS le 2026/08/27 (revue
       d'architecture de PRP-15) : ce cartouche portait « 2,2:1 », « 2,17:1 » et
       « 4,98:1 ». Aucun des trois n'était la valeur de sa paire, et le dépôt
       portait DEUX valeurs de la même paire — `bin/audit-ui.py` l. 97 grave
       2,30 pour `--sky` sur blanc depuis PRP-13, ce cartouche disait 2,17.
       Or c'est exactement l'usage d'un chiffre gravé que d'éprouver la sonde
       (gotcha « un objet dessiné hors de portée de la sonde ») : deux valeurs
       divergentes rendent la sonde inéprouvable. Recalculés par WCAG 2.x, la
       calculatrice ayant d'abord reproduit ONZE chiffres gravés de ce fichier
       (4,58 / 4,27 / 3,63 / 1,33 / 6,66 / 5,78 / 9,28 / 5,90 / 9,01 / 7,36 /
       7,83) — une calculatrice qui ne retrouve pas un chiffre connu ne prouve
       rien des inconnus. Le « 5,02 » de la note ci-dessous, lui, est JUSTE :
       c'est le blanc sur l'ANCIEN `--sky-deep` #1176a8, une autre paire.
       ⚠️ Les mentions historiques de 2,17 et 2,2 dans `DECISIONS.md` (ADR-027)
       et `ROADMAP.md` sont DÉLIBÉRÉMENT laissées : ce sont des relevés datés de
       PRP-08, pas des affirmations courantes sur la palette. */
    /* Assombri de 4 % le 2026/08/20 : à #1176a8 le mot « Routine » de la marque
       mesurait 4,27:1 sur `--violet-soft`, l'extrémité claire du lavis radial du
       body — sous le seuil AA de 4,5. Mesuré par `bin/audit-ui.py`, jamais lisible
       dans une règle. #1071a1 rend 4,58:1 au pire des trois lavis, et fait MONTER
       le texte blanc de la bande d'appel de 5,02 à 5,39:1. */
    --sky-deep: #1071a1;
    --sky-soft: #e4f5fe;
    --mint: #2ecc96;
    /* Assombri de #0f8f63 : à l'ancienne valeur, le texte des messages de
       succès et de la pastille menthe tombait à 3,72:1 sur `--mint-soft`. */
    --mint-deep: #0a7350;
    --mint-soft: #e3f9f0;
    --sun: #ffc93c;
    --sun-deep: #d99b00;
    --sun-soft: #fff4d6;
    --coral: #ef4b5e;
    --coral-soft: #fdeaec;

    /* --- Jetons sémantiques -----------------------------------------------
       Les noms d'origine sont conservés : `app.css`, `kid.css`, `stars.css`,
       `gauge.css` et `trophies.css` les consomment déjà. Seules les VALEURS
       changent, ce qui repeint l'application entière sans toucher une règle. */
    --bg: #fbf7ff;
    --bg-deep: #f1eaff;
    --surface: #ffffff;
    --ink: #241f3d;
    --muted: #5f5878;
    --line: #e2dcf2;
    --accent: var(--violet);
    --accent-deep: var(--violet-deep);
    --accent-soft: var(--violet-soft);
    /* Couleurs « SUR fond » — le pendant obligé d'ADR-027 : sans elles, chaque
       feuille réécrivait son propre `#fff` ou son propre brun, et le dépôt en
       comptait DIX-SEPT hors de ce fichier (mesuré le 2026/08/20). Contrastes
       mesurés, pas supposés : blanc sur --accent 5,78:1, sur --accent-deep
       9,28:1, sur --error 5,90:1 ; --on-sun sur --sun 9,01:1 ; --on-sun-soft
       sur --sun-soft 7,36:1 ; --on-sky-soft sur --sky-soft 7,83:1. */
    --on-accent: #ffffff;
    --on-sun: #3b2a00;
    --on-sun-soft: #6b4a00;
    --on-sky-soft: #10506f;
    --error: #c22133;
    --success: var(--mint-deep);

    /* L'étoile de l'écran 3 a son propre jeton, et ce n'est pas du
       raffinement : elle est dessinée en `clip-path`, donc sans bordure
       possible, et sa seule lisibilité vient du contraste de son aplat contre
       le fond de page. Réutiliser `--bg-deep` la rendait quasi invisible sur
       le nouveau fond lilas — mesuré en navigateur, invisible à tout test PHP.
       C'est l'étoile EN ATTENTE, le fond que le liquide recouvre en montant.
       ⚠️ Un second jeton vivait ici jusqu'à ADR-030 — le socle d'une case de la
       grille, et la grille n'existe plus. Retiré plutôt que laissé :
       `StyleCoverageTest` vérifie qu'une CLASSE de gabarit porte une règle,
       jamais qu'un JETON est consommé, donc un jeton mort passerait en silence,
       pour toujours. */
    /* LE CHROME DE L'ESPACE ADULTE (ADR-038) — trois jetons, AUCUNE couleur
       neuve : chacun pointe sur un jeton déjà défini plus haut.

       ⚠️ `--surface-2` désigne le PLATEAU de page, JAMAIS une carte teintée.
       La lecture littérale du ROADMAP (« --surface-2 sur .card ») est RÉFUTÉE :
       `--accent-soft` vaut `--violet-soft` vaut #efeafd, donc une carte à cette
       teinte met DOUZE pastilles d'`app.css` à 1,00:1 — le texte reste lisible,
       le BOUTON disparaît. Le nom est conservé pour rester trouvable depuis le
       ROADMAP ; le sens ne l'est pas. */
    --surface-2: var(--bg-deep);
    --band-top: var(--ink);
    --band-bottom: var(--accent-deep);

    --star-empty: #ded5f7;

    /* Le rond VIDE du marqueur « c'est fait » (ADR-032), avant la coche. Un
       jeton PROPRE parce qu'aucun jeton existant ne convenait, et les deux
       candidats d'instinct échouent tous deux — mesuré, jamais supposé :
       `--line` (le jeton des bordures) rend 1,33:1 sur blanc, donc quasi
       invisible, ce qui annulerait la décision même de montrer une CIBLE à
       l'enfant ; `--muted` rend 6,66:1, visible mais lourd pour un état « à
       faire », et un rond trop noir redevient un cadrage négatif. Celui-ci rend
       3,63:1 — au-dessus du plancher de 3:1 des composants d'interface NON
       TEXTUELS, sans devenir une colonne de reproches en bout de chaque rangée.
       ⚠️ Ce chiffre a été mesuré À LA MAIN, la sonde de contraste historique
       ne retenant que les éléments porteurs d'un nœud de TEXTE — qu'un objet
       DESSINÉ n'a par définition pas. La SEPTIÈME sonde de `bin/audit-ui.py`
       (PRP-13, même tranche) le remesure désormais contre le plancher de 3:1,
       ce rond étant un `stroke` SVG : le retirer ou l'exempter rendrait ce
       nombre à nouveau invérifiable. */
    --check-idle: #8b7fb3;

    /* --- Rythme ------------------------------------------------------------
       Un seul jeu de rayons et d'ombres. Les coins sont FRANCHEMENT ronds :
       c'est le premier signal « ceci est pour les enfants », avant même la
       couleur, et il coûte une propriété. */
    --r-sm: 10px;
    --r-md: 16px;
    --r-lg: 24px;
    --r-xl: 32px;
    --r-pill: 999px;

    --shadow-sm: 0 2px 6px rgba(36, 31, 61, 0.07);
    --shadow-md: 0 6px 18px rgba(36, 31, 61, 0.10);
    --shadow-lg: 0 16px 40px rgba(36, 31, 61, 0.16);
    /* L'ombre PORTÉE des cibles enfant : un relief franc qui dit « ça
       s'enfonce », et qui disparaît au `:active`. Un enfant de 3 ans ne connaît
       pas le survol — il connaît l'appui. */
    --shadow-press: 0 5px 0 rgba(74, 47, 168, 0.22);

    /* --- Typographie -------------------------------------------------------
       Pile ARRONDIE d'abord (Apple `ui-rounded`, Windows Segoe UI Variable),
       repli sur la pile système. Aucune police n'est téléchargée : voir la
       règle 1 du cartouche. */
    --font: ui-rounded, "SF Pro Rounded", "Segoe UI Variable Display",
        "Segoe UI", system-ui, -apple-system, Roboto, "Helvetica Neue", sans-serif;

    /* --- Durées ------------------------------------------------------------ */
    --t-fast: 140ms;
    --t-mid: 260ms;
    --t-slow: 520ms;

    /* --- DÉCOR (ADR-035) ---------------------------------------------------
       Le décor de CHAQUE enfant, en quatre jetons. Ces valeurs-ci sont celles
       de la MAISON — l'espace parent, le site public, `/login` : partout où
       aucune classe `kid-decor--` n'est posée. Elles sont DÉPLACÉES depuis
       l'existant, pas inventées : le sol est `--bg`, la bordure `--line`, la
       tuile `--surface`. L'apparence sans décor est donc celle d'hier PAR
       CONSTRUCTION.

       🔴 IL N'Y A NI CLASSE MARQUEUR NI SÉLECTEUR D'ATTRIBUT, et ce n'est pas
       une économie. Une propriété personnalisée redéfinie par
       `body.kid-decor--x` (0,2,1) est dans la PORTÉE des déclarations de `body`
       (0,0,1) : c'est la valeur CALCULÉE DU JETON SUR L'ÉLÉMENT qui décide,
       jamais l'ordre des règles. Donc aucun combat de spécificité, et le décor
       par défaut n'est pas une règle à écrire — c'est l'absence de classe.

       `none` est un `<bg-image>` PARFAITEMENT VALIDE dans une liste de couches :
       la première couche est simplement vide, et les trois lavis qui suivent
       gardent exactement leur rendu d'hier. */
    --decor-sol: var(--bg);
    --decor-bord: var(--line);
    --decor-tuile: var(--surface);

    /* L'ENCRE DU DÉCOR (ADR-036) — la couleur des QUATRE textes qui reposent
       DIRECTEMENT sur la scène : `.kid-title`, `.kid-who__name`,
       `.kid-progress__text`, `.kid-gauge__total-count`. Tout le reste du
       parcours enfant vit sur un panneau OPAQUE et garde `--ink`.

       Le défaut vaut `--ink` : une page SANS décor — l'espace parent, le site
       public, `/login` — rend donc exactement ce qu'elle rendait hier. Une
       page ajoutée sans y penser hérite du choix sûr, jamais d'un blanc
       invisible sur fond clair. */
    --decor-ink: var(--ink);

    /* LA HAUTEUR DES DEUX BANDES DE SCÈNE (ADR-036), et il n'y a QU'UNE source.
       🔴 TROIS règles les consomment — la boîte du calque, et les deux marges
       que `.shell` réserve pour que le contenu ne les chevauche PAS. Les écrire
       trois fois les ferait diverger au premier ajustement, et la divergence
       n'aurait rien de visible : le titre glisserait simplement SUR le décor,
       ce qui est exactement le défaut mesuré sur le prototype (une planète sous
       le titre, du blanc sur un aplat orange, ~2,6:1). C'est la huitième sonde
       de `bin/audit-ui.py` qui l'attrape désormais — mais une garde n'excuse
       pas une duplication qu'on peut ne pas écrire. */
    /* 🔴 LA HAUTEUR SUIT LA LARGEUR, ET C'EST LE CORRECTIF D'UN DÉFAUT VU EN
       PRODUCTION SUR GRAND ÉCRAN (ADR-037, amendé le 2026-08-28).

       Première rédaction : `min(69vw, 26rem)`. Une hauteur PLAFONNÉE sous un
       `background-size: cover` fait scaler le dessin sur la LARGEUR puis le
       ROGNE en hauteur. Mesuré :

         largeur   échelle   dessin rendu   % du viewBox VU
           390 px    1,08x        271 px          99 %
           768 px    2,13x        533 px          78 %
          1920 px    5,33x       1333 px          31 %

       À 1920 px, un soleil de 25 unités devenait un disque de 267 px, et — bien
       pire — la fraction `--decor-opaque` DEVENAIT FAUSSE : elle suppose qu'on
       voit tout le viewBox, alors qu'on n'en voyait que le tiers haut. Les
       oiseaux du bas du dessin remontaient donc dans la bande du titre, à
       l'endroit exact que cette fraction existe pour protéger.

       Le rapport largeur/hauteur du calque est désormais CELUI du viewBox, et
       la largeur est plafonnée à celle de la colonne de contenu : `cover` ne
       rogne plus RIEN à aucune largeur, donc la fraction redevient vraie. Les
       côtés d'un grand écran montrent le dégradé, qui EST le ciel.

       ⚠️ Les deux constantes de division sont les rapports des viewBox
       (360/250 et 360/140). Les changer sans changer les SVG rend le contrat de
       fraction faux EN SILENCE — c'est pourquoi la huitième sonde compare
       désormais le rapport de la BOÎTE à celui du DESSIN. */
    --decor-largeur: 100%;
    --decor-h-ciel: max(calc(100vw * 340 / 1440), 9rem);
    --decor-h-sol: max(calc(100vw * 220 / 1440), 6rem);

    /* LA FRACTION DE LA BANDE QUI PORTE DES OBJETS, comptée depuis son bord
       ancré. Le reste est le FONDU du SVG, donc vide.

       🔴 C'EST CE CHIFFRE, ET NON LA HAUTEUR, QUE `.shell` RÉSERVE — et c'est
       aussi lui que lit la huitième sonde de `bin/audit-ui.py`. Réserver la
       bande ENTIÈRE repousserait le contenu de 269 px sur un téléphone pour
       rien, puisque sa moitié basse ne peint rien ; n'en réserver aucune
       remettrait le titre SUR la planète, à 2,6:1 — le défaut que la maquette
       avait elle-même relevé.

       Ces deux valeurs DOIVENT correspondre au `stop-opacity` des masques des
       SVG (0,54 pour le ciel, 0,38 depuis le haut pour le sol, donc 0,62
       depuis le bas). Les faire diverger décale la zone gardée par rapport à
       la zone dessinée, en silence. */
    --decor-opaque-ciel: 0.56;
    --decor-opaque-sol: 0.64;

    /* LES CINQ CIELS (ADR-036). Deux arrêts par décor, et l'arrêt BAS est le
       SOL — la couleur opaque peinte sous tout le reste, donc l'empreinte
       qu'exige le comparateur `--distinct-backdrop` de `bin/audit-ui.py`, où
       un fond absent est un échec FERME.

       🔴 CES DIX VALEURS SONT DES `#hex`, ET C'EST LEUR PLACE : `theme.css`
       est LE fichier où une couleur se DÉFINIT (ADR-027). `ThemeCatalog` n'en
       porte que les NOMS, et `ThemeCatalogTest` les résout ici pour mesurer
       l'encre contre les deux arrêts.

       Contrastes GRAVÉS, mesurés le 2026-08-28 avant d'écrire la règle, témoin
       de méthode inclus (sept chiffres déjà gravés du dépôt reproduits, 7/7) :

         décor        encre     pire arrêt   rapport
         lilas        #241f3d   #cfe0fb      11,74:1
         espace       #ffffff   #6b3f96       7,56:1
         dinosaures   #ffffff   #166f52       6,12:1
         vehicules    #ffffff   #9e5222       5,70:1
         animaux      #ffffff   #843268       7,96:1

       Le plancher des cinq est 5,82 — au-dessus du 4,5 d'AA, et au-dessus du
       5,66 que le filigrane d'ADR-035 atteignait au MIEUX. C'est la mesure qui
       JUSTIFIE le renversement : un fond profond autorise du blanc, un fond
       pâle impose du gris.

       ⚠️ `vehicules` est le plus serré des cinq, et c'est un arbitrage DATÉ du
       2026-08-28 : son ciel a été RÉCHAUFFÉ après la passe « regarder les cinq
       décors », où le brun d'origine (#3d1405 → #7d3410) rendait un aplat
       terne sur toute la bande médiane. Le réchauffer coûte du contraste —
       8,11 → 5,82 — et il reste 1,3 point de marge sur AA. Ne pas l'éclaircir
       davantage sans REMESURER : le prochain cran passe sous le plancher.

       Séparation ΔE2000 des cinq ciels : minimum 13,36 (seuil 8 d'ADR-035). */
    --decor-lilas-c1: #cfe0fb;
    --decor-lilas-c2: #dde8fd;
    --decor-lilas-c3: #ebe6fc;
    --decor-lilas-c4: #f6eefe;
    --decor-espace-c1: #140f33;
    --decor-espace-c2: #2a1d5e;
    --decor-espace-c3: #4a2f86;
    --decor-espace-c4: #6b3f96;
    --decor-dinosaures-c1: #04241a;
    --decor-dinosaures-c2: #093c2c;
    --decor-dinosaures-c3: #0f5540;
    --decor-dinosaures-c4: #166f52;
    --decor-vehicules-c1: #3a1206;
    --decor-vehicules-c2: #5c2410;
    --decor-vehicules-c3: #7d3a18;
    --decor-vehicules-c4: #9e5222;
    --decor-animaux-c1: #240a20;
    --decor-animaux-c2: #431436;
    --decor-animaux-c3: #62214e;
    --decor-animaux-c4: #843268;
}

* {
    box-sizing: border-box;
}

html {
    /* Une ancre `#…` qui saute brutalement désoriente ; ici elle glisse. */
    scroll-behavior: smooth;
}

body {
    margin: 0;
    min-height: 100vh;
    color: var(--ink);
    font: 17px/1.6 var(--font);
    /* `background-color` et JAMAIS le raccourci `background:` — ce dernier
       remet `background-image` à `none` (G16), donc effacerait le motif du
       décor déclaré deux lignes plus bas. Le fichier vivait jusqu'ici avec le
       raccourci suivi de `background-image`, ce qui ne marchait QUE par l'ordre
       des déclarations : fragile, et sans raison de l'être. */
    background-color: var(--decor-sol);
    /* Le ciel : deux halos très pâles, fixes, qui donnent de la profondeur sans
       coûter une image ni gêner la lecture. `background-attachment: fixed` est
       volontairement absent — il est coûteux et saccadé sur iOS.

       Le MOTIF du décor (ADR-035) est la PREMIÈRE couche, donc au-dessus des
       lavis. Sans décor il vaut `none` et la couche est vide. */
    background-image:
        radial-gradient(60rem 30rem at 12% -8%, var(--sky-soft) 0%, transparent 60%),
        radial-gradient(48rem 26rem at 92% 4%, var(--violet-soft) 0%, transparent 62%),
        radial-gradient(40rem 24rem at 50% 100%, var(--sun-soft) 0%, transparent 58%);

    /* 🔴 CES DEUX LISTES SONT ÉCRITES EN ENTIER, UNE ENTRÉE PAR COUCHE, ET
       C'EST PORTANT (G18 de PRP-15, ADR-035 point 2-bis).

       TOUTES les propriétés `background-*` sont des LISTES indexées sur les
       couches de `background-image`, et une liste PLUS COURTE que le nombre de
       couches est RECYCLÉE sur les suivantes (CSS Backgrounds 3, § Layering
       multiple background images). Ce bloc portait `background-repeat:
       no-repeat` — UNE valeur pour TROIS couches : le motif ajouté en première
       position en aurait hérité et se serait peint UNE SEULE FOIS, en haut à
       gauche, au lieu de carreler. Et `background-size` n'était pas déclarée du
       tout, donc `auto` — qui, sur un SVG SANS dimensions intrinsèques, se
       résout en `contain` : un motif étiré sur toute la page.

       Les deux défauts sont MUETS : aucun test PHP ne lit `background-repeat`,
       et la garde croisée constate seulement qu'une RÈGLE EXISTE. Seul le
       comparateur `--distinct-backdrop` de `bin/audit-ui.py` les voit, et
       uniquement parce qu'il lit ces deux propriétés COUCHE PAR COUCHE.

       ⚠️ Et ce contrôle NE PEUT PAS s'écrire en comparant la LONGUEUR de la
       liste au nombre de couches : mesuré le 2026/08/27, le navigateur rend
       toujours ces listes DÉJÀ DÉPLIÉES — raccourcir celle-ci à
       `background-size: 200px 200px` ressort du style calculé en quatre
       entrées identiques, et la première rédaction du comparateur, écrite par
       longueur, sortait ✅ sur exactement cette mutation. C'est la VALEUR de
       chaque couche qui porte : les lavis restent `auto` / `no-repeat`.

       Ne jamais compter sur le recyclage : il est correct au sens de la
       spécification et faux au sens de l'intention. */
    background-repeat: no-repeat, no-repeat, no-repeat;
    background-size: auto, auto, auto;
    -webkit-text-size-adjust: 100%;

    /* L'ANCRE des deux calques de scène (ADR-036). `.kid-decor__ciel` et
       `.kid-decor__sol` sont `position: absolute` : sans conteneur positionné,
       ils se caleraient sur le bloc conteneur initial et le calque du BAS
       viserait le bas de la fenêtre au lieu du bas du document.

       `position: relative` sur `body` n'a AUCUN autre effet ici — le corps de
       page ne porte ni `top` ni `z-index`, et le seul élément qui s'y superpose
       (`.kid-done`, en `position: fixed`) échappe par construction au
       positionnement d'un ancêtre non transformé. */
    position: relative;

    /* L'adresse de contact de `/confidentialite` fait 45 caractères SANS
       espace : à 320 px elle débordait de 116 px (mesuré). Avec le
       `overflow-x: clip` ci-dessous, un débordement n'est plus atteignable au
       défilement — il est simplement COUPÉ —, donc le filet transformerait une
       gêne en perte d'information sur la page qui porte le recours Loi 25.
       `break-word` plutôt qu'`anywhere` : il ne coupe QUE le mot qui ne tient
       pas, et laisse la prose française se composer normalement. */
    overflow-wrap: break-word;

    /* Le FILET contre le défilement horizontal, jamais l'excuse pour en créer.
       `clip` et non `hidden` : `hidden` ferait du `<body>` un conteneur de
       défilement, ce qui casse `position: sticky` et le glissement vers une
       ancre. Un débordement reste un défaut à corriger à sa source — celui du
       héros l'a été (voir `site.css`) ; cette ligne empêche seulement qu'un
       futur oubli offre une barre horizontale à un enfant sur tablette, qui la
       trouvera avant nous. */
    overflow-x: clip;
}

.shell {
    max-width: 46rem;
    margin: 0 auto;
    padding: 1.25rem 1rem 3rem;
}

/* La page publique respire plus large que les écrans d'application. */
.shell--wide {
    max-width: 68rem;
}

h1,
h2,
h3 {
    font-weight: 800;
    letter-spacing: -0.015em;
    line-height: 1.2;
}

h1 {
    font-size: clamp(1.7rem, 1.2rem + 2vw, 2.3rem);
    margin: 0.2rem 0 1rem;
}

h2 {
    font-size: 1.3rem;
}

a {
    color: var(--accent-deep);
    text-underline-offset: 0.18em;
}

a:hover {
    color: var(--violet);
}

:focus-visible {
    outline: 3px solid var(--sky);
    outline-offset: 3px;
    border-radius: 4px;
}

/* ==========================================================================
   Identité — la marque, faute de logo dessiné par un tiers
   Le titre EST le logo : deux mots, deux couleurs, une étoile. Rendu en texte
   et non en image, donc il reste net à toute taille, se lit par un lecteur
   d'écran et ne coûte aucune requête.
   ========================================================================== */

.brand {
    display: inline-flex;
    align-items: center;
    gap: 0.55rem;
    text-decoration: none;
    color: inherit;
    font-weight: 800;
    letter-spacing: -0.02em;
    line-height: 1;
}

.brand__mark {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.4em;
    height: 2.4em;
    flex: 0 0 auto;
    border-radius: 30%;
    background: linear-gradient(150deg, var(--sun) 0%, var(--coral) 55%, var(--violet) 100%);
    box-shadow: var(--shadow-sm);
    font-size: 0.62em;
}

.brand__mark svg {
    width: 62%;
    height: 62%;
    display: block;
}

.brand__words {
    display: grid;
    line-height: 1.05;
}

.brand__word--1 {
    color: var(--violet-deep);
}

.brand__word--2 {
    color: var(--sky-deep);
}

.brand--lg {
    font-size: 2rem;
}

.brand--sm {
    font-size: 1.15rem;
}

/* La marque est un lien vers l'accueil : elle a droit au même seuil tactile que
   les autres. Le rembourrage est horizontalement nul pour ne pas la décaler. */
a.brand {
    min-height: 44px;
    padding: 0.15rem 0;
}

/* ==========================================================================
   En-tête et pied de page (chrome)
   Absents du parcours enfant : l'écran 1 n'offre qu'un ⚙️ discret, et une
   barre de navigation y serait une porte de sortie à portée de doigt.
   ========================================================================== */

/* Premier élément focusable de la page : hors de l'écran tant qu'il n'a pas le
   focus, puis visible. Sans lui, un visiteur au clavier retraverse l'en-tête à
   chaque page. */
.skip-link {
    position: absolute;
    left: -9999px;
    top: 0;
    z-index: 100;
    padding: 0.7rem 1.1rem;
    border-radius: 0 0 var(--r-md) 0;
    background: var(--accent);
    color: #fff;
    font-weight: 700;
    text-decoration: none;
}

.skip-link:focus {
    left: 0;
    color: #fff;
}

.site-header {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    max-width: 68rem;
    margin: 0 auto;
    padding: 0.9rem 1rem;
}

.site-header__nav {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.4rem 1rem;
}

/* 40 px mesurés à 768 px de large le 2026/08/20 — sous le seuil, et invisible
   au format téléphone où ce lien quitte l'en-tête (voir la requête média plus
   bas). C'est le constat qui a justifié de mesurer les cibles à DEUX largeurs :
   un défaut peut n'exister qu'en tablette, l'appareil que ce projet vise. */
.site-header__link {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    font-weight: 600;
    text-decoration: none;
    padding: 0.4rem 0;
}

.site-header__link:hover {
    text-decoration: underline;
}

/* Sous 560 px, le lien « Confidentialité » quitte l'en-tête : il est déjà dans
   le pied de page, et trois cibles empilées y repoussaient le héros hors de
   l'écran d'ouverture. Les deux gestes qui COMPTENT restent. */
@media (max-width: 560px) {
    .site-header__link {
        display: none;
    }
}

.site-footer {
    max-width: 68rem;
    margin: 2rem auto 0;
    padding: 1.5rem 1rem 2rem;
    border-top: 1px solid var(--line);
    color: var(--muted);
    font-size: 0.9rem;
    text-align: center;
}

.site-footer__links {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0 1.25rem;
    margin: 0 0 0.4rem;
    padding: 0;
    list-style: none;
}

/* 20 px de haut sans ceci — trois liens serrés au bas d'un téléphone, dont on
   touche le voisin une fois sur deux. Le rembourrage vertical ne change rien à
   l'apparence, il ne fait qu'agrandir la CIBLE. */
.site-footer__links a {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
}

.site-footer__legal {
    margin: 0;
}

/* ==========================================================================
   Boutons — une seule famille, trois poids
   `.btn` est la forme canonique. `app.css` habille encore `button` nu pour les
   formulaires existants ; les deux partagent les mêmes jetons, donc rien ne
   diverge.
   ========================================================================== */

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    min-height: 48px;
    padding: 0.7rem 1.35rem;
    border: 0;
    border-radius: var(--r-pill);
    background: var(--accent);
    color: #fff;
    font: inherit;
    font-weight: 700;
    text-decoration: none;
    cursor: pointer;
    box-shadow: var(--shadow-press);
    transition: transform var(--t-fast) ease, box-shadow var(--t-fast) ease,
        background-color var(--t-fast) ease;
}

.btn:hover {
    background: var(--violet-deep);
    color: #fff;
    transform: translateY(-2px);
}

/* L'appui ENFONCE réellement le bouton : l'ombre portée se résorbe et le
   bouton descend d'autant. C'est le retour tactile le plus lisible pour un
   enfant qui ne lit pas encore. */
.btn:active {
    transform: translateY(3px);
    box-shadow: 0 2px 0 rgba(74, 47, 168, 0.22);
}

.btn--lg {
    min-height: 60px;
    padding: 0.95rem 2rem;
    font-size: 1.2rem;
}

.btn--sun {
    background: var(--sun);
    color: #3b2a00;
    box-shadow: 0 5px 0 rgba(217, 155, 0, 0.45);
}

.btn--sun:hover {
    background: #ffd45f;
    color: #3b2a00;
}

.btn--ghost {
    background: transparent;
    color: var(--accent-deep);
    border: 2px solid var(--line);
    box-shadow: none;
}

.btn--ghost:hover {
    background: var(--accent-soft);
    color: var(--accent-deep);
    border-color: var(--accent);
}

/* Pot de miel du formulaire de demande d'accès (ADR-017).

   ⚠️ IL VIT DANS *CETTE* FEUILLE, chargée sur toutes les pages, et non dans la
   feuille du site public chargée conditionnellement : si la seule feuille qui
   le masque venait à ne pas charger, le champ deviendrait VISIBLE et un
   visiteur humain le remplirait — sa demande serait alors silencieusement
   jetée. Un dispositif muet par conception ne doit dépendre d'aucun chargement
   optionnel.

   `aria-hidden` et `tabindex="-1"` sont posés dans le gabarit : un champ
   invisible mais atteignable au clavier ou annoncé par un lecteur d'écran
   piégerait un visiteur au lieu d'un robot. */
.honeypot {
    position: absolute;
    left: -9999px;
    width: 1px;
    height: 1px;
    overflow: hidden;
    opacity: 0;
}

/* ==========================================================================
   Animations — la bibliothèque commune
   Toutes déclarées ici, toutes éteintes en fin de fichier. Une `@keyframes`
   définie ailleurs échapperait au bloc d'extinction : ne pas en écrire.
   ========================================================================== */

@keyframes mr-float {
    0%, 100% { transform: translateY(0); }
    50%      { transform: translateY(-10px); }
}

@keyframes mr-drift {
    0%   { transform: translate3d(0, 0, 0) rotate(0deg); }
    50%  { transform: translate3d(14px, -12px, 0) rotate(6deg); }
    100% { transform: translate3d(0, 0, 0) rotate(0deg); }
}

@keyframes mr-pop {
    0%   { transform: scale(0.82); opacity: 0; }
    60%  { transform: scale(1.04); opacity: 1; }
    100% { transform: scale(1); opacity: 1; }
}

@keyframes mr-rise {
    0%   { transform: translateY(14px); opacity: 0; }
    100% { transform: translateY(0); opacity: 1; }
}

@keyframes mr-twinkle {
    0%, 100% { transform: scale(1) rotate(0deg); opacity: 0.85; }
    50%      { transform: scale(1.18) rotate(12deg); opacity: 1; }
}

@keyframes mr-wiggle {
    0%, 100% { transform: rotate(0deg); }
    25%      { transform: rotate(-4deg); }
    75%      { transform: rotate(4deg); }
}

@keyframes mr-sheen {
    0%   { background-position: -140% 0; }
    100% { background-position: 240% 0; }
}

.anim-float  { animation: mr-float 4s ease-in-out infinite; }
.anim-drift  { animation: mr-drift 11s ease-in-out infinite; }
.anim-pop    { animation: mr-pop var(--t-mid) ease-out both; }
.anim-rise   { animation: mr-rise var(--t-slow) ease-out both; }
.anim-twinkle { animation: mr-twinkle 2.6s ease-in-out infinite; }

/* Décalages, pour qu'une rangée d'éléments n'ondule pas au garde-à-vous. */
.anim-delay-1 { animation-delay: 0.15s; }
.anim-delay-2 { animation-delay: 0.35s; }
.anim-delay-3 { animation-delay: 0.55s; }
.anim-delay-4 { animation-delay: 0.75s; }

.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* ==========================================================================
   LE CHROME DE L'ESPACE ADULTE (ADR-038)
   ==========================================================================

   Trois étages, et le troisième est celui qu'on ATTENDAIT le plus et qu'il ne
   faut surtout PAS faire :

     1. un BANDEAU de tête profond, portant la marque en clair ;
     2. un PLATEAU de page (`--surface-2`) ;
     3. des CARTES qui restent BLANCHES.

   🔴 CE QUE CE BLOC REFUSE, ET C'EST SON CŒUR. Le ROADMAP prescrivait
   « `--surface-2` sur `.card` ». Mesuré : `--accent-soft` VAUT `--violet-soft`
   VAUT `#efeafd`. Une carte teintée à cette valeur met à **1,00:1** les DOUZE
   sites `--accent-soft` d'`app.css` — les pastilles de navigation du tableau de
   bord, les flèches ↑ ↓ ✕, le sélecteur d'emoji. Le TEXTE y reste lisible
   (13,34), mais l'AFFORDANCE DE BOUTON disparaît, sur l'écran qu'un parent
   remplit debout. Le nom `--surface-2` est conservé pour rester trouvable
   depuis le ROADMAP, mais il désigne le PLATEAU, jamais une carte.

   Corollaire, et il est gros : `.card` n'est pas touchée, donc le ricochet sur
   les NEUF gabarits hors espace parent (6 auth + 2 admin + 1 menu) — dont HUIT
   ne sont rendus par aucun harnais — n'existe tout simplement pas.

   ── POURQUOI UN BANDEAU PROFOND, QUE LE ROADMAP DONNAIT POUR RISQUÉ ────────
   Il avait raison sur le fait et tort sur la conclusion. Mesuré : `--sky-deep`
   sur un en-tête `#e9e2fb` rend **4,29 — échec AA** ; sur `#efeafd`, **4,58**,
   à 0,08 du plancher. Un bandeau PÂLE est donc un cul-de-sac. Un bandeau
   PROFOND dissout la contrainte : la marque y passe de 4,58 à **8,30**. C'est
   la mesure d'ADR-036 appliquée au chrome adulte — un fond pâle impose du gris,
   un fond profond autorise du blanc — et elle fait MONTER le chiffre le plus
   serré du dépôt.

   🔴 LE BANDEAU EST PEINT SUR `.site-header`, JAMAIS EN COUCHE DU `<body>`.
   `JS_CONTRAST` moissonne les arrêts du PREMIER ancêtre à dégradé, quelle que
   soit la géométrie : un bandeau posé sur le corps de page ferait mesurer le
   `h1` du plateau contre `#241f3d`, soit **1,00:1** — un ÉCHEC rapporté sur du
   CSS parfaitement sain. Même défaut, même remède qu'ADR-036.

   Contrastes GRAVÉS, mesurés le 2026-08-28, témoin de méthode inclus (sept
   chiffres déjà gravés du dépôt reproduits, 7/7) :

     marque « Mission »  --violet-soft sur bandeau   7,89   (pire arrêt)
     marque « Routine »  --sky-soft    sur bandeau   8,30   (était 4,58)
     h1                  --ink         sur plateau  13,41   (était 14,83)
     texte discret       --muted       sur plateau   5,69   (était  6,29)
     lien de retour      --accent-deep sur plateau   7,93   (était  8,77)
     erreur / succès                   sur plateau   5,04 / 5,01
     carte BLANCHE                     sur plateau   1,17   (était  1,06)

   Plancher de la tranche : **5,01**. Aucun jeton ne descend sous 4,99.

   ⚠️ CE QUE L'AUDIT NE VERRA PAS, et il faut l'écrire. L'ombre de la carte porte
   l'essentiel de la profondeur perçue, et AUCUNE sonde ne mesure une ombre. La
   bordure `--line` tombe de 1,33 à 1,14 contre le plateau : elle cesse d'être le
   porteur de séparation, ce qui est acceptable — un conteneur n'est pas un
   composant au sens de WCAG 1.4.11 — mais doit être DIT, sans quoi quelqu'un
   « corrigera » `--line` et repeindra tout le dépôt.

   ⚠️ INTERDIT : un slug `.kid-decor--parent`. `ThemeCatalogTest` est
   bidirectionnel et exigerait qu'une telle règle corresponde à une entrée du
   catalogue, c'est-à-dire à un décor OFFERT AUX ENFANTS. Et la règle
   `body[class*="kid-decor--"] .shell` poserait des dizaines de rem de marge sur
   un écran parent. L'espace adulte n'a PAS de slug. */

/* Le PLATEAU. `background-image: none` REMPLACE les trois lavis de la maison,
   il ne s'y ajoute pas : trois lavis pâles laissés sous un bandeau sombre
   reproduiraient le faux échec décrit plus haut (ADR-036, contrainte 2). */
body.app-area {
    background-color: var(--surface-2);
    background-image: none;
}

/* Le BANDEAU. `max-width: none` pour qu'il traverse la page ; le contenu reste
   centré par un rembourrage calculé, donc SANS élément supplémentaire — et le
   bandeau reste l'ANCÊTRE de la marque, ce qui est la condition pour que
   `JS_CONTRAST` mesure la vraie paire. */
.app-area .site-header {
    max-width: none;
    padding: 0.9rem max(1rem, calc((100% - 68rem) / 2));
    background: linear-gradient(180deg, var(--band-top) 0%, var(--band-bottom) 100%);
}

/* La marque s'inverse SUR le bandeau. Les deux jetons clairs sont ceux déjà
   définis dans ce fichier : aucune couleur neuve. */
.app-area .site-header .brand__word--1 {
    color: var(--violet-soft);
}

.app-area .site-header .brand__word--2 {
    color: var(--sky-soft);
}

/* La carte se DÉTACHE du plateau par son OMBRE, pas par sa teinte — c'est ce
   qui permet de la laisser blanche, donc de ne casser aucune des douze
   pastilles. Portée à l'espace adulte seulement. */
.app-area .card {
    box-shadow: var(--shadow-md);
}

/* ==========================================================================
   LES CINQ DÉCORS — DES SCÈNES (ADR-036, FIDÉLITÉ À LA MAQUETTE : ADR-037)
   ==========================================================================

   🔴 CE QUE LA PREMIÈRE LIVRAISON D'ADR-036 AVAIT MAL COMPRIS, ET QUI PRODUIT
   UN ÉCRAN « HACHÉ » : elle faisait du SVG le ciel. C'est l'inverse.

     LE CIEL EST LE DÉGRADÉ, il court sur TOUTE la page.
     LES SVG NE SONT QUE DES OBJETS posés dessus, en haut et en bas.

   La maquette approuvée par le propriétaire le 2026-08-28 (« Filigrane ou
   planète ») le montrait sans ambiguïté : son écran portait un dégradé à
   QUATRE arrêts sur toute sa hauteur, et deux calques SVG **masqués en fondu**
   par-dessus. Livrer deux bandes opaques à bord net sur un dégradé à deux
   arrêts donne trois surfaces qui se voient l'une l'autre — d'où la couture.

   TROIS ÉCARTS REFERMÉS ICI, tous relevés en comparant le livré à la maquette :

     1. le dégradé passe de DEUX arrêts à QUATRE ;
     2. chaque calque porte un MASQUE DE FONDU dans son propre SVG — le ciel
        s'efface vers le bas, le sol apparaît en fondu. Plus aucun bord net ;
     3. les rangées de tâches perdent leur bordure et gagnent une ombre portée :
        des cartes qui FLOTTENT sur la scène, au lieu de cadres posés dessus.

   ── POURQUOI LE MASQUE VIT DANS LE SVG ET NON EN CSS ──────────────────────
   `mask-image` en CSS demande un préfixe `-webkit-` encore aujourd'hui et se
   comporte diversement sur les tablettes visées. Un `<mask>` SVG est du SVG
   1.1, universellement rendu, et il voyage AVEC le dessin : un calque déplacé
   emporte son fondu. C'est aussi ce que fait la maquette.

   ── CE QUI N'A PAS CHANGÉ, ET NE DOIT PAS ─────────────────────────────────
   Les calques restent des ÉLÉMENTS du DOM (jamais des couches
   `background-image` du `<body>`), le `<body>` ne gagne AUCUNE classe, et
   `.shell` réserve la hauteur des DEUX bandes d'objets. Les trois raisons sont
   dans ADR-036 et elles tiennent toujours : le piège des listes `background-*`
   recyclées, `compare_backdrops()` qui encode l'ancien modèle, et la huitième
   sonde qui n'a rien à mesurer sans boîte.

   🔴 ET C'EST CE DERNIER POINT QUI DÉCIDE DE LA HAUTEUR DES BANDES. La bande
   est la zone où vivent les OBJETS, pas le ciel : le ciel est le dégradé,
   qu'aucun texte ne peut « chevaucher » puisqu'il est le fond du `<body>`.
   Agrandir la bande pour « plus de ciel » ne ferait que repousser le contenu
   vers le bas — le ciel, lui, est déjà partout.

   Contrastes GRAVÉS, mesurés le 2026-08-28 avant d'écrire la règle. Témoin de
   méthode : la maquette annonce 18,33:1 pour son titre, la calculatrice rend
   18,33:1 sur la même paire (blanc / #140f33).

     décor        encre     pire arrêt   rapport
     lilas        #241f3d   #cfe0fb      11,74:1
     espace       #ffffff   #6b3f96       7,56:1
     dinosaures   #ffffff   #166f52       6,12:1
     vehicules    #ffffff   #9e5222       5,70:1
     animaux      #ffffff   #843268       7,96:1

   Le plancher des cinq est 5,70 — au-dessus d'AA (4,5), et au-dessus du 5,66
   que le filigrane d'ADR-035 atteignait AU MIEUX.

   ⚠️ Le pire arrêt est TOUJOURS une EXTRÉMITÉ de la rampe : la luminance y est
   monotone, donc les arrêts du milieu sont bornés par les deux bouts. La garde
   les mesure quand même TOUS LES QUATRE — une rampe future non monotone
   rendrait ce raisonnement faux en silence. */

/* Le dégradé du décor REMPLACE les trois lavis de la maison, il ne s'y ajoute
   pas : `JS_CONTRAST` moissonne les arrêts de TOUTES les couches et retient le
   pire, donc un lavis `--sun-soft` laissé sous un ciel sombre ferait sortir un
   titre blanc à ~1,07:1 sur du CSS parfaitement sain (ADR-036). */
body[class*="kid-decor--"] {
    background-image: linear-gradient(
        180deg,
        var(--decor-ciel-1) 0%,
        var(--decor-ciel-2) 38%,
        var(--decor-ciel-3) 72%,
        var(--decor-ciel-4) 100%
    );
    background-repeat: no-repeat;
    background-size: cover;
    background-attachment: scroll;
}

/* LES DEUX BANDES D'OBJETS. `z-index: -1` les met derrière TOUT le contenu sans
   qu'un gabarit ait à s'en soucier, et `pointer-events: none` garantit qu'aucun
   ne peut recouvrir une cible tactile — la sixième sonde existe précisément
   parce qu'un élément assis sur le ⚙️ l'avait tué au doigt.

   `background-size: cover` et JAMAIS `100% 100%` : ce dernier ÉTIRE la scène,
   et un rapport de 3,5 à 6 selon la largeur déformerait visiblement une planète
   ou une roue. `cover` recadre au lieu de déformer. */
.kid-decor__ciel,
.kid-decor__sol {
    position: absolute;
    /* PLEINE LARGEUR. C'est le cadre du DESSIN qui est large (1440), pas le
       calque qui est étroit : une scène de 360 de large étalée sur 1920 px
       agrandit ses objets 5,3 fois, une scène de 1440 les laisse tranquilles.
       Le rapport du calque est celui du cadre, donc `cover` ne rogne RIEN. */
    left: 0;
    width: var(--decor-largeur);
    z-index: -1;
    pointer-events: none;
    background-repeat: no-repeat;
    background-size: cover;
}

.kid-decor__ciel {
    top: 0;
    height: var(--decor-h-ciel);
    /* Relue par la huitième sonde via `getComputedStyle` : c'est ainsi que la
       géométrie gardée reste la MÊME que la géométrie réservée, sans que le
       chiffre soit écrit deux fois. */
    --decor-opaque: var(--decor-opaque-ciel);
    background-image: var(--decor-calque-haut);
    background-position: top center;
}

.kid-decor__sol {
    bottom: 0;
    height: var(--decor-h-sol);
    --decor-opaque: var(--decor-opaque-sol);
    background-image: var(--decor-calque-bas);
    background-position: bottom center;
}

/* LE CONTENU NE CHEVAUCHE PAS LES OBJETS, et c'est la moitié structurelle de la
   tranche — le reste n'est que peinture (ADR-036, arbitrage 3).

   Quatre textes du parcours enfant reposent DIRECTEMENT sur la scène :
   `.kid-title`, `.kid-who__name`, `.kid-progress__text` et
   `.kid-gauge__total-count`. Tous les autres vivent déjà sur un panneau OPAQUE
   — `.kid-tile`, `.kid-choice`, `.kid-step__button`, `.kid-done__panel`,
   `.kid-back`, `.kid-empty`.

   Ces deux marges réservent les deux bandes d'OBJETS. Le dégradé, lui, passe
   dessous sans réserve : c'est le fond du `<body>`, et le texte y repose
   légitimement — c'est ce que la garde AA mesure. */
body[class*="kid-decor--"] .shell {
    padding-top: calc(var(--decor-h-ciel) * var(--decor-opaque-ciel) + 0.75rem);
    padding-bottom: calc(var(--decor-h-sol) * var(--decor-opaque-sol) + 1.25rem);
}

/* Sur une scène, le texte libre gagne une ombre PORTÉE — la maquette le fait,
   et ce n'est pas cosmétique : elle décolle le titre d'un fond dégradé dont la
   luminance varie sous lui. Le contraste mesuré est celui de l'encre contre les
   arrêts ; l'ombre est ce qui empêche le glyphe de se dissoudre visuellement à
   l'endroit où la rampe passe le plus près de sa propre valeur. */
body[class*="kid-decor--"] .kid-title,
body[class*="kid-decor--"] .kid-who__name {
    text-shadow: 0 2px 12px rgba(0, 0, 0, 0.4);
}

/* `lilas` est CLAIR : une ombre noire sous une encre sombre l'empâterait. */
.kid-decor--lilas .kid-title,
.kid-decor--lilas .kid-who__name {
    text-shadow: 0 1px 3px rgba(255, 255, 255, 0.9);
}

/* L'ETOILE EN ATTENTE, SUR UNE SCENE. La maquette relevait elle-meme ce point
   comme OUVERT : « sa partie non remplie fait une pointe grise sur le ciel
   sombre ; sur fond pale elle passait, ici elle demande son propre
   traitement ». Un aplat opaque #ded5f7 sur un ciel profond est une tache
   lavande de 160 px. Un blanc TRANSLUCIDE, lui, prend la couleur du ciel
   sous lui et redevient un creux — ce que la maquette fait.

   Le defaut (`--star-empty`) reste l'aplat opaque : sans decor, rien ne bouge. */
.kid-decor--lilas {
    --decor-sol: var(--decor-lilas-c4);
    --decor-ciel-1: var(--decor-lilas-c1);
    --decor-ciel-2: var(--decor-lilas-c2);
    --decor-ciel-3: var(--decor-lilas-c3);
    --decor-ciel-4: var(--decor-lilas-c4);
    --decor-ink: #241f3d;
    --decor-calque-haut: url('/assets/img/decor/lilas-haut-3.svg');
    --decor-calque-bas: url('/assets/img/decor/lilas-bas-3.svg');
    --star-empty: rgba(90, 70, 160, 0.16);
    --decor-bord: var(--violet);
    --decor-tuile: var(--violet-soft);
}

.kid-decor--espace {
    --decor-sol: var(--decor-espace-c4);
    --decor-ciel-1: var(--decor-espace-c1);
    --decor-ciel-2: var(--decor-espace-c2);
    --decor-ciel-3: var(--decor-espace-c3);
    --decor-ciel-4: var(--decor-espace-c4);
    --decor-ink: #ffffff;
    --decor-calque-haut: url('/assets/img/decor/espace-haut-3.svg');
    --decor-calque-bas: url('/assets/img/decor/espace-bas-3.svg');
    --star-empty: rgba(255, 255, 255, 0.16);
    --decor-bord: var(--sky);
    --decor-tuile: var(--sky-soft);
}

.kid-decor--dinosaures {
    --decor-sol: var(--decor-dinosaures-c4);
    --decor-ciel-1: var(--decor-dinosaures-c1);
    --decor-ciel-2: var(--decor-dinosaures-c2);
    --decor-ciel-3: var(--decor-dinosaures-c3);
    --decor-ciel-4: var(--decor-dinosaures-c4);
    --decor-ink: #ffffff;
    --decor-calque-haut: url('/assets/img/decor/dinosaures-haut-3.svg');
    --decor-calque-bas: url('/assets/img/decor/dinosaures-bas-3.svg');
    --star-empty: rgba(255, 255, 255, 0.16);
    --decor-bord: var(--mint);
    --decor-tuile: var(--mint-soft);
}

.kid-decor--vehicules {
    --decor-sol: var(--decor-vehicules-c4);
    --decor-ciel-1: var(--decor-vehicules-c1);
    --decor-ciel-2: var(--decor-vehicules-c2);
    --decor-ciel-3: var(--decor-vehicules-c3);
    --decor-ciel-4: var(--decor-vehicules-c4);
    --decor-ink: #ffffff;
    --decor-calque-haut: url('/assets/img/decor/vehicules-haut-3.svg');
    --decor-calque-bas: url('/assets/img/decor/vehicules-bas-3.svg');
    --star-empty: rgba(255, 255, 255, 0.16);
    --decor-bord: var(--sun);
    --decor-tuile: var(--sun-soft);
}

.kid-decor--animaux {
    --decor-sol: var(--decor-animaux-c4);
    --decor-ciel-1: var(--decor-animaux-c1);
    --decor-ciel-2: var(--decor-animaux-c2);
    --decor-ciel-3: var(--decor-animaux-c3);
    --decor-ciel-4: var(--decor-animaux-c4);
    --decor-ink: #ffffff;
    --decor-calque-haut: url('/assets/img/decor/animaux-haut-3.svg');
    --decor-calque-bas: url('/assets/img/decor/animaux-bas-3.svg');
    --star-empty: rgba(255, 255, 255, 0.16);
    --decor-bord: var(--coral);
    --decor-tuile: var(--coral-soft);
}

/* ==========================================================================
   EXTINCTION — exhaustive, et c'est ce qui compte
   Un enfant sensible au mouvement doit obtenir une application entièrement
   STATIQUE, pas une application « un peu moins animée ». On coupe donc à la
   racine : toute animation, toute transition, tout défilement glissé.
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
    html {
        scroll-behavior: auto;
    }

    *,
    *::before,
    *::after {
        animation-duration: 0.001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.001ms !important;
    }

    /* Les classes d'entrée ne doivent pas laisser l'élément à `opacity: 0` :
       `both` fige l'état INITIAL quand la durée tombe à zéro. On rend donc
       l'état final à la main. */
    .anim-pop,
    .anim-rise {
        animation: none;
        opacity: 1;
        transform: none;
    }

    .btn:hover,
    .btn:active {
        transform: none;
    }
}
