/* ==========================================================================
   HUNGRY JAZZ — COMPOSANTS
   Formes : rectangles, arêtes vives, aucun radius, aucune ombre (brief 3.5)
   ========================================================================== */

/* ==========================================================================
   BOUTONS  —  D-02 : primaire = encre sur papier, inversé sur fond sombre
   ========================================================================== */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2xs);
  min-height: var(--tap-min);
  padding: var(--sp-2xs) var(--sp-s);
  border-radius: var(--radius);
  font-family: var(--f-display);
  font-size: var(--fs-label);
  font-weight: var(--fw-bold);
  letter-spacing: var(--ls-nav);
  text-transform: uppercase;
  text-align: center;
  transition: background-color var(--t-base) var(--ease),
              color var(--t-base) var(--ease),
              transform var(--t-fast) var(--ease);
}

.btn__arrow {
  display: inline-block;
  transition: transform var(--t-base) var(--ease);
}
.btn:hover .btn__arrow,
.btn:focus-visible .btn__arrow { transform: translateX(.35em); }

/* Primaire : aplat noir, texte blanc */
.btn--primary {
  background: var(--c-ink);
  color: var(--c-paper);
  border: var(--bd-rule) solid var(--c-ink);
}
.btn--primary:hover,
.btn--primary:focus-visible { background: transparent; color: var(--c-ink); }

/* Secondaire : contour */
.btn--ghost {
  background: transparent;
  color: currentColor;
  border: var(--bd-rule) solid currentColor;
}
.btn--ghost:hover,
.btn--ghost:focus-visible { background: var(--c-ink); color: var(--c-paper); }

/* Sur fond sombre, le primaire s inverse : aplat blanc, texte noir */
.chapter--ink .btn--primary,
.hero .btn--primary,
.drawer .btn--primary {
  background: var(--c-paper);
  color: var(--c-ink);
  border-color: var(--c-paper);
}
.chapter--ink .btn--primary:hover,
.chapter--ink .btn--primary:focus-visible,
.hero .btn--primary:hover,
.hero .btn--primary:focus-visible,
.drawer .btn--primary:hover,
.drawer .btn--primary:focus-visible {
  background: transparent;
  color: var(--c-paper);
}

.chapter--ink .btn--ghost:hover,
.chapter--ink .btn--ghost:focus-visible,
.hero .btn--ghost:hover,
.hero .btn--ghost:focus-visible {
  background: var(--c-paper);
  color: var(--c-ink);
}

/* Lien éditorial avec flèche */
.link-arrow {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-3xs);
  font-family: var(--f-cond);
  font-size: var(--fs-label);
  font-weight: var(--fw-bold);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  padding-block: var(--sp-3xs);
  border-bottom: var(--bd-rule) solid currentColor;
}
.link-arrow span { transition: transform var(--t-base) var(--ease); }
.link-arrow:hover span,
.link-arrow:focus-visible span { transform: translateX(.35em); }

/* ==========================================================================
   PLACEHOLDERS — sobres, explicitement remplaçables, jamais du faux contenu
   ========================================================================== */
.ph {
  position: relative;
  display: grid;
  place-items: center;
  background: transparent;
  border: var(--bd-hair) solid var(--c-rule-soft);
  color: var(--c-on-paper-muted);
  text-align: center;
  padding: var(--sp-s);
}
.chapter--ink .ph { border-color: var(--c-rule-soft-inv); color: var(--c-on-ink-muted); }

.ph__text {
  font-family: var(--f-cond);
  font-size: var(--fs-micro);
  font-weight: var(--fw-bold);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
}

.ph--portrait { aspect-ratio: 3 / 4; }
.ph--wide     { aspect-ratio: 16 / 10; }

/* Note « information non fournie » — visible, jamais inventée */
.pending {
  font-family: var(--f-cond);
  font-size: var(--fs-micro);
  font-weight: var(--fw-bold);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  opacity: .6;
  border-left: var(--bd-rule) solid currentColor;
  padding-left: var(--sp-3xs);
}

/* ==========================================================================
   01 — HERO  (brief 5 : non négociable, plein premier écran)
   ========================================================================== */
.hero {
  position: relative;
  /* Repli pour les navigateurs sans svh, puis la valeur correcte. */
  min-height: 100vh;
  min-height: 100svh;
  display: grid;
  grid-template-rows: var(--header-h) 1fr auto;
  background: var(--c-ink-surface);
  color: var(--c-on-ink);
  overflow: hidden;
  isolation: isolate;
}

/* ---- Média plein cadre ---- */
.hero__media {
  position: absolute;
  inset: 0;
  z-index: -1;
  background-color: #000;
  /* Damier volontairement à la limite du perceptible : rappel de la texture du
     logo, sans imiter le damier « image manquante » d un éditeur graphique.
     Sert de placeholder tant que la vidéo réelle n est pas fournie. */
  background-image: repeating-conic-gradient(#070707 0% 25%, #000 0% 50%);
  background-size: clamp(64px, 9vw, 128px) clamp(64px, 9vw, 128px);
}

.hero__video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* D-05 : cohérent avec la photographie N&B du brief 3.6 */
  filter: grayscale(1) contrast(1.06);
}

/* Étiquette du placeholder — disparaît dès qu une vidéo est lue */
.hero__media-label {
  position: absolute;
  inset-block-end: var(--sp-m);
  inset-inline-start: 50%;
  transform: translateX(-50%);
  color: rgba(255, 255, 255, .34);
  pointer-events: none;
}
.hero.has-video .hero__media-label { display: none; }

