/* ==========================================================================
   eshop.css — page « free your mind… »
   --------------------------------------------------------------------------
   Charge apres style.css, dont il reprend les jetons (couleurs, rythme,
   typographie). Rien ici ne s'applique aux autres pages.

   Sommaire
     01. Jetons propres a la page
     02. Barre du compte a rebours, en-tete decale
     03. Scene 3D, ecran de chargement, navigation laterale
     04. Titre et boutons
     05. Scenes (collection, le t-shirt point par point)
     06. Bandeau defilant
     07. Visuel collection (sans 3D)
     08. Shooting
     09. Video
     10. Textes de la marque
     11. Ruban
     12. Fiches produits
     13. Formulaire de precommande
     14. Etats de depart des animations (sous .fx seulement)
     15. Mode 3D (sous .tee3d seulement)
     16. Mouvement reduit
   ========================================================================== */


/* 01. Jetons propres a la page ============================================= */

.page-eshop {
  /* Police du logo « donovan adp▌ » : Courier Prime, en graisse normale.
     (Mesure au pixel sur le fichier du logo : meme quantite d'encre, memes
     terminaisons arrondies. Courier New est plus maigre, les graisses
     « Bold » deux fois trop lourdes.) */
  --f-type: 'Courier Prime', 'Courier New', Courier, monospace;
  --studio: #f2f2f2;          /* fond gris des maquettes produit */
  --glow: 0 0 0.3em rgba(237, 233, 227, 0.32), 0 0 0.08em rgba(237, 233, 227, 0.5);
  --bar-h: 2.25rem;           /* barre du compte a rebours */
  --top-h: calc(var(--bar-h) + var(--head-h) + env(safe-area-inset-top, 0px));
}

/* L'attribut hidden doit gagner sur les display: grid / flex des blocs
   (formulaire, compte a rebours, bloc de commande) : c'est lui que eshop.js
   pose pour basculer d'un etat a l'autre. */
.page-eshop [hidden] { display: none !important; }

/* Les deux barres fixes recouvrent le haut des ancres : on les decale. */
.page-eshop [id] { scroll-margin-top: calc(var(--top-h) + 1rem); }

.nowrap { white-space: nowrap; }

/* Titre de section et mention a droite : la mention passe dessous plutot
   que d'elargir la page sur un ecran etroit. */
.page-eshop .lede { flex-wrap: wrap; row-gap: 0.75rem; }

/* Curseur de terminal, le motif du logo et de l'impression. Fixe : il ne
   clignote nulle part (demande du client). */
.cursor {
  display: inline-block;
  width: 0.55em;
  height: 0.9em;
  margin-left: 0.12em;
  vertical-align: -0.08em;
  background: currentColor;
}


/* 02. Barre du compte a rebours ============================================ */

.countbar {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 102;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: clamp(0.75rem, 2.5vw, 2rem);
  min-height: var(--bar-h);
  padding: env(safe-area-inset-top, 0px) var(--gutter) 0;
  font-family: var(--f-mono);
  font-size: var(--t-meta);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--paper-dim);
  background: rgba(8, 8, 7, 0.94);
  border-bottom: 1px solid var(--rule);
}

.countbar p { margin: 0; white-space: nowrap; }

.countbar__time {
  color: var(--paper);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.06em;
}
.countbar__time [data-unit] { font-size: 0.8125rem; }
.countbar__u { margin: 0 0.5em 0 0.12em; color: var(--paper-dim); }
.countbar__u:last-child { margin-right: 0; }

