/* ==========================================================================
   GINKO DISPLAYS. Design System
   Noir & blanc. HW Cigars (serif) + Area Inktrap (sans).
   Aucune dépendance externe. Tout est local.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. FONTS
   -------------------------------------------------------------------------- */
@font-face {
  font-family: "HW Cigars";
  src: url("../fonts/HWCigars-Light.woff2") format("woff2");
  font-weight: 300 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Area Inktrap";
  src: url("../fonts/Area-Inktrap-Trial-Regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
/* La version Trial embarque une ligature "fi" defectueuse : elle avale le point
   du i et affiche "confrm" au lieu de "confirm". On desactive les ligatures
   standard sur cette famille. A revoir si la version sous licence est correcte. */
body, input, button, textarea, select {
  font-variant-ligatures: no-common-ligatures;
  font-feature-settings: "liga" 0, "clig" 0;
}
@font-face {
  font-family: "Area Inktrap Extended";
  src: url("../fonts/Area-Inktrap-Extended-Medium.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Degular";
  src: url("../fonts/DegularVariable.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

/* Poppins : remplace les deux Area Inktrap sur les pages francaises,
   dont la licence ne couvre que la version anglaise. */
@font-face {
  font-family: "Poppins";
  src: url("../fonts/Poppins-Regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Poppins";
  src: url("../fonts/Poppins-Medium.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

/* --------------------------------------------------------------------------
   2. TOKENS
   -------------------------------------------------------------------------- */
:root {
  /* Palette : noir et blanc, aucun accent coloré */
  --gk-black: #000000;
  --gk-near-black: #0a0a0a;
  --gk-charcoal: #1a1a18;
  --gk-white: #ffffff;
  --gk-off-white: #f5f5f4;
  --gk-paper: #eeeeec;
  --gk-mid-gray: #a8a8a6;
  --gk-warm-gray: #737370;

  /* Gris sourd sémantique : bascule selon le fond, pour rester lisible.
     Sur noir 6.54:1, sur blanc 5.62:1, sur paper 4.84:1. Tous au-dessus de AA. */
  --muted: #909089;
  --body-ink: var(--gk-mid-gray);

  /* Typographie */
  --font-serif: "HW Cigars", "PP Editorial New", "Cormorant Garamond", Georgia, serif;
  --font-sans: "Area Inktrap", "Degular", "Söhne", system-ui, sans-serif;
  --font-sans-ext: "Area Inktrap Extended", var(--font-sans);
}

/* Pages francaises : la licence Area Inktrap ne couvre que l'anglais,
   Poppins prend sa place (corps comme eyebrows). Le serif ne change pas. */
html[lang="fr"] {
  --font-sans: "Poppins", "Degular", system-ui, sans-serif;
  --font-sans-ext: "Poppins", "Degular", system-ui, sans-serif;
}

:root {

  /* Échelle typographique : reprise du site d'origine.
     Plate et resserrée : le titre ne hurle pas, il pose.
     Titres : line-height 1, letter-spacing -0.6px. */
  --fs-eyebrow: 0.625rem;   /* 10px */
  --fs-body: 0.875rem;      /* 14px */
  --fs-lead: 0.875rem;      /* 14px : aucun paragraphe au-dela du corps */
  --fs-h3: 1.625rem;        /* 26px */
  --fs-h2: 2rem;            /* 32px */
  --fs-h1: 2.5rem;          /* 40px */
  --fs-hero: 3rem;          /* 48px, plafond, jamais au-delà */

  /* Rythme vertical : plus d'air qu'à l'origine, c'est le luxe */
  --space-2xs: 0.5rem;
  --space-xs: 1rem;
  --space-sm: 1.75rem;
  --space-md: 2.75rem;
  --space-lg: 4.5rem;
  --space-xl: 6.5rem;
  --space-2xl: 8.5rem;
  --space-3xl: 10.5rem;

  /* Layout */
  --wrap: 1280px;
  --wrap-narrow: 780px;
  --gutter: 2.5rem;

  /* Aucun arrondi nulle part : bords droits, c'est la direction artistique. */
  --radius: 0;

  /* Motion : Ginko ne bondit pas, Ginko se révèle */
  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  /* La courbe des revelations : un depart plus franc, une pose tres longue.
     La meme duree parait plus vive au debut et plus douce a la fin. */
  --ease-reveal: cubic-bezier(0.22, 1, 0.36, 1);
  --dur: 900ms;
  --dur-fast: 600ms;
}

/* Sur un tres grand ecran, un gabarit fige a 1280 px flotte dans le vide et
   la typographie parait timide. Tout monte d'un cran, dans les memes
   proportions : le dessin ne change pas, il respire plus grand. */
@media (min-width: 1680px) {
  :root {
    --wrap: 1440px;
    --fs-hero: 3.5rem;
    --fs-h1: 2.875rem;
    --fs-h2: 2.25rem;
    --fs-lead: 1.25rem;
    --space-lg: 5.25rem;
    --space-xl: 7.5rem;
  }
}

/* Écrans intermédiaires : on resserre l'échelle d'un cran */
@media (max-width: 1100px) {
  :root {
    --fs-hero: 2.5rem;   /* 40px */
    --fs-h1: 2.25rem;    /* 36px */
    --fs-h2: 1.75rem;    /* 28px */
    --fs-h3: 1.5rem;     /* 24px */
    --fs-lead: 0.875rem;
    --gutter: 2rem;
  }
}

@media (max-width: 700px) {
  :root {
    --fs-hero: 2rem;     /* 32px */
    --fs-h1: 1.875rem;   /* 30px */
    --fs-h2: 1.5rem;     /* 24px */
    --fs-h3: 1.3125rem;  /* 21px */
    --fs-lead: 0.875rem;
    --gutter: 1.5rem;
    --space-sm: 1.5rem;
    --space-md: 2.25rem;
    --space-lg: 3.5rem;
    --space-xl: 5rem;
    --space-2xl: 6.5rem;
    --space-3xl: 8rem;
  }
}

/* --------------------------------------------------------------------------
   3. RESET
   -------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

body {
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  line-height: 1.78;
  letter-spacing: 0;
  color: var(--gk-white);
  background: var(--gk-black);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

img, picture, video, svg { display: block; max-width: 100%; }
img, video { height: auto; }
input, button, textarea, select { font: inherit; color: inherit; }
button { background: none; border: 0; cursor: pointer; }
a { color: inherit; text-decoration: none; }

/* Accessibilité : lien d'évitement */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 200;
  padding: 0.75rem 1.25rem;
  background: var(--gk-white);
  color: var(--gk-black);
}
.skip-link:focus { left: 1rem; top: 1rem; }

:focus-visible {
  outline: 1px solid currentColor;
  outline-offset: 3px;
}

/* --------------------------------------------------------------------------
   4. TYPOGRAPHIE
   -------------------------------------------------------------------------- */
.eyebrow {
  font-family: var(--font-sans-ext);
  font-size: var(--fs-eyebrow);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.2em;   /* = 2px à 10px, comme l'origine */
  line-height: 1;
  color: var(--muted);
  margin-bottom: var(--space-md);
}
/* Un intertitre colle a son titre n'ouvre pas une section, il l'annonce :
   l'ecart general le detachait trop, et les reprises en ligne le collaient
   trop. Une seule valeur, partout ou les deux se suivent. Un intertitre qui
   coiffe une grille, lui, garde l'ecart plein : il n'a pas de titre pour
   porter le regard jusqu'au contenu. */
.section .eyebrow:has(+ h2),
.section .eyebrow:has(+ h3) { margin-bottom: var(--space-sm); }
.section--light .eyebrow,
.section--paper .eyebrow { color: var(--muted); }

/* Titres : serif, très peu de graisse, interligne serré.
   C'est l'interligne à 1 qui donne le ton éditorial. */
h1, h2, h3, .h3 {
  font-family: var(--font-serif);
  font-weight: 300;
  line-height: 1.04;
  letter-spacing: -0.015em;
  text-wrap: balance;
}

h1 { font-size: var(--fs-h1); }
h2 { font-size: var(--fs-h2); }
h3, .h3 { font-size: var(--fs-h3); line-height: 1.12; }

/* Le hero est le seul à monter à 48px */
.hero__title, .page-hero h1 { font-size: var(--fs-hero); }

h4, .h4 {
  font-family: var(--font-sans-ext);
  font-size: var(--fs-body);
  font-weight: 500;
  line-height: 1.45;
  letter-spacing: 0;
}

/* Chapô : plus grand que le corps, en sans, légèrement resserré */
.lead {
  font-size: var(--fs-lead);
  line-height: 1.7;
  letter-spacing: 0;
  color: var(--gk-mid-gray);
  max-width: 52ch;
}
.section--light .lead, .section--paper .lead { color: var(--muted); }

/* La largeur de lecture ne concerne que le texte courant.
   L'appliquer à tous les p décalait eyebrows et boutons dans les sections centrées. */
.prose p, .legal p { max-width: 60ch; }
.prose p + p { margin-top: 1.6em; }
.prose { color: var(--gk-mid-gray); }
.section--light .prose, .section--paper .prose { color: var(--gk-charcoal); }

.caption {
  font-size: 0.75rem;
  line-height: 1.7;
  color: var(--muted);
}

em { font-style: italic; }

/* --------------------------------------------------------------------------
   5. LAYOUT
   -------------------------------------------------------------------------- */
.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--gutter);
}
.wrap--narrow { max-width: var(--wrap-narrow); }

.section {
  padding-block: var(--space-2xl);
  position: relative;
}
.section--tight { padding-block: var(--space-xl); }

.section--light {
  background: var(--gk-white);
  color: var(--gk-charcoal);
  --muted: #68685f;
  --body-ink: var(--gk-charcoal);
}
.section--paper {
  background: var(--gk-paper);
  color: var(--gk-charcoal);
  --muted: #68685f;
  --body-ink: var(--gk-charcoal);
}
.section--dark {
  background: var(--gk-black);
  color: var(--gk-white);
}

.grid { display: grid; gap: var(--space-md); }
.grid--2 { grid-template-columns: repeat(2, 1fr); }
.grid--3 { grid-template-columns: repeat(3, 1fr); }

@media (max-width: 1000px) {
  .grid--3, .grid--4 { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 640px) {
  .grid--2, .grid--3, .grid--4 { grid-template-columns: 1fr; }
}

/* Bloc éditorial asymétrique : titre à gauche, texte à droite */
.split {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
  gap: var(--space-md) var(--space-xl);
  align-items: start;
}
@media (max-width: 900px) {
  .split { grid-template-columns: 1fr; gap: var(--space-md); }
}

/* --------------------------------------------------------------------------
   6. BOUTONS
   -------------------------------------------------------------------------- */
/* Au doigt, un bouton sans reponse a l'air mort : un tassement d'un pour
   cent le temps de l'appui suffit. */
.btn:active { transform: scale(0.99); }
.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.8em;
  font-family: var(--font-sans-ext);
  font-size: 0.625rem;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.2em;
  padding: 1.15em 2.4em;
  border-radius: 0;
  border: 1px solid transparent;
  transition: background var(--dur-fast) var(--ease),
              color var(--dur-fast) var(--ease),
              border-color var(--dur-fast) var(--ease);
}

/* --- la regle des deux CTA ------------------------------------------------
   Un bouton ne porte pas de fleche : son cadre dit deja qu'on clique. Un lien
   n'a pas de cadre, c'est sa fleche qui le dit, et rien d'autre : un filet
   sous le mot faisait une deuxieme ligne pleine a cote du bouton. Les deux
   sont en Area Inktrap Extended, meme corps et meme chasse : cote a cote, ils
   se lisent comme une action principale et son alternative.
   -------------------------------------------------------------------------- */
.link-underline {
  display: inline-flex;
  align-items: baseline;
  gap: 0.7em;
  font-size: 0.625rem;
  text-transform: uppercase;
  letter-spacing: 0.2em;
}
.link-underline::after {
  content: "\2192";
  letter-spacing: 0;
  transition: transform var(--dur-fast) var(--ease);
}
.link-underline:hover::after { transform: translateX(4px); }

/* Un bouton et son alternative discrete, sur une meme ligne. En flex : sur un
   ecran etroit ils passent l'un sous l'autre en gardant le meme bord gauche,
   la ou une marge fixe les decalait en escalier. */
.actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1.15rem 2rem;
}

.btn--primary {
  background: var(--gk-white);
  color: var(--gk-black);
}
.btn--primary:hover { background: var(--gk-paper); }

.btn--ghost {
  border-color: rgba(255, 255, 255, 0.35);
  color: var(--gk-white);
}
.btn--ghost:hover {
  border-color: var(--gk-white);
  background: rgba(255, 255, 255, 0.06);
}

.section--light .btn--primary,
.section--paper .btn--primary {
  background: var(--gk-black);
  color: var(--gk-white);
}
.section--light .btn--primary:hover,
.section--paper .btn--primary:hover { background: var(--gk-charcoal); }

.section--light .btn--ghost,
.section--paper .btn--ghost {
  border-color: rgba(0, 0, 0, 0.25);
  color: var(--gk-charcoal);
}
.section--light .btn--ghost:hover { border-color: var(--gk-black); background: rgba(0,0,0,0.04); }

/* --------------------------------------------------------------------------
   LA BIBLIOTHEQUE : UNE CONSTELLATION
   Les visuels flottent autour du texte au lieu de defiler en bandeau. Chacun
   derive a son propre pas quand la page bouge, et change d'image de temps en
   temps, au hasard : on ne regarde pas une selection arretee, on regarde une
   bibliotheque qui respire. Le texte garde le centre, rien ne passe dessus.
   -------------------------------------------------------------------------- */
.bibliotheque {
  position: relative;
  display: grid;
  place-items: center;
  /* Assez haute pour la derive, assez courte pour qu'une bonne dizaine de
     cadres entourent le texte au meme moment. */
  min-height: 132svh;
  /* Les cadres debordent des deux bords : on les coupe sans faire du bloc un
     conteneur de defilement. */
  overflow-x: clip;
}

.galaxie {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.galaxie__vue {
  position: absolute;
  left: var(--x);
  top: var(--y);
  width: var(--w);
  display: block;
  /* La derive suit le defilement : --defile va de -1 a 1, --amp donne a
     chaque cadre son amplitude, donc son eloignement apparent. Amplitude et
     largeur se comptent en svh, comme la hauteur de la section : la geometrie
     verticale ne depend alors plus du format de l'ecran, et deux cadres qui
     ne se touchent pas ici ne se toucheront nulle part. */
  transform: translate3d(0, calc(var(--defile, 0) * var(--amp, 5) * -1svh), 0);
}
.galaxie__vue--portrait { aspect-ratio: 3 / 4; }
.galaxie__vue--paysage  { aspect-ratio: 3 / 2; }

.galaxie__couche {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  /* Le fondu reste doux, mais court : les images se relaient sans cesse, un
     enchainement lent aurait fait bouillie. */
  transition: opacity 800ms var(--ease);
}
.galaxie__couche.est-vue { opacity: 1; }

.bibliotheque__mot {
  position: relative;
  z-index: 2;
  max-width: 48ch;
  text-align: center;
  padding-block: var(--space-2xl);
}
.bibliotheque__mot .lead,
.bibliotheque__mot .caption { margin-inline: auto; }
.bibliotheque__mot .lead { max-width: 46ch; }

@media (max-width: 900px) {
  /* Dix cadres autour d'une colonne etroite, c'est un fouillis : on n'en
     garde que quatre, aux quatre coins, et plus grands. */
  .bibliotheque { min-height: 0; }
  .galaxie__vue { display: none; }
  .galaxie__vue:nth-child(2),
  .galaxie__vue:nth-child(5),
  .galaxie__vue:nth-child(10),
  .galaxie__vue:nth-child(12) { display: block; width: 32vw; }
  .bibliotheque__mot { padding-block: calc(var(--space-2xl) * 1.6); }
}

@media (prefers-reduced-motion: reduce) {
  .galaxie__vue { transform: none; }
  .galaxie__couche { transition: none; }
}

/* --------------------------------------------------------------------------
   LES SERVICES, EN CARTES
   Quatre prestations que rien n'illustrait : quatre titres et quatre
   paragraphes dans le noir. Une image dit en un regard ce qu'une prestation
   recouvre, la ou trois lignes de texte demandent qu'on les lise.
   -------------------------------------------------------------------------- */
.cartes-services {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--space-sm);
}

.cartes-services--duo { grid-template-columns: repeat(2, 1fr); }
@media (max-width: 760px) { .cartes-services--duo { grid-template-columns: 1fr; } }

.carte-service {
  display: flex;
  flex-direction: column;
  border: 1px solid rgba(255, 255, 255, 0.14);
  background: var(--gk-black);
}
/* Quand la carte entiere est cliquable, elle ne doit rien prendre du style
   des liens : c'est un bloc, pas un mot souligne. */
a.carte-service {
  color: inherit;
  text-decoration: none;
  transition: border-color var(--dur-fast) var(--ease);
}
.section--light a.carte-service:hover { border-color: rgba(0, 0, 0, 0.4); }
.carte-service__label {
  font-family: var(--font-sans-ext);
  font-size: var(--fs-eyebrow);
  text-transform: uppercase;
  letter-spacing: 0.18em;
  color: var(--muted);
}
.carte-service__txt {
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  line-height: 1.6;
  color: var(--gk-mid-gray);
}
.carte-service__lien {
  display: inline-flex;
  align-items: baseline;
  gap: 0.45rem;
  margin-top: 0.4rem;
  font-family: var(--font-sans-ext);
  font-size: var(--fs-eyebrow);
  text-transform: uppercase;
  letter-spacing: 0.18em;
  color: var(--gk-black);
}
.carte-service__lien i {
  font-style: normal;
  transition: transform var(--dur-fast) var(--ease);
}
a.carte-service:hover .carte-service__lien i { transform: translateX(3px); }
.section--light .carte-service,
.section--paper .carte-service {
  border-color: rgba(0, 0, 0, 0.14);
  background: transparent;
}

.carte-service__vue {
  display: block;
  aspect-ratio: 16 / 10;
  overflow: hidden;
  background: var(--gk-near-black);
}
.carte-service__vue img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* Rendu produit detoure sur blanc : contenu, jamais rogne, sinon la tablette
   sort du cadrage. */
.carte-service__vue--clair { background: var(--gk-white); }
.carte-service__vue--clair img { object-fit: contain; }

.carte-service__corps {
  padding: var(--space-sm);
  display: grid;
  gap: 0.6rem;
}
.carte-service__nom {
  font-family: var(--font-serif);
  font-size: 1.25rem;
  line-height: 1.15;
  letter-spacing: -0.015em;
  color: var(--gk-white);
}
.section--light .carte-service__nom,
.section--paper .carte-service__nom { color: var(--gk-black); }
.carte-service__note {
  font-size: 0.8125rem;
  line-height: 1.6;
  color: var(--gk-mid-gray);
}
.section--light .carte-service__note,
.section--paper .carte-service__note { color: var(--muted); }

@media (max-width: 1000px) { .cartes-services { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 600px) {
  .cartes-services { grid-template-columns: 1fr; gap: var(--space-xs); }
}

/* L'application sous le chapeau : large, posee, elle ouvre la page sur
   l'objet dont il va etre question. */
/* La porte vers les tarifs : centree et ample. Elle ne montre rien, elle
   annonce ; il lui faut donc de la place pour peser, sans quoi elle se lit
   comme une note de bas de page. */
.porte-tarifs {
  display: grid;
  place-items: center;
  min-height: 82svh;
}
.porte-tarifs .wrap { max-width: 54ch; }
.porte-tarifs .lead { max-width: 48ch; }

/* --------------------------------------------------------------------------
   LE SIMULATEUR DE SCENARIO
   Trois axes, quatre choix chacun. Le propos a gauche, le cadre au centre,
   les commandes a droite, la regle sous les trois. Tout dans un ecran.

   Le visuel est pose dans un vrai cadre Ginko, a l'emplacement exact de la
   toile mesure sur l'image : 6,124 % depuis la gauche, 4,922 % depuis le
   haut, 87,66 % de large, 90,262 % de haut.
   -------------------------------------------------------------------------- */
/* ---- le rafraichissement de dalle ---------------------------------------
   Le refresh d'une dalle electrophoretique monochrome, 1750 ms.

   Rien ici n'est un fondu croise, et rien n'est un aplat : les deux images
   gardent leur opacite du debut a la fin, et la nouvelle est composee sur
   l'ancienne en mode difference. C'est le mecanisme physique lui-meme :
   |A - B| vaut zero la ou les deux images s'accordent et un la ou le pigment
   doit se retourner. La couche du dessus dessine donc exactement la carte des
   pixels qui changent d'etat, avec des bords durs et aucune transparence.

   Trois impulsions optiques, comme sur la dalle :

     A stable  ->  SOMBRE : A ecrasee, B affleure a 10 %, solarisation locale
     ->  CLAIR : polarite inversee, |A - B| en negatif, les deux images
         coexistent dans le meme espace, contours nets
     ->  SOMBRE : la polarite revient, la geometrie bascule sur B, fantome de A
     ->  release : B remonte, le fantome s'eteint, contraste stabilise

   Deux proprietes portent tout : la luminosite de chaque couche, et la
   polarite de la toile. La couche A finit a brightness(0) -- une difference
   sur du noir rend la source intacte, la sortie d'animation est donc B, sans
   raccord. Aucun flou, aucun grain, aucun deplacement, jamais de noir ni de
   blanc uniforme : une information demeure a chaque milliseconde.
   -------------------------------------------------------------------------- */
/* --- la polarite de la dalle : elle bascule net, jamais en fondu ---------
   Un invert progressif passerait par un gris uniforme a mi-course, c'est-a-dire
   par la perte totale de l'information. Il bascule donc d'un pas. */
@keyframes gk-eink-pol {
  0%              { filter: none; }
  24.571%         { filter: invert(1); }   /* 430 ms : impulsion claire */
  43.429%         { filter: none; }        /* 760 ms : retour de polarite */
  100%            { filter: none; }
}

/* --- A : ecrasee, relevee, puis reduite a un fantome qui s'eteint -------- */
@keyframes gk-eink-a {
  /* 0 -> 180 ms : stable, aucun mouvement */
  0%, 10.286%     { filter: grayscale(1) brightness(1) contrast(1);
                    animation-timing-function: cubic-bezier(0.4, 0, 0.8, 1); }
  /* 300 ms : compensation sombre. Les blancs de A tombent au gris fonce,
     ses noirs restent noirs : la geometrie de A est intacte. */
  17.143%         { filter: grayscale(1) brightness(0.28) contrast(1.1); }
  /* maintien 130 ms */
  24.571%         { filter: grayscale(1) brightness(0.28) contrast(1.1);
                    animation-timing-function: cubic-bezier(0.4, 0, 0.8, 1); }
  /* 570 ms : A revient a pleine valeur sous polarite inversee */
  32.571%         { filter: grayscale(1) brightness(1) contrast(1); }
  /* maintien 190 ms : le composite clair */
  43.429%         { filter: grayscale(1) brightness(1) contrast(1);
                    animation-timing-function: cubic-bezier(0.4, 0, 0.8, 1); }
  /* 900 ms : A n'est plus qu'un fantome de 12 % sous B */
  51.429%         { filter: grayscale(1) brightness(0.12) contrast(1); }
  62.857%         { filter: grayscale(1) brightness(0.12) contrast(1);
                    animation-timing-function: cubic-bezier(0.2, 0.8, 0.2, 1); }
  /* 1170 / 1250 / 1320 ms : 6 %, 2 %, puis plus rien */
  66.857%         { filter: grayscale(1) brightness(0.06) contrast(1); }
  71.429%         { filter: grayscale(1) brightness(0.02) contrast(1); }
  75.429%, 100%   { filter: grayscale(1) brightness(0) contrast(1); }
}

/* --- B : absente, affleurante, pleine, sombre, puis stabilisee ----------
   A brightness(0) elle ne modifie rien : une difference avec du noir rend
   le fond tel quel. C'est ainsi qu'elle n'existe pas encore, sans recourir
   a l'opacite. */
@keyframes gk-eink-b {
  0%, 10.286%     { filter: grayscale(1) brightness(0) contrast(1);
                    animation-timing-function: cubic-bezier(0.4, 0, 0.8, 1); }
  /* 300 ms : 10 % de B suffisent a retourner localement les pixels de A */
  17.143%         { filter: grayscale(1) brightness(0.1) contrast(1); }
  24.571%         { filter: grayscale(1) brightness(0.1) contrast(1);
                    animation-timing-function: cubic-bezier(0.4, 0, 0.8, 1); }
  /* 570 ms : carte complete des pixels qui changent d'etat */
  32.571%         { filter: grayscale(1) brightness(1) contrast(1); }
  43.429%         { filter: grayscale(1) brightness(1) contrast(1);
                    animation-timing-function: cubic-bezier(0.4, 0, 0.8, 1); }
  /* 900 ms : B domine la geometrie, mais sous-exposee */
  51.429%         { filter: grayscale(1) brightness(0.38) contrast(1.05); }
  62.857%         { filter: grayscale(1) brightness(0.38) contrast(1.05);
                    animation-timing-function: cubic-bezier(0.2, 0.8, 0.2, 1); }
  /* 1320 ms : B propre, encore un point de contraste sous la normale */
  75.429%         { filter: grayscale(0) brightness(1) contrast(0.94); }
  /* 1500 -> 1750 ms : stabilisee, puis plus aucun mouvement */
  85.714%, 100%   { filter: grayscale(0) brightness(1) contrast(1); }
}

/* --------------------------------------------------------------------------
   LE CONFIGURATEUR STUDIO

   Un seul choix, l'espace ; puis la journee de ce mur, quatre moments poses
   sur une frise. On ne compose plus une image, on regarde un lieu vivre : le
   contenu change, il change a des heures ecrites d'avance, et sa nature varie
   selon l'heure. Trois choses comprises en une interaction.

   Deux colonnes, 55 / 45. A gauche le cadre et rien d'autre que ce qui le
   commente : la frise, puis la legende. A droite le propos et les commandes,
   fer a gauche, cales en haut du cadre -- l'asymetrie verticale est voulue.
   Aucune masse noire : la section ne doit peser que par son cadre.
   -------------------------------------------------------------------------- */
.configurateur {
  display: grid;
  place-items: center;
  min-height: 100svh;
  padding-block: var(--space-lg);
}
.confi {
  display: grid;
  /* Deux colonnes cadrees, centrees ensemble plutot qu'etalees sur toute la
     largeur : en 55/45 le cadre flottait au milieu d'un vide a gauche et le
     texte allait mourir contre le bord droit de la fenetre. */
  grid-template-columns: minmax(0, 26rem) minmax(0, 28rem);
  grid-template-areas: "centre cote";
  justify-content: center;
  align-items: center;
  gap: var(--space-xl);
}
/* Le configurateur tient en un seul bloc : ainsi il se centre sur le cadre
   au lieu de se coller en haut, rangee par rangee. */
.confi__cote {
  grid-area: cote;
  display: grid;
  align-content: center;
  justify-items: start;
  gap: var(--space-lg);
}
.confi__propos {
  display: grid;
  justify-items: start;
  gap: var(--space-sm);
  text-align: left;
}
.confi__propos .eyebrow,
.confi__propos h2,
.confi__propos .lead { margin: 0; }

.confi__centre { grid-area: centre; display: grid; justify-items: center; }
.confi__commandes {
  display: grid;
  justify-items: stretch;
  gap: var(--space-md);
  width: 100%;
}

/* ---- le cadre : la meme baguette que partout ailleurs --------------------
   La largeur est aussi bornee par la hauteur d'ecran : le cadre est haut,
   sans quoi la section deborderait sur les portables a ecran bas. */
.confi__cadre {
  margin: 0;
  width: min(100%, 46svh);
  display: grid;
}
.confi__objet { position: relative; display: block; }
.confi__baguette {
  display: block;
  width: 100%;
  height: auto;
  position: relative;
  z-index: 1;
  pointer-events: none;
}
.confi__toile {
  position: absolute;
  left: 6.124%;
  top: 4.922%;
  width: 87.66%;
  height: 90.262%;
  overflow: hidden;
  background: #f2f1ec;
  z-index: 2;
  /* Le mode difference ne doit composer qu'avec l'autre couche. */
  isolation: isolate;
}
.confi__vue {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
}
.confi__vue.est-vue { opacity: 1; }

/* ---- le rafraichissement de dalle ---------------------------------------
   La waveform decrite plus haut, appliquee aux couches du configurateur.
   -------------------------------------------------------------------------- */
.confi__toile.rafraichit .confi__vue--sort,
.confi__toile.rafraichit .confi__vue--entre { opacity: 1; }
.confi__toile.rafraichit .confi__vue--sort  { z-index: 1; }
.confi__toile.rafraichit .confi__vue--entre { z-index: 2; mix-blend-mode: difference; }

.confi__toile.rafraichit                     { animation: gk-eink-pol 1750ms step-end forwards; }
.confi__toile.rafraichit .confi__vue--sort   { animation: gk-eink-a 1750ms linear forwards; }
.confi__toile.rafraichit .confi__vue--entre  { animation: gk-eink-b 1750ms linear forwards; }

/* L'heure en incrustation : elle ne sert qu'en mobile, ou la frise disparait. */
.confi__horaire {
  display: none;
  position: absolute;
  left: 10%;
  bottom: 9%;
  z-index: 3;
  padding: 0.4em 0.75em;
  font-family: var(--font-sans-ext);
  font-size: 0.625rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--gk-white);
  background: rgba(23, 24, 27, 0.72);
}

/* ---- la frise horaire, sous le cadre et a sa largeur ---------------------
   Pas de pastilles vides : une ligne, et le seul palier atteint porte un
   point plein. Le reste se lit dans les heures.
   -------------------------------------------------------------------------- */
.confi__temps { width: 100%; }
/* Le rang atteint sur la frise, de 0 a 1. Declare : sans cela il change d'un
   coup, et il fallait animer separement la largeur du trait et la position du
   curseur -- deux transitions jumelles qui se desynchronisaient, le trait
   trainant derriere la bille. Une seule valeur interpolee, et les deux se
   recalculent ensemble a chaque image. */
@property --pos {
  syntax: "<number>";
  inherits: true;
  initial-value: 0;
}

.confi__frise {
  position: relative;
  min-height: 2.8rem;
}
.confi__frise[hidden] { display: none; }

/* La ligne est pointillee tant que l'heure n'est pas passee, pleine derriere
   le curseur : la journee se remplit a mesure qu'elle se consomme. */
.confi__frise::before,
.confi__frise::after {
  content: "";
  position: absolute;
  left: 4.5px;
  top: calc(0.35rem + 4px);
  height: 1px;
}
.confi__frise::before {
  right: 4.5px;
  background-image: repeating-linear-gradient(to right,
    var(--gk-mid-gray) 0 3px, transparent 3px 8px);
}
.confi__frise::after {
  width: calc(var(--pos, 0) * (100% - 9px));
  background: var(--gk-charcoal);
}
.confi__frise.glisse { transition: --pos var(--glisse, 4000ms) linear; }

/* Les paliers sont poses a la main sur la ligne : en colonnes egales, le
   premier point tombait a 12,5 % et la frise ne s'alignait pas sur le texte
   au-dessus. Le premier est desormais a fleur de bord, le dernier a l'autre. */
.confi__palier {
  position: absolute;
  top: 0;
  /* Meme calcul que le curseur, au pixel pres : reparti en pourcentages purs,
     le point du milieu tombait a 1,5 px du passage de la bille et laissait un
     croissant. */
  left: calc(4.5px + var(--i, 0) * (100% - 9px) / 3);
  transform: translateX(-50%);
  display: grid;
  justify-items: center;
  gap: 0.7rem;
  padding: 0.35rem 0 0;
  border: 0;
  background: none;
  cursor: pointer;
  font-family: var(--font-sans);
  font-size: 0.6875rem;
  white-space: nowrap;
  color: var(--gk-warm-gray);
  transition: color 300ms var(--ease);
}
.confi__palier:first-of-type { left: 0; transform: none; justify-items: start; }
.confi__palier:last-of-type  { left: 100%; transform: translateX(-100%); justify-items: end; }
.confi__palier:hover { color: var(--gk-charcoal); }
.confi__point {
  position: relative;
  z-index: 1;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  border: 1px solid var(--gk-mid-gray);
  background: var(--gk-off-white);
  transition: border-color 300ms var(--ease);
}
.confi__palier[aria-selected="true"] { color: var(--gk-charcoal); }
.confi__palier.est-passe .confi__point {
  background: var(--gk-charcoal);
  border-color: var(--gk-charcoal);
}

/* Le curseur : la seule marque pleine de la frise. Il glisse d'un palier au
   suivant pendant les quatre secondes du moment, et le cadre change quand il
   arrive. On voit donc le temps passer, au lieu de le subir. */
.confi__curseur {
  position: absolute;
  z-index: 2;
  top: calc(0.35rem + 4px);
  left: calc(4.5px + var(--pos, 0) * (100% - 9px));
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--gk-charcoal);
  transform: translate(-50%, -50%);
  pointer-events: none;
}


/* ---- la legende : le tag en prefixe, sur la meme ligne -------------------
   Un bloc de tag autonome faisait une troisieme masse sous le cadre pour
   deux mots. Il est desormais l'amorce de la phrase.
   -------------------------------------------------------------------------- */
.confi__dits {
  display: grid;
  width: 100%;
  margin-top: 1.5rem;
  min-height: 4.6rem;
}
.confi__dit {
  grid-area: 1 / 1;
  margin: 0;
  text-align: center;
  opacity: 0;
  transition: opacity 220ms var(--ease);
}
.confi__dit.est-vue { opacity: 1; }
/* L'usage se lit d'abord, la scene ensuite : colles sur une meme ligne, les
   deux se mangeaient. */
.confi__tag {
  display: block;
  font-family: var(--font-sans-ext);
  font-size: 0.625rem;
  text-transform: uppercase;
  letter-spacing: 0.18em;
  color: var(--gk-warm-gray);
}
.confi__legende {
  display: block;
  margin: 0.65rem auto 0;
  max-width: 40ch;
  font-family: var(--font-serif);
  font-size: 1.0625rem;
  line-height: 1.55;
  color: var(--gk-charcoal);
}

/* ---- le selecteur d'espace et le deroule ---------------------------------
   Une liste verticale : cinq lieux se lisent, ils ne se parcourent pas. */
.confi__bloc { display: grid; gap: 0.85rem; justify-items: start; }
.confi__label {
  font-family: var(--font-sans-ext);
  font-size: var(--fs-eyebrow);
  text-transform: uppercase;
  letter-spacing: 0.2em;
  color: var(--muted);
}
/* Les six lieux tiennent sur une ligne : au-dela, la colonne devient un
   menu et le sixieme se retrouve seul en dessous. */
.confi__espaces { display: flex; flex-wrap: wrap; gap: 0.6rem 1.15rem; }
.confi__espace {
  position: relative;
  padding: 0;
  border: 0;
  background: none;
  /* Meme fonte et meme corps que les heures de la frise : ce sont deux
     rangees de la meme nature, elles doivent se lire du meme oeil. */
  font-family: var(--font-sans);
  font-size: 0.6875rem;
  white-space: nowrap;
  color: var(--gk-mid-gray);
  cursor: pointer;
  transition: color 300ms var(--ease);
}
.confi__espace:hover { color: var(--gk-warm-gray); }
.confi__espace[aria-selected="true"] { color: var(--gk-charcoal); }
/* Un trait de la largeur du mot, six pixels dessous. Pas d'aplat : le noir
   plein d'une pastille serait la masse la plus lourde de la page. */
.confi__espace[aria-selected="true"]::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -6px;
  height: 1px;
  background: currentColor;
}

.confi__espace:focus-visible,
.confi__palier:focus-visible {
  outline: 1px solid var(--gk-charcoal);
  outline-offset: 3px;
}

/* ---- tablette et mobile : une colonne, le cadre en tete de lecture ------- */
@media (max-width: 1023px) {
  .confi {
    grid-template-columns: 1fr;
    grid-template-areas: "cote" "centre";
    gap: var(--space-lg);
    justify-items: center;
  }
  .configurateur { min-height: 0; }
  .confi__propos { max-width: 40rem; width: 100%; }
  .confi__cote { align-content: start; }
  .confi__cadre { width: min(82vw, 24rem); }
  .confi__cote { width: min(82vw, 24rem); justify-items: start; }
}

@media (max-width: 767px) {
  .confi__horaire { display: block; }
  .confi__heure { font-size: 0.625rem; }
}

@media (prefers-reduced-motion: reduce) {
  .confi__toile.rafraichit,
  .confi__toile.rafraichit .confi__vue--sort,
  .confi__toile.rafraichit .confi__vue--entre { animation: none; }
  .confi__dit,
  .confi__frise.glisse { transition: none; }
}

/* --------------------------------------------------------------------------
   LES LICENCES STUDIO
   Trois colonnes, pas trois cartes. Chacune dit d'abord par quelle porte on y
   entre, puis son nom, son montant, et ce qu'elle ajoute. Le detail vit sur la
   page tarifs : ici on montre qu'une licence accompagne deja chaque display.
   Meme hierarchie que la page tarifs : mention en capitales, nom en fonte de
   texte, montant en serif. Les deux pages parlent la meme langue.
   -------------------------------------------------------------------------- */
.licences {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-md);
}
.licences > li {
  display: grid;
  align-content: start;
  gap: 0.55rem;
  border-top: 1px solid rgba(0, 0, 0, 0.16);
  padding-top: 1.3rem;
}
.section--dark .licences > li { border-top-color: rgba(255, 255, 255, 0.18); }

.licence__badge {
  font-family: var(--font-sans-ext);
  font-weight: 400;
  font-size: var(--fs-eyebrow);
  text-transform: uppercase;
  letter-spacing: 0.2em;
  line-height: 1.5;
  color: var(--muted);
}
.licence__nom {
  font-family: var(--font-sans);
  font-size: 1.0625rem;
  font-weight: 500;
  line-height: 1.2;
  letter-spacing: 0.02em;
  margin-top: 0.35rem;
}
.licence__prix {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0 0.5rem;
  margin-top: 0.1rem;
}
.licence__montant {
  font-family: var(--font-serif);
  font-size: clamp(2rem, 2.8vw, 2.6rem);
  line-height: 1;
  letter-spacing: -0.02em;
}
.licence__unite {
  font-family: var(--font-sans);
  font-size: 0.8125rem;
  line-height: 1.4;
  color: var(--muted);
}
.licence__note {
  font-size: 0.8125rem;
  line-height: 1.65;
  color: var(--muted);
  margin-top: 0.6rem;
  max-width: 26ch;
}

@media (max-width: 900px) {
  .licences { grid-template-columns: 1fr; gap: var(--space-sm); }
  .licence__note { max-width: none; }
}

/* --------------------------------------------------------------------------
   LA SCENE STUDIO
   L'application entre de face, en grand, puis recule sur la droite en trois
   quarts pour devenir la demonstration qu'on regarde en lisant le parcours.
   Un seul element du debut a la fin : deux images, meme identiques, se
   liraient comme une coupure.
   -------------------------------------------------------------------------- */
.studio-scene {
  position: relative;
  background: var(--gk-black);
  /* L'application deborde a droite en fin de course : on la coupe sans faire
     de la scene un conteneur de defilement, ce qui decrocherait les sticky.
     Sur les deux axes : au rechargement en cours de page, elle debordait par
     le bas sur la section suivante. */
  overflow: clip;
}

.app-vol {
  position: sticky;
  top: 0;
  height: 100svh;
  display: grid;
  place-items: center;
  z-index: 5;
  pointer-events: none;
}

.app-vol__scene {
  /* Les cinq ecrans se rangent dans la meme case de grille : ils se
     superposent sans sortir du flux. En positionnement absolu a l'interieur
     de la transformation en perspective, ils ne s'affichaient plus du tout. */
  display: grid;
  width: min(1080px, 88vw);
  /* Le voyage : translation, echelle, puis bascule en perspective. L'ordre
     compte, perspective() ne s'applique qu'a ce qui la suit. */
  transform:
    translate3d(var(--vx, 0px), var(--vy, 0px), 0)
    scale(var(--vs, 1))
    perspective(1600px)
    rotateY(var(--vry, 0deg))
    rotateX(var(--vrx, 0deg));
  transform-origin: center;
  will-change: transform;
}

/* Les cinq ecrans se superposent, un seul se voit. Le fondu est lent : c'est
   l'application qui change d'etat, pas une diapositive qui claque. */
.app-vol__ecran {
  grid-area: 1 / 1;
  display: block;
  width: 100%;
  height: auto;
  opacity: 0;
  transition: opacity 700ms var(--ease);
}
.app-vol__ecran.est-vu { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  .app-vol__ecran { transition: none; }
}

@media (max-width: 900px) {
  /* Pas de voyage sur telephone : l'application se pose une fois, de face,
     sous le chapeau, et le parcours se lit ensuite. */
  .app-vol {
    position: static;
    height: auto;
    padding-block: var(--space-xl);
  }
  .app-vol__scene { width: 92vw; transform: none; }
  /* L'image ne suit plus les chapitres : seul l'ecran par defaut reste. */
  .app-vol__ecran:not(.est-vu) { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .app-vol__scene { transform: none; }
}

/* --------------------------------------------------------------------------
   LE PARCOURS STUDIO
   Quatre chapitres qui se suivent, simplement. Celui qu'on traverse s'allume,
   les autres reculent d'un cran : c'est la lecture qui avance, pas un
   dispositif. L'application reste epinglee a cote, du debut a la fin.
   -------------------------------------------------------------------------- */
.parcours {
  --parcours-retrait: 4.5rem;
}

.parcours__grille {
  display: grid;
  grid-template-columns: minmax(0, 6fr) minmax(0, 5fr);
  gap: var(--space-xl);
  align-items: start;
}

/* La case ou l'application se tient : vide, elle ne fait que reserver la
   colonne de droite. */
.parcours__media {
  position: sticky;
  top: calc(var(--space-lg) + 3rem);
  aspect-ratio: 2061 / 1487;
}

.parcours__etapes {
  list-style: none;
  margin: 0;
  padding: 0;
}

/* Chaque chapitre se donne les trois quarts d'un ecran. Le texte reste en
   haut, sous son filet ; l'air qui suit est du temps de defilement, celui
   qu'il faut pour que l'image d'a cote change avant le chapitre suivant. */
.parcours__etape {
  border-top: 1px solid rgba(255, 255, 255, 0.14);
  padding: var(--space-lg) 0;
  min-height: 78svh;
}
/* Le retrait n'apparait que si le script a pris la main : sans lui, les
   quatre chapitres se lisent tous, pleinement. */
.parcours__etapes[data-anime] .parcours__etape {
  opacity: 0.34;
  transition: opacity 760ms var(--ease);
}
.parcours__etapes[data-anime] .parcours__etape.est-lue { opacity: 1; }

.parcours__tete {
  display: grid;
  grid-template-columns: var(--parcours-retrait) minmax(0, 1fr);
  align-items: baseline;
}

/* Numerotation entre crochets, comme partout ailleurs sur le site. */
.parcours__num {
  font-family: var(--font-sans-ext);
  font-size: 0.5625rem;
  font-weight: 500;
  letter-spacing: 0;
  line-height: 1;
  color: rgba(255, 255, 255, 0.35);
}
/* Le titre est un reperage, pas une phrase : capitales et interlettrage, le
   registre des intertitres. C'est le texte en dessous qui parle. */
.parcours__tete h3 {
  font-family: var(--font-sans-ext);
  font-size: var(--fs-eyebrow);
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--gk-white);
  margin: 0;
}

.parcours__corps {
  padding: var(--space-md) 0 0 var(--parcours-retrait);
  max-width: 48ch;
}
.parcours__corps p {
  color: var(--gk-mid-gray);
  font-size: var(--fs-body);
  line-height: 1.8;
}

@media (max-width: 900px) {
  /* Plus de place pour epingler quoi que ce soit : la surface passe devant,
     les quatre chapitres se lisent ensuite, d'un trait. */
  .parcours__grille { grid-template-columns: 1fr; gap: var(--space-lg); }
  .parcours__media { display: none; }
  /* Sur telephone l'image ne suit pas : l'air entre les chapitres n'aurait
     plus d'objet, ils se lisent d'un trait. */
  .parcours__etape { padding: var(--space-md) 0; min-height: 0; }
  .parcours__etapes[data-anime] .parcours__etape { opacity: 1; }
  .parcours__corps { padding: var(--space-sm) 0 0 var(--parcours-retrait); }
}

@media (prefers-reduced-motion: reduce) {
  .parcours__etapes[data-anime] .parcours__etape { opacity: 1; transition: none; }
}

/* --------------------------------------------------------------------------
   7. HEADER
   -------------------------------------------------------------------------- */
.site-header {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 100;
  isolation: isolate;
  padding-block: 1.5rem;
  transition: background var(--dur-fast) var(--ease),
              padding var(--dur-fast) var(--ease),
              border-color var(--dur-fast) var(--ease);
  border-bottom: 1px solid transparent;
}
.site-header.is-scrolled {
  background: rgba(0, 0, 0, 0.82);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  padding-block: 1rem;
  border-bottom-color: rgba(255, 255, 255, 0.08);
}

.site-header__inner {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: var(--space-sm);
}

.nav {
  display: flex;
  align-items: center;
  gap: var(--space-md);
}

/* Restreint a .nav__link : appliquee a tous les liens du menu, cette regle
   imposait capitales et interlettrage aux descriptions du panneau. */
.nav > .nav__item > .nav__link {
  color: var(--gk-white);
  opacity: 0.7;
  transition: opacity var(--dur-fast) var(--ease);
}
/* Le survol doit se dire ici aussi : plus specifique que .nav__link:hover,
   cette regle l'emportait et gardait a 0.7 les entrees sans panneau. Les
   autres s'allumaient par .is-open, que le script ne leur donne jamais :
   Tarifs restait donc grise sous le curseur. */
/* Le survol seulement : la page courante ne reste pas allumee, une entree
   grise sous le curseur et blanche au repos se lirait comme un etat fige. */
.nav > .nav__item > .nav__link:hover,
.nav > .nav__item > .nav__link:focus-visible { opacity: 1; }

.brand {
  display: flex;
  align-items: center;
  justify-self: center;
}
.brand img { height: 19px; width: auto; }

/* En-tete posee sur une page qui s'ouvre en clair : ecrite en blanc elle
   serait invisible. Tout passe au noir tant que la barre reste transparente,
   c'est a dire tant qu'on n'a pas defile et qu'aucun panneau n'est ouvert :
   dans ces deux cas la barre redevient noire et reprend son texte blanc. */
.site-header--sur-clair:not(.is-scrolled):not(:has(.nav__item--has-menu.is-open)) {
  color: var(--gk-black);
}
.site-header--sur-clair:not(.is-scrolled):not(:has(.nav__item--has-menu.is-open)) .brand img {
  filter: invert(1);
}
.site-header--sur-clair:not(.is-scrolled):not(:has(.nav__item--has-menu.is-open)) .nav__link,
.site-header--sur-clair:not(.is-scrolled):not(:has(.nav__item--has-menu.is-open)) .nav__social,
.site-header--sur-clair:not(.is-scrolled):not(:has(.nav__item--has-menu.is-open)) .prefs__label,
.site-header--sur-clair:not(.is-scrolled):not(:has(.nav__item--has-menu.is-open)) .lang-switch {
  color: var(--gk-black);
}
.site-header--sur-clair:not(.is-scrolled):not(:has(.nav__item--has-menu.is-open)) .nav__cta {
  background: var(--gk-black);
  color: var(--gk-white);
}
.site-header--sur-clair:not(.is-scrolled):not(:has(.nav__item--has-menu.is-open)) .nav__cta:hover {
  background: var(--gk-charcoal);
}
.site-header--sur-clair:not(.is-scrolled):not(:has(.nav__item--has-menu.is-open)) .burger span {
  background: var(--gk-black);
}

/* Le CTA vit hors du bloc .nav : il porte donc sa propre typographie. */
.nav__cta {
  display: inline-flex;
  align-items: center;
  font-family: var(--font-sans-ext);
  font-size: var(--fs-eyebrow);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.2em;
  padding: 1em 1.9em;
  background: var(--gk-white);
  color: var(--gk-black);
  transition: background var(--dur-fast) var(--ease);
}
.nav__cta:hover { background: var(--gk-paper); }

.nav__social svg { width: 16px; height: 16px; fill: currentColor; }

/* Burger */
.burger {
  display: none;
  width: 40px;
  height: 40px;
  position: relative;
  justify-self: end;
}
.burger span {
  position: absolute;
  left: 9px;
  width: 22px;
  height: 1px;
  background: var(--gk-white);
  transition: transform var(--dur-fast) var(--ease), opacity 200ms;
}
.burger span:nth-child(1) { top: 17px; }
.burger span:nth-child(2) { top: 23px; }
.burger.is-open span:nth-child(1) { transform: translateY(3px) rotate(45deg); }
.burger.is-open span:nth-child(2) { transform: translateY(-3px) rotate(-45deg); }

@media (max-width: 1000px) {
  .site-header__inner { grid-template-columns: auto 1fr; }
  .brand { justify-self: start; order: -1; }
  .burger { display: block; }
}

/* Menu mobile
   Il s'ouvre sous la barre, qui reste visible avec son logo et sa croix.
   Les rubriques sont repliees : la liste tient dans l'ecran sans defiler,
   et l'on distingue enfin une rubrique de ses pages. */
.mobile-nav {
  position: fixed;
  inset: 0;
  z-index: 99;
  background: var(--gk-black);
  display: flex;
  flex-direction: column;
  padding: calc(var(--space-xl) + 3rem) var(--gutter) var(--space-md);
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--dur-fast) var(--ease), visibility var(--dur-fast);
}
.mobile-nav.is-open { opacity: 1; visibility: visible; }