/* Ancrage du contraste : aplat franc sous le bloc typographique plutôt qu un
   voile dégradé sur toute l image (le voile générique est le rendu « IA »
   que le brief interdit). */
.hero__scrim {
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    linear-gradient(
      100deg,
      rgba(0, 0, 0, .88) 0%,
      rgba(0, 0, 0, .72) 38%,
      rgba(0, 0, 0, .22) 68%,
      rgba(0, 0, 0, .42) 100%
    );
}

/* En portrait, seule une bande étroite de la vidéo reste visible (26 % de sa
   largeur mesurés en 375 px) et la composition devient verticale : un voile
   horizontal n'a plus de sens. On passe donc à un dégradé vertical, un peu
   plus soutenu, qui garantit la lisibilité quelle que soit l'image. */
@media (max-width: 63.999em) {
  .hero__scrim {
    /* Valeurs calées par mesure, image par image, sur toute la durée.
       Avec le cadrage paysage recadré à 26 % :
         .60/.66/.86 → 3,24:1   .70/.76/.90 → 4,22:1   .74/.80/.92 → 4,80:1
       Depuis le passage au cadrage portrait, l'image visible n'est plus la même :
         .74/.80/.92 → 4,52:1  (au seuil, marge trop mince)
         .78/.82/.92 → mesure finale ci-dessous
       Le haut du dégradé porte l'essentiel de la correction : c'est là que se
       trouvent le surtitre H1 et le début de l'accroche. */
    background:
      linear-gradient(
        to bottom,
        rgba(0, 0, 0, .78) 0%,
        rgba(0, 0, 0, .82) 50%,
        rgba(0, 0, 0, .92) 100%
      );
  }
}

/* ---- Contenu ---- */
.hero__inner {
  grid-row: 2;
  display: flex;
  align-items: center;
  padding-block: var(--sp-s);
}

.hero__content { width: 100%; }

/* Filet orange : D-04, unique accent coloré du premier écran */
.hero__accent {
  display: block;
  width: clamp(48px, 6vw, 88px);
  height: var(--bd-block);
  background: var(--c-afro);
  margin-bottom: var(--sp-s);
}

/* H1 réel, premier dans le DOM, visible : ni masqué, ni remplacé (brief 5) */
.hero__h1 {
  font-family: var(--f-cond);
  font-size: var(--fs-label);
  font-weight: var(--fw-bold);
  line-height: var(--lh-label);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--c-on-ink);
  max-width: 34ch;
  margin-bottom: var(--sp-s);
}

/* Sur petit écran le surtitre H1 gagne un cran : le brief §26 en fait une
   priorité mobile. On reste sous l'accroche artistique pour ne pas lui faire
   concurrence. Règle placée APRÈS la déclaration de base — sinon, à
   spécificité égale, c'est cette dernière qui l'emporte. */
@media (max-width: 63.999em) {
  .hero__h1 { font-size: clamp(0.9375rem, 3.7vw, 1.0625rem); }
}

/* Statement artistique : dominant visuellement, jamais à la place du H1 */
.hero__statement {
  font-family: var(--f-display);
  font-weight: var(--fw-black);
  font-size: var(--fs-hero);
  line-height: var(--lh-display);
  letter-spacing: var(--ls-display);
  text-transform: uppercase;
  margin-bottom: var(--sp-m);
}

.hero__statement span { display: block; }
/* Composition en escalier : asymétrie assumée, pas de centrage mou */
.hero__statement span:nth-child(2) { margin-inline-start: clamp(.75rem, 7vw, 8rem); }
.hero__statement span:nth-child(3) { margin-inline-start: clamp(1.5rem, 15vw, 17rem); }

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-s);
}

/* ---- Barre basse : scroll + contrôle vidéo ---- */
.hero__bar {
  grid-row: 3;
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--sp-s);
  padding-block-end: var(--sp-s);
  color: var(--c-on-ink-muted);
}

.hero__scroll {
  display: flex;
  align-items: center;
  gap: var(--sp-2xs);
}
.hero__scroll::before {
  content: "";
  width: var(--bd-hair);
  height: clamp(28px, 4vw, 48px);
  background: currentColor;
  transform-origin: top;
  animation: hj-scroll 2.4s var(--ease) infinite;
}
@keyframes hj-scroll {
  0%, 100% { transform: scaleY(.35); opacity: .4; }
  50%      { transform: scaleY(1);   opacity: 1; }
}

/* Contrôle pause : requis pour tout contenu animé de plus de 5 s (WCAG 2.2.2).
   Masqué tant qu aucune vidéo ne joue réellement. */
.hero__pause {
  min-height: var(--tap-min);
  padding-inline: var(--sp-2xs);
  font-family: var(--f-cond);
  font-size: var(--fs-micro);
  font-weight: var(--fw-bold);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--c-on-ink);
  border-bottom: var(--bd-hair) solid currentColor;
}
.hero__pause[hidden] { display: none; }

/* ==========================================================================
   02 — INTRO ÉDITORIALE
   ========================================================================== */
.intro__lead {
  font-size: var(--fs-lead);
  line-height: 1.4;
  font-weight: var(--fw-medium);
  max-width: 30ch;
  margin-bottom: var(--sp-m);
}

.intro__body { max-width: var(--container-text); }
.intro__body p + p { margin-top: var(--sp-s); }