.countbar__cta {
  padding: 0.3rem 0.85rem;
  color: var(--ink);
  background: var(--paper);
  border-radius: 999px;
  letter-spacing: 0.14em;
  white-space: nowrap;
  transition: background-color 0.3s var(--ease);
}
.countbar__cta:hover { background: #fbf9f6; }
.countbar__cta[aria-disabled='true'] { opacity: 0.55; }

/* Progression dans la page : un filet qui s'etire sous la barre. */
.countbar__progress {
  position: absolute;
  left: 0;
  bottom: -1px;
  width: 100%;
  height: 1px;
  background: var(--paper);
  box-shadow: 0 0 8px rgba(237, 233, 227, 0.7);
  transform: scaleX(0);
  transform-origin: 0 50%;
}

/* Sur telephone et petite tablette : le decompte seul, precede de « sortie
   dans ». Tant que le decompte n'est pas affiche (sans JavaScript), la date
   reste. Jusqu'a 799 px, la date complete ne tient pas a cote du bouton. */
@media (max-width: 799px) {
  .countbar:has(.countbar__time:not([hidden])) .countbar__label { display: none; }
  .countbar__time::before { content: 'sortie dans'; margin-right: 0.8em; color: var(--paper-dim); letter-spacing: 0.16em; }
}
/* Sur telephone, le bouton de la barre disparait : a cote du decompte, il
   n'a pas la place (« precommandes des le 2 octobre » passait sur trois
   lignes et recouvrait le menu sur les ecrans de 400 a 599 px, iPhone Plus
   et Pro Max). Le meme bouton est juste en dessous, en haut de page. */
@media (max-width: 599px) {
  .countbar__cta { display: none; }
}

/* L'en-tete du site passe sous la barre. */
.page-eshop .masthead {
  top: calc(var(--bar-h) + env(safe-area-inset-top, 0px));
  padding-top: clamp(1rem, 2.2vw, 1.75rem);
}


/* 03. Scene 3D, chargement, navigation laterale ============================ */

/* La scene est derriere tout le contenu. Elle n'existe qu'en mode 3D. */
/* Hauteur fixe, celle de l'ecran barres du navigateur repliees : sur
   telephone, la barre d'adresse qui apparait et disparait au defilement ne
   redimensionne plus la scene (les t-shirts du ruban changeaient de taille). */
.stage {
  position: fixed;
  inset: 0 0 auto 0;
  height: 100vh;
  height: 100lvh;
  z-index: -1;
  display: none;
  pointer-events: none;
}
.tee3d .stage { display: block; }

.stage__paper,
.stage__glow {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}
.stage__paper { background: var(--paper); opacity: 0; }

/* Le halo d'un projecteur au-dessus du t-shirt, en niveaux de gris. */
.stage__glow {
  background:
    radial-gradient(42% 38% at 50% 34%, rgba(237, 233, 227, 0.11), rgba(237, 233, 227, 0) 70%),
    radial-gradient(90% 60% at 50% 110%, rgba(237, 233, 227, 0.05), rgba(237, 233, 227, 0) 70%);
}

/* Navigation par section, a droite, sur grand ecran avec souris. */
.railnav { display: none; }

@media (min-width: 1100px) and (hover: hover) {
  .railnav {
    position: fixed;
    right: clamp(1rem, 2vw, 2rem);
    top: 50%;
    z-index: 90;
    display: grid;
    gap: 0.35rem;
    transform: translateY(-50%);
  }
  .railnav a {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 0.75rem;
    min-height: 1.75rem;
    font-family: var(--f-mono);
    font-size: var(--t-meta);
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--paper-mute);
    transition: color 0.3s var(--ease);
  }
  /* Le libelle a gauche du numero : les numeros restent alignes sur le bord. */
  .railnav__t { order: -1; opacity: 0; transform: translateX(6px); transition: opacity 0.3s var(--ease), transform 0.3s var(--ease); }
  .railnav__n { position: relative; padding-right: 1.4rem; }
  .railnav__n::after {
    content: '';
    position: absolute;
    right: 0;
    top: 50%;
    width: 0.8rem;
    height: 1px;
    background: currentColor;
    transform-origin: 100% 50%;
    transition: transform 0.3s var(--ease);
  }
  .railnav a:hover,
  .railnav a.is-active { color: var(--paper); }
  .railnav a:hover .railnav__t,
  .railnav a.is-active .railnav__t { opacity: 1; transform: none; }
  .railnav a.is-active .railnav__n::after { transform: scaleX(1.5); }
  /* Sur le panneau papier, la navigation passe a l'encre. */
  .on-paper .railnav a { color: #7a7a74; }
  .on-paper .railnav a:hover,
  .on-paper .railnav a.is-active { color: var(--ink); }
}


/* 04. Titre et boutons ===================================================== */

.fym-hero {
  position: relative;
  /* Le halo et l'inclinaison des t-shirts ne doivent jamais elargir la page. */
  overflow-x: clip;
  display: grid;
  /* Centre : la video, recadree au carre, ne remplit plus la hauteur. */
  align-content: center;
  min-height: 100svh;
  /* Un vide garanti sous la barre du menu : sur telephone, quand la hauteur
     manque (barres du navigateur affichees), la video remontait jusqu'a
     toucher la barre. Ce vide est aussi retire de la hauteur de la video. */
  --hero-air: clamp(1.5rem, 4svh, 2.5rem);
  padding-top: calc(var(--top-h) + var(--hero-air));
  padding-bottom: clamp(4.25rem, 10vh, 6.5rem);
}

/* La video du t-shirt en rotation, au-dessus du titre. Elle est verticale
   et tournee sur un fond studio gris clair : on la pose comme une carte,
   coins arrondis, avec l'ombre et le halo des boutons. Sa hauteur suit
   celle de l'ecran pour que le titre reste visible sans defiler ; sur
   telephone, elle prend le plus de place possible (demande du client). */
.fym-hero__visual {
  display: flex;
  justify-content: center;
  margin: 0 auto clamp(1.5rem, 4vh, 2.5rem);
}
/* Recadree au carre partout, comme sur ordinateur : la video verticale
   porte une etoile en bas a droite, que ce cadrage laisse hors champ (le
   recadrage ne retire que du fond gris au-dessus et au-dessous du
   t-shirt). Sur telephone, le carre prend toute la largeur utile, sans
   depasser la hauteur qui laisse le titre visible. */
.fym-hero__video {
  display: block;
  width: clamp(260px, min(100vw - 2 * var(--gutter), 100svh - var(--top-h) - var(--hero-air) - 12.75rem), 620px);
  height: auto;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  object-position: 50% 52%;
  background: #b8b8b8;
  border-radius: 1.5rem;
  box-shadow:
    0 30px 60px -24px rgba(0, 0, 0, 0.85),
    0 0 0 1px rgba(237, 233, 227, 0.12),
    0 0 90px -20px rgba(237, 233, 227, 0.35);
}

.fym-hero__text {
  display: grid;
  justify-items: center;
  gap: clamp(1.5rem, 3.5vh, 2.25rem);
  text-align: center;
}

/* Meme dessin que le logo : Courier Prime en graisse normale, la chasse
   un peu ouverte du logo et son halo. */
.fym-title {
  margin: 0;
  font-family: var(--f-type);
  font-weight: 400;
  font-size: clamp(1.9rem, 5vw, 3.6rem);
  line-height: 1;
  letter-spacing: 0.06em;
  color: var(--green);
  text-shadow: 0 0 0.12em rgba(153, 252, 136, 0.55), 0 0 0.45em rgba(153, 252, 136, 0.28);
}

/* Le curseur suit la derniere lettre affichee : pendant la frappe (eshop.js)
   les lettres pas encore tapees sont retirees du rendu, pour que le curseur
   avance avec elles. Il ne clignote pas. */
.fym-title::after {
  content: '';
  display: inline-block;
  width: 0.5em;
  height: 0.78em;
  margin-left: 0.08em;
  vertical-align: -0.06em;
  margin-left: 0.14em;
  background: var(--green);
  box-shadow: 0 0 0.12em rgba(153, 252, 136, 0.55), 0 0 0.45em rgba(153, 252, 136, 0.28);
}

/* Ordinateur : la video passe a droite, en grand, recadree au carre — le
   t-shirt n'occupe que la moitie de la hauteur de la video verticale, le
   recadrage ne retire que du fond gris. Le titre et le bouton a gauche. */
@media (min-width: 1024px) {
  .fym-hero {
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    align-content: center;
    column-gap: clamp(2rem, 5vw, 5rem);
    /* Un vide garanti sous la barre, et autant au-dessus du bas de l'ecran :
       sans lui, sur un ecran d'ordinateur portable, la video touchait la
       barre du menu. */
    --hero-air: clamp(1.5rem, 4vh, 3rem);
    padding-inline: max(var(--gutter), calc((100vw - 1320px) / 2));
    padding-bottom: clamp(3rem, 7vh, 5rem);
  }
  .fym-hero__visual { order: 2; margin: 0; }
  .fym-hero__video {
    width: auto;
    height: clamp(320px, calc(100svh - var(--top-h) - 2 * var(--hero-air) - clamp(3rem, 7vh, 5rem)), 680px);
    aspect-ratio: 1 / 1;
  }
  .fym-hero__text {
    justify-items: start;
    text-align: left;
    padding-inline: 0;
    max-width: none;
  }
  /* Une seule ligne, curseur compris : la taille suit la largeur de la
     colonne, et le curseur ne passe jamais seul a la ligne. */
  .fym-title { font-size: clamp(2.1rem, 3.2vw, 2.9rem); white-space: nowrap; }
}

/* La navigation laterale occupe le bord droit : la video s'en ecarte. */
@media (min-width: 1100px) and (hover: hover) {
  .fym-hero { padding-right: max(calc(var(--gutter) + 8rem), calc((100vw - 1320px) / 2)); }
}

.fym-hero__cue {
  position: absolute;
  left: 50%;
  bottom: clamp(1.25rem, 3.5vh, 2.25rem);
  transform: translateX(-50%);
}

/* Bouton d'action : une pilule claire, detachee du fond par une ombre et
   un halo. Pas de transition sur opacity ni transform : GSAP anime ces
   deux proprietes (apparition, effet aimante), et une transition CSS posee
   dessus lui fait relever des valeurs en cours de route. */
.cta {
  display: inline-flex;
  align-items: center;
  gap: 0.2em;
  min-height: 3.25rem;
  padding: 1rem 1.5rem 1rem 1.9rem;
  font-family: var(--f-mono);
  font-size: var(--t-meta);
  font-weight: 400;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--ink);
  background: var(--paper);
  border-radius: 999px;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.7),
    0 14px 34px -12px rgba(0, 0, 0, 0.8),
    0 0 0 1px rgba(237, 233, 227, 0.18),
    0 0 44px -10px rgba(237, 233, 227, 0.45);
  transition: background-color 0.3s var(--ease), box-shadow 0.4s var(--ease), color 0.3s var(--ease);
}
.cta:hover {
  background: #fbf9f6;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.8),
    0 18px 40px -12px rgba(0, 0, 0, 0.85),
    0 0 0 1px rgba(237, 233, 227, 0.3),
    0 0 60px -6px rgba(237, 233, 227, 0.6);
}