/* --------------------------------------------------------------------------
   8. HERO
   -------------------------------------------------------------------------- */
.hero {
  position: relative;
  min-height: 100svh;
  display: flex;
  align-items: flex-end;
  overflow: hidden;
  background: var(--gk-black);
}

.hero__media {
  position: absolute;
  inset: 0;
  z-index: 0;
  background: var(--gk-black);
}
.hero__media img,
.hero__media video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* La vidéo alterne des plans très clairs et très sombres.
   Deux couches : un voile uniforme discret pour tenir les plans blancs,
   puis un dégradé bas appuyé sous lequel le texte reste toujours lisible. */
.hero__media::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background: rgba(0, 0, 0, 0.3);
}
/* Le texte occupe les 40 % inférieurs : le dégradé s'assombrit à partir de 28 %
   pour que le titre repose toujours sur un fond sombre, quel que soit le plan. */
.hero__media::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background:
    linear-gradient(to bottom,
      rgba(0,0,0,0.55) 0%,
      rgba(0,0,0,0.10) 16%,
      rgba(0,0,0,0.14) 28%,
      rgba(0,0,0,0.52) 48%,
      rgba(0,0,0,0.78) 72%,
      rgba(0,0,0,0.92) 100%);
}

/* Texte ancré en bas : la vidéo respire au-dessus,
   le texte repose sur la zone la plus sombre du dégradé. */
