/* =============================================================================
   Neoria, page /realisations, galerie « Réalisations » façon Exo Ape.
   Feuille de style de la galerie. Elle est chargée par realisations.html et ne
   contient que trois ensembles de règles :
     1. la zone masquée de la page Framer (les anciennes cartes) ;
     2. la galerie elle-même, préfixée .ng- ou ancrée sur #neoria-galerie ;
     3. l'introduction « Page title » de Framer, rendue plein écran (N25).
   Couleurs et polices sont celles du site : #111, #f3f3f2, #2a2a2a, #a8a8a8,
   #2563eb, Albert Sans et Departure Mono Regular (déjà chargées par la page).
   ============================================================================= */

/* -----------------------------------------------------------------------------
   1. Zone masquée
   On ne touche que le conteneur de la liste et ses éléments. La classe ng-pret
   est posée sur <html> par le script une fois la galerie construite : sans
   JavaScript, les cartes Framer restent visibles et la page se comporte comme
   avant. La hauteur vient de --ng-hauteur-zone, calculée par le script.
   Deux sélecteurs pour le conteneur : l'attribut lisible posé par Framer, et
   la classe du module, qui ne dépend d'aucun accent.
   -------------------------------------------------------------------------- */
html.ng-pret [data-framer-name="Réalisations List"],
html.ng-pret .framer-1vuqei7 {
  visibility: hidden !important;
  overflow: hidden;
  height: var(--ng-hauteur-zone, 400px) !important;
}

html.ng-pret [data-framer-name="Case Study Item"] {
  visibility: hidden !important;
}

/* -----------------------------------------------------------------------------
   1.b Introduction plein écran (N25)
   La section « Page title » de Framer occupe toute la hauteur de l'écran et son
   titre est agrandi : la galerie commence juste en dessous. Ces règles vivent
   hors du module Framer, donc elles s'appliquent avant comme après l'hydratation
   React (d'où le !important : elles doivent l'emporter sur le CSS du module).
   -------------------------------------------------------------------------- */
[data-framer-name="Page title"] {
  box-sizing: border-box;
  display: flex !important;
  align-items: center !important;
  justify-content: center !important;
  min-height: 100vh !important;
  min-height: 100svh !important;
  padding: 132px 24px 96px !important;
}

[data-framer-name="Page title"] h1 {
  font-size: clamp(38px, 4.4vw, 72px) !important;
  line-height: 1.03 !important;
}

/* -----------------------------------------------------------------------------
   2. Racine de la galerie
   Ajoutée en fin de <body>, en position absolue par-dessus la zone masquée.
   top et height sont posés par le script. z-index 2 : l'en-tête Framer, mesuré
   dans le CSS de cette page (barre du logotype « NEORIA. » z-index 5, menu
   z-index 10), reste au-dessus, visible et cliquable.
   -------------------------------------------------------------------------- */
#neoria-galerie {
  --ng-sombre: #111111;
  --ng-clair: #f3f3f2;
  --ng-filet: #2a2a2a;
  --ng-secondaire: #a8a8a8;
  --ng-secondaire-clair: #636363;
  --ng-accent: #2563eb;
  --ng-nuit: #0a0d16;
  --ng-sans: "Albert Sans", "Albert Sans Placeholder", sans-serif;
  --ng-mono: "Departure Mono Regular", "Departure Mono Regular Placeholder", monospace;
  --ng-courbe: cubic-bezier(0.215, 0.61, 0.355, 1);
  --ng-duree: 0.5s;
  --ng-gouttiere: clamp(24px, 3.5vw, 56px);

  position: absolute;
  left: 0;
  right: 0;
  z-index: 2;
  font-family: var(--ng-sans);
  font-weight: 400;
  color: #ffffff;
  -webkit-font-smoothing: antialiased;
  visibility: hidden;
}

html.ng-pret #neoria-galerie {
  visibility: visible;
}

/* Aplat de repli : bleu nuit et lueur bleue discrète. Il sert de fond partout
   où une image peut manquer, sans jamais casser la mise en page. */
.ng-aplat {
  background-color: var(--ng-nuit);
  background-image:
    radial-gradient(circle at 30% 20%, rgba(37, 99, 235, 0.24) 0%, rgba(10, 13, 22, 0) 58%),
    radial-gradient(circle at 72% 84%, rgba(37, 99, 235, 0.11) 0%, rgba(10, 13, 22, 0) 54%);
}

.ng-image-absente {
  display: none !important;
}

