/* ============================================================
   NOS VÉHICULES — feuille additionnelle
   ------------------------------------------------------------
   Chargée APRÈS styles.css, et seulement par nos-vehicules.html.
   Elle n'ajoute que ce que l'accueil ne contient pas : la grille
   du catalogue, la carte-véhicule et la feuille de contact.

   Tout le reste — jetons de couleur, tons (data-tone), échelle
   typographique, en-tête, pied de page, boutons, barre mobile —
   vient de styles.css, inchangé. Aucune règle d'ici ne touche à
   une classe de l'accueil : la page d'accueil ne charge pas ce
   fichier, et rien n'y est redéfini.

   La CARTE est un portage du cadre du hero (Spotlight Card,
   21st.dev / @easemize), déjà porté dans styles.css sous le nom
   .hero-frame. On ne le réutilise pas tel quel : le hero est
   dimensionné par le viewport et n'a qu'une rangée utile. On
   reprend donc le MÊME jeu de variables et les MÊMES dégradés,
   avec deux écarts assumés, documentés plus bas.

   ATTENTION (même piège que sur l'accueil) : `background-
   attachment: fixed` est le cœur du Spotlight. Aucun ancêtre
   d'une carte ne doit porter transform, filter, perspective,
   backdrop-filter ni will-change — la lumière se figerait.
   ============================================================ */

/* ---------- Ouverture : un titre, un compte, un filet ---------- */
.veh-top { padding: clamp(30px, 4.6vw, 58px) 0 clamp(16px, 2.2vw, 24px); }
.veh-top-in {
  display: flex; flex-wrap: wrap; align-items: baseline;
  justify-content: space-between; gap: 10px 26px;
}
.veh-title {
  font-size: clamp(2rem, 5.6vw, 3.1rem); font-weight: 700;
  letter-spacing: var(--track-display); line-height: 1.02;
}
.veh-count {
  font-size: var(--fs-3xs); letter-spacing: var(--track-caps);
  text-transform: uppercase; color: var(--text-faint);
}
.veh-count b { color: var(--text); font-weight: 700; }
.veh-rule { height: 1px; background: var(--border); margin-top: clamp(14px, 2vw, 20px); }

/* ==========================================================
   LA GRILLE
   Deux colonnes dès le téléphone, trois à partir de 1040 px.
   Une seule sous 360 px : en dessous, la photographie tombe à
   130 px de large et la carte cesse d'être un objet.

   `align-items: stretch` n'est pas cosmétique. Dans une rangée,
   les noms ne font pas tous le même nombre de lignes ; sans
   égalisation, les prix et les boutons d'une même rangée ne
   tombent jamais sur la même ligne d'horizon — et c'est
   exactement ce qui fait « petite annonce ». Les cadres
   s'égalisent, la photographie garde sa taille, et c'est le bas
   de la carte qui absorbe la différence.
   ========================================================== */
.veh-cat { padding: clamp(20px, 2.6vw, 30px) 0 clamp(56px, 7vw, 100px); }
.veh-grid {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(20px, 3.4vw, 42px) clamp(11px, 2.2vw, 26px);
  align-items: stretch;
}
@media (min-width: 1040px) { .veh-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 359px)  { .veh-grid { grid-template-columns: 1fr; } }

/* …SAUF quand un « Détails » est déplié. Deux raisons, et la seconde
   n'est pas cosmétique :

   1. l'égalisation vaut pour un état de repos ; dès qu'une carte
      gagne 200 px, les voisines s'étirent avec elle et se creusent
      d'un grand vide entre le kilométrage et les boutons ;
   2. `stretch` donne à la carte une hauteur DÉFINIE, qui descend
      jusqu'au dépliant : sa rangée `1fr` se résout alors contre une
      hauteur nulle et le dépliage ne s'ouvre pas du tout. Le
      `0fr → 1fr` exige un conteneur de hauteur AUTOMATIQUE.

   Le dépliage est un état temporaire : la rangée cesse de s'aligner
   le temps de la lecture, et l'alignement revient à la fermeture. */
.veh-grid:has(.v-more.is-open) { align-items: start; }

.veh-msg {
  padding: 26px 0; font-size: var(--fs-xs); color: var(--text-dim);
  border-left: var(--rule) solid var(--yellow); padding-left: 14px; line-height: 1.6;
}
.veh-msg code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .92em; }

