.hero-3d{position:relative;display:flex;flex-direction:column;min-height:460px;overflow:visible;
  isolation:isolate;border:0;border-radius:0;background:transparent;
  height:clamp(460px,calc(100svh - 170px),620px);box-shadow:none}
.hero-3d__canvas{flex:1;width:100%;min-height:360px;display:block;background:transparent;
  touch-action:pan-y;cursor:grab;outline:none}
.hero-3d__canvas:active{cursor:grabbing}
.hero-3d__canvas.is-hovering-drum{cursor:pointer}
.hero-3d__canvas:focus-visible{box-shadow:inset 0 0 0 2px var(--uv)}
.hero-3d__sr-only{position:absolute!important;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0,0,0,0);clip-path:inset(50%);white-space:nowrap;border:0}
.hero-3d__layers{position:absolute;z-index:3;top:16px;right:16px;display:grid;width:min(200px,42%);gap:5px}
.hero-3d__layer{--layer-color:var(--uv);position:relative;display:grid;grid-template-columns:22px minmax(0,1fr) auto;
  min-height:38px;align-items:center;gap:7px;overflow:hidden;border:var(--hair) solid var(--hairline);
  border-radius:var(--radius);padding:7px 8px 9px;background:rgba(10,10,10,.82);color:var(--dim);
  font:600 11px/1 var(--font-mono);letter-spacing:.06em;text-transform:uppercase;cursor:pointer;
  backdrop-filter:blur(8px);
  transition:border-color .15s,color .15s,background .15s,box-shadow .15s,transform .12s,opacity .24s ease}