.hero__inner {
  position: relative;
  z-index: 2;
  width: 100%;
  padding-bottom: var(--space-xl);
  padding-top: var(--space-2xl);
}

/* ---- le hero des fiches d'espace ----------------------------------------
   Meme ouverture que l'accueil, mais le texte occupe les deux bouts : le
   titre en haut, le constat en bas. Le degrade doit donc appuyer aux deux
   extremites et laisser respirer le milieu de l'image.
   -------------------------------------------------------------------------- */
.hero--fiche { align-items: stretch; }
.hero--fiche .hero__media::after {
  background:
    linear-gradient(to bottom,
      rgba(0, 0, 0, 0.86) 0%,
      rgba(0, 0, 0, 0.48) 24%,
      rgba(0, 0, 0, 0.28) 44%,
      rgba(0, 0, 0, 0.58) 62%,
      rgba(0, 0, 0, 0.84) 78%,
      rgba(0, 0, 0, 0.94) 100%);
}
.hero--fiche .hero__inner {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: var(--space-xl);
  padding-top: var(--space-2xl);
  padding-bottom: var(--space-xl);
}
.hero--fiche .hero__title { max-width: 20ch; }
.hero--fiche .hero__bas h2 {
  font-size: var(--fs-h3, 1.6rem);
  margin-top: 0.6rem;
}
.hero--fiche .hero__bas .prose { color: rgba(255, 255, 255, 0.82); }
.hero--fiche .hero__bas .prose p { margin: 0; }

@media (max-width: 860px) {
  /* Sur un ecran etroit, le paragraphe complet ne tient plus sous le titre :
     le hero s'allonge plutot que de rogner le texte. */
  .hero--fiche { min-height: 0; }
  .hero--fiche .hero__inner {
    gap: var(--space-lg);
    padding-top: calc(var(--space-2xl) * 0.7);
  }
}

.hero__title { max-width: 17ch; }
/* Le chapo du hero descend au corps de texte : le titre porte seul. */
.hero__sub {
  margin-top: var(--space-sm);
  max-width: 54ch;
  font-size: var(--fs-body);
  line-height: 1.75;
  letter-spacing: 0;
}

/* Indicateur de scroll */
/* Décalé à droite : il n'entre plus en conflit avec le texte à gauche */

/* Hero secondaire (pages internes) */
.page-hero {
  padding-top: calc(var(--space-xl) + 5rem);
  padding-bottom: var(--space-xl);
  background: var(--gk-black);
  /* Tous les chapeaux de page se lisent sur un axe central : le titre, son
     intertitre et son chapo descendent ensemble. */
  text-align: center;
}
.page-hero .wrap > * { margin-inline: auto; }
/* Le chapô du hero peut respirer plus large que dans le corps de page :
   à 38ch il cassait sur un mot orphelin. */
.page-hero .lead { max-width: 52ch; }
.hero__sub { max-width: 46ch; }

/* Chapeau de page centre : quand l'introduction porte a elle seule tout ce
   qu'il y a a dire avant la comparaison. */
.page-hero--centre .wrap { max-width: 62ch; text-align: center; }
.page-hero--centre .lead { max-width: 52ch; margin: var(--space-md) auto 0; }

/* Chapeau aligne a gauche : quand ce qui suit n'est pas un discours mais une
   grille, le titre prend le meme bord que le tableau qu'il annonce. Centre,
   il flottait au-dessus d'une colonne alignee a gauche. */
.page-hero--gauche { text-align: left; }
.page-hero--gauche .wrap > * { margin-inline: 0; }
.page-hero--gauche .lead { margin-left: 0; margin-right: 0; }

/* Chapeau clair : l'introduction et ce qu'elle annonce partagent alors le
   meme fond, et la page s'ouvre d'un seul tenant au lieu de se couper en
   deux. Le bas n'a plus de marge : la suite enchaine. */
.page-hero--clair {
  background: var(--gk-white);
  color: var(--gk-charcoal);
  --muted: #68685f;
  --body-ink: var(--gk-charcoal);
  padding-bottom: var(--space-lg);
}
.page-hero--clair .eyebrow { color: var(--muted); }
.page-hero--clair h1 { color: var(--gk-black); }
.page-hero--clair .lead { color: var(--muted); }

/* La suite immediate : pas de padding haut, le bloc de texte fait office
   d'en-tete de section. */
.section--formats { padding-top: 0; padding-bottom: var(--space-2xl); }

/* Chapeau noir suivi d'une section noire : rien ne separe les deux fonds, et
   leurs deux marges s'additionnaient en un long vide. Le chapeau et ce qu'il
   annonce se lisent d'un trait : une seule respiration entre les deux. */
.page-hero:has(+ .section--dark) { padding-bottom: var(--space-lg); }
.page-hero + .section--dark { padding-top: var(--space-md); }

/* --------------------------------------------------------------------------
   9. STATS
   -------------------------------------------------------------------------- */
.stats {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  border-top: 1px solid rgba(255, 255, 255, 0.14);
}
.stats > div {
  padding: var(--space-md) var(--space-sm) var(--space-md) 0;
  border-right: 1px solid rgba(255, 255, 255, 0.14);
}
.stats > div:last-child { border-right: 0; }
.stats > div:not(:first-child) { padding-left: var(--space-sm); }

.stat__value {
  font-family: var(--font-serif);
  font-size: var(--fs-h3);
  line-height: 1.04;
  letter-spacing: -0.015em;
}
.stat__label {
  font-family: var(--font-sans-ext);
  font-size: var(--fs-eyebrow);
  text-transform: uppercase;
  letter-spacing: 0.2em;
  line-height: 1;
  color: var(--muted);
  margin-top: 1rem;
}

@media (max-width: 780px) {
  .stats { grid-template-columns: repeat(2, 1fr); }
  .stats > div:nth-child(2n) { border-right: 0; }
  .stats > div:nth-child(n+3) { border-top: 1px solid rgba(255,255,255,0.14); }
}

/* --------------------------------------------------------------------------
   10. CAS D'USAGE
   -------------------------------------------------------------------------- */

.usecase {
  position: relative;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  background: var(--gk-near-black);
}
.usecase img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 1400ms var(--ease), opacity var(--dur) var(--ease);
  opacity: 0.85;
}
.usecase:hover img { transform: scale(1.05); opacity: 1; }
.usecase figcaption {
  position: absolute;
  inset: auto 0 0 0;
  padding: var(--space-sm);
  background: linear-gradient(to top, rgba(0,0,0,0.8), transparent);
  font-family: var(--font-serif);
  font-size: 1.125rem;
  line-height: 1.15;
  letter-spacing: -0.015em;
  color: var(--gk-white);
}


/* --------------------------------------------------------------------------
   11. SPECS
   -------------------------------------------------------------------------- */
/* La grille est solidaire du theme de sa section.
   Avec un fond noir fige, le texte d'une section claire devenait illisible. */
.specs {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-lg) var(--space-md);
}
@media (max-width: 860px) { .specs { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 520px) { .specs { grid-template-columns: 1fr; } }

.spec { padding: 0; }
.spec dt {
  font-family: var(--font-sans-ext);
  font-size: var(--fs-eyebrow);
  text-transform: uppercase;
  letter-spacing: 0.2em;
  line-height: 1;
  color: var(--muted);
}
.spec dd {
  font-family: var(--font-serif);
  font-size: var(--fs-h3);
  line-height: 1.08;
  letter-spacing: -0.015em;
  margin-top: 1rem;
}

/* --------------------------------------------------------------------------
   12. CARTES NUMÉROTÉES (Frame / Studio)
   -------------------------------------------------------------------------- */
/* Les separateurs sont de vrais filets, pas un fond gris qu'on recouvre de
   cases opaques : ce montage laissait voir la trame grise le temps que la
   page peigne, et le fond de section suffit en dessous. */
.steps { display: grid; gap: 0; grid-template-columns: repeat(4, 1fr); }
@media (max-width: 900px) { .steps { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .steps { grid-template-columns: 1fr; } }

.step { padding: var(--space-md) var(--space-sm); }
/* Les cellules de bord ne portent pas de retrait exterieur : la premiere et
   la derniere s'alignent alors sur le titre de section, pas sur une gouttiere
   interne. */
.steps > .step:first-child { padding-left: 0; }
.steps > .step:last-child { padding-right: 0; }
@media (max-width: 900px) {
  .steps > .step:nth-child(2n+1) { padding-left: 0; }
  .steps > .step:nth-child(2n) { padding-right: 0; }
}
@media (max-width: 560px) {
  .steps > .step { padding-left: 0; padding-right: 0; }
}
.step + .step { border-left: 1px solid rgba(255, 255, 255, 0.14); }
.section--light .step + .step,
.section--paper .step + .step { border-left-color: rgba(0, 0, 0, 0.12); }

/* En deux colonnes, la premiere de chaque ligne ne porte pas de filet a
   gauche, mais les lignes suivantes en portent un au-dessus. */
@media (max-width: 900px) {
  .steps > .step:nth-child(2n+1) { border-left: 0; }
  .steps > .step:nth-child(n+3) { border-top: 1px solid rgba(255, 255, 255, 0.14); }
  .section--light .steps > .step:nth-child(n+3),
  .section--paper .steps > .step:nth-child(n+3) { border-top-color: rgba(0, 0, 0, 0.12); }
}
@media (max-width: 560px) {
  .steps > .step + .step { border-left: 0; border-top: 1px solid rgba(255, 255, 255, 0.14); }
  .section--light .steps > .step + .step,
  .section--paper .steps > .step + .step { border-top-color: rgba(0, 0, 0, 0.12); }
}

.step__num {
  font-family: var(--font-sans-ext);
  font-size: 0.5625rem;
  letter-spacing: 0;
  color: var(--muted);
  display: block;
  margin-bottom: var(--space-sm);
}
.step__title { margin-bottom: 0.6rem; }
.step__text { font-size: var(--fs-body); color: var(--gk-mid-gray); }
.section--light .step__text, .section--paper .step__text { color: var(--muted); }

/* Bloc détaillé alterné */
.section--dark .feature { border-top-color: rgba(255, 255, 255, 0.12); }
@media (max-width: 900px) {
  .feature { grid-template-columns: 1fr; padding-block: var(--space-lg); }
  .feature--reverse > .feature__media { order: 0; }
}

/* --------------------------------------------------------------------------
   13. SEGMENTATION (Monetize)
   -------------------------------------------------------------------------- */
.segments { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--space-md); }
@media (max-width: 1000px) { .segments { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .segments { grid-template-columns: 1fr; } }

/* Quatre entrees, quatre filets. Sans trait au-dessus, elles flottaient dans
   le noir et l'on ne voyait plus ou commencait chacune : la couleur du filet
   etait declaree, sa largeur avait disparu. */
.segment {
  border-top: 1px solid rgba(0, 0, 0, 0.16);
  padding-top: 1.3rem;
}
.section--dark .segment { border-top-color: rgba(255, 255, 255, 0.2); }
.segment h3 { font-size: var(--fs-h3); margin-bottom: 1rem; }

.segment p { font-size: var(--fs-body); color: var(--muted); }
.section--dark .segment p { color: var(--gk-mid-gray); }

/* --------------------------------------------------------------------------
   14. PRICING
   -------------------------------------------------------------------------- */
.price-card {
  border: 1px solid rgba(255, 255, 255, 0.16);
  padding: var(--space-lg) var(--space-md);
  border-radius: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
}
.section--light .price-card, .section--paper .price-card { border-color: rgba(0,0,0,0.15); }

.price {
  font-family: var(--font-serif);
  font-size: var(--fs-hero);
  line-height: 1;
  letter-spacing: -0.015em;
}
.price small {
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  letter-spacing: 0;
  color: var(--muted);
  margin-left: 0.35em;
}
.section--light .price small { color: var(--muted); }

.check-list { list-style: none; padding: 0; display: grid; gap: 0.9rem; }
.check-list li {
  display: grid;
  grid-template-columns: 1.4em 1fr;
  gap: 0.7em;
  align-items: start;
  font-size: var(--fs-body);
  color: var(--gk-mid-gray);
}
.section--light .check-list li, .section--paper .check-list li { color: var(--gk-charcoal); }
.check-list svg { width: 14px; height: 14px; margin-top: 0.45em; stroke: currentColor; fill: none; stroke-width: 1.5; }

/* Liste de lieux, séparateur médian */
.venues {
  list-style: none;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem 0;
  font-family: var(--font-sans-ext);
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--gk-mid-gray);
}
.section--light .venues { color: var(--muted); }
.venues li::after { content: " · "; margin: 0 0.7em; opacity: 0.5; }
.venues li:last-child::after { content: ""; }

/* --------------------------------------------------------------------------
   15. GALERIE / BIBLIOTHÈQUE (Studio)
   -------------------------------------------------------------------------- */
.marquee__track {
  display: flex;
  gap: var(--space-xs);
  width: max-content;
  animation: marquee var(--marquee-dur) linear infinite;
}
.marquee:hover .marquee__track { animation-play-state: paused; }
.marquee__track img {
  height: clamp(180px, 24vw, 320px);
  width: auto;
  object-fit: cover;
  filter: grayscale(1);
  opacity: 0.9;
}
@keyframes marquee {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}
.marquee--reverse .marquee__track { animation-direction: reverse; }

@media (prefers-reduced-motion: reduce) {
  .marquee__track { animation: none; }
  .marquee { overflow-x: auto; }
}

/* --------------------------------------------------------------------------
   16. VIDÉO
   -------------------------------------------------------------------------- */

/* Le paragraphe qui porte le bouton doit se recentrer comme le reste. */

.cta__meta {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-sm) var(--space-lg);
  margin-top: var(--space-lg);
}
.cta__meta a, .cta__meta span {
  display: inline-flex;
  align-items: center;
  gap: 0.6em;
  font-size: var(--fs-body);
  color: var(--gk-mid-gray);
  transition: color var(--dur-fast) var(--ease);
}
.cta__meta a:hover { color: var(--gk-white); }
.cta__meta img { width: 15px; height: 15px; opacity: 0.7; }

/* --------------------------------------------------------------------------
   18. FORMULAIRES
   -------------------------------------------------------------------------- */
.form { display: grid; gap: var(--space-sm); }
.form__row { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-sm); }
@media (max-width: 640px) { .form__row { grid-template-columns: 1fr; } }

.field { display: grid; gap: 0.5rem; }
.field label {
  font-family: var(--font-sans-ext);
  font-size: 0.625rem;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  color: var(--muted);
}
.field input,
.field select,
.field textarea {
  width: 100%;
  background: transparent;
  border: 0;
  border-bottom: 1px solid rgba(255, 255, 255, 0.25);
  padding: 0.7rem 0;
  font-size: var(--fs-body);
  border-radius: 0;
  transition: border-color var(--dur-fast) var(--ease);
}
.field input:focus,
.field select:focus,
.field textarea:focus {
  outline: none;
  border-bottom-color: var(--gk-white);
}
.field textarea { resize: vertical; min-height: 7rem; }
.field select option { background: var(--gk-black); }

.section--light .field input,
.section--light .field select,
.section--light .field textarea { border-bottom-color: rgba(0,0,0,0.25); }
.section--light .field input:focus,
.section--light .field select:focus,
.section--light .field textarea:focus { border-bottom-color: var(--gk-black); }

.checkbox {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.8rem;
  align-items: start;
  font-size: var(--fs-body);
  color: var(--muted);
  cursor: pointer;
}
.checkbox input { width: 15px; height: 15px; margin-top: 0.3em; accent-color: currentColor; }

/* Newsletter en ligne */
.newsletter { display: flex; gap: var(--space-xs); align-items: flex-end; flex-wrap: wrap; }
.newsletter .field { flex: 1 1 240px; }

/* --------------------------------------------------------------------------
   19. FOOTER
   -------------------------------------------------------------------------- */
.site-footer {
  background: var(--gk-black);
  border-top: 1px solid rgba(255, 255, 255, 0.12);
  padding-block: var(--space-xl) var(--space-md);
}


/* --------------------------------------------------------------------------
   20. ANIMATIONS AU SCROLL
   Ginko ne bondit pas. Ginko se révèle.
   -------------------------------------------------------------------------- */
/* --------------------------------------------------------------------------
   L'ARRIVEE SUR LA PAGE

   Une navigation interne se faisait d'un coup sec : tout etait deja en cache,
   la page se peignait d'un seul bloc et aucune revelation n'avait le temps de
   se voir. Chaque page s'ouvre donc sur un fondu court, et le pied suit d'un
   cran pour que le regard parte du haut.

   L'opacite revient exactement a 1 : aucun contexte d'empilement ne subsiste
   ensuite, l'en-tete fixe et les menus deroulants gardent leur comportement.
   -------------------------------------------------------------------------- */
@keyframes gk-entree {
  from { opacity: 0; }
  to   { opacity: 1; }
}
/* Ni delai ni mode de remplissage : un delai impose de tenir l'element cache
   avant le depart, et un remplissage laisse la page blanche si l'animation ne
   demarre jamais. Les trois durees suffisent a decaler les arrivees. */
.site-header { animation: gk-entree 480ms var(--ease); }
main          { animation: gk-entree 640ms var(--ease); }
.site-footer  { animation: gk-entree 780ms var(--ease); }

@media (prefers-reduced-motion: reduce) {
  .site-header,
  main,
  .site-footer { animation: none; }
}

html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

[data-reveal] {
  opacity: 0;
  transform: translateY(34px);
  transition: opacity var(--dur) var(--ease-reveal), transform var(--dur) var(--ease-reveal);
  transition-delay: var(--reveal-delay, 0ms);
  will-change: opacity, transform;
}
[data-reveal].is-visible {
  opacity: 1;
  transform: none;
}

/* Variante : révélation sans déplacement (grandes images) */
[data-reveal="fade"] { transform: none; }

/* Une image differee qui arrive apres son cadre claquait d'un coup dans la
   page. Elle nait en fondu. La classe est posee par le script uniquement sur
   les images encore en chargement : celles deja en cache ne clignotent pas,
   et les couches qui pilotent leur propre opacite ne sont jamais touchees. */
img.gk-nait { opacity: 0; }
img.gk-nee { opacity: 1; transition: opacity 700ms var(--ease-reveal); }

/* ---- le depart vers une autre page --------------------------------------
   L'arrivee se fait en fondu depuis un moment ; sans depart assorti, on
   passait d'une page pleine a un blanc sec. Le voile est pose sur le body :
   l'opacite du body lui-meme casserait les contextes d'empilement. */
html.gk-sort body { opacity: 0; transition: opacity 240ms ease; }

/* Parallaxe douce */
[data-parallax] { will-change: transform; }

@media (prefers-reduced-motion: reduce) {
  [data-reveal] { opacity: 1 !important; transform: none !important; transition: none; }
  [data-parallax] { transform: none !important; }
}

/* --------------------------------------------------------------------------
   21. UTILITAIRES
   -------------------------------------------------------------------------- */
.mt-xs { margin-top: var(--space-xs); }
.mt-sm { margin-top: var(--space-sm); }
.mt-md { margin-top: var(--space-md); }
.mt-lg { margin-top: var(--space-lg); }
.mt-xl { margin-top: var(--space-xl); }
.text-center { text-align: center; }
/* Dans une section centrée, toute boîte contrainte se recentre aussi. */
.text-center .lead,
.text-center .prose p,
.text-center p { margin-inline: auto; }
.text-center .check-list { justify-items: center; }
.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;
}


/* En-tête de section avec le sélecteur aligné à droite du titre */
/* Chapeau centre : l'oeil descend sur un axe unique. L'intertitre s'ecarte
   du titre, le chapo s'en rapproche : c'est le titre qui commande le bloc,
   pas l'espace regulier entre trois lignes. */
.section-head--centre {
  max-width: 46ch;
  margin-inline: auto;
  text-align: center;
}
.section-head--centre .eyebrow { margin-bottom: var(--space-sm); }
.section-head--centre h2 { margin: 0; }
.section-head--centre .lead { margin: 0.9rem auto 0; }

.section-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--space-sm) var(--space-md);
  flex-wrap: wrap;
  padding-bottom: var(--space-sm);
}


/* --------------------------------------------------------------------------
   LES FINITIONS, EN REGARD DU TEXTE
   Une photo d'ambiance occupait la moitie du chapitre alors que le sujet,
   ce sont les essences. Elles se lisent maintenant comme la planche d'un
   encadreur : un coin de baguette, un nom, une mention, un filet.
   -------------------------------------------------------------------------- */
.section--dark .finition { border-top-color: rgba(255, 255, 255, 0.14); }
.section--dark .finition:last-child { border-bottom-color: rgba(255, 255, 255, 0.14); }

.section--dark .finition__coin { mix-blend-mode: normal; }


@media (max-width: 560px) {
  .finition { grid-template-columns: 64px minmax(0, 1fr) auto; gap: var(--space-xs); }
  .finition__coin { width: 64px; height: 64px; }
}


/* --------------------------------------------------------------------------
   L'ATELIER
   Un plein ecran, tenu comme une petite application. Un seul cadre, dessine
   une fois : les chapitres n'echangent pas des images, ils allument une piece
   de ce meme cadre. Le survol choisit, le defilement avance tout seul. Tout
   passe par une cle posee sur le panneau, le reste est de la cascade : rien
   n'est reconstruit, l'objet ne cligne jamais.
   -------------------------------------------------------------------------- */
@media (max-width: 900px) {
  .atelier { height: auto; }
  .atelier__pane {
    position: static;
    height: auto;
    grid-template-columns: 1fr;
    gap: var(--space-xl);
    padding-block: var(--space-2xl);
  }
}

