/* =========================================================================
   ALTIPUR — fondations
   Palette stricte : un fond, un accent. Tout le reste vient des visuels.
   ========================================================================= */

/* --- Fontes auto-hébergées (aucune dépendance externe) ------------------ */

@font-face {
  font-family: 'Cinzel';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('../assets/fonts/cinzel-400_700-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Cinzel';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('../assets/fonts/cinzel-400_700-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Instrument Serif';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../assets/fonts/instrument-serif-400-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Instrument Serif';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../assets/fonts/instrument-serif-400-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Schibsted Grotesk';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('../assets/fonts/schibsted-grotesk-400_700-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Schibsted Grotesk';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('../assets/fonts/schibsted-grotesk-400_700-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../assets/fonts/ibm-plex-mono-400-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../assets/fonts/ibm-plex-mono-400-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('../assets/fonts/ibm-plex-mono-500-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('../assets/fonts/ibm-plex-mono-500-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* --- Variables ---------------------------------------------------------- */

:root {
  /* Palette. Un fond, un accent. Aucune autre couleur en CSS. */
  --fond: #080c14;
  --fond-2: #0c111c;
  --or: #c8a96b;
  --or-lien: #d8be85;
  --creme: #f2f0eb;
  --gris: #8a93a3;

  /* L'OR DU SITE — UNE SEULE DÉCLARATION.
     C'est la valeur validée par le client sur les cues du hero. Tout ce qui
     porte l'or en aplat de titrage la reprend, sans exception et sans
     variante : titres de section, chiffres clés, noms de départements,
     numéros de chantier, mot du pied de page. S'il apparaît un jour un
     second `linear-gradient` doré dans ce dossier, c'est un bug. */
  --or-degrade: linear-gradient(105deg, #ebd9ac 0%, #c8a96b 46%, #b08f52 100%);

  /* Voiles : le fond aérien passe derrière, le texte doit rester lisible. */
  --voile: rgba(8, 12, 20, 0.78);
  --voile-fort: rgba(8, 12, 20, 0.92);
  --trait: rgba(200, 169, 107, 0.22);
  --trait-fort: rgba(200, 169, 107, 0.45);

  /* TYPOGRAPHIE — deux serifs, deux rôles, jamais mélangés.

     Cinzel est une capitale romaine inscriptionnelle : pas de vraies
     bas-de-casse, un interlettrage qui doit rester positif. C'est le
     logotype réel du client, elle ne sert qu'à ça — la marque, le mot géant
     du hero, le mot du pied de page.

     Instrument Serif porte tout l'éditorial : titres de section, manifeste,
     noms de surfaces, départements. Très fort contraste, vraies bas-de-casse.
     Ce n'est pas un mélange de deux serifs, c'est une hiérarchie. */
  --logotype: 'Cinzel', 'Times New Roman', serif;
  --display: 'Instrument Serif', 'Times New Roman', serif;
  --corps: 'Schibsted Grotesk', -apple-system, BlinkMacSystemFont, sans-serif;
  --mono: 'IBM Plex Mono', ui-monospace, SFMono-Regular, monospace;

  /* INTERLETTRAGE NÉGATIF SUR LE GRAND TITRAGE.
     C'est le réglage qui sépare visuellement un titre de 2026 d'un titre de
     2019. Trois crans calés sur l'échelle fluide, pas sur des px : au-delà
     de ~4 rem le titre se resserre davantage. Ne jamais appliquer à Cinzel,
     qui a besoin exactement de l'inverse. */
  --tr-xxl: -0.03em;
  --tr-xl: -0.028em;
  --tr-l: -0.02em;

  /* Échelle fluide */
  --t-xxl: clamp(2.75rem, 9.2vw, 9rem);
  --t-xl: clamp(2.15rem, 6.4vw, 6rem);
  --t-l: clamp(1.6rem, 3.6vw, 3.1rem);
  --t-m: clamp(1.1rem, 1.65vw, 1.4rem);
  --t-s: clamp(0.95rem, 1.15vw, 1.05rem);
  --t-mono: clamp(0.66rem, 0.83vw, 0.78rem);

  /* Rythme */
  --gouttiere: clamp(1.25rem, 5vw, 6.5rem);
  --scene-y: clamp(6rem, 14vh, 12rem);
  --scene-y: clamp(6rem, 14svh, 12rem);

  /* LE SYSTÈME DE MOUVEMENT — deux familles de courbes, quatre durées.

     Une seule signature appliquée jusqu'au survol d'un lien de nav se lit
     comme mou. On sépare donc, comme le fait IBM Carbon :

     — expressive : les moments de marque, les révélations, le hero ;
     — productive : la nav, les boutons, les toggles, tout ce qui répond.

     ASYMÉTRIE ENTRÉE / SORTIE. La sortie dure 0,75 fois l'entrée et elle
     accélère au lieu de décélérer, sur `--ease-sortie`. En CSS on l'obtient
     en posant la transition de sortie sur la règle de base et celle d'entrée
     sur la règle d'état : c'est l'état fermé qui décrit la fermeture.

     Aucune durée littérale ailleurs dans ce dossier, à la seule exception
     des boucles infinies — le badge rotatif et l'invite de scroll. */
  --ease-expressive: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-productive: cubic-bezier(0.2, 0, 0.38, 0.9);
  --ease-sortie: cubic-bezier(0.4, 0, 1, 1);

  --d-micro: 120ms; /* survol, changement de couleur */
  --d-state: 260ms; /* changement d'état, header, toggle */
  --d-panel: 600ms; /* ouverture de panneau, menu */
  --d-reveal: 900ms; /* révélation au scroll */

  /* Le décalage d'un line-reveal à la suivante. Un offset, pas une durée. */
  --stagger: 70ms;
}

/* --- Reset -------------------------------------------------------------- */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: auto; /* Lenis pilote le scroll */

  /* WCAG 2.4.11 Focus Not Obscured. La pilule de nav est en position fixed :
     sans cette réserve, un élément qui reçoit le focus derrière elle
     déclenche la failure F110.

     Elle ne suffit pas à elle seule — `scroll-padding` n'agit que sur le
     scroll natif, et Lenis pilote le scroll en JavaScript. Le pont `focusin`
     de js/global.js la double. Les deux sont nécessaires : celui-ci couvre
     le cas sans JS et le mouvement réduit, où Lenis n'est pas instancié. */
  scroll-padding-top: 6.5rem;

  /* Le pendant bas du précédent. La barre d'action est collée en bas et
     masquerait un élément qui y reçoit le focus — c'est la même failure F110
     que la pilule du haut, dans l'autre sens. `--barre-h` est mesurée et
     posée par js/global.js ; elle vaut 0 tant que la barre n'existe pas. */
  scroll-padding-bottom: calc(var(--barre-h, 0px) + 1rem);

  /* PAS DE CHAÎNAGE NI DE REBOND VERTICAL.

     `auto` est la valeur par défaut et elle autorise deux choses qu'on ne
     veut pas ici : le rebond élastique en fin de page sur iOS, et le
     chaînage — un geste qui s'épuise dans un conteneur interne se met à
     faire défiler la page derrière. Combinés à Lenis, qui pilote déjà le
     scroll en JavaScript, les deux donnent des déplacements que personne n'a
     demandés. C'est une des deux causes du « ça part tout seul » signalé sur
     téléphone.

     Seulement sur l'axe Y : `overscroll-behavior: none` couperait aussi le
     geste de retour arrière horizontal du navigateur. */
  overscroll-behavior-y: none;
}

body,
h1,
h2,
h3,
h4,
p,
figure,
blockquote,
dl,
dd,
ul,
ol {
  margin: 0;
  padding: 0;
}

ul,
ol {
  list-style: none;
}

img,
svg,
canvas,
video {
  display: block;
  max-width: 100%;
}

img {
  height: auto;
}

button,
input,
select,
textarea {
  font: inherit;
  color: inherit;
}

body {
  min-height: 100svh;
  background: var(--fond);
  color: var(--creme);
  font-family: var(--corps);
  font-size: var(--t-m);
  line-height: 1.62;
  font-weight: 400;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* Pendant le préchargement du hero, rien ne scrolle. Le failsafe de
   js/hero.js retire cette classe au bout de 7 s quoi qu'il arrive. */
html.is-locked,
html.is-locked body {
  overflow: hidden;
  height: 100%;
}

/* Le fond ne défile pas derrière un panneau ouvert. Pas de `height: 100%`
   ici, contrairement au verrou du préchargeur ci-dessus : la hauteur figée
   remettrait le scroll à zéro à la fermeture du menu. */
html.panneau-ouvert,
html.panneau-ouvert body {
  overflow: hidden;
}

/* --- Typographie -------------------------------------------------------- */

/* Les titres passent en casse normale. Instrument Serif a des bas-de-casse
   magnifiques ; les mettre en capitales revient à n'acheter que la moitié de
   la police. Les capitales restent sur le logotype, les kickers mono et les
   libellés d'interface. */
h1,
h2,
h3 {
  font-family: var(--display);
  font-weight: 400;
  line-height: 0.94;
  letter-spacing: var(--tr-l);
  text-transform: none;
  text-wrap: balance;
}

p {
  text-wrap: pretty;
  max-width: 62ch;
}

.mono {
  font-family: var(--mono);
  font-size: var(--t-mono);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--gris);
  line-height: 1.7;
  font-variant-numeric: tabular-nums;
}

.mono--or {
  color: var(--or-lien);
}

.or {
  color: var(--or-lien);
}

/* --- L'or en aplat de titrage -------------------------------------------
   Un seul dégradé, une seule mécanique. Le repli `@supports not` rend l'or
   plein : sans background-clip, `color: transparent` effacerait le texte. */

.or-fond {
  background-image: var(--or-degrade);
  background-repeat: no-repeat;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

@supports not ((background-clip: text) or (-webkit-background-clip: text)) {
  .or-fond {
    background-image: none;
    color: var(--or);
  }
}

a {
  color: var(--or-lien);
  text-decoration: none;
}

/* Souligné qui se déplie, à l'easing signature. */
.lien {
  position: relative;
  display: inline-block;
  /* WCAG 2.5.8 accorde l'exception aux liens en ligne dans une phrase. On
     n'en a pas besoin : 0,14 em en haut suffisent à passer les 24 px de
     hauteur sans toucher au rythme du paragraphe. */
  padding-top: 0.14em;
  padding-bottom: 0.12em;
}

.lien::after {
  content: '';
  position: absolute;
  inset: auto 0 0 0;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: right;
  transition: transform var(--d-micro) var(--ease-productive);
}

.lien:hover::after,
.lien:focus-visible::after {
  transform: scaleX(1);
  transform-origin: left;
}

/* --- Focus : jamais d'outline supprimée sans remplacement ---------------

   Objectif AAA (2.4.13 Focus Appearance) : au moins 2 px, et un contraste
   d'au moins 3:1 entre l'état focus et l'état non focus.

   Mesuré au colorimètre : l'or #C8A96B sur le fond #080C14 donne 8,71:1.
   Mais le focus peut aussi tomber sur le hero, au-dessus d'une frame de ciel
   clair, où l'or seul retomberait sous 2:1. D'où l'anneau à deux tons :
   une couronne sombre de 0 à 7 px posée en box-shadow, et l'or de 3 à 5 px
   par-dessus (l'outline se peint au-dessus des ombres). Quel que soit ce
   qu'il y a derrière, l'or est toujours cerné de sombre — donc toujours
   au-dessus de 3:1. */

:focus-visible {
  outline: 2px solid var(--or);
  outline-offset: 3px;
  border-radius: 2px;
  box-shadow:
    0 0 0 3px var(--fond),
    0 0 0 7px rgba(8, 12, 20, 0.85);
}

:focus:not(:focus-visible) {
  outline: none;
}

/* --- Utilitaires -------------------------------------------------------- */

.vh {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.saut {
  position: fixed;
  top: 0.75rem;
  left: 0.75rem;
  z-index: 200;
  padding: 0.7rem 1.1rem;
  background: var(--fond);
  border: 1px solid var(--or);
  color: var(--or-lien);
  font-family: var(--mono);
  font-size: var(--t-mono);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  transform: translateY(-160%);
  transition: transform var(--d-state) var(--ease-productive);
}

.saut:focus-visible {
  transform: translateY(0);
}

.enveloppe {
  width: 100%;
  max-width: 1560px;
  margin-inline: auto;
  padding-inline: var(--gouttiere);
}

/* --- Reveal générique (piloté par IntersectionObserver, jamais ScrollTrigger) */

[data-reveal] {
  opacity: 0;
  transform: translate3d(0, 26px, 0);
  transition:
    opacity var(--d-reveal) var(--ease-expressive),
    transform var(--d-reveal) var(--ease-expressive);
}

[data-reveal].est-vu {
  opacity: 1;
  transform: none;
}

/* Filet du piège au focus. Un bloc pas encore révélé est à `opacity: 0` mais
   reste tabulable : le focus peut y tomber sans que rien ne se voie. La règle
   ci-dessous le rend visible immédiatement, et js/global.js pose en plus la
   classe `.est-vu` pour que l'état soit définitif. */
[data-reveal]:focus-within,
[data-reveal]:has(:focus-visible) {
  opacity: 1;
  transform: none;
}

/* --- prefers-reduced-motion : porte de sortie globale ------------------- */

@media (prefers-reduced-motion: reduce) {
  /* Les quatre durées se rabattent au même palier : une seule déclaration
     suffit à mettre tout le site au pas. Le `!important` ci-dessous reste
     comme filet pour ce qui n'emprunterait pas les variables. */
  :root {
    --d-micro: 200ms;
    --d-state: 200ms;
    --d-panel: 200ms;
    --d-reveal: 200ms;
    --stagger: 0ms;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 200ms !important;
    scroll-behavior: auto !important;
  }

  [data-reveal] {
    transform: none;
    transition: opacity var(--d-reveal) linear;
  }
}