.intro__grid { display: grid; gap: var(--sp-l); }
@media (min-width: 64em) {
  .intro__grid { grid-template-columns: 5fr 6fr; gap: var(--sp-xl); align-items: start; }
  .intro__lead { margin-bottom: 0; }
}

/* ==========================================================================
   03 — UNIVERS / COURS
   Sections pleine largeur en aplat de couleur. Chaque univers occupe son
   propre chapitre : la couleur devient le repère de navigation, pas une
   décoration. Composition alternée gauche/droite pour l'asymétrie.
   ========================================================================== */

.uni {
  background: var(--c-accent);
  color: var(--c-on-color);          /* noir — contrastes mesurés, D-09 */
  padding-block: var(--sp-chapter);
  overflow: hidden;
}

.uni__inner {
  display: grid;
  gap: var(--sp-l);
}

@media (min-width: 64em) {
  .uni__inner {
    grid-template-columns: 6fr 5fr;
    gap: var(--sp-xl);
    align-items: start;
  }
  /* Alternance : le second univers inverse la composition */
  .uni--alt .uni__head { grid-column: 2; grid-row: 1; }
  .uni--alt .uni__body { grid-column: 1; grid-row: 1; }
}

.uni__kicker {
  font-family: var(--f-cond);
  font-size: var(--fs-micro);
  font-weight: var(--fw-bold);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  margin-bottom: var(--sp-s);
  /* Opacité portée de .72 à .88 : sur l'aplat bleu #4080C0, du noir à 72 %
     ne mesurait que 3,84:1, sous le seuil AA de 4,5:1 pour du texte normal.
     À 88 % la mesure passe à 4,64:1 (orange 5,26:1, lavande et rose au-delà).
     Le bleu est le cas contraignant : il impose au moins .85.
     Correction d'accessibilité uniquement — aucune couleur, aucun token et
     aucune règle de mise en page ne changent. Voir docs/DECISIONS.md D-82. */
  opacity: .88;
}

.uni__title {
  font-family: var(--f-display);
  font-weight: var(--fw-black);
  font-size: clamp(3rem, 9.5vw, 9rem);
  line-height: .86;
  letter-spacing: var(--ls-display);
  text-transform: uppercase;
}

/* Le titre reste visible pendant que la colonne de droite défile :
   effet « affiche épinglée », sans aucun JS. */
@media (min-width: 64em) {
  .uni__head { position: sticky; top: calc(var(--header-h-compact) + var(--sp-m)); }
}

.uni__text {
  font-size: var(--fs-lead);
  line-height: 1.35;
  font-weight: var(--fw-medium);
  max-width: 34ch;
  margin-bottom: var(--sp-m);
}

/* ---- Liste de cours : lignes pleine largeur, sans carte ---------------- */
.uni__list {
  border-top: var(--bd-rule) solid currentColor;
  margin-bottom: var(--sp-m);
}

.uni__item {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: baseline;
  gap: var(--sp-3xs) var(--sp-s);
  padding-block: var(--sp-s);
  border-bottom: var(--bd-hair) solid rgba(0, 0, 0, .32);
}

.uni__item-name {
  font-family: var(--f-display);
  font-size: clamp(1.25rem, 2vw, 1.75rem);
  font-weight: var(--fw-bold);
  letter-spacing: -.01em;
}

.uni__item-meta,
.uni__item-dur {
  font-family: var(--f-cond);
  font-size: var(--fs-label);
  font-weight: var(--fw-bold);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  opacity: .78;
}

.uni__item-meta { grid-column: 1; }
.uni__item-dur  { grid-column: 2; grid-row: 1; }

/* ---- Stardust : dégradé bicolore et mention de sélection en typographie,
        sans aucune pastille (les pastilles font UI générique) ------------- */
.uni--stardust {
  background: linear-gradient(104deg,
    var(--c-stardust) 0%,
    var(--c-stardust) 46%,
    var(--c-stardust-alt) 46%,
    var(--c-stardust-alt) 100%);
}

.uni__note {
  font-family: var(--f-cond);
  font-size: var(--fs-label);
  font-weight: var(--fw-bold);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  border-top: var(--bd-rule) solid currentColor;
  padding-top: var(--sp-2xs);
  margin-bottom: var(--sp-m);
}

/* Bouton posé sur un aplat de couleur : bloc noir, texte blanc. */
.uni .btn--primary {
  background: var(--c-ink);
  color: var(--c-paper);
  border-color: var(--c-ink);
}
.uni .btn--primary:hover,
.uni .btn--primary:focus-visible {
  background: transparent;
  color: var(--c-ink);
}


/* ==========================================================================
   04 — PLANNING  (brief 12 : composant piloté par les données)
   ========================================================================== */

/* Sélecteur de jours — généré, jamais écrit en dur (D-12) */
.schedule__days {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-3xs);
  margin-bottom: var(--sp-l);
}

.day {
  min-width: var(--tap-min);
  min-height: var(--tap-min);
  padding-inline: var(--sp-2xs);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--f-cond);
  font-size: var(--fs-label);
  font-weight: var(--fw-bold);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--c-on-ink);
  border: var(--bd-hair) solid var(--c-rule-soft-inv);
  transition: background-color var(--t-fast) var(--ease),
              color var(--t-fast) var(--ease),
              border-color var(--t-fast) var(--ease);
}
/* Ciblé sur `button` : le libellé du jour unique n'est pas une commande,
   il ne doit pas réagir au survol. */