/* -----------------------------------------------------------------------------
   3. Mode A, l'expérience (bureau)
   Une section haute, une scène plein écran collante. Le script pose la hauteur
   de la scène en pixels pour rester d'accord avec son calcul de palier.
   -------------------------------------------------------------------------- */
.ng-scene {
  position: -webkit-sticky;
  position: sticky;
  top: 0;
  z-index: 1;
  height: 100vh;
  overflow: hidden;
  display: block;
  transform-origin: 50% 0%;
  transition:
    transform 0.8s var(--ng-courbe),
    opacity 0.4s linear;
}

html.ng-tous .ng-scene {
  transform: translateY(-104%) rotate(1.4deg);
}

/* 3.a Fond plein cadre, deux calques pour un fondu net. */
.ng-fonds {
  position: absolute;
  inset: 0;
}

.ng-fond {
  position: absolute;
  inset: 0;
  opacity: 0;
  transform: scale(1.045);
  transition:
    opacity var(--ng-duree) var(--ng-courbe),
    transform 0.9s var(--ng-courbe);
}

.ng-fond.ng-actif {
  opacity: 1;
  transform: scale(1);
}

.ng-fond-image {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.ng-voile {
  position: absolute;
  inset: 0;
  background-image:
    /* Voile de gauche, derrière le bloc de texte : dégradé radial doux, discret,
       qui garantit le contraste des textes sur une image sombre. */
    radial-gradient(130% 88% at 2% 50%, rgba(8, 10, 16, 0.74) 0%, rgba(8, 10, 16, 0.40) 42%, rgba(8, 10, 16, 0) 74%),
    linear-gradient(90deg, rgba(9, 11, 15, 0.74) 0%, rgba(9, 11, 15, 0.30) 44%, rgba(9, 11, 15, 0) 66%),
    linear-gradient(180deg, rgba(9, 11, 15, 0.44) 0%, rgba(9, 11, 15, 0.58) 46%, rgba(9, 11, 15, 0.80) 100%);
}

/* 3.b Bloc de titre, à gauche. */
.ng-texte {
  position: absolute;
  top: 50%;
  left: var(--ng-gouttiere);
  transform: translateY(-50%);
  /* N14 : garder de l'air entre le texte et l'image centrale. Mesure de l'ecart
     horizontal vignette moins texte : 45 px a 810 px et 91 px a 1440 px avant,
     61 px et 111 px apres. */
  width: min(28vw, 400px);
  min-width: 240px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}

.ng-pole {
  margin: 0;
  font-family: var(--ng-mono);
  font-size: 12px;
  font-weight: 400;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.88);
}

.ng-nom-masque {
  overflow: hidden;
  margin-top: 14px;
  padding-bottom: 0.08em;
}

.ng-nom {
  margin: 0;
  font-family: var(--ng-sans);
  font-size: clamp(34px, 3.6vw, 62px);
  font-weight: 500;
  line-height: 1.1;
  letter-spacing: -0.015em;
  color: #ffffff;
  text-wrap: balance;
}

.ng-nom-interne {
  display: block;
  transform: translateY(0);
}

.ng-nom-interne.ng-monte {
  animation: ng-monte var(--ng-duree) var(--ng-courbe) both;
}

@keyframes ng-monte {
  from { transform: translateY(112%); }
  to   { transform: translateY(0); }
}

.ng-sous-titre {
  margin: 10px 0 0;
  font-size: clamp(14px, 1.1vw, 17px);
  line-height: 1.5;
  color: rgba(255, 255, 255, 0.9);
}

.ng-phrase {
  margin: 16px 0 0;
  max-width: 36ch;
  font-size: clamp(15px, 1.15vw, 18px);
  line-height: 1.6;
  color: rgba(255, 255, 255, 0.9);
}

/* 3.c Vignette portrait centrée. */
.ng-vignette-bouton {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 22vw;
  min-width: 152px;
  max-width: 420px;
  padding: 0;
  border: 0;
  background: none;
  display: block;
  transform: translate(-50%, -50%);
  border-radius: 2px;
  cursor: pointer;
  transition: transform var(--ng-duree) var(--ng-courbe);
}

.ng-vignette-bouton.ng-vignette-fixe {
  cursor: default;
}

.ng-vignette-bouton:focus-visible {
  outline: 2px solid var(--ng-accent);
  outline-offset: 4px;
}

@media (hover: hover) {
  .ng-vignette-bouton:not(.ng-vignette-fixe):hover {
    transform: translate(-50%, -50%) scale(1.012);
  }
}