.hero-3d__layer[data-preset="warm"]{--layer-color:#FF7A00}
.hero-3d__layer[data-preset="cold"]{--layer-color:var(--tom)}
.hero-3d__layer[data-preset="rainbow"]{--layer-color:var(--uv)}
.hero-3d__layer:hover{border-color:var(--dim);color:var(--fg)}
.hero-3d__layer:active{transform:translateY(1px)}
.hero-3d__layer:focus-visible{outline:2px solid var(--fg);outline-offset:2px}
.hero-3d__layer:disabled{opacity:.42;cursor:wait;transform:none}
.hero-3d__layer.is-active{border-color:var(--layer-color);background:rgba(18,18,18,.94);color:var(--fg);
  box-shadow:inset 2px 0 0 var(--layer-color),0 0 16px color-mix(in srgb,var(--layer-color) 24%,transparent)}
.hero-3d__layer-index{color:var(--faint);font-weight:500}
.hero-3d__layer-name{min-width:0;overflow:hidden;text-overflow:ellipsis;text-align:left;white-space:nowrap}
.hero-3d__layer-state{color:var(--faint);font-size:11px}
.hero-3d__layer.is-active .hero-3d__layer-state{color:var(--layer-color)}
.hero-3d__layer-swatch{position:absolute;right:0;bottom:0;left:0;height:2px;opacity:.42}
.hero-3d__layer[data-preset="warm"] .hero-3d__layer-swatch{background:linear-gradient(90deg,#FF2D55,#FF453A,#FF6B35,#FF7A00,#FF9F0A,#FFD060,#FF5E3A,#D93600)}
.hero-3d__layer[data-preset="cold"] .hero-3d__layer-swatch{background:linear-gradient(90deg,#8A5CFF,#6C63FF,#3B82F6,#247CFF,#00AEEF,#00E5FF,#00D6C9,#7C3AED)}
.hero-3d__layer[data-preset="rainbow"] .hero-3d__layer-swatch{background:linear-gradient(90deg,#FF2D55,#FF7A00,#FFD60A,#B8FF00,#00FF6A,#00E5FF,#247CFF,#8A5CFF)}
.hero-3d__layer.is-active .hero-3d__layer-swatch{opacity:1}
.hero-3d__keys{position:absolute;left:16px;right:16px;bottom:74px;z-index:3;display:grid;
  grid-template-columns:repeat(8,minmax(44px,1fr));gap:6px;opacity:.72;transition:opacity .18s ease}
.hero-3d:hover .hero-3d__keys,.hero-3d:focus-within .hero-3d__keys{opacity:1}
.hero-3d__key{display:flex;min-width:0;min-height:44px;align-items:center;justify-content:center;gap:5px;
  border:var(--hair) solid var(--hairline);border-radius:var(--radius);padding:5px 4px;
  background:rgba(10,10,10,.7);color:var(--dim);font:600 11px/1 var(--font-mono);
  letter-spacing:.02em;text-transform:uppercase;white-space:nowrap;cursor:pointer;
  transition:transform .12s,color .12s,background .12s,border-color .12s,box-shadow .12s,opacity .24s ease}
/* Libellé trop long pour sa touche (« НАПОЛЬНЫЙ ТОМ 1 », « ORTA TOM 1 ») : il
   s'ellipse au lieu de déborder sur la touche voisine. */
.hero-3d__key-label{min-width:0;overflow:hidden;text-overflow:ellipsis}
.hero-3d__key-shortcut{display:grid;flex:0 0 19px;width:19px;height:19px;place-items:center;
  border:var(--hair) solid currentColor;border-radius:1px;color:var(--fg);font-size:11px}
.hero-3d__key[data-zone="kick"]{--active-color:var(--kick)}
.hero-3d__key[data-zone="snare"]{--active-color:var(--snare)}
.hero-3d__key[data-zone="tom"]{--active-color:var(--tom)}
.hero-3d__key[data-zone="tomBass"]{--active-color:var(--tom-bass)}
.hero-3d__key:hover{color:var(--fg);border-color:var(--dim)}
.hero-3d__key:disabled{opacity:.42;cursor:wait;transform:none;box-shadow:none}
.hero-3d__key:focus-visible{outline:2px solid var(--uv);outline-offset:2px;color:var(--fg)}
.hero-3d__key:active{transform:translateY(2px) scale(.97)}
.hero-3d__key.is-active{color:#0A0A0A;background:var(--active-color,#F4F4F0);
  border-color:#F4F4F0;box-shadow:0 0 0 2px #0A0A0A,0 0 18px var(--active-color,#F4F4F0);
  transform:translateY(2px) scale(.97)}
.hero-3d__key.is-active .hero-3d__key-shortcut{color:#0A0A0A}
.hero-3d__viz{position:relative;height:58px;border-top:0;opacity:.72}
.hero-3d__viz canvas{display:block;width:100%;height:100%}
.hero-3d__legend{position:absolute;right:16px;bottom:16px;z-index:3;margin:0;color:var(--faint);
  font:11px/1 var(--font-mono);letter-spacing:.1em;text-transform:uppercase}
/* Légende longue (de, ru, tr…) : elle ne dépasse plus la moitié droite du visuel,
   moins la demi-largeur du bouton son centré (≤ 42 px) et un écart — avant, elle
   glissait sous ce bouton. Au-delà, elle passe à la ligne, et la seconde ligne
   descend sous le pointillé au lieu de remonter dessus : la légende est ancrée
   par le HAUT. top = bas d'origine (16 px) + une ligne de 1em + la demi-interligne
   (3 px) ajoutée par line-height 1em + 6px — demi-interligne entière, sinon
   l'arrondi décale le texte d'un pixel : la première ligne reste au pixel près
   là où elle était. La légende française (300 px à 1440) tient sur une ligne. */
.hero-3d__legend{top:calc(100% - 16px - 1em - 3px);bottom:auto;max-width:calc(50% - 16px - 58px);
  line-height:calc(1em + 6px);text-align:right}
/* Coupure du son : contrôle d'accessibilité, donc visible en permanence —
   il n'est jamais atténué avec les autres overlays (voir HR-04 plus bas). */
/* Placé en bas au centre, et NON en haut à gauche : .hero__copy (z-index 2) passe
   au-dessus de .hero__visual (z-index 1), donc tout overlay du hero situé sous la
   colonne de texte est inclicable — le z-index 3 est prisonnier du contexte
   d'empilement de .hero__visual et ne peut pas en sortir. Le bas-centre est la
   seule zone atteignable à toutes les largeurs (vérifié de 1024 à 1600 px). */
.hero-3d__mute{position:absolute;z-index:3;left:50%;bottom:16px;translate:-50% 0;display:flex;min-height:36px;
  align-items:center;gap:6px;border:var(--hair) solid var(--hairline);border-radius:var(--radius);
  padding:6px 10px;background:rgba(10,10,10,.82);color:var(--dim);font:600 11px/1 var(--font-mono);
  letter-spacing:.06em;text-transform:uppercase;cursor:pointer;backdrop-filter:blur(8px);
  transition:border-color .15s,color .15s,background .15s}
.hero-3d__mute:hover{border-color:var(--dim);color:var(--fg)}
.hero-3d__mute:focus-visible{outline:2px solid var(--uv);outline-offset:2px;color:var(--fg)}
/* Activé dès le chargement du module : soit utilisable aussitôt, soit jamais
   (sans WebGL il n'y a aucun son à couper). C'est une indisponibilité, pas une
   attente — d'où not-allowed plutôt que le sablier (cf. MI-04). */
.hero-3d__mute:disabled{opacity:.42;cursor:not-allowed}
.hero-3d__mute-icon{flex:0 0 14px;width:14px;height:14px}
.hero-3d__mute-speaker{fill:currentColor}
.hero-3d__mute-wave,.hero-3d__mute-cross{fill:none;stroke:currentColor;stroke-width:1.7;stroke-linecap:round}
.hero-3d__mute-cross{opacity:0}
.hero-3d__mute[aria-pressed="true"]{color:var(--faint)}
.hero-3d__mute[aria-pressed="true"] .hero-3d__mute-wave{opacity:0}
.hero-3d__mute[aria-pressed="true"] .hero-3d__mute-cross{opacity:1}
/* Loader scopé */
.hero-3d__loader{position:absolute;inset:0;z-index:4;display:grid;place-items:center;
  background:transparent;text-align:center;transition:opacity .4s ease}
.hero-3d__loader.is-hidden{opacity:0;pointer-events:none}
.hero-3d__loader-logo{font:800 20px var(--font-display);letter-spacing:.18em;color:var(--fg)}
.hero-3d__loader-track{width:180px;height:2px;margin:14px auto 8px;background:var(--hairline);overflow:hidden}
/* scaleX plutôt que width : animer une propriété de mise en page force un
   recalcul à chaque image. La barre occupe toute sa piste et se révèle par
   transformation, qui reste sur le compositeur. */
.hero-3d__loader-bar{height:100%;width:100%;transform:scaleX(0);transform-origin:left;background:var(--uv);transition:transform .2s ease}
.hero-3d__loader-label{display:flex;justify-content:space-between;width:180px;margin:0 auto;
  color:var(--dim);font:11px var(--font-mono);letter-spacing:.1em;text-transform:uppercase}
.hero-3d__loader-error{display:none;max-width:260px;margin:12px auto 0;color:var(--dim);
  font:12px/1.5 var(--font-body)}
.hero-3d__loader.has-error .hero-3d__loader-error{display:block}
.hero-3d__loader.has-error .hero-3d__loader-track,.hero-3d__loader.has-error .hero-3d__loader-label{display:none}
/* Poster fallback : paint immédiat, no-webgl, saveData */
.hero-3d__poster{position:absolute;inset:0;z-index:2;display:grid;place-items:center;gap:14px;
  background:radial-gradient(60% 60% at 50% 42%,color-mix(in srgb,var(--uv) 14%,transparent),transparent 70%);
  transition:opacity .4s ease}
.hero-3d.is-live .hero-3d__poster{opacity:0;pointer-events:none}
.hero-3d__poster-dots{display:flex;gap:10px}
/* Les huit pastilles previsualisent les huit futs : elles reprennent donc les
   couleurs de la palette indexees sur les instruments (kick, snare, tom, tom
   basse), et non un degrade arc-en-ciel dont quatre teintes — #FF2D55, #FF7A00,
   #FFD60A, #247CFF — n existaient nulle part dans tokens.css. */
.hero-3d__poster-dots i{width:12px;height:12px;border-radius:50%;box-shadow:0 0 16px currentColor}
.hero-3d__poster-dots i[data-zone="kick"]{color:var(--kick);background:var(--kick)}
.hero-3d__poster-dots i[data-zone="snare"]{color:var(--snare);background:var(--snare)}
.hero-3d__poster-dots i[data-zone="tom"]{color:var(--tom);background:var(--tom)}
.hero-3d__poster-dots i[data-zone="tomBass"]{color:var(--tom-bass);background:var(--tom-bass)}
.hero-3d__poster-cta{display:none;padding:10px 18px;border:var(--hair) solid var(--hairline);
  border-radius:var(--radius);background:transparent;color:var(--fg);font:600 13px var(--font-mono);cursor:pointer}
.hero-3d[data-manual="true"] .hero-3d__poster-cta{display:inline-block}
.hero-3d.is-live .hero-3d__poster-cta{display:none}
/* HR-04 — au repos, presets et touches s'effacent pour dégager le canvas ; ils
   reviennent au survol du hero ou dès qu'un contrôle prend le focus clavier.
   Réservé aux appareils qui ont un vrai survol : en tactile, où le survol
   n'existe pas, les overlays restent exactement comme avant. Jamais de
   display:none ni visibility:hidden — les lecteurs d'écran les gardent toujours. */
@media (hover: hover) and (pointer: fine){
  .hero-3d__keys{opacity:1}
  .hero-3d__layer,.hero-3d__key{opacity:.34}
  .hero-3d__layer.is-active{opacity:.6}
  .hero-3d:hover .hero-3d__layer,.hero-3d:hover .hero-3d__key,
  .hero-3d:focus-within .hero-3d__layer,.hero-3d:focus-within .hero-3d__key{opacity:1}
  /* Préfixé .hero-3d pour égaler la spécificité des règles de survol ci-dessus :
     sans ça, survoler le hero pendant le chargement rallumait les boutons désactivés. */
  .hero-3d .hero-3d__layer:disabled,.hero-3d .hero-3d__key:disabled{opacity:.3}
}
@media(max-width:860px){ .hero-3d{height:auto;min-height:0} .hero-3d__canvas{min-height:360px} }
@media(max-width:560px){
  .hero-3d__canvas{min-height:320px}
  .hero-3d__layers{top:10px;right:10px;left:10px;width:auto;grid-template-columns:repeat(3,minmax(0,1fr));gap:4px}
  .hero-3d__layer{grid-template-columns:auto minmax(0,1fr);min-height:44px;gap:5px;padding:6px 7px 8px;font-size:11px}
  .hero-3d__layer-index{display:none}
  .hero-3d__layer-state{font-size:11px}
  /* En dessous de 560px la colonne de texte ne chevauche plus le visuel : on
     retrouve l'ancrage haut-gauche, sous les presets qui prennent toute la largeur.
     Il faut annuler explicitement le bottom et le translate de la règle de base. */
  /* 44 px de cible au doigt (36 avant) : le bouton Son descend sous les presets agrandis. */
  .hero-3d__mute{top:62px;bottom:auto;left:10px;translate:none;min-height:44px;padding:5px 10px}
  .hero-3d__keys{left:12px;right:12px;bottom:72px;grid-template-columns:repeat(4,minmax(44px,1fr));gap:6px}
  .hero-3d__key{font-size:11px;letter-spacing:0}
  .hero-3d__key-label{position:absolute!important;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
    clip:rect(0,0,0,0);clip-path:inset(50%);white-space:nowrap;border:0}
  .hero-3d__legend{right:12px;top:calc(100% - 15px - 1em - 3px);bottom:auto;max-width:calc(100% - 24px);font-size:11px;letter-spacing:.06em}
}
/* Téléphone et tablette étroite : presets et touches sortent du visuel. Posés en
   superposition, la rangée de touches (deux lignes de 44 px) recouvrait les toms
   basse et la grosse caisse, et le bouton Son les toms du haut. Ils passent dans
   le flux : presets + Son sur une ligne au-dessus du canvas, touches en dessous.
   Le canvas garde toute sa surface pour le modèle 3D. */
@media(max-width:860px){
  /* Le visuel déborde à droite jusqu'au bord de l'écran (.hero__visual, +gutter),
     y compris en RTL : les contrôles, eux, s'arrêtent à la gouttière, en physique. */
  .hero-3d__layers{position:relative;order:-1;inset:auto;width:auto;margin:0 calc(var(--gutter) + 52px) 8px 0;
    grid-template-columns:repeat(3,minmax(0,1fr))}
  .hero-3d__mute{top:0;bottom:auto;left:auto;right:var(--gutter);translate:none;
    min-width:44px;min-height:44px;justify-content:center;padding:5px}
  .hero-3d__mute-label{position:absolute!important;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
    clip:rect(0,0,0,0);clip-path:inset(50%);white-space:nowrap;border:0}
  .hero-3d__keys{position:relative;order:1;inset:auto;margin:8px var(--gutter) 0 0;opacity:1}
  .hero-3d__viz{order:2}
}
@media(prefers-reduced-motion:reduce){
  .hero-3d__loader,.hero-3d__poster,.hero-3d__loader-bar,.hero-3d__layer,.hero-3d__key,
  .hero-3d__keys,.hero-3d__mute{transition:none}
}