/* ==========================================================
   LA CARTE — portage du cadre du hero
   Deux écarts assumés par rapport à .hero-frame :

   · la deuxième rangée de la grille du composant ne porte plus
     les repères de défilement mais l'IDENTITÉ du véhicule.
     C'est ce qui rend le cadre PRESQUE CARRÉ (396 × 403 px au
     bureau) alors que la photographie reste en 16/10 — le seul
     rapport que les clichés du garage supportent sans couper
     une voiture ;
   · les repères descendent DANS l'image, faute de rangée libre.
   ========================================================== */
.veh { display: flex; flex-direction: column; min-width: 0; }
.veh > .v-frame { flex: 1 1 auto; }

.v-frame {
  /* getInlineStyles() du composant d'origine, à l'identique */
  --base: 52; --spread: 0; --radius: 14; --border: 3;
  --backdrop: var(--spot-backdrop); --backup-border: var(--backdrop);
  --size: 200; --outer: 1;
  --border-size: calc(var(--border, 2) * 1px);
  --spotlight-size: calc(var(--size, 150) * 1px);
  --hue: calc(var(--base) + (var(--xp, 0) * var(--spread, 0)));

  background-image: radial-gradient(
    var(--spotlight-size) var(--spotlight-size) at
    calc(var(--x, 0) * 1px) calc(var(--y, 0) * 1px),
    hsl(var(--hue, 210) calc(var(--saturation, 100) * 1%) calc(var(--lightness, 70) * 1%) / var(--bg-spot-opacity, .1)), transparent
  );
  background-color: var(--backdrop, transparent);
  background-size: calc(100% + (2 * var(--border-size))) calc(100% + (2 * var(--border-size)));
  background-position: 50% 50%;
  background-attachment: fixed;
  border: var(--border-size) solid var(--backup-border);
  border-radius: 1rem;
  position: relative;
  display: grid; grid-template-rows: auto 1fr;
  gap: clamp(9px, 1.3vw, 14px);
  padding: clamp(7px, 1.1vw, 14px);
  box-shadow: var(--elev-1);
  -webkit-backdrop-filter: blur(5px); backdrop-filter: blur(5px);
  touch-action: pan-y;
  transition: box-shadow .45s var(--ease), border-color .45s var(--ease);
}
@media (hover: hover) and (pointer: fine) {
  .v-frame:hover {
    --backup-border: rgb(var(--yellow-rgb) / .55);
    box-shadow: var(--elev-2), 0 0 30px -12px rgb(var(--yellow-rgb) / .5);
  }
}

/* PIÈGE — dans .v-frame, --border vaut « 3 », SANS UNITÉ (c'est la
   valeur du composant d'origine, reprise telle quelle). Écrire ici
   `border-color: var(--border)` produit une déclaration invalide,
   donc currentColor : un liseré NOIR. On repasse par
   --backup-border, la variable prévue pour cela. Même piège pour
   `border-radius: var(--radius)` à l'intérieur d'une carte. */
.veh.is-sold .v-frame { --backup-border: rgba(10, 10, 11, .11); box-shadow: none; }
@media (hover: hover) and (pointer: fine) {
  .veh.is-sold .v-frame:hover { --backup-border: rgba(10, 10, 11, .18); box-shadow: var(--elev-1); }
}

/* beforeAfterStyles du composant : déjà dans styles.css, en
   sélecteur global [data-spotlight]. Rien à redéclarer ici. */

/* ---------- La fenêtre et le film ---------- */
.v-window {
  position: relative; overflow: hidden;
  aspect-ratio: 16 / 10;
  border-radius: calc(var(--radius) * 1px - 6px);
  background: var(--paper-2);
}
.v-track {
  display: flex; width: 100%; height: 100%;
  transform: translate3d(calc(var(--i, 0) * -100% + var(--drag, 0px)), 0, 0);
  transition: transform 820ms var(--ease);
}
.v-frame.is-dragging .v-track { transition: none; }
.v-frame.is-settling .v-track { transition: transform 320ms var(--ease); }
.v-shot { flex: 0 0 100%; height: 100%; margin: 0; overflow: hidden; }
.v-shot img {
  width: 100%; height: 100%; object-fit: cover;
  filter: var(--photo-filter);
  transition: scale .8s var(--ease), filter .8s var(--ease);
}
@media (hover: hover) and (pointer: fine) { .v-frame:hover .v-shot img { scale: 1.035; } }
.veh.is-sold .v-shot img { filter: grayscale(.72) contrast(1.02) opacity(.9); }