button.day:hover { border-color: var(--c-on-ink); }

/* L état actif ne repose pas que sur la couleur : le fond s inverse
   et aria-pressed porte l information (brief 25). */
.day[aria-pressed="true"] {
  background: var(--c-paper);
  color: var(--c-ink);
  border-color: var(--c-paper);
}

/* Jour unique : même pastille que l'onglet actif, mais ce n'est pas un
   bouton — il n'y a rien à choisir. Le nom est écrit en entier, la place
   ne manque pas. Les jours sans séance ne sont plus rendus du tout : la
   règle qui les grisâit n'avait plus de cible. */
.day--seul {
  background: var(--c-paper);
  color: var(--c-ink);
  border-color: var(--c-paper);
  padding-inline: var(--sp-s);
  cursor: default;
}

/* ---- Liste de créneaux ---- */
.schedule__list { border-top: var(--bd-hair) solid var(--c-rule-soft-inv); }

.slot { border-bottom: var(--bd-hair) solid var(--c-rule-soft-inv); }

.slot__h { margin: 0; font-size: inherit; font-weight: inherit; letter-spacing: normal; }

.slot__btn {
  width: 100%;
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: var(--sp-2xs) var(--sp-s);
  padding: var(--sp-s) 0;
  min-height: var(--tap-min);
  color: var(--c-on-ink);
  transition: color var(--t-fast) var(--ease);
}
@media (max-width: 47.999em) {
  .slot__btn {
    grid-template-columns: 1fr auto;
    row-gap: var(--sp-4xs);
  }
  .slot__time { grid-column: 1; }
  .slot__name { grid-column: 1; }
  .slot__meta { grid-column: 1; }
  .slot__dur  { grid-column: 1; }
  .slot__chev { grid-column: 2; grid-row: 1 / span 2; align-self: center; }
}

/* ---- Glyphe de durée : demi-cercle = 1 h, cercle plein = 1 h 30 ---------
   Même clé visuelle que le Pack 12 h. La durée reste écrite à côté :
   le glyphe ne porte jamais seul l'information. */
.slot__dur {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-3xs);
  font-family: var(--f-cond);
  font-size: var(--fs-label);
  font-weight: var(--fw-bold);
  letter-spacing: .04em;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--c-accent);
  transition: color var(--t-fast) var(--ease) 0ms;
}
.slot__dur svg { width: 15px; height: 15px; flex: none; }

/* Sur l'aplat de survol, le glyphe bascule au noir comme le texte, avec le
   même retard que lui pour ne pas disparaître pendant le balayage. */
.slot:hover .slot__dur,
.slot__btn:focus-visible .slot__dur,
.slot.is-open .slot__dur {
  color: var(--c-on-color);
  transition-delay: 340ms;
}
.slot.is-open .slot__dur { transition-delay: 0ms; }

/* ---- Légende du planning ------------------------------------------------ */
.schedule__key {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-s);
  margin-bottom: var(--sp-l);
  font-family: var(--f-cond);
  font-size: var(--fs-micro);
  font-weight: var(--fw-bold);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--c-on-ink-muted);
}
.schedule__key span { display: inline-flex; align-items: center; gap: var(--sp-3xs); }
.schedule__key svg { width: 14px; height: 14px; }

/* Bande de couleur de l univers : signal visuel, mais jamais le seul indice
   (la discipline est toujours écrite en toutes lettres). */
.slot { position: relative; }
.slot::before {
  content: "";
  position: absolute;
  inset-block: 0;
  inset-inline-start: calc(var(--gutter) * -1);
  width: var(--bd-block);
  background: var(--c-accent);
  transform: scaleY(0);
  transform-origin: center;
  transition: transform var(--t-base) var(--ease);
}
.slot:hover::before,
.slot:focus-within::before,
.slot.is-open::before { transform: scaleY(1); }

.slot__time {
  font-family: var(--f-cond);
  font-size: clamp(1.125rem, 1.7vw, 1.5rem);
  font-weight: var(--fw-bold);
  letter-spacing: .04em;
  white-space: nowrap;
}

.slot__name {
  font-family: var(--f-display);
  font-size: clamp(1.375rem, 2.4vw, 2.25rem);
  font-weight: var(--fw-black);
  line-height: 1.05;
  letter-spacing: var(--ls-display);
  text-transform: uppercase;
}

.slot__meta {
  font-family: var(--f-cond);
  font-size: var(--fs-micro);
  font-weight: var(--fw-bold);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--c-on-ink-muted);
}
@media (min-width: 48em) {
  .slot__meta { justify-self: end; text-align: right; }
  .slot__btn { grid-template-columns: auto 1fr auto auto auto; }
}

.slot__chev {
  width: 1.5rem;
  height: 1.5rem;
  position: relative;
  flex: none;
}
.slot__chev::before,
.slot__chev::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  inset-block-start: 50%;
  height: var(--bd-rule);
  background: currentColor;
  transition: transform var(--t-base) var(--ease);
}
.slot__chev::after { transform: rotate(90deg); }
.slot.is-open .slot__chev::after { transform: rotate(0deg); }

/* Dépliement sans calcul de hauteur en JS : pas de reflow, pas de CLS */
.slot__panel {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows var(--t-base) var(--ease);
}
.slot.is-open .slot__panel { grid-template-rows: 1fr; }

/* Replié, le contenu doit sortir de l ordre de tabulation : sans cela les liens
   du panneau restent focusables alors qu ils sont invisibles. */
