/*
 * MADS — composants animés : hero, étoiles de service, menu, constellation,
 * carrousel.
 *
 * Ces règles concernent des éléments rendus en light DOM par le serveur, que
 * les web components se contentent d'animer. Elles doivent donc rester
 * lisibles seules : sans JavaScript, la page reste correctement composée.
 */

/* ============================================================ hero accueil */

mads-hero {
  position: relative;
  display: block;
  min-height: var(--vh);
  overflow: hidden;
}

/* La nuée occupe tout le fond ; elle ne doit jamais intercepter un clic
   destiné à une étoile ou au texte. */
.home-hero__flow {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

.home-hero__content {
  position: relative;
  z-index: 2;
  padding: clamp(3rem, 6vh, 4.5rem) var(--gutter) 0;
  /* Le bloc de texte ne s'étale pas sous les étoiles de droite */
  max-width: min(64rem, 92%);
  pointer-events: none;
}

.home-hero__content a,
.home-hero__content button {
  pointer-events: auto;
}

.home-hero__logo {
  display: block;
  width: clamp(190px, 29.5vw, 430px);
  margin-bottom: clamp(1rem, 2.4vh, 1.75rem);
  color: var(--c-ink);
}

.home-hero__logo svg {
  width: 100%;
  height: auto;
  fill: currentColor;
}

.home-hero__intro {
  max-width: 46ch;
  font-family: var(--f-title);
  font-size: var(--t-lead);
  font-weight: 300;
  line-height: 1.34;
}

/* ------------------------------------------------------- étoiles services */

.hero-stars {
  position: absolute;
  inset: 0;
  z-index: 3;
  /* Taille de l'étoile et corps du libellé attaché : une seule variable, dont
     découlent le recentrage sur l'ancre et l'échelle du texte. */
  --hero-star-size: clamp(28px, 2.15vw, 34px);
  /* La liste ne couvre pas la page : seules les étoiles sont cliquables */
  pointer-events: none;
}

.hero-star {
  position: absolute;
  left: var(--x);
  top: var(--y);
  /* La dérive est écrite par le composant ; au repos elle vaut zéro, donc la
     composition à l'arrêt est exactement celle de la maquette. */
  transform: translate(var(--dx, 0px), var(--dy, 0px));
  pointer-events: auto;
}

.hero-star__link {
  display: flex;
  align-items: flex-start;
  gap: 1rem;
  /* L'icône est centrée sur le point d'ancrage : on remonte le lien d'une
     demi-hauteur d'icône et on le décale d'une demi-largeur. La valeur suit
     donc --hero-star-size, elle n'est pas à recalculer à la main. */
  transform: translate(calc(var(--hero-star-size) / -2), calc(var(--hero-star-size) / -2));
  padding: 0.35rem 0.5rem 0.35rem 0;
  color: var(--c-ink);
}

.hero-star__icon {
  flex: none;
  width: var(--hero-star-size);
  height: var(--hero-star-size);
  transition: transform var(--d-base) var(--e-out);
}

.hero-star__icon svg {
  width: 100%;
  height: 100%;
  fill: currentColor;
}

.hero-star:hover .hero-star__icon,
.hero-star:focus-within .hero-star__icon {
  transform: rotate(90deg) scale(1.12);
}

.hero-star__text {
  display: block;
  padding-top: 2px;
  font-family: var(--f-title);
  font-size: clamp(1.15rem, 1.45vw, 1.45rem);
  font-weight: 300;
  line-height: 1.28;
  white-space: nowrap;
}

.star-label__line {
  display: block;
}

.star-label__char {
  display: inline-block;
  white-space: pre;
}

/* Révélation lettre par lettre, de gauche à droite.
   Ces règles ne s'appliquent qu'une fois le composant initialisé : sans JS,
   `is-ready` n'est jamais posé et tous les libellés restent visibles. */
mads-hero.is-ready .star-label__char {
  clip-path: inset(0 100% 0 0);
  transition: clip-path 260ms var(--e-out);
  transition-delay: 0ms;
}

mads-hero.is-ready .hero-star[data-revealed] .star-label__char {
  clip-path: inset(0 -0.15em 0 0);
  /* Le retard croît avec l'index de la lettre : le mot se dévoile de la
     gauche vers la droite au lieu d'apparaître d'un bloc. */
  transition-delay: calc(var(--i) * 18ms);
}

/* Sans survol possible (tactile), les libellés restent affichés : sinon les
   services deviendraient inaccessibles au doigt. */
@media (hover: none) {
  mads-hero.is-ready .star-label__char {
    clip-path: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  mads-hero.is-ready .star-label__char {
    transition-duration: 1ms;
    transition-delay: 0ms;
  }
}

/* Les étoiles du hero sont absentes de la maquette mobile : le hero y est un
   simple bloc logo + texte, et les services restent joignables par le menu. */
@media (max-width: 900px) {
  mads-hero {
    min-height: 0;
  }

  .hero-stars {
    display: none;
  }

  .home-hero__content {
    padding-block: clamp(4.5rem, 16vw, 6rem) clamp(3rem, 12vw, 4rem);
    max-width: none;
  }

  .home-hero__logo {
    width: min(56vw, 260px);
  }
}

/* ------------------------------------------------ incitation au défilement */

/* Unique sur la page, en bas du hero : une flèche pivotée d'un quart de tour
   qui descend et remonte lentement. */
.hero-scroll {
  position: absolute;
  left: 50%;
  bottom: clamp(1.5rem, 4vh, 2.75rem);
  z-index: 4;
  display: grid;
  place-items: center;
  width: 64px;
  height: 64px;
  margin-left: -32px;
  color: var(--c-ink);
  opacity: 0.55;
  transition: opacity var(--d-fast) var(--e-out);
}

.hero-scroll:hover,
.hero-scroll:focus-visible {
  opacity: 1;
}

.hero-scroll__arrow {
  display: block;
  width: 26px;
  /* arrow-right.svg pivotée : une seule icône sert dans les deux directions */
  transform: rotate(90deg);
  animation: hero-scroll-bob 2.4s var(--e-out) infinite;
}

.hero-scroll__arrow svg {
  display: block;
  width: 100%;
  height: auto;
  fill: currentColor;
}

@keyframes hero-scroll-bob {
  0%, 100% { transform: rotate(90deg) translateX(0); }
  50%      { transform: rotate(90deg) translateX(10px); }
}

/* Le hero mobile ne fait pas la hauteur de l'écran : la flèche n'y aurait
   rien à annoncer. */
@media (max-width: 900px) {
  .hero-scroll {
    display: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .hero-scroll__arrow {
    animation: none;
  }
}

/* ================================================================= menu */

/* Le contenu du menu est en light DOM (projeté dans un <slot>) : il est donc
   stylé ici, et non dans le shadow DOM du composant. */
.menu-nav {
  display: flex;
  flex-direction: column;
  gap: clamp(0.35rem, 1vh, 0.75rem);
}

.menu-nav a {
  display: inline-block;
  width: fit-content;
  font-family: var(--f-title);
  font-size: clamp(1.75rem, 2.4vw, 2.25rem);
  font-weight: 300;
  line-height: 1.28;
  color: var(--c-panel-ink);
  opacity: 0.92;
  transition:
    opacity var(--d-fast) var(--e-out),
    transform var(--d-fast) var(--e-out);
}

.menu-nav a:hover,
.menu-nav a:focus-visible {
  opacity: 1;
  transform: translateX(0.35rem);
}

/* Page courante : discrètement soulignée plutôt que grisée, pour rester
   cliquable et lisible. */
.menu-nav a[aria-current='page'] {
  text-decoration: underline;
  text-underline-offset: 0.2em;
  text-decoration-thickness: 1px;
}

.menu-foot {
  margin-top: clamp(2rem, 6vh, 3.5rem);
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  font-size: var(--t-body);
  color: var(--c-panel-ink);
  opacity: 0.72;
}

.menu-foot a:hover {
  text-decoration: underline;
  text-underline-offset: 0.22em;
}

/* ========================================================= constellation */

/* Tous les enfants du bandeau sont en position absolue : sa hauteur de contenu
   vaut donc zéro, et sans hauteur imposée il ne s'affichait rien du tout — ni
   nuée, ni étoiles, ni liaisons, juste le fond crème de la section.
   `min-height: inherit` lui fait reprendre celle de .case-constellation, sans
   avoir à répéter la valeur des deux côtés. */
mads-mini-hero {
  position: relative;
  display: block;
  min-height: inherit;
  overflow: hidden;
}

.constellation__flow {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

/* Les liaisons passent sous les étoiles mais au-dessus de la nuée */
.constellation__lines {
  position: absolute;
  inset: 0;
  z-index: 2;
  width: 100%;
  height: 100%;
  color: var(--c-ink);
  opacity: 0.55;
  pointer-events: none;
}

.constellation__stars {
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
}

.constellation__star {
  position: absolute;
  left: var(--x);
  top: var(--y);
  transform: translate(var(--dx, 0px), var(--dy, 0px));
  pointer-events: auto;
}

/* Le projet courant n'est pas un lien mais un <span> : les deux partagent
   la même géométrie. */
.constellation__star > a,
.constellation__star > span {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  transform: translate(-9px, -50%);
  padding: 0.35rem 0.5rem 0.35rem 0;
  color: var(--c-ink);
}

.constellation__star .icon {
  flex: none;
  width: 18px;
  height: 18px;
  transition: transform var(--d-base) var(--e-out);
}

.constellation__star .icon svg {
  width: 100%;
  height: 100%;
  fill: currentColor;
}

.constellation__star a:hover .icon,
.constellation__star a:focus-visible .icon {
  transform: rotate(90deg) scale(1.15);
}

.constellation__star .star-label {
  font-family: var(--f-title);
  font-size: clamp(1.1rem, 1.35vw, 1.35rem);
  font-weight: 300;
  line-height: 1.3;
  white-space: nowrap;
}

/* Le projet consulté est marqué mais non cliquable : il est déjà à l'écran.
   Curseur par défaut et sélection bloquée — rien n'y invite au clic, il ne
   faut pas non plus qu'un glissement de souris le surligne comme du texte. */
.constellation__star[data-current] > span {
  cursor: default;
  user-select: none;
}

.constellation__star[data-current] .star-label {
  font-weight: 500;
  text-decoration: underline;
  text-underline-offset: 0.24em;
  text-decoration-thickness: 1px;
}

/* Cascade au premier passage dans le champ (voir _observeReveal) */
mads-mini-hero .star-label__char {
  clip-path: inset(0 100% 0 0);
}

mads-mini-hero.is-revealed .star-label__char {
  clip-path: inset(0 -0.15em 0 0);
  transition: clip-path 320ms var(--e-out);
  transition-delay: calc(var(--i) * 22ms);
}

/* Sans JS, le découpage n'a pas lieu : rien n'est masqué. Avec JS mais
   mouvement réduit, on affiche sans cascade. */
@media (prefers-reduced-motion: reduce) {
  mads-mini-hero .star-label__char {
    clip-path: none;
  }
}

@media (max-width: 700px) {
  .constellation__star .star-label {
    font-size: 1.0625rem;
  }
}

/* ============================================================ carrousel */

mads-carousel {
  position: relative;
  display: block;
}

.carousel__viewport {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 100%;
  overflow-x: auto;
  /* Explicite, et non laissé au calcul du navigateur : dès qu'un axe cesse
     d'être `visible`, l'autre ne peut plus l'être non plus et bascule sur
     `auto`. Le moindre pixel de dépassement — un arrondi de hauteur suffit —
     rendait alors le carrousel défilable verticalement, ce qui n'a aucun sens
     pour une bande d'images qui se parcourt horizontalement. */
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  /* Sans JS, le carrousel reste une bande défilable au doigt */
  overscroll-behavior-x: contain;
}

.carousel__viewport::-webkit-scrollbar {
  display: none;
}

.carousel__slide {
  scroll-snap-align: start;
}

.carousel__slide mads-picture {
  width: 100%;
  aspect-ratio: 4 / 5;
}

.carousel__controls {
  display: flex;
  align-items: center;
  gap: 1.15rem;
  margin-bottom: 0.9rem;
}

/* Les flèches sont au-dessus du visuel, alignées à gauche (maquette cas
   client). Elles restent dans le flux pour ne pas masquer l'image. */
.carousel__btn {
  display: grid;
  place-items: center;
  width: 22px;
  height: 22px;
  color: var(--c-ink);
  transition: opacity var(--d-fast) ease, transform var(--d-fast) var(--e-out);
}

.carousel__btn svg {
  width: 12px;
  height: auto;
  fill: currentColor;
}

.carousel__btn:hover:not(:disabled) {
  transform: scale(1.15);
}

.carousel__btn:disabled {
  opacity: 0.25;
  cursor: default;
}

.carousel__count {
  font-size: var(--t-tiny);
  color: var(--c-ink-soft);
  font-variant-numeric: tabular-nums;
}

@media (max-width: 900px) {
  .carousel__slide mads-picture {
    aspect-ratio: 3 / 2;
  }

  /* Sur mobile, l'image du cas client est pleine largeur et les commandes
     passent sous elle pour ne pas surcharger le haut de page. */
  .carousel__controls {
    margin: 0.75rem 0 0;
    padding-inline: var(--gutter);
  }

  mads-carousel {
    display: flex;
    flex-direction: column;
  }

  .carousel__controls {
    order: 2;
  }
}