/* Les flèches sont celles du hero (.frame-nav, styles.css) : même
   pastille claire, même chevron noir, même découverte à
   l'approche. On ne change que l'échelle — 34 px sur une carte de
   180 px couvraient un cinquième de la voiture — et le repos au
   doigt, où aucun survol n'existe. */
.v-window .frame-nav { width: clamp(26px, 2.4vw, 32px); height: clamp(26px, 2.4vw, 32px); z-index: 3; }
.v-window .frame-nav-prev { left: 9px; }
.v-window .frame-nav-next { right: 9px; }
@media (hover: none), (pointer: coarse) {
  .v-window .frame-nav-prev { opacity: var(--nav-prev, .5); translate: 0 -50%; }
  .v-window .frame-nav-next { opacity: var(--nav-next, .5); translate: 0 -50%; }
}

/* Les repères quittent la deuxième rangée — elle porte désormais
   l'identité — et reviennent DANS l'image, où sont les photos.
   Sur la photographie, le gris de --tick-off disparaîtrait : on
   passe au blanc translucide, avec une ombre portée. */
.v-ticks {
  position: absolute; left: 0; right: 0; bottom: 8px; z-index: 2;
  display: flex; justify-content: center; gap: 5px; pointer-events: none;
}
.v-tick {
  display: block; width: 15px; height: 2.5px; border-radius: 3px;
  background: rgba(255, 255, 255, .5); box-shadow: 0 1px 3px rgba(0, 0, 0, .4);
  transition: background var(--dur) var(--ease);
}
.v-tick.is-on { background: var(--yellow); }

/* La pastille de catégorie. Rectangulaire, et JAMAIS jaune : sur
   ce site le jaune veut dire « agissez ici », il reste au bouton.
   Démonstration = noir plein · Occasion = verre clair ·
   Vendu = noir avec une pastille rouge. */
.v-flag {
  position: absolute; top: 9px; left: 9px; z-index: 2;
  padding: 4px 8px; border-radius: 3px;
  font-size: var(--fs-3xs); font-weight: 700;
  letter-spacing: var(--track-caps-wide); text-transform: uppercase; line-height: 1;
}
.v-flag.demo { background: var(--ink); color: #fff; }
.v-flag.occ  { background: var(--glass-solid); color: var(--ink);
               -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px); }