.atelier__tete { margin-bottom: clamp(2rem, 6vh, 4.5rem); }
.atelier__tete .eyebrow {
  color: rgba(255, 255, 255, 0.55);
  margin-bottom: clamp(1.4rem, 3vh, 2.2rem);
}
.atelier__tete h2 { margin: 0; max-width: 18ch; }

/* ---------- Le sommaire ---------- */
.atelier__menu { display: grid; }
.atelier__onglet {
  display: grid;
  align-items: center;
  width: 100%;
  /* Hauteur posee une fois pour toutes : le sommaire ne bouge jamais. Le
     contenu, lui, est centre, donc un titre sans sous-titre se recentre de
     lui-meme au lieu de rester colle en haut. */
  min-height: clamp(4.5rem, 11vh, 6.5rem);
  padding: 0;
  text-align: left;
  background: none;
  border: 0;
  color: inherit;
  cursor: pointer;
}
/* Les filets separent, ils n'encadrent pas : rien au-dessus du premier
   chapitre, rien sous le dernier. */
.atelier__onglet + .atelier__onglet { border-top: 1px solid rgba(255, 255, 255, 0.12); }

/* Numerotation entre crochets, comme le sommaire du pied de page. */
.atelier__num {
  grid-row: 1;
  align-self: center;
  font-family: var(--font-sans-ext);
  font-size: 0.5625rem;
  font-weight: 500;
  letter-spacing: 0;
  color: rgba(255, 255, 255, 0.35);
  transition: color var(--dur-fast) var(--ease);
}
.atelier__onglet.is-on .atelier__num { color: var(--gk-white); }

.atelier__titre {
  /* Place explicitement : sans cela il tombait en deuxieme rangee et le
     numero se retrouvait quarante pixels au-dessus de lui. */
  grid-column: 2;
  grid-row: 1;
  font-family: var(--font-serif);
  font-weight: 300;
  font-size: clamp(1rem, 1.4vw, 1.25rem);
  line-height: 1.25;
  letter-spacing: -0.005em;
  color: rgba(255, 255, 255, 0.55);
  transition: color var(--dur-fast) var(--ease);
}
.atelier__onglet.is-on .atelier__titre { color: var(--gk-white); }

/* Le sous-titre se replie a hauteur nulle sans disparaitre du flux : la
   rangee passe de 0fr a 1fr, ce qui s'anime, contrairement a une hauteur
   automatique. */
.atelier__ligne {
  display: grid;
  grid-template-columns: 2.6rem minmax(0, 1fr);
  column-gap: var(--space-xs);
  /* minmax(0, ...) et non 0fr seul : une rangee a 0fr garde quand meme la
     taille minimale de son contenu, ici le retrait du sous-titre. Elle
     mesurait donc 8,8 px et decalait le titre vers le haut. */
  grid-template-rows: auto minmax(0, 0fr);
  transition: grid-template-rows 420ms var(--ease);
}
.atelier__onglet.is-on .atelier__ligne { grid-template-rows: auto minmax(0, 1fr); }

.atelier__sous {
  grid-column: 2;
  min-height: 0;
  overflow: hidden;
  padding-top: 0.55rem;
  opacity: 0;
  font-family: var(--font-sans);
  font-size: 0.75rem;
  font-weight: 400;
  text-transform: none;
  letter-spacing: 0;
  line-height: 1.4;
  color: rgba(255, 255, 255, 0.45);
  transition: opacity 420ms var(--ease);
}
.atelier__onglet.is-on .atelier__sous { opacity: 1; }
.atelier__sous > span, .atelier__sous { display: block; }

/* ---------- Le cadre ---------- */
/* Le dessin se cale a gauche, sur le meme bord que le texte : deux axes dans
   la meme colonne se voyaient tout de suite. */
.croquis {
  /* Hauteur posee, jamais deduite : elle dependait de la longueur du texte
     du chapitre, et le cadre changeait donc de taille et de position d'un
     volet a l'autre. C'est exactement ce que l'animation doit eviter. */
  width: auto;
  height: clamp(260px, 42vh, 460px);
  max-width: 100%;
  color: var(--gk-white);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}
/* Un seul blanc, une seule epaisseur, et les traits toujours pleinement
   visibles. Ce n'est pas l'opacite qui designe le chapitre actif, c'est le
   remplissage : le trait dit la forme, la matiere dit le choix. */
.croquis .piece {
  opacity: 1;
  transition: opacity 620ms var(--ease);
}
.croquis .piece--acc,
.croquis .piece--fix,
.croquis .piece--verre { opacity: 0; }

/* La baguette et la marie-louise se remplissent au lieu de changer de trait :
   c'est une matiere qu'on designe, pas un contour. */
.croquis .plein {
  fill: currentColor;
  opacity: 0;
  transition: opacity 620ms var(--ease);
}
[data-atelier-corps][data-piece="passe"] .croquis .piece--passe .plein { opacity: 1; }

/* Quatre profils de baguette, pas quatre teintes : une fine, une large, une
   a gradins, une texturee. Ils ne se substituent pas, ils se deforment. Les
   proprietes de geometrie d'un rectangle SVG etant animables en CSS, il
   suffit de faire varier une epaisseur pour que le cadre se transforme. */
.croquis {
  overflow: visible;
  --ep: 19px;                  /* epaisseur relevee sur la photographie */
  --ext-x: 0px;   --ext-y: 110px;
  --ext-l: 1000px; --ext-h: 800px;
}
.croquis .f-plein, .croquis .f-hachure, .croquis .f-creux,
.croquis .f-trait, .croquis .f-gradin, .croquis .m-plein {
  transition: x 620ms var(--ease), y 620ms var(--ease),
              width 620ms var(--ease), height 620ms var(--ease),
              opacity 620ms var(--ease);
}

/* La matiere de la baguette, et l'evidement qui la creuse. */
.croquis .f-plein { fill: currentColor; opacity: 0; }
.croquis .f-hachure { fill: url(#gk-hachure); opacity: 0; }
.croquis .f-creux { fill: var(--gk-black); }
.croquis .f-creux,
.croquis .f-int,
.croquis .m-plein {
  x: calc(var(--ext-x) + var(--ep));
  y: calc(var(--ext-y) + var(--ep));
  width: calc(var(--ext-l) - 2 * var(--ep));
  height: calc(var(--ext-h) - 2 * var(--ep));
}
.croquis .f-gradin { opacity: 0; }

/* La marie-louise : sa matiere s'arrete au bord de l'image. */
.croquis .m-plein { fill: currentColor; opacity: 0; }
.croquis .m-creux { fill: var(--gk-black); }

/* Les quatre profils. */
[data-atelier-corps][data-bois="0"] .croquis { --ep: 8px; }
[data-atelier-corps][data-bois="1"] .croquis { --ep: 42px; }
[data-atelier-corps][data-bois="2"] .croquis { --ep: 34px; }
[data-atelier-corps][data-bois="3"] .croquis { --ep: 26px; }

/* Le gradin n'existe que sur le troisieme profil. */
[data-atelier-corps][data-bois="2"] .croquis .f-gradin {
  opacity: 1;
  x: calc(var(--ext-x) + var(--ep) / 2);
  y: calc(var(--ext-y) + var(--ep) / 2);
  width: calc(var(--ext-l) - var(--ep));
  height: calc(var(--ext-h) - var(--ep));
}

/* La matiere n'apparait que sur le chapitre de la baguette, et la texture
   seulement sur le quatrieme profil. */
[data-atelier-corps][data-piece="cadre"] .croquis .f-plein { opacity: 1; }
[data-atelier-corps][data-piece="cadre"][data-bois="3"] .croquis .f-hachure { opacity: 1; }
[data-atelier-corps][data-piece="passe"] .croquis .m-plein { opacity: 1; }

/* La baguette ne se remplit pas de blanc : elle prend ses essences, l'une
   apres l'autre, une seconde chacune. C'est la seule couleur du site, et
   elle appartient au produit. */
.croquis .essence { opacity: 0; transition: opacity 500ms var(--ease); }
[data-atelier-corps][data-bois="0"] .croquis .essence[data-bois="0"],
[data-atelier-corps][data-bois="1"] .croquis .essence[data-bois="1"],
[data-atelier-corps][data-bois="2"] .croquis .essence[data-bois="2"],
[data-atelier-corps][data-bois="3"] .croquis .essence[data-bois="3"] { opacity: 1; }

[data-atelier-corps][data-piece="cadre"] .croquis .piece--cadre,
[data-atelier-corps][data-piece="passe"] .croquis .piece--passe,
[data-atelier-corps][data-piece="verre"] .croquis .piece--verre,
[data-atelier-corps][data-piece="acc"] .croquis .piece--acc,
[data-atelier-corps][data-piece="fix"] .croquis .piece--fix { opacity: 1; }

.croquis [data-fix],
.croquis [data-acc] { opacity: 0; transition: opacity 460ms var(--ease); }
[data-atelier-corps][data-fix="0"] .croquis [data-fix="0"],
[data-atelier-corps][data-fix="1"] .croquis [data-fix="1"],
[data-atelier-corps][data-fix="2"] .croquis [data-fix="2"],
[data-atelier-corps][data-fix="3"] .croquis [data-fix="3"],
[data-atelier-corps][data-acc="0"] .croquis [data-acc="0"],
[data-atelier-corps][data-acc="1"] .croquis [data-acc="1"] { opacity: 1; }

/* ---------- Le texte ---------- */
/* La place du texte est reservee sur le volet le plus long : sans cela le
   cadre remontait ou descendait selon le chapitre. */
.atelier__texte[hidden] { display: none; }
.atelier__texte {
  max-width: 54ch;
  animation: atelierEntree 460ms var(--ease) both;
}
@keyframes atelierEntree {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}

.atelier__texte p {
  font-size: var(--fs-body);
  line-height: 1.8;
  color: rgba(255, 255, 255, 0.7);
}
.atelier__texte p + p { margin-top: 0.9rem; }

/* La planche des essences ne concerne que la baguette. */

@media (prefers-reduced-motion: reduce) {
  .atelier { height: auto; }
  .atelier__pane { position: static; height: auto; }
  .croquis .piece, .croquis [data-fix], .croquis [data-acc] { transition: none; }
  .atelier__texte { animation: none; }
}


/* --------------------------------------------------------------------------
   L'ATELIER, L'OUVERTURE
   Le cadre entre seul, tient le centre de l'ecran, puis rejoint sa place a
   droite en retrecissant, et la section se decouvre autour de lui. Le point
   d'arrivee n'est pas une valeur en dur : c'est une case reservee dans la
   mise en page, que le script mesure. La choregraphie reste donc juste quelle
   que soit la taille de l'ecran.
   -------------------------------------------------------------------------- */
.ouverture {
  position: relative;
  height: 420vh;
  /* Le chapeau pose deja son retrait bas : on remonte la piste d'autant,
     sinon le cadre demarre trop loin du titre. */
  margin-top: calc(var(--space-xl) * -1);
  background: var(--gk-black);
  color: var(--gk-white);
}
.ouverture__pane {
  position: sticky;
  --entete: 5.5rem;
  top: var(--entete);
  height: calc(100vh - var(--entete));
  width: 100%;
  max-width: calc(var(--wrap) + 2 * var(--gutter));
  margin-inline: auto;
  padding: clamp(2rem, 5vh, 4rem) var(--gutter);
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
  gap: clamp(3rem, 9vw, 9rem);
  align-items: center;
  overflow: hidden;
}

/* Sommaire et texte ne se decouvrent qu'une fois le cadre range. */
.ouverture__gauche, .ouverture__droite {
  display: grid;
  align-content: center;
  min-height: 0;
  opacity: var(--ouv-texte, 0);
  transform: translateY(calc((1 - var(--ouv-texte, 0)) * 16px));
}
.ouverture__droite { gap: clamp(1.5rem, 4vh, 3rem); }

/* La case reservee : elle ne se voit pas, elle tient la place du cadre. */
.ouverture__cible { height: clamp(200px, 34vh, 380px); }
.ouverture__dits { min-height: clamp(9rem, 22vh, 12rem); }

/* Le cadre est pose sur le panneau, pas dans une colonne : il part donc du
   centre de l'ecran avant de rejoindre sa case. */
.ouverture__cadre {
  position: absolute;
  top: 50%;
  left: 50%;
  transform:
    translate(-50%, -50%)
    translate(var(--ouv-x, 0px), var(--ouv-y, 0px))
    scale(var(--ouv-e, 1));
  transform-origin: center;
  will-change: transform;
  pointer-events: none;
}
.ouverture__cadre {
  position: absolute;
  /* La hauteur du dessin, nommee ici : la photographie se cale dessus. */
  --croquis-h: clamp(360px, 74vh, 820px);
}
/* Les deux cotes sont ecrits, aucun n'est laisse a "auto". Avec une largeur
   automatique, une boite trop etroite rabotait le SVG : lui gardait son
   rapport en se recentrant dans la boite reduite, la photographie non, et
   elle s'ecrasait d'autant. Au zoom arriere l'ecart devenait franc. */
.ouverture__cadre .croquis {
  display: block;
  height: var(--croquis-h);
  width: calc(var(--croquis-h) * 1000 / 1040);
  /* Le max-width general rabotait justement cette largeur : ici la boite
     doit tenir son rapport, quitte a deborder. Elle plafonne a 820px de
     haut, soit 788 de large : elle tient dans n'importe quel bureau. */
  max-width: none;
  color: var(--gk-white);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}

/* La photographie du vrai cadre occupe exactement la boite du dessin : le
   trait se trace donc par-dessus elle, au meme endroit, pendant qu'elle
   s'efface. C'est ce qui donne le passage de l'objet a son epure. */
.ouverture__photo {
  /* La photographie se cale sur la baguette du dessin, pas sur la boite du
     SVG : celle-ci reserve de la place au-dessus et au-dessous pour le
     crochet et le chevalet, et un simple "contain" decalait donc l'image
     d'une poignee de pixels. Les valeurs sont les proportions du viewBox :
     la baguette occupe 110 a 910 sur 1040 de haut, toute la largeur. */
  position: absolute;
  left: 0;
  top: 10.5769%;
  width: 100%;
  height: 76.9231%;
  object-fit: fill;
  opacity: var(--ouv-photo, 1);
  pointer-events: none;
}

/* Les traits se dessinent : pathLength normalise chaque trace, tous
   avancent donc du meme pas quelle que soit leur longueur reelle. */
.ouverture__cadre [pathLength] {
  stroke-dasharray: 1;
  /* Rien de trace tant que le script n'a pas parle. */
  stroke-dashoffset: calc(1 - var(--ouv-trace, 0));
}
.ouverture__cadre .piece--cadre .plein,
.ouverture__cadre .essence,
.ouverture__cadre .f-plein,
.ouverture__cadre .f-hachure,
.ouverture__cadre .m-plein { opacity: 0; }

@media (max-width: 900px) {
  .ouverture { height: auto; }
  .ouverture__pane {
    position: static;
    height: auto;
    grid-template-columns: 1fr;
    gap: var(--space-xl);
    padding-block: var(--space-2xl);
    overflow: visible;
  }
  .ouverture__gauche, .ouverture__droite { opacity: 1; transform: none; }
  .ouverture__cible { display: none; }
  /* Sur telephone, c'est la photographie qu'on montre : le dessin ne vaut
     que par ses etats, et il n'y a plus d'interaction pour les appeler. */
  .ouverture__cadre { position: static; transform: none; order: -1; }
  .ouverture__cadre .croquis { display: none; }
  .ouverture__photo {
    position: static;
    display: block;
    width: min(100%, 520px);
    height: auto;
    margin-inline: auto;
    opacity: 1;
  }

  /* Chaque chapitre porte son texte : on lit une liste, plus un dispositif.
     Une seule colonne, un seul bord gauche : le numero, le titre, son
     intertitre et le texte s'alignent tous, au lieu de se decaler en marches
     d'escalier. */
  .ouverture__dits { min-height: 0; }
  .atelier__menu { gap: 0; }

  .atelier__onglet {
    min-height: 0;
    padding: var(--space-md) 0 0;
    cursor: default;
  }
  .atelier__onglet + .atelier__onglet { border-top: 0; }

  .atelier__ligne {
    grid-template-columns: 1fr;
    grid-template-rows: auto auto auto;
    column-gap: 0;
  }
  .atelier__num {
    grid-row: 1;
    grid-column: 1;
    margin-bottom: 0.9rem;
  }
  /* Le titre reprend le dessus : il etait plus petit et plus gris que le
     texte qu'il annonce. */
  .atelier__titre {
    grid-row: 2;
    grid-column: 1;
    font-size: 1.5rem;
    color: var(--gk-white);
  }
  .atelier__sous {
    grid-row: 3;
    grid-column: 1;
    opacity: 1;
    padding-top: 0.4rem;
  }

  .atelier__menu [data-texte] {
    padding: var(--space-sm) 0 var(--space-lg);
    max-width: none;
    animation: none;
    border-bottom: 1px solid rgba(255, 255, 255, 0.12);
  }
  .atelier__menu [data-texte]:last-child { border-bottom: 0; }
  .atelier__menu [data-texte] p { font-size: var(--fs-body); line-height: 1.8; }
}

@media (prefers-reduced-motion: reduce) {
  .ouverture { height: auto; }
  .ouverture__pane { position: static; height: auto; overflow: visible; }
  .ouverture__gauche, .ouverture__droite { opacity: 1; transform: none; }
  .ouverture__cible { display: none; }
  .ouverture__cadre { position: static; transform: none; }
  .ouverture__photo { display: none; }
  .ouverture__cadre [pathLength] { stroke-dasharray: none; }
}


/* La note commerciale ferme le passage a l'acte : le prix et le delai se
   disent la, pas au detour d'une etape. */
.steps__note {
  max-width: 62ch;
  margin: var(--space-lg) auto 0;
  text-align: center;
}

/* --------------------------------------------------------------------------
   LE DERNIER MOT
   L'invitation, le bouton, puis la phrase de cloture sous un filet. Elle est
   la derniere chose qu'on lit : elle n'a pas a se battre avec le bouton.
   -------------------------------------------------------------------------- */
.devis {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  padding-block: clamp(6rem, 18vh, 11rem);
  color: var(--gk-white);
  background: var(--gk-black);
}
.devis__fond { position: absolute; inset: 0; z-index: -2; }
.devis__fond img { width: 100%; height: 100%; object-fit: cover; object-position: center 45%; }
.devis::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(180deg,
    rgba(0,0,0,0.9) 0%, rgba(0,0,0,0.62) 40%,
    rgba(0,0,0,0.62) 60%, rgba(0,0,0,0.92) 100%);
}
.devis__inner {
  position: relative;
  max-width: 46ch;
  text-align: center;
  /* Trois elements, deux ecarts identiques : l'intertitre, le titre et le
     bouton se suivent au meme pas, et le bloc se centre d'un seul tenant. */
  display: grid;
  justify-items: center;
  gap: clamp(1.6rem, 4vh, 2.6rem);
}
.devis .eyebrow { color: rgba(255, 255, 255, 0.6); }
.devis__inner .eyebrow { margin: 0; }
.devis__inner h2 { margin: 0 auto; }
.devis__cta { margin: 0; }


/* --------------------------------------------------------------------------
   23b. CHOISIR SON FORMAT
   Les deux formats sont montres cote a cote, a la meme echelle : c'est la
   seule facon de voir que le Monumental est plus grand. Deux pages separees
   demandaient de s'en souvenir d'un onglet a l'autre.
   -------------------------------------------------------------------------- */


/* La livraison : moitie image, moitie texte. L'image tient toute la hauteur
   de la section, elle n'est pas une illustration posee au-dessus d'un
   paragraphe mais l'autre moitie du propos. */
.livraison {
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-items: stretch;
  min-height: min(84vh, 780px);
  background: var(--gk-paper);
  /* La section ne porte pas de classe --paper : sans ces jetons elle heritait
     du texte blanc et du gris clair du theme sombre, illisibles ici. */
  color: var(--gk-charcoal);
  --muted: #68685f;
  --body-ink: var(--gk-charcoal);
}
.livraison h2 { color: var(--gk-black); }
.livraison .eyebrow, .livraison .lead { color: var(--muted); }
.livraison__media { margin: 0; overflow: hidden; }
.livraison__media img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.livraison__dit {
  display: flex;
  align-items: center;
  padding: var(--space-xl) var(--gutter);
}
.livraison__dit > div { max-width: 40ch; }
.livraison__dit .eyebrow { margin-bottom: var(--space-sm); }
.livraison__dit .lead { margin-top: var(--space-sm); }

@media (max-width: 860px) {
  .livraison { grid-template-columns: 1fr; min-height: 0; }
  .livraison__media img { height: auto; aspect-ratio: 4 / 3; }
  .livraison__dit { padding-block: var(--space-lg); }
}

.formats {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-lg) var(--space-xl);
  align-items: start;
}
@media (max-width: 760px) { .formats { grid-template-columns: 1fr; } }

.format { margin: 0; scroll-margin-top: 6rem; }
.format__media { margin: 0 0 var(--space-md); }
.format__media img {
  display: block;
  width: 100%;
  height: auto;
  /* Les rendus sont detoures sur blanc : la section l'est aussi, le fond de
     l'image se confond donc avec celui de la page. Un mode de fusion aurait
     suffi, mais le contexte d'empilement cree par les animations de
     revelation l'annule. */
}
.format__eye { margin-bottom: 0.5rem; }
.format__name {
  font-family: var(--font-serif);
  font-size: var(--fs-h3);
  line-height: 1.15;
  letter-spacing: -0.015em;
  margin: 0;
}

.format__specs {
  display: grid;
  gap: 0;
  margin: var(--space-sm) 0 0;
  border-top: 1px solid rgba(0, 0, 0, 0.1);
}
.format__specs > div {
  display: flex;
  justify-content: space-between;
  gap: var(--space-xs);
  padding: 0.65rem 0;
  border-bottom: 1px solid rgba(0, 0, 0, 0.12);
}
.format__specs dt {
  font-family: var(--font-sans-ext);
  font-size: var(--fs-eyebrow);
  text-transform: uppercase;
  letter-spacing: 0.18em;
  color: var(--muted);
}
.format__specs dd { margin: 0; font-size: var(--fs-body); }


.format__for {
  margin-top: var(--space-sm);
  font-size: var(--fs-body);
  line-height: 1.7;
  color: var(--muted);
}

/* La phrase qui aide a trancher, quand la comparaison n'a pas suffi */
.formats__aide {
  max-width: 46ch;
  margin: var(--space-xl) auto 0;
  text-align: center;
}
.formats__aide p { font-size: var(--fs-lead); color: var(--muted); }

/* --------------------------------------------------------------------------
   23. FICHES PRODUIT
   -------------------------------------------------------------------------- */
.model-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  border: 1px solid rgba(255, 255, 255, 0.16);
  border-radius: 0;
  overflow: hidden;
  background: var(--gk-near-black);
}
.section--light .model-card, .section--paper .model-card {
  border-color: rgba(0, 0, 0, 0.14);
  background: var(--gk-paper);
}
.model-card__media { aspect-ratio: 4 / 3; overflow: hidden; }
.model-card__media img { width: 100%; height: 100%; object-fit: cover; }
.model-card__body { padding: 0 var(--space-md) var(--space-md); display: grid; gap: var(--space-sm); }

/* Séparateur "ou" entre achat et leasing */
.or-rule {
  display: flex;
  align-items: center;
  gap: var(--space-xs);
  color: var(--muted);
  font-family: var(--font-sans-ext);
  font-size: var(--fs-eyebrow);
  text-transform: uppercase;
  letter-spacing: 0.2em;
}
.or-rule::before, .or-rule::after {
  content: "";
  flex: 1;
  height: 1px;
  background: rgba(255, 255, 255, 0.16);
}
.section--light .or-rule::before, .section--light .or-rule::after,
.section--paper .or-rule::before, .section--paper .or-rule::after {
  background: rgba(0, 0, 0, 0.14);
}

/* Plans Studio */
.plans { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-sm); }
/* Trois licences : jamais 2 + 1, l'orpheline sous les deux autres a l'air
   d'une erreur de grille. On passe directement en pile. */
@media (max-width: 1000px) { .plans { grid-template-columns: 1fr; max-width: 34rem; margin-inline: auto; } }

.plan {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  padding: var(--space-md) var(--space-sm);
  border: 1px solid rgba(255, 255, 255, 0.16);
  border-radius: 0;
}
.section--light .plan, .section--paper .plan { border-color: rgba(0,0,0,0.14); }
/* Une mention en capitales : c'est le registre des intertitres, donc
   l'extended. Une regle groupee plus bas la ramenait a la fonte de texte. */