.slot__panel-inner {
  overflow: hidden;
  min-height: 0;
  visibility: hidden;
  transition: visibility 0s linear var(--t-base);
}
.slot.is-open .slot__panel-inner { visibility: visible; transition-delay: 0s; }

.slot__detail {
  display: grid;
  gap: var(--sp-m);
  padding-block: var(--sp-2xs) var(--sp-l);
}
@media (min-width: 64em) {
  .slot__detail { grid-template-columns: 6fr 5fr; gap: var(--sp-xl); }
}

.slot__desc { max-width: 52ch; color: var(--c-on-ink); }

.slot__facts {
  display: grid;
  gap: var(--sp-3xs);
  align-content: start;
}

.slot__fact {
  display: grid;
  grid-template-columns: 8.5rem 1fr;
  gap: var(--sp-s);
  padding-block: var(--sp-4xs);
  border-bottom: var(--bd-hair) solid var(--c-rule-soft-inv);
}
.slot__fact dt {
  font-family: var(--f-cond);
  font-size: var(--fs-micro);
  font-weight: var(--fw-bold);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--c-on-ink-muted);
}
.slot__fact dd {
  font-family: var(--f-cond);
  font-size: var(--fs-label);
  font-weight: var(--fw-bold);
  letter-spacing: .04em;
  text-transform: uppercase;
  margin: 0;
}

.slot__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-s);
  margin-top: var(--sp-s);
}

/* Jour sans séance */
.schedule__empty {
  padding-block: var(--sp-l);
  text-align: center;
  color: var(--c-on-ink-muted);
}

/* ==========================================================================
   05 — TARIFS
   ========================================================================== */
.pricing { display: grid; gap: var(--grid-gap); }
@media (min-width: 64em) {
  .pricing { grid-template-columns: repeat(12, 1fr); }
  .price--unit   { grid-column: 1 / span 4; }
  .price--pack   { grid-column: 5 / span 4; }
  .price--annual { grid-column: 9 / span 4; }
}

.price {
  background: var(--c-accent, var(--c-paper));
  color: var(--c-on-color);
  padding: var(--sp-m) var(--sp-s) var(--sp-s);
  display: flex;
  flex-direction: column;
  border: var(--bd-rule) solid var(--c-ink);
}

.price--unit   { --c-accent: var(--p-blue-light); }
.price--pack   { --c-accent: var(--p-yellow); }
.price--annual { --c-accent: var(--p-green); }

.price__title {
  font-size: var(--fs-h3);
  font-weight: var(--fw-black);
  text-transform: uppercase;
  letter-spacing: var(--ls-display);
  margin-bottom: var(--sp-s);
}

.price__rows { display: grid; gap: var(--sp-3xs); margin-bottom: var(--sp-s); }

.price__row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--sp-s);
  padding-block: var(--sp-4xs);
  border-bottom: var(--bd-hair) solid rgba(0, 0, 0, .22);
}

.price__row-label {
  font-family: var(--f-cond);
  font-size: var(--fs-label);
  font-weight: var(--fw-bold);
  letter-spacing: .05em;
  text-transform: uppercase;
}

.price__row-value {
  font-family: var(--f-display);
  font-size: clamp(1.25rem, 2vw, 1.75rem);
  font-weight: var(--fw-black);
  white-space: nowrap;
}

.price__note {
  font-family: var(--f-cond);
  font-size: var(--fs-micro);
  font-weight: var(--fw-bold);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  margin-top: auto;
  padding-top: var(--sp-s);
}

/* Schéma Pack 12h : demi-cercle = 1 h, cercle plein = 1 h 30 (brief 13) */
.pack-key {
  display: grid;
  gap: var(--sp-2xs);
  margin-bottom: var(--sp-s);
}
.pack-key__row {
  display: flex;
  align-items: center;
  gap: var(--sp-2xs);
  font-family: var(--f-cond);
  font-size: var(--fs-micro);
  font-weight: var(--fw-bold);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
}
.pack-key svg { flex: none; }

/* ==========================================================================
   06 — PROFESSEURS  (Karl + Vivian uniquement — jamais Stardust)
   Deux panneaux pleine hauteur en aplat de couleur, séparés net.
   Aucune pastille : les compétences sont écrites en une ligne éditoriale.
   ========================================================================== */
.people {
  display: grid;
  grid-template-columns: 1fr;
}
@media (min-width: 64em) {
  .people { grid-template-columns: 1fr 1fr; }
}

.person {
  padding-block: var(--sp-xl);
  padding-inline: var(--gutter);
  display: flex;
  flex-direction: column;
}

/* Les panneaux sont pleine largeur : sans cela leur texte se cale sur la
   gouttière et non sur la marge du conteneur, et le décalage se creuse avec
   la largeur d'écran (236 px mesurés en 1920). Le côté extérieur reprend donc
   la marge réelle de la page, le côté intérieur garde un simple retrait. */
/* `100%` vaut ici la largeur du panneau, soit la moitié de la zone de contenu :
   la marge de page vaut donc `100% - container/2`. On part de l'élément et non
   de `100vw`, qui inclut l'ascenseur et décalait l'alignement de 7 px. */
@media (min-width: 64em) {
  .person--karl {
    padding-inline-start: max(var(--gutter), calc(100% - var(--container) / 2));
    padding-inline-end: var(--sp-l);
  }
  .person--vivian {
    padding-inline-start: var(--sp-l);
    padding-inline-end: max(var(--gutter), calc(100% - var(--container) / 2));
  }
}