.ng-vignette {
  position: relative;
  display: block;
  width: 100%;
  aspect-ratio: 4 / 5;
  overflow: hidden;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.12);
}

.ng-vignette-image {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* 3.d Barre du bas. */
.ng-bas {
  position: absolute;
  left: var(--ng-gouttiere);
  right: var(--ng-gouttiere);
  bottom: clamp(22px, 3vw, 46px);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
}

.ng-bouton {
  -webkit-appearance: none;
  appearance: none;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  cursor: pointer;
}

.ng-tous {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  min-height: 44px;
  padding: 0 16px 0 12px;
  margin-left: -12px;
  border-radius: 10px;
  font-family: var(--ng-mono);
  font-size: 12px;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: #ffffff;
  transition: background-color 0.25s ease;
}

.ng-tous:hover {
  background-color: rgba(0, 0, 0, 0.32);
}

.ng-tous:focus-visible,
.ng-filtre:focus-visible {
  outline: 2px solid var(--ng-accent);
  outline-offset: 3px;
}

.ng-points {
  display: block;
  flex: none;
}

.ng-compteur {
  display: inline-flex;
  align-items: baseline;
  gap: 7px;
  margin: 0;
  font-family: var(--ng-mono);
  font-size: 13px;
  line-height: 1.25;
  letter-spacing: 0.08em;
  color: rgba(255, 255, 255, 0.58);
}

.ng-compteur-masque {
  display: inline-block;
  overflow: hidden;
  height: 1.25em;
  vertical-align: bottom;
}

.ng-compteur-chiffre {
  display: inline-block;
  line-height: 1.25;
  color: #ffffff;
}

.ng-compteur-chiffre.ng-glisse {
  animation: ng-glisse var(--ng-duree) var(--ng-courbe) both;
}

@keyframes ng-glisse {
  from { transform: translateY(115%); }
  to   { transform: translateY(0); }
}

/* -----------------------------------------------------------------------------
   4. Disque « Voir »
   86 px, fond sombre translucide flouté. Il suit le pointeur avec un retard,
   au-dessus de la vignette, et n'apparaît que si le projet a une page détail.
   Il ne capte pas les clics : c'est la vignette qui porte l'action.
   -------------------------------------------------------------------------- */
.ng-disque {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 3;
  width: 86px;
  height: 86px;
  margin: -43px 0 0 -43px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: rgba(12, 14, 18, 0.52);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.18);
  color: #ffffff;
  font-family: var(--ng-mono);
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  opacity: 0;
  pointer-events: none;
  will-change: transform;
  transition: opacity 0.28s ease;
}

.ng-disque.ng-visible {
  opacity: 1;
}

/* -----------------------------------------------------------------------------
   5. Mode B, « Tous les projets » : grille régulière (N34)
   Calque clair plein écran. Il passe sous la scène (z-index 0 contre 1) pour
   que la scène, en remontant, le découvre. Filtres en haut, grille de cartes
   défilante en dessous, bouton Fermer en bas à gauche.
   3 colonnes à 1440 px, 2 à 810 px. À moins de 810 px, la galerie mobile
   prend le relais (une colonne).
   -------------------------------------------------------------------------- */
.ng-panneau {
  position: fixed;
  inset: 0;
  z-index: 0;
  display: flex;
  flex-direction: column;
  /* La page ne doit pas défiler derrière le calque : le débordement est
     contenu et la chaîne de défilement est coupée. */
  overflow: hidden;
  overscroll-behavior: contain;
  background-color: var(--ng-clair);
  color: var(--ng-sombre);
  opacity: 0;
  visibility: hidden;
  transition:
    opacity 0.36s ease,
    visibility 0s linear 0.36s;
}

html.ng-tous .ng-panneau {
  opacity: 1;
  visibility: visible;
  transition:
    opacity 0.36s ease,
    visibility 0s linear 0s;
}

.ng-filtres {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 4px;
  padding: clamp(96px, 13vh, 150px) 24px 0;
  flex: none;
}

.ng-filtre {
  min-height: 44px;
  padding: 0 14px;
  border-radius: 8px;
  white-space: nowrap;
  font-family: var(--ng-mono);
  font-size: 13px;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--ng-secondaire-clair);
  transition:
    color 0.22s ease,
    background-color 0.22s ease,
    box-shadow 0.22s ease;
}

.ng-filtre:hover {
  color: #111111;
  background-color: rgba(17, 17, 17, 0.06);
}