.plan__badge {
  font-family: var(--font-sans-ext);
  font-weight: 400;
  font-size: var(--fs-eyebrow);
  text-transform: uppercase;
  letter-spacing: 0.2em;
  color: var(--muted);
  line-height: 1.5;
}
/* Trois registres, trois roles. La mention en capitales dit a qui la formule
   s'adresse, le nom l'identifie, le montant porte le regard. Nom et montant
   partageaient la meme serif au meme corps : on lisait deux titres au lieu
   d'un nom et d'un prix. */
/* Le nom n'est pas un label : fonte de texte, bas de casse. L'extended en
   capitales est deja pris par la mention juste au-dessus. */
.plan__nom {
  font-family: var(--font-sans);
  font-size: 1.0625rem;
  font-weight: 500;
  line-height: 1.2;
  letter-spacing: 0.02em;
  margin-top: 0.5rem;
}
.plan__price {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0 0.5rem;
  margin-top: 0.2rem;
}
.plan__montant {
  font-family: var(--font-serif);
  font-size: clamp(2.25rem, 3.4vw, 3rem);
  line-height: 1;
  letter-spacing: -0.02em;
}
.plan__unite {
  font-family: var(--font-sans);
  font-size: 0.8125rem;
  line-height: 1.4;
  color: var(--muted);
}
.plan--featured .plan__unite { color: inherit; opacity: 0.6; }
.plan .check-list li { font-size: var(--fs-body); }

/* Étapes numérotées horizontales (Player) */
.flow { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-md); }
@media (max-width: 780px) { .flow { grid-template-columns: 1fr; } }

/* Bandeau de statut sobre */
.notice {
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: 0;
  padding: var(--space-md);
}
.section--light .notice, .section--paper .notice { border-color: rgba(0,0,0,0.14); }

/* Fil d'Ariane */
/* --------------------------------------------------------------------------
   FIL D'ARIANE
   Place en fin de page, juste avant le pied : il sert au retour en arriere,
   pas a l'entree. En haut du hero il coupait la lecture du titre.
   -------------------------------------------------------------------------- */
.crumbbar {
  background: var(--gk-black);
  border-top: 1px solid rgba(255, 255, 255, 0.1);
  padding-block: var(--space-md);
}
.crumbbar ol {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.55em;
  font-family: var(--font-sans-ext);
  font-size: var(--fs-eyebrow);
  text-transform: uppercase;
  letter-spacing: 0.2em;
  line-height: 1;
  color: var(--muted);
}
.crumbbar a { color: var(--muted); transition: color var(--dur-fast) var(--ease); }
.crumbbar a:hover { color: var(--gk-white); }
.crumbbar [aria-current="page"] { color: var(--gk-mid-gray); }
.crumbbar li::after { content: "/"; margin-left: 0.55em; opacity: 0.4; }
.crumbbar li:last-child::after { content: ""; margin: 0; }

/* --------------------------------------------------------------------------
   24. PIED DE PAGE, 4 COLONNES
   Remplace la grille en 3 parties de la première version.
   -------------------------------------------------------------------------- */


/* --------------------------------------------------------------------------
   25. MENU PRINCIPAL ET PANNEAU DEROULANT
   Le lien de tete reste un vrai lien : les moteurs le suivent, le clavier
   l'atteint. Le panneau n'est qu'un confort, jamais un passage oblige.
   -------------------------------------------------------------------------- */
.site-header__inner {
  grid-template-columns: auto 1fr auto;
  gap: var(--space-md);
}

.nav {
  display: flex;
  align-items: center;
  gap: var(--space-md);
  justify-self: center;
}

/* Volontairement pas de position ici : le panneau doit se caler sur toute
   la largeur du header, pas sur l'entree de menu. */
.nav__item { position: static; }
.nav__item--has-menu > .nav__link::before {
  content: "";
  position: absolute;
  left: -0.9rem;
  right: -0.9rem;
  top: 100%;
  /* Doit couvrir le centrage vertical de la barre plus son padding bas :
     c'est exactement la bande que la souris traverse pour atteindre le
     panneau. Le panneau, absolu et plus loin dans le DOM, passe au-dessus,
     ce pont ne bloque donc aucun clic. */
  height: 3rem;
}

.nav__link {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  font-family: var(--font-sans-ext);
  font-size: var(--fs-eyebrow);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.2em;
  color: var(--gk-white);
  opacity: 0.72;
  padding-block: 0.6rem;
  transition: opacity var(--dur-fast) var(--ease);
}
.nav__link:hover,
.nav__link[aria-current="page"],
.nav__item--has-menu.is-open .nav__link,
.nav__item--has-menu:focus-within .nav__link { opacity: 1; }

/* Pas de trait sous les entrees de navigation : l'opacite pleine suffit a
   marquer le survol, et le chevron dit le reste. */
.nav__link { position: relative; }

.nav__chev {
  width: 9px;
  height: 6px;
  transition: transform var(--dur-fast) var(--ease);
}
.nav__item--has-menu.is-open .nav__chev,
.nav__item--has-menu:focus-within .nav__chev { transform: rotate(180deg); }

.nav__end {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  justify-self: end;
}

.nav__social {
  display: inline-flex;
  opacity: 0.6;
  transition: opacity var(--dur-fast) var(--ease);
}
.nav__social:hover { opacity: 1; }
.nav__social svg { width: 15px; height: 15px; fill: currentColor; }

/* ---------- Le panneau ---------- */
.mega {
  position: absolute;
  left: 0;
  right: 0;
  top: 100%;
  /* Le panneau doit se detacher du fond noir de la page : fond legerement
     releve, filet net en haut et en bas, et ombre portee. */
  background: var(--gk-black);
  border-top: 1px solid rgba(255, 255, 255, 0.14);
  border-bottom: 1px solid rgba(255, 255, 255, 0.14);
  /* Le panneau se deroule du haut vers le bas, il n'apparait pas en fondu :
     c'est une hauteur qui s'ouvre, et le contenu se decouvre au fur et a
     mesure. Aucune transformation ici, sinon le voile en position fixe
     serait rogne par l'overflow. */
  max-height: 0;
  overflow: hidden;
  visibility: hidden;
  transition: max-height 720ms cubic-bezier(0.16, 0.84, 0.24, 1), visibility 720ms;
}
/* Bascule d'une rubrique a l'autre : le cadre ne bouge pas, il n'a pas a
   coulisser une seconde fois. Le sortant s'efface vite, l'entrant apparait
   sans glissement : c'est le contenu qui change, pas le panneau. */
.site-header.nav-swap .mega { transition: none; }
.site-header.nav-swap .mega::after { transition: none; }

/* Le contenu se renouvelle en cascade, jamais d'un bloc. */
@keyframes megaEntree {
  from { opacity: 0; transform: translateY(12px); }
  to   { opacity: 1; transform: none; }
}
@keyframes megaVignette {
  from { opacity: 0; transform: scale(1.05); }
  to   { opacity: 1; transform: scale(1); }
}
.nav__item--has-menu.is-open > .mega .mega__lead {
  animation: megaEntree 620ms var(--ease) 120ms both;
}
.nav__item--has-menu.is-open > .mega .mega__card {
  animation: megaEntree 680ms var(--ease) calc(190ms + var(--i, 0) * 90ms) both;
}
.nav__item--has-menu.is-open > .mega .mega__thumb img {
  animation: megaVignette 1200ms var(--ease) calc(190ms + var(--i, 0) * 90ms) both;
}
.nav__item--has-menu.is-open > .mega .mega__links li {
  animation: megaEntree 580ms var(--ease) calc(280ms + var(--i, 0) * 55ms) both;
}
.nav__item--has-menu.is-open > .mega .mega__outro {
  animation: megaEntree 580ms var(--ease) 380ms both;
}
@media (prefers-reduced-motion: reduce) {
  .nav__item--has-menu.is-open > .mega * { animation: none !important; }
}

/* La hauteur d'ouverture est posee par le script, a la hauteur reelle du
   contenu : le plafond ci-dessous ne sert qu'au clavier, quand le script
   n'intervient pas. */
.nav__item--has-menu:focus-within > .mega,
.nav__item--has-menu.is-open > .mega {
  max-height: 78vh;
  visibility: visible;
}

/* Le panneau reste noir. C'est la page derriere qui recule : elle est
   floutee et assombrie, ce qui detache le panneau sans l'eclaircir. */
.mega::after {
  content: "";
  position: fixed;
  inset: 0;
  top: 100%;
  z-index: -1;
  background: rgba(0, 0, 0, 0.72);
  backdrop-filter: blur(6px) saturate(0.8);
  -webkit-backdrop-filter: blur(6px) saturate(0.8);
  pointer-events: none;
  opacity: 0;
  transition: opacity 620ms var(--ease);
}
.nav__item--has-menu.is-open > .mega::after,
.nav__item--has-menu:focus-within > .mega::after { opacity: 1; }

/* En haut de page, l'en-tete doit devenir opaque quand un panneau s'ouvre,
   sinon le contenu de la page transparait derriere la barre. */
.site-header:has(.nav__item--has-menu:focus-within),
.site-header:has(.nav__item--has-menu.is-open) {
  background: var(--gk-black);
  border-bottom-color: rgba(255, 255, 255, 0.14);
}

.mega__inner {
  display: grid;
  grid-template-columns: minmax(0, 4fr) minmax(0, 8fr);
  gap: var(--space-xl);
  padding-block: var(--space-lg);
}
.mega__lead { max-width: 30ch; }
.mega__intro {
  font-size: var(--fs-body);
  line-height: 1.7;
  color: var(--gk-mid-gray);
  margin-block: 0 var(--space-sm);
}

/* Grille de 6 colonnes : la repartition suit le nombre d'entrees, pour ne
   jamais laisser une case vide en bout de ligne. */
.mega__grid {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 1px;
  background: rgba(255, 255, 255, 0.1);
  border: 1px solid rgba(255, 255, 255, 0.1);
}

/* 2 entrees : moitie et moitie */
.mega__grid[data-count="1"] > .mega__card { grid-column: span 6; }
.mega__grid[data-count="2"] > .mega__card { grid-column: span 3; }

/* 3 entrees : trois tiers */
.mega__grid[data-count="3"] > .mega__card { grid-column: span 2; }

/* 4 entrees : deux et deux */
.mega__grid[data-count="4"] > .mega__card { grid-column: span 3; }

/* 5 entrees : les deux modeles en avant sur la premiere ligne,
   les trois pages de reference en tiers sur la seconde. */
.mega__grid[data-count="5"] > .mega__card { grid-column: span 2; }
.mega__grid[data-count="5"] > .mega__card:nth-child(1),
.mega__grid[data-count="5"] > .mega__card:nth-child(2) { grid-column: span 3; }

@media (max-width: 1100px) {
  .mega__grid > .mega__card,
  .mega__grid[data-count="2"] > .mega__card,
  .mega__grid[data-count="3"] > .mega__card,
  .mega__grid[data-count="4"] > .mega__card,
  .mega__grid[data-count="5"] > .mega__card,
  .mega__grid[data-count="5"] > .mega__card:nth-child(1),
  .mega__grid[data-count="5"] > .mega__card:nth-child(2) { grid-column: span 3; }
}

.mega__card {
  position: relative;
  display: block;
  background: var(--gk-black);
  transition: background var(--dur-fast) var(--ease);
}
.mega__card:hover { background: var(--gk-near-black); }

/* La vignette : le produit est visuel, le menu doit l'etre aussi. */
.mega__thumb {
  display: block;
  aspect-ratio: 16 / 10;
  overflow: hidden;
  background: var(--gk-near-black);
}
.mega__thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0.62;
  transform: scale(1.02);
  transition: opacity var(--dur) var(--ease), transform 1200ms var(--ease);
}
.mega__card:hover .mega__thumb img { opacity: 1; transform: scale(1.06); }

/* Vignette claire : pour les rendus produit detoures sur blanc. L'image est
   contenue, jamais rognee, sinon la baguette sortirait du cadrage 16/10. */
.mega__thumb--light { background: var(--gk-white); }
/* Pleine opacite au repos : sur fond blanc, un voile ne fait pas reculer
   l'image, il la delave et donne l'air d'un chargement inacheve. */
.mega__thumb--light img { object-fit: contain; opacity: 1; transform: scale(1); }
.mega__card:hover .mega__thumb--light img { opacity: 1; transform: scale(1.04); }

.mega__body { padding: var(--space-sm); display: grid; gap: 0.55rem; }

.mega__name {
  font-family: var(--font-serif);
  font-size: 1.25rem;
  line-height: 1.12;
  letter-spacing: -0.015em;
  text-transform: none;
  color: var(--gk-white);
}
.mega__desc {
  font-family: var(--font-sans);
  font-size: 0.8125rem;
  line-height: 1.55;
  letter-spacing: 0;
  text-transform: none;
  color: var(--gk-mid-gray);
  max-width: 30ch;
}
.mega__arrow {
  position: absolute;
  top: 0.9rem;
  right: 1rem;
  color: var(--gk-white);
  opacity: 0;
  transform: translateX(-4px);
  transition: opacity var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}
.mega__card:hover .mega__arrow { opacity: 1; transform: translateX(0); }

@media (max-width: 1000px) {
  .nav, .nav__end { display: none; }
  .site-header__inner { grid-template-columns: auto 1fr; }
}

/* ---------- Menu mobile ---------- */
.mobile-nav__inner {
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100%;
  min-height: 0;
}

.mnav {
  list-style: none;
  margin: 0;
  padding: 0;
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}
.mnav__item + .mnav__item { border-top: 1px solid rgba(255, 255, 255, 0.12); }

.mnav__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-xs);
}
.mnav__link {
  display: block;
  flex: 1 1 auto;
  padding: 1.45rem 0;
  font-family: var(--font-serif);
  font-size: 1.5rem;
  line-height: 1.15;
  letter-spacing: -0.015em;
  color: var(--gk-white);
}

/* Le chevron a sa propre cible tactile : ouvrir la rubrique et aller sur sa
   page sont deux intentions differentes, elles meritent deux cibles. */
.mnav__toggle {
  flex: none;
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  color: rgba(255, 255, 255, 0.6);
  background: none;
  border: 0;
}
.mnav__toggle svg {
  width: 12px;
  height: 8px;
  transition: transform var(--dur-fast) var(--ease);
}
.mnav__toggle[aria-expanded="true"] { color: var(--gk-white); }
.mnav__toggle[aria-expanded="true"] svg { transform: rotate(180deg); }

/* Le depliage se joue, il ne saute pas. La hauteur est posee en pixels par
   le script, la transition la conduit ; les liens suivent en decale, du haut
   vers le bas, comme une liste qui se decouvre. Sans JS, l'attribut hidden
   garde le panneau replie. */
.mnav__panel {
  display: grid;
  gap: 0.85rem;
  padding: 0 0 0;
  height: 0;
  overflow: hidden;
  visibility: hidden;
  /* La visibilite bascule aux deux bouts, pas au milieu : visible des le
     premier pixel a l'ouverture, masquee seulement une fois repliee. */
  transition: height 560ms var(--ease),
              padding 560ms var(--ease),
              visibility 0s linear 560ms;
}
.mnav__panel[hidden] { display: none; }
.mnav__panel.is-open {
  visibility: visible;
  padding: 0.2rem 0 1.35rem;
  transition: height 560ms var(--ease),
              padding 560ms var(--ease),
              visibility 0s linear 0s;
}
.mnav__panel a {
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  line-height: 1.3;
  color: rgba(255, 255, 255, 0.62);
  opacity: 0;
  transform: translateY(7px);
  transition: opacity 420ms var(--ease), transform 420ms var(--ease);
}
.mnav__panel.is-open a { opacity: 1; transform: none; }
.mnav__panel.is-open a:nth-child(1) { transition-delay: 110ms; }
.mnav__panel.is-open a:nth-child(2) { transition-delay: 165ms; }
.mnav__panel.is-open a:nth-child(3) { transition-delay: 220ms; }
.mnav__panel.is-open a:nth-child(4) { transition-delay: 275ms; }
.mnav__panel.is-open a:nth-child(5) { transition-delay: 330ms; }
.mnav__panel.is-open a:nth-child(n+6) { transition-delay: 385ms; }

@media (prefers-reduced-motion: reduce) {
  .mnav__panel,
  .mnav__panel a { transition: none; }
  .mnav__panel a { transition-delay: 0s; }
}

/* Le pied reste en bas, hors du defilement de la liste */
.mnav__foot {
  flex: none;
  padding-top: var(--space-sm);
  border-top: 1px solid rgba(255, 255, 255, 0.12);
}
.mnav__cta { display: block; width: 100%; text-align: center; }
.mnav__prefs {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-xs);
  margin-top: var(--space-sm);
}
.mnav__lang {
  font-family: var(--font-sans-ext);
  font-size: var(--fs-eyebrow);
  text-transform: uppercase;
  letter-spacing: 0.2em;
  color: rgba(255, 255, 255, 0.62);
}
/* Dans le pied du menu, la devise est une preference discrete, pas un choix
   a faire : deux petits libelles, l'actif souligne. Les encadres blancs du
   reste du site y prenaient toute la place. */
.mnav__currency { display: flex; gap: 1rem; }
.mnav__currency .prefs__opt {
  padding: 0;
  border: 0;
  background: none;
  font-family: var(--font-sans-ext);
  font-size: var(--fs-eyebrow);
  text-transform: uppercase;
  letter-spacing: 0.2em;
  color: rgba(255, 255, 255, 0.45);
}
.mnav__currency .prefs__opt:hover { background: none; color: var(--gk-white); }
.mnav__currency .prefs__opt.is-on,
.mnav__currency .prefs__opt[aria-pressed="true"] {
  color: var(--gk-white);
  background: none;
  border: 0;
  text-decoration: underline;
  text-underline-offset: 0.35em;
  text-decoration-thickness: 1px;
}

/* --------------------------------------------------------------------------
   26. TABLEAU COMPARATIF
   Il doit rester lisible sur mobile : il defile dans son propre conteneur,
   la page ne part jamais en scroll horizontal.
   -------------------------------------------------------------------------- */
.table-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

.cmp {
  width: 100%;
  min-width: 720px;
  border-collapse: collapse;
  text-align: left;
}
.cmp th, .cmp td {
  padding: 1.1rem 1.2rem;
  border-bottom: 1px solid rgba(0, 0, 0, 0.12);
  vertical-align: top;
  font-size: var(--fs-body);
  line-height: 1.5;
}
.section--dark .cmp th,
.section--dark .cmp td { border-bottom-color: rgba(255, 255, 255, 0.14); }

.cmp thead th {
  font-family: var(--font-sans-ext);
  font-size: var(--fs-eyebrow);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.2em;
  color: var(--muted);
  padding-bottom: 1.3rem;
}
/* Seuls les en-tetes de colonnes portent l'extended : sur une ligne de
   tableau, elle etire la lecture au lieu de la guider. Les criteres gardent
   la graisse pour se distinguer des valeurs, pas la chasse. */
.cmp tbody th {
  font-family: var(--font-sans);
  font-weight: 500;
  color: var(--body-ink);
  white-space: nowrap;
}
.cmp td { color: var(--muted); }

/* La colonne Ginko porte la valeur qui compte : elle est en pleine encre. */
.cmp td.cmp--yes { color: var(--body-ink); }
.cmp tbody tr:hover th,
.cmp tbody tr:hover td { background: rgba(0, 0, 0, 0.03); }
.section--dark .cmp tbody tr:hover th,
.section--dark .cmp tbody tr:hover td { background: rgba(255, 255, 255, 0.03); }

.cmp thead th:nth-child(2),
.cmp tbody td:nth-child(2) { background: rgba(0, 0, 0, 0.04); }
.section--dark .cmp thead th:nth-child(2),
.section--dark .cmp tbody td:nth-child(2) { background: rgba(255, 255, 255, 0.04); }

/* --------------------------------------------------------------------------
   27. HUB DES UNIVERS
   -------------------------------------------------------------------------- */
.universes {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1px;
  background: rgba(255, 255, 255, 0.14);
  border: 1px solid rgba(255, 255, 255, 0.14);
}
@media (max-width: 1100px) { .universes { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 620px)  { .universes { grid-template-columns: 1fr; } }

.universe {
  background: var(--gk-black);
  padding: var(--space-md) var(--space-sm);
  transition: background var(--dur-fast) var(--ease);
  /* Le contenu se cale au milieu de la tuile : les huit textes n'ont pas la
     meme longueur, alignes en haut ils flottaient chacun a sa hauteur. */
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.universe:hover { background: var(--gk-near-black); }
.universe { text-align: center; }
.universe__texte { display: block; }
.universe__texte .eyebrow { display: block; margin-bottom: 1.1rem; }
.universe__titre {
  display: block;
  font-family: var(--font-serif);
  font-size: 1.25rem;
  line-height: 1.25;
  letter-spacing: -0.01em;
  color: var(--gk-white);
  margin-bottom: 0.8rem;
}
.universe__line {
  font-size: var(--fs-body);
  color: var(--muted);
  max-width: 28ch;
  margin-inline: auto;
}

/* --------------------------------------------------------------------------
   28. FRISE
   -------------------------------------------------------------------------- */


/* --------------------------------------------------------------------------
   29. FONDATEURS
   -------------------------------------------------------------------------- */
.person { padding-top: 0; }
.section--light .person, .section--paper .person { border-top-color: rgba(0, 0, 0, 0.16); }
.person h3 { font-size: var(--fs-h3); margin-bottom: 0.5rem; }
.person__role {
  font-family: var(--font-sans-ext);
  font-size: var(--fs-eyebrow);
  text-transform: uppercase;
  letter-spacing: 0.2em;
  color: var(--muted);
  margin-bottom: 1.1rem;
}

/* --------------------------------------------------------------------------
   30. FAQ
   Un accordeon natif : il fonctionne sans JavaScript et reste accessible.
   -------------------------------------------------------------------------- */
.faq { border-top: 1px solid rgba(255, 255, 255, 0.14); }
.section--light .faq { border-top-color: rgba(0, 0, 0, 0.12); }

.faq__item { border-bottom: 1px solid rgba(255, 255, 255, 0.14); }
.section--light .faq__item { border-bottom-color: rgba(0, 0, 0, 0.12); }

.faq__item summary {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-sm);
  padding-block: var(--space-sm);
  cursor: pointer;
  list-style: none;
  font-family: var(--font-serif);
  font-size: var(--fs-h3);
  line-height: 1.2;
  letter-spacing: -0.015em;
  transition: opacity var(--dur-fast) var(--ease);
}
.faq__item summary::-webkit-details-marker { display: none; }
.faq__item summary:hover { opacity: 0.7; }

/* Le signe passe de plus a moins, sans image ni script */
.faq__sign {
  position: relative;
  flex: none;
  width: 12px;
  height: 12px;
  margin-top: 0.4em;
}
.faq__sign::before,
.faq__sign::after {
  content: "";
  position: absolute;
  inset: 0;
  margin: auto;
  background: currentColor;
  transition: transform var(--dur-fast) var(--ease), opacity var(--dur-fast) var(--ease);
}
.faq__sign::before { width: 12px; height: 1px; }
.faq__sign::after  { width: 1px; height: 12px; }
.faq__item[open] .faq__sign::after { transform: rotate(90deg); opacity: 0; }

.faq__answer {
  padding-bottom: var(--space-sm);
  max-width: 62ch;
}
.faq__answer p { color: var(--gk-mid-gray); }
.section--light .faq__answer p { color: var(--gk-charcoal); }

/* --------------------------------------------------------------------------
   31. LES TROIS MOMENTS (pages univers)
   -------------------------------------------------------------------------- */
.moments { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-lg); }
@media (max-width: 900px) { .moments { grid-template-columns: 1fr; gap: var(--space-md); } }

.moment { padding-top: 0; }
.section--dark .moment { border-top-color: rgba(255, 255, 255, 0.2); }
.moment__num {
  font-family: var(--font-serif);
  font-size: 1.125rem;
  color: var(--muted);
  margin-bottom: 1.1rem;
}
.moment h3 { font-size: var(--fs-h3); margin-bottom: 0.9rem; }
.moment__text { font-size: var(--fs-body); color: var(--body-ink); max-width: 34ch; }