.person--karl {
  background: var(--c-solo-jazz);
  color: var(--c-on-color);
}
.person--vivian {
  background: var(--c-stardust);
  color: var(--c-on-color);
}

.person__role {
  font-family: var(--f-cond);
  font-size: var(--fs-micro);
  font-weight: var(--fw-bold);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  /* Opacité portée de .72 à .88 : sur l'aplat bleu #4080C0, du noir à 72 %
     ne mesurait que 3,84:1, sous le seuil AA de 4,5:1 pour du texte normal.
     À 88 % la mesure passe à 4,64:1 (orange 5,26:1, lavande et rose au-delà).
     Le bleu est le cas contraignant : il impose au moins .85.
     Correction d'accessibilité uniquement — aucune couleur, aucun token et
     aucune règle de mise en page ne changent. Voir docs/DECISIONS.md D-82. */
  opacity: .88;
  margin-bottom: var(--sp-2xs);
}

.person__name {
  font-family: var(--f-display);
  font-size: clamp(2.25rem, 5vw, 4rem);
  font-weight: var(--fw-black);
  line-height: .92;
  letter-spacing: var(--ls-display);
  text-transform: uppercase;
  margin-bottom: var(--sp-m);
}

/* Les portraits fournis font 267 × 273 px. On borne donc leur affichage :
   étirés sur toute la largeur du panneau (~600 px), ils seraient très flous.
   À 280 px ils restent nets sur écran standard et acceptables en haute densité.
   → Des fichiers plus définis restent à fournir pour la production. */
.person__media {
  margin-bottom: var(--sp-s);
  max-width: clamp(180px, 26vw, 280px);
}
.person__media img {
  width: 100%;
  height: auto;
  aspect-ratio: 267 / 273;
  object-fit: cover;
  /* Sans effet sur ces fichiers, déjà en niveaux de gris : le filtre garantit
     que toute photo couleur ajoutée plus tard respectera la DA (brief §3.6). */
  filter: grayscale(1);
}
.person .ph { border-color: rgba(0, 0, 0, .28); color: rgba(0, 0, 0, .5); }

/* Disciplines : une ligne de texte, pas une rangée de pastilles. */
.person__disciplines {
  font-family: var(--f-cond);
  font-size: var(--fs-label);
  font-weight: var(--fw-bold);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  border-top: var(--bd-rule) solid currentColor;
  border-bottom: var(--bd-hair) solid rgba(0, 0, 0, .3);
  padding-block: var(--sp-2xs);
  margin-bottom: var(--sp-s);
}

.person__bio { max-width: 48ch; }
.person__bio p + p { margin-top: var(--sp-2xs); }

.person__links { margin-top: auto; padding-top: var(--sp-m); }

/* ==========================================================================
   08 — FAQ  (même motif de dépliement que le planning)
   ========================================================================== */
.faq { border-top: var(--bd-hair) solid var(--c-rule-soft); }

.faq__item { border-bottom: var(--bd-hair) solid var(--c-rule-soft); }

.faq__q { margin: 0; font-size: inherit; }

.faq__btn {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-s);
  padding: var(--sp-s) 0;
  min-height: var(--tap-min);
  font-family: var(--f-display);
  font-size: clamp(1.125rem, 1.9vw, 1.625rem);
  font-weight: var(--fw-bold);
  line-height: 1.2;
  text-align: left;
}

.faq__panel {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows var(--t-base) var(--ease);
}
.faq__item.is-open .faq__panel { grid-template-rows: 1fr; }
.faq__panel-inner {
  overflow: hidden;
  min-height: 0;
  visibility: hidden;
  transition: visibility 0s linear var(--t-base);
}
.faq__item.is-open .faq__panel-inner { visibility: visible; transition-delay: 0s; }
.faq__panel-inner > div { padding-bottom: var(--sp-m); max-width: 60ch; }
.faq__panel-inner p + p { margin-top: var(--sp-2xs); }
.faq__item.is-open .slot__chev::after { transform: rotate(0deg); }

/* ==========================================================================
   09 — ACTUALITÉS
   ========================================================================== */
.news {
  display: grid;
  gap: var(--sp-xl);                 /* empilées en mobile : vrai intervalle */
}

@media (min-width: 48em) {
  .news {
    grid-template-columns: repeat(3, 1fr);
    column-gap: var(--grid-gap);
    row-gap: 0;                      /* l'espacement interne est géré aux marges */
  }
}

/* Alignement des cartes entre elles.
   Sans cela, un titre qui passe sur deux lignes décale l'accroche de ses
   voisines. `subgrid` fait partager les mêmes rangées à toutes les cartes :
   visuel, date, titre et accroche s'alignent quelle que soit la longueur du
   texte. Sans support de subgrid, on retombe simplement sur l'empilement
   naturel — la page reste correcte, seulement moins réglée. */
@supports (grid-template-rows: subgrid) {
  @media (min-width: 48em) {
    .news { grid-template-rows: auto auto auto auto; }
    .news__item,
    .news__link {
      grid-row: span 4;
      display: grid;
      grid-template-rows: subgrid;
    }
  }
}

.news__link { color: inherit; }

/* La date était collée au visuel : on lui donne de l'air. */
.news__media { margin-bottom: var(--sp-m); }
.news__media img {
  width: 100%;
  aspect-ratio: 16 / 10;
  object-fit: cover;
  filter: grayscale(1);
}