.cta__cursor {
  display: inline-block;
  width: 0.62em;
  height: 1.05em;
  margin-left: 0.6em;
  background: currentColor;
  border-radius: 2px;
  transition: transform 0.35s var(--ease);
}
.cta:hover .cta__cursor,
.cta:focus-visible .cta__cursor { transform: translateX(0.3em); }

.cta--on-light {
  color: var(--paper);
  background: var(--ink);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.12),
    0 14px 30px -12px rgba(8, 8, 7, 0.55),
    0 0 0 1px rgba(8, 8, 7, 0.9);
}
.cta--on-light:hover {
  background: #2a2a27;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.16),
    0 20px 36px -12px rgba(8, 8, 7, 0.6),
    0 0 0 1px rgba(8, 8, 7, 0.9);
}
.cta--on-light:focus-visible { outline-color: var(--ink); }

/* Avant l'ouverture des precommandes (voir ESHOP dans data.js). Grise par
   filter et non par opacity : l'apparition des fiches (eshop.js) pose une
   opacite en ligne qui l'ecraserait. */
.cta[aria-disabled='true'],
.cta[aria-disabled='true']:hover { filter: opacity(0.45); cursor: not-allowed; box-shadow: none; }
.cta[aria-disabled='true'] .cta__for { display: none; }
.cta[aria-disabled='true'] .cta__cursor { transform: none; }

