/* =========================================================================
   /assistant/ : l'assistant produit et marque, en application plein ecran.
   -------------------------------------------------------------------------
   Le principe qui gouverne tout le fichier : LA PAGE NE DEFILE PAS. Le corps
   fait exactement une hauteur d'ecran, l'en-tete du site occupe le haut, et
   ce qui reste est partage entre trois blocs qui ne bougent plus :

     bandeau photo  ->  se contracte des le premier message
     fil            ->  le seul element qui defile, a l'interieur de lui-meme
     rail de fiche  ->  ferme tant qu'aucun produit n'a ete cite

   Consequence assumee : cette page n'a pas le grand pied de page du site.
   Un pied de page pousse forcement la conversation hors de l'ecran, ce que
   la regle ci-dessus interdit. Les mentions utiles tiennent sous le champ de
   saisie, et la navigation reste entiere en haut.
   ========================================================================= */

/* ---------------------------------------------------------------- shell -- */

/* L'attribut « hidden » ne suffit pas des qu'une regle d'auteur pose un
   « display ». La feuille du navigateur dit bien « [hidden] { display:none } »,
   mais toute declaration d'auteur la depasse, quelle que soit sa specificite :
   le fil, la scene de comparaison et la ligne rangee declarent tous un
   display, ils restaient donc affiches tous ensemble, les uns par-dessus les
   autres. styles.css fait la meme declaration pour ses propres panneaux
   (.mega, .dropd, .drawer, .acx), c'est la convention du projet. */
.asst-thread__log[hidden],
.asst-compare[hidden],
.asst-dock[hidden],
.asst-rail[hidden] { display: none; }


/* Le site n'a pas d'utilitaire d'etiquette invisible : celui-ci sert au libelle
   du champ de saisie, qui doit exister pour un lecteur d'ecran sans se voir. */
.asst-body .visually-hidden {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  clip-path: inset(50%); overflow: hidden; white-space: nowrap;
}


html:has(body.asst-body) { height: 100%; }

body.asst-body {
  height: 100dvh;
  min-height: 100dvh;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  background: var(--atl-ink-1000);
}

/* La barre de progression de defilement que main.js injecte partout n'a
   aucun sens sur une page qui ne defile pas. */
body.asst-body .scrollprog { display: none; }

.asst-app {
  flex: 1 1 auto;
  min-height: 0;
  display: grid;
  grid-template-rows: auto minmax(0, 1fr);
}

/* ---------------------------------------------------------------- decor -- */

/* La photo occupe toute la surface de l'application, DERRIERE la conversation.
   Trois plans empiles, dans cet ordre : le decor (z 0), le voile (z 1), tout
   le reste (z 2). L'isolation cree le contexte d'empilement, sans quoi ces
   z-index iraient se comparer a ceux de l'en-tete du site. */
.asst-app { position: relative; isolation: isolate; }

.asst-scene {
  position: absolute; inset: 0; z-index: 0;
  overflow: hidden;
  /* Photo de secours : si la banque d'images est muette, le decor garde une
     image plutot que de se reduire a un aplat noir. Les calques la couvrent
     des que la banque repond. */
  background: var(--atl-ink-1000) url('/assets/img/gym-1.jpg') center 38% / cover no-repeat;
}

/* Les deux calques qui se fondent l'un dans l'autre. Aucun autre mouvement que
   l'opacite : c'est ce qui rend le changement calme au lieu de clignotant. */
.asst-hero__layer {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: 50% 38%;
  opacity: 0;
  transition: opacity var(--asst-fade, 1500ms) linear;
}
.asst-hero__layer.is-on { opacity: 1; }

/* LE VOILE. C'est lui qui rend la page lisible, et son profil n'est pas
   decoratif : il est calque sur l'endroit ou le texte se trouve.

   La conversation est ancree EN BAS et grandit vers le haut. Le bas doit donc
   etre franchement noir, jusqu'a la moitie de la hauteur au moins, sinon la
   derniere reponse et le champ de saisie passent sur une salle eclairee. Plus
   haut, le voile s'ouvre : c'est la zone que le texte n'atteint que lorsqu'il
   a deja ete lu et defile.

   Le second degre, horizontal, protege le titre et les messages, qui vivent a
   gauche, sans assombrir la droite ou la photo respire. */
.asst-scene__veil {
  position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background:
    /* 1. Le raccord avec l'en-tete du site, et l'assurance que le titre ne
          tombe jamais sur un plafond surexpose. */
    linear-gradient(to bottom, rgba(0, 0, 0, .62) 0%, rgba(0, 0, 0, 0) 22%),
    /* 2. La protection laterale : le titre et les messages vivent a gauche,
          la photo respire a droite. */
    linear-gradient(100deg,
      rgba(0, 0, 0, .70) 0%,
      rgba(0, 0, 0, .38) 34%,
      rgba(0, 0, 0, .08) 62%,
      rgba(0, 0, 0, .30) 100%),
    /* 3. Le degrade principal, du bas vers le haut. Franchement opaque sur les
          deux tiers inferieurs, la ou vit la conversation ; il ne s'ouvre que
          dans le dernier quart, ou le texte n'arrive qu'apres avoir ete lu. */
    linear-gradient(to top,
      var(--atl-ink-1000) 0%,
      rgba(0, 0, 0, .99) 24%,
      rgba(0, 0, 0, .96) 42%,
      rgba(0, 0, 0, .89) 58%,
      rgba(0, 0, 0, .72) 74%,
      rgba(0, 0, 0, .46) 88%,
      rgba(0, 0, 0, .30) 100%);
}

/* La pastille qui nomme l'endroit photographie. Elle apparait quand le decor
   change de sujet, ce qui fait lire le changement comme voulu plutot que
   comme aleatoire. */
/* La pastille se pose en haut a DROITE tant que la conversation n'a pas
   commence, et passe a GAUCHE des qu'elle demarre : c'est exactement le moment
   ou le rail de fiche vient occuper la droite, et ou le titre libere la
   gauche. Deux regles valent mieux qu'un chevauchement. */
.asst-scene__credit {
  position: absolute; z-index: 3;
  right: clamp(16px, 3vw, 34px); top: 16px;
  margin: 0;
  display: inline-flex; align-items: center; gap: 8px;
  padding: 6px 12px;
  background: rgba(0, 0, 0, .5);
  border: 1px solid rgba(255, 255, 255, .16);
  font-family: var(--font-mono);
  font-size: .64rem; letter-spacing: .1em; text-transform: uppercase;
  color: var(--atl-ink-150);
  opacity: 0;
  transform: translateY(-6px);
  transition: opacity 460ms var(--ease-out), transform 460ms var(--ease-out);
}
.asst-scene__credit.is-on { opacity: 1; transform: none; }
.asst-app.is-engaged .asst-scene__credit {
  right: auto; left: var(--gutter-desk);
}
.asst-scene__credit::before {
  content: ""; width: 5px; height: 5px; border-radius: 50%;
  background: var(--accent); flex: 0 0 auto;
}

/* ----------------------------------------------------------------- hero -- */

/* Plus un bandeau, juste un titre pose sur le decor. Il s'efface entierement
   des le premier message : la conversation demandee prend la place du discours
   d'accueil, et la photo reste. */
.asst-hero {
  position: relative; z-index: 2;
  padding-block: clamp(18px, 4vh, 46px) clamp(4px, 1vh, 14px);
  transition: opacity 320ms var(--ease-out), max-height 620ms var(--ease-out),
              padding 620ms var(--ease-out);
  overflow: hidden;
  max-height: 40vh;
}
.asst-app.is-engaged .asst-hero {
  opacity: 0; max-height: 0; padding-block: 0; pointer-events: none;
}

.asst-hero__inner { display: flex; flex-direction: column; gap: 10px; }

.asst-hero__eyebrow { margin: 0; }
.asst-hero__title {
  margin: 0;
  font-family: var(--font-display);
  text-transform: uppercase;
  letter-spacing: var(--track-display);
  line-height: 1.02;
  font-size: clamp(1.7rem, 3.6vw, 2.7rem);
  color: #fff;
  max-width: 18ch;
}
.asst-hero__lede {
  margin: 0;
  max-width: 52ch;
  color: var(--atl-ink-150);
  font-size: .93rem; line-height: 1.55;
}

/* ---------------------------------------------------------------- layout - */

