/* ============================================================
   Aladdin Antique and Rugs — theme.css
   Palette verrouillée client (extraite des tapis réels).
   Interdits : rouge saturé, dégradés décoratifs, glassmorphism.
   ============================================================ */

:root{
  --night:  #1B2942;
  --garnet: #7A2530;
  --gold:   #B8985A;
  --ivory:  #F2EDE1;
  --sage:   #6B7A5E;
  --black:  #14120F;

  --ivory-60: rgba(242,237,225,.6);
  --ivory-85: rgba(242,237,225,.85);

  --font-display: "Cormorant Garamond", Georgia, serif;
  --font-body: "Jost", "Segoe UI", sans-serif;

  --nav-h: 76px;
  --ease-out: cubic-bezier(.23,1,.32,1);
  /* Mouvement à l'écran (pas une entrée/sortie) : accélère puis freine. */
  --ease-in-out: cubic-bezier(.77,0,.175,1);
}

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

html{ scroll-behavior:smooth; scroll-padding-top:var(--nav-h); }

body{
  margin:0;
  font-family:var(--font-body);
  font-weight:300;
  font-size:1rem;
  line-height:1.6;
  color:var(--black);
  background:var(--ivory);
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
  transition:opacity .18s ease;
}
/* Bascule de langue : bref voile pendant que le texte + la direction
   LTR/RTL changent sous le capot — jamais un remplacement à froid. */
body.lang-switching{ opacity:.45; }

img{ max-width:100%; display:block; }
a{ color:inherit; }
body.no-scroll{ overflow:hidden; }

::selection{ background:rgba(184,152,90,.4); }
/* L'or tient largement sur les fonds sombres du site (mesuré : 6,84:1 sur
   #14120F du catalogue et du footer, 5,32:1 sur le nuit du hero). */
:focus-visible{ outline:2px solid var(--gold); outline-offset:3px; }
/* ... mais PAS sur ivoire : 2,34:1, sous le 3:1 que WCAG 1.4.11 exige d'un
   indicateur de focus. Un utilisateur au clavier perdait donc son repère sur
   « À propos » et « Contact », soit 2 sections sur 5 — trouvé à la mesure lors
   de l'audit du 2026-08-06, jamais signalé auparavant.

   Le grenat est déjà LA couleur « sur ivoire » du projet : les libellés du
   bloc contact sont passés en grenat le 2026-07-12 pour exactement cette
   raison (« l'or sur ivoire ≈ 2,1:1, l'or reste réservé aux fonds sombres »).
   La règle existait donc, elle n'avait simplement jamais été étendue au
   focus. Mesuré ici : 8,42:1. Aucune nouvelle couleur introduite. */
.about :focus-visible,
.contact :focus-visible{ outline-color:var(--garnet); }

.skip-link{
  position:fixed; top:-100%; left:1rem; z-index:200;
  padding:.8rem 1.2rem;
  background:var(--black); color:var(--ivory);
  font-size:.8rem; letter-spacing:.12em; text-transform:uppercase; text-decoration:none;
}
.skip-link:focus{ top:1rem; }

/* ---------- Ornement signature : ◈ sur trait fin ---------- */
.ornament{ display:flex; align-items:center; justify-content:center; gap:1rem; }
.ornament__line{ width:64px; height:1px; background:rgba(184,152,90,.75); }
.ornament__mark{ color:var(--gold); font-size:.9rem; line-height:1; }

/* ---------- Navigation ---------- */
/* Pas de backdrop-filter ici : glassmorphism proscrit par le brief,
   et un backdrop-filter ferait de la nav le containing block du
   panneau mobile position:fixed (bug documenté, racine §4.5). */
.nav{
  position:fixed; top:0; left:0; right:0; z-index:100;
  display:flex; align-items:center; justify-content:space-between;
  height:var(--nav-h);
  padding:0 clamp(1.25rem,4vw,3rem);
  color:var(--ivory);
  background:transparent;
  border-bottom:1px solid transparent;
  transition:background-color .4s ease, border-color .4s ease;
}
.nav.is-scrolled,
.nav.menu-open{
  background:rgba(20,18,15,.97);
  border-bottom-color:rgba(184,152,90,.16);
}

.nav__brand{ display:flex; align-items:center; gap:.75rem; min-height:44px; text-decoration:none; }
.nav__ornament{ color:var(--gold); font-size:.85rem; }
.nav__lockup{ display:flex; flex-direction:column; line-height:1.1; }
.nav__name{ font-family:var(--font-display); font-weight:600; font-size:1.3rem; letter-spacing:.03em; }
/* Logotype (exemption contraste WCAG 1.4.3) — opacité montée quand même
   pour la lisibilité sur photo. */
.nav__sub{ font-size:.58rem; font-weight:400; letter-spacing:.34em; text-transform:uppercase; color:rgba(242,237,225,.78); margin-top:2px; }

/* Grammaire d'état unique du site : le trait d'or souligne l'actif
   (nav, toggle langue, filtres) — l'or n'est jamais une couleur de texte
   dans le chrome. */
.nav__links{ display:flex; gap:.25rem; }
.nav__links a{
  position:relative;
  display:inline-flex; align-items:center;
  min-height:44px; padding:0 1rem;
  font-size:.76rem; font-weight:400; letter-spacing:.18em; text-transform:uppercase;
  color:var(--ivory-85); text-decoration:none;
  transition:color .25s ease;
}
.nav__links a::after{
  content:''; position:absolute; left:1rem; right:1rem; bottom:9px;
  height:1px; background:var(--gold);
  transform:scaleX(0); transform-origin:left center;
  transition:transform .3s var(--ease-out);
}
.nav__links a:hover{ color:var(--ivory); }
.nav__links a:hover::after,
.nav__links a.is-current::after{ transform:scaleX(1); }
.nav__links a.is-current{ color:var(--ivory); }

.nav__right{ display:flex; align-items:center; gap:.75rem; }

/* Pastille quasi opaque : garantit le contraste du toggle sur n'importe
   quelle zone de la photo (l'auvent clair échouait au pixel), et se fond
   dans la nav une fois scrollée. L'or marque l'état actif en soulignement,
   jamais en couleur de texte à cette taille (4.5:1 impossible sur photo). */
.lang-toggle{
  display:flex; align-items:center;
  background:rgba(20,18,15,.9); padding:0 .4rem;
}
.lang-toggle button{
  min-height:44px; min-width:44px; padding:0 .35rem;
  background:none; border:0; cursor:pointer;
  font-family:var(--font-body); font-weight:400; font-size:.76rem; letter-spacing:.14em;
  color:var(--ivory-85);
  transition:color .25s ease;
}
.lang-toggle button:hover{ color:var(--ivory); }
/* Retour de presse — la passe du 2026-07-13 avait posé « scale(.97) sur tout
   le pressable », mais le toggle de langue et le burger n'en avaient jamais
   reçu (trouvé en auditant les états, pas à l'œil). Ce sont pourtant les deux
   commandes les plus sollicitées au doigt : sans retour, un tap sur mobile ne
   confirme rien tant que le re-rendu n'a pas eu lieu. Valeur alignée sur les
   autres petites commandes (.filter .96, .lightbox__thumb .95). */
.lang-toggle button:active{ transform:scale(.94); }
.lang-toggle button.is-active{
  color:var(--ivory);
  text-decoration:underline; text-underline-offset:5px;
  text-decoration-color:var(--gold);
}
.lang-toggle__sep{ color:rgba(242,237,225,.35); font-size:.7rem; }

.burger{
  display:none;
  flex-direction:column; justify-content:center; align-items:center; gap:6px;
  width:44px; height:44px;
  background:none; border:0; cursor:pointer; padding:0;
}
.burger:active{ transform:scale(.94); }
.burger span{
  width:22px; height:1.5px; background:var(--ivory);
  transition:transform .3s var(--ease-out);
}
.burger.is-open span:nth-child(1){ transform:translateY(3.75px) rotate(45deg); }
.burger.is-open span:nth-child(2){ transform:translateY(-3.75px) rotate(-45deg); }

