/* ==========================================================================
   IMPRA — CARROSSERIE : LE GRAPHIC SYSTEM APPLIQUÉ AU SITE
   Couche additive, chargée après media.impra.css et scene.impra.css.

   Source : graphic-system/bibliotheque.html (Foundation Pack vectoriel)
   Règles : IMPRA_GRAPHIC_SYSTEM.md · emplacements : IMPRA_HOMEPAGE_GRAPHIC_PLAN.md §I

   Ce fichier ne redéfinit aucun token de marque, aucune grille, aucun
   composant du système source. Il déclare :
     1. le thème d'objet (les variables que consomment les SVG),
     2. les scènes et les micros,
     3. leurs comportements de motion.

   Les noms de variables sont IDENTIQUES à ceux de la bibliothèque : un
   spécimen s'y colle sans réécriture, et une correction faite là-bas se
   reporte ici à l'identique.
   ========================================================================== */

/* ==========================================================================
   1. THÈME D'OBJET — FOND CLAIR
   Portée : .gs uniquement. Rien ne fuit dans la page.
   ========================================================================== */
.gs {
  /* accents et états — repris des tokens de marque, jamais redéfinis */
  --blue:      var(--impra-blue);
  --blue-deep: #0F49A8;
  --blue-lit:  #4D94F5;
  --blue-soft: var(--impra-blue-soft);
  --navy:      var(--impra-navy);
  --ok:        var(--impra-success);
  --warn:      var(--impra-warning);
  --danger:    var(--impra-danger);

  /* rampe de valeurs — la matière du système */
  --n950:#0A0F1E; --n900:#0F172E; --n800:#16223C; --n700:#1E2E4F; --n600:#2A3F66;
  --a500:#4A5A72; --a400:#64748B; --a300:#8C9AB0; --a200:#B3BECE; --a100:#D3DAE4;
  --g75:#E7EDF4;  --g50:#F2F5FA;  --g0:#FFFFFF;

  /* dégradés de panneaux — variante claire */
  --f-flank:url(#gFlankL); --f-belt:url(#gBeltL); --f-roof:url(#gRoofL);
  --f-hood:url(#gHoodL); --f-glasstop:url(#gGlassTopL); --f-glasside:url(#gGlassSideL);
  --f-screen:url(#gScreenL); --f-paperface:url(#gPaperL); --f-folder:url(#gFolderL);
  --f-cover:url(#gCoverL); --f-safe:url(#gSafeL);

  /* véhicule */
  --v-shadow-op:.9; --v-ground:var(--impra-border); --v-ground-op:1;
  --v-rocker:#22304F; --v-under:#0E1730; --v-nose:#9FACC0;
  --v-pillar:#16223C; --v-apillar:#96A4B9;
  --v-well:#0B1223; --v-tire:#111A2E; --v-tirering:#1C2740;
  --v-rim:#B9C3D2; --v-slot:#25334F; --v-hub:#5D6E86; --v-hubc:#22304F; --v-caliper:#1E2E4F;
  --v-detail:#16223C; --v-lamp:#E9F0F9; --v-lampline:#4D94F5;
  --v-shut:#0F172E; --v-shut-op:.20; --v-lame:#FFFFFF; --v-lame-op:.92;
  --v-farrail:#9AA7BB; --v-trace:var(--impra-blue);

  /* objets */
  --o-ink:var(--impra-navy); --o-mut:#5C6A80; --o-paper-side:#C2CCDA;
  --o-folder-side:#16223C; --o-folder-slot:#0A0F1E;
  --o-chip:#FFFFFF; --o-chip-bd:var(--impra-border);
  --o-socle-top:#DBE1EA; --o-socle-front:#B3BECE; --o-socle-side:#8C9AB0;
  --o-track:#D9E0EA; --o-tick:#9AA7BB;
  --o-screenbar:#D3DAE4; --o-devicebody:#1E2E4F; --o-deviceside:#0A0F1E; --o-deviceedge:#2A3F66;
  --o-ghost:#8C9AB0;
}

/* ==========================================================================
   2. THÈME D'OBJET — FOND INK
   Mêmes panneaux, valeurs redistribuées. Aucun objet n'est redessiné.
   ========================================================================== */
.gs--ink {
  --f-flank:url(#gFlankD); --f-belt:url(#gBeltD); --f-roof:url(#gRoofD);
  --f-hood:url(#gHoodD); --f-glasstop:url(#gGlassTopD); --f-glasside:url(#gGlassSideD);
  --f-screen:url(#gScreenD); --f-paperface:url(#gPaperD); --f-folder:url(#gFolderD);
  --f-cover:url(#gCoverD); --f-safe:url(#gSafeD);

  --v-shadow-op:.55; --v-ground:#2A3B60; --v-ground-op:.55;
  --v-rocker:#131E38; --v-under:#0A1123; --v-nose:#6E7E96;
  --v-pillar:#0B1223; --v-apillar:#8C9AB0;
  --v-well:#060B16; --v-tire:#0B1223; --v-tirering:#16223C;
  --v-rim:#98A6BA; --v-slot:#1B2740; --v-hub:#4A5A72; --v-hubc:#131E38; --v-caliper:#16223C;
  --v-detail:#0B1223; --v-lamp:#EAF2FF; --v-lampline:#4D94F5;
  --v-shut:#060B16; --v-shut-op:.45; --v-lame:#FFFFFF; --v-lame-op:1;
  --v-farrail:#5C6C86; --v-trace:#2D82F0;

  --o-ink:#F2F5FA; --o-mut:#8FA0BC; --o-paper-side:#8C9AB0;
  --o-folder-side:#0A0F1E; --o-folder-slot:#05080F;
  --o-chip:#16223C; --o-chip-bd:#2A3B60;
  --o-socle-top:#3A4C6E; --o-socle-front:#243654; --o-socle-side:#182742;
  --o-track:#2A3B60; --o-tick:#5C6C86;
  --o-screenbar:#2E4166; --o-devicebody:#26385C; --o-deviceside:#0A1123; --o-deviceedge:#3A4F78;
  --o-ghost:#5C6C86;
}

/* Le sprite de définitions ne doit jamais occuper de place ni être lu */
.gs-defs { position: absolute; width: 0; height: 0; overflow: hidden; }

/* ==========================================================================
   3. TYPOGRAPHIE DANS LES OBJETS
   Trois rôles seulement : légende, valeur, libellé. Toujours tabulaire.
   ========================================================================== */
.gs text { font-family: var(--impra-font); }
.gs .t-val { font-weight: var(--weight-bold); fill: var(--o-ink); font-variant-numeric: var(--font-numeric); letter-spacing: -.2px; }
.gs .t-cap { font-weight: var(--weight-semibold); fill: var(--o-mut); letter-spacing: .08em; text-transform: uppercase; }
.gs .t-lab { font-weight: var(--weight-semibold); fill: var(--o-ink); }

/* ==========================================================================
   4. PLATEAU D'EXPOSITION
   Toute scène est posée : halo, trame 48, jamais un fond plat.
   ========================================================================== */
.gs-stage {
  position: relative;
  margin: 0;
  border-radius: var(--radius-images);
  overflow: hidden;
  border: var(--border-hairline);
  background: radial-gradient(120% 92% at 50% 22%, #FFFFFF 0%, #EFF4FC 48%, #E4EBF7 100%);
}
.gs-stage::before {
  content: "";
  position: absolute; inset: 0;
  background-image:
    linear-gradient(to right, rgba(31,116,231,.05) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(31,116,231,.05) 1px, transparent 1px);
  background-size: 48px 48px;
  -webkit-mask-image: radial-gradient(92% 74% at 50% 45%, #000 18%, transparent 80%);
          mask-image: radial-gradient(92% 74% at 50% 45%, #000 18%, transparent 80%);
  pointer-events: none;
}
.gs-stage > svg { position: relative; display: block; width: 100%; height: auto; }
.gs-stage--ink {
  background: radial-gradient(95% 88% at 50% 30%, #17233F 0%, #101A33 55%, #0B1226 100%);
  border-color: #101A33;
}

/* ==========================================================================
   5. MICROS L1  (S4 bento · S6 bande Ink)
   Un idéogramme propriétaire par domaine, position constante, jamais animé.
   ========================================================================== */
.gs-micro { display: block; width: 52px; height: 52px; flex: 0 0 52px; }
/* Sur la bande Ink, le micro remplace la tuile d'icône générique du système
   source : même encombrement, même position, vocabulaire propriétaire. */
.gs-tile {
  display: grid; place-items: center;
  width: 56px; height: 56px;
  border-radius: var(--radius-cards);
  background: rgba(255,255,255,.07);
  border: 1px solid rgba(255,255,255,.10);
}
.gs-tile .gs-micro { width: 40px; height: 40px; flex-basis: 40px; }
/* Le tracé lieur des trois instruments de pilotage — 1 px, 25 %, décoratif */
.gs-link-row { position: relative; }
.gs-link-row::before {
  content: "";
  position: absolute; left: 28px; right: calc(33.333% - 28px); top: 28px; height: 1px;
  background: rgba(127,176,255,.25);
  pointer-events: none;
}
@media (max-width: 900px) { .gs-link-row::before { display: none; } }

/* ==========================================================================
   6. HERO — LE PLATEAU DU PRODUIT RÉEL  (N1+)

   ⚑ 23 août 2026 — HORS SERVICE. Le hero reçoit désormais une composition
   produit finie (`assets/hero-composition.webp`), qui porte déjà son propre
   sol, sa profondeur et ses plaquettes. Y superposer la plinthe, le Tracé,
   la plaque et la plaquette du système ferait doublon — le plan §I les avait
   prévus parce que le hero ne contenait que des emplacements vides.
   Les règles sont conservées telles quelles : elles resteront justes le jour
   où un hero de page intérieure aura besoin d'un plateau. À supprimer sur
   décision explicite.
   ========================================================================== */
.hero__visual { isolation: isolate; }
/* Sol : plinthe + tracé + ombre de contact, derrière la carte produit.
   Le ratio de la boîte suit celui du viewBox — sinon « meet » réduirait la
   plinthe à une vignette centrée au lieu d'un plateau. */
.hero-ground {
  position: absolute;
  left: -4%; right: -4%; bottom: -18%;
  height: auto;
  aspect-ratio: 600 / 120;
  z-index: 0;
  pointer-events: none;
}
/* Plaquette KPI adossée à la carte web (C1) — la pilule flottante du système
   source, avec du vocabulaire IMPRA. */
.hero-kpi {
  position: absolute;
  top: 22%; right: -7%;
  width: 148px; height: 56px;
  z-index: 4;
  filter: drop-shadow(0 8px 18px rgba(15,23,46,.14));
}
/* Plaque au pied du téléphone (A9), posée sur la plinthe */
.hero-plate {
  position: absolute;
  left: 30%; bottom: -16%;
  width: 122px; height: 34px;
  z-index: 4;
  filter: drop-shadow(0 6px 14px rgba(15,23,46,.16));
}
@media (max-width: 1100px) { .hero-kpi { right: -3%; width: 132px; height: 50px; } }
/* Mobile : le socle et la plaque suffisent — la plaquette disparaît (§I) */
@media (max-width: 900px) {
  .hero-kpi { display: none; }
  .hero-ground { left: 0; right: 0; bottom: -6%; height: 30%; }
  .hero-plate { position: static; width: 122px; height: 34px; margin: var(--space-16) auto 0; display: block; }
}

/* ==========================================================================
   7. S5 — TERRAIN ↔ BUREAU
   ⚑ 23 août 2026 — PARTIELLEMENT HORS SERVICE. La variante horizontale est
   remplacée par l'illustration 2.5D `impra-l2-02-field-office-sync` (Level 1).
   La variante verticale reste en service sous 768 px, mais sa bascule est
   désormais pilotée par `assets.impra.css` : plus aucun élément ne porte
   `.sync-scene`. Ces règles sont conservées jusqu'à la production de la
   variante verticale 2.5D (MA-03), après quoi elles pourront disparaître.
   ========================================================================== */
.sync-scene .gs-fig--v { display: none; }
@media (max-width: 900px) {
  .sync-scene .gs-fig--h { display: none; }
  .sync-scene .gs-fig--v { display: block; }
}

/* ==========================================================================
   8. S7 — LA CHAÎNE DOCUMENTAIRE
   ⚑ 23 août 2026 — HORS SERVICE. La frise vectorielle est remplacée par
   l'illustration 2.5D `impra-b10-document-statuses` (Level 1), qui dit l'ÉTAT
   des pièces là où les trois cartes disent déjà leurs TYPES. Plus aucun
   élément ne porte `.doc-chain`. Règles conservées : elles resteront justes
   pour une future page Documents qui voudrait détailler la chaîne.
   Une frise d'objets reliés par le connecteur G2. Elle reflue naturellement :
   six stations au desktop, trois au mobile — les trois autres sont retirées,
   jamais compressées.
   ========================================================================== */
.doc-chain {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: 0;
  align-items: end;
  padding: var(--space-32) var(--space-24) var(--space-24);
}
.doc-chain__node {
  position: relative;
  display: grid; justify-items: center; gap: var(--space-8);
  padding-inline: var(--space-8);
  text-align: center;
}
/* Le connecteur : trajectoire pointillée bleue entre deux stations */
.doc-chain__node:not(:last-child)::after {
  content: "";
  position: absolute; z-index: 0;
  left: calc(50% + 34px); right: calc(-50% + 34px);
  top: 44px; height: 2px;
  background-image: linear-gradient(90deg, var(--impra-blue) 0 7px, transparent 7px 14px);
  background-size: 14px 2px;
  opacity: .55;
}
.doc-chain__obj { position: relative; z-index: 1; display: block; width: 88px; height: 88px; }
.doc-chain__label {
  font-size: var(--text-caption); line-height: 1.35;
  font-weight: var(--weight-semibold);
  color: var(--impra-navy);
}
.doc-chain__state {
  font-size: 10px; letter-spacing: .07em; text-transform: uppercase;
  color: var(--impra-muted-soft);
}
@media (max-width: 980px) {
  .doc-chain { grid-template-columns: repeat(3, minmax(0, 1fr)); row-gap: var(--space-32); }
  /* Deux rangées de trois : la chaîne reflue, aucune station n'est perdue */
  .doc-chain__node:not(:last-child)::after { left: calc(50% + 30px); right: calc(-50% + 30px); }
  .doc-chain__node:nth-child(3n)::after { display: none; }
  .doc-chain__obj { width: 76px; height: 76px; }
}

/* ==========================================================================
   9. S11 — LE PASSAGE
   Portique entrouvert + le regard du lynx. Le fragment reste partiel : on ne
   satisfait pas la curiosité avant le clic.
   ========================================================================== */
.teaser--portal {
  padding: 0;
  align-content: stretch;
  justify-items: stretch;
  background: transparent;
  border-color: transparent;
  min-height: 260px;
  -webkit-mask-image: linear-gradient(90deg, #000 0%, #000 88%, transparent 100%);
          mask-image: linear-gradient(90deg, #000 0%, #000 88%, transparent 100%);
}
.portal-scene { position: relative; width: 100%; height: 100%; min-height: 260px; }
.portal-scene__svg { position: absolute; inset: 0; width: 100%; height: 100%; }
.portal-scene__lynx {
  position: absolute;
  right: -2%; bottom: 0;
  width: 46%;
  height: auto;
  -webkit-mask-image: linear-gradient(180deg, #000 0%, #000 72%, transparent 100%);
          mask-image: linear-gradient(180deg, #000 0%, #000 72%, transparent 100%);
  transition: filter 600ms var(--ease-standard);
}
.portal-scene__rim { transition: opacity 600ms var(--ease-standard); opacity: .35; }
/* Au survol du CTA : l'arête du portique et les accents du lynx s'allument.
   Le fragment intérieur, lui, ne bouge pas. */
#explorer .band-card:has(.btn--on-ink:hover) .portal-scene__rim,
#explorer .band-card:has(.btn--on-ink:focus-visible) .portal-scene__rim { opacity: 1; }
#explorer .band-card:has(.btn--on-ink:hover) .portal-scene__lynx,
#explorer .band-card:has(.btn--on-ink:focus-visible) .portal-scene__lynx { filter: saturate(1.22) brightness(1.06); }
.portal-scene__note {
  position: absolute; left: var(--space-24); bottom: var(--space-16);
  margin: 0; max-width: 20ch;
  font-size: var(--text-caption); color: rgba(255,255,255,.55);
}
@media (max-width: 900px) {
  .teaser--portal {
    min-height: 200px;
    -webkit-mask-image: linear-gradient(180deg, #000 0%, #000 82%, transparent 100%);
            mask-image: linear-gradient(180deg, #000 0%, #000 82%, transparent 100%);
  }
  .portal-scene { min-height: 200px; }
  .portal-scene__lynx { width: 42%; right: 0; }
  .portal-scene__note { display: none; }
}

/* ==========================================================================
   10. AVATAR DU WIDGET — la seconde apparition, fonctionnelle
   Tête du lynx officiel recadrée. Aucun redessin, aucune pose.
   ========================================================================== */
.chat-widget__avatar--lynx {
  background-color: var(--impra-blue);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='none' stroke='white' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round' d='M21 11.6a7.8 7.8 0 0 1-8.4 7.7 9 9 0 0 1-3.2-.62L4 20l1.36-4.1A7.6 7.6 0 0 1 3.9 11.6 7.8 7.8 0 0 1 12.45 4 7.8 7.8 0 0 1 21 11.6z'/%3E%3C/svg%3E");
  background-size: 17px 17px;
  background-position: center;
  background-repeat: no-repeat;
}

/* ==========================================================================
   11. MOTION
   Trois gestes seulement : Tracer, Assembler, Circuler. Rien en boucle hors
   des deux scènes qui le justifient. Tout neutralisé en mouvement réduit.
   ========================================================================== */
/* Tracer — la ligne se dessine une fois, à l'entrée */
.gs-trace { stroke-dasharray: var(--len, 600); stroke-dashoffset: var(--len, 600); }
.is-in .gs-trace,
.gs-stage.is-in .gs-trace { animation: gsTrace 1000ms var(--ease-standard) forwards; }
@keyframes gsTrace { to { stroke-dashoffset: 0; } }

/* Assembler — les objets posés arrivent après le tracé */
.gs-assemble { opacity: 0; transform: translateY(8px); }
.is-in .gs-assemble { animation: gsAssemble 520ms var(--ease-standard) 620ms forwards; }
.is-in .gs-assemble[data-delay="2"] { animation-delay: 710ms; }
@keyframes gsAssemble { to { opacity: 1; transform: none; } }

/* Circuler — le flux de synchronisation, seule boucle de la section S5 */
.gs-flow { stroke-dasharray: 9 9; }
.is-in .gs-flow { animation: gsFlow 1.4s linear infinite; }
@keyframes gsFlow { to { stroke-dashoffset: -18; } }
/* La plaquette voyage toutes les 5,2 s, puis la ligne d'arrivée s'allume */
.gs-travel { offset-rotate: 0deg; }
.is-in .gs-travel { animation: gsTravel 5.2s var(--ease-standard) infinite; }
@keyframes gsTravel {
  0%, 6%    { opacity: 0; transform: translate(0, 0); }
  14%       { opacity: 1; }
  62%       { opacity: 1; transform: translate(var(--tx, 0px), var(--ty, 0px)); }
  76%, 100% { opacity: 0; transform: translate(var(--tx, 0px), var(--ty, 0px)); }
}
.is-in .gs-arrive { animation: gsArrive 5.2s var(--ease-standard) infinite; }
@keyframes gsArrive { 0%, 58% { opacity: 0; } 66%, 88% { opacity: 1; } 96%, 100% { opacity: 0; } }

/* Le flux documentaire : play-once au scroll, jamais en boucle */
.doc-chain.is-in .doc-chain__node { animation: gsAssemble 480ms var(--ease-standard) backwards; }
.doc-chain.is-in .doc-chain__node:nth-child(1) { animation-delay: 0ms; }
.doc-chain.is-in .doc-chain__node:nth-child(2) { animation-delay: 130ms; }
.doc-chain.is-in .doc-chain__node:nth-child(3) { animation-delay: 260ms; }
.doc-chain.is-in .doc-chain__node:nth-child(4) { animation-delay: 390ms; }
.doc-chain.is-in .doc-chain__node:nth-child(5) { animation-delay: 520ms; }
.doc-chain.is-in .doc-chain__node:nth-child(6) { animation-delay: 650ms; }
/* L'état documentaire (B10) se lit sans animation : le contour « manquant » reste
   visible sous la pièce reçue. Un état métier ne doit jamais dépendre d'un
   mouvement — ni du JavaScript, ni du temps de lecture du visiteur. */

@media (prefers-reduced-motion: reduce) {
  .gs-trace { stroke-dasharray: none; stroke-dashoffset: 0; animation: none !important; }
  .gs-assemble { opacity: 1; transform: none; animation: none !important; }
  .is-in .gs-flow, .is-in .gs-travel, .is-in .gs-arrive,
  .doc-chain.is-in .doc-chain__node { animation: none !important; }
  .gs-travel, .gs-arrive { opacity: 1; }
  .portal-scene__rim { opacity: .7; }
}