.asst-shell {
  --asst-rail-w: clamp(300px, 26vw, 372px);
  min-height: 0;
  position: relative; z-index: 2;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 0px;
  /* Une seule rangee, qui prend TOUTE la hauteur. Sans cette ligne la rangee
     se dimensionne sur son contenu : sur un ecran haut avec peu de messages,
     le champ de saisie remontait au milieu de la page et laissait un grand
     vide noir en dessous. */
  grid-template-rows: minmax(0, 1fr);
  transition: grid-template-columns 560ms var(--ease-out), gap 560ms var(--ease-out);
  padding-block: clamp(14px, 2vw, 24px) clamp(12px, 1.6vw, 20px);
  gap: 0;
}
/* Une fiche existe, mais elle est rangee : le rail se reduit a sa languette. */
.asst-shell.has-fiche {
  grid-template-columns: minmax(0, 1fr) 44px;
  gap: clamp(14px, 1.6vw, 22px);
}
/* La fiche est deployee. */
.asst-shell.has-fiche.rail-open {
  grid-template-columns: minmax(0, 1fr) var(--asst-rail-w);
  gap: clamp(20px, 2.4vw, 34px);
}

/* Le plateau s'ouvre entre le fil et le rail : la conversation reste a
   gauche, la salle se dresse au centre, la fiche s'assemble a droite. */
.asst-shell.has-stage {
  grid-template-columns: minmax(0, 1fr) minmax(280px, 1.05fr) 0px;
  gap: clamp(14px, 1.6vw, 22px);
}
.asst-shell.has-stage.has-fiche {
  grid-template-columns: minmax(0, 1fr) minmax(280px, 1.05fr) 44px;
}
.asst-shell.has-stage.has-fiche.rail-open {
  grid-template-columns: minmax(0, 1fr) minmax(260px, 1fr) var(--asst-rail-w);
  gap: clamp(16px, 2vw, 28px);
}
.asst-shell.has-stage .asst-thread { max-width: 42rem; }

/* ------------------------------------------------------------------ fil -- */

/* Une conversation ne se lit pas sur 1200 px : le fil garde une largeur de
   lecture. Il s'aligne a GAUCHE, sur la meme regle verticale que le titre du
   bandeau : centre, il flotterait a cote de son propre titre. */
.asst-thread {
  min-width: 0; min-height: 0;
  width: 100%; max-width: 880px;
  display: grid;
  /* La colonne DOIT etre declaree en minmax(0, 1fr). Laissee implicite, la
     piste vaut « auto », donc max-content : la grille de comparaison, qui
     demande 940px, faisait alors deborder toute la page vers la droite au lieu
     de se serrer. minmax(0, …) est ce qui autorise la piste a etre plus etroite
     que son contenu. */
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: minmax(0, 1fr) auto;
}

.asst-thread__log {
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 4px clamp(6px, 1vw, 14px) 20px 0;
  display: flex; flex-direction: column;
  scrollbar-width: thin;
  scrollbar-color: var(--atl-ink-700) transparent;
  /* Le haut du fil s'efface. Deux raisons : le texte qui defile ne se coupe
     plus net sur une arete, et il ne remonte plus dans la partie claire de la
     photo, ou il deviendrait illisible avant d'avoir disparu. */
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 46px);
  mask-image: linear-gradient(to bottom, transparent 0, #000 46px);
}

/* margin-top:auto pousse le flux vers le bas tant qu'il ne remplit pas le
   fil, et n'a plus aucun effet des qu'il deborde : le haut reste donc
   toujours atteignable, ce que justify-content:flex-end ne garantit pas. */
.asst-thread__stream {
  margin-top: auto;
  display: flex; flex-direction: column; gap: 22px;
}
/* Tant que rien n'a ete demande, l'accueil se pose au milieu, pas en bas. */
.asst-app:not(.is-engaged) .asst-thread__stream { margin-bottom: auto; }
.asst-thread__log::-webkit-scrollbar { width: 8px; }
.asst-thread__log::-webkit-scrollbar-thumb { background: var(--atl-ink-700); }
.asst-thread__log::-webkit-scrollbar-track { background: transparent; }

/* --- l'accueil, tant que rien n'a ete demande --- */
.asst-intro {
  display: grid; gap: 18px;
  max-width: 62ch;
}
.asst-intro.is-out {
  animation: asst-fade-out 320ms var(--ease-out) forwards;
  pointer-events: none;
}
.asst-intro__mark {
  width: 34px; height: 34px;
  display: grid; place-items: center;
  background: var(--accent);
  color: #fff;
}
.asst-intro__mark svg { display: block; }
.asst-intro__line {
  margin: 0;
  font-size: clamp(1.05rem, 1.9vw, 1.35rem);
  line-height: 1.45;
  color: var(--atl-ink-100);
  max-width: 34ch;
}
.asst-intro__hint {
  margin: 0;
  font-family: var(--font-mono);
  font-size: .66rem; letter-spacing: .11em; text-transform: uppercase;
  color: var(--atl-ink-400);
}