/* Les tuiles du hub sont des liens : elles doivent le montrer. */
.universe {
  position: relative;
  display: block;
  color: inherit;
}
/* Une fleche posee dans un coin ne dit pas ou elle mene : le lien se nomme.
   La place qu'il occupe est reservee en permanence, donc la tuile ne change
   jamais de hauteur et la grille ne bouge pas quand on survole. Au repos le
   texte se centre dans la tuile entiere ; a l'arrivee du lien il remonte de
   la moitie de la reserve, et les deux se centrent ensemble. */
.universe { --reserve: calc(1.15rem + var(--space-sm)); }
.universe__texte {
  transform: translateY(calc(var(--reserve) / 2));
  transition: transform 340ms var(--ease);
}
.universe:hover .universe__texte,
.universe:focus-visible .universe__texte { transform: none; }

.universe__voir {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 0.45rem;
  height: 1.15rem;
  margin-top: var(--space-sm);
  font-family: var(--font-sans-ext);
  font-size: var(--fs-eyebrow);
  text-transform: uppercase;
  letter-spacing: 0.18em;
  color: var(--gk-white);
  opacity: 0;
  transition: opacity 260ms var(--ease);
}
.universe__voir i {
  font-style: normal;
  transition: transform var(--dur-fast) var(--ease);
}
.universe:hover .universe__voir,
.universe:focus-visible .universe__voir { opacity: 1; }
.universe:hover .universe__voir i { transform: translateX(3px); }

/* Sans survol, le lien reste ouvert : au doigt, la tuile serait restee muette. */
@media (hover: none) {
  .universe__texte { transform: none; }
  .universe__voir { opacity: 1; }
}

/* ==========================================================================
   32. PAGE D'ACCUEIL
   ========================================================================== */

.hero__actions {
  display: flex;
  align-items: center;
  gap: var(--space-md);
  flex-wrap: wrap;
  margin-top: var(--space-md);
}

/* --------------------------------------------------------------------------
   L'INTERACTION SIGNATURE : LE RAFRAICHISSEMENT ENCRE
   Une dalle e-paper ne fond pas une image dans l'autre. Elle se rafraichit :
   bref eclair, trame grossiere, puis resolution en niveaux de gris.
   C'est ce geste que l'on rejoue a l'apparition, puis plus rien ne bouge,
   parce qu'une image tenue ne consomme rien.
   -------------------------------------------------------------------------- */
.eink { position: relative; overflow: hidden; }
/* Rendu produit : centre et contenu, jamais pleine largeur */
.eink > img { display: block; width: 100%; }

/* Etat de depart : contraste dur et desature, comme une premiere passe */
.eink[data-eink] > img {
  filter: grayscale(1) contrast(2.4) brightness(1.08);
  transform: scale(1.015);
  transition: filter 1400ms var(--ease), transform 1800ms var(--ease);
  will-change: filter, transform;
}
.eink.is-inked > img {
  filter: grayscale(0) contrast(1) brightness(1);
  transform: scale(1);
}

/* La trame : points fins qui se dissolvent, comme le pigment qui se place */
.eink[data-eink]::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background-image: radial-gradient(currentColor 42%, transparent 43%);
  background-size: 4px 4px;
  color: #0a0a0a;
  opacity: 0.9;
  transition: opacity 1200ms var(--ease), background-size 1600ms var(--ease);
}
.section--light .eink[data-eink]::before,
.section--paper .eink[data-eink]::before { color: #f2f2f0; }

.eink.is-inked::before { opacity: 0; background-size: 1px 1px; }

/* L'eclair de rafraichissement, tres bref */
.eink[data-eink]::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  background: var(--gk-white);
  opacity: 0;
}
.section--dark .eink[data-eink]::after { background: var(--gk-black); }
.eink.is-flashing::after { animation: einkFlash 420ms steps(2, end); }

@keyframes einkFlash {
  0%   { opacity: 0; }
  30%  { opacity: 0.55; }
  60%  { opacity: 0.12; }
  100% { opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .eink[data-eink] > img { filter: none; transform: none; transition: none; }
  .eink[data-eink]::before, .eink[data-eink]::after { display: none; }
}

/* --------------------------------------------------------------------------
   CARTES MODELE CLIQUABLES
   -------------------------------------------------------------------------- */
.model-card--link { color: inherit; display: block; }
.model-card--link .model-card__media { display: block; aspect-ratio: 4 / 3; }
.model-card--link .model-card__media img { width: 100%; height: 100%; object-fit: cover; }

.model-card--link .model-card__body {
  display: grid;
  gap: 0.75rem;
  padding: var(--space-md) var(--space-sm) var(--space-md);
}
.model-card--link .eyebrow { margin-bottom: 0; }
.model-card--link .h3 { display: block; }

.model-card__meta {
  font-size: var(--fs-body);
  color: var(--muted);
}

.model-card--link .link-underline { justify-self: start; margin-top: 0.4rem; }

/* Toute la carte repond au survol : l'image avance d'un cran dans son cadre,
   le lien s'allume et sa fleche part. Le pointeur peut etre n'importe ou
   sur la carte, c'est elle qui est cliquable, pas seulement le lien. */
.model-card__media img,
.model-card--link .model-card__media img { transition: transform 1.1s var(--ease-reveal); }
.model-card--link:hover .model-card__media img { transform: scale(1.045); }
.model-card--link .link-underline {
  color: var(--muted, var(--gk-mid-gray));
  transition: color var(--dur-fast) var(--ease);
}
.section--dark .model-card--link:hover .link-underline { color: var(--gk-white); }
.section--light .model-card--link:hover .link-underline,
.section--paper .model-card--link:hover .link-underline { color: var(--gk-black); }
.model-card--link:hover .link-underline::after { transform: translateX(4px); }

/* --------------------------------------------------------------------------
   LES HUIT UNIVERS, EN LISTE
   Une ligne par univers : le nom bascule en encre pleine au survol.
   -------------------------------------------------------------------------- */
.worlds {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 0 var(--space-xl);
  border-top: 1px solid rgba(0, 0, 0, 0.12);
}
@media (max-width: 800px) { .worlds { grid-template-columns: 1fr; gap: 0; } }
.section--dark .worlds { border-top-color: rgba(255, 255, 255, 0.14); }

.world {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-sm);
  padding-block: var(--space-sm);
  border-bottom: 1px solid rgba(0, 0, 0, 0.12);
  font-family: var(--font-serif);
  font-size: var(--fs-h3);
  line-height: 1.1;
  letter-spacing: -0.015em;
  color: var(--muted);
  transition: color var(--dur-fast) var(--ease), padding-left var(--dur-fast) var(--ease);
}
.section--dark .world { border-bottom-color: rgba(255, 255, 255, 0.14); }

.world:hover {
  color: var(--gk-charcoal);
  padding-left: 0.6rem;
}
.section--dark .world:hover { color: var(--gk-white); }

.world i {
  font-style: normal;
  opacity: 0;
  transform: translateX(-6px);
  transition: opacity var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}
.world:hover i { opacity: 1; transform: translateX(0); }

/* --------------------------------------------------------------------------
   33. PARTENAIRES
   En texte, pas en logos : aucun logo tiers ne peut etre publie sans accord
   ecrit, et les formulations retenues sont celles validees commercialement.
   -------------------------------------------------------------------------- */


/* --------------------------------------------------------------------------
   34. LIENS TEXTE DU PANNEAU
   Toutes les entrees ne meritent pas une carte. Les pages de reference
   vivent en liste, a gauche, sous l'intro.
   -------------------------------------------------------------------------- */
.mega__links {
  list-style: none;
  padding: 0;
  margin: var(--space-sm) 0 0;
  display: grid;
  gap: 0.15rem;
}
/* Les filets ne servent qu'a separer : un trait au-dessus du premier et un
   autre sous le dernier fermaient la liste comme un tableau. */
.mega__links li + li { border-top: 1px solid rgba(255, 255, 255, 0.12); }
.mega__links a {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-xs);
  padding-block: 0.85rem;
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  letter-spacing: 0;
  text-transform: none;
  color: rgba(255, 255, 255, 0.78);
  transition: color var(--dur-fast) var(--ease), padding-left var(--dur-fast) var(--ease);
}
.mega__links a:hover { color: var(--gk-white); padding-left: 0.45rem; }
.mega__links i {
  font-style: normal;
  opacity: 0.45;
  transition: opacity var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}
.mega__links a:hover i { opacity: 1; transform: translateX(3px); }

/* Le "Tout voir" respire sous la liste et se lit comme une action a part */
.mega__lead .link-underline { display: inline-block; margin-top: 1.4rem; }

/* Le lien vers la rubrique est la premiere entree de la liste : meme filet,
   meme rythme. Seule sa couleur pleine dit que c'est la destination
   principale ; une typographie a part l'aurait sorti de l'alignement. */
.mega__links--tout a { color: var(--gk-white); }
.mega__links--tout i { opacity: 0.8; }

/* Avec deux cartes seulement, la colonne de gauche peut respirer davantage. */
.mega__inner { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); }

/* --------------------------------------------------------------------------
   35. DECLARATION ET ARGUMENTS
   Une affirmation qui porte, puis les faits qui la soutiennent.
   Le recit a la troisieme personne sonnait anecdotique : ici la phrase
   fait le travail, et les colonnes donnent la matiere commerciale.
   -------------------------------------------------------------------------- */
.statement {
  font-family: var(--font-serif);
  font-size: var(--fs-hero);
  font-weight: 300;
  line-height: 1.08;
  letter-spacing: -0.02em;
  max-width: 22ch;
  text-wrap: balance;
}
.statement em {
  font-style: italic;
  color: var(--muted);
}

/* --------------------------------------------------------------------------
   LA SCENE
   Trois colonnes de gris se lisaient en diagonale, donc pas du tout. Ici la
   phrase que les gens prononcent vraiment devant le cadre passe devant, en
   serif et en grand ; l'explication la suit, discrete. On s'arrete sur une
   phrase entendue, pas sur un intertitre qui la resume.
   -------------------------------------------------------------------------- */
/* La phrase d'ouverture et son bouton se partagent la ligne : le bouton
   n'attend plus la fin de la scene pour se montrer, et la phrase dispose de
   la largeur qu'il lui faut pour tenir en deux lignes. */
.reaction__tete {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--space-lg) var(--space-xl);
  flex-wrap: wrap;
}
.reaction__tete .statement { max-width: 30ch; }
.reaction__cta { flex: none; margin: 0; }
@media (max-width: 860px) {
  .reaction__tete { align-items: flex-start; }
  .reaction__tete .statement { max-width: 22ch; }
}

.scene {
  list-style: none;
  /* La phrase d'ouverture a besoin de respirer avant que la scene commence :
     le premier filet ne doit pas venir la souligner. */
  margin: var(--space-2xl) 0 0;
  padding: 0;
}
.scene__temps {
  display: grid;
  grid-template-columns: 4rem minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--space-md) var(--space-lg);
  align-items: baseline;
  padding-block: var(--space-lg);
  border-top: 1px solid rgba(0, 0, 0, 0.14);
}
/* Aucun filet sous le dernier temps : la scene se termine, elle ne referme
   pas un tableau. */
.section--dark .scene__temps { border-top-color: rgba(255, 255, 255, 0.16); }

.scene__num {
  font-family: var(--font-sans-ext);
  font-size: var(--fs-eyebrow);
  font-weight: 500;
  letter-spacing: 0.2em;
  color: var(--muted);
}
.scene__dit {
  font-family: var(--font-serif);
  font-size: clamp(1.375rem, 2.4vw, 1.875rem);
  line-height: 1.2;
  letter-spacing: -0.015em;
  text-wrap: balance;
}
.scene__note {
  font-size: var(--fs-body);
  line-height: 1.8;
  color: var(--muted);
  max-width: 38ch;
}

@media (max-width: 900px) {
  .scene__temps {
    grid-template-columns: 1fr;
    gap: 0.9rem;
    padding-block: var(--space-md);
  }
  .scene__note { max-width: none; }
}

/* --------------------------------------------------------------------------
   36. CARTES PARTENAIRES A TRAME DE POINTS
   Reprise fidele de la page de tests d'origine. Le logo est un SVG injecte
   inline par hovercards.js (data-svg-path) et trace en contour blanc 0.5px.
   Au survol : la trame WebGL s'allume dans la couleur de la carte, le trait
   du logo prend cette couleur et se remplit, le logo zoome, le nom apparait.
   -------------------------------------------------------------------------- */