.v-flag.sold { background: var(--ink); color: #fff; display: inline-flex; align-items: center; gap: 6px; }
.v-flag.sold i { width: 5px; height: 5px; border-radius: 50%; background: #e0564a; display: block; }

/* RÉSERVÉ — le troisième état, arrivé avec l'espace
   d'administration. Il se pose entre les deux autres, et son
   dessin le dit : l'aplat JAUNE de la marque, encre noire.

   Pourquoi le jaune et pas un troisième gris : réservé n'est pas
   une demi-mesure, c'est une bonne nouvelle — la voiture plaît.
   Le jaune est déjà, partout sur le site, la couleur de ce qui
   bouge (les boutons, les filets d'action) ; le noir reste celui
   de ce qui est acquis (démonstration, vendu). Une voiture
   réservée n'est pas grisée pour autant : elle garde ses
   couleurs, contrairement à `.is-sold`, parce qu'elle peut
   encore redevenir disponible. */
.v-flag.res { background: var(--yellow); color: var(--ink); }

/* ---------- Deuxième rangée : l'identité ----------
   Quatre lignes, jamais cinq. Le visiteur doit comprendre la
   voiture en deux à trois secondes ; tout le reste est derrière
   « Détails ». */
.v-foot {
  --foot-gap: clamp(5px, .7vw, 7px);
  display: flex; flex-direction: column; gap: var(--foot-gap); padding: 2px 4px 3px;
}
.v-make {
  font-size: var(--fs-3xs); letter-spacing: var(--track-caps-wide);
  text-transform: uppercase; color: var(--text-faint); line-height: 1;
}
.v-name {
  font-size: clamp(.94rem, 1.5vw, 1.125rem); font-weight: 700;
  letter-spacing: var(--track-soft); line-height: 1.22;
}
.v-price {
  font-size: clamp(.94rem, 1.5vw, 1.125rem); font-weight: 700;
  letter-spacing: var(--track-soft); line-height: 1;
}
.v-price.ask { font-weight: 400; color: var(--text-faint); font-size: var(--fs-xs); }
.veh.is-sold .v-name, .veh.is-sold .v-price { color: var(--text-faint); }
.v-meta {
  font-size: var(--fs-3xs); letter-spacing: var(--track-caps);
  text-transform: uppercase; color: var(--text-faint); line-height: 1.5;
}

.v-acts {
  display: flex; flex-wrap: wrap; justify-content: space-between; gap: 5px 14px;
  margin-top: auto; padding-top: clamp(8px, 1.1vw, 11px); border-top: 1px solid var(--border);
}
.v-act {
  background: none; border: none; padding: 0; cursor: pointer;
  font-size: var(--fs-3xs); letter-spacing: var(--track-caps); text-transform: uppercase;
  color: var(--text-dim); display: inline-flex; align-items: center; gap: 6px;
  transition: color var(--dur-fast) var(--ease);
}
.v-act.hot { color: var(--text); font-weight: 700; }
.v-act svg { transition: transform var(--dur-fast) var(--ease); }
.v-act .chev { transition: transform var(--dur) var(--ease); }
.v-act[aria-expanded="true"] .chev { transform: rotate(180deg); }
@media (hover: hover) and (pointer: fine) {
  .v-act:hover { color: var(--text); }
  .v-act.hot:hover svg { transform: translateX(3px); }
}
.v-act:active { transform: scale(.97); }

/* Le supplément d'information. Fermé par défaut — la carte n'est
   pas un accordéon : deux phrases, un filet de garantie, la liste
   d'équipements, rien de plus. Fermé, il ne coûte pas même
   l'interligne de la colonne. */
/* La HAUTEUR est animée en pixels, mesurée par le script, et non par
   le procédé habituel `grid-template-rows: 0fr → 1fr`. Celui-ci exige
   un conteneur de hauteur automatique ; ici le dépliant est un enfant
   souple d'une colonne elle-même logée dans une rangée de grille, et
   la valeur `1fr` s'y résolvait à ZÉRO — le dépliage ne s'ouvrait pas
   du tout. La mesure explicite ne dépend d'aucune de ces conditions.
   À la fin de l'animation le script repasse en `auto` : un
   changement de largeur (rotation du téléphone) ne laisse alors
   jamais une hauteur figée trop courte. */
.v-more { overflow: hidden; height: 0; transition: height .42s var(--ease); }
.v-more:not(.is-open) { margin-top: calc(-1 * var(--foot-gap)); }
.v-more-in { padding-top: 11px; display: flex; flex-direction: column; gap: 9px; }
.v-desc { font-size: var(--fs-2xs); line-height: 1.6; color: var(--text-dim); }
.v-tags {
  font-size: var(--fs-3xs); letter-spacing: var(--track-caps);
  text-transform: uppercase; color: var(--text-faint); line-height: 1.65;
}
.v-warr {
  font-size: var(--fs-3xs); letter-spacing: var(--track-caps); text-transform: uppercase;
  color: var(--text); border-left: var(--rule) solid var(--yellow);
  padding-left: 9px; line-height: 1.45;
}

/* ==========================================================
   LA CARTE D'OLIVIER — la fin de page
   ----------------------------------------------------------
   Refonte du 12 août. Diagnostic d'abord, parce qu'il change
   la réponse : la section était DÉJÀ noire (data-tone="dark").
   Le noir ne manquait donc pas — en ajouter n'aurait rien
   réglé. Trois choses la faisaient paraître pâle :

     1. AUCUN BORD. Bandeau noir pleine largeur, suivi du pied
        de page noir : deux blocs qui se rejoignent et forment
        un pavé de 500 px sans arête. Rien ne dit où la page
        se termine.
     2. LA HIÉRARCHIE À L'ENVERS. « Une question sur un
        véhicule ? » était en blanc plein, « Olivier vous
        répond. » — la phrase qui porte tout — en gris chaud.
        L'œil lisait donc le décor avant le message.
     3. LE FILET JAUNE INVISIBLE. `.eyebrow-line` naît en
        scaleX(0) et n'est déployé que par `[data-reveal].in` ;
        le <p> ne portait pas l'attribut, la marque jaune de
        l'accroche n'est jamais apparue.

   Correctifs, dans l'ordre du système de couleurs du site :

     NOIR — même quantité, mais posé en CARTE sur le blanc du
       catalogue, avec rayon, ombre à trois distances et de
       l'air autour. C'est le geste de `.signature` sur
       l'accueil, réemployé et non réinventé. Le noir cesse
       d'être un fond et devient un objet ; le pied de page
       retrouve sa frontière.
     BLANC — réservé à « Olivier vous répond. », en 700 et en
       blanc PUR : la seule chose la plus claire du bloc. La
       hiérarchie se fait par la valeur, pas par la couleur.
     GRIS CHAUD — la question (en 400, plus petit) et le
       paragraphe. La deuxième encre du site, à sa place.
     JAUNE — deux apparitions, jamais adjacentes : le filet du
       bord haut (marque à l'échelle du bloc) et le bouton
       (l'action). Le tiret de l'accroche est la même marque à
       l'échelle du mot, et il fonctionne enfin.

   Profondeur : le losange gravé à 4 % — filigrane déjà employé
   par « Le garage » et « Contact ». Aucun effet nouveau, aucun
   dégradé, aucun halo.
   ========================================================== */
.oli { padding: 0 0 clamp(56px, 8vw, 112px); }

.oli-card {
  position: relative; overflow: hidden;
  background: var(--bg);
  border-radius: clamp(var(--radius-lg), 2.4vw, 26px);
  padding: clamp(36px, 5.2vw, 68px) clamp(24px, 4vw, 60px) clamp(34px, 4.8vw, 60px);
  /* Trois distances — contact, épaisseur, pièce autour. La carte
     est noire mais l'ombre est celle du ton CLAIR : c'est sur du
     blanc qu'elle est posée, pas sur du noir. */
  box-shadow:
    0 1px 2px rgba(10, 10, 11, .06),
    0 12px 26px -14px rgba(10, 10, 11, .24),
    0 44px 88px -44px rgba(10, 10, 11, .55);
}
/* Le filet jaune plein le long du bord haut : 3 px en dur, comme
   `.signature::before`. --rule vaut 1 px en ton sombre, ce qui est
   juste pour un liseré de carte mais trop maigre pour une marque
   de bloc. */
.oli-card::before {
  content: ""; position: absolute; top: 0; left: 0; right: 0;
  height: 3px; background: var(--yellow);
}
.oli-losange {
  top: 50%; right: -6%; width: clamp(230px, 32vw, 440px);
  transform: translateY(-50%) rotate(-9deg);
}

.oli-in { position: relative; z-index: 1; display: grid; gap: clamp(26px, 3.4vw, 46px); align-items: center; }
@media (min-width: 820px) { .oli-in { grid-template-columns: minmax(0, 1fr) auto; } }
.oli-num { margin-bottom: 20px; }

/* Colonne flex : sans elle, les marges négatives des deux `.line`
   fusionnent et l'interligne du titre saute (le piège est documenté
   au § 8 de styles.css). */
.oli-title {
  display: flex; flex-direction: column;
  font-family: var(--font-display); font-weight: 700;
  font-size: clamp(1.8rem, 3.7vw, 2.9rem);
  letter-spacing: var(--track-display); line-height: 1.08;
  /* Filet de sécurité aux largeurs intermédiaires : si la phrase
     doit passer à la ligne, qu'elle se coupe en deux moitiés égales
     plutôt que sur une veuve d'un mot. */
  text-wrap: balance;
}
/* Le masque de révélation impose opacity:0 par défaut ; ici c'est
   la montée de `.line-inner` qui fait la révélation, pas le fondu. */
.oli-title[data-reveal] { opacity: 1; }
/* La question est l'amorce : plus petite, en 400, en gris chaud. */
.oli-title .line:first-child { font-size: .58em; }
.oli-q { font-weight: 400; letter-spacing: var(--track-head); color: var(--ink-warm); }
.oli-a { color: #fff; }

.oli-lead {
  margin-top: 18px; max-width: 46ch;
  font-size: var(--fs-sm); line-height: 1.7; color: var(--text-dim);
  text-wrap: pretty;
}

/* COLONNE, et pas une simple rangée qui se replie. La piste de
   droite est en `auto` : elle se dimensionne sur le contenu MAX,
   c'est-à-dire sur tout le bloc mis bout à bout. Avec la signature
   posée en `width:100%` dans la même rangée flex, la piste
   réservait 564 px pour un contenu qui en occupait 408 — et les
   156 px volés au titre le faisaient passer à la ligne, sur une
   veuve (« répond. » seul). Deux niveaux, et chacun se mesure
   pour ce qu'il est. */
.oli-acts { display: flex; flex-direction: column; align-items: flex-start; gap: 13px; }
.oli-btns { display: flex; flex-wrap: wrap; align-items: center; gap: 12px 14px; }
/* Au téléphone les deux boutons passent l'un sous l'autre : à
   largeurs différentes ils font un escalier. Pleine largeur et
   centrés, comme les boutons du menu mobile (.btn.block). */
@media (max-width: 620px) {
  .oli-acts, .oli-btns { width: 100%; }
  .oli-btns > .btn { flex: 1 1 100%; justify-content: center; }
}
/* On n'écrit pas à un garage, on écrit à quelqu'un : le nom tient
   la place de la photographie tant qu'elle n'est pas là. */
.oli-sign {
  font-size: var(--fs-3xs); letter-spacing: var(--track-caps-wide);
  text-transform: uppercase; color: var(--ink-warm);
}
/* L'adresse d'Olivier, EN CLAIR sous sa signature. La feuille de
   contact ne suffit pas : elle ouvre le logiciel de courrier du
   visiteur, ce que beaucoup n'ont pas configuré, et elle ne donne
   rien à recopier sur un téléphone. L'écrire est le seul moyen
   qu'on puisse en faire ce qu'on veut.
   Ni majuscules ni interlettrage : une adresse se lit lettre à
   lettre, l'espacement des petites capitales la rendrait plus
   longue à déchiffrer, pas plus élégante. Elle reste en gris
   chaud — la deuxième encre — sous la signature, jamais à côté du
   bouton : c'est un recours, pas une troisième action. */
.oli-mail {
  margin-top: -4px;
  font-size: var(--fs-2xs); color: var(--ink-warm);
  border-bottom: 1px solid transparent;
  transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
@media (hover: hover) and (pointer: fine) {
  .oli-mail:hover { color: #fff; border-bottom-color: rgb(var(--yellow-rgb)); }
}
/* Sur fond noir, le bouton d'action passe au jaune : c'est la
   règle du site, pas une exception de cette page. */
.oli .btn-primary { background: var(--yellow); color: var(--ink); }
@media (hover: hover) and (pointer: fine) { .oli .btn-primary:hover { background: #fff; color: var(--ink); } }

/* ==========================================================
   LA FEUILLE DE CONTACT — une seule pour toute la page
   <dialog> natif : piège de focus, Échap et fond inerte sont
   fournis par le navigateur. Carte centrée au bureau, feuille
   qui monte du bas au téléphone (le pouce y arrive).
   ========================================================== */
dialog.sheet {
  border: none; padding: 0; background: transparent;
  max-width: none; max-height: none; width: 100%; height: 100%;
  margin: 0; overflow: visible; color: var(--ink);
}
dialog.sheet::backdrop { background: rgba(10, 10, 11, .55); -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px); }
.sheet-box {
  position: absolute; left: 50%; top: 50%; translate: -50% -50%;
  width: min(560px, calc(100vw - 32px)); max-height: min(88vh, 760px); overflow: auto;
  background: #fff; border: 1px solid rgba(10, 10, 11, .11); border-radius: var(--radius-lg);
  box-shadow: var(--elev-3); padding: clamp(20px, 3vw, 30px);
}
@media (max-width: 640px) {
  .sheet-box {
    left: 0; top: auto; bottom: 0; translate: none; width: 100%; max-height: 92vh;
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
    padding: 20px 18px calc(20px + env(safe-area-inset-bottom));
  }
}
.sheet-x {
  position: absolute; top: 12px; right: 12px; width: 32px; height: 32px; border-radius: 50%;
  border: 1px solid rgba(10, 10, 11, .11); background: #fff; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
}
.sheet-who { display: flex; align-items: center; gap: 13px; }
/* Emplacement de la photographie d'Olivier. Tant qu'elle n'est
   pas là, un cercle en pointillé : un vide DÉCLARÉ vaut mieux
   qu'une silhouette générique. */
.sheet-av {
  width: 46px; height: 46px; border-radius: 50%; flex: 0 0 auto;
  border: 1px dashed rgba(10, 10, 11, .22); display: grid; place-items: center;
  font-size: var(--fs-3xs); letter-spacing: var(--track-caps); color: #75726d;
  background: var(--paper); overflow: hidden;
}
.sheet-av img { width: 100%; height: 100%; object-fit: cover; }
.sheet-who b { display: block; font-size: var(--fs-sm); font-weight: 700; letter-spacing: var(--track-soft); }
.sheet-who span { font-size: var(--fs-3xs); letter-spacing: var(--track-caps); text-transform: uppercase; color: #75726d; }
.sheet-veh {
  display: flex; align-items: center; gap: 12px; margin-top: 18px; padding: 10px;
  background: var(--paper); border: 1px solid rgba(10, 10, 11, .11); border-radius: var(--radius);
}
.sheet-veh img { width: 74px; height: 46px; object-fit: cover; border-radius: 4px; flex: 0 0 auto; }
.sheet-veh div { min-width: 0; }
.sheet-veh b {
  display: block; font-size: var(--fs-xs); font-weight: 700; letter-spacing: var(--track-soft);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.sheet-veh span { font-size: var(--fs-3xs); letter-spacing: var(--track-caps); text-transform: uppercase; color: #75726d; }
.sheet-form { margin-top: 18px; display: grid; gap: 12px; }
.sheet-2 { display: grid; gap: 12px; }
@media (min-width: 480px) { .sheet-2 { grid-template-columns: 1fr 1fr; } }
.sheet-field label {
  display: block; font-size: var(--fs-3xs); letter-spacing: var(--track-caps);
  text-transform: uppercase; color: #75726d; margin-bottom: 5px;
}
.sheet-field input, .sheet-field textarea {
  width: 100%; font: inherit; font-size: var(--fs-2xs); padding: 11px 12px;
  border: 1px solid rgba(10, 10, 11, .22); border-radius: var(--radius); background: #fff; color: var(--ink);
}
.sheet-field textarea { min-height: 88px; resize: vertical; line-height: 1.55; }
.sheet-send { margin-top: 4px; display: flex; flex-wrap: wrap; gap: 11px; align-items: center; }
.sheet-note { margin-top: 14px; font-size: var(--fs-3xs); color: #75726d; line-height: 1.6; }
.sheet-ok { margin-top: 14px; font-size: var(--fs-2xs); color: var(--ink); line-height: 1.6;
            border-left: 3px solid var(--yellow); padding-left: 10px; }
/* L'échec de l'envoi : même forme que la confirmation, mais un rouge
   sourd — c'est une information à lire, pas une alarme. */
.sheet-err { margin-top: 14px; font-size: var(--fs-2xs); color: var(--ink); line-height: 1.6;
             border-left: 3px solid #b4362f; padding-left: 10px; }
/* Le pot de miel : hors de l'écran, hors du parcours clavier, hors
   des lecteurs d'écran — mais bien présent dans le DOM du robot. */
.sheet-piege { position: absolute; left: -9999px; width: 1px; height: 1px; opacity: 0; pointer-events: none; }

/* ==========================================================
   LE TÉLÉPHONE — deux colonnes, donc chaque pixel compte.
   Rien n'est retiré de la carte : c'est l'approche des
   capitales et le corps qui se resserrent, pour que
   « CONTACTER OLIVIER » tienne sur une ligne dans une colonne
   de 140 px et que la PHOTOGRAPHIE reste le plus grand objet.
   ========================================================== */
@media (max-width: 759px) {
  .v-frame { border-radius: .8rem; }
  .v-window { border-radius: 7px; }
  .v-window .frame-nav { width: 22px; height: 22px; }
  .v-window .frame-nav svg { width: 12px; height: 12px; }
  .v-window .frame-nav-prev { left: 6px; opacity: var(--nav-prev, .42); }
  .v-window .frame-nav-next { right: 6px; opacity: var(--nav-next, .42); }
  .v-flag { top: 6px; left: 6px; padding: 3px 6px; font-size: .62rem; letter-spacing: .13em; }
  .v-ticks { bottom: 6px; gap: 4px; }
  .v-tick { width: 12px; height: 2px; }
  .v-foot { padding: 0 2px 3px; }
  .v-make { font-size: .62rem; letter-spacing: .15em; }
  .v-meta { font-size: .65rem; letter-spacing: .045em; }
  .v-act { font-size: .66rem; letter-spacing: .04em; gap: 5px; }
  .v-desc { font-size: .73rem; }
  .v-tags, .v-warr { font-size: .65rem; letter-spacing: .05em; }
}