.news__meta {
  font-family: var(--f-cond);
  font-size: var(--fs-micro);
  font-weight: var(--fw-bold);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--c-on-paper-muted);
}

/* Le titre était à l'échelle H3 (jusqu'à 40 px) : beaucoup trop lourd pour
   une carte d'aperçu, il écrasait le reste de la section. */
.news__title {
  font-size: clamp(1.0625rem, 1.5vw, 1.375rem);
  font-weight: var(--fw-bold);
  line-height: 1.25;
  margin-top: var(--sp-2xs);
  text-wrap: pretty;
}

/* Accroche : les premières lignes de l'article, jamais un texte réécrit. */
.news__excerpt {
  margin-top: var(--sp-2xs);
  font-size: var(--fs-body);
  line-height: 1.5;
  color: var(--c-on-paper-muted);
  /* Trois lignes maximum : au-delà, les hauteurs de cartes divergeraient. */
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.news__link:hover .news__title,
.news__link:focus-visible .news__title {
  text-decoration: underline;
  text-underline-offset: .2em;
}

/* ==========================================================================
   BANDEAU CTA FINAL
   ========================================================================== */
.cta-band {
  background: var(--c-afro);
  color: var(--c-on-color);
  padding-block: var(--sp-xl);
}

.cta-band__title {
  font-size: var(--fs-h2);
  font-weight: var(--fw-black);
  text-transform: uppercase;
  letter-spacing: var(--ls-display);
  line-height: var(--lh-display);
  margin-bottom: var(--sp-m);
  max-width: 18ch;
}

.cta-band .btn--primary {
  background: var(--c-ink);
  color: var(--c-paper);
  border-color: var(--c-ink);
}
.cta-band .btn--primary:hover,
.cta-band .btn--primary:focus-visible { background: transparent; color: var(--c-ink); }

/* ==========================================================================
   RÉVÉLATION AU SCROLL — un seul IntersectionObserver, transform + opacity
   ========================================================================== */
[data-reveal] {
  transition: opacity var(--t-slow) var(--ease-out),
              transform var(--t-slow) var(--ease-out);
}

/* L état masqué n est JAMAIS posé par le CSS seul : il est « armé » par le JS,
   et uniquement sur les éléments réellement situés sous la ligne de flottaison.
   Conséquence : sans JS, en mouvement réduit, sur une ancre ou après un scroll
   rapide, aucun contenu ne peut rester invisible. */
[data-reveal].is-armed { opacity: 0; transform: translateY(14px); }

/* ==========================================================================
   COULEUR & MOUVEMENT — ajouts de l'itération 2
   ========================================================================== */


/* ---- RÉVÉLATION PAR MASQUE ----------------------------------------------
   Chaque ligne est enfermée dans un conteneur en overflow:hidden ; le texte
   remonte depuis le bas. Réservé aux titres courts (moins de 8 mots) :
   au-delà, le découpage alourdit le DOM sans bénéfice. */
.line { display: block; overflow: hidden; }
.line__in {
  display: block;
  transform: translateY(0);
  transition: transform var(--t-reveal) var(--ease-expo);
  transition-delay: calc(var(--i, 0) * var(--stagger));
}
/* Le parent ne s'estompe pas : seul le mouvement des lignes fait l'effet. */
[data-reveal="lines"].is-armed { opacity: 1; transform: none; }
[data-reveal="lines"].is-armed .line__in { transform: translateY(110%); }

/* ---- APPARITION EN CASCADE ----------------------------------------------
   Maximum ~8 enfants : au-delà, les derniers items paraissent en retard. */
[data-reveal="stagger"].is-armed { opacity: 1; transform: none; }
[data-reveal="stagger"] > * {
  transition: opacity var(--t-slow) var(--ease-power),
              transform var(--t-slow) var(--ease-power);
}
[data-reveal="stagger"].is-armed > * { opacity: 0; transform: translateY(20px); }
[data-reveal="stagger"] > *:nth-child(1) { transition-delay: calc(0 * var(--stagger-list)); }
[data-reveal="stagger"] > *:nth-child(2) { transition-delay: calc(1 * var(--stagger-list)); }
[data-reveal="stagger"] > *:nth-child(3) { transition-delay: calc(2 * var(--stagger-list)); }
[data-reveal="stagger"] > *:nth-child(4) { transition-delay: calc(3 * var(--stagger-list)); }
[data-reveal="stagger"] > *:nth-child(5) { transition-delay: calc(4 * var(--stagger-list)); }
[data-reveal="stagger"] > *:nth-child(6) { transition-delay: calc(5 * var(--stagger-list)); }
[data-reveal="stagger"] > *:nth-child(7) { transition-delay: calc(6 * var(--stagger-list)); }
[data-reveal="stagger"] > *:nth-child(8) { transition-delay: calc(7 * var(--stagger-list)); }

/* ---- PLANNING : la couleur de l'univers envahit la LIGNE ----------------
   L'aplat est porté par le bouton, pas par le créneau entier. Posé sur le
   créneau (`inset-block: 0` sur `.slot`), il recouvrait aussi le panneau
   déplié et masquait entièrement les informations du cours.
   `isolation: isolate` garde le pseudo-élément dans le bouton : il passe
   derrière le texte, jamais derrière le fond de la section. */
.slot__btn { position: relative; isolation: isolate; }
.slot__btn::before {
  content: "";
  position: absolute;
  inset-block: 0;
  inset-inline: calc(var(--gutter) * -1);
  background: var(--c-accent);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--t-slow) var(--ease-expo);
  z-index: -1;
}
/* Survol, focus clavier, et créneau ouvert : l'aplat reste alors sur la ligne
   et sert d'indicateur d'état actif. On n'utilise pas `:focus-within` sur le
   créneau : après un clic, le focus reste sur le bouton et l'aplat ne se
   retirait plus. */