.asst-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.asst-chip {
  appearance: none;
  border: 1px solid rgba(255, 255, 255, .16);
  background: rgba(0, 0, 0, .55);
  color: var(--atl-ink-150);
  font: inherit; font-size: .84rem;
  padding: 9px 14px;
  cursor: pointer;
  text-align: left;
  transition: border-color var(--dur-base) var(--ease-out), background var(--dur-base) var(--ease-out), color var(--dur-base) var(--ease-out);
}
.asst-chip:hover { border-color: var(--accent); color: #fff; background: rgba(20, 20, 22, .88); }
.asst-chip:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Les suites, sous une reponse : plus discretes que les puces d'accueil, elles
   accompagnent le texte au lieu de le concurrencer, et se posent l'une apres
   l'autre une fois la reponse ecrite. */
.asst-chips--suites { margin-top: 16px; }
.asst-chip--suite {
  font-size: .8rem; padding: 7px 12px;
  border-style: dashed;
  border-color: rgba(255, 255, 255, .22);
  color: var(--atl-ink-300);
  animation: asst-rise 460ms var(--ease-out) both;
  animation-delay: var(--d, 0ms);
}
.asst-chip--suite:hover { border-style: solid; color: #fff; }
.asst-chip--suite::before {
  content: "";
  width: 4px; height: 4px; border-radius: 50%;
  background: var(--accent); flex: 0 0 auto;
  margin-right: 2px;
}
.asst-chip--suite { display: inline-flex; align-items: center; gap: 7px; }

/* --- les messages --- */
.asst-msg { max-width: 100%; line-height: 1.68; font-size: .95rem; }

.asst-msg--user {
  align-self: flex-end;
  max-width: min(76%, 52ch);
  background: var(--accent); color: #fff;
  padding: 11px 16px;
  border-radius: 14px 14px 3px 14px;
  animation: asst-rise 420ms var(--ease-out) both;
}

/* La reponse n'est pas une bulle : elle occupe la largeur utile et respire,
   parce que c'est le texte qu'on vient lire. */
.asst-msg--bot {
  align-self: stretch;
  max-width: 68ch;
  color: var(--atl-ink-100);
  display: grid; gap: 0;
  padding-left: 34px;
  position: relative;
}
.asst-msg--bot::before {
  content: "";
  position: absolute; left: 0; top: 3px;
  width: 20px; height: 20px;
  background: var(--accent);
  clip-path: polygon(50% 0%, 100% 27%, 100% 73%, 50% 100%, 0% 73%, 0% 27%);
}
.asst-msg--bot strong { color: #fff; font-weight: 600; }
.asst-msg--bot em { color: var(--atl-ink-200); }
.asst-msg--bot code {
  font-family: var(--font-mono);
  font-size: .88em; background: var(--atl-ink-800);
  padding: .08em .38em; border-radius: 2px;
}

/* Chaque bloc de la reponse arrive l'un apres l'autre, comme si le texte
   se posait. Le retard est porte par --d, pose element par element en JS. */
.asst-msg--bot > * { animation: asst-rise 460ms var(--ease-out) both; animation-delay: var(--d, 0ms); }

.asst-p { margin: 0 0 .85em; }
.asst-p:last-child { margin-bottom: 0; }

.asst-sub {
  margin: 1.25em 0 .5em; font-weight: 600; color: #fff;
  font-size: .88rem; letter-spacing: .02em;
}
.asst-sub:first-child { margin-top: 0; }

/* styles.css met « ul { list-style:none } » pour toute la nav du site : sans
   ce rappel, une enumeration du modele s'affiche comme des lignes indentees
   sans puce, et on ne lit plus que c'est une liste. */
.asst-list { margin: 0 0 .9em; padding-left: 1.15em; display: grid; gap: .42em; list-style: disc; }
.asst-list li { line-height: 1.6; }
.asst-list li::marker { color: var(--accent); }
.asst-list:last-child { margin-bottom: 0; }

/* --- les boutons de page sous une reponse --- */
.asst-links { display: flex; flex-wrap: wrap; gap: 8px; margin: 14px 0 0; }
.asst-link {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 8px 13px;
  border: 1px solid rgba(255, 255, 255, .16);
  background: rgba(0, 0, 0, .55);
  color: var(--atl-ink-100);
  text-decoration: none;
  font-size: .82rem;
  transition: border-color var(--dur-base) var(--ease-out), background var(--dur-base) var(--ease-out), color var(--dur-base) var(--ease-out);
}
.asst-link svg { flex: 0 0 auto; transition: transform var(--dur-base) var(--ease-out); }
.asst-link:hover { border-color: var(--accent); background: var(--atl-ink-800); color: #fff; }
.asst-link:hover svg { transform: translateX(3px); }
.asst-link:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.asst-msg--system {
  align-self: center; text-align: center;
  color: var(--atl-ink-400); font-size: .84rem; font-style: italic;
  max-width: 46ch;
  animation: asst-rise 420ms var(--ease-out) both;
}
/* Le refus quotidien porte un lien vers le formulaire : il se centre comme le
   message qui l'accompagne, et perd l'italique du texte d'erreur. */
.asst-msg--system .asst-links { justify-content: center; margin-top: 12px; }
.asst-msg--system .asst-link { font-style: normal; }

/* --- l'attente --- */
.asst-thinking {
  align-self: flex-start;
  display: flex; align-items: center; gap: 10px;
  padding-left: 34px; position: relative;
  color: var(--atl-ink-400); font-size: .86rem;
  animation: asst-rise 300ms var(--ease-out) both;
}
.asst-thinking::before {
  content: "";
  position: absolute; left: 0; top: 1px;
  width: 20px; height: 20px;
  background: var(--accent);
  clip-path: polygon(50% 0%, 100% 27%, 100% 73%, 50% 100%, 0% 73%, 0% 27%);
  animation: asst-pulse 1.5s var(--ease-out) infinite;
}
.asst-thinking__dots { display: inline-flex; gap: 4px; }
.asst-thinking__dots i {
  width: 5px; height: 5px; border-radius: 50%;
  background: var(--atl-ink-400);
  animation: asst-bounce 1.1s ease-in-out infinite;
}
.asst-thinking__dots i:nth-child(2) { animation-delay: .16s; }
.asst-thinking__dots i:nth-child(3) { animation-delay: .32s; }

/* ------------------------------------------------------------- projet ---- */

/* La liste prete a partir vers « Mon projet ». Elle se distingue du reste de
   la reponse par un filet rouge a gauche : ce n'est plus du texte, c'est une
   chose qu'on emporte. */
.asst-projet {
  margin-top: 18px;
  border: 1px solid rgba(255, 255, 255, .16);
  border-left: 2px solid var(--accent);
  background: rgba(0, 0, 0, .58);
  padding: 14px 16px 16px;
  max-width: 460px;
  animation: asst-rise 520ms var(--ease-out) both;
  animation-delay: 120ms;
}
.asst-projet__title {
  margin: 0 0 12px;
  font-family: var(--font-mono);
  font-size: .62rem; letter-spacing: .12em; text-transform: uppercase;
  color: var(--atl-ink-400);
}
.asst-projet__list { margin: 0; padding: 0; list-style: none; display: grid; gap: 9px; }
.asst-projet__line {
  display: grid;
  grid-template-columns: 34px minmax(0, 1fr) auto auto;
  align-items: center; gap: 10px;
  animation: asst-rise 460ms var(--ease-out) both;
  animation-delay: var(--d, 0ms);
}
.asst-projet__media {
  width: 34px; height: 34px;
  background: var(--atl-ink-900);
  display: grid; place-items: center; overflow: hidden;
}
.asst-projet__media img { width: 100%; height: 100%; object-fit: contain; display: block; }
.asst-projet__name {
  font-size: .84rem; color: var(--atl-ink-100); line-height: 1.3;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.asst-projet__code {
  font-family: var(--font-mono);
  font-size: .62rem; letter-spacing: .05em; color: var(--atl-ink-500);
}
.asst-projet__qty {
  font-family: var(--font-mono);
  font-size: .74rem; color: #fff;
  min-width: 34px; text-align: right;
}

.asst-projet__go {
  appearance: none; cursor: pointer;
  width: 100%;
  margin-top: 14px;
  display: inline-flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 12px 15px;
  border: 1px solid var(--accent);
  background: var(--accent);
  color: #fff; font: inherit; font-size: .84rem; font-weight: 600;
  transition: background var(--dur-base) var(--ease-out), border-color var(--dur-base) var(--ease-out);
}
.asst-projet__go svg { transition: transform var(--dur-base) var(--ease-out); }
.asst-projet__go:hover:not(:disabled) { background: var(--atl-red-deep); border-color: var(--atl-red-deep); }
.asst-projet__go:hover:not(:disabled) svg { transform: translateX(3px); }
.asst-projet__go:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
.asst-projet__go:disabled {
  cursor: default;
  background: transparent; color: var(--atl-ink-300);
  border-color: var(--atl-ink-700);
}

/* ---------------------------------------------------------- comparaison - */

/* La scene occupe la MEME rangee de grille que le fil et le recouvre : le
   champ de saisie ne bouge pas d'un pixel quand elle s'ouvre, et la
   conversation reste exactement ou elle etait, juste derriere. */
.asst-thread__log,
.asst-compare { grid-row: 1; grid-column: 1; }

.asst-compare {
  min-height: 0;
  display: grid; grid-template-rows: auto minmax(0, 1fr);
  animation: asst-rise 460ms var(--ease-out) both;
}

.asst-compare__head {
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  padding-bottom: 12px;
  border-bottom: 1px solid rgba(255, 255, 255, .12);
}
.asst-compare__title {
  margin: 0;
  font-family: var(--font-mono);
  font-size: .68rem; letter-spacing: .14em; text-transform: uppercase;
  color: var(--atl-ink-300);
}
.asst-compare__close {
  appearance: none; cursor: pointer;
  display: inline-flex; align-items: center; gap: 8px;
  padding: 7px 12px;
  border: 1px solid rgba(255, 255, 255, .18);
  background: rgba(0, 0, 0, .5);
  color: var(--atl-ink-200);
  font: inherit; font-size: .78rem;
  transition: border-color var(--dur-base) var(--ease-out), color var(--dur-base) var(--ease-out);
}
.asst-compare__close svg { transition: transform var(--dur-base) var(--ease-out); }
.asst-compare__close:hover { border-color: var(--accent); color: #fff; }
.asst-compare__close:hover svg { transform: translateX(-3px); }
.asst-compare__close:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* overflow-x cadenasse : rien dans cette scene ne doit pouvoir pousser la page
   de cote, la regle « ca ne defile pas » vaut aussi sur l'axe horizontal. */
.asst-compare__body {
  min-height: 0; overflow-y: auto; overflow-x: hidden;
  padding: 18px 4px 8px 0;
  scrollbar-width: thin;
  scrollbar-color: var(--atl-ink-700) transparent;
}

/* Une seule grille pour les deux appareils : c'est l'alignement des lignes qui
   FAIT la comparaison. Deux cartes posees cote a cote, chacune avec ses
   propres hauteurs de ligne, ne se comparent pas, elles se ressemblent. */
.asst-cmp {
  display: grid;
  grid-template-columns: minmax(74px, 112px) minmax(0, 1fr) minmax(0, 1fr);
  gap: 0 clamp(12px, 2vw, 26px);
  align-items: stretch;
  max-width: 940px;
}

/* La tete de colonne est un lien : toute la colonne mene a la fiche complete,
   ce qui evite une rangee de boutons en bas. Cette rangee coutait soixante
   pixels, et soixante pixels ici, ce sont deux mesures de moins visibles sans
   defiler, alors que voir les mesures en regard est TOUT l'interet de l'ecran. */
.asst-cmp__head {
  display: grid; gap: 5px; padding-bottom: 13px;
  text-decoration: none; color: inherit;
}
.asst-cmp__head > * { animation: asst-rise 500ms var(--ease-out) both; animation-delay: var(--d, 0ms); }
.asst-cmp__head:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.asst-cmp__media {
  position: relative;
  height: clamp(94px, 15vh, 146px);
  background: var(--atl-ink-900);
  border: 1px solid var(--atl-ink-800);
  overflow: hidden;
  transition: border-color var(--dur-base) var(--ease-out);
}
.asst-cmp__head:hover .asst-cmp__media { border-color: var(--accent); }
.asst-cmp__media img {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: contain; display: block;
  padding: 10px;
}
.asst-cmp__code {
  font-family: var(--font-mono);
  font-size: .68rem; letter-spacing: .1em; color: var(--accent);
  margin-top: 4px;
}
.asst-cmp__name { font-size: .95rem; font-weight: 600; line-height: 1.3; color: #fff; }
.asst-cmp__line { font-size: .76rem; color: var(--atl-ink-400); }

/* Chaque mesure occupe une ligne complete de la grille : l'intitule a gauche,
   les deux valeurs en regard. */
.asst-cmp__label,
.asst-cmp__value {
  padding: 7px 0;
  border-top: 1px solid rgba(255, 255, 255, .08);
  font-size: .82rem;
  line-height: 1.4;
}
.asst-cmp__label {
  font-family: var(--font-mono);
  font-size: .6rem; letter-spacing: .1em; text-transform: uppercase;
  color: var(--atl-ink-500);
  padding-right: 8px;
}
.asst-cmp__value { color: var(--atl-ink-100); }
.asst-cmp__value--vide { color: var(--atl-ink-600); }

/* Le rappel du lien, dans la tete de colonne : sans lui, rien ne dit que la
   colonne entiere est cliquable. */
.asst-cmp__cta {
  display: inline-flex; align-items: center; gap: 7px;
  margin-top: 2px;
  font-size: .74rem; color: var(--atl-ink-400);
  transition: color var(--dur-base) var(--ease-out);
}
.asst-cmp__cta svg { transition: transform var(--dur-base) var(--ease-out); }
.asst-cmp__head:hover .asst-cmp__cta { color: var(--accent); }
.asst-cmp__head:hover .asst-cmp__cta svg { transform: translateX(3px); }

/* Pendant la comparaison, le rail se retire : les deux appareils sont deja
   sur la scene, la colonne de droite ne ferait que les repeter en plus petit. */
.asst-shell.is-comparing,
.asst-shell.is-comparing.has-fiche,
.asst-shell.is-comparing.has-fiche.rail-open {
  grid-template-columns: minmax(0, 1fr);
  gap: 0;
}
.asst-shell.is-comparing .asst-rail { display: none; }
.asst-shell.is-comparing .asst-thread { max-width: none; }

/* ------------------------------------------------------------ le fil range - */

/* La conversation reduite a une ligne, juste au-dessus du champ de saisie.
   C'est la poignee qui la ramene : elle montre le debut de la derniere
   reponse, donc on sait ce qu'on va retrouver avant de cliquer. */
.asst-dock {
  appearance: none; cursor: pointer;
  width: 100%;
  display: flex; align-items: center; gap: 10px;
  margin-bottom: 10px;
  padding: 10px 14px;
  border: 1px solid rgba(255, 255, 255, .14);
  background: rgba(0, 0, 0, .55);
  color: var(--atl-ink-300);
  font: inherit; font-size: .8rem;
  text-align: left;
  animation: asst-rise 460ms var(--ease-out) both;
  animation-delay: 120ms;
  transition: border-color var(--dur-base) var(--ease-out), color var(--dur-base) var(--ease-out);
}
.asst-dock:hover { border-color: var(--accent); color: #fff; }
.asst-dock:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.asst-dock__mark {
  width: 14px; height: 14px; flex: 0 0 auto;
  background: var(--accent);
  clip-path: polygon(50% 0%, 100% 27%, 100% 73%, 50% 100%, 0% 73%, 0% 27%);
}
.asst-dock__text {
  flex: 1 1 auto; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-style: italic;
}
.asst-dock__cue {
  flex: 0 0 auto;
  font-family: var(--font-mono);
  font-size: .6rem; letter-spacing: .1em; text-transform: uppercase;
  color: var(--atl-ink-500);
}
.asst-dock:hover .asst-dock__cue { color: var(--accent); }

/* -------------------------------------------------------------- composer - */

.asst-thread__foot { padding-top: 14px; }

.asst-composer {
  display: flex; align-items: flex-end; gap: 10px;
  padding: 8px 8px 8px 16px;
  background: var(--atl-ink-900);
  border: 1px solid var(--atl-ink-600);
  border-radius: 26px;
  box-shadow: 0 18px 40px -26px rgba(0, 0, 0, .95);
  transition: border-color var(--dur-base) var(--ease-out);
}
.asst-composer:focus-within { border-color: var(--accent); }

.asst-composer__field {
  flex: 1 1 auto; min-width: 0;
  background: none; border: 0; resize: none;
  color: var(--atl-ink-50);
  font: inherit; font-size: .95rem; line-height: 1.5;
  padding: 10px 0;
  max-height: 132px; overflow-y: auto;
  scrollbar-width: thin;
}
.asst-composer__field::placeholder { color: var(--atl-ink-400); }
.asst-composer__field:focus { outline: none; }

.asst-composer__send {
  flex: 0 0 auto;
  width: 40px; height: 40px; border-radius: 50%;
  border: 0; background: var(--accent); color: #fff;
  display: grid; place-items: center; cursor: pointer;
  transition: background var(--dur-base) var(--ease-out), transform var(--dur-quick) var(--ease-out), opacity var(--dur-base) var(--ease-out);
}
.asst-composer__send:hover:not(:disabled) { background: var(--atl-red-deep); }
.asst-composer__send:active:not(:disabled) { transform: scale(.94); }
.asst-composer__send:disabled { opacity: .34; cursor: default; }
.asst-composer__send:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }

.asst-note {
  margin: 10px 2px 0;
  font-size: .72rem; line-height: 1.5;
  color: var(--atl-ink-500);
  max-width: 78ch;
}

.asst-escape {
  appearance: none; cursor: pointer;
  display: inline-flex; align-items: center; gap: 8px;
  margin: 8px 2px 0;
  padding: 0;
  border: 0; background: none;
  font: inherit; font-size: .72rem;
  color: var(--atl-ink-400);
  text-decoration: underline;
  text-underline-offset: 3px;
}
.asst-escape[hidden] { display: none; }
.asst-escape:hover { color: var(--accent); }
.asst-escape:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

.asst-ask {
  margin-top: 16px;
  display: grid; gap: 10px;
  max-width: 52ch;
}
.asst-ask__q {
  margin: 0;
  font-size: .88rem; color: #fff; font-weight: 600;
}

.asst-relais {
  margin-top: 18px;
  border: 1px solid rgba(255, 255, 255, .16);
  border-left: 2px solid var(--accent);
  background: rgba(0, 0, 0, .58);
  padding: 14px 16px 16px;
  max-width: 460px;
  animation: asst-rise 520ms var(--ease-out) both;
}
.asst-relais__title {
  margin: 0 0 8px;
  font-family: var(--font-mono);
  font-size: .62rem; letter-spacing: .12em; text-transform: uppercase;
  color: var(--accent);
}
.asst-relais__texte {
  margin: 0 0 14px;
  font-size: .86rem; line-height: 1.5; color: var(--atl-ink-150);
}
.asst-relais__go {
  display: inline-flex; align-items: center; justify-content: space-between; gap: 10px;
  width: 100%;
  padding: 12px 15px;
  border: 1px solid var(--accent);
  background: var(--accent);
  color: #fff; font-size: .84rem; font-weight: 600; text-decoration: none;
  transition: background var(--dur-base) var(--ease-out);
}
.asst-relais__go svg { transition: transform var(--dur-base) var(--ease-out); }
.asst-relais__go:hover { background: var(--atl-red-deep); border-color: var(--atl-red-deep); }
.asst-relais__go:hover svg { transform: translateX(3px); }
.asst-relais__go:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }

/* Pastilles de besoin, au-dessus du champ : elles disent CE QUE l'assistant
   a retenu (jambes, condo, espace compact) sans renvoyer une nouvelle
   question. Cachees tant qu'aucun tour n'a classe le besoin. */
.asst-context {
  display: flex; flex-wrap: wrap; gap: 6px;
  margin: 0 2px 10px;
}
.asst-context[hidden] { display: none; }
.asst-tag {
  font-family: var(--font-mono);
  font-size: .58rem; letter-spacing: .12em; text-transform: uppercase;
  padding: 5px 9px;
  border: 1px solid rgba(255, 255, 255, .16);
  background: rgba(0, 0, 0, .45);
  color: var(--atl-ink-300);
}

.asst-app[data-asst-scene="projet"] .asst-composer,
.asst-app[data-asst-scene="selection"] .asst-composer { border-color: rgba(196, 30, 58, .45); }
.asst-app[data-asst-scene="service"] .asst-composer { border-color: var(--atl-ink-500); }

/* Mosaique dans le fil. Le rail reste la fiche approfondie ; ceci est la
   reponse visuelle a « qu'avez-vous pour X », lisible aussi sous 900px. */
.asst-mosaic {
  margin: 16px 0 8px;
  display: grid; gap: 10px;
  max-width: 68ch;
}
.asst-mosaic__label {
  margin: 0;
  font-family: var(--font-mono);
  font-size: .6rem; letter-spacing: .12em; text-transform: uppercase;
  color: var(--atl-ink-500);
}
.asst-mosaic__row {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(128px, 1fr));
  gap: 8px;
}
.asst-mosaic__card {
  appearance: none; cursor: pointer;
  display: grid; gap: 5px;
  width: 100%;
  padding: 8px;
  border: 1px solid rgba(255, 255, 255, .12);
  background: rgba(0, 0, 0, .55);
  text-align: left; font: inherit; color: inherit;
  animation: asst-rise 460ms var(--ease-out) both;
  animation-delay: var(--d, 0ms);
  transition: border-color var(--dur-base) var(--ease-out), background var(--dur-base) var(--ease-out);
}
.asst-mosaic__card:hover { border-color: var(--accent); background: rgba(20, 20, 22, .88); }
.asst-mosaic__card:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.asst-mosaic__open {
  font-size: .62rem; color: var(--atl-ink-400);
  text-decoration: underline; text-underline-offset: 2px;
}
.asst-mosaic__open:hover { color: var(--accent); }

/* ------------------------------------------------------------------ stage - */

.asst-stage {
  min-width: 0; min-height: 0;
  display: grid;
  grid-template-rows: auto minmax(0, 1fr);
  border: 1px solid rgba(255, 255, 255, .12);
  background: rgba(0, 0, 0, .42);
  padding: 12px 12px 14px;
  animation: asst-rise 560ms var(--ease-out) both;
}
.asst-stage[hidden] { display: none; }

.asst-stage__head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 10px; margin-bottom: 10px;
}
.asst-stage__title {
  margin: 0;
  font-family: var(--font-mono);
  font-size: .62rem; letter-spacing: .14em; text-transform: uppercase;
  color: var(--accent);
}
.asst-stage__meta {
  margin: 0;
  font-family: var(--font-mono);
  font-size: .58rem; letter-spacing: .08em; text-transform: uppercase;
  color: var(--atl-ink-500);
  text-align: right;
}

.asst-floor {
  min-height: 0;
  position: relative;
  display: grid; place-items: stretch;
}

.asst-floor__room {
  --rw: 1100; --rh: 720;
  position: relative;
  width: auto; height: auto;
  max-width: 100%; max-height: 100%;
  aspect-ratio: var(--rw) / var(--rh);
  margin: auto;
  background:
    repeating-linear-gradient(
      0deg,
      rgba(255, 255, 255, .035) 0,
      rgba(255, 255, 255, .035) 1px,
      transparent 1px,
      transparent calc(100% * 50 / var(--rh))
    ),
    repeating-linear-gradient(
      90deg,
      rgba(255, 255, 255, .035) 0,
      rgba(255, 255, 255, .035) 1px,
      transparent 1px,
      transparent calc(100% * 50 / var(--rw))
    ),
    rgba(8, 8, 10, .78);
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, .14),
    0 18px 40px -24px rgba(0, 0, 0, .85);
  overflow: hidden;
}
.asst-floor__room::before {
  content: "";
  position: absolute; inset: 5px;
  border: 1px solid rgba(196, 30, 58, .55);
  pointer-events: none;
  clip-path: inset(0 100% 0 0);
  animation: asst-wall 900ms var(--ease-out) forwards;
}
.asst-floor.is-skel .asst-floor__room::before { animation-duration: 1400ms; }
.asst-floor.is-tight .asst-floor__room::before { border-color: rgba(196, 30, 58, .85); }

.asst-floor__ghost {
  position: absolute;
  border: 1px dashed rgba(255, 255, 255, .16);
  background: rgba(255, 255, 255, .02);
  pointer-events: none;
  opacity: 0;
  animation: asst-ghost 1.8s ease-in-out infinite;
  animation-delay: var(--d, 0ms);
}
.asst-floor__north {
  position: absolute; top: 8px; left: 50%;
  transform: translateX(-50%);
  z-index: 2;
  font-family: var(--font-mono);
  font-size: .58rem; letter-spacing: .16em;
  color: var(--accent);
  pointer-events: none;
}
.asst-floor__door {
  position: absolute; bottom: 0; left: 44%;
  width: 12%; height: 9px;
  background: var(--atl-ink-1000);
  border: 1px solid var(--accent);
  border-bottom: 0;
  pointer-events: none;
  z-index: 2;
}
.asst-floor__scale {
  position: absolute; right: 8px; bottom: 8px;
  z-index: 2;
  font-family: var(--font-mono);
  font-size: .5rem; letter-spacing: .1em; text-transform: uppercase;
  color: var(--atl-ink-500);
  background: rgba(0, 0, 0, .55);
  padding: 2px 6px;
  pointer-events: none;
}

.asst-floor__bay {
  appearance: none; cursor: pointer;
  position: absolute;
  margin: 0; padding: 4px;
  border: 1px solid rgba(255, 255, 255, .22);
  background: rgba(12, 12, 14, .88);
  color: inherit; font: inherit;
  display: grid;
  grid-template-rows: auto 1fr auto;
  align-content: space-between;
  overflow: hidden;
  animation: asst-bay 620ms var(--ease-out) both;
  animation-delay: var(--d, 0ms);
  transition: border-color var(--dur-base) var(--ease-out), background var(--dur-base) var(--ease-out), transform 420ms var(--ease-out), box-shadow 420ms var(--ease-out);
}
.asst-floor__bay:hover,
.asst-floor__bay.is-on {
  border-color: var(--accent);
  background: rgba(20, 12, 14, .95);
  box-shadow: 0 0 0 1px var(--accent), 0 10px 24px -16px rgba(196, 30, 58, .8);
  z-index: 2;
}
.asst-floor__bay:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.asst-floor__bay img {
  position: absolute; inset: 18px 6px 22px;
  width: auto; height: auto; max-width: calc(100% - 12px); max-height: calc(100% - 40px);
  object-fit: contain; margin: auto; display: block;
  pointer-events: none;
}
.asst-floor__foot {
  position: relative; z-index: 1;
  font-family: var(--font-mono);
  font-size: .48rem; letter-spacing: .06em;
  color: var(--atl-ink-400);
  justify-self: start;
}
.asst-floor__stamp {
  position: relative; z-index: 1;
  font-family: var(--font-mono);
  font-size: .52rem; letter-spacing: .1em;
  color: var(--accent);
  background: rgba(0, 0, 0, .55);
  padding: 2px 5px;
  justify-self: start;
}

@keyframes asst-wall {
  to { clip-path: inset(0 0 0 0); }
}
@keyframes asst-bay {
  from { opacity: 0; transform: translateY(10px) scale(.96); }
  to   { opacity: 1; transform: none; }
}
@keyframes asst-ghost {
  0%, 100% { opacity: .22; }
  50%      { opacity: .55; }
}
.asst-mosaic__media {
  position: relative;
  aspect-ratio: 4 / 3;
  background: var(--atl-ink-900);
  overflow: hidden;
}
.asst-mosaic__media img {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: contain; display: block;
  padding: 8px;
}
.asst-mosaic__code {
  font-family: var(--font-mono);
  font-size: .58rem; letter-spacing: .1em; color: var(--accent);
}
.asst-mosaic__name {
  font-size: .76rem; line-height: 1.3; color: var(--atl-ink-100);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}

/* ------------------------------------------------------------------ rail - */

.asst-rail {
  position: relative;
  min-width: 0; min-height: 0;
  overflow: hidden;
}

/* Le panneau garde sa largeur pendant que la colonne se reduit : sans cela le
   texte se recomposerait pendant toute la transition, ce qui se voit. */
/* Le rail se detache maintenant d'une photo, plus d'un aplat noir : il lui
   faut sa propre surface, sinon les intervalles entre les cartes laissent
   passer la salle et la colonne perd sa tenue. */
.asst-rail__panel {
  width: var(--asst-rail-w, 340px);
  height: 100%;
  display: grid; grid-template-rows: auto minmax(0, 1fr) auto;
  border-left: 1px solid rgba(255, 255, 255, .09);
  background: linear-gradient(to bottom, rgba(0, 0, 0, .58), rgba(0, 0, 0, .86));
  padding-left: clamp(16px, 1.8vw, 26px);
  opacity: 0;
  transform: translateX(20px);
  transition: opacity 420ms var(--ease-out), transform 520ms var(--ease-out);
}
.asst-shell.rail-open .asst-rail__panel { opacity: 1; transform: none; }
.asst-shell:not(.rail-open) .asst-rail__panel { pointer-events: none; }

/* La languette : ce qui reste du rail une fois range. Une vignette du produit
   et son intitule a la verticale, cale au milieu de la hauteur : un onglet,
   pas un mur. */
.asst-rail__tuck {
  position: absolute; z-index: 2;
  right: 0; top: 50%; transform: translateY(-50%);
  width: 44px; height: min(250px, 68%);
  appearance: none; cursor: pointer;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 14px;
  padding: 14px 0;
  border: 1px solid var(--atl-ink-800); border-right: 0;
  background: var(--atl-ink-900);
  color: var(--atl-ink-300);
  font: inherit;
  opacity: 0; pointer-events: none;
  transition: opacity 300ms var(--ease-out), color var(--dur-base) var(--ease-out), border-color var(--dur-base) var(--ease-out);
}
.asst-shell.has-fiche:not(.rail-open) .asst-rail__tuck { opacity: 1; pointer-events: auto; transition-delay: 220ms; }
.asst-rail__tuck:hover { color: #fff; border-color: var(--accent); }
.asst-rail__tuck:focus-visible { outline: 2px solid var(--accent); outline-offset: -3px; }
.asst-rail__tuckthumb {
  width: 28px; height: 28px; flex: 0 0 auto;
  background: var(--atl-ink-800);
  display: none; place-items: center; overflow: hidden;
}
.asst-rail__tuckthumb.is-on { display: grid; }
.asst-rail__tuckthumb img { width: 100%; height: 100%; object-fit: contain; display: block; }
.asst-rail__tucklabel {
  writing-mode: vertical-rl;
  font-family: var(--font-mono);
  font-size: .62rem; letter-spacing: .16em; text-transform: uppercase;
}

.asst-rail__head {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--atl-ink-800);
}
.asst-rail__title {
  margin: 0;
  font-family: var(--font-mono);
  font-size: .66rem; letter-spacing: .12em; text-transform: uppercase;
  color: var(--atl-ink-400);
}
.asst-rail__close {
  appearance: none; border: 0; background: none; cursor: pointer;
  color: var(--atl-ink-400); padding: 4px; line-height: 0;
  transition: color var(--dur-base) var(--ease-out);
}
.asst-rail__close:hover { color: #fff; }
.asst-rail__close:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.asst-rail__body {
  min-height: 0; overflow-y: auto;
  padding: 16px 4px 8px 0;
  display: grid; gap: 22px; align-content: start;
  scrollbar-width: thin;
  scrollbar-color: var(--atl-ink-700) transparent;
}
.asst-rail__body::-webkit-scrollbar { width: 6px; }
.asst-rail__body::-webkit-scrollbar-thumb { background: var(--atl-ink-700); }

.asst-dossier {
  border-top: 1px solid rgba(255, 255, 255, .12);
  padding: 12px 8px 16px 0;
  display: grid; gap: 10px;
  background:
    linear-gradient(to right, var(--accent) 0, var(--accent) 2px, transparent 2px),
    linear-gradient(to top, rgba(0, 0, 0, .45), transparent 18px);
  padding-left: 12px;
}
.asst-dossier[hidden] { display: none; }
.asst-dossier__title {
  margin: 0;
  font-family: var(--font-mono);
  font-size: .6rem; letter-spacing: .14em; text-transform: uppercase;
  color: var(--accent);
}
.asst-dossier__meta {
  margin: 0;
  font-family: var(--font-mono);
  font-size: .52rem; letter-spacing: .08em; text-transform: uppercase;
  color: var(--atl-ink-500);
}
.asst-dossier.is-ready .asst-dossier__meta { color: var(--accent); }
.asst-dossier__lines {
  margin: 0; padding: 0;
  list-style: none;
  display: grid; gap: 7px;
}
.asst-dossier__line {
  display: grid;
  grid-template-columns: 88px minmax(0, 1fr);
  gap: 8px;
  align-items: baseline;
  animation: asst-type 480ms var(--ease-out) both;
  animation-delay: var(--d, 0ms);
}
.asst-dossier__k {
  font-family: var(--font-mono);
  font-size: .56rem; letter-spacing: .1em; text-transform: uppercase;
  color: var(--atl-ink-500);
}
.asst-dossier__v {
  font-size: .78rem; line-height: 1.35; color: var(--atl-ink-100);
}
.asst-dossier__line.is-ouvert .asst-dossier__v { color: var(--atl-ink-300); font-style: italic; }
.asst-dossier__line.is-ouvert .asst-dossier__v::after {
  content: "";
  display: inline-block;
  width: 6px; height: 11px;
  margin-left: 5px;
  background: var(--accent);
  vertical-align: -1px;
  animation: asst-caret 1s steps(1) infinite;
}
.asst-dossier__line.is-action .asst-dossier__v { color: var(--accent); }
.asst-dossier__go {
  appearance: none; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: space-between;
  gap: 10px; width: 100%;
  padding: 11px 13px;
  border: 1px solid var(--accent);
  background: var(--accent);
  color: #fff; font: inherit; font-size: .8rem; font-weight: 600;
  text-align: left;
  transition: background var(--dur-base) var(--ease-out);
}
.asst-dossier__go[hidden] { display: none; }
.asst-dossier__go:hover { background: var(--atl-red-deep); }
.asst-dossier__go:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
.asst-dossier__go svg { transition: transform var(--dur-base) var(--ease-out); }
.asst-dossier__go:hover svg { transform: translateX(3px); }

.asst-rail__group { display: grid; gap: 10px; }
.asst-rail__grouptitle {
  margin: 0;
  font-family: var(--font-mono);
  font-size: .62rem; letter-spacing: .12em; text-transform: uppercase;
  color: var(--atl-ink-500);
}

/* --- la fiche, la carte pleine --- */
.asst-fiche {
  display: grid; gap: 0;
  border: 1px solid var(--atl-ink-800);
  background: var(--atl-ink-900);
  text-decoration: none; color: inherit;
}
.asst-fiche > * { animation: asst-rise 520ms var(--ease-out) both; animation-delay: var(--d, 0ms); }

/* La photo est posee en ABSOLU dans un cadre a ratio fixe, et ce n'est pas un
   detail de style. En flux, « height:100% » sur l'image ne resolvait pas : la
   hauteur du cadre vient de son aspect-ratio, donc la hauteur de reference est
   indefinie pour un enfant en pourcentage, et l'image retombait sur son propre
   ratio. Elle mesurait 283 px de haut dans un cadre de 197, « object-fit:
   contain » n'avait plus rien a contenir, et c'est overflow:hidden qui
   tranchait la machine en haut et en bas. En absolu avec inset:0, le cadre a
   une hauteur definie et contain fait enfin son travail. */
.asst-fiche__media {
  position: relative;
  aspect-ratio: 4 / 3;
  background: var(--atl-ink-800);
  overflow: hidden;
  border-bottom: 1px solid var(--atl-ink-800);
}
.asst-fiche__media img {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: contain; display: block;
  padding: 12px;
  transition: transform 700ms var(--ease-out);
  animation: asst-photo-in 700ms var(--ease-out) both;
  animation-delay: 280ms;
}
.asst-fiche:hover .asst-fiche__media img { transform: scale(1.04); }

.asst-fiche__chassis {
  position: absolute; inset: 0; pointer-events: none; z-index: 1;
}
.asst-fiche__chassis svg {
  width: 100%; height: 100%; display: block;
}
.asst-fiche__draw {
  fill: none;
  stroke: var(--accent);
  stroke-width: 1.15;
  stroke-linejoin: miter;
  stroke-dasharray: 1200;
  stroke-dashoffset: 1200;
  animation: asst-draw 1280ms var(--ease-out) forwards;
}

.asst-fiche__dim {
  position: absolute; z-index: 2; right: 8px; bottom: 8px;
  font-family: var(--font-mono);
  font-size: .55rem; letter-spacing: .08em;
  color: var(--accent);
  background: rgba(0, 0, 0, .7);
  padding: 3px 6px;
  animation: asst-plate 640ms var(--ease-out) both;
  animation-delay: 720ms;
}

.asst-fiche__charge {
  display: flex; align-items: flex-end; gap: 3px;
  height: 16px;
  margin: 8px 15px 0;
}
.asst-fiche__charge i {
  display: block; width: 7px;
  background: var(--atl-ink-600);
  animation: asst-rise 420ms var(--ease-out) both;
}
.asst-fiche__charge--stack i:nth-child(1) { height: 6px; animation-delay: 480ms; }
.asst-fiche__charge--stack i:nth-child(2) { height: 10px; animation-delay: 540ms; }
.asst-fiche__charge--stack i:nth-child(3) { height: 14px; animation-delay: 600ms; background: var(--accent); }
.asst-fiche__charge--plates i {
  width: 10px; height: 10px; border-radius: 50%;
  border: 1px solid var(--atl-ink-500);
  background: transparent;
}
.asst-fiche__charge--plates i:nth-child(3) { border-color: var(--accent); }

.asst-fiche.is-service .asst-fiche__code {
  display: inline-block;
  padding: 3px 7px;
  border: 1px solid rgba(196, 30, 58, .55);
  background: rgba(196, 30, 58, .12);
  animation: asst-plate 700ms var(--ease-out) both;
  animation-delay: 360ms;
}

.asst-fiche__head { padding: 14px 15px 0; display: grid; gap: 5px; }
.asst-fiche__code {
  font-family: var(--font-mono);
  font-size: .68rem; letter-spacing: .1em; color: var(--accent);
}
.asst-fiche__name {
  margin: 0;
  font-size: 1rem; font-weight: 600; line-height: 1.28; color: #fff;
}
.asst-fiche__line { font-size: .78rem; color: var(--atl-ink-300); }

.asst-fiche__specs {
  margin: 12px 15px 0; padding-top: 12px;
  border-top: 1px solid var(--atl-ink-800);
  display: grid; gap: 7px;
}
.asst-spec { display: grid; grid-template-columns: 78px 1fr; gap: 10px; align-items: baseline; }
.asst-spec__k {
  font-family: var(--font-mono);
  font-size: .6rem; letter-spacing: .1em; text-transform: uppercase;
  color: var(--atl-ink-500);
}
.asst-spec__v { font-size: .78rem; color: var(--atl-ink-150); line-height: 1.45; }

.asst-fiche__points {
  margin: 12px 15px 0; padding: 0 0 0 1.05em;
  display: grid; gap: .4em; list-style: disc;
}
.asst-fiche__points li { font-size: .78rem; line-height: 1.5; color: var(--atl-ink-300); }
.asst-fiche__points li::marker { color: var(--accent); }

/* Le bouton reste colle au bas du rail tant que la fiche defile : c'est
   l'action de la carte, elle ne doit jamais tomber sous la ligne de flottaison
   quand plusieurs produits ont ete cites. */
.asst-fiche__cta {
  position: sticky; bottom: 0; z-index: 1;
  background: var(--atl-ink-900);
  margin: 14px 15px 15px;
  display: inline-flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 10px 13px;
  border: 1px solid var(--atl-ink-700);
  font-size: .8rem; color: #fff;
  transition: border-color var(--dur-base) var(--ease-out), background var(--dur-base) var(--ease-out);
}
/* Un degrade au-dessus du bouton colle : sans lui, la puce qu'il recouvre est
   tranchee net et se lit comme un defaut plutot que comme "il y en a encore". */
.asst-fiche__cta::before {
  content: "";
  position: absolute; left: -15px; right: -15px; bottom: 100%;
  height: 24px; pointer-events: none;
  background: linear-gradient(to top, var(--atl-ink-900), rgba(11, 11, 12, 0));
}
.asst-fiche:hover .asst-fiche__cta { border-color: var(--accent); background: var(--accent); }
.asst-fiche__cta svg { transition: transform var(--dur-base) var(--ease-out); }
.asst-fiche:hover .asst-fiche__cta svg { transform: translateX(3px); }
.asst-fiche:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* --- les cartes compactes, pour ce qui a ete cite en plus ou plus tot --- */
.asst-card {
  display: grid; grid-template-columns: 54px 1fr; gap: 12px; align-items: center;
  padding: 9px; border: 1px solid var(--atl-ink-800);
  background: var(--atl-ink-900); color: inherit; text-decoration: none;
  transition: border-color var(--dur-base) var(--ease-out), background var(--dur-base) var(--ease-out);
  animation: asst-rise 460ms var(--ease-out) both; animation-delay: var(--d, 0ms);
}
.asst-card:hover { border-color: var(--accent); background: var(--atl-ink-800); }
.asst-card:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.asst-card__media {
  width: 54px; height: 54px; background: var(--atl-ink-800); overflow: hidden;
  display: grid; place-items: center;
}
.asst-card__media img { width: 100%; height: 100%; object-fit: contain; display: block; }
.asst-card__body { display: grid; gap: 3px; min-width: 0; }
.asst-card__name { font-size: .82rem; font-weight: 600; line-height: 1.3; color: var(--atl-ink-100); }
.asst-card__meta {
  font-family: var(--font-mono);
  font-size: .62rem; color: var(--atl-ink-500); letter-spacing: .05em;
}

/* --- l'ossature qui se pose avant la vraie fiche --- */
.asst-skel { display: grid; gap: 0; border: 1px solid var(--atl-ink-800); background: var(--atl-ink-900); }
.asst-skel.is-out { animation: asst-collapse 340ms var(--ease-out) forwards; }
/* Meme ratio que .asst-fiche__media : l'ossature annonce la forme exacte de
   ce qui va la remplacer, sinon la carte saute de hauteur a l'arrivee. */
.asst-skel__media { position: relative; aspect-ratio: 4 / 3; border-bottom: 1px solid var(--atl-ink-800); }
.asst-skel__lines { padding: 15px; display: grid; gap: 10px; }
.asst-bone {
  height: 11px;
  background: linear-gradient(90deg, var(--atl-ink-800) 0%, var(--atl-ink-700) 40%, var(--atl-ink-800) 80%);
  background-size: 280% 100%;
  animation: asst-shimmer 1.6s linear infinite;
}
.asst-skel__media.asst-bone { height: auto; }
.asst-bone--sm { height: 8px; width: 42%; }
.asst-bone--md { width: 78%; }
.asst-bone--lg { height: 15px; width: 92%; }

/* --------------------------------------------------------- arrivee ------- */

/* L'entree de la page. Le decor est deja la quand le titre se pose, et le
   champ de saisie arrive en dernier : l'oeil suit l'ordre de lecture au lieu
   de recevoir toute l'interface d'un bloc. Rien ne bouge ensuite. */
.asst-hero__eyebrow { animation: asst-rise 620ms var(--ease-out) both; animation-delay: 80ms; }
.asst-hero__title   { animation: asst-rise 700ms var(--ease-out) both; animation-delay: 150ms; }
.asst-hero__lede    { animation: asst-rise 700ms var(--ease-out) both; animation-delay: 240ms; }
.asst-intro__mark   { animation: asst-rise 620ms var(--ease-out) both; animation-delay: 320ms; }
.asst-intro__line   { animation: asst-rise 620ms var(--ease-out) both; animation-delay: 380ms; }
.asst-intro__hint   { animation: asst-rise 620ms var(--ease-out) both; animation-delay: 440ms; }
.asst-intro .asst-chip { animation: asst-rise 560ms var(--ease-out) both; }
.asst-intro .asst-chip:nth-child(1) { animation-delay: 500ms; }
.asst-intro .asst-chip:nth-child(2) { animation-delay: 560ms; }
.asst-intro .asst-chip:nth-child(3) { animation-delay: 620ms; }
.asst-intro .asst-chip:nth-child(4) { animation-delay: 680ms; }
.asst-thread__foot  { animation: asst-rise 700ms var(--ease-out) both; animation-delay: 420ms; }

/* Une fois la conversation lancee, ces retards n'ont plus de raison d'etre :
   le champ de saisie ne doit pas rejouer son entree a chaque redimensionnement
   ou changement de langue. */
.asst-app.is-engaged .asst-thread__foot { animation: none; }

/* ------------------------------------------------------------ mouvement -- */

@keyframes asst-rise {
  from { opacity: 0; transform: translateY(9px); }
  to   { opacity: 1; transform: none; }
}
@keyframes asst-fade-out {
  from { opacity: 1; transform: none; }
  to   { opacity: 0; transform: translateY(-8px); }
}
@keyframes asst-collapse {
  from { opacity: 1; transform: none; }
  to   { opacity: 0; transform: scale(.97); }
}
@keyframes asst-shimmer {
  from { background-position: 140% 0; }
  to   { background-position: -140% 0; }
}
@keyframes asst-pulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: .38; }
}
@keyframes asst-bounce {
  0%, 60%, 100% { transform: translateY(0); opacity: .5; }
  30%           { transform: translateY(-4px); opacity: 1; }
}
@keyframes asst-draw {
  to { stroke-dashoffset: 0; }
}
@keyframes asst-photo-in {
  from { opacity: 0; transform: scale(.97); }
  to   { opacity: 1; transform: none; }
}
@keyframes asst-plate {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}
@keyframes asst-type {
  from { opacity: 0; transform: translateX(-6px); }
  to   { opacity: 1; transform: none; }
}
@keyframes asst-caret {
  50% { opacity: 0; }
}

/* ------------------------------------------------------------ responsive - */

/* Ecran bas : l'accroche saute et le titre maigrit, la conversation prime.
   Le decor, lui, ne bouge pas : il n'occupe plus de hauteur a lui. */
@media (max-height: 720px) {
  .asst-hero { padding-block: clamp(12px, 2.5vh, 22px) 4px; }
  .asst-hero__lede { display: none; }
  .asst-hero__title { font-size: clamp(1.2rem, 2.4vw, 1.7rem); max-width: 40ch; }
}

@media (max-width: 1180px) {
  .asst-shell.has-stage,
  .asst-shell.has-stage.has-fiche,
  .asst-shell.has-stage.has-fiche.rail-open {
    grid-template-columns: minmax(0, 1fr) var(--asst-rail-w, 0px);
    grid-template-rows: minmax(0, 1fr) minmax(168px, 32vh);
  }
  .asst-shell.has-stage.has-fiche:not(.rail-open) {
    grid-template-columns: minmax(0, 1fr) 44px;
  }
  .asst-thread { grid-row: 1; grid-column: 1; }
  .asst-stage { grid-row: 2; grid-column: 1; }
  .asst-rail { grid-row: 1 / -1; grid-column: 2; }
}

/* Sous 900px le rail ne tient plus a cote : le panneau devient une feuille qui
   monte par-dessus la conversation, et la languette une pastille flottante. */
@media (max-width: 900px) {
  .asst-shell,
  .asst-shell.has-fiche,
  .asst-shell.has-fiche.rail-open,
  .asst-shell.has-stage,
  .asst-shell.has-stage.has-fiche,
  .asst-shell.has-stage.has-fiche.rail-open,
  .asst-shell.has-stage.has-fiche:not(.rail-open) {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: minmax(0, 1fr) auto;
    gap: 0;
  }
  .asst-thread { grid-row: 1; grid-column: 1; }
  .asst-stage { grid-row: 2; grid-column: 1; max-height: 34vh; margin: 0 0 8px; }
  .asst-rail { grid-row: auto; grid-column: auto; position: absolute; inset: auto auto 0 0; width: 0; height: 0; overflow: visible; }

  .asst-rail__panel {
    position: fixed; z-index: 41;
    right: 0; bottom: 0; left: 0;
    width: auto; height: min(78dvh, 640px);
    background: var(--atl-ink-1000);
    border-left: 0; border-top: 1px solid var(--atl-ink-700);
    box-shadow: 0 -24px 60px -30px rgba(0, 0, 0, .95);
    padding: 16px clamp(18px, 5vw, 28px) 0;
    opacity: 1;
    transform: translateY(103%);
    transition: transform 460ms var(--ease-out);
  }
  .asst-shell.rail-open .asst-rail__panel { transform: none; }

  /* La pastille se pose JUSTE au-dessus du champ de saisie : --asst-foot-h est
     la hauteur reelle du pied, mesuree par assistant.js, sinon la pastille
     recouvrirait le bouton d'envoi sur certains ecrans. */
  .asst-rail__tuck {
    position: fixed; z-index: 40;
    right: clamp(14px, 4vw, 24px);
    bottom: calc(var(--asst-foot-h, 118px) + 26px);
    top: auto; left: auto;
    transform: none;
    width: auto; height: auto;
    flex-direction: row; gap: 9px;
    padding: 9px 14px;
    border: 1px solid var(--accent); border-right: 1px solid var(--accent);
    background: var(--atl-ink-900);
    color: #fff;
    box-shadow: 0 14px 30px -18px rgba(0, 0, 0, .9);
  }
  .asst-rail__tuckthumb { width: 22px; height: 22px; }
  .asst-rail__tucklabel { writing-mode: horizontal-tb; letter-spacing: .1em; }

  /* La pastille flotte au-dessus du fil : le fil lui reserve sa bande, sinon
     elle se pose sur la derniere ligne de la reponse ou sur une suggestion. */
  .asst-shell.has-fiche .asst-thread__log { padding-bottom: 58px; }
}

@media (max-width: 720px) {
  .asst-hero { padding-block: 14px 4px; }
  .asst-hero__lede { display: none; }
  .asst-hero__title { font-size: clamp(1.25rem, 6vw, 1.7rem); }
  /* La pastille du decor disparait sous 720px. Il n'y a plus un seul coin
     libre : en haut la conversation defile, en bas vivent le champ de saisie
     et le rappel de la fiche. Et le voile est si franc a cette largeur que la
     photo ne se lit presque plus : nommer l'endroit n'apporte plus rien. */
  .asst-scene__credit,
  .asst-app.is-engaged .asst-scene__credit { display: none; }
  /* Sur un ecran etroit le voile doit etre plus franc : la colonne de texte
     occupe toute la largeur, il n'y a plus de cote ou la photo respire. */
  .asst-scene__veil {
    background: linear-gradient(to top,
      var(--atl-ink-1000) 0%, rgba(0, 0, 0, .99) 26%, rgba(0, 0, 0, .95) 44%,
      rgba(0, 0, 0, .84) 62%, rgba(0, 0, 0, .62) 82%, rgba(0, 0, 0, .42) 100%);
  }
  /* La comparaison reste a DEUX colonnes sous 720px : les empiler la
     supprimerait, c'est la mise en regard qui fait tout l'interet. On retire
     la colonne des intitules et on pose chaque intitule au-dessus de sa
     premiere valeur, sur toute la largeur. */
  .asst-cmp { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 0 12px; }
  .asst-cmp__coin { display: none; }
  .asst-cmp__label {
    grid-column: 1 / -1;
    border-top: 1px solid rgba(255, 255, 255, .08);
    padding: 9px 0 0;
    font-size: .56rem;
  }
  .asst-cmp__value { border-top: 0; padding: 2px 0 9px; font-size: .78rem; }
  .asst-cmp__media { height: clamp(84px, 13vh, 120px); }
  .asst-cmp__name { font-size: .85rem; }
  .asst-compare__close span { display: none; }
  .asst-compare__close { padding: 8px 10px; }
  .asst-dock__cue { display: none; }

  .asst-msg--user { max-width: 88%; }
  .asst-msg--bot { padding-left: 28px; }
  .asst-msg--bot::before, .asst-thinking::before { width: 17px; height: 17px; }
  .asst-thinking { padding-left: 28px; }
  .asst-note { font-size: .68rem; }
  .asst-mosaic__row {
    display: flex;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scroll-snap-type: x mandatory;
    gap: 8px;
    padding-bottom: 6px;
    scrollbar-width: thin;
  }
  .asst-mosaic__card { flex: 0 0 148px; scroll-snap-align: start; }
}

/* --------------------------------------------------------- accessibilite - */

@media (prefers-reduced-motion: reduce) {
  .asst-hero,
  .asst-hero__eyebrow, .asst-hero__lede, .asst-scene__credit,
  .asst-shell, .asst-rail__panel, .asst-rail__tuck,
  .asst-composer, .asst-chip, .asst-card,
  .asst-link, .asst-link svg, .asst-fiche__media img, .asst-fiche__cta,
  .asst-fiche__cta svg, .asst-composer__send { transition: none !important; }

  .asst-hero__layer { transition: opacity 200ms linear; }

  .asst-msg--user, .asst-msg--system, .asst-msg--bot > *,
  .asst-fiche > *, .asst-card, .asst-thinking,
  .asst-projet, .asst-projet__line,
  .asst-hero__eyebrow, .asst-hero__title, .asst-hero__lede,
  .asst-intro__mark, .asst-intro__line, .asst-intro__hint,
  .asst-chip, .asst-thread__foot {
    animation: none !important; opacity: 1 !important; transform: none !important;
  }
  .asst-bone { animation: none !important; background: var(--atl-ink-800); }
  .asst-thinking::before { animation: none !important; }
  .asst-thinking__dots i { animation: none !important; opacity: .7; }
  .asst-intro.is-out { animation: none !important; display: none; }
  .asst-fiche__draw { animation: none !important; stroke-dashoffset: 0; }
  .asst-floor__room::before { animation: none !important; clip-path: none; }
  .asst-floor__bay, .asst-dossier__line, .asst-fiche__media img,
  .asst-fiche__charge i, .asst-fiche__dim { animation: none !important; opacity: 1 !important; transform: none !important; }
  .asst-floor__ghost { animation: none !important; opacity: .3; }
  .asst-dossier__line.is-ouvert .asst-dossier__v::after { animation: none !important; opacity: .7; }
}