.ginko-hovercards {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-sm);
}
@media (max-width: 900px) { .ginko-hovercards { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .ginko-hovercards { grid-template-columns: 1fr; } }

.hover-card {
  position: relative;
  aspect-ratio: 16 / 10;
  overflow: hidden;
  background: #09090b;          /* le JS pose les memes valeurs, on evite le flash */
  border: 1px solid #111;
  transition: border-color 300ms ease;
}

.hover-card .depth-background,
.hover-card .canvas-container,
.hover-card .gradient-mask-center,
.hover-card .gradient-mask-bottom {
  position: absolute;
  inset: 0;
  display: block;
  pointer-events: none;
}
.hover-card .canvas-container { z-index: 1; }
.hover-card .canvas-container canvas {
  width: 100% !important;
  height: 100% !important;
  display: block;
}
.hover-card .depth-background {
  background: radial-gradient(60% 60% at 50% 42%, rgba(255, 255, 255, 0.05), transparent 72%);
}
.hover-card .gradient-mask-center {
  z-index: 2;
  background: radial-gradient(circle at 50% 50%, transparent 0%, rgba(9, 9, 11, 0.85) 78%);
}
.hover-card .gradient-mask-bottom {
  z-index: 2;
  background: linear-gradient(to top, #09090b 0%, transparent 42%);
}

.hover-card .card-content {
  position: absolute;
  inset: 0;
  z-index: 10;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  /* Padding symetrique : le nom ne s'affiche plus sous le logo, rien ne
     doit plus decaler le centrage. */
  padding: var(--space-md);
  transition: transform 300ms ease;
}

/* Le logo, injecte inline : contour blanc fin, rempli en couleur au survol */
.hover-card .icon-container {
  width: 58%;
  max-width: 240px;
  height: 60px;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: visible;
  transform: scale(1);
  transition: transform 300ms ease;
}
.hover-card:hover .icon-container { transform: scale(1.15); }

.hover-card .icon-container svg {
  width: 100%;
  height: 100%;
  overflow: visible;
}
.hover-card .icon-container path,
.hover-card .icon-container circle,
.hover-card .icon-container rect,
.hover-card .icon-container polygon,
.hover-card .icon-container polyline,
.hover-card .icon-container ellipse,
.hover-card .icon-container line {
  fill: var(--svg-fill-color, transparent) !important;
  stroke: var(--svg-stroke-color, #ffffff) !important;
  stroke-width: 1.1px !important;
  vector-effect: non-scaling-stroke !important;
  transition: fill 300ms ease, stroke 300ms ease !important;
}
/* Au repos, le contour se lit sans effort ; au survol il s'affirme. */
.hover-card .icon-container {
  opacity: 0.72;
  transition: opacity 300ms ease, transform 300ms ease;
}
.hover-card:hover .icon-container { opacity: 1; }
.hover-card:hover .icon-container path,
.hover-card:hover .icon-container circle,
.hover-card:hover .icon-container rect,
.hover-card:hover .icon-container polygon,
.hover-card:hover .icon-container polyline,
.hover-card:hover .icon-container ellipse,
.hover-card:hover .icon-container line { stroke-width: 1.4px !important; }

/* Le nom, sous le logo, seulement au survol */
.hover-card .card-title {
  position: relative;
  margin-top: 0.9rem;
  font-family: var(--font-sans-ext);
  font-size: var(--fs-eyebrow);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.2em;
  color: var(--gk-white);
  opacity: 0;
  transition: opacity 300ms ease;
  white-space: nowrap;
}
.hover-card:hover .card-title { opacity: 1; }

/* La quatrieme case reste muette : elle annonce sans rien promettre. */

/* --------------------------------------------------------------------------
   37. VUE ECLATEE, SEQUENCE AU SCROLL
   L'objet se demonte a mesure qu'on descend. Le visuel est colle pendant
   que le texte defile a cote : on comprend l'assemblage sans quitter la page.
   -------------------------------------------------------------------------- */
/* La section doit etre nettement plus haute que l'ecran, sinon la sequence
   n'a pas de course : le visuel colle change de frame pendant que le texte
   defile a cote. */
/* Vue eclatee.
   La section est haute par necessite : sa hauteur est la duree de la
   sequence. Mais seule l'image tenait au scroll, le texte s'arretait au bout
   d'un ecran et les deux suivants restaient vides. C'est desormais le bloc
   entier qui reste colle, image et texte ensemble : on ne descend plus dans
   du vide, on regarde l'objet se defaire. */
.exploded {
  min-height: 240vh;
  position: relative;
  padding-block: 0;
}
@media (max-width: 1000px) { .exploded { min-height: 0; padding-block: var(--space-2xl); } }

.exploded__inner {
  position: sticky;
  top: 0;
  /* Hauteur exacte de la fenetre : le bloc colle doit tenir en entier, sinon
     son bas, bouton compris, reste hors d'atteinte pendant toute la
     sequence. */
  height: 100vh;
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
  gap: var(--space-lg) var(--space-xl);
  align-items: center;
  padding-block: var(--space-md);
}
@media (max-width: 1000px) {
  .exploded__inner {
    position: static;
    min-height: 0;
    grid-template-columns: 1fr;
    gap: var(--space-lg);
    padding-block: 0;
  }
}

.exploded__stage { display: flex; justify-content: center; align-items: center; }

.exploded__canvas {
  width: 100%;
  max-width: 480px;
  height: auto;
  display: block;
}

.exploded__text { padding-block: 0; }

/* Ecran court : le bloc ne tiendrait pas dans la fenetre, on renonce au
   collage plutot que de rogner le texte. */
@media (max-height: 780px) {
  .exploded { min-height: 0; padding-block: var(--space-2xl); }
  .exploded__inner { position: static; height: auto; padding-block: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .exploded { min-height: 0; padding-block: var(--space-2xl); }
  .exploded__inner { position: static; height: auto; padding-block: 0; }
}


/* Le selecteur de devise en pied de section garde son ancienne allure */


/* --------------------------------------------------------------------------
   39. PANNEAU DE PREFERENCES : REGION ET DEVISE
   Un seul bouton dans le header, un petit panneau dessous. La region est un
   vrai lien (suivi par les moteurs), la devise un bouton memorise.
   -------------------------------------------------------------------------- */
.prefs { position: relative; }

.prefs__btn {
  display: inline-flex;
  align-items: center;
  gap: 0.55em;
  font-family: var(--font-sans-ext);
  font-size: var(--fs-eyebrow);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  line-height: 1;
  padding: 0.72em 0;
  border: 0;
  background: transparent;
  color: var(--gk-mid-gray);
  transition: color var(--dur-fast) var(--ease);
}
.prefs__btn:hover,
.prefs__btn[aria-expanded="true"] { color: var(--gk-white); }
.prefs__btn[aria-expanded="true"] .nav__chev { transform: rotate(180deg); }

/* La modale : le site reste visible derriere, flou, sous un voile noir 60 % */
.prefs-modal {
  position: fixed;
  inset: 0;
  z-index: 300;
  display: grid;
  place-items: center;
  padding: 1.5rem;
  background: rgba(0, 0, 0, 0.6);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--dur-fast) var(--ease), visibility var(--dur-fast);
}
.prefs-modal.is-open { opacity: 1; visibility: visible; }

.prefs-modal__dialog {
  position: relative;
  width: min(400px, 100%);
  background: var(--gk-near-black, #0a0a0a);
  border: 1px solid rgba(255, 255, 255, 0.14);
  padding: 2.2rem 2.2rem 2.4rem;
  transform: translateY(10px);
  transition: transform var(--dur-med, 0.4s) var(--ease);
}
.prefs-modal.is-open .prefs-modal__dialog { transform: none; }

.prefs-modal__close {
  position: absolute;
  top: 1.05rem;
  right: 1.05rem;
  display: grid;
  place-items: center;
  width: 2rem;
  height: 2rem;
  color: var(--gk-mid-gray);
  background: transparent;
  border: 0;
  transition: color var(--dur-fast) var(--ease);
}
.prefs-modal__close:hover { color: var(--gk-white); }
.prefs-modal__close svg { width: 12px; height: 12px; }

.prefs__label {
  font-family: var(--font-sans-ext);
  font-size: 0.5625rem;
  text-transform: uppercase;
  letter-spacing: 0.22em;
  color: var(--muted);
  margin: 0 0 0.55rem;
}
.prefs__group { display: grid; gap: 1px; margin-bottom: 1.1rem; }
.prefs__group:last-child { margin-bottom: 0; }
.prefs__group[role="group"] { grid-template-columns: 1fr 1fr; }

.prefs__opt {
  display: block;
  text-align: left;
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  letter-spacing: 0;
  text-transform: none;
  padding: 0.6rem 0.7rem;
  color: var(--gk-mid-gray);
  border: 1px solid rgba(255, 255, 255, 0.1);
  background: transparent;
  transition: color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
.prefs__opt:hover { color: var(--gk-white); background: rgba(255, 255, 255, 0.05); }
.prefs__opt.is-on,
.prefs__opt[aria-pressed="true"] {
  color: var(--gk-black);
  background: var(--gk-white);
  border-color: var(--gk-white);
}


/* --------------------------------------------------------------------------
   40. DISCIPLINE TYPOGRAPHIQUE
   Area Inktrap Extended est reservee aux eyebrows : tres courts, uppercase,
   traques. Partout ou le texte peut s'allonger (boutons, titres de cartes,
   badges), on redescend sur Area Inktrap regular.
   -------------------------------------------------------------------------- */
.btn,
.link-underline,
.nav__cta,
.plan__cta { font-family: var(--font-sans-ext); font-weight: 500; }

/* Exception : un lien pose dans une phrase garde la police de la phrase.
   L'Extended est reservee aux libelles courts, pas au fil du texte. */
.link-inline { font-family: inherit; font-weight: inherit; letter-spacing: inherit; }

h4, .h4,
.step__title { font-family: var(--font-sans); font-weight: 400; }

/* Le titre de la newsletter est une phrase, pas un label */


/* --------------------------------------------------------------------------
   41. LE CHAMP OUVERT DES ESPACES
   La cible ne se compte pas : les pages detaillees sont des exemples, la
   liste ouverte et la signature disent que le champ continue.
   -------------------------------------------------------------------------- */
.spaces-open { max-width: 52ch; margin-inline: auto; text-align: center; }
.spaces-open__words {
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  line-height: 2;
  color: var(--muted);
}
.spaces-open__line {
  font-family: var(--font-serif);
  font-size: var(--fs-h3);
  line-height: 1.2;
  letter-spacing: -0.015em;
  color: var(--gk-white);
  margin-top: var(--space-sm);
}

/* La fin de la liste : la phrase qui ferme le propos passe devant, la liste
   des autres lieux la suit en petit, et un lien mene a l'ensemble. Les deux
   lignes se disputaient l'attention en bas a gauche, dans deux typographies
   differentes et sans hierarchie. */
.worlds__fin {
  margin-top: var(--space-xl);
  padding-top: var(--space-lg);
  border-top: 1px solid rgba(0, 0, 0, 0.12);
  display: grid;
  justify-items: center;
  text-align: center;
}
.worlds__silence {
  font-family: var(--font-serif);
  font-size: clamp(1.5rem, 2.8vw, 2.125rem);
  line-height: 1.15;
  letter-spacing: -0.015em;
  max-width: 24ch;
}
.worlds__more {
  margin-top: var(--space-sm);
  max-width: 52ch;
  font-size: var(--fs-body);
  line-height: 1.8;
  color: var(--muted);
}
.worlds__cta { margin-top: var(--space-md); }
.section--dark .worlds__more .worlds__silence { color: var(--gk-white); }

.mega__outro {
  margin-top: 1.1rem;
  font-size: var(--fs-caption);
  font-family: var(--font-serif);
  font-style: normal;
  color: rgba(255, 255, 255, 0.55);
}

/* --------------------------------------------------------------------------
   42. FORMULES STUDIO : LISIBLES ET VIVANTES
   Un filtre eclaire la formule qui correspond au mode d'acquisition. La
   carte Pro (voie la plus courante) s'inverse en blanc. L'heritage
   "Tout X, et en plus" devient une chip, chaque carte a son action.
   -------------------------------------------------------------------------- */
.plan {
  position: relative;
  transition: transform var(--dur-fast) var(--ease),
              border-color var(--dur-fast) var(--ease),
              opacity var(--dur-fast) var(--ease),
              box-shadow var(--dur-fast) var(--ease);
}
.plan:hover { transform: translateY(-3px); border-color: rgba(0, 0, 0, 0.4); }
.section--dark .plan:hover { border-color: rgba(255, 255, 255, 0.45); }

/* La formule des flottes multi-sites : inversee, c'est elle qu'on montre */
.section--light .plan--featured, .section--paper .plan--featured {
  background: var(--gk-black);
  border-color: var(--gk-black);
  color: var(--gk-off-white, #f5f5f4);
}
.section--light .plan--featured .plan__badge,
.section--paper .plan--featured .plan__badge { color: rgba(255, 255, 255, 0.6); }
.section--light .plan--featured .check-list li,
.section--paper .plan--featured .check-list li { color: rgba(255, 255, 255, 0.82); }
.section--dark .plan--featured {
  background: var(--gk-white);
  border-color: var(--gk-white);
  color: var(--gk-black);
}
.section--dark .plan--featured .plan__badge { color: rgba(0, 0, 0, 0.55); }
.section--dark .plan--featured .check-list li { color: rgba(0, 0, 0, 0.8); }

/* Une ligne, pas une pastille encadree : le filet lui donnait l'air d'un
   champ de saisie vide au milieu de la carte. */
.plan__inherit {
  font-family: var(--font-sans);
  font-size: var(--fs-caption);
  color: var(--muted);
  border-top: 1px solid rgba(128, 128, 128, 0.22);
  padding-top: var(--space-xs);
}
.plan--featured .plan__inherit { color: inherit; opacity: 0.7; }

.plan__cta {
  margin-top: auto;
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  color: inherit;
  border-top: 1px solid rgba(128, 128, 128, 0.25);
  padding-top: var(--space-xs);
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  transition: letter-spacing var(--dur-fast) var(--ease);
}
.plan__cta span { transition: transform var(--dur-fast) var(--ease); display: inline-block; }
.plan__cta:hover span { transform: translateX(4px); }

/* Panneau Spaces : la page hub en grand, les sous-pages en liens egaux */
.mega__inner--feature {
  display: grid;
  grid-template-columns: minmax(0, 3fr) minmax(0, 5fr) minmax(0, 4fr);
  gap: var(--space-xl);
  align-items: start;
}
.mega__card--feature { display: flex; flex-direction: column; }
.mega__card--feature .mega__thumb { aspect-ratio: 16 / 10; }
.mega__card--feature .mega__name {
  font-size: var(--fs-h3);
}
.mega__inner--feature .mega__links { margin-top: 0; }
.mega__inner--feature .mega__outro { margin-top: 1.4rem; }


/* Les ajouts de chaque formule : marques d'un +, pas d'une coche */
.check-list--plus li.plus { display: flex; gap: 0.6rem; align-items: baseline; }
.plus__mark {
  font-family: var(--font-serif);
  font-size: 1.1em;
  line-height: 1;
  flex: none;
}


/* --------------------------------------------------------------------------
   43. LABELS FLOTTANTS
   Le libelle attend a la place du texte ; au focus ou une fois rempli,
   il monte et devient le titre du champ. Les selects gardent leur titre
   fixe : ils ont toujours une valeur affichee.
   -------------------------------------------------------------------------- */
.field:has(:where(input[placeholder], textarea[placeholder])) {
  position: relative;
  padding-top: 1.3rem;
  gap: 0;
}
/* Un libelle reste un libelle, en bas comme en haut : meme fonte, meme
   capitale, meme interlettrage. Il changeait de famille et de casse en
   montant, et l'on croyait lire deux mots differents. Seuls la taille, la
   place et la couleur bougent. */
.field:has(:where(input[placeholder], textarea[placeholder])) > label {
  position: absolute;
  left: 0;
  top: 2rem;
  font-family: var(--font-sans-ext);
  /* En capitales interlettrees, un libelle prend beaucoup plus de place qu'en
     bas de casse : au corps du texte courant il ecrasait le champ. */
  font-size: 0.6875rem;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  color: var(--muted);
  pointer-events: none;
  transition: top var(--dur-fast) var(--ease), font-size var(--dur-fast) var(--ease),
              color var(--dur-fast) var(--ease);
}
.field:has(input[placeholder]):focus-within > label,
.field:has(textarea[placeholder]):focus-within > label,
.field:has(input[placeholder]:not(:placeholder-shown)) > label,
.field:has(textarea[placeholder]:not(:placeholder-shown)) > label {
  top: 0 !important;
  font-size: 0.625rem !important;
}
.field:has([placeholder]):focus-within > label { color: var(--gk-white); }
.section--light .field:has([placeholder]):focus-within > label { color: var(--gk-black); }

/* --------------------------------------------------------------------------
   44. LE FOOTER
   La newsletter vit dans un cadre Ginko : une baguette fine, un
   passe-partout, le contenu comme un tirage. En pied de page, le wordmark
   geant tronque se remplit d'encre a l'apparition, lettre apres lettre.
   -------------------------------------------------------------------------- */
.site-footer { overflow: hidden; padding-bottom: 0; }


/* --------------------------------------------------------------------------
   45. L'INTRO
   La video hero en plein ecran a l'arrivee sur le site, une fois par
   session. Un pourcentage de chargement, le son au choix, un passage
   possible. Le site apparait quand la video se termine.
   -------------------------------------------------------------------------- */
.intro {
  position: fixed;
  inset: 0;
  z-index: 500;
  /* L'image d'attente est posee sur le fond : si la video tarde ou refuse de
     partir -- economiseur de batterie iOS, connexion lente -- le visiteur voit
     une photographie du produit, pas un ecran noir qui a l'air casse. */
  background: var(--gk-black) url("/assets/img/tech/hero-poster-1280.webp") center / cover no-repeat;
  transition: opacity 0.9s var(--ease), visibility 0.9s;
}
.intro.is-done { opacity: 0; visibility: hidden; pointer-events: none; }
.intro__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 0.8s var(--ease);
}
.intro.is-playing .intro__video { opacity: 1; }
.intro.is-ready .intro__pct { opacity: 0; }

.intro__bar {
  position: absolute;
  left: clamp(1.5rem, 5vw, 4rem);
  right: clamp(1.5rem, 5vw, 4rem);
  bottom: clamp(1.3rem, 4vh, 2.6rem);
  display: flex;
  justify-content: space-between;
  align-items: baseline;
}
.intro__ctl {
  font-family: var(--font-sans-ext);
  font-size: 0.6875rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--gk-white);
  background: transparent;
  border: 0;
  padding: 0.55rem 0;
  /* La video peut etre claire sous les commandes : une ombre portee les
     detache sans ajouter de cadre. */
  text-shadow: 0 1px 14px rgba(0, 0, 0, 0.9), 0 0 34px rgba(0, 0, 0, 0.7);
  transition: opacity var(--dur-fast) var(--ease);
}
.intro__ctl:hover { opacity: 0.72; }

/* Deux voiles d'encre en pied d'ecran, sous les commandes */
.intro::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 34vh;
  pointer-events: none;
  background: linear-gradient(to top,
    rgba(0, 0, 0, 0.92) 0%,
    rgba(0, 0, 0, 0.55) 42%,
    rgba(0, 0, 0, 0) 100%);
}
.intro__bar { z-index: 2; }
.intro__pct {
  z-index: 2;
  text-shadow: 0 1px 14px rgba(0, 0, 0, 0.9);
}

/* --------------------------------------------------------------------------
   46. INK, NOT LIGHT : DANS L'ENCRE
   Les capsules en fond de section, pleine largeur, voilees pour la
   lisibilite. Le texte est pose dessus, l'image respire en parallaxe.
   -------------------------------------------------------------------------- */
.ink-hero {
  position: relative;
  overflow: hidden;
  min-height: 88vh;
  display: flex;
  align-items: center;
  padding-block: var(--space-xxl, 8rem);
  background: var(--gk-black);
  color: var(--gk-white);
}
.ink-hero__bg { position: absolute; inset: -10% 0; z-index: 0; }
.ink-hero__bg img,
.ink-hero__video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.ink-hero__veil {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(90deg, rgba(0, 0, 0, 0.86) 0%, rgba(0, 0, 0, 0.55) 48%, rgba(0, 0, 0, 0.2) 100%),
    linear-gradient(0deg, rgba(0, 0, 0, 0.55) 0%, rgba(0, 0, 0, 0) 34%);
}
.ink-hero__content {
  position: relative;
  z-index: 1;
  width: 100%;
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
  gap: var(--space-xl);
  align-items: start;
}
@media (max-width: 900px) {
  .ink-hero__content { grid-template-columns: 1fr; gap: var(--space-lg); }
}

/* Version chapeau de page : elle passe sous la barre fixe, et son intertitre
   accompagne le titre dans la meme colonne. */
.ink-hero--page { padding-top: calc(var(--space-2xl) + 5rem); }
.ink-hero__tete .eyebrow { color: rgba(255, 255, 255, 0.6); margin-bottom: var(--space-sm); }
.ink-hero__tete .ink-hero__title { margin: 0; }

.ink-hero__prose {
  max-width: 56ch;
  align-self: start;
  margin-top: clamp(3.5rem, 10vh, 8rem);
  font-size: 0.8125rem;
}
.ink-hero__prose p + p { margin-top: 1.4em; }
.ink-hero__prose p { color: rgba(255, 255, 255, 0.82); font-size: 0.8125rem; line-height: 1.75; }
/* Le lien de fin se detache de la prose : c'est une action, pas une phrase */
.ink-hero__prose p:has(.link-underline) { margin-top: var(--space-md); }
/* Le bouton n'appartient pas au paragraphe : il lui faut son propre recul.
   Le selecteur reprend le conteneur, sinon ".ink-hero__prose p + p" le
   remporte -- deux elements pesent plus qu'un -- et le bouton se retrouve a
   19,5 px, colle au texte comme une phrase de plus. */
.ink-hero__prose p.ink-hero__cta { margin-top: 40px; }


/* --------------------------------------------------------------------------
   47. ACCESSIBILITE AA : FOCUS VISIBLE ET CONTRASTES
   Ajouts seulement, aucune regle precedente n'est reecrite : ce qui suit
   gagne par la cascade ou par la specificite. Un seul anneau de focus pour
   tout le site : 2px, decale de 3px, bords droits comme le reste. L'anneau
   se pose autour de l'element, donc sur le fond de la section : sa couleur
   suit la section (blanc sur sombre, noir sur clair), pas l'element.
   -------------------------------------------------------------------------- */

/* Renforce l'anneau global de la section 3 : 1px currentColor etait trop
   fin, et gris sur les liens attenues (.crumbbar, .footer-nav, --muted). */
:focus-visible {
  outline: 2px solid var(--gk-white);
  outline-offset: 3px;
}

/* Sections claires : l'anneau passe a l'encre noire. */
.section--light :focus-visible,
.section--paper :focus-visible {
  outline-color: var(--gk-black);
}

/* Les champs n'ont pas d'anneau : l'encadre casse la finesse du trait.
   Le focus reste signale par le soulignement qui passe au blanc, par le
   libelle qui monte, et par le trait epaissi ci-dessous. */
.field input:focus-visible,
.field select:focus-visible,
.field textarea:focus-visible {
  outline: none;
  border-bottom-width: 2px;
  border-bottom-color: var(--gk-white);
}
.section--light .field input:focus-visible,
.section--light .field select:focus-visible,
.section--light .field textarea:focus-visible,
.section--paper .field input:focus-visible,
.section--paper .field select:focus-visible,
.section--paper .field textarea:focus-visible {
  border-bottom-color: var(--gk-black);
}

/* Le lien d'evitement et les elements sur fond blanc dans une page noire
   (CTA du header, option active de la modale) : l'anneau decale tombe sur
   le fond sombre autour, le blanc global convient. Rien a surcharger. */

/* Contraste : les commandes de l'intro flottent sur la video, dont certains
   plans sont tres clairs. On monte l'encre (0.72 vers 0.85) et on pose une
   ombre discrete qui garantit la lecture quel que soit le plan. */
.intro__ctl {
  color: rgba(255, 255, 255, 0.85);
  text-shadow: 0 1px 10px rgba(0, 0, 0, 0.55);
}

/* Contraste : la legende du bandeau encre etait a 0.5 d'opacite sur une
   image voilee, environ 5.3:1 sur noir pur mais sans garantie sur les zones
   les moins voilees. 0.72 tient AA avec de la marge sans changer le ton. */


/* --------------------------------------------------------------------------
   48. SPECS SANS CADRES
   Les grilles de caracteristiques respirent : pas de cellules, pas de
   filets, la valeur en serif un peu plus grande. Elles apparaissent en un
   seul fondu, sans cascade ni glissement.
   -------------------------------------------------------------------------- */
.specs [data-reveal],
.specs[data-reveal] {
  transform: none !important;
  transition-delay: 0ms !important;
  transition-duration: 0.9s;
}


/* --------------------------------------------------------------------------
   50. LA FICHE TECHNIQUE
   /specifications/ se lit comme une notice : groupes en deux colonnes,
   rangees libelle / valeur compactes, filets a peine poses. Chaque groupe
   apparait en un seul fondu.
   -------------------------------------------------------------------------- */
.sheet { border-top: 1px solid rgba(255, 255, 255, 0.16); }
.sheet__group {
  display: grid;
  grid-template-columns: minmax(0, 4fr) minmax(0, 8fr);
  gap: var(--space-sm) var(--space-xl);
  padding-block: var(--space-md);
  border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
@media (max-width: 780px) { .sheet__group { grid-template-columns: 1fr; } }
.sheet__title {
  font-family: var(--font-sans-ext);
  font-size: var(--fs-eyebrow);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.2em;
  color: var(--muted);
  padding-top: 0.6rem;
}
.sheet__rows { margin: 0; }
.sheet__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--space-sm);
  padding-block: 0.6rem;
}
.sheet__row + .sheet__row { border-top: 1px solid rgba(255, 255, 255, 0.07); }
.sheet__row dt { color: var(--muted); font-size: var(--fs-body); }
.sheet__row dd { font-size: var(--fs-body); color: rgba(255, 255, 255, 0.92); }
.sheet__group[data-reveal] { transform: none; transition-duration: 0.9s; }
.sheet__group[data-reveal].is-visible { transform: none; }

/* Cartes partenaires : le logo suffit, pas de nom au survol */
.ginko-hovercards .card-title { display: none; }


/* --------------------------------------------------------------------------
   52. FOOTER, QUATRIEME LECTURE : LA COMPOSITION DE STUDIO
   Trois zones sur une ligne : newsletter typographique, navigation
   serree, cartouche atelier avec l'heure de Paris. En cloture, une fine
   trame d'encre qui s'imprime. Rien ne crie.
   -------------------------------------------------------------------------- */


.footer-legal a { color: inherit; transition: color var(--dur-fast) var(--ease); }
.footer-legal a:hover { color: var(--gk-white); }


/* --------------------------------------------------------------------------
   53. FOOTER, REPRISE DE L'ORIGINAL : DEUX MATIERES
   L'encre a gauche, le papier a droite. Le panneau clair de la newsletter
   posé sur le noir : c'est la signature du footer d'origine. Il deborde
   legerement vers le haut, comme une feuille glissee sur la page.
   -------------------------------------------------------------------------- */

.site-footer { padding: 0; overflow: visible; }


.footer-legal a { color: inherit; transition: color var(--dur-fast) var(--ease); }
.footer-legal a:hover { color: var(--gk-white); }

/* Le papier : le panneau clair, seule zone lumineuse du pied de page */


/* --------------------------------------------------------------------------
   54. FOOTER PLEIN ECRAN
   Le footer occupe un ecran entier et absorbe la derniere invitation. Un
   cadre Ginko en fond sous un voile d'encre, la phrase du mur au centre,
   et quatre zones indexees en pied, comme le sommaire d'un dossier.
   -------------------------------------------------------------------------- */

.footer-full {
  position: relative;
  min-height: 100svh;
  display: flex;
  overflow: hidden;
  padding: 0;
  background: var(--gk-black);
}
.footer-full__bg { position: absolute; inset: 0; z-index: 0; }
.footer-full__bg img { width: 100%; height: 100%; object-fit: cover; opacity: 0.5; }
.footer-full__bg::after {
  content: "";
  position: absolute;
  inset: 0;
  /* L'image se devoile derriere l'invitation, puis s'efface sous le plan
     du site, qui doit rester parfaitement lisible. */
  background:
    linear-gradient(180deg,
      rgba(0, 0, 0, 0.55) 0%,
      rgba(0, 0, 0, 0.3) 24%,
      rgba(0, 0, 0, 0.48) 46%,
      rgba(0, 0, 0, 0.9) 62%,
      rgba(0, 0, 0, 0.97) 78%),
    linear-gradient(90deg, rgba(0, 0, 0, 0.42) 0%, rgba(0, 0, 0, 0.08) 50%, rgba(0, 0, 0, 0.42) 100%);
}
.footer-full__inner {
  position: relative;
  z-index: 1;
  width: min(100% - 3rem, var(--wrap));
  margin-inline: auto;
  padding-block: clamp(3rem, 7vh, 5rem) clamp(1.2rem, 3vh, 2rem);
  display: grid;
  grid-template-rows: 1fr auto auto;
  gap: clamp(1.6rem, 4vh, 3rem);
  align-items: center;
}

/* La phrase du mur, au centre de l'ecran */
.footer-say {
  text-align: center;
  align-self: center;
  padding-block: clamp(3rem, 8vh, 6rem);
}
.footer-say__title {
  font-family: var(--font-serif);
  font-size: clamp(1.9rem, 4.2vw, 3.4rem);
  line-height: 1.08;
  letter-spacing: -0.02em;
  max-width: 20ch;
  margin-inline: auto;
}

/* Les zones indexees, comme un sommaire */
.footer-index {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: var(--space-sm);
  align-items: start;
  /* Le sommaire respire autant au-dessus qu'en dessous, sous un filet
     qui separe l'invitation du plan du site. */
  margin-block: clamp(3rem, 8vh, 6rem);
  padding-top: clamp(3rem, 8vh, 6rem);
  border-top: 1px solid rgba(255, 255, 255, 0.16);
}
@media (max-width: 1100px) { .footer-index { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 700px)  { .footer-index { grid-template-columns: 1fr 1fr; } }
@media (max-width: 440px)  { .footer-index { grid-template-columns: 1fr; } }

.fz__label {
  font-family: var(--font-sans-ext);
  font-size: 0.5625rem;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.2em;
  color: var(--gk-white);
  margin-bottom: 0.9rem;
}
.fz__list { list-style: none; padding: 0; margin: 0; display: grid; gap: 0.18rem; }
.fz__list a, .fz__list li {
  font-size: 0.75rem;
  line-height: 1.75;
  color: rgba(255, 255, 255, 0.74);
  transition: color var(--dur-fast) var(--ease);
}
.fz__list a:hover { color: var(--gk-white); }

.fz--news { grid-column: span 2; }
@media (max-width: 1100px) { .fz--news { grid-column: span 3; } }
@media (max-width: 700px)  { .fz--news { grid-column: span 2; } }
@media (max-width: 440px)  { .fz--news { grid-column: span 1; } }
.fz__intro { font-size: 0.8125rem; color: var(--gk-mid-gray); max-width: 34ch; }
.fz__form {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--space-sm);
  align-items: end;
  margin-top: var(--space-sm);
}
.fz__form [data-form-status] { grid-column: 1 / -1; margin: 0; }
.fz__consent { margin-top: 0.7rem; max-width: 42ch; font-size: 0.6875rem; }

.footer-close {
  display: flex;
  justify-content: space-between;
  gap: var(--space-sm);
  flex-wrap: wrap;
  padding-top: var(--space-sm);
  border-top: 1px solid rgba(255, 255, 255, 0.1);
}
.footer-legal a { color: inherit; transition: color var(--dur-fast) var(--ease); }
.footer-legal a:hover { color: var(--gk-white); }

/* Le footer plein ecran doit tenir dans l'ecran, y compris sur les
   hauteurs courtes : l'echelle suit la hauteur de la fenetre. */
.footer-say__title { font-size: clamp(1.75rem, 3.4vw, 2.5rem); }  /* 40 px au maximum */

@media (max-height: 860px) {
  .footer-say__title { max-width: 24ch; }
  .fz__list a, .fz__list li { line-height: 1.6; }
  .fz__intro { display: none; }
  .fz__consent { font-size: 0.625rem; max-width: 46ch; }
}

/* Le bloc central du footer : la section Let's begin au complet */
.footer-say__eyebrow { margin-bottom: clamp(2rem, 4.5vh, 3.2rem); }
.footer-say__meta {
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: 0.8rem clamp(1.5rem, 4vw, 3.5rem);
  margin-top: clamp(2.4rem, 5.5vh, 3.8rem);
  font-size: var(--fs-body);
  color: var(--gk-mid-gray);
}
.footer-say__meta a, .footer-say__meta span {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  transition: color var(--dur-fast) var(--ease);
}
.footer-say__meta img { opacity: 0.6; }
.footer-say__meta a:hover { color: var(--gk-white); }
.footer-say__actions {
  display: flex;
  justify-content: center;
  align-items: center;
  flex-wrap: wrap;
  gap: clamp(1rem, 3vw, 2.5rem);
  margin-top: clamp(2.4rem, 5.5vh, 3.8rem);
}


/* Le footer porte de nouveau le bloc Let's begin : un seul element,
   donc l'image de fond court sous l'ensemble, sans rupture. */
.footer-full { min-height: 100svh; }
.footer-full__inner { grid-template-rows: 1fr auto auto; }
/* L'index reste compact : l'interlettrage du libelle ecarterait les
   crochets de la lettre. */
.fz__label span {
  color: var(--muted);
  margin-right: 0.7em;
  letter-spacing: 0;
}


/* --------------------------------------------------------------------------
   55. LES FINITIONS
   Un seul recit, centre : quatre bois compris dans le prix, puis toute autre
   matiere sur demande. Les coins de cadre sont photographies sur fond blanc,
   la section est donc blanche elle aussi : seule la baguette flotte, sans
   vignette apparente. Bords droits, conformement a la direction artistique.
   -------------------------------------------------------------------------- */
.finishes__head {
  max-width: 46ch;
  margin-inline: auto;
  text-align: center;
}
.finishes__head .eyebrow { margin-bottom: var(--space-xs); }
.finishes__head .lead { margin-top: var(--space-xs); margin-inline: auto; }

/* Les quatre essences */
.swatches {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--space-sm);
  max-width: 880px;
  margin: var(--space-lg) auto 0;
  padding: 0;
  list-style: none;
}
@media (max-width: 900px) { .swatches--five { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 720px) { .swatches { grid-template-columns: repeat(2, 1fr); gap: var(--space-xs); } }

.swatch {
  display: grid;
  justify-items: center;
  text-align: center;
  margin: 0;
}
.swatch img {
  width: 100%;
  height: auto;
  aspect-ratio: 386 / 380;
  object-fit: cover;
  /* Les coins sont photographies sur fond blanc. Le produit fait disparaitre
     ce blanc quel que soit le fond de section : seule la baguette flotte,
     sans vignette rapportee. Les teintes sont toutes plus sombres que le
     papier, elles traversent le melange sans se deformer. */
  mix-blend-mode: multiply;
  transition: transform var(--dur-fast) var(--ease);
}
.swatch:hover img { transform: translateY(-4px); }
.swatch__name {
  font-family: var(--font-sans-ext);
  font-size: var(--fs-eyebrow);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.18em;
  line-height: 1.5;
  margin-top: 0.9rem;
}
.swatch__note {
  font-size: 0.6875rem;
  color: var(--muted);
  margin-top: 0.3rem;
}

/* Aller plus loin : plein cadre sur l'atelier, texte par-dessus.
   L'image est un <img> et non un background : elle profite ainsi du srcset
   et du chargement differe, ce qu'un background-image ne sait pas faire. */
.beyond {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  color: var(--gk-white);
  background: var(--gk-black);
  padding-block: var(--space-2xl);
}
.beyond__media { position: absolute; inset: 0; z-index: -2; }
.beyond__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 42%;
}
/* Deux voiles : un aplat qui garantit le contraste du texte, un degrade qui
   raccroche la section aux sections noires voisines par ses bords. */
.beyond::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(180deg,
    rgba(0,0,0,0.88) 0%, rgba(0,0,0,0.52) 34%,
    rgba(0,0,0,0.52) 66%, rgba(0,0,0,0.9) 100%);
}