.ng-filtre[aria-pressed="true"] {
  color: #111111;
  box-shadow: inset 0 -2px 0 0 var(--ng-accent);
}

.ng-grille-zone {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: clamp(28px, 4.5vh, 56px) var(--ng-gouttiere) clamp(104px, 14vh, 160px);
}

.ng-grille {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(20px, 2.2vw, 36px);
  max-width: 1600px;
  margin: 0 auto;
}

.ng-carte {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  padding: 0;
  border: 0;
  background: none;
  text-align: left;
  color: inherit;
  font: inherit;
  cursor: pointer;
  opacity: 0;
  transform: translateY(24px);
  transition:
    opacity 0.5s ease,
    transform 0.5s var(--ng-courbe);
}

html.ng-tous .ng-carte {
  opacity: 1;
  transform: translateY(0);
}

.ng-carte:focus-visible {
  outline: 2px solid var(--ng-accent);
  outline-offset: 4px;
}

.ng-carte-image {
  position: relative;
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  border-radius: 2px;
  box-shadow: inset 0 0 0 1px rgba(17, 17, 17, 0.10);
  transition: box-shadow 0.25s ease;
}

.ng-carte-photo {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.6s var(--ng-courbe);
}

@media (hover: hover) {
  .ng-carte:hover .ng-carte-image {
    box-shadow: inset 0 0 0 1px rgba(17, 17, 17, 0.34);
  }

  .ng-carte:hover .ng-carte-photo {
    transform: scale(1.03);
  }
}

.ng-carte-meta {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding-top: 14px;
}

.ng-carte-nom {
  font-size: 19px;
  font-weight: 500;
  line-height: 1.2;
  letter-spacing: -0.01em;
  color: #111111;
}

.ng-carte-sous-titre {
  font-size: 15px;
  line-height: 1.4;
  color: var(--ng-secondaire-clair);
}

.ng-carte-pole {
  margin-top: 2px;
  font-family: var(--ng-mono);
  font-size: 12px;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--ng-secondaire-clair);
}

.ng-grille-vide {
  grid-column: 1 / -1;
  margin: 24px 0 0;
  font-size: 16px;
  color: var(--ng-secondaire-clair);
}

.ng-fermer {
  position: absolute;
  left: var(--ng-gouttiere);
  bottom: clamp(22px, 3vw, 44px);
  display: inline-flex;
  align-items: center;
  gap: 12px;
  min-height: 44px;
  padding: 0 16px 0 12px;
  border-radius: 10px;
  background-color: rgba(243, 243, 242, 0.92);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  box-shadow: 0 1px 2px rgba(17, 17, 17, 0.14), inset 0 0 0 1px rgba(17, 17, 17, 0.08);
  font-family: var(--ng-mono);
  font-size: 12px;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: #111111;
  transition: background-color 0.22s ease;
}

.ng-fermer:hover {
  background-color: #ffffff;
}

.ng-fermer:focus-visible {
  outline: 2px solid var(--ng-accent);
  outline-offset: 3px;
}

