/* ==========================================================
FITZ DESIGN SYSTEM — voir DESIGN_SYSTEM.md à la racine
pour la documentation complète avec exemples. Ce fichier est LA
seule source de tokens/composants partagés : toute page qui a
besoin d'une couleur, d'un espacement, d'un rayon, d'une ombre,
d'une taille de texte ou d'un composant (bouton, champ, carte,
badge, tableau, modale) doit consommer ce qui est ici plutôt que
réinventer sa propre valeur localement.
========================================================== */

:root{

/* ==========================================================
COLORS — refonte 2026-08 : palette bleu profond / violet discret /
gris modernes (remplace l'ancien marron/or). La couleur ne sert
plus qu'à signaler une action ou un état vraiment important — les
icônes/cartes génériques passent en gris neutre, pas en couleur de
marque par défaut. Les alias --primary-color/--accent-color/etc.
restent pour compatibilité avec le code existant ; le nouveau
travail doit préférer les noms d'échelle (--primary-600,
--accent-500...). Voir plus bas --gradient-fitz/--glow-fitz : Fitz
a désormais son propre système de couleur, découplé de --accent-*.
========================================================== */

/* REFONTE 2026-09-02 — PLUS AUCUN BLEU (décision utilisateur, déjà
appliquée à l'admin) : l'échelle primaire quitte l'indigo pour la
famille ENCRE CHAUDE du site. L'historique de ce fichier allait déjà
dans ce sens (--ink-surface avait remplacé --primary-900 sur les
boutons, --background-light avait perdu son voile bleu) — ceci achève
le mouvement : tout ce qui consomme --primary-*/--gradient-primary
devient chaud d'un coup, sans toucher les pages une à une. */
--primary-50:#F5F1E8;
--primary-600:#211D18;
--primary-700:#3A3228;
--primary-900:#14100D;

--primary-color:var(--primary-600);
--primary-hover:var(--primary-700);
--primary-dark:var(--primary-900);

--accent-100:#EEEAFB;
--accent-500:#7E71D8;
--accent-600:#6459B8;
--accent-color:var(--accent-500);

/* ==========================================================
ACCENT AMBRE (2026-08-02) — vie et touche premium sur un site que le
bleu rend sérieux mais un peu froid. Le bleu reste dominant.

CE N'EST PAS L'ANCIEN OR. #D4A24C (thème marron/or abandonné) était
un or éteint, désaturé, pensé pour aller avec du bordeaux. Celui-ci
est un ambre franc, +22 points de saturation, choisi pour tenir face
au bleu profond. Ne jamais réintroduire #D4A24C ni #8B1E3F.

RÈGLE D'EMPLOI — par petites touches, jamais en fond de section
large. Réservé au CTA principal, aux badges de mise en avant, aux
icônes de points forts et aux soulignements de titres clés. Viser
moins de 10-15% de la surface visible.

  --amber-500  SURFACES uniquement (fond de bouton, de badge, de
               pastille). Toujours avec un libellé --ink-surface :
               7,8:1 (c'était --primary-900 et 8,24:1 jusqu'au
               2026-08-28 — voir --ink-surface plus bas). Sur blanc il
               ne fait que 2,16:1 — donc jamais en couleur de texte
               sur fond clair.
  --amber-600  survol de ces mêmes surfaces (5,85:1 avec le libellé).
  --amber-700  la SEULE valeur admise pour du texte ou une icône
               ambre sur fond clair : 5,8 / 5,5 / 5,3 sur --background,
               --background-soft et --background-alt.
========================================================== */

--amber-500:#E9A319;
--amber-600:#C9860B;
--amber-700:#8A5D00;

--success:#22C55E;
--warning:#EAA83D;
--danger:#EF4444;

/* ==========================================================
ÉCHELLE D'ÉTAT (2026-08-22) — les trois valeurs ci-dessus sont des
couleurs de SURFACE VIVE : mesurées sur --background/--background-soft/
--background-alt elles donnent 2,28 / 2,07 / 3,76 — aucune ne passe le
4,5:1 exigé pour du texte, et --success/--warning n'atteignent même pas
le 3:1 des composants non textuels. Elles restent valides en pastille
pleine avec un libellé sombre, jamais en couleur de texte ou d'icône
sur fond clair.

Cette échelle comble ce manque, sur le même modèle que --amber-500/600/
700 plus haut (surface / survol-surface / texte) :

  --*-500  stop clair d'un dégradé, jamais seul sur fond clair
  --*-600  SURFACES non textuelles (anneau, barre de progression,
           pastille) — 3,30 / 3,19 / 4,83, au-dessus du seuil 3:1 de
           WCAG 1.4.11
  --*-700  la SEULE valeur admise pour du TEXTE ou une icône porteuse
           de sens sur fond clair — 5,02 / 5,02 / 6,47 sur --background
           (4,58 / 4,58 / 5,91 sur --background-alt, le plus sombre des
           trois fonds), donc AA partout
  --*-50   teinte de fond très claire, pour une zone d'état entière

Introduite pour le score du diagnostic (results.css) : un score ne peut
pas être lisible en vert/ambre/rouge sans une valeur de texte qui tient
le contraste. Toute autre page qui doit signaler un état bon/moyen/
faible consomme CES tokens plutôt que d'inventer ses propres verts.
========================================================== */

--success-50:#ECFDF5;
--success-500:#34D399;
--success-600:#16A34A;
--success-700:#15803D;

--warning-50:#FFFBEB;
--warning-500:#FBBF24;
--warning-600:#D97706;
--warning-700:#B45309;

--danger-50:#FEF2F2;
--danger-500:#F87171;
--danger-600:#DC2626;
--danger-700:#B91C1C;

/* ÉCHELLE DE GRIS TEXTE — trois niveaux porteurs d'information, plus
un quatrième strictement décoratif. Valeurs revues le 2026-08-02 après
un audit de contraste : les anciennes (#64748B / #94A3B8) échouaient au
niveau AA sur les fonds clairs du site.

NEUTRES PAPIER — bascule du 2026-08-28
--------------------------------------
Toute l'échelle passe du slate FROID (bleuté : #0F172A / #475569 sur
#FFFFFF / #F8FAFC) à un neutre PAPIER CHAUD. Le blanc pur et ses gris
bleutés étaient le dernier vestige de la palette bleue abandonnée —
et le fond blanc lui-même n'était pas blanc : --gradient-hero posait
deux voiles radiaux #E9EBFA / #F0EDFB, soit du bleu et du violet, sur
tout le site.

La LUMINOSITÉ de chaque échelon est conservée, seule la teinte
change : les rapports de contraste restent donc ceux qui avaient été
validés lors de l'audit AA du 2026-08-02, à quelques centièmes près.

Contrastes remesurés sur --background (#FDFCFA), --background-soft
(#F8F6F2) et --background-alt (#F1EEE8) :

  --text-color       17.6 / 17.0 / 15.6
  --text-light        7.6 /  7.3 /  6.7
  --text-muted        5.4 /  5.2 /  4.8
  --text-decorative   3.7 /  3.5 /  3.3   (jamais pour du texte)

Il n'existe aucune valeur plus claire que --text-muted qui passe 4.5:1
sur ces trois fonds : c'est pourquoi --text-light a dû être assombri en
même temps, sinon les deux niveaux devenaient indiscernables.

--text-decorative NE DOIT JAMAIS porter de texte lisible. Il est
réservé au non-textuel dont le sens est déjà donné à côté : icône d'un
champ de recherche qui a son libellé, glyphe d'illustration d'un état
vide dont le message est écrit en dessous, pastille inactive. Il tient
le seuil 3:1 de WCAG 1.4.11 pour les composants non textuels. Un
libellé, une aide de formulaire, une méta-donnée, un placeholder ou
l'icône d'un bouton d'action prennent --text-muted, jamais celui-ci.

Les pages à fond sombre (dashboard.css, admin/control-center.css)
surchargent --text-light/--text-muted dans leur propre scope : ces
valeurs-ci sont celles du contexte CLAIR. */

--text-color:#1A1714;
--text-light:#57514A;
--text-muted:#6E6760;
--text-decorative:#8A837A;

--background:#FDFCFA;
--background-soft:#F8F6F2;
--background-alt:#F1EEE8;
/* Voile neutre chaud : était rgba(51,65,140,.08), un voile du bleu
#33418C — la dernière teinte bleue du système clair. */
--background-light:rgba(26,23,20,.055);

--border-color:#E5E1D9;

/* ENCRE DE SURFACE (2026-08-28) — le fond des boutons pleins, et le
libellé posé sur l'or. Distincte de --text-color (#1A1714) à dessein :
une surface exactement de la couleur du texte qui l'entoure se lit
comme un trou dans la page plutôt que comme un objet posé dessus.

Remplace --primary-900 (#12162E, marine) partout où celui-ci servait
d'encre sur les boutons — c'était le dernier bleu des libellés.
Contrastes : blanc sur --ink-surface 16,8:1 ; --ink-surface sur
--amber-500 7,8:1. */
--ink-surface:#211D18;
--ink-surface-hover:#342D24;

--glass:rgba(255,255,255,.72);
--glass-border:rgba(255,255,255,.45);

/* Thème "app shell" (dashboard/admin) — un seul jeu de tokens
sombres, partagé, au lieu que chaque page reforke sa propre
version avec des valeurs qui dérivent. Toute page à fond sombre
doit surcharger les tokens ci-dessus avec CEUX-LÀ dans son propre
scope (ex. `body.app-shell{ --background:var(--shell-bg); ...}`),
jamais avec de nouvelles valeurs inventées localement. */
--shell-bg:#2C261E;
--shell-surface:#211D18;
--shell-elevated:#3A332A;
--shell-border:rgba(255,255,255,.08);
--shell-text:#F5F1E8;
--shell-shadow-xs:0 2px 10px rgba(0,0,0,.32), inset 0 1px 0 rgba(255,255,255,.04);
--shell-shadow-sm:0 8px 20px rgba(0,0,0,.36);
--shell-shadow-md:0 14px 32px rgba(0,0,0,.42);
--shell-shadow-lg:0 22px 52px rgba(0,0,0,.48);

/* ==========================================================
GRADIENTS — un jeu limité et intentionnel. Toute nouvelle surface
qui "a besoin d'un dégradé" doit d'abord se demander si elle peut
consommer l'un des trois ci-dessous avant d'en inventer un
nouveau (c'est la dérive la plus commune trouvée dans l'audit :
des dizaines de quasi-copies de --gradient-primary avec des stops
légèrement différents).
========================================================== */

/* Recoloré encre chaude le 2026-09-02 (même refonte que l'échelle
--primary-* ci-dessus) : le premier arrêt reste le bord « éclairé ». */
--gradient-primary:
linear-gradient(
135deg,
#4A4032 0%,
#211D18 55%,
#14100D 100%
);

/* ==========================================================
DÉGRADÉ PROFOND — les GRANDES surfaces sombres (2026-08-22)
==========================================================
--gradient-primary reste parfait sur une petite surface : un bouton,
une pastille, une jauge, où l'on ne voit guère que son premier stop
lumineux (#4A5BC4). Étalé sur un écran entier, ce même stop occupe en
revanche tout un coin en bleu vif, et c'est lui qui donnait aux pages
Fitz leur fond « bleu électrique ».

Ce token garde la même construction (135deg, trois arrêts) que
--gradient-primary, pensée pour se lire comme du noir sur une grande
surface sans devenir un aplat plat (`background:#000` perdrait la
profondeur diagonale).

Recoloré en graphite neutre le 2026-08-28 : la première version
resserrait --gradient-primary vers son extrémité marine (#1C2246 /
#12162E / #070A16), et continuait malgré tout à se lire comme "fond
bleu foncé" à l'usage réel (retour utilisateur, sur plusieurs pages :
hero, .fitz-demo, .opportunites, parcours eligibility-*, results.css).
Ce token abandonne donc toute teinte bleue plutôt que la resserrer
davantage.

Recoloré une seconde fois le 2026-09-01, du graphite vers l'ENCRE
CHAUDE : même retour utilisateur une itération plus loin — le graphite
« neutre » (#26262C/#18181C/#0A0A0C) se lisait toujours comme du bleu
à côté des surfaces sombres chaudes du site (bandeau « ouvert en ce
moment », pages catalogue en marron chaud), et l'utilisateur a demandé
explicitement d'aligner le fond de la section Fitz sur ce marron-là.
Les trois arrêts reprennent des valeurs chaudes DÉJÀ établies ailleurs
plutôt que d'en inventer : #2C2419 (radial du bandeau opportunités,
css/homepage-redesign.css), #1C1710 et #0D0A06 (voiles des heros
catalogue, css/catalog.css), à luminosité équivalente aux arrêts
graphite qu'elles remplacent — les contrastes du texte blanc posé
dessus ne bougent donc pas (ils s'améliorent d'un cheveu, les arrêts
chauds étant à peine plus sombres). Tous les consommateurs suivent
d'un coup : .fitz-demo, le repli du hero, les fonds des parcours
eligibility-* et results.

À réserver aux surfaces pleine page ou pleine section. Un bouton ou
une pastille garde --gradient-primary : l'identité bleue de la marque
reste voulue à cette échelle, seules les GRANDES surfaces sombres en
sont détachées.
========================================================== */

--gradient-deep:
linear-gradient(
135deg,
#2C2419 0%,
#1C1710 45%,
#0D0A06 100%
);

/* Fond de page. Recoloré le 2026-08-28 : les deux voiles étaient
#E9EBFA (bleu) et #F0EDFB (violet) sur blanc pur — c'est ce qui
donnait au "fond blanc" du site sa dominante froide, alors même que
le bleu et le violet avaient été abandonnés partout ailleurs. Même
construction (2 radiaux + un aplat), en papier chaud. */
--gradient-hero:
radial-gradient(circle at top left,#F6F2EA 0%,transparent 45%),
radial-gradient(circle at bottom right,#F3EFE6 0%,transparent 35%),
#FDFCFA;

/* Signature Fitz — "la marque dans la marque" : reconnaissable
partout où Fitz apparaît (avatar, halo, bulles de réponse, badges).
REFAIT le 2026-08-27 : le dégradé "aurore" violet → indigo → cyan
d'origine était présenté comme "découplé du reste de la palette" —
mais la personne qui a demandé ce site a dit, deux fois, ne plus
vouloir voir de bleu ni de violet nulle part, sans faire d'exception
pour Fitz. Ce dégradé restait le dernier bleu/violet du site, visible
au premier coup d'œil (badge "Suggéré par Fitz" d'applications.html,
entre autres). Fitz garde son identité propre — un dégradé "aurore"
qui lui est propre, pas repris ailleurs — mais entièrement dans la
même famille ambre que le reste du site : du plus clair au plus
foncé de l'échelle (--amber-500/600/700), plutôt qu'une couleur
distincte. */
--gradient-fitz:
linear-gradient(135deg,var(--amber-500) 0%,var(--amber-600) 55%,var(--amber-700) 100%);

--glow-fitz:0 0 0 1px rgba(233,163,25,.35), 0 8px 20px rgba(233,163,25,.20), 0 0 18px rgba(233,163,25,.22);

/* Couleur à plat (pour une SURFACE, un halo ou une bordure fine) —
alignée sur --amber-700, la seule valeur de l'échelle ambre admise
en couleur de TEXTE sur fond clair (voir la règle plus haut). */
--fitz-color:var(--amber-700);

/* ==========================================================
SHADOWS — élévation sobre. Une carte "mise en avant" se distingue
par une bordure d'accent + --shadow-lg, jamais par un flou plus
gros : le spectacle (--shadow-xl à 120px de flou) a été retiré du
vocabulaire du site.
========================================================== */

/* Teinte passée de rgba(15,23,42,…) — un slate BLEU — à l'encre chaude
rgba(26,23,20,…) le 2026-08-28, avec les neutres papier. Une ombre
porte la couleur de la lumière qui la crée : une ombre bleue sur un
fond papier chaud se lit comme une salissure grise, pas comme un
relief. Opacités et géométries inchangées. */

--shadow-xs:
0 1px 3px rgba(26,23,20,.05);

--shadow-sm:
0 4px 12px rgba(26,23,20,.08);

--shadow-md:
0 8px 20px rgba(26,23,20,.10);

--shadow-lg:
0 16px 32px rgba(26,23,20,.14);

/* ==========================================================
BORDER RADIUS — resserré.
========================================================== */

--radius-xs:6px;
--radius-sm:10px;
--radius-md:14px;
--radius-lg:20px;
--radius-full:999px;

/* ==========================================================
Z-INDEX
========================================================== */

--z-header:1000;
--z-modal:2000;
--z-overlay:9999;

/* ==========================================================
SPACING — grille 8pt. --space-2xs comble le seul vrai trou (rien
en dessous de 8px n'existait alors que des gaps d'icône/badge en
ont besoin) ; le reste de l'échelle est inchangé.
========================================================== */

--space-2xs:4px;
--space-xs:8px;
--space-sm:16px;
--space-md:24px;
--space-lg:40px;
--space-xl:72px;
--space-2xl:120px;

/* ==========================================================
TRANSITIONS — --ease-standard est le défaut global (sobre,
prévisible) ; --ease-premium reste disponible mais réservé aux
moments de signature (halo Fitz), plus au comportement par défaut
de chaque carte/bouton du site.
========================================================== */

--ease-standard:cubic-bezier(.4,0,.2,1);
--ease-premium:cubic-bezier(.16,1,.3,1);

--transition:
all .2s var(--ease-standard);

/* ==========================================================
TYPOGRAPHY — Sora pour les titres, Inter pour le texte courant.
Échelle inchangée (déjà auditée et validée) : toute page qui a
besoin d'une taille/graisse pour un rôle déjà couvert ici doit
consommer ces tokens/classes plutôt que redéfinir sa propre valeur.
========================================================== */

--font-display:"Sora",sans-serif;
--font-body:"Inter",sans-serif;

--fs-hero:clamp(2.75rem,5.2vw,4.25rem);
--fs-h1:clamp(2.25rem,4vw,3.4rem);
--fs-h2:clamp(1.9rem,3.2vw,2.75rem);
--fs-h3:1.3rem;
--fs-h4:1.05rem;
--fs-h5:.95rem;
--fs-lead:clamp(1.05rem,1.3vw,1.15rem);
--fs-body:1rem;
--fs-small:.9rem;
--fs-caption:.8rem;
--fs-button:.95rem;
--fs-label:.85rem;

--fs-page-title:clamp(1.35rem,1.6vw,1.65rem);
--fs-subtitle:1rem;
--fs-card-title:1.1rem;
--fs-badge:.72rem;
--fs-nav:.92rem;
--fs-footer:.88rem;
--fs-meta:.82rem;
--fs-stat:clamp(1.6rem,2.4vw,2.1rem);
--fs-stat-sm:1.45rem;

--fw-regular:400;
--fw-medium:500;
--fw-semibold:600;
--fw-bold:700;
--fw-extrabold:800;

--lh-tight:1.1;
--lh-snug:1.25;
--lh-normal:1.5;
--lh-relaxed:1.7;

--ls-tight:-.02em;
--ls-snug:-.01em;
--ls-normal:0;
--ls-wide:.05em;

/* ==========================================================
LOGO FITZUNIVERSE — source unique. Ne jamais redéfinir ces deux
tokens ailleurs (c'est la couleur écrite en dur dans le balisage
qui avait produit 6 habillages différents du même symbole).

TROIS tokens, et trois seulement : --logo-accent (la pièce ambre du
symbole), --logo-structure (le grand arc et le mot « Fitz »),
--logo-descriptor (le mot « UNIVERSE »).

TOUS LES TROIS SONT ÉCRITS EN LITTÉRAL, JAMAIS var(--amber-*).
ONZE feuilles du dépôt redéfinissent l'échelle ambre en terracotta —
recompté le 2026-08-31, le commentaire précédent n'en annonçait que
trois : base.css elle-même, catalog-redesign, details-redesign,
eligibility-questions-redesign, eligibility-test-redesign,
homepage-redesign, journey-shell, login-redesign, offers-redesign,
payment-redesign, results-redesign. Passer par un token ambre
ramènerait instantanément les habillages multiples que ce bloc
existe pour empêcher.

--logo-accent est INVARIANT : #E9A319 sur tous les fonds, sans
exception. C'est LE signe de reconnaissance — il ne devient jamais
brun, jamais terracotta, jamais blanc.
--logo-structure n'a que DEUX états : encre sur fond clair (défaut
ci-dessous), papier sur fond sombre (variante .on-dark plus bas).
--logo-descriptor a lui aussi DEUX états, et il est le seul ajout du
2026-08-31 : sur fond clair un ambre foncé lisible (#8A5D00, 5,76:1
sur papier), sur fond sombre l'accent lui-même (#E9A319, 7,75:1).
Avant lui, « UNIVERSE » était soit la structure à 72 % d'opacité —
donc illisible sur fond sombre — soit du terracotta selon la page.
Aucun bleu, aucune quatrième couleur.
========================================================== */
--logo-accent:#E9A319;
--logo-structure:var(--ink-surface);
--logo-descriptor:#8A5D00;

}

/* ==========================================================
ÉCHELLE TYPO SUR TÉLÉPHONE (2026-09-01, passe mobile — retour
utilisateur : « réduire certaines tailles des écritures pour que la
page contienne correctement les photos »)
==========================================================
Les clamp() ci-dessus ont des PLANCHERS pensés pour le bureau : sur un
écran de 375px, --fs-hero tombait à 2.75rem (44px) et --fs-h2 à
1.9rem (30px) — chaque titre de section mangeait 4 à 6 lignes, et les
photos/cartes se retrouvaient repoussées hors du premier écran. Sous
576px, les planchers descendent d'un cran vers les échelles des sites
mobiles actuels (titre ~34px, section ~25px). Un @media sur :root et
non des règles par page : tous les titres du site (accueil, catalogue,
parcours, espace) suivent d'un coup, et les rapports entre niveaux
sont conservés. Les tailles de corps (--fs-body/small/caption) ne
bougent pas — elles sont déjà à l'échelle mobile. */
@media(max-width:576px){

:root{

--fs-hero:2.15rem;

--fs-h1:1.9rem;

--fs-h2:1.55rem;

--fs-h3:1.18rem;

--fs-lead:1rem;

--fs-page-title:1.3rem;

--fs-stat:1.5rem;

}

}

/* Seule variante autorisée du symbole : fond sombre. .on-dark est le
crochet générique à poser sur un conteneur sombre ponctuel (ex. la
carte encre de login.html) ; les autres sélecteurs sont les surfaces
sombres permanentes du site — hero (header non scrollé), pied de
page, FAB Fitz, marque de la sidebar admin (.sidebar-brand) et logo
de la connexion admin. */
.on-dark,
.header:not(.is-scrolled),
.footer,
.fitz-fab,
.admin-logo-wrap{
--logo-structure:#FDFCFA;
--logo-descriptor:#E9A319;
}
/* .sidebar-brand a QUITTÉ ce bloc le 2026-09-04 : la sidebar de
l'admin est claire depuis la refonte du 2026-09-02, et
admin/control-center.css redéclarait les tokens clairs pour
compenser — ce qui donnait DEUX sources pour --logo-descriptor et
faisait échouer test/logo-lockup.test.mjs. Elle hérite désormais
des valeurs claires de :root, qui sont exactement celles que la
surcharge rétablissait. */

/* Balisage canonique (identique dans tous les fichiers) : un <svg
class="fitz-mark"> sans AUCUN attribut stroke= ; le grand arc porte
.mark-structure, la pièce ambre .mark-accent. La classe de
dimensionnement existante reste à côté (fitz-mark logo-mark,
fitz-mark logo-icon…). */
.fitz-mark .mark-structure{
stroke:var(--logo-structure);
fill:none;
transition:stroke .3s ease;
}

.fitz-mark .mark-accent{
stroke:var(--logo-accent);
fill:none;
}


/* ==========================================================
LOCKUP FITZUNIVERSE — symbole + nom, un seul composant.

Remplace les TROIS lockups qui coexistaient (public .logo-text
avec styles inline, .journey-brand-text de l'espace étudiant,
.sidebar-brand-text de l'admin) : trois balisages, trois
typographies, trois couleurs de descripteur pour la même marque.

LES POLICES SONT ÉCRITES EN LITTÉRAL, jamais var(--font-display)
ni var(--font-body). DIX-SEPT feuilles du dépôt redéfinissent
--font-display (recompté le 2026-08-31) en trois systèmes
typographiques différents — Sora, Space Grotesk + Plus Jakarta,
Newsreader + Public Sans. Le nom de la marque changeait donc de
caractère selon la page : c'est LA cause du « pas le même rendu
partout ». Un logo ne suit pas la typographie de la page qui
l'accueille, c'est l'inverse.

RÉGLAGE OPTIQUE : « UNIVERSE » épouse la largeur de « Fitz ». Le
letter-spacing de .295em élargit le mot, et la marge droite
négative de même valeur reprend l'espace que la dernière lettre
traîne derrière elle — sans elle, le mot déborderait de son
espacement final. Mesuré à --lockup-size:44px : « Fitz » 70,70 px,
« UNIVERSE » 70,69 px peints (73,61 px de boîte moins 2,92 px de
marge). Écart : 0,01 px.

Trois tailles en service : 48px (en-tête et pied public), 30px
(espace étudiant et sidebar admin), 24px (compact). Voir
design-previews/logo-lockup.html.
========================================================== */

.fitz-lockup{
--lockup-size:36px;  /* défaut réduit de 44 à 36 le 2026-09-01 —
   demande utilisateur : le lockup d'en-tête était trop grand pour un
   rendu professionnel. Les tailles réelles sont posées PAR CONTEXTE
   ci-dessous ; ce défaut ne sert qu'aux emplacements sans contexte
   connu (aperçus de design-previews/). */
display:inline-flex;
align-items:center;
gap:calc(var(--lockup-size) * .26);
text-decoration:none;
line-height:1;
}

.fitz-lockup .fitz-mark{
width:var(--lockup-size);
height:var(--lockup-size);
flex:0 0 auto;
display:block;
}

.fitz-lockup-text{
display:flex;
flex-direction:column;
gap:calc(var(--lockup-size) * .055);
}

.fitz-lockup-name{
font-family:"Newsreader",Georgia,serif;
font-weight:700;
font-size:calc(var(--lockup-size) * .60);
letter-spacing:-.005em;
line-height:.95;
color:var(--logo-structure);
}

.fitz-lockup-sub{
font-family:"Public Sans",system-ui,sans-serif;
font-weight:600;
font-size:calc(var(--lockup-size) * .225);
letter-spacing:.295em;
margin-right:-.295em;
text-transform:uppercase;
line-height:1;
color:var(--logo-descriptor);
}

/* TAILLES PAR CONTEXTE (2026-09-01) — les tailles quittent le HTML.
Elles vivaient en style="--lockup-size:NNpx" sur chacun des 35 lockups :
un changement global demandait 35 modifications, et surtout un style
inline BAT toute règle de feuille — les paliers responsive de
css/header.css (42px puis 36px) ne s'appliquaient donc JAMAIS, le logo
mobile restait à 48px. Règles mortes depuis leur écriture, révélées en
réduisant la taille de base. Désormais : une règle par contexte ici, et
les paliers d'en-tête (css/header.css, réécrits en
.header .fitz-lockup pour garder la priorité) redeviennent effectifs. */
.header .fitz-lockup,
.footer .fitz-lockup{
--lockup-size:36px;
}

.journey-topbar .fitz-lockup,
.sidebar-brand .fitz-lockup,
.page-brandbar .fitz-lockup{
--lockup-size:30px;
}

/* Barre de marque des pages sans en-tete (offers, payment, results,
eligibility-questions, eligibility-test). Volontairement minimale :
elle porte le lockup et rien d'autre, sans se substituer aux en-tetes
existants de ces pages. */
.page-brandbar{
max-width:1200px;
margin:0 auto;
padding:22px 24px 0;
}

/* Variante pour les pages dont le body est un conteneur flex qui
CENTRE la carte (eligibility-test, eligibility-questions :
body{display:flex; safe center}). Laissee dans le flux, la barre y
devenait un DEUXIEME enfant flex : logo plante a mi-hauteur a gauche,
carte poussee hors du centre (constate le 2026-08-31). Sortie du flux,
elle se pose en haut et le centrage d'origine est retrouve. Ces deux
pages sont sur fond sombre (--gradient-deep) : leur barre porte aussi
la classe on-dark, sinon « Fitz » est encre sur encre. */
.page-brandbar--overlay{
position:absolute;
top:0;
left:0;
right:0;
z-index:10;

/* La barre est une bande PLEINE LARGEUR posee au-dessus du contenu :
sans ceci, sa boite invisible recouvre le « Retour a l'accueil » place
juste en dessous et avale le clic — le lien paraissait mort
(constate le 2026-08-31, quelques minutes apres la mise en place de
l'overlay). Seul le lockup reste cliquable ; le reste de la bande
laisse passer les clics vers ce qu'il y a dessous. */
pointer-events:none;
}

.page-brandbar--overlay > *{
pointer-events:auto;
}


/* ==========================================================
RESET
========================================================== */

*{
margin:0;
padding:0;
box-sizing:border-box;
}

/* PAS de `scroll-behavior:smooth` ici — retiré le 2026-09-06 après mesure
en production : un saut d'ancre durait 547 ms, et un « retour en haut »
depuis 40 000 px, 1 479 ms. Pendant tout ce temps le site paraît mou alors
qu'il tient 60 fps : le lissage global ne rendait pas le défilement fluide,
il rendait chaque saut LENT.

Le lissage reste là où il est un choix : les `scrollIntoView({behavior:
"smooth"})` de applications.js (on suit une carte des yeux). S'il manque un
jour sur les ancres de l'accueil, il se pose sur ces liens-là dans
js/main.js — jamais sur `html`, qui l'imposerait à toute navigation, y
compris aux sauts que le navigateur fait pour l'utilisateur.

Le `scroll-behavior:auto !important` de css/animations.css
(prefers-reduced-motion) reste en place : il ne coûte rien et couvre les
lissages locaux. */

::selection{
background:var(--primary-color);
color:#fff;
}

html{
scrollbar-color:#B7AFA3 var(--background-soft);
scrollbar-width:thin;
}

::-webkit-scrollbar{
width:11px;
}

::-webkit-scrollbar-track{
background:var(--background-soft);
}

/* Pouce NEUTRE CHAUD (2026-09-02) : l'indigo --primary-color était le
dernier bleu visible sur toutes les pages (signalé par l'utilisateur,
capture du Control Center) — la barre de défilement n'est pas un
élément de marque, elle reste discrète. */
::-webkit-scrollbar-thumb{
background:#B7AFA3;
border-radius:999px;
border:3px solid var(--background-soft);
}

::-webkit-scrollbar-thumb:hover{
background:#8A837A;
}

body{

font-family:"Inter",sans-serif;

color:var(--text-color);

background:var(--gradient-hero);

line-height:1.6;

/* Empêche le "scroll chaining" au bord haut/bas de la page : sans
ça, arriver en butée du document en scrollant vite (trackpad, molette
inertielle) transmet l'inertie restante au geste de navigation du
navigateur (pull-to-refresh sur Chrome Android, glissement de retour
sur certains trackpads) — d'où une sensation de scroll qui "accroche"
ou déclenche autre chose que prévu en bout de page. --y seulement :
--x reste au comportement par défaut pour ne pas gêner le geste de
retour au doigt depuis le bord de l'écran (Safari iOS, Chrome
Android), qui est une navigation voulue, pas un effet de bord du
scroll vertical. */
overscroll-behavior-y:contain;

}

img{

max-width:100%;

/* height:auto AJOUTÉ à la passe mobile du 2026-09-01 — il manquait au
trio canonique. Sans lui, une image portant width=/height= HTML (posés
partout à l'audit du 2026-08-29 contre le CLS) garde sa hauteur
d'ATTRIBUT quand max-width:100% réduit sa largeur : sur téléphone,
.vision-photo (800x533) s'affichait en 335x533, étirée verticalement —
et sa règle CSS aspect-ratio était ignorée (elle exige une dimension
auto). height:auto ne touche que l'attribut : toute règle CSS de
hauteur (object-fit:cover des cartes, drapeaux à taille fixe...) est
plus spécifique qu'un sélecteur d'élément et continue de gagner. */
height:auto;

display:block;

}

a{

text-decoration:none;

color:inherit;

}

ul{

list-style:none;

}

/* EXCEPTION — les listes rendues depuis du Markdown par Fitz gardent
   leurs puces. La règle ci-dessus retire les puces de TOUTES les
   listes du site, ce qui convient aux menus et aux grilles de cartes
   mais transformait une énumération de Fitz en bloc de lignes
   indistinctes : constaté le 2026-09-05 sur la page de résultats, dans
   « Ce qui rend votre dossier crédible ». Une liste de faits doit se
   lire comme une liste. */
.ai-md-list,
.fitz-analysis-body ul{

list-style:disc;

padding-left:20px;

}

/* ==========================================================
LIEN RETOUR (.back-link) — 2026-08-28

Centralisé ici : jusqu'ici défini deux fois à l'identique dans
offers.css et payment.css (même sort que .ai-badge avant lui, voir la
note en tête de sa règle dans payment.css — "quatre pages avaient fini
avec quatre badges différents"). Un ".back-link" est un <a href="...">
tout ce qu'il y a de plus normal (fonctionne sans JS, ouvrable dans un
nouvel onglet, lisible par un lecteur d'écran) ; js/back-link.js
l'améliore au clic pour ramener l'étudiant exactement où il en était
sur la page précédente plutôt qu'en haut d'une page cible fixe — voir
ce fichier pour le détail. Toute page qui ajoute un ".back-link" doit
aussi charger js/back-link.js, sinon le lien reste fonctionnel mais
perd cette restauration de position.

Le style de base ci-dessous convient à un lien posé sur un fond clair
(page dans .container). Pages avec un contexte visuel différent :
- scholarship-details.html pose son ".back-link" sur la photo de héros
  (fond sombre) — surchargé dans scholarship-details.css.
- Les pages de l'espace étudiant (sidebar) le posent dans
  .topbar-title, à côté d'un h1 déjà en gras — marge resserrée dans
  dashboard.css pour ne pas alourdir la barre supérieure.
========================================================== */

.back-link{

display:inline-flex;

align-items:center;

gap:8px;

margin-bottom:32px;

color:var(--text-light);

font-weight:var(--fw-semibold);

font-size:.9rem;

transition:var(--transition);

}

.back-link i,
.back-link svg{

width:16px;

height:16px;

}

.back-link:hover{

color:var(--primary-color);

}

/* ==========================================================
CONTAINER
========================================================== */

.container{

width:min(1200px,92%);

margin:auto;

}

/* ==========================================================
BUTTONS — hover sobre (fond plus foncé + léger lift). L'ancien
effet de "sweep" brillant animé au survol a été retiré : c'est
une des signatures les plus reconnaissables du vibe coding, et
elle n'ajoutait aucune clarté fonctionnelle.
========================================================== */

/* ==========================================================
BOUTONS — physique de la pression (refonte 2026-08-28)
==========================================================
Chaque variante a une identité de SURFACE (voir plus bas) ; ce bloc-ci
définit ce qu'elles partagent : la façon dont un bouton répond au
doigt et à la souris.

RELÂCHEMENT PLUS LENT QUE LA PRESSION
Un bouton réel s'enfonce d'un coup et remonte en se détendant. Une
transition symétrique (l'ancienne : .15s dans les deux sens) donne au
contraire une réponse molle à l'aller et pressée au retour, exactement
l'inverse. On sépare donc les deux temps : 200ms au repos/relâchement
(ci-dessous), et --btn-press à l'enfoncement (voir .btn:active).

--btn-press est une VARIABLE et non une valeur écrite dans .btn:active
pour une raison précise : .btn-secondary a besoin de 0s (voir sa note),
et .btn:active pèse le même poids que .btn-secondary:active tout en
arrivant après dans le fichier — il l'aurait donc écrasée en silence.
Chaque variante règle sa propre durée de pression, personne n'écrase
personne.

HYGIÈNE TACTILE
Les trois dernières déclarations n'ont d'effet que sur écran tactile,
et corrigent des défauts qu'on ne voit jamais en testant à la souris :
le rectangle gris que Safari iOS peint sur tout élément pressé, la
sélection du libellé au double-tap ou à l'appui long, et le délai de
300ms que les navigateurs mobiles gardaient pour distinguer un
double-tap d'un zoom.
========================================================== */

/* ==========================================================
TROIS NIVEAUX, DÉFINIS ICI ET NULLE PART AILLEURS
(lot VITRINE-COMMERCIALE, 2026-09-11)
==========================================================
« Tous imposants », pris à la lettre, voudrait dire que plus aucun ne
ressort. La hiérarchie est donc portée par le NIVEAU, pas par la taille :

  1. PRINCIPAL   .btn-accent — ambre plein, libellé encre, 52 px de haut
                 (48 sur téléphone), flèche qui glisse au survol, légère
                 élévation, enfoncement au clic. UN SEUL par section
                 visible : deux boutons ambre côte à côte s'annulent.
  2. SECONDAIRE  .btn-secondary — papier PLEIN et bordure franche, en
                 valeurs LITTÉRALES : sur les pages sombres
                 (body.catalog-dark, l'espace), --background vaut un
                 voile translucide et --text-color du crème — un bouton
                 qui les consommait devenait un fantôme transparent au
                 libellé clair (capture 2 de Charles).
  3. LIEN        .btn-link — texte souligné avec flèche, pour une action
                 mineure à côté d'un principal.

.btn-primary (encre) reste l'action STRUCTURANTE des formulaires et de
l'espace étudiant (« Enregistrer », « Calculer », « Continuer ») : même
gabarit et même physique que le principal, mais il n'est pas un appel
commercial. Sur les pages publiques, l'action qui vend est ambre.

« Vivant » : transform et opacity seulement, 150 à 250 ms, tout
désactivé sous prefers-reduced-motion. Aucun clignotement, aucun
rebond permanent. Une feuille de page ne redéfinit AUCUN de ces
niveaux — les redéfinitions locales (.steps-footer .btn-primary,
.catalog-dark .pre-entree .btn-primary, .btn-lg de l'accueil, §6 de
css/vivant.css) ont été retirées avec ce lot.
========================================================== */

.btn{

--btn-press:90ms;

position:relative;

display:inline-flex;

align-items:center;

justify-content:center;

gap:10px;

padding:13px 22px;

/* Une bordure sur TOUTES les variantes (transparente là où la surface
est pleine) : deux boutons côte à côte partagent la même boîte, sans
les 2 px d'écart que la seule bordure du secondaire créait. */
border:1px solid transparent;

border-radius:var(--radius-md);

font-weight:600;

transition:transform 200ms var(--ease-standard),
box-shadow 200ms var(--ease-standard),
background-color 200ms var(--ease-standard),
border-color 200ms var(--ease-standard),
color 200ms var(--ease-standard);

cursor:pointer;

-webkit-tap-highlight-color:transparent;

user-select:none;

touch-action:manipulation;

}

/* LA FLÈCHE QUI GLISSE — sur les trois niveaux. Lucide remplace
<i data-lucide="arrow-right"> par <svg class="lucide lucide-arrow-right">
(js/icones.js) ; .steps-cta-arrow est la flèche en clair du pied
d'étapes de l'accueil. transform seul, 200 ms. */
.btn > .lucide-arrow-right,
.btn > .steps-cta-arrow{

transition:transform 200ms var(--ease-standard);

}

.btn:hover > .lucide-arrow-right,
.btn:hover > .steps-cta-arrow,
.btn:focus-visible > .lucide-arrow-right,
.btn:focus-visible > .steps-cta-arrow{

transform:translateX(4px);

}

/* ENCRE — l'action structurante (« Continuer », « Enregistrer »).
Passé du bleu --primary-600 à l'encre le 2026-08-28. C'était la
dernière surface bleue de taille du site : les grands fonds sont
graphite (--gradient-deep), les neutres sont papier chaud, le
sur-titre est or — un bouton bleu ne renvoyait plus à rien et se
lisait comme un vestige.

C'est aussi la répartition prévue de longue date par la palette
« encre & or » : l'encre porte les boutons, l'or reste l'accent
unique. Deux rôles, deux couleurs, aucune concurrence — là où bleu
+ or + graphite en faisaient trois qui se disputaient la hiérarchie.

Teinte volontairement plus claire que --text-color (#1A1714) : une
surface exactement de la couleur du texte qui l'entoure paraît un
trou dans la page plutôt qu'un objet posé dessus. Blanc sur #211D18 :
16,8:1. */
.btn-primary{

min-height:52px;

background:var(--ink-surface);

color:#fff;

}

.btn-primary:hover{

background:var(--ink-surface-hover);

transform:translateY(-2px);

box-shadow:var(--shadow-md);

}

/* PAPIER — l'action de second rang, à côté d'une action encre ou or.
Filet fin plutôt que surface pleine : elle doit rester lisible sans
jamais concurrencer le bouton qui compte. Son moment à elle, c'est la
pression (voir :active plus bas). */
.btn-secondary{

/* Pression instantanée, voir la note de .btn-secondary:active. Réglée
ici, en variable, plutôt que dans :active — c'est ce qui la protège de
.btn:active, qui arrive plus loin dans le fichier à poids égal. */
--btn-press:0s;

min-height:48px;

/* LITTÉRAUX, PAS DES TOKENS (lot VITRINE-COMMERCIALE) : voir la note
en tête du bloc. Papier #FDFCFA, encre #1A1714 (15,6:1), bordure
franche rgba(26,23,20,.32) — un bouton qui se lit sur le papier comme
sur l'encre des pages sombres, sans jamais devenir un fantôme. */
border-color:rgba(26,23,20,.32);

background:#FDFCFA;

color:#1A1714;

}

.btn-secondary:hover{

border-color:#1A1714;

color:#1A1714;

background:#F3EFE8;

transform:translateY(-1px);

box-shadow:var(--shadow-sm);

}

/* Retour visuel à l'enfoncement (2026-08-22, demande utilisateur : ces
boutons "gardent leur couleur blanche mais changent de couleur au
clic"). Le bouton reste donc blanc au repos ET au survol — seul le
temps de la pression il se remplit en ambre.

Doit rester APRÈS :hover dans le fichier : un bouton pressé est presque
toujours survolé en même temps, et les deux sélecteurs pèsent le même
poids (0,2,0). C'est l'ordre source, et lui seul, qui fait gagner
celui-ci. Le déplacer plus haut annulerait l'effet sans rien casser
d'autre — donc sans que ça se voie en relecture.

Même piège, résolu autrement, pour la DURÉE : .btn:active arrive
encore après cette règle, à poids égal, et écraserait un
transition-duration écrit ici. D'où --btn-press:0s posé sur
.btn-secondary lui-même (voir plus haut) plutôt qu'ici.

--ink-surface sur --amber-500, jamais du blanc : l'ambre vif est une
couleur de SURFACE, blanc dessus tombe à 2,16:1 alors que l'encre
tient 7,8:1 (voir la note --amber-* plus haut). Cette teinte est par
ailleurs réservée au CTA principal unique de chaque page (.btn-accent),
mais la règle vise la hiérarchie AU REPOS — deux boutons ambre côte à
côte s'annulent. Un état pressé n'existe qu'un à la fois et ne coexiste
avec rien : l'esprit de la règle est respecté.

transition-duration:0s est indispensable, pas cosmétique : .btn anime
background-color sur .15s, or un clic ordinaire sur un LIEN dure ~50ms
avant que la navigation ne parte. Avec l'animation par défaut, la
couleur n'atteignait qu'un tiers de sa valeur avant de disparaître —
c'est pourquoi le premier essai a été jugé sans effet. En instantané,
même une pression brève affiche l'ambre à pleine intensité.

L'icône suit sans rien de plus — Lucide dessine en currentColor. */
.btn-secondary:active{

background:var(--amber-500);

border-color:var(--amber-500);

color:var(--ink-surface);

transition-duration:0s;

}

/* OR — le CTA principal d'une page. L'ambre le détache des boutons
encre courants sans que la page devienne dorée. Un seul par page : si deux
boutons ambre se retrouvent à l'écran, aucun des deux ne ressort. */
.btn-accent{

min-height:52px;

padding-left:26px;

padding-right:26px;

/* LITTÉRAUX (voir --amber-500/--ink-surface) : les pages sombres
remappent --amber-700 mais pas ceux-ci — écrits en clair pour qu'aucun
scope ne puisse les atteindre. Encre sur ambre : 7,8:1. */
background:#E9A319;

color:#211D18;

font-weight:var(--fw-bold);

box-shadow:0 1px 2px rgba(33,29,24,.08), 0 8px 18px -10px rgba(233,163,25,.7);

}

.btn-accent:hover{

background:#F2B640;

color:#211D18;

transform:translateY(-2px);

box-shadow:0 2px 4px rgba(33,29,24,.08), 0 14px 26px -12px rgba(233,163,25,.85);

}

/* LIEN — le troisième niveau : texte souligné avec flèche, pour une
action mineure posée à côté d'un principal (« Voir les formules »).
Aucune surface, aucune ombre ; la flèche glisse comme sur les autres.
Cible tactile de 44 px tenue par la hauteur de boîte, pas par du
rembourrage qui l'aurait détaché de son texte. */
.btn-link{

--btn-press:0s;

/* 46 et non 44 : la boîte fractionnaire rend un cheveu de moins que la
valeur déclarée (43 px mesurés à 44) — un plancher se dépasse. */
min-height:46px;

padding:6px 2px;

border-color:transparent;

border-radius:var(--radius-xs);

background:transparent;

color:var(--text-color);

text-decoration:underline;

text-decoration-thickness:1.5px;

text-underline-offset:4px;

}

.btn-link:hover{

color:var(--amber-700);

background:transparent;

box-shadow:none;

}

.btn-link:active{

transform:none;

}

@media(max-width:640px){

.btn-accent,
.btn-primary{ min-height:48px; }

}

.btn-ghost{

background:transparent;

color:var(--text-light);

}

.btn-ghost:hover{

background:var(--background-soft);

color:var(--text-color);

}

/* Le fantôme n'a pas de surface au repos : sans état pressé propre, un
appui dessus ne renvoie rien du tout sur écran tactile, où il n'y a pas
de survol pour préparer le geste. Assombrissement d'un cran par rapport
au survol — le seul retour disponible ici. */
.btn-ghost:active{

background:var(--background-alt);

}

/* --danger-600 et non --danger : mesuré, #EF4444 ne donne que 3,76:1
avec du blanc, sous l'AA. Le bouton porte des actions irréversibles
(« Supprimer définitivement mon compte ») — c'est le dernier libellé
du site qui devrait être difficile à lire. #DC2626 tient 4,83:1 et
reste franchement rouge. */

.btn-danger{

background:var(--danger-600);

color:#fff;

}

.btn-danger:hover{

background:#DC2626;

}

.btn-sm{ padding:9px 16px; font-size:var(--fs-small); border-radius:var(--radius-sm); }
.btn-lg{ padding:16px 28px; font-size:1.05rem; }

/* L'ENFONCEMENT — commun à toutes les variantes.
Le bouton descend d'un pixel ET se contracte légèrement, au lieu de
seulement rapetisser (ancien `translateY(0) scale(.98)`). La nuance
compte : une échelle seule fait rétrécir l'objet sur place, comme s'il
s'éloignait ; un pixel de descente le fait entrer dans la page, ce qui
est le geste qu'on imite.

L'ombre est annulée en même temps — un objet plaqué contre une surface
ne projette plus rien. C'est ce qui vend l'enfoncement, davantage que
le déplacement lui-même.

.985 et non .98 : à 22px de haut de texte, 2 % de réduction suffisent à
rendre un libellé visiblement flou le temps de la pression.

var(--btn-press) : 90ms par défaut, 0s pour .btn-secondary. Voir la
note en tête du bloc boutons. */
.btn:active{

transform:translateY(1px) scale(.985);

box-shadow:none;

transition-duration:var(--btn-press);

}

/* Anneau de focus : outline plutôt que box-shadow, or plutôt que bleu.
box-shadow ne dessinait rien sur les boutons à fond sombre (l'ombre
portée se confondait avec la surface) et l'anneau bleu rgba(51,65,140)
renvoyait à une palette abandonnée. `outline` suit le border-radius
dans tous les moteurs actuels, se pose PAR-DESSUS toute surface quelle
que soit sa couleur, et survit au mode contraste forcé de Windows —
trois choses qu'une ombre portée ne fait pas.

L'écart de 2px empêche l'anneau de se coller au bord du bouton, où il
se lirait comme une bordure plutôt que comme un focus. */
.btn:focus-visible{

outline:2px solid var(--amber-600);

outline-offset:2px;

}

.btn:disabled,
.btn[disabled]{

opacity:.5;

cursor:not-allowed;

transform:none;

box-shadow:none;

}

/* ==========================================================
ÉCRANS TACTILES
==========================================================
Sur un appareil sans survol, :hover ne s'annule pas au retrait du
doigt : le navigateur le laisse actif jusqu'au prochain appui
ailleurs. Un bouton touché restait donc soulevé et ombré, figé dans un
état qui n'existe que pour la souris — le défaut le plus courant des
sites qui n'ont été essayés qu'au trackpad. On neutralise le survol là
où il n'a pas de sens ; l'état pressé, lui, reste (voir .btn:active).

La hauteur minimale de 44px est la cible tactile recommandée par les
WCAG (2.5.8) comme par Apple. .btn-sm (9px de rembourrage + .9rem de
texte ≈ 36px) passait dessous : au doigt, on le manquait. Le
rembourrage n'est pas touché, seule la hauteur de boîte est relevée —
la mise en page ne bouge pas sur les écrans à souris.
========================================================== */

@media (hover:none){

.btn:hover{

transform:none;

box-shadow:none;

}

}

@media (pointer:coarse){

.btn{ min-height:44px; }

}

/* Le déplacement et la contraction sont le seul retour de pression :
les supprimer entièrement laisserait le bouton muet. On garde donc le
changement de couleur (instantané, aucun mouvement) et on retire le
seul mouvement — conformément à la règle globale de
css/animations.css, qui ramène toute animation à .01ms. */
@media (prefers-reduced-motion:reduce){

.btn,
.btn:hover,
.btn:active,
.btn > .lucide-arrow-right,
.btn:hover > .lucide-arrow-right,
.btn > .steps-cta-arrow,
.btn:hover > .steps-cta-arrow{

transform:none;

transition:none;

}

}

/* ==========================================================
TYPOGRAPHIC HIERARCHY — rôles partagés par toute page. Une page
ne doit redéfinir une taille/graisse de titre, de lead ou de
libellé que si son contexte l'exige vraiment (ex. densité d'un
tableau admin) — jamais par habitude locale.
========================================================== */

h1, h2, h3, h4, h5, h6{

font-family:var(--font-display);

font-weight:var(--fw-bold);

letter-spacing:var(--ls-tight);

color:var(--text-color);

}

h1{ font-size:var(--fs-h1); line-height:var(--lh-tight); }
h2{ font-size:var(--fs-h2); line-height:var(--lh-tight); }
h3{ font-size:var(--fs-h3); line-height:var(--lh-snug); }
h4{ font-size:var(--fs-h4); line-height:var(--lh-snug); }
h5, h6{ font-size:var(--fs-h5); line-height:var(--lh-snug); letter-spacing:var(--ls-snug); }

p{

font-family:var(--font-body);

font-size:var(--fs-body);

line-height:var(--lh-relaxed);

color:var(--text-light);

}

.lead{

font-family:var(--font-body);

font-size:var(--fs-lead);

font-weight:var(--fw-medium);

line-height:var(--lh-relaxed);

color:var(--text-light);

}

.text-small{ font-size:var(--fs-small); }

/* Contenu réservé aux lecteurs d'écran (légende de tableau, libellé de
contexte). Existait en double dans payment.css et
eligibility-questions.css : remonté ici, les deux copies locales
deviennent redondantes et pourront être retirées. */
.visually-hidden{

position:absolute;

width:1px;

height:1px;

padding:0;

margin:-1px;

overflow:hidden;

clip:rect(0,0,0,0);

white-space:nowrap;

border:0;

}

/* Lien d'évitement — masqué comme .visually-hidden ci-dessus tant
qu'il n'a pas le focus clavier, puis reprend sa place normale (pas de
clip) pour être lisible. Premier élément du <body> sur les pages qui
l'utilisent, avant même le header, pour sauter sa navigation. */
.skip-link{

position:absolute;

top:-100%;

left:12px;

z-index:var(--z-header, 1000);

padding:12px 20px;

background:var(--primary-dark);

color:#fff;

font-weight:600;

border-radius:var(--radius-sm);

}

/* :focus-visible et non :focus (lot PEIGNE-FIN, 2026-09-10) : un focus
donné par un toucher ou par un script faisait apparaître le lien en
bloc sombre en haut à gauche de la page (photo de Charles, offers.html
sur téléphone). Il ne se montre qu'au clavier, son seul usage. */
.skip-link:focus-visible{

top:12px;

}

.text-caption{

font-size:var(--fs-caption);

letter-spacing:var(--ls-wide);

text-transform:uppercase;

font-weight:var(--fw-semibold);

color:var(--text-muted);

}

label, .label{

font-family:var(--font-body);

font-size:var(--fs-label);

font-weight:var(--fw-semibold);

color:var(--text-color);

}

button, .btn, input, select, textarea{

font-family:var(--font-body);

}

.btn{

font-size:var(--fs-button);

font-family:var(--font-body);

}

table{

font-family:var(--font-body);

font-size:var(--fs-small);

}

th{

font-weight:var(--fw-semibold);

font-size:var(--fs-caption);

letter-spacing:var(--ls-wide);

text-transform:uppercase;

color:var(--text-muted);

}

/* ==========================================================
RÔLES APPLICATIFS — titre de page (shell dashboard/admin), titre de
carte, sous-titre, navigation, pied de page, méta-information,
statistique.
========================================================== */

.text-page-title, .topbar-title h1{

font-family:var(--font-display);

font-size:var(--fs-page-title);

font-weight:var(--fw-bold);

line-height:var(--lh-tight);

letter-spacing:var(--ls-tight);

color:var(--text-color);

}

.text-subtitle{

font-family:var(--font-body);

font-size:var(--fs-subtitle);

font-weight:var(--fw-regular);

line-height:var(--lh-normal);

color:var(--text-light);

}

.text-card-title{

font-family:var(--font-display);

font-size:var(--fs-card-title);

font-weight:var(--fw-bold);

line-height:var(--lh-snug);

letter-spacing:var(--ls-snug);

color:var(--text-color);

}

.text-badge{

font-family:var(--font-display);

font-size:var(--fs-badge);

font-weight:var(--fw-bold);

letter-spacing:.02em;

}

.nav-link, .text-nav{

font-family:var(--font-body);

font-size:var(--fs-nav);

font-weight:var(--fw-semibold);

letter-spacing:var(--ls-normal);

}

.text-footer, footer, .footer{

font-size:var(--fs-footer);

}

.text-meta{

font-family:var(--font-body);

font-size:var(--fs-meta);

font-weight:var(--fw-medium);

color:var(--text-muted);

letter-spacing:var(--ls-normal);

}

.text-stat{

font-family:var(--font-display);

font-size:var(--fs-stat);

font-weight:var(--fw-extrabold);

line-height:1;

letter-spacing:var(--ls-tight);

font-variant-numeric:tabular-nums;

color:var(--text-color);

}

.text-stat-sm{

font-family:var(--font-display);

font-size:var(--fs-stat-sm);

font-weight:var(--fw-extrabold);

line-height:1;

letter-spacing:var(--ls-tight);

font-variant-numeric:tabular-nums;

}

/* ==========================================================
LISIBILITÉ SUR IMAGE — voile à deux couches réutilisable partout où
du texte repose sur une photo (héros, cartes bourses/universités).
========================================================== */

.text-on-media{

color:#fff;

text-shadow:0 1px 3px rgba(0,0,0,.35), 0 8px 24px rgba(0,0,0,.25);

}

/* Distinction du nom "Fitz" dans le texte courant, écho du "Bridge"
doré du logo (.logo .bridge, css/header.css). --amber-700 par défaut :
seule valeur ambre admise pour du texte sur fond clair (5,8:1 sur
--background). Les contextes app-shell à fond sombre (dashboard.css)
surchargent cette règle avec --amber-500, comme .sidebar-brand-text
.bridge le fait déjà pour le même mot dans la sidebar. */
.fitz-name{

color:var(--amber-700);

}

/* ==========================================================
KEYFRAMES PARTAGÉS
========================================================== */

@keyframes shimmer-sweep{

0%{ background-position:100% 50%; }

100%{ background-position:0 50%; }

}

@media (prefers-reduced-motion: reduce){

.ai-skeleton,
.bourses-skeleton-line{ animation:none; }

}

/* ==========================================================
COMPONENTS PARTAGÉS — cartes, badges, alertes/états vides,
champs de formulaire, tableau, base de modale. Toute nouvelle
carte/badge/alerte/champ/tableau/modale du site doit partir d'ici
plutôt que réinventer sa propre structure.
========================================================== */

.card{

background:var(--background);

border:1px solid var(--border-color);

border-radius:var(--radius-md);

box-shadow:var(--shadow-xs);

transition:var(--transition);

}

.card:hover{

box-shadow:var(--shadow-sm);

transform:translateY(-1px);

}

/* Hiérarchie d'importance — une grille de cartes ne doit pas toutes
peser pareil visuellement. .card--featured se distingue par une
bordure d'accent, pas par une ombre plus spectaculaire ;
.card--subtle pour ce qui est secondaire/désactivé. */

.card--featured{

border-color:rgba(126,113,216,.4);

box-shadow:var(--shadow-md);

}

.card--featured:hover{

box-shadow:var(--shadow-lg);

transform:translateY(-2px);

}

.card--subtle{

box-shadow:none;

background:var(--background-soft);

}

.card--subtle:hover{

box-shadow:var(--shadow-xs);

transform:none;

}

/* ==========================================================
SURFACE FITZ — le blanc chaud des cartes où Fitz s'exprime
==========================================================
Recette extraite le 2026-08-22 de `.fitz-demo .hero-demo::after`
(css/homepage-sections.css), où elle vivait seule. Demandée à
l'identique sur les autres pages qui incarnent Fitz : plutôt qu'une
4e copie divergente du même dégradé, elle est déclarée ici une fois
et consommée par une classe.

CE QUE ÇA FAIT, ET POURQUOI ÇA MARCHE — le point contre-intuitif :
le halo est un ::after en z-index:-1, mais il ne passe PAS derrière
la carte. Dès que l'élément crée un contexte d'empilement (via
isolation:isolate ici, ou un backdrop-filter déjà présent), le
z-index négatif est borné à ce contexte : le halo se peint alors
AU-DESSUS du fond de la carte et SOUS son contenu. C'est exactement
ce qui donne à la carte sa teinte crème (mesurée : de #F6F0E4 sur
les bords à #F4DFB8 au centre) au lieu d'un blanc pur — et non un
simple débordement lumineux autour d'elle.

Retirer isolation:isolate ferait donc basculer le halo derrière la
carte : il ne resterait qu'une lueur périphérique, la surface
redeviendrait blanche. Ce n'est pas un détail d'implémentation.

RAPPORT À LA RÈGLE AMBRE (voir --amber-500 plus haut, "jamais en
fond de section large") : c'est une entorse assumée et bornée, pas
une dérive. Elle ne s'applique qu'aux surfaces où Fitz parle en son
nom, jamais à une section de contenu ordinaire, et le halo est
contenu par l'overflow:hidden de la carte.

NE PAS l'appliquer à une surface qui porte déjà une couleur d'état :
sur results.html, le lavage ambré rendrait indistinct un axe "moyen"
(ambre) d'un axe "bon" (vert) dans la décomposition du score. La
carte de récit la reçoit, la carte de score non — délibérément.

Sur un élément SANS overflow:hidden, réduire `inset` sinon le halo
déborde largement au-delà de la carte. */

.fitz-surface{

position:relative;

/* Indispensable : c'est lui qui fait passer le halo par-dessus le
fond de la carte (voir plus haut). Sans effet si l'élément crée
déjà un contexte d'empilement via backdrop-filter. */
isolation:isolate;

/* Le lavage ambré assombrit la surface : mesuré au point le plus
chaud de la carte (#F7DFB1), --text-muted tombe à 3,96:1 — sous le
4,5:1 exigé pour du texte, alors qu'il tient 5,15:1 sur blanc. Toute
métadonnée, aide de champ ou légende posée sur une surface Fitz
échouerait donc AA sans rien changer d'autre.

--text-muted est redéfini ici, sur la surface elle-même, plutôt que
corrigé composant par composant : la variable cascade à toute la
carte, donc aucun texte secondaire ne peut passer au travers, y
compris ceux ajoutés plus tard. La valeur reprend --text-light —
par la VARIABLE depuis le 2026-09-02 : l'ancienne copie en dur
(#475569) datait de l'échelle slate et restait le dernier gris
BLEUTÉ actif du système ; en suivant la variable, la surface Fitz
reste alignée sur l'échelle chaude quoi qu'elle devienne. */
--text-muted:var(--text-light);

}

.fitz-surface::after{

content:"";

position:absolute;

inset:-70px;

z-index:-1;

/* Sans filter:blur (lot DEUX-MOTEURS, 2026-09-11) : le flou sur ce
calque négatif forçait WebKit à séparer le fond de la carte de son
premier plan — c'est cette séparation qui a laissé deux messages
superposés sur l'accueil (captures iPhone de Charles). La douceur est
dans les arrêts du dégradé. Couleurs mesurées avant/après : voir le
rapport du lot. isolation:isolate ci-dessus reste INTOUCHÉ. */
background:radial-gradient(circle, rgba(233,163,25,.38) 0%, rgba(233,163,25,.26) 24%, rgba(233,163,25,.14) 45%, rgba(233,163,25,.05) 62%, transparent 78%);

pointer-events:none;

}

@media(max-width:640px){

.fitz-surface::after{

inset:-36px;

}

}

@media (prefers-contrast: more){

/* Le lavage ambré réduit le contraste du texte sur la carte : on le
retire pour qui demande explicitement plus de contraste. */
.fitz-surface::after{ display:none; }

}

/* Verre dépoli — recette unique consommant --glass/--glass-border.
Réservé aux surfaces qui le justifient réellement (fond de header
au scroll, backdrop de modale) — pas un décor par défaut sur les
cartes de contenu. */

.glass-panel{

background:var(--glass);

border:1px solid var(--glass-border);

backdrop-filter:blur(16px);

-webkit-backdrop-filter:blur(16px);

}

.glass-panel--dark{

background:rgba(23,19,16,.45);

border:1px solid rgba(255,255,255,.16);

backdrop-filter:blur(16px);

-webkit-backdrop-filter:blur(16px);

}

.badge{

display:inline-flex;

align-items:center;

gap:6px;

padding:5px 12px;

border-radius:var(--radius-full);

font-family:var(--font-display);

font-size:var(--fs-badge);

font-weight:var(--fw-bold);

letter-spacing:.02em;

background:var(--background-light);

color:var(--primary-color);

white-space:nowrap;

}

.badge i,
.badge svg{ width:14px; height:14px; }

.badge-success{ background:rgba(34,197,94,.12); color:#178a44; }
.badge-warning{ background:rgba(234,168,61,.15); color:#a3711d; }
.badge-danger{ background:rgba(239,68,68,.12); color:#c53030; }
.badge-neutral{ background:var(--background-alt); color:var(--text-light); }

/* ==========================================================
BADGE FITZ — signature unique (2026-08-22)
==========================================================
Le badge qui annonce "c'est Fitz qui vous parle". UNE seule
définition pour tout le site : eligibility-test, eligibility-
questions, results, offers, payment.

Avant cette règle il en existait quatre, écrites séparément :
.fitz-badge (css/ai-suite.css, pilule violette translucide, texte
--primary-color) et trois copies de .ai-badge — deux identiques
(payment.css, results.css : fond --background-light) et une
divergente (offers.css : blanc translucide sur la photo du hero).
Sur eligibility-questions le libellé passait en plus par
.fitz-name, donc en ambre. Résultat : quatre Fitz différents dans
un même parcours, quand le badge est justement ce qui doit le
rendre reconnaissable d'une page à l'autre.

COULEUR — AMBRE (choix de l'utilisateur, 2026-08-22 : "pour la
couleur, je préfère le orange"). Le badge était violet Fitz ; il
passe à l'ambre de la marque.

Ce n'est pas une entorse à la règle "Fitz a sa propre couleur,
jamais l'ambre" : le mot "Fitz" est DÉJÀ ambre partout ailleurs sur
le site (.fitz-name plus haut, --amber-700, "écho du Bridge doré du
logo"). C'est la pilule violette qui était l'exception — une même
page pouvait écrire "Fitz" en ambre dans une phrase et en violet
dans le badge, à quelques centimètres d'écart. L'ambre les accorde.
Le violet Fitz reste la couleur de l'AVATAR, du halo et des bulles
de réponse : la distinction Fitz/marque ne disparaît pas, elle se
déplace du libellé vers l'assistant lui-même.

Valeurs, contraintes par la règle d'emploi de l'ambre plus haut :
  libellé  --amber-700 (#8A5D00) — la SEULE valeur ambre admise
           pour du texte sur fond clair. 5,76:1 sur le blanc de la
           pilule.
  contour  --amber-500 (#E9A319) — l'ambre franc, celui qu'on
           reconnaît comme orange. Il ne peut pas porter le texte
           (2,16:1 sur blanc) mais il porte parfaitement le
           contour : c'est lui qui fait lire le badge comme orange.

CE QU'ON N'A PAS FAIT : une pilule ambre PLEINE avec libellé
marine. Elle est plus franchement orange et passe 8,24:1, mais
--amber-500 en aplat est la surface du CTA PRINCIPAL du site. Un
badge non cliquable habillé comme le bouton d'action principal se
fait prendre pour un bouton — d'autant qu'il y en a un vrai plus bas
sur offers et payment. Le contour donne l'orange sans le
malentendu.

FOND OPAQUE, volontairement. Une pilule translucide s'adapte au
fond et change donc d'aspect d'une page à l'autre — c'est ce qui
avait forcé la variante blanche d'offers.css sur le hero
photographique. Un fond blanc plein tient aussi bien sur le crème
des pages d'éligibilité que sur une photo sombre, et reste
littéralement le même badge partout.

AUCUNE MARGE ICI : l'espacement dépend de la page (badge centré
au-dessus d'un titre, ou aligné à côté d'un avatar sur
eligibility-test). Chaque feuille de page pose sa propre marge.
.ai-badge est conservé comme alias : il est encore dans le HTML de
results/offers/payment, et le renommer partout n'apporterait
rien de plus que ce que fait cet alias. */

.fitz-badge,
.ai-badge{

/* flex, pas inline-flex : combiné à width:max-content, c'est ce qui
permet à `margin:0 auto` de centrer le badge sur results, offers et
payment. En inline-flex les marges auto ne centrent rien et le badge
retomberait sur le text-align du parent — centré par hasard ici,
décalé ailleurs. */
display:flex;

align-items:center;

gap:8px;

width:max-content;

max-width:100%;

padding:9px 18px;

border-radius:var(--radius-full);

background:#FFFFFF;

border:1.5px solid var(--amber-500);

box-shadow:0 1px 2px rgba(20,16,13,.05), 0 6px 18px rgba(233,163,25,.22);

color:var(--amber-700);

font-family:var(--font-display);

font-weight:var(--fw-bold);

font-size:.88rem;

letter-spacing:-.005em;

/* Pas de white-space:nowrap : le libellé long d'eligibility-test
("Fitz, votre conseiller intelligent") doit pouvoir passer à la
ligne sur petit écran. En nowrap il dépassait la carte et
rouvrait le débordement horizontal corrigé sur ces pages. */

}

/* Pas de règle d'icône ici : le badge n'en porte plus (2026-08-22,
demande de l'utilisateur). Le robot `bot` a été retiré du HTML des
cinq pages, pas seulement masqué — une icône masquée en CSS reste
dans le DOM, lue par les lecteurs d'écran et rechargée par Lucide à
chaque `createIcons()`. Règle "Icônes" de DESIGN_SYSTEM.md : une
icône qui ne fait que décorer se retire, et celle-ci ne disait rien
que le mot "Fitz" juste à côté ne disait déjà.
Ne pas réintroduire de `.fitz-badge i/svg` : ce serait une règle
sans cible tant qu'aucun badge ne porte d'icône. */

/* Le nom "Fitz" est déjà ambre dans le TEXTE COURANT (.fitz-name,
plus haut) — écho du "Bridge" doré du logo. Le badge prend donc la
même famille de couleur : `color:inherit` suffit, et les deux
écritures du mot "Fitz" sur une même page s'accordent enfin au lieu
de se contredire (ambre dans la phrase, violet dans la pilule). */
.fitz-badge .fitz-name,
.ai-badge .fitz-name{ color:inherit; }

.alert{

display:flex;

align-items:flex-start;

gap:12px;

padding:16px 20px;

border-radius:var(--radius-sm);

border:1px solid var(--border-color);

background:var(--background-soft);

font-size:var(--fs-small);

color:var(--text-light);

}

.alert i,
.alert svg{ flex-shrink:0; width:18px; height:18px; color:var(--primary-color); }

.alert-danger{ background:rgba(239,68,68,.06); border-color:rgba(239,68,68,.25); color:#9f1c1c; }
.alert-danger i,
.alert-danger svg{ color:var(--danger); }

.alert-warning{ background:rgba(234,168,61,.08); border-color:rgba(234,168,61,.3); color:#7a5216; }
.alert-warning i,
.alert-warning svg{ color:var(--warning); }

.alert-success{ background:rgba(34,197,94,.08); border-color:rgba(34,197,94,.3); color:#166534; }
.alert-success i,
.alert-success svg{ color:var(--success); }

.empty-state{

display:flex;

flex-direction:column;

align-items:center;

gap:14px;

padding:60px 24px;

text-align:center;

color:var(--text-light);

}

/* Glyphe d'illustration : le message de l'état vide est écrit juste
en dessous, l'icône ne porte aucune information à elle seule. */
.empty-state i,
.empty-state svg{ width:36px; height:36px; color:var(--text-decorative); }

.empty-state h3{ font-size:var(--fs-h4); color:var(--text-color); }

/* Champ de formulaire — LE seul système de champ du site. Remplace
les 6+ recettes indépendantes trouvées dans l'audit (.input-wrap
dupliqué, .apps-field, .uni-toolbar-field, .bourses-search-field,
.docs-search-field, .form-group...). Structure attendue :
<div class="field">
  <label>Libellé</label>
  <div class="field-control">
    <i data-lucide="..."></i>
    <input/select/textarea>
  </div>
  <p class="field-hint">Aide ou erreur</p>
</div>
La div .field-control est optionnelle si aucune icône n'est
nécessaire (l'input peut alors être un enfant direct de .field). */

.field{

display:flex;

flex-direction:column;

gap:6px;

}

.field label{

font-size:var(--fs-label);

font-weight:var(--fw-semibold);

color:var(--text-color);

}

.field-control{

position:relative;

display:flex;

align-items:center;

}

.field-control i,
.field-control svg{

position:absolute;

left:16px;

width:18px;

height:18px;

color:var(--text-decorative);

pointer-events:none;

}

.field input,
.field select,
.field textarea,
.field-control input,
.field-control select,
.field-control textarea{

width:100%;

padding:12px 16px;

border:1px solid var(--border-color);

border-radius:var(--radius-sm);

background:var(--background);

font-family:var(--font-body);

font-size:var(--fs-body);

color:var(--text-color);

transition:border-color .15s var(--ease-standard), box-shadow .15s var(--ease-standard);

}

.field-control i + input,
.field-control i + select,
.field-control i + textarea{

padding-left:46px;

}

.field textarea{

resize:vertical;

min-height:110px;

}

.field input:focus,
.field select:focus,
.field textarea:focus{

outline:none;

border-color:var(--primary-color);

box-shadow:0 0 0 3px rgba(26,23,20,.10);

}

.field input::placeholder,
.field textarea::placeholder{

color:var(--text-muted);

}

.field-hint{

font-size:var(--fs-caption);

color:var(--text-muted);

}

.field.has-error input,
.field.has-error select,
.field.has-error textarea{

border-color:var(--danger);

}

.field.has-error .field-hint{

color:var(--danger);

}

/* Tableau partagé — bordures, en-tête, survol de ligne. Remplace
les tableaux non tokenisés (admin notamment). */

.table{

width:100%;

border-collapse:collapse;

}

.table th{

text-align:left;

padding:12px 16px;

border-bottom:1px solid var(--border-color);

}

.table td{

padding:14px 16px;

border-bottom:1px solid var(--border-color);

color:var(--text-color);

}

.table tbody tr{

transition:background-color .15s var(--ease-standard);

}

.table tbody tr:hover{

background:var(--background-soft);

}

.table tbody tr:last-child td{

border-bottom:none;

}

.modal-base{

position:fixed;

inset:0;

z-index:var(--z-modal);

display:flex;

align-items:center;

justify-content:center;

padding:24px;

background:rgba(23,19,16,.55);

backdrop-filter:blur(4px);

}

.modal-base[hidden]{ display:none; }

.modal-base .modal-card{

width:100%;

max-width:520px;

max-height:90vh;

overflow-y:auto;

/* Défilement à inertie natif sur les anciens WebKit iOS (Safari
récent le fait déjà par défaut, mais sans cette ligne le défilement
interne d'une modale y devient saccadé/pas-à-pas sur les versions
encore en usage) — sans effet ailleurs, propriété ignorée par tout
autre moteur. */
-webkit-overflow-scrolling:touch;

/* Une fois en butée haute/basse du contenu de la modale, empêche
l'inertie restante de "passer au travers" et de faire défiler la page
en arrière-plan — c'était le cas par défaut : fermer visuellement la
modale en scrollant vite jusqu'au bout donnait l'impression que la
page entière avait bougé sous elle. */
overscroll-behavior:contain;

background:var(--background);

border-radius:var(--radius-lg);

box-shadow:var(--shadow-lg);

padding:32px;

}

.modal-base .modal-header{

display:flex;

align-items:center;

justify-content:space-between;

margin-bottom:18px;

}

.modal-base .modal-close{

background:none;

border:none;

cursor:pointer;

color:var(--text-light);

}

/* ==========================================================
<picture> — TRANSPARENT POUR LA MISE EN PAGE (2026-08-22)
==========================================================
Les photos de la page d'accueil sont désormais servies en AVIF, puis
WebP, puis JPEG, via <picture><source ...><img></picture>.

display:contents fait disparaître la boîte du <picture> : c'est
l'<img> qui redevient l'enfant direct de son parent pour la mise en
page. Sans cette règle, tout le CSS existant se serait retrouvé à
styler un intermédiaire invisible — .vision-illustration est un
conteneur flex dont l'enfant serait devenu le <picture> (sans
largeur propre) au lieu de l'image, .hero-media positionne son image
en absolu, etc. Il aurait fallu réécrire une dizaine de règles ; ici
une seule ligne, et aucune feuille de page n'a eu à changer.

<picture> n'a aucune sémantique propre (c'est un simple sélecteur de
source) : le retirer du rendu ne retire rien à personne, ni à
l'arbre d'accessibilité ni au sens du document. C'est exactement le
cas d'usage prévu pour display:contents.
========================================================== */

picture{ display:contents; }

/* ==========================================================
GLOBAL SECTIONS
========================================================== */

section{

position:relative;

padding:110px 0;

overflow:hidden;

}

.section{

padding:110px 0;

}

/* Rythme vertical mobile (passe mobile 2026-09-01, lot 3) : 110px de
respiration entre sections est un rythme d'écran de bureau ; sur un
téléphone il fait défiler du vide et éloigne les contenus les uns des
autres. ~64px est le pas des sites mobiles actuels. Les feuilles de
page qui redéfinissent leur propre padding de section APRÈS base.css
(ex. homepage-sections.css) doivent porter leur propre palier ≤576px :
un @media n'ajoute aucune spécificité, c'est l'ordre de chargement qui
tranche. */
@media(max-width:576px){

section,
.section{

padding:64px 0;

}

}

.section-header{

max-width:760px;

margin:0 auto 70px;

text-align:center;

}

.section-header h2{

font-size:clamp(2rem,4vw,3.2rem);

line-height:1.15;

font-weight:800;

margin-bottom:20px;

color:var(--text-color);

}

.section-header p{

font-size:1.1rem;

color:var(--text-light);

line-height:1.8;

}

.section-badge{

display:inline-flex;

align-items:center;

gap:10px;

padding:10px 18px;

margin-bottom:22px;

border-radius:999px;

background:rgba(26,23,20,.06);

color:var(--primary-color);

font-weight:700;

font-size:.92rem;

}

.section-badge i,
.section-badge svg{

width:18px;

height:18px;

}

/* ==========================================================
SAISIE SUR TÉLÉPHONE — PAS DE ZOOM AU FOCUS (2026-09-03)
==========================================================
Retour utilisateur (captures iPhone) : « le site n'est pas statique…
surtout quand on essaie de saisir un texte ». Cause : iOS Safari ZOOME
automatiquement la page dès qu'un champ dont la police fait moins de
16px reçoit le focus — et la page se décale, puis ne revient pas à
l'échelle après le clavier. Plusieurs champs du site sont en
--fs-small (14,4px) ou moins (recherche du catalogue, filtres, champs
des outils). Sous 720px, tout champ de saisie passe à 16px : c'est la
seule parade fiable (maximum-scale=1 est à proscrire, il bloque le
zoom d'accessibilité). !important assumé : des dizaines de règles de
page posent leur propre taille avec une spécificité plus haute, et
l'exception doit gagner partout, y compris sur les champs injectés. */
@media (max-width:720px){
input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="file"]),
select,
textarea{
font-size:16px !important;
}
}


/* ==========================================================
CHAMPS NOMBRE ET DATE (lot CONTRÔLES-UNIFIÉS, 2026-09-11)
==========================================================
Charles refuse les contrôles dessinés par le système : curseur minuscule
du <input type="number">, calendrier du <input type="date">.

NOMBRE — le curseur natif disparaît, le champ garde type="number" :
c'est lui qui ouvre le clavier numérique sur téléphone. Même valeur,
même nom, mêmes min/max/step ; seul l'habillage change.

DATE — DÉCISION (à ne pas rouvrir sans raison) : le sélecteur natif est
GARDÉ. Il est fiable, connu, excellent sur téléphone ; un calendrier
maison correct (fuseaux, clavier, saisie manuelle, lecteurs d'écran)
est le composant le plus coûteux à écrire, et un calendrier mal fait
serait pire que le natif. On habille le CHAMP au repos (police, hauteur,
icône) pour qu'il ressemble aux autres ; le panneau qui s'ouvre reste
celui du navigateur. */
input.fitz-num{
appearance:textfield;
-moz-appearance:textfield;
}

input.fitz-num::-webkit-outer-spin-button,
input.fitz-num::-webkit-inner-spin-button{
-webkit-appearance:none;
appearance:none;
margin:0;
}

input.fitz-date{
appearance:none;
-webkit-appearance:none;
font-family:inherit;
font-size:inherit;
color:inherit;
min-height:44px;
}

input.fitz-date::-webkit-calendar-picker-indicator{
cursor:pointer;
opacity:.65;
}

input.fitz-date:hover::-webkit-calendar-picker-indicator,
input.fitz-date:focus::-webkit-calendar-picker-indicator{
opacity:1;
}

/* Cases à cocher et boutons radio : le navigateur les dessine, mais il
accepte une couleur d'accent — la marque, en littéral (les variables
ambre sont redéfinies en terracotta par onze feuilles). Fini le bleu
système des radios « Niveau visé » (diagnostic-france.html). */
input[type="checkbox"],
input[type="radio"]{
accent-color:#E9A319;
}

/* ==========================================================
CHOIX UNIQUE — .fitz-choice (lot FINITIONS-VISUELLES, 2026-09-11)
==========================================================
Le bouton radio du SITE, dans la lignée de fitz-select : le rond dessiné
par le système ne se voit plus. Structure :

  <label class="fitz-choice">
    <input type="radio" name="…" value="…">
    <span class="fitz-choice-dot" aria-hidden="true"></span>
    <span>Libellé</span>
  </label>

L'input reste dans le DOM — clavier, lecteur d'écran, `:checked`,
form.reset() — mais sort du rendu ; le point est dessiné en CSS et
suit `input:checked ~ .fitz-choice-dot`, sans JavaScript ni :has().
Le focus clavier se voit sur le point (input:focus-visible ~ .dot).
Première page servie : profile.html (test de langue, type
d'université, garant). */
.fitz-choice-group{
display:flex;
flex-wrap:wrap;
gap:10px;
}

/* Le second sélecteur (0,2,0) l'emporte sur les « .input-group label »
des formulaires (0,1,1), qui posent display:block sur tout label. */
.fitz-choice,
.fitz-choice-group .fitz-choice{
position:relative;
display:inline-flex;
align-items:center;
gap:9px;
min-height:40px;
padding:8px 14px 8px 12px;
border:1.5px solid var(--border-color);
border-radius:999px;
background:var(--background-soft);
color:var(--text-color);
font-size:.88rem;
font-weight:600;
line-height:1.3;
cursor:pointer;
transition:border-color .15s ease, background .15s ease;
}

.fitz-choice:hover{ border-color:var(--primary-color); }

.fitz-choice input{
position:absolute;
width:1px;
height:1px;
padding:0;
margin:-1px;
overflow:hidden;
clip:rect(0,0,0,0);
white-space:nowrap;
border:0;
}

.fitz-choice-dot{
flex-shrink:0;
width:16px;
height:16px;
border-radius:50%;
border:1.5px solid var(--text-light);
background:#FFFFFF;
box-sizing:border-box;
transition:border-color .15s ease, background .15s ease, box-shadow .15s ease;
}

/* Choisi : l'ambre de la marque, en LITTÉRAL (onze feuilles redéfinissent
l'échelle ambre en terracotta), avec un point d'encre au centre. */
.fitz-choice input:checked ~ .fitz-choice-dot{
border-color:#E9A319;
background:#E9A319;
box-shadow:inset 0 0 0 3px #FFFFFF;
}

.fitz-choice:has(input:checked){
border-color:#E9A319;
background:rgba(233,163,25,.10);
}

.fitz-choice input:focus-visible ~ .fitz-choice-dot{
outline:2px solid var(--primary-color);
outline-offset:2px;
}

.fitz-choice input:disabled ~ *{ opacity:.55; }

/* ==========================================================
   LA RECHERCHE — UN SEUL CHAMP POUR TOUT L'ESPACE ÉTUDIANT
   ==========================================================
   (lot ESPACE-ÉTUDIANT, 2026-09-13)

   L'audit des champs a trouvé TROIS recherches texte, trois recettes,
   aucune partagée :
     - le catalogue (.catalog-search-field) : loupe en absolu, bouton
       d'effacement, focus terracotta sur le conteneur ;
     - « Mes documents » (.docs-search-field) : loupe en ligne, fond
       beige, **aucun état de focus** ;
     - l'historique de Fitz (.ai-chat-history-search) : troisième
       géométrie, troisième taille de police, **aucun état de focus**.

   Deux champs sur trois ne réagissaient donc pas au clavier : pour qui
   navigue à la tabulation, le curseur disparaissait purement et
   simplement. Et trois rayons, trois tailles et deux positions de loupe
   se voyaient d'un écran à l'autre du même espace.

   `.fitz-recherche` est le champ du site. Il reprend ce qui marchait
   dans le catalogue — focus sur le conteneur, icône qui vire à l'ambre —
   et le pose sur le papier chaud de l'espace étudiant. Une seule
   définition : la prochaine page qui cherche quelque chose l'utilise.

   Structure attendue :
     <div class="fitz-recherche">
       <i data-lucide="search"></i>
       <input type="search" placeholder="…">
     </div>
   ========================================================== */

/* ⚠️ CE COMPOSANT NE DÉCLARE PAS SON `flex`. C'EST LE CONTENEUR QUI DÉCIDE.
   Il portait `flex:1 1 260px` — juste dans la barre d'outils de « Mes
   documents », qui est une RANGÉE, et catastrophique dans la colonne de
   l'historique de Fitz : sur l'axe vertical, ce `260px` devient une
   HAUTEUR, le champ s'est étiré sur 260 px et a écrasé la liste des
   conversations contre le bas du panneau. C'est le grand vide que
   Charles a entouré en rouge le 2026-09-14.
   Un composant réutilisable décrit son APPARENCE ; sa place dans un flux
   appartient à la page qui le pose. Voir documents.css, qui l'étire
   lui-même dans sa rangée. */
.fitz-recherche{
position:relative;
display:flex;
align-items:center;
gap:9px;
flex:0 0 auto;
width:100%;
box-sizing:border-box;
min-width:0;
padding:9px 14px;
border:1px solid var(--border-color);
border-radius:var(--radius-sm);
background:var(--background);
transition:border-color .15s var(--ease-standard, ease), box-shadow .15s var(--ease-standard, ease);
}

.fitz-recherche i,
.fitz-recherche svg{
flex-shrink:0;
width:16px;
height:16px;
color:var(--text-muted);
transition:color .15s var(--ease-standard, ease);
}

.fitz-recherche input{
flex:1 1 auto;
min-width:0;
border:none;
outline:none;
background:transparent;
font-family:var(--font-body);
font-size:.88rem;
color:var(--text-color);
/* La croix native de <input type="search"> est dessinée par l'OS et
   ignore la charte : on la retire, le champ se vide à la main. */
appearance:none;
-webkit-appearance:none;
}

.fitz-recherche input::-webkit-search-cancel-button{ display:none; }
.fitz-recherche input::placeholder{ color:var(--text-muted); }

/* CE QUI MANQUAIT : le champ répond au clavier. */
.fitz-recherche:focus-within{
border-color:var(--accent-color);
box-shadow:0 0 0 3px rgba(190,96,50,.16);
}

.fitz-recherche:focus-within i,
.fitz-recherche:focus-within svg{ color:var(--accent-color); }