.beyond__inner {
  max-width: 66ch;
  margin-inline: auto;
  text-align: center;
}
.beyond__inner .eyebrow { color: rgba(255, 255, 255, 0.62); }
.beyond__inner h2 { margin-top: var(--space-xs); }
.beyond__inner .lead {
  max-width: 44ch;
  margin: var(--space-sm) auto 0;
  color: rgba(255, 255, 255, 0.86);
}

/* Les matieres possibles, en petites capitales separees par un filet */
.beyond__mats {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.55rem 1.1rem;
  margin: var(--space-md) 0 0;
  padding: 0;
  list-style: none;
}
.beyond__mats li {
  position: relative;
  font-family: var(--font-sans-ext);
  font-size: var(--fs-eyebrow);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.18em;
  color: rgba(255, 255, 255, 0.72);
}
.beyond__mats li + li::before {
  content: "";
  position: absolute;
  left: -0.58rem;
  top: 0.25em;
  bottom: 0.15em;
  width: 1px;
  background: rgba(255, 255, 255, 0.28);
}
.beyond__cta { margin-top: var(--space-md); }


/* Le choix du son : deux etats cote a cote, l'actif souligne */
.intro__sound { display: inline-flex; align-items: baseline; gap: 0.5rem; }
.intro__sep {
  font-family: var(--font-sans-ext);
  font-size: 0.8125rem;
  color: rgba(255, 255, 255, 0.5);
  text-shadow: 0 1px 14px rgba(0, 0, 0, 0.9);
}
.intro__sound .intro__ctl { opacity: 0.6; }
.intro__sound .intro__ctl:hover { opacity: 0.85; }
.intro__sound .intro__ctl.is-on {
  opacity: 1;
  text-decoration: underline;
  text-underline-offset: 5px;
  text-decoration-thickness: 1px;
}


/* --------------------------------------------------------------------------
   56. L'INTRO : COMMANDES ET APPARITIONS
   Le libelle "son" reste neutre, seuls les deux etats se soulignent. Le
   compteur occupe le coin bas droit, et le bouton "passer" vient prendre
   sa place une fois le chargement acheve. Tout entre en douceur.
   -------------------------------------------------------------------------- */
.intro__sound { display: inline-flex; align-items: baseline; gap: 0.55rem; }
.intro__sound-label,
.intro__sep {
  font-family: var(--font-sans-ext);
  font-size: 0.6875rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--gk-white);
  text-shadow: 0 1px 14px rgba(0, 0, 0, 0.9);
}
.intro__sep { opacity: 0.45; font-weight: 400; }
.intro__sound .intro__ctl { opacity: 0.55; }
.intro__sound .intro__ctl:hover { opacity: 0.85; }
.intro__sound .intro__ctl.is-on {
  opacity: 1;
  text-decoration: underline;
  text-underline-offset: 5px;
  text-decoration-thickness: 1.5px;
}

/* Compteur et bouton "passer" partagent le meme coin */
.intro__end {
  position: relative;
  display: grid;
  justify-items: end;
  align-items: center;
  min-width: 6rem;
}
.intro__end > * { grid-area: 1 / 1; justify-self: end; margin: 0; }
.intro__pct {
  /* Le compteur et le bouton "passer" occupent la meme case de grille. Une
     fois efface le compteur restait cliquable et, avec son z-index, couvrait
     les trois quarts du bouton : le clic tombait dans le vide. Il n'a jamais
     rien a intercepter. */
  pointer-events: none;
  font-family: var(--font-sans-ext);
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  color: var(--gk-white);
  text-shadow: 0 1px 14px rgba(0, 0, 0, 0.9);
  font-variant-numeric: tabular-nums;
  transition: opacity 0.5s var(--ease), transform 0.5s var(--ease);
}
.intro.is-ready .intro__pct { opacity: 0; transform: translateY(-6px); }
.intro__skip {
  opacity: 0;
  transform: translateY(6px);
  pointer-events: none;
  transition: opacity 0.6s var(--ease) 0.15s, transform 0.6s var(--ease) 0.15s;
}
.intro.is-ready .intro__skip { opacity: 1; transform: none; pointer-events: auto; }
.intro__skip span { display: inline-block; transition: transform var(--dur-fast) var(--ease); }
.intro__skip:hover span { transform: translateX(4px); }

/* Entree en scene : les commandes montent doucement au premier affichage */
@keyframes introEntree {
  from { opacity: 0; transform: translateY(12px); }
  to   { opacity: 1; transform: none; }
}
.intro__sound { animation: introEntree 1.1s var(--ease) 0.5s both; }
.intro__end   { animation: introEntree 1.1s var(--ease) 0.75s both; }
@media (prefers-reduced-motion: reduce) {
  .intro__sound, .intro__end { animation: none; }
}

/* --------------------------------------------------------------------------
   57. L'APERCU DES UNIVERS
   Au survol d'un univers, une vignette du lieu suit le curseur avec un
   leger retard, et se remplace quand on passe au suivant. Purement
   decoratif : la liste reste utilisable sans lui, et il ne s'affiche pas
   sur les appareils tactiles ni si les animations sont reduites.
   -------------------------------------------------------------------------- */
.worlds { position: relative; }
.worlds .world { position: relative; z-index: 1; }
.worlds__peek {
  transform-origin: 0 100%;
  position: fixed;
  top: 0;
  left: 0;
  z-index: 0;
  width: clamp(190px, 17vw, 300px);
  aspect-ratio: 3 / 2;
  overflow: hidden;
  pointer-events: none;
  opacity: 0;
  /* Le coin bas gauche de la vignette repose sur le curseur */
  transform: translate3d(0, -100%, 0) scale(0.94);
  transition: opacity 0.45s var(--ease), transform 0.45s var(--ease);
  will-change: transform;
}
.worlds__peek img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 0.35s var(--ease);
}
.worlds__peek.is-on { opacity: 1; transform: translate3d(0, -100%, 0) scale(1); }
.worlds__peek.is-on img { opacity: 1; }

@media (hover: none), (prefers-reduced-motion: reduce) {
  .worlds__peek { display: none; }
}


/* La composition de la section encre : le titre tient le haut a gauche,
   la prose descend a droite. La video occupe tout le fond. */
.ink-hero { align-items: stretch; }
.ink-hero__title {
  font-size: clamp(1.5rem, 2.4vw, 2.1rem);
  line-height: 1.16;
  letter-spacing: -0.02em;
  max-width: 14ch;
  align-self: start;
}
.ink-hero__prose p + p { margin-top: 1.5em; }

@media (max-width: 900px) {
  .ink-hero__title { max-width: 18ch; }
  .ink-hero__prose { align-self: start; margin-top: var(--space-md); }
}


/* La legende des capsules ferme la section, en bas a gauche, en retrait */
.ink-hero__content { position: relative; min-height: 62vh; }
.ink-hero__caption {
  grid-column: 1 / -1;
  justify-self: start;
  align-self: end;
  margin: 0;
  /* Une seule ligne : la legende ne doit pas se replier */
  max-width: none;
  white-space: nowrap;
  color: rgba(255, 255, 255, 0.42);
}
@media (max-width: 640px) {
  .ink-hero__caption { white-space: normal; max-width: 40ch; }
}
@media (max-width: 900px) { .ink-hero__caption { margin-top: var(--space-md); } }

/* --------------------------------------------------------------------------
   58. GINKO STUDIO : LE TEXTE AU CENTRE, LES CARTES AUTOUR
   Le discours tient le milieu, les cartes exportees de l'application
   flottent de part et d'autre. La typographie reste celle de Ginko
   Displays : seules les cartes viennent du logiciel.
   -------------------------------------------------------------------------- */
.studio {
  overflow: hidden;
  /* La section occupe au moins un ecran : les cartes ont besoin de place
     pour deriver au defilement sans se marcher dessus. */
  min-height: 100svh;
  display: flex;
  align-items: center;
}
.studio__inner { position: relative; width: 100%; }

.studio__center {
  position: relative;
  z-index: 2;
  max-width: 44rem;
  margin-inline: auto;
  text-align: center;
  padding-block: clamp(2rem, 6vh, 5rem);
}
.studio__center .lead { margin-inline: auto; }
.studio__actions {
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: var(--space-sm);
  margin-top: var(--space-lg);
}
.studio__note { margin-top: var(--space-md); color: var(--muted); }

/* Les cartes exportees de l'application, posees autour du texte */
.studio__card {
  position: absolute;
  z-index: 1;
  height: auto;
  filter: drop-shadow(0 24px 48px rgba(0, 0, 0, 0.55));
}
/* Sur fond clair, l'ombre s'allege : une carte posee, pas une carte qui pese. */
.section--light .studio__card { filter: drop-shadow(0 10px 22px rgba(0, 0, 0, 0.10)); }
.studio__card--floor   { width: 262px; top: 4%;  left: -5%; }
.studio__card--gallery { width: 246px; top: 46%; left: -2%; }
.studio__card--lounge  { width: 246px; top: 14%; right: -3%; }

@media (max-width: 1240px) {
  .studio__card--floor   { width: 216px; left: -8%; }
  .studio__card--gallery { width: 204px; left: -7%; }
  .studio__card--lounge  { width: 204px; right: -7%; }
}
/* Sous cette largeur les cartes chevaucheraient le texte : elles passent
   dessous plutot que de disparaitre. */
@media (max-width: 1000px) {
  .studio__inner { display: grid; gap: var(--space-lg); }
  .studio__center { order: -1; padding-block: 0; }
  .studio__card {
    position: static;
    width: 100%;
    max-width: 236px;
    justify-self: center;
  }
  .studio__card--floor { display: none; }
}
@media (max-width: 700px) { .studio__card--gallery { display: none; } }


/* --------------------------------------------------------------------------
   59. LES CARTES VIVANTES
   Les cartes de Studio suivent le curseur en profondeur, et un trait
   pointille anime relie l'etage a la galerie : la donnee descend.
   -------------------------------------------------------------------------- */
/* L'inclinaison est portee par le transform du script, qui compose la
   translation du defilement et la rotation propre a chaque carte.
   L'image, elle, ne porte que le zoom au survol. */
.studio__card {
  display: block;
  will-change: transform;
  pointer-events: auto;
}
.studio__card img {
  display: block;
  width: 100%;
  height: auto;
  transition: transform 0.55s cubic-bezier(0.22, 0.61, 0.36, 1);
}
.studio__card:hover img { transform: scale(1.045); }
/* Etat de repli si le script ne tourne pas : les cartes restent penchees. */
.studio__card--floor   { transform: rotate(-5.5deg); }
.studio__card--gallery { transform: rotate(4.2deg); }
.studio__card--lounge  { transform: rotate(-3.8deg); }

/* Le fil de transmission entre les deux cartes de gauche */
.studio__wire {
  /* Le fil couvre toute la zone : son trace est recalcule au defilement,
     puisque les deux cartes se deplacent a des vitesses differentes. */
  position: absolute;
  inset: 0;
  z-index: 1;
  width: 100%;
  height: 100%;
  pointer-events: none;
  overflow: visible;
}
.studio__wire-path {
  stroke: rgba(255, 255, 255, 0.32);
}
/* Sur fond clair, le fil s'ecrit a l'encre. */
.section--light .studio__wire-path {
  stroke: rgba(0, 0, 0, 0.35);
  stroke-width: 1.2;
  stroke-dasharray: 5 7;
  animation: wireFlow 1.6s linear infinite;
}
@keyframes wireFlow { to { stroke-dashoffset: -24; } }

@media (max-width: 1000px) { .studio__wire { display: none; } }
@media (prefers-reduced-motion: reduce) {
  .studio__wire-path { animation: none; }
  .studio__card { transition: none; }
}

/* ==========================================================================
   Le site vivant : masques, aimants, cameleon
   Chaque geste repond a un geste du visiteur. Amplitudes courtes, courbes
   longues : Ginko ne bondit pas, Ginko se revele.
   ========================================================================== */

/* ---- les grands titres se tirent comme une epreuve -----------------------
   La ligne monte dans son propre cadre : le masque s'ouvre pendant que le
   texte se pose. La classe est donnee par le script aux h1/h2 reveles. */
/* Le cadre du masque : il clippe la ligne pendant sa montee, avec une
   marge interieure compensee pour ne pas rogner les deliés du serif.
   Transform pur, aucun clip-path : le geste passe partout. */
[data-reveal].gk-masque {
  transform: none;
  overflow: hidden;
  padding: 0.18em 0.12em;
  margin: -0.18em -0.12em;
}
.gk-masque .gk-ligne {
  display: block;
  transform: translateY(118%);
  transition: transform 0.9s var(--ease-reveal);
  transition-delay: var(--reveal-delay, 0ms);
}
.gk-masque.is-visible .gk-ligne { transform: none; }

/* ---- les images se decouvrent en reculant d'un cran ----------------------
   Un leger exces d'echelle qui se resorbe : le cadre recadre l'image.
   :where() garde la priorite basse : une figure qui a deja son propre
   mouvement (zoom au survol des usecases) n'est pas contrariee. */
:where(figure[data-reveal]) { overflow: hidden; }
:where(figure[data-reveal]) img {
  transform: scale(1.06);
  transition: transform 1.3s var(--ease-reveal);
  transition-delay: var(--reveal-delay, 0ms);
}
:where(figure[data-reveal].is-visible) img { transform: none; }

/* ---- l'en-tete s'efface a la descente, revient a la remontee ------------ */
.site-header {
  transition: background var(--dur-fast) var(--ease),
              padding var(--dur-fast) var(--ease),
              border-color var(--dur-fast) var(--ease),
              transform 560ms var(--ease-reveal);
}
.site-header.est-cache { transform: translateY(-102%); }

/* ---- les boutons aimantes ------------------------------------------------
   Le bouton suit le curseur de quelques pixels, pas plus : une presence,
   pas une poursuite. Les variables sont posees par le script. */
.gk-aimant {
  transform: translate3d(var(--mx, 0px), var(--my, 0px), 0);
  transition: background var(--dur-fast) var(--ease),
              color var(--dur-fast) var(--ease),
              border-color var(--dur-fast) var(--ease),
              transform 340ms var(--ease-reveal);
}
.gk-aimant:active {
  transform: translate3d(var(--mx, 0px), var(--my, 0px), 0) scale(0.98);
}

/* ---- le cameleon : le fond de page fond d'une section a l'autre ----------
   Les sections a fond plein pretent leur couleur au body, qui fond de l'une
   a l'autre : plus de coupure nette entre le noir et le blanc. Le texte des
   sections visibles suit le mouvement, pour rester du bon cote du contraste. */
body.gk-cameleon { transition: background-color 900ms ease; }
body.gk-cameleon main section { transition: color 900ms ease; }
body.gk-cameleon.gk-clair main section.section--dark { color: var(--gk-charcoal); }
body.gk-cameleon:not(.gk-clair) main section.section--light,
body.gk-cameleon:not(.gk-clair) main section.section--paper { color: var(--gk-white); }

/* ---- les formulaires repondent au doigt ---------------------------------
   Un trait plein balaie le champ qui prend le focus ; le message d'envoi
   nait en fondu plutot que d'apparaitre sec. */
form .field { position: relative; }
form .field::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 520ms var(--ease-reveal);
  pointer-events: none;
}
form .field:focus-within::after { transform: scaleX(1); }

[data-form-status]:not(:empty) { animation: gk-fondu-texte 520ms var(--ease-reveal); }
@keyframes gk-fondu-texte {
  from { opacity: 0; transform: translateY(6px); }
}

/* ---- le pied de page se pose --------------------------------------------
   L'image du fond arrive un cran trop grande et se resorbe tres lentement
   quand l'invitation se revele : la page se termine sur un mouvement. */
.footer-full__bg { overflow: hidden; }
.footer-full__bg img {
  transform: scale(1.07);
  transition: transform 2.4s var(--ease-reveal);
}
.footer-full:has([data-reveal].is-visible) .footer-full__bg img { transform: none; }

@media (prefers-reduced-motion: reduce) {
  .gk-masque .gk-ligne { transform: none !important; transition: none; }
  :where(figure[data-reveal]) img { transform: none !important; transition: none; }
  .site-header.est-cache { transform: none; }
  body.gk-cameleon,
  body.gk-cameleon main section { transition: none; }
  .gk-aimant { transform: none !important; }
  .footer-full__bg img { transform: none; transition: none; }
}

/* ---- l'en-tete suit le cameleon -----------------------------------------
   Quand le fond de page est au blanc, la barre passe au blanc elle aussi
   et son texte a l'encre, dans le meme fondu que la page. Le panneau
   deroulant et le menu mobile gardent leur propre traitement. */
body.gk-cameleon .site-header {
  transition: background 900ms ease,
              padding var(--dur-fast) var(--ease),
              border-color 900ms ease,
              transform 560ms var(--ease-reveal);
}
body.gk-clair .site-header { color: var(--gk-black); }
body.gk-clair .site-header.is-scrolled {
  background: rgba(255, 255, 255, 0.86);
  border-bottom-color: rgba(0, 0, 0, 0.08);
}
body.gk-cameleon .site-header .brand img { transition: filter 500ms ease; }
body.gk-clair .site-header .brand img { filter: invert(1); }
body.gk-cameleon .site-header .nav__link,
body.gk-cameleon .site-header .nav__social,
body.gk-cameleon .site-header .prefs__label,
body.gk-cameleon .site-header .lang-switch { transition: color 500ms ease; }
body.gk-clair .site-header .nav__link,
body.gk-clair .site-header .nav__social,
body.gk-clair .site-header .prefs__label,
body.gk-clair .site-header .lang-switch { color: var(--gk-black); }
body.gk-clair .site-header .nav__cta {
  background: var(--gk-black);
  color: var(--gk-white);
}
body.gk-clair .site-header .nav__cta:hover { background: var(--gk-charcoal); }
body.gk-clair .site-header .burger span { background: var(--gk-black); }

/* ---- les cartes de prix se remplissent d'encre au survol -----------------
   Un voile noir balaie la carte de gauche a droite ; les textes passent en
   blanc et glissent d'un cran, en cascade, le prix prend un souffle.
   Sur les sections sombres, c'est le blanc qui remplit et l'encre qui ecrit. */
.price-card {
  position: relative;
  overflow: hidden;
  transition: border-color 640ms var(--ease-reveal);
}
.price-card::before {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--gk-black);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 640ms var(--ease-reveal);
  pointer-events: none;
}
.price-card > * { position: relative; z-index: 1; }
.price-card:hover::before { transform: scaleX(1); }
.price-card:hover { border-color: var(--gk-black); }

.price-card .eyebrow,
.price-card .price,
.price-card .check-list li {
  transition: color 480ms ease, transform 640ms var(--ease-reveal);
}
.price-card .price { transform-origin: left center; }
.price-card:hover .eyebrow { color: var(--gk-mid-gray); transform: translateX(8px); }
.price-card:hover .price {
  color: var(--gk-white);
  transform: translateX(8px) scale(1.02);
  transition-delay: 40ms;
}
.price-card:hover .check-list li { color: var(--gk-white); transform: translateX(8px); }
.price-card:hover .check-list li:nth-child(1) { transition-delay: 90ms; }
.price-card:hover .check-list li:nth-child(2) { transition-delay: 140ms; }
.price-card:hover .check-list li:nth-child(3) { transition-delay: 190ms; }

.section--dark .price-card::before { background: var(--gk-white); }
.section--dark .price-card:hover { border-color: var(--gk-white); }
.section--dark .price-card:hover .eyebrow { color: var(--gk-warm-gray); }
.section--dark .price-card:hover .price,
.section--dark .price-card:hover .check-list li { color: var(--gk-black); }

@media (prefers-reduced-motion: reduce) {
  .price-card::before { transition: none; }
  .price-card .eyebrow,
  .price-card .price,
  .price-card .check-list li { transition: color 480ms ease; transform: none !important; }
}

/* ---- les univers au doigt ------------------------------------------------
   Sur ecran tactile le survol n'existe pas : c'est la lecture qui choisit.
   La ligne qui traverse la zone de lecture se decale et s'encre, comme
   sous le pointeur, et la vignette du lieu se pose en bas a droite. Elle
   change de ligne en ligne et se retire avec la section. */
.world.est-lu { color: var(--gk-charcoal); padding-left: 0.6rem; }
.section--dark .world.est-lu { color: var(--gk-white); }
.world.est-lu i { opacity: 1; transform: translateX(0); }

.worlds__peek--pose {
  display: block;
  position: fixed;
  top: auto;
  left: auto;
  right: 16px;
  bottom: 16px;
  z-index: 60;
  width: min(44vw, 210px);
  transform: none;
  translate: 0 14px;
  opacity: 0;
  transition: opacity 480ms var(--ease-reveal), translate 480ms var(--ease-reveal);
}
.worlds__peek--pose.est-la { opacity: 1; translate: 0 0; }
.worlds__peek--pose img { opacity: 1; }

/* ---- les logos au doigt --------------------------------------------------
   La carte lue rejoue son survol : memes etats que :hover, la scene
   canvas est relancee par le script via les evenements de souris. */
.hover-card.est-lu .icon-container { transform: scale(1.15); opacity: 1; }
.hover-card.est-lu .icon-container path,
.hover-card.est-lu .icon-container circle,
.hover-card.est-lu .icon-container rect,
.hover-card.est-lu .icon-container polygon,
.hover-card.est-lu .icon-container polyline,
.hover-card.est-lu .icon-container ellipse,
.hover-card.est-lu .icon-container line { stroke-width: 1.4px !important; }
.hover-card.est-lu .card-title { opacity: 1; }

/* ---- les menus suivent le cameleon --------------------------------------
   Panneau ouvert en phase claire : l'interieur passe au blanc, texte a
   l'encre. En phase sombre, rien ne change : le noir reste le noir. */
body.gk-clair .site-header:has(.nav__item--has-menu:focus-within),
body.gk-clair .site-header:has(.nav__item--has-menu.is-open) {
  background: var(--gk-white);
  border-bottom-color: rgba(0, 0, 0, 0.12);
}

/* le grand panneau */
body.gk-clair .mega {
  background: var(--gk-white);
  border-top-color: rgba(0, 0, 0, 0.12);
  border-bottom-color: rgba(0, 0, 0, 0.12);
}
body.gk-clair .mega__intro { color: var(--gk-warm-gray); }
body.gk-clair .mega__grid {
  background: rgba(0, 0, 0, 0.1);
  border-color: rgba(0, 0, 0, 0.1);
}
body.gk-clair .mega__card { background: var(--gk-white); }
body.gk-clair .mega__card:hover { background: var(--gk-off-white); }
body.gk-clair .mega__name { color: var(--gk-black); }
body.gk-clair .mega__desc { color: var(--gk-warm-gray); }
body.gk-clair .mega__arrow { color: var(--gk-black); }
body.gk-clair .mega__links a { color: rgba(0, 0, 0, 0.62); }
body.gk-clair .mega__links a:hover { color: var(--gk-black); }
body.gk-clair .mega__lead .link-underline { color: var(--gk-black); }

/* le menu mobile */
body.gk-clair .mobile-nav { background: var(--gk-white); }
body.gk-clair .mnav__item + .mnav__item { border-top-color: rgba(0, 0, 0, 0.12); }
body.gk-clair .mnav__link { color: var(--gk-black); }
body.gk-clair .mnav__toggle { color: rgba(0, 0, 0, 0.55); }
body.gk-clair .mnav__toggle[aria-expanded="true"] { color: var(--gk-black); }
body.gk-clair .mnav__panel a { color: rgba(0, 0, 0, 0.6); }
body.gk-clair .mnav__foot { border-top-color: rgba(0, 0, 0, 0.12); }
body.gk-clair .mnav__cta { background: var(--gk-black); color: var(--gk-white); }
body.gk-clair .mnav__cta:hover { background: var(--gk-charcoal); }
body.gk-clair .mnav__lang { color: rgba(0, 0, 0, 0.6); }
body.gk-clair .mnav__currency .prefs__opt { color: rgba(0, 0, 0, 0.45); }
body.gk-clair .mnav__currency .prefs__opt:hover,
body.gk-clair .mnav__currency .prefs__opt[aria-pressed="true"] { color: var(--gk-black); }