@media (max-width: 1199.98px) {
  .ng-grille {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* -----------------------------------------------------------------------------
   6. Mobile, moins de 810 px : liste verticale simple, une colonne.
   La zone masquée est ici sur le fond sombre #111 de la section Framer : le
   texte de la liste est donc clair.
   -------------------------------------------------------------------------- */
.ng-mobile {
  display: none;
  padding: 0 8vw;
  color: #ffffff;
}

/* Filtres sur deux lignes plutôt qu'une seule rangée qui défile : le dernier
   libellé n'est plus coupé. Espacement régulier, zones tactiles de 44 px
   (règle .ng-filtre), aucun débordement horizontal. Cette règle ne sert qu'en
   mobile : au-dessus de 810 px, .ng-mobile est masqué. */
.ng-mobile-filtres {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px;
  margin: 0 0 26px;
  padding: 0 0 6px;
}

/* Les filtres de la liste mobile sont sur le fond sombre de la section : ils
   reprennent les couleurs claires, avec un contraste au moins égal au repos.
   Sur mobile seulement, ils sont un peu plus petits et plus serrés pour tenir
   sur deux lignes à 390 px ; la hauteur tactile de 44 px est conservée. */
.ng-mobile .ng-filtre {
  color: var(--ng-secondaire);
  font-size: 12px;
  padding: 0 6px;
}

.ng-mobile .ng-filtre:hover {
  color: #ffffff;
  background-color: rgba(255, 255, 255, 0.08);
}

.ng-mobile .ng-filtre[aria-pressed="true"] {
  color: #ffffff;
  box-shadow: inset 0 -2px 0 0 var(--ng-accent);
}

.ng-mobile-liste {
  display: flex;
  flex-direction: column;
  gap: 0;
  padding: 0 0 64px;
}

/* Filet court entre deux projets, comme les filets de la page Framer. */
.ng-mobile-item + .ng-mobile-item {
  margin-top: 44px;
  padding-top: 30px;
  border-top: 1px solid var(--ng-filet);
}

.ng-mobile-item {
  display: block;
  width: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  -webkit-appearance: none;
  appearance: none;
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: default;
  opacity: 0;
  transform: translateY(18px);
}

.ng-mobile-item.ng-lien {
  cursor: pointer;
}

.ng-mobile-item.ng-vu {
  opacity: 1;
  transform: translateY(0);
  transition:
    opacity 0.5s var(--ng-courbe),
    transform 0.5s var(--ng-courbe);
}

.ng-mobile-vignette {
  position: relative;
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.10);
}

.ng-mobile-image {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.ng-mobile-nom {
  display: block;
  margin: 14px 0 0;
  font-size: 19px;
  font-weight: 500;
  line-height: 1.25;
  color: #ffffff;
}

.ng-mobile-sous-titre {
  display: block;
  margin: 4px 0 0;
  font-size: 15px;
  line-height: 1.4;
  color: var(--ng-secondaire);
}

.ng-mobile-pole {
  display: block;
  margin: 8px 0 0;
  font-family: var(--ng-mono);
  font-size: 12px;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--ng-secondaire);
}

.ng-mobile-item:focus-visible {
  outline: 2px solid var(--ng-accent);
  outline-offset: 4px;
}

@media (max-width: 809.98px) {
  .ng-scene,
  .ng-panneau,
  .ng-disque {
    display: none;
  }

  .ng-mobile {
    display: block;
  }
}

@media (min-width: 810px) {
  .ng-mobile {
    display: none;
  }
}

/* -----------------------------------------------------------------------------
   7. Mouvement réduit : fondus simples uniquement.
   Le script pose aussi la classe ng-reduit sur <html> et supprime les
   translations, rotations et mises à l'échelle côté JavaScript.
   -------------------------------------------------------------------------- */
html.ng-reduit .ng-scene {
  transition: opacity 0.3s linear;
}

html.ng-reduit.ng-tous .ng-scene {
  transform: none;
  opacity: 0;
}

html.ng-reduit .ng-nom-interne.ng-monte,
html.ng-reduit .ng-compteur-chiffre.ng-glisse {
  animation: ng-fondu 0.3s linear both;
}

@keyframes ng-fondu {
  from { opacity: 0; }
  to   { opacity: 1; }
}

html.ng-reduit .ng-carte,
html.ng-reduit .ng-mobile-item {
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  #neoria-galerie .ng-fond,
  #neoria-galerie .ng-carte,
  #neoria-galerie .ng-mobile-item {
    transform: none !important;
  }

  #neoria-galerie .ng-carte-photo {
    transition: none;
  }

  #neoria-galerie .ng-nom-interne.ng-monte {
    transform: none;
  }
}

/* -----------------------------------------------------------------------------
   8. Etiquette « Neo ... » a cote du pole (N30)
   Le titre de chaque carte dit desormais ce que le projet fait ; le nom de
   produit reste visible comme une petite etiquette, sur la meme ligne que le
   pole. La ligne reste unique, donc les cartes de la grille restent alignees.
   Fond sombre (scene, liste mobile) par defaut, variante claire pour la grille.
   -------------------------------------------------------------------------- */
.ng-pole,
.ng-carte-pole,
.ng-mobile-pole {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}

.ng-etiquette {
  display: inline-block;
  flex: none;
  padding: 3px 9px;
  border: 1px solid rgba(255, 255, 255, 0.34);
  border-radius: 999px;
  font-family: var(--ng-mono);
  font-size: 10px;
  font-weight: 400;
  line-height: 1.25;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.9);
}

.ng-carte-pole .ng-etiquette {
  border-color: rgba(17, 17, 17, 0.24);
  color: var(--ng-secondaire-clair);
}

/* La regle ci-dessus pose display, ce qui l'emporterait sur l'attribut hidden. */
.ng-etiquette[hidden] {
  display: none;
}