/* ---------- Menu mobile (panneau plein écran solide) ---------- */
/* Même grammaire que la lightbox : sortie vive, entrée posée avec un
   soupçon de mouvement (jamais un simple fondu plat). */
.mobile-menu{
  position:fixed; inset:0; z-index:90;
  display:flex; flex-direction:column; align-items:center; justify-content:center; gap:3rem;
  background:var(--black); color:var(--ivory);
  opacity:0; visibility:hidden;
  transform:scale(.98);
  transition:opacity .2s ease, transform .2s ease, visibility 0s linear .2s;
}
.mobile-menu.is-open{
  opacity:1; visibility:visible;
  transform:scale(1);
  transition:opacity .32s var(--ease-out), transform .32s var(--ease-out);
}
.mobile-menu nav{ display:flex; flex-direction:column; align-items:center; gap:2.2rem; }
.mobile-menu a{
  font-family:var(--font-display); font-size:2rem; font-weight:500;
  color:var(--ivory); text-decoration:none; letter-spacing:.02em;
  transition:color .2s ease;
}
.mobile-menu a:hover{ color:var(--gold); }

/* ---------- Hero ---------- */
.hero{
  position:relative; isolation:isolate; overflow:hidden;
  min-height:100vh; min-height:100svh;
  display:flex; align-items:flex-end; justify-content:center;
  padding:calc(var(--nav-h) + 1rem) clamp(1.25rem,5vw,2rem) clamp(3.5rem,10vh,6.5rem);
  background:var(--night);
  color:var(--ivory);
}

/* Chorégraphie « éclairage de la vitrine » — passe créative Fable
   (2026-07-15). Seule exception assumée à la retenue de motion du site :
   jouée UNE fois, au chargement, jamais sur une interaction répétée.
   Séquence : la photo s'éveille (recul 1.07→1, voile d'obscurité qui se
   lève comme un éclairage qu'on allume), le lieu se lit avant le nom,
   le nom se lève mot à mot sous masque, le trait d'or se trace depuis
   le ◈ — la grammaire d'état du site (souligné d'or = actif) jouée une
   fois, en grand — puis tagline, CTA, appel au défilement.
   Pattern commun à tous les keyframes : état de base = état FINAL,
   `from{}` seul, fill `backwards` pour tenir l'état initial pendant le
   délai → la règle globale prefers-reduced-motion (animation:none)
   rend tout visible d'emblée sans règle dédiée. */
.hero__bg{
  position:absolute; inset:0; z-index:-2;
  transform-origin:50% 40%;
  animation:hero-settle 3.2s var(--ease-out) both;
  /* Nombre d'éléments fixe (1 hero, jamais 100+) : le hint direct en CSS
     est sûr ici — contrairement aux cards de catalogue (voir script.js),
     où le même hint permanent sur chaque vignette gaspillerait de la
     mémoire GPU une fois le catalogue étoffé (audit gsap-performance). */
  will-change:transform;
}
.hero__bg picture{ display:contents; }
/* Cadrage desktop : lampes et tapis suspendus dans la moitié haute,
   le bloc typographique se pose sur la zone basse sombre (tapis drapés). */
.hero__bg img{
  width:100%; height:100%;
  object-fit:cover; object-position:50% 42%;
}
@keyframes hero-settle{
  from{ transform:scale(1.07); }
}

/* Vidéo hero (Veo 3.1 Lite — plan lent « la vitrine s'éveille »).
   Même cadrage que hero.jpg. Fondu en entrée une fois qu'elle joue
   réellement (classe posée par le JS sur l'évènement `playing`) — le
   poster/l'image tient jusque-là. Masquée sous 640px (mobile = crop
   art-dirigé statique, et pas de mp4 sur data mobile). */
.hero__video{
  position:absolute; inset:0;
  width:100%; height:100%;
  object-fit:cover; object-position:50% 42%;
  opacity:0; transition:opacity .8s ease;
  /* La vidéo s'éclaire en avançant (dolly + lampes) → l'eyebrow tombait
     à 4.51:1 au pire instant (limite 4.5, mesuré). Léger assombrissement
     de la vidéo seule (imperceptible, l'image reste riche) pour rendre
     la marge de contraste confortable ; le chemin statique est intact. */
  filter:brightness(.9);
}
.hero__bg--playing .hero__video{ opacity:1; }
/* La vidéo porte son propre mouvement (dolly) : on neutralise le recul
   CSS quand elle joue — le chemin statique garde son `hero-settle`. */
.hero__bg--playing{ animation:none; }
@media (max-width:640px){ .hero__video{ display:none; } }

/* Scrim asymétrique : bande haute légère pour la nav, cœur transparent
   (le médaillon respire), densité en bas où se pose le bloc typographique.
   À re-mesurer au pixel composite (QA) — jamais un voile plat. */
.hero__scrim{
  position:absolute; inset:0; z-index:-1;
  background:
    linear-gradient(180deg,
      rgba(20,18,15,.55) 0%,
      rgba(20,18,15,.18) 20%,
      rgba(20,18,15,.22) 44%,
      rgba(20,18,15,.58) 57%,
      rgba(20,18,15,.68) 66%,
      rgba(20,18,15,.92) 100%);
  /* Stop 57% ajouté (mesure 2026-07-15) : la ligne du lieu (eyebrow)
     traverse le tapis éclairé à droite à 1440 — p05 4.46 < 4.5 sans lui.
     Le cœur de la photo (44%) reste intact. */
}
/* hero-mobile.jpg a SA composition (franges claires du tapis suspendu
   exactement derrière la ligne du lieu, ~48% de hauteur) → scrim dédié,
   mesuré : p05 3.84 avec le scrim desktop, l'eyebrow exige ≥.60 d'alpha
   dans sa zone. Jamais un voile plat : la bande 20–40% reste légère. */
@media (max-width:640px){
  .hero__scrim{
    background:
      linear-gradient(180deg,
        rgba(20,18,15,.55) 0%,
        rgba(20,18,15,.25) 20%,
        rgba(20,18,15,.35) 40%,
        rgba(20,18,15,.62) 50%,
        rgba(20,18,15,.74) 66%,
        rgba(20,18,15,.94) 100%);
  }
}

/* Voile d'ouverture : l'obscurité se lève sur la vitrine (après le scrim
   dans le DOM → peint au-dessus de lui, sous le contenu). Un peu plus
   dense en haut : la lumière semble monter depuis l'étal. */
.hero__veil{
  position:absolute; inset:0; z-index:-1;
  background:linear-gradient(180deg,
    rgba(20,18,15,.97) 0%,
    rgba(20,18,15,.9) 45%,
    rgba(20,18,15,.82) 100%);
  opacity:0; pointer-events:none;
  animation:veil-lift 1.5s ease .05s backwards;
}
@keyframes veil-lift{ from{ opacity:1; } }

.hero__content{
  max-width:56rem;
  text-align:center;
}

/* Le lieu avant le nom — petites capitales espacées, comme une ligne de
   lot. Ivoire, pas or : mesuré au pixel composite, l'or échoue à 4.5:1
   sur cette zone de la photo (p05 2.2–2.7) — même verdict que le
   lang-toggle (« jamais l'or en couleur de texte sur photo »). L'accent
   or du hero vit dans le ◈ et le trait tracé, éléments non-texte. */
.hero__eyebrow{
  margin:0;
  font-size:.74rem; font-weight:400;
  letter-spacing:.32em; text-transform:uppercase;
  color:var(--ivory-85);
}