.band-cta {
  display: flex;
  justify-content: center;
  margin-top: clamp(2.5rem, 6vw, 4rem);
}

.band-cta--end {
  flex-direction: column;
  align-items: center;
  gap: 1.5rem;
  margin-top: clamp(4rem, 10vw, 7rem);
  padding-top: clamp(3rem, 7vw, 5rem);
  border-top: 1px solid var(--rule);
}
.band-cta--end .tag { margin: 0; }


/* 05. Scenes ================================================================
   Un ecran par idee. En 3D, le t-shirt occupe la moitie droite (ordinateur)
   ou le haut de l'ecran (telephone) ; le texte, l'autre moitie. */

.scene {
  position: relative;
  display: grid;
  align-content: center;
  min-height: 100svh;
  padding-block: calc(var(--top-h) + 2rem) 4rem;
}

.scene__text { max-width: 30rem; }
.scene__text > * { margin: 0; }
.scene__text > * + * { margin-top: 1.25rem; }

.scene__kicker { color: var(--paper-dim); }

.scene__title {
  font-size: clamp(2.6rem, 7.5vw, 5.75rem);
  font-weight: 800;
  line-height: 0.95;
  letter-spacing: -0.05em;
  text-transform: lowercase;
}

.scene__body {
  max-width: 26ch;
  font-size: clamp(1.0625rem, 1.5vw, 1.3125rem);
  line-height: 1.5;
  color: var(--paper-dim);
}

/* « Edition limitee : 15 pieces par couleur. » tient sur une ligne, meme
   a 320 px : la taille suit la largeur de l'ecran sur telephone. */
.scene__body--wide { max-width: none; }
.scene__oneline { font-size: min(1em, 4.3vw); }

/* La collection : le texte en haut, les deux t-shirts dessous. */
.scene--collection { align-content: start; gap: clamp(2rem, 5vw, 3.5rem); }

/* Masques des lignes (SplitText) : la ligne monte depuis sous sa propre
   ligne de base, comme sortie d'une fente. */
.page-eshop .line-mask { overflow: hidden; padding-bottom: 0.08em; margin-bottom: -0.08em; }


/* 06. Bandeau defilant ===================================================== */

.marquee {
  overflow: hidden;
  border-block: 1px solid var(--rule);
  padding-block: clamp(0.9rem, 2vw, 1.4rem);
}

.marquee__track {
  display: flex;
  width: max-content;
  animation: marquee 38s linear infinite;
}

.marquee__track span {
  display: inline-flex;
  align-items: center;
  font-family: var(--f-type);
  font-weight: 400;
  font-size: clamp(1.25rem, 3.4vw, 2.5rem);
  letter-spacing: -0.02em;
  white-space: nowrap;
}
.marquee__track span::after {
  content: '';
  width: 0.45em;
  height: 0.75em;
  margin-inline: 0.9em;
  background: var(--paper-mute);
}

/* Deux series identiques dans la piste : a -50 %, la seconde a pris
   exactement la place de la premiere, la boucle ne se voit pas. */
@keyframes marquee { to { transform: translateX(-50%); } }


/* 07. Visuel collection (sans 3D) ========================================= */

.collection { margin: 0; }

.collection__inner {
  overflow: hidden;
  background: var(--studio);
}

.collection__inner img { width: 100%; }

@media (max-width: 719px) {
  .collection { margin-inline: calc(var(--gutter) * -1); }
}


/* 08. Shooting ============================================================ */

.worn__viewport { overflow: hidden; }

.worn__track {
  display: grid;
  gap: var(--gap);
  width: 100%;
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

@media (max-width: 719px) {
  .worn__track { padding-inline: 0; }
}

@media (min-width: 720px) {
  .worn__track { grid-template-columns: repeat(3, 1fr); }
}

.worn__frame {
  margin: 0;
  overflow: hidden;
  background: var(--tone, var(--ink-raised));
}

.worn__frame img {
  width: 100%;
  aspect-ratio: 3 / 4;
  object-fit: cover;
}

/* Rail horizontal, pose par eshop.js sur ordinateur seulement : la section
   est epinglee et la piste glisse de cote pendant le defilement. La largeur
   d'une photo est bornee par la hauteur de l'ecran, pour qu'elle y tienne
   entiere sous l'en-tete. */
.worn--rail {
  padding-block: 0;
  display: grid;
  align-content: center;
  min-height: 100svh;
  padding-top: var(--top-h);
}
.worn--rail .worn__track {
  display: flex;
  width: max-content;
  max-width: none;
  gap: clamp(1.5rem, 3vw, 3rem);
  padding-inline: max(var(--gutter), calc((100vw - var(--shell)) / 2 + var(--gutter)));
}
.worn--rail .worn__frame {
  width: min(34vw, calc((100svh - var(--top-h) - 12rem) * 0.75));
  flex: none;
}
.worn--rail .worn__frame img { transform: scale(1.12); }


/* 09. Video ================================================================ */

.clip {
  position: relative;
  width: min(100%, 420px);
  margin-inline: auto;
  aspect-ratio: 9 / 16;
  background: var(--ink-raised);
  overflow: hidden;
}

.clip__facade,
.clip iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

.clip__facade img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.9s var(--ease), opacity 0.4s var(--ease);
}
.clip__facade:hover img { transform: scale(1.03); }