.slot:hover .slot__btn::before,
.slot__btn:focus-visible::before,
.slot.is-open .slot__btn::before { transform: scaleX(1); }
/* Le texte bascule en noir sur l'aplat : contraste conservé, jamais du blanc
   sur une couleur claire (voir les contrastes mesurés, D-09).
   La bascule est retardée du temps que l'aplat mette à passer sous le texte :
   sans ce délai, le texte devient noir sur noir pendant ~300 ms. Au retour,
   aucun délai — la couleur revient immédiatement. */
.slot__btn, .slot__meta { transition: color var(--t-fast) var(--ease) 0ms; }
.slot:hover .slot__btn,
.slot__btn:focus-visible,
.slot.is-open .slot__btn {
  color: var(--c-on-color);
  transition-delay: 300ms;
}
.slot:hover .slot__meta,
.slot__btn:focus-visible .slot__meta,
.slot.is-open .slot__meta {
  color: rgba(0, 0, 0, .72);
  transition-delay: 340ms;
}
/* Un créneau déjà ouvert garde sa couleur : la bascule est donc immédiate,
   sans le retard prévu pour laisser passer l'aplat. */
.slot.is-open .slot__btn,
.slot.is-open .slot__meta { transition-delay: 0ms; }

/* ---- TARIFS : grands nombres colorés sur fond encre -------------------- */
.price--unit,
.price--annual {
  --c-accent: var(--c-ink-surface);
  background: var(--c-ink-surface);
  color: var(--c-on-ink);
  border-color: var(--c-ink-surface);
}
.price--pack {
  --c-accent: #F2F2F2;
  background: #F2F2F2;
  color: var(--c-ink);
  border-color: var(--c-ink);
}

.price--unit .price__row,
.price--annual .price__row { border-bottom-color: var(--c-rule-soft-inv); }

.price__row-value {
  font-size: clamp(2rem, 4vw, 3.25rem);
  line-height: 1;
  font-weight: var(--fw-black);
}
/* Bleu 5,07:1 et orange 5,76:1 sur noir : conformes AA en texte normal,
   et ce sont ici de très grands caractères. */
.price__row--solo .price__row-value { color: var(--c-solo-jazz); }
.price__row--afro .price__row-value { color: var(--c-afro); }

.price__sub {
  font-family: var(--f-cond);
  font-size: var(--fs-micro);
  font-weight: var(--fw-bold);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  opacity: .6;
}

/* Schéma du Pack 12 h : rangées de formes, demi-cercle = 1 h, plein = 1 h 30 */
.pack-row { display: flex; flex-wrap: wrap; gap: var(--sp-4xs); margin-bottom: var(--sp-2xs); }
.pack-row svg { flex: none; }

/* ---- Mouvement réduit : tout est neutralisé ---------------------------- */
@media (prefers-reduced-motion: reduce) {
  .line__in { transform: none !important; transition: none; }
  [data-reveal="stagger"] > * { opacity: 1 !important; transform: none !important; }
  .slot__btn::before { transition: none; }
}

/* ---- Lieu cliquable vers Google Maps ------------------------------------ */
/* 23 PX DE HAUT, SOIT UN PIXEL SOUS LE MINIMUM. WCAG 2.2 demande 24 px pour
   une cible de pointage, et ce lien tombait juste en dessous — assez pour être
   non conforme, trop peu pour se voir. Le remplissage vertical règle la cible
   sans écarter les lignes du créneau : `inline-flex` n'augmente pas la hauteur
   de ligne du bloc parent ici, la ligne du lieu étant seule sur sa ligne. */
.slot__lieu {
  display: inline-flex;
  align-items: baseline;
  gap: var(--sp-4xs);
  padding-block: 2px;
  border-bottom: var(--bd-hair) solid currentColor;
  transition: color var(--t-fast) var(--ease);
}
.slot__lieu:hover,
.slot__lieu:focus-visible { color: var(--c-accent); }
.slot__lieu-ico { font-size: .8em; transition: transform var(--t-base) var(--ease); }
.slot__lieu:hover .slot__lieu-ico,
.slot__lieu:focus-visible .slot__lieu-ico { transform: translate(.15em, -.15em); }

/* Enveloppe visuelle des titres d'univers : le titre sémantique complet est
   porté par un `.sr-only`, l'affichage stylisé est masqué aux technologies
   d'assistance. Cette enveloppe doit rester un bloc pour que les lignes
   à masque conservent leur comportement. */
.uni__title-visuel { display: block; }

/* Les conditions du Pack sur les cartes de tarifs : frais de dossier et
   validité, en une ligne sous le montant. Le prix affiché est celui du
   premier pack de la saison ; cette ligne dit ce qui change ensuite. */
.price__conditions {
  margin-block: var(--sp-3xs) var(--sp-2xs);
  /* Pleine opacité, contrairement aux autres mentions : c'est une condition
     de prix, pas une légende. */
  opacity: 1;
}