.hero__title{
  margin:1.05rem 0 0;
  font-family:var(--font-display); font-weight:500;
  font-size:clamp(2.5rem,6.6vw,4.9rem);
  line-height:1.06; letter-spacing:.012em;
  text-wrap:balance;
  /* Nom de marque latin : isolé LTR — des inline-blocks (les masques)
     se réordonnent visuellement dans un paragraphe RTL, même famille
     de bug bidi que le compteur « 1 / 5 » de la fiche. */
  direction:ltr; unicode-bidi:isolate;
}
.hero__mask{
  display:inline-block; overflow:hidden;
  vertical-align:bottom;
  /* Respiration sous la ligne de base : ne jamais tondre les descentes
     (le g de « Rugs ») pendant que le mot est masqué. */
  padding-bottom:.14em; margin-bottom:-.14em;
}
.hero__word{
  display:inline-block;
  animation:word-rise .85s var(--ease-out) calc(.5s + var(--word)*.11s) backwards;
}
@keyframes word-rise{ from{ transform:translateY(118%); } }
.hero__amp{ font-style:italic; font-weight:400; }

/* Le trait d'or se trace depuis le ◈ : marque d'abord, lignes ensuite,
   chacune grandissant depuis le côté du diamant vers l'extérieur. */
.hero__rule{ margin:1.35rem auto 1.2rem; }
.hero__rule .ornament__mark{ animation:rule-mark .5s var(--ease-out) 1.02s backwards; }
.hero__rule .ornament__line{ animation:rule-line .65s var(--ease-out) 1.18s backwards; }
.hero__rule .ornament__line:first-child{ transform-origin:right center; }
.hero__rule .ornament__line:last-child{ transform-origin:left center; }
[dir="rtl"] .hero__rule .ornament__line:first-child{ transform-origin:left center; }
[dir="rtl"] .hero__rule .ornament__line:last-child{ transform-origin:right center; }
@keyframes rule-mark{ from{ opacity:0; transform:scale(.4); } }
@keyframes rule-line{ from{ transform:scaleX(0); } }

.hero__tagline{
  margin:0 0 2.2rem;
  font-family:var(--font-display); font-style:italic; font-weight:400;
  font-size:clamp(1.2rem,2.5vw,1.55rem);
  color:var(--ivory-85);
}
.hero__tagline sup{ font-size:.65em; }

.hero__cta{ display:flex; flex-wrap:wrap; justify-content:center; gap:1.1rem; }

/* Fondus séquencés (eyebrow .22s → tagline 1.5s → CTA 1.72s) — les mots
   du titre et le trait d'or ont leur propre chorégraphie ci-dessus. */
.hero__seq{ animation:hero-in .7s var(--ease-out) backwards; }
.hero__seq--1{ animation-delay:.22s; }
.hero__seq--2{ animation-delay:1.5s; }
.hero__seq--3{ animation-delay:1.72s; }
@keyframes hero-in{
  from{ opacity:0; transform:translateY(18px); }
}

/* Appel au défilement : un fil discret, un segment d'or qui coule vers
   le bas puis se repose. Masqué quand la place manque (le CTA prime). */
.hero__cue{
  position:absolute; left:50%; bottom:1.4rem; z-index:1;
  width:1px; height:46px;
  transform:translateX(-50%);
  overflow:hidden;
  background:rgba(242,237,225,.16);
  animation:cue-in .9s ease 2.2s backwards;
}
.hero__cue::after{
  content:''; position:absolute; left:0; top:0;
  width:1px; height:16px;
  background:var(--gold);
  transform:translateY(-16px);
  animation:cue-run 2.6s var(--ease-in-out) 2.8s infinite;
}
@keyframes cue-in{ from{ opacity:0; } }
@keyframes cue-run{
  0%{ transform:translateY(-16px); }
  62%{ transform:translateY(46px); }
  100%{ transform:translateY(46px); }
}
@media (max-width:640px), (max-height:600px){
  .hero__cue{ display:none; }
}