.clip__play {
  position: absolute;
  inset: auto 0 0 0;
  display: flex;
  align-items: center;
  gap: 0.9rem;
  padding: 3rem 1.25rem 1.25rem;
  background: linear-gradient(to top, rgba(8, 8, 7, 0.85), rgba(8, 8, 7, 0));
}
.clip__play svg {
  width: 3.25rem;
  height: 3.25rem;
  padding: 0.9rem;
  color: var(--ink);
  background: var(--paper);
  border-radius: 50%;
  box-shadow: 0 10px 26px -10px rgba(0, 0, 0, 0.8), 0 0 36px -8px rgba(237, 233, 227, 0.5);
  transition: transform 0.35s var(--ease);
}
.clip__play .tag { color: var(--paper); }
.clip__facade:hover svg,
.clip__facade:focus-visible svg { transform: scale(1.08); }
.clip__facade:focus-visible { outline-offset: -4px; }

@media (max-width: 719px) {
  .clip { width: calc(100% + var(--gutter) * 2); margin-inline: calc(var(--gutter) * -1); }
}


/* 10. Textes de la marque ================================================== */

.manifesto {
  display: grid;
  gap: clamp(3rem, 7vw, 4rem) clamp(2rem, 4vw, 3.5rem);
}

@media (min-width: 960px) {
  .manifesto { grid-template-columns: repeat(3, 1fr); }
}

.manifesto__item > * { margin: 0; }
.manifesto__item > * + * { margin-top: 1.1em; }

.manifesto__item .manifesto__kicker { color: var(--green); }
.manifesto__kicker .cursor { width: 0.7em; height: 0.8em; }

.manifesto__title {
  margin-top: 1.4rem !important;
  padding-bottom: 1rem;
  font-size: clamp(1.5rem, 2.6vw, 2rem);
  font-weight: 800;
  line-height: 1.05;
  letter-spacing: -0.035em;
  text-transform: lowercase;
  position: relative;
}
.manifesto__title::after {
  content: '';
  position: absolute;
  left: 0;
  bottom: 0;
  width: 2.75rem;
  height: 3px;
  background: var(--green);
}

.manifesto__item p { color: var(--paper-dim); line-height: 1.65; }

/* Les passages en vert des visuels d'origine : chasse fixe et meme vert
   terminal (releve au pixel sur les images du client). */
.manifesto__item .manifesto__mono {
  font-family: var(--f-mono);
  font-size: 0.94em;
  line-height: 1.6;
  color: var(--green);
}


/* 12. Fiches produits ======================================================
   Deux panneaux pleine largeur. Le fond du panneau clair est un calque a
   part (.product__bg) : eshop.js l'etire du haut vers le bas quand le
   panneau arrive — la bascule noir → blanc — en ne jouant que sur transform.
   Sans script, le calque est simplement la. */

.products { padding-top: var(--band); }
.products .lede { margin-bottom: 0; }

.product {
  --p-fg: var(--paper);
  --p-dim: var(--paper-dim);
  --p-line: var(--rule);
  position: relative;
  isolation: isolate;
  color: var(--p-fg);
  padding-block: clamp(3.5rem, 9vw, 7rem);
}

.product--light {
  --p-fg: var(--ink);
  --p-dim: #4f4f4a;        /* 7,1:1 sur le papier */
  --p-line: rgba(8, 8, 7, 0.16);
  margin-top: clamp(2.5rem, 6vw, 4rem);
}
.product--light :focus-visible { outline-color: var(--ink); }
.product--light ::selection { background: var(--ink); color: var(--paper); }

.product__bg {
  position: absolute;
  inset: 0;
  z-index: -1;
  transform-origin: 50% 0;
}
.product--light .product__bg { background: var(--paper); }
.product--dark .product__bg { background: var(--ink); }

.product__body {
  display: grid;
  gap: clamp(2rem, 5vw, 3rem);
  align-items: center;
}

@media (min-width: 900px) {
  .product__body { grid-template-columns: 1fr 1.25fr; gap: clamp(2.5rem, 5vw, 4.5rem); }
  /* Les infos a gauche, le t-shirt a droite, sur les deux fiches : en 3D,
     c'est a droite que le t-shirt se pose. */
  .product__media { order: 2; }
}

.product__media { perspective: 1400px; }

