/* ═══════════════════════════════════════════════════════════════════════════════════════
   Cabestian — le pied de page du site, partagé.
   ───────────────────────────────────────────────────────────────────────────────────────
   Ces règles viennent d'accueil.css, où elles ne servaient qu'à la page d'accueil. Les
   pages champ se terminaient, elles, sur un pied propre — « Comment on démarre », un lien
   de retour et un bouton — qui ne ressemblait à rien d'autre sur le site : arrivé au bout
   d'une fiche produit, on ne retrouvait ni la marque, ni les autres champs d'actions, ni
   la bande de la grue. Le même pied partout, désormais.

   ATTENTION, dette assumée : ces règles sont pour l'instant DUPLIQUÉES — l'accueil garde
   les siennes dans accueil.css. La déduplication demande de toucher à la page la plus
   complexe du site (loader, WebGL, scrub) et n'a pas été faite dans la même passe que le
   reste. À faire : charger cette feuille dans index.html et retirer d'accueil.css les deux
   blocs recopiés ci-dessous, puis vérifier l'accueil de bout en bout.
   ═══════════════════════════════════════════════════════════════════════════════════════ */

.site-footer{position:relative;z-index:2;background:#08141D}
.sf-frame{position:relative;max-width:960px;margin:0 auto;border-left:1px solid rgba(200,214,228,.12);border-right:1px solid rgba(200,214,228,.12);background:radial-gradient(40% 80% at 30% 0%, rgba(192,69,94,.10), transparent 70%)}
.sf-rule{height:1px;width:100%;background:rgba(200,214,228,.12)}
.sf-grid{display:grid;grid-template-columns:repeat(6,1fr);gap:24px;padding:46px 36px}
.sf-brand{grid-column:span 4;display:flex;flex-direction:column;gap:22px}
.sf-mark{display:block;width:max-content}
.sf-mark img{height:26px;width:auto;display:block}
.sf-tagline{font-family:var(--fm);font-size:var(--t-petit);line-height:1.6;color:#8C99A8;max-width:30ch;letter-spacing:.01em}
.sf-socials{display:flex;gap:10px;margin-top:2px}
.sf-socials a{display:grid;place-items:center;width:34px;height:34px;border:1px solid rgba(200,214,228,.12);border-radius:8px;color:#E4E9EF;transition:background .2s,color .2s,border-color .2s}
.sf-socials a:hover{background:#C0455E;color:#fff;border-color:#C0455E}
.sf-socials svg{width:16px;height:16px;display:block}
/* Cibles tactiles (M17, audit du 23/09), le dessin ne bouge pas :
   · LinkedIn et GitHub, 34 × 34 à 10 px d'écart : 6 px de débord depuis la boîte de
     remplissage (32 px, bordure déduite) portent chacun à 44 × 44, bord à bord avec son
     voisin, sans recouvrement ;
   · le logo (112 × 26) et le lien « Cabestian » du copyright (17 px) passent à 44 de haut,
     dans l'air qui les entoure ;
   · les liens de colonne sont empilés au pas de 27 px : 44 chacun les ferait se recouvrir.
     Leur zone couvre donc tout le pas, sans trou entre deux liens — au-dessus du minimum
     de 24 px (WCAG 2.5.8) mais en deçà des 44 px, qu'on n'atteindrait qu'en espaçant la
     colonne, donc en changeant le dessin. */
.sf-socials a{position:relative}
.sf-socials a::after{content:'';position:absolute;inset:-6px}
.sf-mark{position:relative}
.sf-mark::after{content:'';position:absolute;left:0;right:0;top:50%;transform:translateY(-50%);height:44px}
.sf-copy a{position:relative;display:inline-block}
.sf-copy a::after{content:'';position:absolute;left:-4px;right:-4px;top:50%;transform:translateY(-50%);height:44px}
.sf-col{grid-column:span 3}
@media(min-width:720px){.sf-col{grid-column:span 1}}
@media(max-width:719px){.sf-brand{grid-column:1/-1}}
.sf-k{display:block;font-family:var(--fm);font-size:var(--t-micro);letter-spacing:.2em;text-transform:uppercase;color:#8C99A8;margin-bottom:14px}
.sf-col a{display:block;width:max-content;font-family:var(--fd);font-size:var(--t-base);color:#E4E9EF;text-decoration:none;padding:5px 0;cursor:pointer;transition:color .2s}
.sf-col a:hover{color:#C0455E}
.sf-copy{padding:16px 36px 26px;text-align:center}
.sf-copy p{font-family:var(--fm);font-size:var(--t-petit);letter-spacing:.08em;color:#8C99A8;font-weight:400}
.sf-copy a{color:#8C99A8;text-decoration:none}
.sf-copy a:hover{color:#C0455E}
.sf-dotk{color:#C0455E}

.site-footer{ overflow:hidden; }
/* La pill quitte l'écran sur le footer : pas de fondu, elle SORT par le haut.
   Rien en CSS ici, tout passe par GSAP dans index.html, parce que le verre de
   la pill est peint dans un canvas plein écran (#gl) qui ne peut pas glisser :
   c'est __glassBarY qui déplace la barre de verre, en même temps que la nav. */
.sf-px-wrap{ position:absolute; inset:0; z-index:0; pointer-events:none; }
.sf-px-src{ position:absolute; top:0; left:0; width:1px; height:1px; opacity:0; }
.sf-px{
  position:absolute; inset:0; width:100%; height:100%; display:block;
  image-rendering:pixelated; -ms-interpolation-mode:nearest-neighbor;
  opacity:1;
}
.sf-px-wrap::after{
  content:''; position:absolute; inset:0;
  background:
    linear-gradient(180deg, rgba(8,20,29,.72) 0%, rgba(8,20,29,.24) 26%, rgba(8,20,29,.14) 58%, rgba(8,20,29,.62) 100%),
    linear-gradient(90deg, rgba(8,20,29,.82) 0%, rgba(8,20,29,.40) 42%, rgba(8,20,29,.06) 100%);
}
.site-footer .sf-frame{ position:relative; z-index:1; }

/* Le footer gagne en hauteur : la bande a besoin d'air pour qu'on lise la flèche
   de la grue, et le contenu se pose en bas plutôt que d'être centré dans un ruban. */
.site-footer{ min-height:clamp(820px,100vh,1180px); display:flex; flex-direction:column; justify-content:flex-end; }
/* Le cadre du footer portait un halo bordeaux à 10 % en haut à gauche
   (radial-gradient d'origine) : sur la bande pixelisée bleue, il virait au violet
   et cassait la teinte. Il est remplacé par un voile encre, sans couleur, dont le
   seul rôle est de garantir la lisibilité du texte au-dessus de l'image. */
.site-footer .sf-frame{
  background:linear-gradient(180deg, rgba(8,20,29,.58) 0%, rgba(8,20,29,.80) 55%, rgba(8,20,29,.90) 100%);
}

/* Apparition du texte à l'entrée du footer : montée de 14 px et opacité, en cascade
   par colonne. Sobre, dans le même geste que le reste du site. */
.site-footer .sf-grid > *,
.site-footer .sf-bottom{
  opacity:0; transform:translateY(14px);
  transition:opacity .7s cubic-bezier(.2,.7,.2,1), transform .7s cubic-bezier(.2,.7,.2,1);
}
.site-footer.is-in .sf-grid > *{ opacity:1; transform:none; }
.site-footer.is-in .sf-grid > *:nth-child(1){ transition-delay:.02s }
.site-footer.is-in .sf-grid > *:nth-child(2){ transition-delay:.12s }
.site-footer.is-in .sf-grid > *:nth-child(3){ transition-delay:.20s }
.site-footer.is-in .sf-grid > *:nth-child(4){ transition-delay:.28s }
.site-footer.is-in .sf-bottom{ opacity:1; transform:none; transition-delay:.38s }

@media (prefers-reduced-motion:reduce){
  .site-footer .sf-grid > *,
  .site-footer .sf-bottom{ opacity:1; transform:none; transition:none; }
}

/* La substitution en points (_shared/dotmorph.js), reprise d'accueil.css à l'identique.
   Sans ces règles, le canvas.dots de chaque lien restait en position static : il occupait
   63 px dans le flux et disloquait la colonne « Champs d'actions » (audit du 23/09, B2),
   et le mot en points s'affichait à droite du lien au lieu de s'y superposer. Le canvas
   DÉBORDE de la boîte du mot, il ne participe pas à la mise en page. */
.dm{position:relative;display:inline-block;cursor:pointer}
.dm .dots{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);pointer-events:none;opacity:0;transition:opacity .13s linear}
.dm.on .dots{opacity:1}
.dm .letters{transition:opacity .13s linear}
.dm.on .letters{opacity:0}
.dm:focus-visible{outline:2px solid #C0455E;outline-offset:4px;border-radius:2px}

/* Le mot révélé en points déborde sur ses voisins : pendant le survol, la colonne recule.
   Deux règles reprises d'accueil.css, que les pages champ ne chargent pas. */
.dm-groupe a{transition:opacity .28s cubic-bezier(.16,1,.3,1)}
.dm-groupe.dm-actif a:not(.on){opacity:.16}