/* ---------- Boutons ---------- */
.btn{
  display:inline-flex; align-items:center; justify-content:center;
  min-height:50px; padding:.4rem 2.2rem;
  font-family:var(--font-body); font-weight:400; font-size:.78rem;
  letter-spacing:.22em; text-transform:uppercase; text-decoration:none;
  border:1px solid transparent;
  transition:background-color .25s ease, color .25s ease, border-color .25s ease,
             transform .16s var(--ease-out);
}
.btn:active{ transform:scale(.97); }
.btn--primary{ border-color:var(--gold); color:var(--ivory); }
.btn--primary:hover{ background:var(--gold); color:var(--black); }
.btn--primary:active{ background:#a5894e; border-color:#a5894e; color:var(--black); }
.btn--ghost{ border-color:rgba(242,237,225,.35); color:var(--ivory); }
.btn--ghost:hover{ border-color:var(--ivory); }
.btn--ghost:active{ background:rgba(242,237,225,.12); }

/* ---------- Sections : coquille commune ---------- */
[hidden]{ display:none !important; }

.section{ padding:5rem clamp(1.25rem,5vw,2rem); scroll-margin-top:var(--nav-h); }
@media (min-width:900px){ .section{ padding:7.5rem 2rem; } }

.section__inner{ max-width:1200px; margin:0 auto; }
.section__head{ text-align:center; margin-bottom:clamp(2.8rem,6vw,4.5rem); }
.section__title{
  margin:1.4rem 0 0;
  font-family:var(--font-display); font-weight:500;
  font-size:clamp(2rem,4vw,2.9rem); letter-spacing:.02em;
}

/* Rythme : chaque section respire différemment — jamais un padding uniforme.
   Le catalogue (l'œuvre) reçoit le plus d'air. */
.about{ padding-block:6.5rem 7.5rem; }
.catalogue{ padding-block:8.5rem 9.5rem; }
/* L'œuvre prend la largeur (critère Perrotin C13, mesuré : 1200px/120px de
   gouttières laissaient ~14% de surface aux marges) : le catalogue seul
   s'élargit à 1376px — les sections textuelles restent à 1200px, une
   colonne de lecture n'est pas une cimaise. */
.catalogue .section__inner{ max-width:1376px; }
.contact{ padding-block:7rem 8.5rem; }
@media (min-width:900px){
  .about{ padding-block:8rem 9rem; }
  .catalogue{ padding-block:11rem 11.5rem; }
  .contact{ padding-block:9rem 10.5rem; }
  .catalogue .section__head{ margin-bottom:clamp(3.5rem,7vw,5.5rem); }
}

/* ---------- À propos ---------- */
.about{ background:var(--ivory); color:var(--black); }
.about__grid{
  display:grid; gap:clamp(2.5rem,6vw,5rem); align-items:center;
  max-width:1100px; margin:0 auto;
}
/* Composition décalée : l'image ancre le haut, le texte démarre plus bas. */
@media (min-width:900px){
  .about__grid{ grid-template-columns:5fr 6fr; align-items:start; }
  .about__text{ padding-top:3.25rem; }
}
/* Empilé (mobile/tablette) : largeur plafonnée — jamais plus de ~70ch. */
@media (max-width:899px){
  .about__grid{ max-width:42rem; }
}
.about__media{
  margin:0; padding:.9rem;
  border:1px solid rgba(184,152,90,.45);
  background:rgba(255,255,255,.45);
}
.about__media img{ width:100%; height:auto; }
.about__text p{
  margin:0 0 1.2rem;
  font-size:1.02rem; line-height:1.85; font-weight:300;
  color:rgba(20,18,15,.85);
}
.about__sign{
  margin-top:1.8rem;
  font-family:var(--font-display); font-style:italic; font-weight:500;
  font-size:1.3rem; color:var(--black);
}

/* ---------- Catalogue ---------- */
.catalogue{ background:var(--black); color:var(--ivory); }
.catalogue .section__title{ color:var(--ivory); }

.filters{
  display:flex; flex-wrap:wrap; justify-content:center;
  gap:.35rem .5rem;
  max-width:900px; margin:0 auto clamp(2.2rem,5vw,3.5rem);
}
/* 3 familles réelles (client) : simple ligne de texte, l'état actif est
   souligné d'or — même langage que le toggle de langue, pas de chips. */
.filter{
  min-height:44px; padding:.5rem 1.1rem;
  background:none; border:0; cursor:pointer;
  font-family:var(--font-body); font-weight:400; font-size:.74rem;
  letter-spacing:.16em; text-transform:uppercase;
  color:var(--ivory-60);
  transition:color .2s ease, transform .12s var(--ease-out);
}
.filter:hover{ color:var(--ivory); }
.filter:active{ transform:scale(.96); }
.filter.is-active{
  color:var(--ivory);
  text-decoration:underline; text-underline-offset:6px;
  text-decoration-color:var(--gold);
}

/* Recherche — subordonnée à la taxonomie, jamais un moteur de recherche
   e-commerce : aucun fond, aucun arrondi, aucune ombre, pas de loupe. Un
   simple filet qui passe à l'or au focus, c'est-à-dire exactement la
   grammaire d'état du site (l'or souligne l'actif : toggle de langue,
   filtre actif, et maintenant le champ). */
.catsearch{
  position:relative;
  width:clamp(240px, 50vw, 330px);
  margin:0 auto clamp(2.2rem,5vw,3.5rem);
}
.catsearch__input{
  width:100%; min-height:44px;
  /* Propriétés logiques : padding-inline-end réserve la place du bouton
     d'effacement et suit automatiquement le RTL — aucune règle miroir. */
  padding-block:.5rem;
  padding-inline:0 2.75rem;
  background:none; border:0;
  /* rgba en clair et non un token : le projet n'a que --ivory / --ivory-60 /
     --ivory-85. Un var(--ivory-15) inventé serait INVALIDE et la couleur
     retomberait silencieusement sur currentColor — soit un filet ivoire
     pleine opacité, tout l'inverse d'un trait discret (défaut réellement
     produit ici, vu à la mesure et pas à la relecture).

     .38 et non .22 comme au premier jet : à .22 le filet composite à
     1,87:1 sur le fond #14120F, sous le 3:1 que WCAG 1.4.11 demande pour
     la bordure d'un composant d'interface — le champ était littéralement
     difficile à voir, et c'est le retour utilisateur qui l'a signalé avant
     que je le mesure. Seuil atteint à .36 ; .38 laisse une marge. Reste
     dans la famille des bordures du projet (.btn--ghost est à .35). */
  border-bottom:1px solid rgba(242,237,225,.38);
  border-radius:0; /* iOS arrondit type=search par défaut */
  -webkit-appearance:none; appearance:none;
  color:var(--ivory);
  font-family:var(--font-body); font-weight:400;
  /* 16px et pas .74rem comme .filter, malgré la cohérence de registre :
     sous 16px, Safari iOS ZOOME la page à la prise de focus d'un input et
     l'utilisateur doit repincer pour revenir. Un bouton (.filter) n'a pas ce
     problème, un champ de saisie si — c'est la même famille de défaut mobile
     que le bouton de 26px et la puce de 38px déjà corrigés sur ce projet.
     Le letter-spacing est resserré (.12em au lieu de .16em) pour compenser
     visuellement la taille supérieure. */
  font-size:16px;
  letter-spacing:.12em; text-transform:uppercase;
  text-align:start;
  transition:border-color .25s ease;
}
.catsearch__input::placeholder{ color:var(--ivory-60); opacity:1; }
/* Focus : l'or souligne l'actif (grammaire du site). Le box-shadow épaissit
   le filet à 2px sans le border-width, donc sans décalage de mise en page —
   une simple bascule de couleur sur 1px serait un repère trop faible au
   clavier pour justifier outline:none. */
.catsearch__input:focus{
  outline:none;
  border-bottom-color:var(--gold);
  box-shadow:0 1px 0 0 var(--gold);
}
/* La croix native de Chrome/Safari doublerait notre bouton. */
.catsearch__input::-webkit-search-cancel-button{ -webkit-appearance:none; appearance:none; }

.catsearch__clear{
  position:absolute; inset-block-start:0; inset-inline-end:0;
  width:44px; height:44px;              /* cible tactile pleine, §5 racine */
  display:flex; align-items:center; justify-content:center;
  background:none; border:0; cursor:pointer;
  color:var(--ivory-60); font-size:1.35rem; line-height:1;
  transition:color .2s ease;
}
.catsearch__clear:hover{ color:var(--ivory); }
.catsearch__clear:active{ transform:scale(.94); }
.catsearch__clear[hidden]{ display:none; }

/* Grille dense au service du volume (11+ pièces) ; la première pièce
   (rythme éditorial, pas un hasard de DOM) casse la répétition en
   s'étalant pleine largeur — sans elle, une grille identique répétée
   redevient le "identical card grid" que la méthode bannit. */
.grid{
  display:grid;
  grid-template-columns:repeat(auto-fill, minmax(320px, 1fr));
  gap:clamp(2rem,3.5vw,2.8rem) clamp(1.5rem,3vw,2.2rem);
  max-width:1376px; margin:0 auto;
}

.card--featured{ grid-column:1 / -1; }
.card--featured .card__btn{
  display:grid;
  grid-template-columns:1.35fr 1fr;
  grid-template-rows:auto auto 1fr;
  column-gap:clamp(2rem,4vw,3.5rem);
}
.card--featured .card__media{
  grid-column:1; grid-row:1 / -1;
  aspect-ratio:6/5;
}
.card--featured .card__eyebrow{ grid-column:2; grid-row:1; margin-top:0; }
.card--featured .card__name{
  grid-column:2; grid-row:2;
  /* Le nom de la pièce vedette est le PLUS GRAND texte de l'écran
     catalogue, devant « La collection » (critère Perrotin C1 : l'œuvre
     domine toujours le chrome — mesuré : 36.8px vs 46.4px avant, le
     mobilier de section écrasait la pièce). Vérifié aux 3 largeurs :
     32.8 > 32 (375), 32.8 > 30.7 (768), 49 > 46.4 (1440). */
  font-size:clamp(2.05rem,3.4vw,3.05rem);
}

@media (max-width:900px){
  .card--featured .card__btn{
    grid-template-columns:1fr; grid-template-rows:auto auto auto;
    column-gap:0;
  }
  .card--featured .card__media{ grid-column:1; grid-row:1; aspect-ratio:3/4; }
  .card--featured .card__eyebrow{ grid-column:1; grid-row:2; margin-top:1.2rem; }
  .card--featured .card__name{ grid-column:1; grid-row:3; }
}

/* Carte de clôture — comble la ligne finale incomplète de la grille dense
   (10 pièces / 3 colonnes = une ligne à 1 seule carte, orpheline visuellement)
   et rappelle que le catalogue grandit, plutôt qu'un vide silencieux. */
.card--cta .card-cta__inner{
  display:flex; flex-direction:column; align-items:flex-start;
  justify-content:center; height:100%;
  /* `width:100%` est INDISPENSABLE, pas décoratif : avec `height:100%`
     seul, `aspect-ratio` dérivait la largeur de la HAUTEUR de la ligne
     (572px mesurés dans une colonne de 435px). La carte débordait donc
     toujours ; tant qu'elle tombait en colonne 1 ou 2 le débordement
     mordait sur la colonne voisine sans atteindre le bord de page, et
     restait invisible. Dès que le nombre de pièces change de parité
     (une vente, un retrait, un ajout) elle atterrit en dernière colonne
     et la PAGE déborde — 105px mesurés. Largeur et hauteur étant toutes
     deux définies, `aspect-ratio` est ignoré et la carte remplit sa
     cellule ; il ne reprend la main que si elle est seule sur sa ligne
     (hauteur indéfinie), ce qui était son intention d'origine. */
  width:100%;
  aspect-ratio:3/4; box-sizing:border-box;
  padding:2.2rem;
  border:1px solid rgba(184,152,90,.3);
  background:rgba(242,237,225,.02);
}
.card-cta__mark{ color:var(--gold); font-size:1.3rem; }
.card-cta__title{
  display:block; margin-top:1rem;
  font-family:var(--font-display); font-weight:500;
  font-size:1.35rem; line-height:1.28; color:var(--ivory);
  text-wrap:balance;
}
.card-cta__body{
  display:block; margin-top:.8rem;
  font-size:.88rem; line-height:1.55; color:var(--ivory-60);
}
.card-cta__action{
  margin-top:1.6rem;
  min-height:44px; padding:.4rem 1.6rem;
  font-size:.72rem;
}
@media (hover:hover) and (pointer:fine){
  .card--cta:hover{ transform:none; }
}
.grid__empty{
  margin:3rem auto 0; max-width:32rem;
  text-align:center; font-size:.95rem; color:var(--ivory-60);
}
/* Compteur de résultats : vide (donc sans hauteur) hors recherche active —
   « 18 pièces » affiché en permanence relèverait du registre boutique. */
.grid__count{
  margin:1.6rem auto 0; text-align:center;
  font-family:var(--font-body); font-size:.7rem;
  letter-spacing:.16em; text-transform:uppercase;
  color:var(--ivory-60);
}
.grid__count:empty{ margin:0; }

.card{ transition:transform .3s var(--ease-out); }
.card.is-hidden{ display:none; }
.card__btn{
  display:block; width:100%; padding:0;
  background:none; border:0; cursor:pointer;
  text-align:start; color:inherit; font:inherit;
}
.card__media{
  position:relative; display:block;
  aspect-ratio:3/4; overflow:hidden;
  background:#1a1713;
}
.card__media img{
  width:100%; height:100%; object-fit:cover;
}
/* Liseré d'or au survol : la pièce est « encadrée » quand on la considère.
   Le zoom d'image au survol a été retiré (critère Perrotin C7, mesuré
   scale 1.045 avant) : on n'étire pas un tapis du XIXe sous le curseur —
   le feedback vit dans le CADRE (liseré + lift de la card entière),
   jamais dans les pixels de l'œuvre. Le liseré est densifié (.55→.8)
   pour compenser la disparition du zoom. */
.card__media::after{
  content:''; position:absolute; inset:0;
  border:1px solid rgba(184,152,90,0);
  transition:border-color .35s ease;
  pointer-events:none;
}
.card__btn:focus-visible .card__media::after{ border-color:rgba(184,152,90,.8); }
@media (hover:hover) and (pointer:fine){
  .card:hover{ transform:translateY(-4px); }
  .card__btn:hover .card__media::after{ border-color:rgba(184,152,90,.8); }
}
.card__count{
  position:absolute; right:.7rem; bottom:.7rem;
  padding:.28rem .6rem;
  background:rgba(20,18,15,.75); color:var(--ivory-85);
  font-size:.68rem; letter-spacing:.12em; text-transform:uppercase;
}
html[lang="ar"] .card__count{ letter-spacing:0; text-transform:none; }
.card__eyebrow{
  display:block; margin-top:1.2rem;
  font-size:.68rem; letter-spacing:.24em; text-transform:uppercase;
  color:var(--gold);
}
.card__name{
  display:block; margin-top:.5rem;
  font-family:var(--font-display); font-weight:500;
  font-size:1.5rem; line-height:1.22; color:var(--ivory);
  text-wrap:balance;
}

/* Mention d'état (Vendu / Réservé) — écho volontairement ATONE de
   l'eyebrow : mêmes corps, graisse et interlettrage, mais ivoire
   atténué au lieu de l'or. La grammaire du site réserve l'or à l'actif
   (trait d'or = état courant) ; une pièce vendue est précisément ce qui
   ne l'est plus. La photo, elle, n'est jamais touchée — ni grisée ni
   désaturée : ce serait contredire l'exigence unique du client (voir
   la pièce comme si l'on se tenait devant elle). */
.card__status{
  display:block; margin-top:.55rem;
  font-size:.68rem; font-weight:500; letter-spacing:.24em; text-transform:uppercase;
  color:var(--ivory-60);
}
/* Vedette : le statut suit le nom dans la colonne texte, pas sous la photo. */
.card--featured .card__status{ grid-column:2; grid-row:3; }
@media (max-width:900px){
  .card--featured .card__status{ grid-column:1; grid-row:4; }
}

/* Conversion distribuée (critère Perrotin C8) : micro-lien d'enquiry
   sous chaque pièce — la prise de contact vit au niveau de l'œuvre,
   pas seulement au fond de la fiche. Registre : minuscule, fléché,
   souligné d'or au survol (grammaire d'état du site). */
.card__contact{ margin-top:.55rem; }
.card__contact-link{
  display:inline-flex; align-items:center;
  min-height:44px; padding:.2rem 0;
  font-size:.7rem; font-weight:400; letter-spacing:.18em; text-transform:uppercase;
  color:var(--ivory-60); text-decoration:none;
  transition:color .2s ease;
}
.card__contact-link::before{
  content:'\2192\00a0\00a0';  /* → : flèche portée par le CSS, mirroirée en RTL */
}
[dir="rtl"] .card__contact-link::before{ content:'\2190\00a0\00a0'; }
html[lang="ar"] .card__contact-link{ letter-spacing:0; text-transform:none; }
html[lang="ar"] .card__status,
html[lang="ar"] .lightbox__status{ letter-spacing:0; text-transform:none; }
.card__contact-link:hover{
  color:var(--ivory);
  text-decoration:underline; text-underline-offset:5px;
  text-decoration-color:var(--gold);
}
/* Le micro-lien de conversion est, sur mobile, la seule action atteignable
   sans ouvrir la fiche — il lui manquait pourtant tout retour au doigt.
   Valeur plus discrète (.97) que les commandes carrées : c'est du texte, une
   réduction franche s'y verrait comme un défaut de rendu. */
.card__contact-link:active{ transform:scale(.97); }
/* La vedette : sa grille interne vit sur le bouton (frère du lien) —
   l'article devient lui-même une grille aux mêmes colonnes pour que le
   micro-lien s'aligne sur la colonne texte, pas sous la photo. */
.card--featured{
  display:grid;
  grid-template-columns:1.35fr 1fr;
  column-gap:clamp(2rem,4vw,3.5rem);
}
.card--featured .card__btn{ grid-column:1 / -1; }
.card--featured .card__contact{ grid-column:2; margin-top:.9rem; }
@media (max-width:900px){
  .card--featured{ grid-template-columns:1fr; }
  .card--featured .card__contact{ grid-column:1; }
}

/* ---------- Lightbox / fiche produit ---------- */
/* Entrée posée (.3s), sortie vive (.18s) — asymétrie délibérée : le
   panneau se déploie (scale + léger translateY, centré comme il se doit
   pour un modal non ancré à un déclencheur), le fond ne fait qu'un fondu. */
.lightbox{
  position:fixed; inset:0; z-index:120;
  display:flex; align-items:center; justify-content:center;
  padding:clamp(0rem,2vw,2.5rem);
  opacity:0; visibility:hidden;
  transition:opacity .18s ease, visibility 0s linear .18s;
}
.lightbox.is-open{
  opacity:1; visibility:visible;
  transition:opacity .3s var(--ease-out);
}
.lightbox__panel{
  transform:scale(.96) translateY(10px);
  opacity:0;
  transition:transform .2s ease, opacity .18s ease;
  /* Instance unique réutilisée (jamais 1-par-carte) et interaction
     répétée plusieurs fois par session : le hint permanent est justifié
     ici, contrairement aux cards (audit gsap-performance). */
  will-change:transform, opacity;
}
.lightbox.is-open .lightbox__panel{
  transform:scale(1) translateY(0);
  opacity:1;
  transition:transform .34s var(--ease-out), opacity .3s var(--ease-out);
}

/* Déploiement v2 (passe Fable) : la photo s'installe d'abord, puis la
   colonne d'information se compose de haut en bas — la fiche « se
   dresse » comme un lot qu'on présente, au lieu d'apparaître d'un bloc.
   Même pattern que le hero (from{} + backwards) : rejoue à chaque
   ouverture, s'annule net à la fermeture (retour instantané à l'état
   de base pendant le fondu de sortie), et prefers-reduced-motion
   neutralise tout via la règle globale. */
.lightbox.is-open .lightbox__gallery{ animation:lb-in .55s var(--ease-out) .05s backwards; }
.lightbox.is-open .lightbox__family{ animation:lb-rise .45s var(--ease-out) .16s backwards; }
.lightbox.is-open .lightbox__name{ animation:lb-rise .45s var(--ease-out) .22s backwards; }
.lightbox.is-open .lightbox__status{ animation:lb-rise .45s var(--ease-out) .19s backwards; }
.lightbox.is-open .lightbox__ref{ animation:lb-rise .45s var(--ease-out) .27s backwards; }
.lightbox.is-open .lightbox__meta > div:nth-child(1){ animation:lb-rise .4s var(--ease-out) .3s backwards; }
.lightbox.is-open .lightbox__meta > div:nth-child(2){ animation:lb-rise .4s var(--ease-out) .34s backwards; }
.lightbox.is-open .lightbox__meta > div:nth-child(3){ animation:lb-rise .4s var(--ease-out) .38s backwards; }
.lightbox.is-open .lightbox__meta > div:nth-child(4){ animation:lb-rise .4s var(--ease-out) .42s backwards; }
.lightbox.is-open .lightbox__meta > div:nth-child(5){ animation:lb-rise .4s var(--ease-out) .46s backwards; }
.lightbox.is-open .lightbox__desc{ animation:lb-rise .45s var(--ease-out) .48s backwards; }
.lightbox.is-open .lightbox__price{ animation:lb-rise .45s var(--ease-out) .54s backwards; }
.lightbox.is-open .lightbox__cta{ animation:lb-rise .45s var(--ease-out) .6s backwards; }
@keyframes lb-in{ from{ opacity:0; transform:scale(.985); } }
@keyframes lb-rise{ from{ opacity:0; transform:translateY(14px); } }
.lightbox__scrim{ position:absolute; inset:0; background:rgba(20,18,15,.94); cursor:pointer; }
.lightbox__close{
  position:absolute; top:.9rem; right:.9rem; z-index:5;
  width:48px; height:48px;
  display:flex; align-items:center; justify-content:center;
  background:rgba(20,18,15,.85); color:var(--ivory);
  border:1px solid rgba(184,152,90,.4); cursor:pointer;
  font-size:1.5rem; line-height:1;
  transition:color .25s ease, border-color .25s ease;
}
.lightbox__close:hover{ color:var(--gold); border-color:var(--gold); }
/* Même retour de presse que les deux autres commandes de la fiche
   (.lightbox__nav et .lightbox__thumb l'avaient, la fermeture non). */
.lightbox__close:active{ transform:scale(.94); }
.lightbox__panel{
  --lb-pad:clamp(1.25rem,3vw,2.5rem);
  position:relative;
  width:min(1160px,100%); max-height:min(92vh,100%);
  overflow-y:auto;
  display:grid; gap:clamp(1.5rem,3vw,3rem);
  background:var(--black); color:var(--ivory);
  border:1px solid rgba(184,152,90,.22);
  padding:var(--lb-pad);
}
/* Garde-fou min-width sur la colonne unique mobile : sans lui, la largeur
   intrinsèque de la photo (contain à 62vh de haut ≈ 377px) impose son
   min-content à toute la colonne et fait déborder le panneau du viewport
   à 375px (texte tronqué au bord droit — mesuré, panel scrollWidth 421
   pour 358 de clientWidth). Le template desktop se protégeait déjà avec
   minmax(0,…) ; la colonne implicite mobile, non. */
.lightbox__gallery,
.lightbox__info{ min-width:0; }

/* Scrollbars des zones défilantes de la fiche : jamais la barre grise
   par défaut du navigateur en plein noir de maison de vente (élément
   brut par accident — audit anti-slop 2026-07-15). Le filet d'or fin
   sert aussi d'affordance : il signale que la colonne d'info défile
   (les CTA vivent parfois sous le pli aux viewports courts). */
.lightbox__panel,
.lightbox__info,
.lightbox__thumbs{
  scrollbar-width:thin;
  scrollbar-color:rgba(184,152,90,.35) transparent;
}
.lightbox__panel::-webkit-scrollbar,
.lightbox__info::-webkit-scrollbar,
.lightbox__thumbs::-webkit-scrollbar{ width:8px; height:8px; }
.lightbox__panel::-webkit-scrollbar-thumb,
.lightbox__info::-webkit-scrollbar-thumb,
.lightbox__thumbs::-webkit-scrollbar-thumb{
  background:rgba(184,152,90,.3);
}
.lightbox__panel::-webkit-scrollbar-track,
.lightbox__info::-webkit-scrollbar-track,
.lightbox__thumbs::-webkit-scrollbar-track{ background:transparent; }
@media (min-width:900px){
  .lightbox__panel{ grid-template-columns:minmax(0,1.15fr) minmax(0,1fr); overflow:visible; }
  .lightbox__info{ max-height:calc(92vh - 5rem); overflow-y:auto; padding-right:.5rem; }
}
.lightbox__main{ position:relative; }
.lightbox__zoom{
  display:block; width:100%; padding:0; margin:0;
  background:none; border:0; cursor:zoom-in;
}
.lightbox__main img{
  width:100%; max-height:62vh; object-fit:contain;
  background:#0f0e0c;
  transition:opacity .22s ease, filter .22s ease;
}
/* Le blur masque le chevauchement des deux photos pendant le fondu. */
.lightbox__main img.is-swapping{ opacity:0; filter:blur(6px); }

/* Mode zoom plein écran : la photo seule, au service de « voir la pièce
   comme si l'on se tenait devant elle ». */
.lightbox.is-zoomed{ padding:0; }
.lightbox.is-zoomed .lightbox__zoom{ cursor:zoom-out; }
.lightbox.is-zoomed .lightbox__panel{
  grid-template-columns:1fr;
  width:100%; height:100%; max-height:100%;
  border:0; background:rgba(15,14,12,.98);
  align-content:center;
}
.lightbox.is-zoomed .lightbox__info{ display:none; }
.lightbox.is-zoomed .lightbox__main img{ max-height:calc(100vh - 190px); }
.lightbox.is-zoomed .lightbox__foot{ justify-content:center; }
.lightbox.is-zoomed .lightbox__thumbs{ flex:0 0 auto; }

/* Loupe d'inspection du nouage (mode zoom, pointeur fin).
   Bordure + ombre assumées : c'est un instrument optique fonctionnel,
   l'ombre le détache de la photo qu'il grossit. */
.lightbox__lens{
  position:absolute; z-index:4;
  width:220px; height:220px;
  border:1px solid rgba(184,152,90,.65);
  border-radius:50%;
  background-repeat:no-repeat;
  box-shadow:0 8px 32px rgba(0,0,0,.55);
  opacity:0; pointer-events:none;
  transition:opacity .18s ease;
}
.lightbox__nav{
  position:absolute; top:50%; transform:translateY(-50%);
  width:52px; height:52px;
  display:flex; align-items:center; justify-content:center;
  background:rgba(20,18,15,.68); color:var(--ivory-85);
  border:0; cursor:pointer;
  font-size:1.9rem; line-height:1; font-family:var(--font-display);
  transition:color .2s ease, background-color .2s ease, transform .12s var(--ease-out);
}
.lightbox__nav:hover{ color:var(--gold); background:rgba(20,18,15,.78); }
.lightbox__nav:active{ transform:translateY(-50%) scale(.94); }
.lightbox__nav--prev{ left:.6rem; }
.lightbox__nav--next{ right:.6rem; }
.lightbox__foot{
  display:flex; align-items:center; gap:1rem;
  margin-top:.85rem;
}
.lightbox__thumbs{
  display:flex; gap:.6rem; flex:1 1 auto;
  overflow-x:auto; padding-bottom:.25rem;
}
.lightbox__thumb{
  flex:0 0 auto; width:64px; height:64px; padding:0;
  background:none; border:1px solid transparent; cursor:pointer;
  opacity:.62;
  transition:opacity .2s ease, border-color .2s ease, transform .12s var(--ease-out);
}
.lightbox__thumb:hover{ opacity:1; }
.lightbox__thumb:active{ transform:scale(.95); }
.lightbox__thumb img{ width:100%; height:100%; object-fit:cover; }
.lightbox__thumb.is-active{ border-color:var(--gold); opacity:1; }
.lightbox__counter{
  flex:0 0 auto;
  font-family:var(--font-display); font-style:italic;
  font-size:1rem; letter-spacing:.06em;
  color:var(--ivory-60);
  /* "1 / 5" est une paire numérique de sens LTR : isolée pour ne jamais
     s'inverser visuellement dans un contexte RTL (bug bidi réel constaté). */
  direction:ltr; unicode-bidi:isolate;
}
/* Utilitaire générique pour tout contenu LTR (numéro, poignée @handle,
   adresse) intégré dans une page RTL — même bug bidi que le compteur
   ci-dessus, généralisé le 2026-07-14 après découverte sur le téléphone,
   l'Instagram et l'adresse de la section Contact. */
.ltr-isolate{ direction:ltr; unicode-bidi:isolate; }
@media (min-width:900px){
  .lightbox__thumb{ width:72px; height:72px; }
}
.lightbox__family{
  margin:0 0 .5rem;
  font-size:.7rem; letter-spacing:.24em; text-transform:uppercase;
  color:var(--gold);
}
.lightbox__name{
  margin:0 0 .55rem;
  font-family:var(--font-display); font-weight:500;
  font-size:clamp(1.6rem,3vw,2.2rem); line-height:1.15;
  text-wrap:balance;
}
/* Référence de la pièce — la convention de lot d'une maison de vente,
   discrète sous le nom. L'ID latin (TPS-001) reste un run LTR unique,
   correct tel quel dans le contexte arabe. */
.lightbox__ref{
  margin:0 0 1.6rem;
  font-size:.72rem; letter-spacing:.2em; text-transform:uppercase;
  color:var(--ivory-60);
}
/* État de la pièce, en TÊTE de colonne — sous la famille, avant le nom.
   Ce n'est pas un choix esthétique : à 375px la colonne d'information
   défile sous une barre CTA collante à fond plein, et tout ce qui suit
   la réf. est hors écran à l'ouverture. Une mention placée plus bas
   laissait une pièce vendue paraître disponible dans la vue initiale.
   Ici elle est lue avant toute action, à toutes les largeurs. */
.lightbox__status{
  margin:0 0 .7rem;
  font-size:.72rem; font-weight:500; letter-spacing:.2em; text-transform:uppercase;
  color:var(--ivory-60);
}
.lightbox__meta{ margin:0; }
.lightbox__meta > div{
  display:grid; grid-template-columns:110px 1fr; gap:1rem;
  padding:.65rem 0;
  border-bottom:1px solid rgba(242,237,225,.08);
}
.lightbox__meta dt{
  font-size:.68rem; letter-spacing:.2em; text-transform:uppercase;
  color:var(--gold); padding-top:.2rem;
}
.lightbox__meta dd{ margin:0; font-size:.95rem; color:var(--ivory-85); }
.lightbox__desc{
  margin:1.3rem 0 0;
  font-size:.98rem; line-height:1.8; font-weight:300;
  color:var(--ivory-85);
}
.lightbox__price{
  margin:1.7rem 0 0;
  font-size:.8rem; letter-spacing:.2em; text-transform:uppercase;
  color:var(--ivory);
}
.lightbox__price::before{
  content:''; display:block;
  width:34px; height:1px;
  background:rgba(184,152,90,.6);
  margin-bottom:.9rem;
}
.lightbox__cta{ display:flex; flex-wrap:wrap; gap:.8rem; margin-top:1.4rem; }
/* Mobile : le panneau se scrolle sur ~2 écrans — sans ceci, WhatsApp/
   e-mail (l'action principale de toute la fiche) n'apparaissent qu'après
   ~665px de scroll (mesuré à 375×812). Barre collée au bas du panneau,
   dans la zone de pouce, fond plein pour que le texte défile dessous. */
@media (max-width:899px){
  .lightbox__cta{
    position:sticky; bottom:calc(-1 * var(--lb-pad)); z-index:2;
    margin:1.4rem calc(-1 * var(--lb-pad)) calc(-1 * var(--lb-pad));
    padding:.9rem var(--lb-pad) var(--lb-pad);
    background:var(--black);
    border-top:1px solid rgba(184,152,90,.18);
  }
}

/* ---------- Contact ---------- */
.contact{ background:var(--ivory); color:var(--black); }
.contact__grid{
  display:grid; gap:clamp(2.5rem,6vw,4.5rem); align-items:start;
  max-width:1100px; margin:0 auto;
}
@media (min-width:900px){ .contact__grid{ grid-template-columns:5fr 6fr; } }
@media (max-width:899px){ .contact__grid{ max-width:42rem; } }
.contact__list{ margin:0; }
.contact__list > div{
  display:grid; grid-template-columns:110px 1fr; gap:1.2rem;
  padding:1.05rem 0;
  border-bottom:1px solid rgba(20,18,15,.12);
}
/* Labels en grenat (pas en or) : l'or à 4.5:1 ne passe pas sur ivoire. */
.contact__list dt{
  font-size:.7rem; letter-spacing:.2em; text-transform:uppercase;
  color:var(--garnet); padding-top:.3rem;
}
.contact__list dd{ margin:0; font-size:1rem; font-weight:300; color:rgba(20,18,15,.88); }
.contact__list a{
  display:inline-block; padding:.6rem 0; margin:-.6rem 0;
  color:inherit; text-decoration:underline;
  text-underline-offset:4px; text-decoration-color:rgba(184,152,90,.6);
  transition:color .25s ease, text-decoration-color .25s ease;
}
.contact__list a:hover{ color:var(--garnet); text-decoration-color:var(--garnet); }
.contact__map{
  padding:.9rem;
  border:1px solid rgba(184,152,90,.45);
  background:rgba(255,255,255,.45);
}
.contact__map iframe{ display:block; width:100%; height:420px; border:0; }

/* ---------- Footer ---------- */
.footer{
  background:var(--black); color:var(--ivory);
  text-align:center;
  padding:3.5rem 1.5rem 2.8rem;
}
.footer .ornament__line{ width:44px; }
.footer__brand{
  margin:1.1rem 0 .4rem;
  font-family:var(--font-display); font-weight:500; font-size:1.25rem;
}
.footer__insta{ margin:.2rem 0 1rem; }
.footer__insta a{
  display:inline-flex; align-items:center;
  min-height:44px; padding:0 .5rem;
  font-size:.78rem; letter-spacing:.14em;
  color:var(--ivory-60); text-decoration:underline;
  text-underline-offset:4px; text-decoration-color:rgba(184,152,90,.5);
  transition:color .25s ease;
}
.footer__insta a:hover{ color:var(--ivory); }
.footer__copy{
  margin:0;
  font-size:.72rem; letter-spacing:.14em;
  color:rgba(242,237,225,.6);
}

/* ---------- Impression : document de consultation, pas d'UI ---------- */
@media print{
  .nav{ position:static; background:var(--black); }
  .burger, .mobile-menu, .lightbox, .skip-link, .lang-toggle{ display:none !important; }
  .hero{ min-height:auto; }
}

/* ---------- Reveals au scroll (plumbing pour les sections à venir) ---------- */
html.js [data-reveal]{
  opacity:0; transform:translateY(20px);
  transition:opacity .4s var(--ease-out), transform .4s var(--ease-out);
  transition-delay:var(--reveal-delay,0s);
}
html.js [data-reveal].is-visible{ opacity:1; transform:none; }

/* Passe Fable : la photo de card compose son entrée (clip + léger recul)
   pendant le fondu de la card. Le clip vit sur l'ENFANT img, jamais sur
   l'élément observé par l'IntersectionObserver (§4.7 racine : clipper
   l'observé annule sa surface d'intersection — deadlock silencieux).
   Pas de fill forward : l'animation finie, la transition de survol
   (.card__media img) reprend ses droits sans délai hérité. */
html.js .card[data-reveal].is-visible .card__media img{
  animation:card-photo .6s var(--ease-out) backwards;
  animation-delay:var(--reveal-delay,0s);
}
@keyframes card-photo{
  from{ clip-path:inset(0 0 14% 0); transform:scale(1.06); }
}

/* À l'impression, aucun observer ne tourne : tout doit être visible. */
@media print{
  html.js [data-reveal]{ opacity:1; transform:none; }
}

/* ---------- Responsive ---------- */
@media (max-width:900px){
  :root{ --nav-h:64px; }
  .nav__links{ display:none; }
  .burger{ display:flex; }
  .ornament__line{ width:44px; }
}

/* Tenue de la nav avec 4 langues (2026-07-19). Mesuré à 375px AVANT la
   4e langue : brand 117 + toggle 137 + burger 44 + padding 28,8 + gap 5,6
   = 332,4/375 ; le bouton ZH (+44) portait le total à 376,4 → débordement.
   On récupère la place sur les respirations horizontales UNIQUEMENT
   (padding de nav, padding latéral du toggle, gap) : les cibles tactiles
   restent 44×44, aucune information n'est masquée. */
@media (max-width:430px){
  .nav{ padding:0 .5rem; }
  .nav__right{ gap:.15rem; }
  .lang-toggle{ padding:0; }
  .lang-toggle button{ padding:0 .1rem; }
  .lang-toggle__sep{ display:none; }
}

@media (max-width:640px){
  /* Le crop mobile (hero-mobile.jpg) est une tranche verticale art-directée
     de la devanture. Bloc typographique resserré, posé sur la zone basse sombre. */
  .hero__bg img{ object-position:50% 50%; }
  .hero__title{ font-size:2.15rem; margin:1.4rem 0 .8rem; }
  .hero__tagline{ font-size:1.15rem; margin-bottom:.7rem; }
  /* Or mesuré à 3.51:1 sur la tranche mobile → ivoire (l'or tient à ≥768px). */
  .hero__subtitle{ margin-bottom:2rem; color:var(--ivory-85); }
  .hero__cta{ gap:.8rem; }
}

/* ---------- Arabe / RTL ----------
   Cormorant Garamond n'a aucun glyphe arabe : bascule de tokens vers
   Amiri (display) + Noto Naskh Arabic (corps). Écriture liée : jamais
   d'interlettrage ni d'italique synthétique. */
html[lang="ar"]{
  --font-display:"Amiri", "Noto Naskh Arabic", serif;
  --font-body:"Noto Naskh Arabic", "Segoe UI", sans-serif;
}
html[lang="ar"] body{ line-height:1.8; }
html[lang="ar"] *{ letter-spacing:0 !important; }
html[lang="ar"] .hero__tagline,
html[lang="ar"] .about__sign,
html[lang="ar"] .lightbox__counter{ font-style:normal; }
html[lang="ar"] .about__text p,
html[lang="ar"] .lightbox__desc{ line-height:2; }

/* ---------- Chinois (zh, LTR) — même pattern que l'arabe -----------
   Cormorant/Jost n'ont aucun idéogramme : sans override, le navigateur
   substitue une fonte système arbitraire. Noto Serif SC (display) +
   Noto Sans SC (corps). Le CJK ne supporte ni l'interlettrage (il
   disloque les idéogrammes) ni l'italique (oblique synthétique laide),
   et sa densité verticale plus forte affaisse les blocs de texte : les
   interlignes sont rehaussés en conséquence. Pas de règle RTL — le
   chinois est LTR, `dir` reste `ltr`. */
/* ORDRE CRITIQUE : le latin AVANT le CJK. La résolution de police est
   faite caractère par caractère — Cormorant/Jost couvrent le latin (nom
   de la maison, réf. TPS-001, adresse postale) et n'ont aucun idéogramme,
   qui tombe donc naturellement sur Noto. Mettre Noto en tête capturait
   AUSSI le latin : le titre du hero passait de 83 à 166px (deux lignes)
   et perdait la typographie signature du site — mesuré le 2026-07-20. */
html[lang="zh"]{
  --font-display:"Cormorant Garamond", "Noto Serif SC", serif;
  --font-body:"Jost", "Noto Sans SC", sans-serif;
}
html[lang="zh"] body{ line-height:1.85; }
html[lang="zh"] *{ letter-spacing:0 !important; }
/* Jamais d'italique synthétique sur du CJK. */
html[lang="zh"] .hero__tagline,
html[lang="zh"] .about__sign,
html[lang="zh"] .lightbox__counter{ font-style:normal; }
/* Les petites capitales espacées n'ont aucun sens en idéogrammes. */
html[lang="zh"] .hero__eyebrow,
html[lang="zh"] .card__eyebrow,
html[lang="zh"] .filter,
html[lang="zh"] .btn,
html[lang="zh"] .nav__links a,
html[lang="zh"] .card__count,
html[lang="zh"] .card__contact-link,
html[lang="zh"] .card__status,
html[lang="zh"] .contact__list dt,
html[lang="zh"] .lightbox__meta dt,
html[lang="zh"] .lightbox__price,
html[lang="zh"] .lightbox__status,
html[lang="zh"] .lightbox__ref{ text-transform:none; }
html[lang="zh"] .about__text p,
html[lang="zh"] .lightbox__desc{ line-height:2; }

/* Miroir RTL des positions physiques */
[dir="rtl"] .nav__links a::after{ transform-origin:right center; }
[dir="rtl"] .skip-link{ left:auto; right:1rem; }
[dir="rtl"] .card__count{ right:auto; left:.7rem; }
[dir="rtl"] .lightbox__close{ right:auto; left:.9rem; }
[dir="rtl"] .lightbox__nav--prev{ left:auto; right:.6rem; }
[dir="rtl"] .lightbox__nav--next{ right:auto; left:.6rem; }
@media (min-width:900px){
  [dir="rtl"] .lightbox__info{ padding-right:0; padding-left:.5rem; }
}

/* Nav mobile : 3 langues doivent tenir à 375px sans sacrifier les 44px */
@media (max-width:430px){
  .nav{ padding:0 .9rem; }
  .nav__right{ gap:.35rem; }
  .nav__ornament{ display:none; }
  .nav__name{ font-size:1.15rem; }
  .lang-toggle{ padding:0 .15rem; }
  .lang-toggle button{ padding:0 .1rem; }
  .lang-toggle__sep{ display:none; }
}

/* ---------- prefers-reduced-motion : tout visible, zéro mouvement ---------- */
@media (prefers-reduced-motion:reduce){
  html{ scroll-behavior:auto; }
  *,*::before,*::after{ animation:none !important; transition:none !important; }
  /* Le hero n'a plus besoin de règle dédiée : tous ses keyframes ont
     pour état de base l'état final (pattern from{} + backwards). */
  html.js [data-reveal]{ opacity:1; transform:none; }
}