/* Une seule vue a la fois, en grand : la face, ou le dos. Ce sont les
   photos d'origine, non detourees (tools/cutout-tshirts.py, fichiers vue-*),
   sur le gris de leur studio : le cadre reprend ce gris pour qu'elles s'y
   fondent sans bord. */
.product__stage {
  position: relative;
  aspect-ratio: 748 / 600;
  overflow: hidden;
  border-radius: 1.25rem;
  background: var(--studio);
  box-shadow: 0 24px 50px -28px rgba(0, 0, 0, 0.7);
}

.product__view {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  transform-origin: 46% 37%;
  transition: opacity 0.5s var(--ease), transform 0.85s var(--ease);
}
.product__view--dos { opacity: 0; }

/* « impression » : grossi sur l'inscription ; « dos » : l'autre vue. */
.product__stage[data-view='front'] .product__view--face { transform: scale(2.3); }
.product__stage[data-view='back'] .product__view--face { opacity: 0; }
.product__stage[data-view='back'] .product__view--dos { opacity: 1; }

.product__views {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: 1rem;
}

.chip {
  min-height: 2.75rem;
  padding: 0.5rem 1rem;
  font-family: var(--f-mono);
  font-size: var(--t-meta);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--p-dim);
  border: 1px solid var(--p-line);
  border-radius: 999px;
  transition: color 0.3s var(--ease), border-color 0.3s var(--ease), background 0.3s var(--ease);
}
.chip:hover { color: var(--p-fg); border-color: var(--p-fg); }
.chip[aria-pressed='true'] { color: var(--p-fg); border-color: var(--p-fg); background: color-mix(in srgb, var(--p-fg) 8%, transparent); }

.product__info > * { margin: 0; }
.product__info > * + * { margin-top: 1.25rem; }

.product__edition { color: var(--p-dim); }

.product__name {
  font-size: clamp(1.5rem, 3.2vw, 2.25rem);
  font-weight: 800;
  line-height: 1.08;
  letter-spacing: -0.035em;
  text-transform: lowercase;
}

.product__price {
  font-family: var(--f-mono);
  font-size: 1.25rem;
  letter-spacing: 0.02em;
}
.product__price[hidden] { display: none; }

/* La mention des frais de port : presente, sans concurrencer le prix. */
.product__shipping {
  margin-left: 0.5em;
  font-size: var(--t-meta);
  letter-spacing: 0.04em;
  color: var(--p-dim);
  white-space: nowrap;
}

.product__facts {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 0;
  padding: 0;
  list-style: none;
  font-family: var(--f-mono);
  font-size: var(--t-meta);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--p-dim);
}
.product__facts { gap: 0.5rem 1.4rem; }

/* Details repliables : natifs, donc clavier et lecteurs d'ecran sans aide. */
.details { border-top: 1px solid var(--p-line); }

.details__item { border-bottom: 1px solid var(--p-line); }

.details__item summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 3rem;
  padding-block: 0.75rem;
  font-family: var(--f-mono);
  font-size: var(--t-meta);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  cursor: pointer;
  list-style: none;
}
.details__item summary::-webkit-details-marker { display: none; }
.details__item summary::after {
  content: '+';
  font-size: 1.1rem;
  line-height: 1;
  transition: transform 0.3s var(--ease);
}
.details__item[open] summary::after { transform: rotate(45deg); }

.details__body { padding-bottom: 1.25rem; color: var(--p-dim); }
.details__body p { margin: 0 0 0.4em; }

.care { display: grid; gap: 0.75rem; margin: 0; padding: 0; list-style: none; }
.care li { display: flex; align-items: center; gap: 0.9rem; line-height: 1.35; }
.care svg { flex: none; width: 2rem; height: 2rem; color: var(--p-fg); }

.product .cta { margin-top: 2rem; }

.sprite { position: absolute; width: 0; height: 0; overflow: hidden; }


/* 13. Formulaire de precommande ============================================ */

.preorder__layout {
  display: grid;
  gap: clamp(2rem, 5vw, 3rem);
}

@media (min-width: 960px) {
  .preorder__layout { grid-template-columns: 1fr 2fr; gap: clamp(3rem, 6vw, 5rem); }
}

.preorder__aside { color: var(--paper-dim); }
.preorder__aside p { margin: 0 0 1.25rem; max-width: 36ch; }
.preorder__stock { font-size: 0.875rem; color: var(--paper); }

.preorder__closed {
  margin: 0 0 1.5rem;
  font-family: var(--f-mono);
  color: var(--paper-dim);
}

/* Le formulaire reprend .form et .field de la page contact. Libelles plus
   clairs ici : sur une commande, ils se lisent, ils ne se devinent pas. */
.preorder__form { margin-top: 0; padding-top: 0; border-top: 0; }
/* Avant l'ouverture des precommandes : le formulaire reste visible mais
   grise, ses champs desactives par eshop.js. */
.preorder__form[data-locked] { opacity: 0.45; }
.preorder__form[data-locked] * { cursor: not-allowed; }
.preorder__form[data-locked] .choice__opt:hover span { color: inherit; border-color: inherit; }
.preorder .form__submit[disabled] { box-shadow: none; }
.preorder__form[data-locked] .form__submit:hover { opacity: 1; }
.preorder .form__submit {
  border-radius: 999px;
  padding: 1.05rem 2.2rem;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.7), 0 14px 34px -12px rgba(0, 0, 0, 0.8), 0 0 44px -10px rgba(237, 233, 227, 0.45);
}
.preorder__done { border-radius: 1.25rem; }
.preorder .field__label { color: var(--paper-dim); }
.preorder .req { color: var(--paper); }
/* Exemples de saisie plus lisibles que sur le contact (4:1 au lieu de 2,6:1) :
   sur une adresse de livraison, ils guident vraiment. */
.preorder .field__input::placeholder { color: #71716b; }
.preorder .opt { margin-left: 0.6em; color: var(--paper-dim); letter-spacing: 0.1em; text-transform: none; }

.form__row { display: grid; gap: clamp(1.75rem, 4vw, 2.5rem) 2rem; }

@media (min-width: 600px) {
  .form__row { grid-template-columns: 1fr 1fr; }
  .form__row--address { grid-template-columns: 1fr 1.6fr; }
  .form__row--address [data-field='pays'] { grid-column: 1 / -1; }
}

@media (min-width: 1100px) {
  .form__row--address { grid-template-columns: 1fr 1.6fr 1.3fr; }
  .form__row--address [data-field='pays'] { grid-column: auto; }
}

.honeypot { display: none; }

select.field__input {
  appearance: none;
  padding-right: 2rem;
  cursor: pointer;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5l5 5 5-5' fill='none' stroke='%23ede9e3' stroke-width='1.4'/%3E%3C/svg%3E") no-repeat right 0.25rem center / 0.75rem;
}
select.field__input option { color: var(--paper); background: var(--ink-raised); }

/* Choix couleur et taille : de vrais boutons radio, masques visuellement
   mais toujours focalisables — la pastille dessine leur etat. */
.choice { margin: 0; padding: 0; border: 0; min-width: 0; display: grid; gap: 0.75rem; }
.choice legend { padding: 0; margin-bottom: 0.75rem; }
.choice__row { display: flex; flex-wrap: wrap; gap: 0.5rem; }

.choice__opt { position: relative; }
.choice__opt input {
  position: absolute;
  inset: 0;
  opacity: 0;
  margin: 0;
  cursor: pointer;
}
.choice__opt span {
  display: grid;
  place-items: center;
  min-width: 3.5rem;
  min-height: 3rem;
  padding: 0.5rem 1.1rem;
  font-family: var(--f-mono);
  font-size: 0.8125rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--paper-dim);
  border: 1px solid var(--rule);
  border-radius: 999px;
  transition: color 0.25s var(--ease), background 0.25s var(--ease), border-color 0.25s var(--ease);
}
.choice__opt:hover span { color: var(--paper); border-color: var(--paper-dim); }
.choice__opt input:checked + span { color: var(--ink); background: var(--paper); border-color: var(--paper); }
.choice__opt input:focus-visible + span { outline: 2px solid var(--paper); outline-offset: 3px; }

.consent { display: grid; gap: 0.75rem; }
.consent__label {
  display: flex;
  align-items: flex-start;
  gap: 0.9rem;
  cursor: pointer;
}
.consent__label input {
  flex: none;
  width: 1.35rem;
  height: 1.35rem;
  margin: 0.1rem 0 0;
  accent-color: var(--paper);
  cursor: pointer;
}
.consent__note {
  margin: 0;
  padding-left: 2.25rem;
  font-size: 0.875rem;
  color: var(--paper-dim);
}
.consent__note a { border-bottom: 1px solid var(--rule); }

.form__legend { margin: 0; color: var(--paper-dim); }

/* Erreurs : en blanc plein, precedees d'un trait, et le champ fautif garde
   un soulignement epais. Le site n'a pas de couleur d'alerte — c'est voulu. */
.field__error {
  margin: 0;
  font-family: var(--f-mono);
  font-size: 0.75rem;
  letter-spacing: 0.04em;
  line-height: 1.5;
  color: var(--paper);
}
.field__error:empty { display: none; }
.field__error::before { content: '— '; }

.field__input[aria-invalid='true'] { border-bottom: 2px solid var(--paper); }
.choice[data-invalid] .choice__opt span { border-color: var(--paper-dim); }
.consent[data-invalid] .consent__label input { outline: 2px solid var(--paper); outline-offset: 2px; }

.preorder__done {
  padding: clamp(2rem, 5vw, 3rem);
  border: 1px solid var(--rule);
}
/* Recoit le focus apres l'envoi : sans marge, son haut passe sous la barre fixe. */
.preorder__done { scroll-margin-top: calc(var(--top-h) + 1rem); }
.preorder__done:focus { outline: none; }
.preorder__done p { margin: 0 0 0.75rem; color: var(--paper-dim); }
.preorder__done .preorder__done-title {
  margin-bottom: 1.5rem;
  font-family: var(--f-type);
  font-weight: 400;
  font-size: clamp(1.6rem, 4vw, 2.5rem);
  color: var(--paper);
  text-shadow: var(--glow);
}



/* 11. Ruban ================================================================
   Trois couches separees de haut en bas, sans chevauchement : le titre et la
   legende, la phrase geante, la serie de t-shirts (canvas de tee3d.js).

   Par defaut (sans JavaScript, sans WebGL, « reduire les animations ») : la
   phrase entiere et une rangee fixe de t-shirts, dans le flux.

   En mode 3D (.will-3d) : la section est haute et son cadre reste colle a
   l'ecran (sticky) pendant qu'elle defile. La phrase glisse, s'arrete au
   centre ou elle se lit en entier, puis repart ; les t-shirts ondulent
   (eshop.js, buildRibbon). Le canvas est DANS la section : rien ne peut en
   sortir, ni au-dessus de « les modeles » ni ailleurs.

   Hauteurs en svh : celle de l'ecran barres du navigateur deployees, qui
   ne change pas quand la barre d'adresse de l'iPhone va et vient. */

.ribbon {
  position: relative;
  isolation: isolate;
  padding-block: var(--band);
  /* clip et non hidden : hidden ferait de la section un conteneur de
     defilement, et le cadre colle (sticky) ne collerait plus. clip-path
     double la coupe pour les navigateurs qui ignorent overflow: clip. */
  overflow: clip;
  clip-path: inset(0);
}

.ribbon__frame {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: clamp(1.5rem, 4.5svh, 3rem);
}

.will-3d .ribbon {
  height: 230vh;
  height: 230svh;
  padding-block: 0;
}

/* Le haut du cadre passe sous la barre et l'en-tete fixes : on le reserve,
   pour que le contenu se centre dans la partie vraiment visible. */
.will-3d .ribbon__frame {
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100svh;
  padding-top: var(--top-h);
  padding-bottom: clamp(1rem, 3svh, 2rem);
}

.ribbon__lede {
  flex-wrap: wrap;
  row-gap: 0.5rem;
  margin-bottom: 0;
}

/* La phrase tient en entier dans la largeur : 15 signes de chasse fixe
   (0,57 em chacun avec l'approche) a 10vw font 86 % de l'ecran. */
.ribbon__giant {
  margin: 0;
  text-align: center;
  white-space: nowrap;
  font-family: var(--f-type);
  font-weight: 400;
  font-size: clamp(2.25rem, 10vw, 10rem);
  line-height: 1;
  letter-spacing: -0.03em;
  /* Lettres noires cernees du vert terminal de la marque, sans halo.
     paint-order : le contour est peint sous le remplissage, il reste net
     et ne mange pas l'interieur des lettres. */
  color: var(--ink);
  -webkit-text-stroke: clamp(3px, 0.05em, 8px) var(--green);
  paint-order: stroke fill;
}

.ribbon__giant span { display: inline-block; }
.will-3d .ribbon__giant span { will-change: transform; }

/* La bande des t-shirts : sa hauteur suit la largeur, bornee par l'ecran. */
.ribbon__tees {
  position: relative;
  height: min(52vw, 38vh, 26rem);
  height: min(52vw, 38svh, 26rem);
}

.ribbon__canvas {
  display: none;
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}
.tee3d .ribbon__canvas { display: block; }
.tee3d .ribbon__row { display: none; }

.ribbon__row {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: clamp(0.5rem, 2vw, 1.5rem);
  height: 100%;
  padding-inline: var(--gutter);
}
.ribbon__row img { width: 30vw; height: auto; }
.ribbon__row img:nth-child(n+4) { display: none; }

@media (min-width: 720px) {
  .ribbon__row img { width: 20vw; }
  .ribbon__row img:nth-child(4) { display: block; }
}

@media (min-width: 1100px) {
  .ribbon__row img { width: 16vw; max-width: 19rem; }
  .ribbon__row img:nth-child(5) { display: block; }
}


/* 14. Etats de depart des animations =======================================
   Uniquement sous .fx, que pose eshop-boot.js. Ne concerne que le haut de
   page, visible au premier rendu : sans cet etat ecrit d'avance, le titre
   s'afficherait une fraction de seconde avant d'etre efface puis tape. Le
   reste de la page est prepare par eshop.js, hors de l'ecran.

   Filet : si eshop.js ne s'execute pas (fichier bloque, erreur), il ne pose
   jamais .fx-ready et l'animation ci-dessous rend tout visible apres 2,5 s. */

.fx .fym-hero [data-fx],
.fx [data-type] { opacity: 0; }

.fx:not(.fx-ready) .fym-hero [data-fx],
.fx:not(.fx-ready) [data-type] { animation: fx-failsafe 0s 2.5s forwards; }

@keyframes fx-failsafe { to { opacity: 1; } }


/* 15. Mode 3D ==============================================================
   Classe .tee3d posee par eshop.js une fois la scene prete : elle fait
   apparaitre le canvas (section 03). La 3D ne sert qu'au ruban et aux
   silhouettes derriere les textes de la marque ; tout le reste de la page
   garde ses visuels fixes. */

@media (max-width: 899px) {
  .scene__title { font-size: clamp(2.4rem, 12vw, 3.5rem); }
}


/* 16. Mouvement reduit ===================================================== */

@media (prefers-reduced-motion: reduce) {
  .marquee__track { animation: none !important; }
  .product__stage img { transition: none; }
  .ribbon__giant span { transform: none !important; }
}
