/* ============================================================================
   Magic Sequencer — style
   Dark / synthwave / IDM. Potard central, rings concentriques, accents cyan.
   ========================================================================== */

:root {
  /* Palette */
  --bg:         #08080c;
  --bg-elev:    #12121a;
  --bg-elev-2:  #1a1a26;
  --border:     #1e1e2a;
  --text:       #e0e0f0;
  --text-dim:   #5a5a70;

  --accent:     #00f0ff;
  --accent-dim: #005a66;
  --magenta:    #ff3aa5;
  --magenta-dim:#6a1a4a;

  /* Largeurs des 2 colonnes latérales — exposées ici (pas sur #app) pour
     que le pre-master mixer modal (appended au body) puisse les lire. */
  --col-left-w:  260px;
  --col-right-w: 340px;
}

* { box-sizing: border-box; margin: 0; padding: 0; }

html, body { height: 100%; }

body {
  background:
    radial-gradient(ellipse at 50% 40%, #14141f 0%, var(--bg) 70%),
    var(--bg);
  color: var(--text);
  font-family: 'JetBrains Mono', 'Fira Code', 'Menlo', 'Consolas', monospace;
  font-size: 13px;
  letter-spacing: 0.04em;
  overflow: hidden;          /* Tout tient dans un écran — pas de scroll */
  user-select: none;
}

#app {
  display: grid;
  /* Layout 3-col pleine hauteur : kit-browser | center-col | right-rack.
     Kit-browser élargi à 260px pour accueillir le SEQ·NOTES sidebar-docked. */
  grid-template-columns: var(--col-left-w) 1fr var(--col-right-w);
  height: 100vh;             /* Fixé à un viewport */
  padding: 16px 20px;
  gap: 12px;
  /* Variables exposées pour positionner le pre-master mixer modal sans
     chevaucher la colonne LFOs (LFO drag possible pendant l'ouverture). */
  --col-left-w:  260px;
  --col-right-w: 340px;
  transition:
    grid-template-columns 280ms cubic-bezier(0.65, 0.05, 0.36, 1),
    padding-left  280ms cubic-bezier(0.65, 0.05, 0.36, 1),
    padding-right 280ms cubic-bezier(0.65, 0.05, 0.36, 1);
}
/* Quand on contracte : retarde le shrink de la colonne pour que le contenu
   slide à gauche avant que la place se referme. À l'expand, no delay → la
   colonne s'élargit immédiatement pour faire room au contenu qui glisse in. */
#app.collapsing-left {
  transition:
    grid-template-columns 460ms cubic-bezier(0.65, 0.05, 0.36, 1) 580ms,
    padding-left 460ms cubic-bezier(0.65, 0.05, 0.36, 1) 580ms;
}
/* État collapsed — la colonne gauche se réduit fortement (icon-only). */
#app.left-collapsed {
  --col-left-w: 56px;
  /* Réduit le padding-left du page-level pour que la sidebar colle
     au bord gauche → plus d'espace mort entre l'écran et la col. */
  padding-left: 0;
}
/* Collapsed à droite : FX knob big + chips FX + LFOs courbes + master VU/mixer */
#app.right-collapsed {
  --col-right-w: 88px;
  padding-right: 0;
}
/* Right collapse : rapide, sans delay → la col se ferme tout de suite et
   les FX chips se replacent à leur taille d'origine (pas de resize). */
#app.collapsing-right {
  transition:
    grid-template-columns 260ms cubic-bezier(0.65, 0.05, 0.36, 1),
    padding-right 260ms cubic-bezier(0.65, 0.05, 0.36, 1);
}

/* ============================================================
   PRE-MASTER MIXER MODAL
   ============================================================ */
.master-mixer-modal[hidden] { display: none; }
.master-mixer-modal {
  position: fixed;
  /* Couvre uniquement la zone CENTRALE — laisse les colonnes left/right
     visibles & interactives (LFO drag depuis la stack droite). */
  top: 16px;
  left: calc(20px + var(--col-left-w) + 12px);
  right: calc(20px + var(--col-right-w) + 12px);
  bottom: 16px;
  z-index: 9999;
  pointer-events: none;     /* le panel re-active pointer-events; backdrop aussi */
}
.master-mixer-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(8, 5, 14, 0.65);
  backdrop-filter: blur(4px);
  pointer-events: auto;
  animation: mm-backdrop-fade 200ms ease;
}
@keyframes mm-backdrop-fade {
  from { opacity: 0; }
  to   { opacity: 1; }
}
.master-mixer-panel {
  position: absolute;
  inset: 0;
  background: rgba(14, 10, 22, 0.96);
  border: 1px solid #6a4a8a;
  border-radius: 6px;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.6),
              0 0 24px rgba(176, 122, 208, 0.25);
  display: flex;
  flex-direction: column;
  pointer-events: auto;
  animation: mm-panel-slide 240ms cubic-bezier(0.2, 0.8, 0.2, 1);
  overflow: hidden;
}
@keyframes mm-panel-slide {
  from { transform: translateY(20px) scale(0.985); opacity: 0; }
  to   { transform: translateY(0)      scale(1);     opacity: 1; }
}
.master-mixer-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 14px;
  border-bottom: 1px solid #2a2a3a;
  background: linear-gradient(180deg, rgba(176, 122, 208, 0.08), transparent);
}
.master-mixer-title {
  font-family: inherit;
  font-size: 12px;
  letter-spacing: 0.35em;
  font-weight: 700;
  color: #d8a8e8;
  text-shadow: 0 0 8px rgba(176, 122, 208, 0.5);
}
.master-mixer-close {
  background: transparent;
  border: 1px solid #6a4a8a;
  color: #b07ad0;
  font-family: inherit;
  font-size: 14px;
  font-weight: 700;
  line-height: 1;
  width: 24px;
  height: 24px;
  border-radius: 3px;
  cursor: pointer;
  transition: all 120ms ease;
}
.master-mixer-close:hover {
  background: rgba(176, 122, 208, 0.18);
  color: #fff;
  border-color: #d8a8e8;
  box-shadow: 0 0 8px rgba(176, 122, 208, 0.5);
}

/* View switcher (PLANETS / CONSOLE / MATRIX) au centre du header */
.master-mixer-views {
  display: flex;
  gap: 4px;
  margin: 0 auto;
}
.master-mixer-view-btn {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-dim);
  font-family: inherit;
  font-size: 9px;
  letter-spacing: 0.25em;
  font-weight: 700;
  padding: 6px 12px;
  border-radius: 3px;
  cursor: pointer;
  transition: all 120ms ease;
}
.master-mixer-view-btn:hover { border-color: var(--accent-dim); color: var(--accent-dim); }
.master-mixer-view-btn.active {
  background: rgba(0, 240, 255, 0.16);
  border-color: var(--accent);
  color: var(--accent);
  box-shadow: 0 0 8px rgba(0, 240, 255, 0.35);
}
.master-mixer-body {
  flex: 1;
  min-width: 0;
  overflow-y: auto;
  overflow-x: hidden;       /* contraint la largeur du body → enfants doivent scroller eux-mêmes */
  padding: 12px 14px 16px;
  display: flex;
  flex-direction: column;
  gap: 14px;
  box-sizing: border-box;
}

/* MASTER section title (gardé pour la section master-bus dans detail panel) */
.mm-section { display: flex; flex-direction: column; gap: 4px; }
.mm-section-title {
  font-size: 9px;
  letter-spacing: 0.3em;
  font-weight: 700;
  color: var(--text-dim);
  text-transform: uppercase;
  padding: 4px 0;
  border-bottom: 1px solid #2a2a3a;
  margin-bottom: 2px;
}

/* ============================================================
   VISUALIZER — Canvas 2D audio-réactif (replace solar planets)
   ============================================================ */
.viz-wrap {
  display: grid;
  grid-template-columns: 1fr 240px;
  gap: 12px;
  height: 100%;
  min-height: 0;
}
.viz-canvas-host {
  position: relative;
  width: 100%;
  height: 100%;
  min-height: 0;
  background: radial-gradient(circle at center, #0a0814 0%, #04020c 100%);
  border-radius: 4px;
  overflow: hidden;
  border: 1px solid var(--border);
  transition: border-color 120ms ease, box-shadow 120ms ease;
}
.viz-canvas-host.viz-drag-over {
  border-color: #b0a0e0;
  box-shadow: inset 0 0 24px rgba(176, 160, 224, 0.4);
}
.viz-drop-hint {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  pointer-events: none;
  font-size: 11px;
  letter-spacing: 0.25em;
  color: rgba(176, 160, 224, 0.65);
  opacity: 0;
  transition: opacity 140ms ease;
}
.viz-canvas-host.viz-drag-over .viz-drop-hint { opacity: 1; }
.viz-canvas {
  display: block;
  width: 100%;
  height: 100%;
}
.viz-controls {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 10px;
  background: rgba(12, 12, 20, 0.85);
  border: 1px solid var(--border);
  border-radius: 4px;
  overflow-y: auto;
  min-height: 0;
}
.viz-controls-header {
  font-size: 10px;
  letter-spacing: 0.3em;
  font-weight: 700;
  color: #b0a0e0;
  padding-bottom: 4px;
  border-bottom: 1px solid var(--border);
}
.viz-modes {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 3px;
}
.viz-modes-hint {
  font-size: 7px;
  letter-spacing: 0.15em;
  color: rgba(176, 160, 224, 0.4);
  text-align: center;
  margin-top: 2px;
  font-style: italic;
}
.viz-mode-pill {
  background: transparent;
  border: 1px solid rgba(176, 160, 224, 0.3);
  color: rgba(176, 160, 224, 0.6);
  font-family: inherit;
  font-size: 8px;
  letter-spacing: 0.12em;
  font-weight: 700;
  padding: 5px 0;
  border-radius: 2px;
  cursor: pointer;
  transition: all 100ms ease;
}
.viz-mode-pill:hover {
  border-color: #b0a0e0;
  color: #b0a0e0;
}
.viz-mode-pill.active {
  background: linear-gradient(180deg, rgba(176, 160, 224, 0.35), rgba(176, 160, 224, 0.18));
  border-color: #b0a0e0;
  color: #fff;
  box-shadow: 0 0 8px rgba(176, 160, 224, 0.5), inset 0 0 4px rgba(176, 160, 224, 0.4);
}
.viz-sliders {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.viz-slider-row {
  display: grid;
  grid-template-columns: 48px 1fr;
  align-items: center;
  gap: 6px;
}
.viz-slider-label {
  font-size: 8px;
  letter-spacing: 0.18em;
  font-weight: 700;
  color: rgba(176, 160, 224, 0.85);
}
.viz-slider { height: 14px; }
/* Quand un LFO est assigné à un slider viz, son fill change de couleur */
.viz-slider.viz-slider-lfo .fill {
  background: linear-gradient(90deg, #ff7ad0, #b0a0e0) !important;
  box-shadow: 0 0 4px rgba(255, 122, 208, 0.5);
}
.viz-section-label {
  font-size: 8px;
  letter-spacing: 0.25em;
  font-weight: 700;
  color: rgba(176, 160, 224, 0.5);
  margin-top: 4px;
  padding-bottom: 2px;
}
.viz-ws-pills {
  display: flex;
  flex-wrap: wrap;
  gap: 3px;
}
.viz-ws-pill {
  flex: 1 1 auto;
  background: transparent;
  border: 1px solid rgba(176, 160, 224, 0.25);
  color: rgba(176, 160, 224, 0.55);
  font-family: inherit;
  font-size: 8px;
  letter-spacing: 0.12em;
  font-weight: 700;
  padding: 4px 6px;
  border-radius: 2px;
  cursor: pointer;
  transition: all 100ms ease;
}
.viz-ws-pill:hover { border-color: #b0a0e0; color: #b0a0e0; }
.viz-ws-pill.active {
  background: rgba(176, 160, 224, 0.22);
  border-color: #b0a0e0;
  color: #fff;
  box-shadow: 0 0 6px rgba(176, 160, 224, 0.4);
}
.viz-image-zone {
  display: flex;
  gap: 4px;
}
.viz-image-btn {
  flex: 1;
  background: transparent;
  border: 1px dashed rgba(176, 160, 224, 0.45);
  color: rgba(176, 160, 224, 0.85);
  font-family: inherit;
  font-size: 9px;
  letter-spacing: 0.18em;
  font-weight: 700;
  padding: 6px 8px;
  border-radius: 3px;
  cursor: pointer;
  transition: all 100ms ease;
}
.viz-image-btn:hover {
  border-color: #b0a0e0;
  background: rgba(176, 160, 224, 0.1);
  color: #fff;
}
.viz-image-btn.viz-image-clear {
  flex: 0 0 28px;
  color: rgba(255, 80, 80, 0.85);
  border-color: rgba(255, 80, 80, 0.45);
  padding: 6px 4px;
}
.viz-image-btn.viz-image-clear:hover {
  background: rgba(255, 80, 80, 0.12);
  border-color: #ff5050;
}
.viz-image-btn.viz-image-reset {
  flex: 0 0 auto;
  color: rgba(255, 168, 74, 0.85);
  border-color: rgba(255, 168, 74, 0.45);
  border-style: solid;
}
.viz-switch-row {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 6px;
  align-items: center;
}
.viz-switch-pills {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 3px;
}
.viz-switch-pill {
  background: transparent;
  border: 1px solid rgba(176, 160, 224, 0.3);
  color: rgba(176, 160, 224, 0.6);
  font-family: inherit;
  font-size: 8px;
  letter-spacing: 0.12em;
  font-weight: 700;
  padding: 4px 0;
  border-radius: 2px;
  cursor: pointer;
}
.viz-switch-pill:hover { border-color: #b0a0e0; color: #b0a0e0; }
.viz-switch-pill.active {
  background: rgba(176, 160, 224, 0.25);
  border-color: #b0a0e0;
  color: #fff;
  box-shadow: 0 0 6px rgba(176, 160, 224, 0.4);
}
.viz-switch-info {
  font-size: 8px;
  letter-spacing: 0.15em;
  color: rgba(176, 160, 224, 0.7);
  font-variant-numeric: tabular-nums;
  min-width: 36px;
  text-align: right;
}
.viz-layout-pills {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 3px;
}
.viz-layout-pill {
  background: transparent;
  border: 1px solid rgba(95, 192, 128, 0.3);
  color: rgba(95, 192, 128, 0.65);
  font-family: inherit;
  font-size: 8px;
  letter-spacing: 0.12em;
  font-weight: 700;
  padding: 4px 0;
  border-radius: 2px;
  cursor: pointer;
}
.viz-layout-pill:hover { border-color: #5fc080; color: #5fc080; }
.viz-layout-pill.active {
  background: rgba(95, 192, 128, 0.25);
  border-color: #5fc080;
  color: #fff;
  box-shadow: 0 0 6px rgba(95, 192, 128, 0.4);
}
/* Chance sliders : couleur jaune/orange (dice / random) */
.viz-chance-sliders .viz-slider .fill {
  background: linear-gradient(90deg, rgba(255, 168, 74, 0.85), rgba(224, 192, 80, 0.85)) !important;
}
.viz-chance-sliders .viz-slider-label {
  color: rgba(255, 168, 74, 0.85);
}
.viz-chance-randomize-btn {
  width: 100%;
  background: rgba(255, 168, 74, 0.12) !important;
  border: 1px dashed #ffa84a !important;
  color: #ffa84a !important;
  font-size: 9px;
  letter-spacing: 0.25em;
}
.viz-chance-randomize-btn:hover {
  background: rgba(255, 168, 74, 0.25) !important;
  color: #fff !important;
}
.viz-image-btn.viz-image-reset:hover {
  background: rgba(255, 168, 74, 0.12);
  border-color: #ffa84a;
}
.viz-mirror-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 4px;
}
.viz-mirror-btn {
  background: transparent;
  border: 1px solid rgba(176, 160, 224, 0.3);
  color: rgba(176, 160, 224, 0.65);
  font-family: inherit;
  font-size: 9px;
  letter-spacing: 0.18em;
  font-weight: 700;
  padding: 5px 0;
  border-radius: 2px;
  cursor: pointer;
  transition: all 100ms ease;
}
.viz-mirror-btn:hover { border-color: #b0a0e0; color: #b0a0e0; }
.viz-mirror-btn.active {
  background: rgba(176, 160, 224, 0.25);
  border-color: #b0a0e0;
  color: #fff;
  box-shadow: 0 0 6px rgba(176, 160, 224, 0.4);
}
.viz-blend-pills {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 3px;
}
.viz-blend-pill {
  background: transparent;
  border: 1px solid rgba(176, 160, 224, 0.25);
  color: rgba(176, 160, 224, 0.55);
  font-family: inherit;
  font-size: 7px;
  letter-spacing: 0.1em;
  font-weight: 700;
  padding: 4px 0;
  border-radius: 2px;
  cursor: pointer;
  transition: all 100ms ease;
}
.viz-blend-pill:hover { border-color: #b0a0e0; color: #b0a0e0; }
.viz-blend-pill.active {
  background: rgba(176, 160, 224, 0.25);
  border-color: #b0a0e0;
  color: #fff;
  box-shadow: 0 0 6px rgba(176, 160, 224, 0.4);
}
/* Cursor sur le canvas en mode IMAGE pour signaler le drag */
.viz-canvas-host { cursor: default; }
.viz-canvas-host:has(canvas) { cursor: default; }
.viz-controls-hint {
  font-size: 8px;
  letter-spacing: 0.15em;
  color: rgba(176, 160, 224, 0.4);
  text-align: center;
  font-style: italic;
  margin-top: auto;
  padding-top: 6px;
}

/* ============================================================
   SOLAR SYSTEM MIXER (legacy, sub-renderers still used by console)
   ============================================================ */
.solar-wrap {
  display: grid;
  grid-template-columns: 1fr 240px;
  gap: 12px;
  height: 100%;
  min-height: 0;
}
.solar-svg {
  width: 100%;
  height: 100%;
  background: radial-gradient(circle at center, #0a0814 0%, #04020c 100%);
  border-radius: 4px;
}
.solar-star { pointer-events: none; }
.orbit-ring {
  fill: none;
  stroke: rgba(255, 255, 255, 0.06);
  stroke-width: 1;
  stroke-dasharray: 2 4;
}
.solar-sun {
  cursor: pointer;
  transition: transform 80ms ease-out;
}
.sun-halo {
  fill: #ffd84a;
  opacity: 0.18;
  filter: blur(8px);
}
.sun-core { filter: url(#solar-glow); }
.sun-label {
  fill: #3a2300;
  font-family: inherit;
  font-size: 16px;
  font-weight: 900;
  text-anchor: middle;
  pointer-events: none;
  letter-spacing: 0.08em;
}
.solar-sun:hover .sun-halo { opacity: 0.34; }
.solar-planet {
  cursor: pointer;
  transition: opacity 220ms ease;
}
.planet-body { filter: url(#solar-glow); transition: r 60ms ease-out; }
.planet-halo {
  stroke-width: 1;
  pointer-events: none;
  transition: r 60ms ease-out, opacity 220ms ease;
}
.planet-label {
  fill: #fff;
  font-family: inherit;
  font-size: 7px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-anchor: middle;
  pointer-events: none;
}
.solar-planet.focused .planet-body { filter: url(#solar-glow) brightness(1.4); }
.solar-planet.focused .planet-halo { stroke-width: 2; opacity: 1 !important; }
.solar-planet.dimmed { opacity: 0.22; }
.solar-planet:hover .planet-body { filter: url(#solar-glow) brightness(1.2); }
.planet-moon {
  pointer-events: none;
  filter: drop-shadow(0 0 2px currentColor);
}

/* DETAIL PANEL (côté droit du système) */
.solar-detail {
  background: rgba(14, 10, 22, 0.6);
  border: 1px solid #2a2a3a;
  border-radius: 4px;
  padding: 12px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.solar-detail-hint {
  color: var(--text-dim);
  font-size: 9px;
  letter-spacing: 0.18em;
  text-align: center;
  padding: 20px 8px;
  font-style: italic;
}
.solar-detail-title {
  font-size: 12px;
  letter-spacing: 0.3em;
  font-weight: 700;
  color: var(--accent);
  text-shadow: 0 0 6px rgba(0, 240, 255, 0.4);
  padding-bottom: 6px;
  border-bottom: 1px solid #2a2a3a;
}
.solar-detail-subtitle {
  font-size: 8px;
  letter-spacing: 0.25em;
  color: var(--text-dim);
  font-weight: 700;
  padding: 6px 0 2px;
}
.solar-detail-row {
  display: grid;
  grid-template-columns: 60px 1fr 60px;
  gap: 8px;
  align-items: center;
}
.solar-detail-label {
  font-size: 9px;
  letter-spacing: 0.18em;
  font-weight: 700;
  color: var(--text-dim);
}
.solar-vol-slider { height: 16px; }
.solar-mute-btn {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-dim);
  font-family: inherit;
  font-size: 8px;
  letter-spacing: 0.15em;
  font-weight: 700;
  padding: 4px 6px;
  border-radius: 2px;
  cursor: pointer;
  transition: all 120ms ease;
}
.solar-mute-btn:hover { border-color: var(--magenta-dim); color: var(--magenta-dim); }
.solar-mute-btn.active {
  background: rgba(255, 58, 165, 0.18);
  border-color: var(--magenta);
  color: var(--magenta);
}
.solar-fx-row {
  display: grid;
  grid-template-columns: 12px 50px 1fr;
  gap: 6px;
  align-items: center;
  padding: 3px 0;
}
.solar-fx-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  box-shadow: 0 0 6px currentColor;
}
.solar-fx-name {
  font-size: 9px;
  letter-spacing: 0.15em;
  font-weight: 700;
  color: var(--text);
}
.solar-fx-chance { height: 12px; }

/* ============================================================
   CONSOLE VIEW — analog mixing console aesthetic
   ============================================================ */
.console-wrap {
  display: flex;
  flex-direction: column;
  gap: 10px;
  height: 100%;
  min-height: 0;
  min-width: 0;
  width: 100%;
  padding: 10px;
  background: var(--bg);
  border-radius: 4px;
  overflow: hidden;          /* contraint horizontalement → enfants peuvent scroll */
  box-sizing: border-box;
}
.console-strips-area {
  flex: 1;
  min-height: 0;
  min-width: 0;
  /* PAS width:0 (kill l'élément dans flex column où cross-axis ne grow pas).
     align-self: stretch (défaut) suffit ; parent console-wrap a overflow:hidden
     pour contraindre la largeur, et nous on scroll horizontalement à l'intérieur. */
  align-self: stretch;
  display: flex;
  gap: 4px;
  overflow-x: scroll;       /* SCROLL forcé → scrollbar toujours visible */
  overflow-y: hidden;
  padding: 4px 2px;
  background: rgba(0, 0, 0, 0.25);
  border: 1px solid var(--border);
  border-radius: 3px;
  box-sizing: border-box;
}
/* Scrollbar custom : plus visible et "touch friendly" pour la console mixer */
.console-strips-area::-webkit-scrollbar       { height: 10px; }
.console-strips-area::-webkit-scrollbar-track {
  background: rgba(0, 0, 0, 0.4);
  border-radius: 4px;
}
.console-strips-area::-webkit-scrollbar-thumb {
  background: rgba(176, 122, 208, 0.5);
  border-radius: 4px;
  border: 1px solid rgba(176, 122, 208, 0.3);
}
.console-strips-area::-webkit-scrollbar-thumb:hover {
  background: rgba(176, 122, 208, 0.8);
}
.console-premaster-row {
  flex: 0 0 auto;
  display: flex;
  gap: 8px;
  align-items: stretch;
  min-height: 140px;
  max-height: 220px;
}
/* Pre-master modules : look identique aux bass-box / poly-box du site */
.premaster-module {
  display: flex;
  flex-direction: column;
  background: rgba(12, 12, 20, 0.85);
  border: 1px solid var(--border);
  border-top: 2px solid currentColor;
  border-radius: 4px;
  min-width: 180px;
  transition: opacity 140ms ease;
  color: var(--text-dim);
}
.premaster-module.disabled { opacity: 0.45; }
.premaster-module.premaster-master {
  border-top-color: #ffd84a;
  min-width: 380px;
  flex: 2;
  color: #ffd84a;
}
.premaster-module.premaster-tape {
  border-top-color: #ff7ad0;
  flex: 1;
  color: #ff7ad0;
}
.premaster-module.premaster-future {
  border-top-color: var(--border);
  flex: 1;
  opacity: 0.55;
  border-style: dashed;
  color: var(--text-dim);
}
.premaster-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 5px 8px;
  border-bottom: 1px solid var(--border);
}
.premaster-name {
  font-size: 9px;
  letter-spacing: 0.3em;
  font-weight: 700;
  color: currentColor;
}
.premaster-on {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-dim);
  font-family: inherit;
  font-size: 8px;
  letter-spacing: 0.18em;
  font-weight: 700;
  padding: 3px 8px;
  border-radius: 2px;
  cursor: pointer;
  transition: all 120ms ease;
}
.premaster-on.always-on {
  background: rgba(255, 216, 74, 0.15);
  border-color: #ffd84a;
  color: #ffd84a;
  cursor: default;
}
/* Master toggle ON : highlighted yellow (color du master bus) */
.premaster-master .premaster-on.active {
  background: rgba(255, 216, 74, 0.18);
  border-color: #ffd84a;
  color: #ffd84a;
  box-shadow: 0 0 8px rgba(255, 216, 74, 0.35);
}
.premaster-master .premaster-on:not(.active) {
  background: rgba(255, 80, 80, 0.12);
  border-color: #ff5050;
  color: #ff5050;
  box-shadow: 0 0 8px rgba(255, 80, 80, 0.35);
}
.premaster-on:hover:not(.always-on) {
  border-color: var(--accent-dim);
  color: var(--accent-dim);
}
.premaster-module:not(.disabled) .premaster-on:not(.always-on) {
  background: rgba(0, 240, 255, 0.14);
  border-color: var(--accent);
  color: var(--accent);
}
.premaster-body {
  flex: 1;
  padding: 8px;
  overflow-y: auto;
  min-height: 0;
}
.premaster-hint {
  color: var(--text-dim);
  font-size: 9px;
  letter-spacing: 0.2em;
  font-style: italic;
  text-align: center;
  padding: 12px 4px;
  opacity: 0.7;
}
/* Le master section dans le premaster-master : grille 2 colonnes des sliders */
.premaster-master .mm-section-master {
  background: transparent;
  border-left: none;
  padding: 0;
  margin-left: 0;
  width: auto;
}
.premaster-master .mm-section-master .mm-section-title { display: none; }
.premaster-master .master-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(70px, 1fr));
  gap: 4px;
}

/* ============================================================================
   TAPE master FX UI : pills (STUDER/AMPEX/CRUSH) + horizontal sliders
   ============================================================================ */
.premaster-tape .premaster-on.active {
  background: rgba(255, 122, 208, 0.18);
  border-color: #ff7ad0;
  color: #ff7ad0;
  box-shadow: 0 0 8px rgba(255, 122, 208, 0.35);
}
.premaster-tape .premaster-on:not(.active) {
  background: rgba(255, 80, 80, 0.08);
  border-color: rgba(255, 80, 80, 0.5);
  color: rgba(255, 80, 80, 0.85);
}
.premaster-tape .premaster-body {
  padding: 6px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.tape-type-row {
  display: flex;
  gap: 3px;
  justify-content: space-between;
}
.tape-type-pill {
  flex: 1;
  background: transparent;
  border: 1px solid rgba(255, 122, 208, 0.35);
  color: rgba(255, 122, 208, 0.6);
  font-family: inherit;
  font-size: 8px;
  letter-spacing: 0.18em;
  font-weight: 700;
  padding: 4px 0;
  border-radius: 2px;
  cursor: pointer;
  transition: all 100ms ease;
}
.tape-type-pill:hover {
  border-color: #ff7ad0;
  color: #ff7ad0;
}
.tape-type-pill.active {
  background: linear-gradient(180deg, rgba(255, 122, 208, 0.35), rgba(255, 122, 208, 0.18));
  border-color: #ff7ad0;
  color: #fff;
  box-shadow: 0 0 8px rgba(255, 122, 208, 0.5), inset 0 0 4px rgba(255, 122, 208, 0.4);
}
.tape-sliders {
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.tape-slider {
  display: grid;
  grid-template-columns: 48px 1fr 26px;
  align-items: center;
  gap: 6px;
}
.tape-slider-label {
  font-size: 8px;
  letter-spacing: 0.18em;
  font-weight: 700;
  color: rgba(255, 122, 208, 0.85);
}
.tape-slider input[type=range] {
  -webkit-appearance: none;
  appearance: none;
  background: transparent;
  width: 100%;
  height: 14px;
  cursor: pointer;
}
.tape-slider input[type=range]::-webkit-slider-runnable-track {
  height: 3px;
  background: linear-gradient(90deg, rgba(255, 122, 208, 0.5), rgba(255, 122, 208, 0.15));
  border-radius: 2px;
}
.tape-slider input[type=range]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 10px;
  height: 10px;
  margin-top: -3.5px;
  background: #ff7ad0;
  border-radius: 50%;
  box-shadow: 0 0 6px rgba(255, 122, 208, 0.7);
  cursor: pointer;
}
.tape-slider input[type=range]::-moz-range-track {
  height: 3px;
  background: rgba(255, 122, 208, 0.35);
  border-radius: 2px;
}
.tape-slider input[type=range]::-moz-range-thumb {
  width: 10px;
  height: 10px;
  background: #ff7ad0;
  border: none;
  border-radius: 50%;
  box-shadow: 0 0 6px rgba(255, 122, 208, 0.7);
  cursor: pointer;
}
.tape-slider-val {
  font-size: 9px;
  font-variant-numeric: tabular-nums;
  color: rgba(255, 122, 208, 0.9);
  text-align: right;
}
.premaster-tape.disabled .tape-type-pill,
.premaster-tape.disabled .tape-slider input[type=range] {
  pointer-events: none;
}
.console-strip {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  width: 78px;
  flex-shrink: 0;
  padding: 6px 4px;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-top: 2px solid currentColor;
  border-radius: 3px;
  gap: 6px;
  position: relative;
}
.console-strip.kind-lane    { color: #5fc080; }
.console-strip.kind-mono    { color: #00f0ff; }
.console-strip.kind-poly    { color: #ff7ad0; }
.console-strip.kind-slicer  { color: #ffa84a; }
.console-strip.kind-grain   { color: #5fc0d8; }
.console-strip.kind-fm      { color: #ff8a3a; }
.console-strip.kind-bouncer { color: #b07ad0; }
.console-strip.kind-ext     { color: #ffa84a; }

/* Console strip = drop target pour FX chips depuis la palette droite */
.console-strip.drag-over-fx {
  background: rgba(255, 168, 74, 0.10);
  box-shadow: inset 0 0 0 2px #ffa84a, 0 0 12px rgba(255, 168, 74, 0.35);
  transition: background 80ms ease, box-shadow 80ms ease;
}

.console-name {
  font-size: 8px;
  letter-spacing: 0.22em;
  font-weight: 700;
  text-align: center;
  text-transform: uppercase;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  padding: 2px 0 4px;
  border-bottom: 1px solid var(--border);
  color: currentColor;
}

/* GAIN — pre-fader input trim (0..2× = -∞..+6dB), affiché en dB */
.console-gain {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: 3px 0 4px;
  border-bottom: 1px solid var(--border);
}
.console-gain-label {
  font-size: 7px;
  letter-spacing: 0.2em;
  font-weight: 700;
  color: rgba(255, 255, 255, 0.45);
}
.console-gain-slider {
  width: calc(100% - 6px);
  height: 12px;
  position: relative;
  background: rgba(10, 10, 16, 0.7);
  border: 1px solid var(--border);
  border-radius: 2px;
  cursor: ew-resize;
  overflow: hidden;
}
.console-gain-slider .fill {
  position: absolute;
  inset: 0;
  width: 50%;
  background: linear-gradient(90deg, rgba(95, 192, 128, 0.6), rgba(255, 216, 74, 0.6) 50%, rgba(255, 80, 80, 0.6));
  pointer-events: none;
}
.console-gain-slider .label {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
}
.console-gain-slider .val {
  font-size: 7px;
  font-weight: 700;
  color: #fff;
  text-shadow: 0 0 2px #000;
}

/* EQ KNOBS — 3 bandes par strip (HI / MID / LO) */
.console-eq {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 4px 0;
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  background: var(--bg);
  border-radius: 2px;
}
.eq-knob {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1px;
  cursor: ns-resize;
  user-select: none;
}
.eq-knob-dial {
  width: 26px;
  height: 26px;
}
.eq-knob-bg {
  fill: var(--bg-elev);
  stroke: var(--border);
  stroke-width: 1;
}
.eq-knob-arc {
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  filter: drop-shadow(0 0 3px currentColor);
}
.eq-knob-pointer {
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  transform-origin: 0 0;
  transform: rotate(var(--ang, 0deg));
  opacity: 0.95;
}
.eq-knob:hover .eq-knob-arc { stroke-width: 2.5; }
.eq-knob:hover .eq-knob-bg { stroke: currentColor; }
.eq-knob-label {
  font-size: 7px;
  letter-spacing: 0.2em;
  font-weight: 700;
  color: var(--text-dim);
  text-transform: uppercase;
}
.eq-knob:hover .eq-knob-label { color: currentColor; }

/* Fader-rail = un SEUL rail avec VU et handle superposés (style lane-VU) */
.console-fader {
  flex: 1;
  width: 22px;
  align-self: center;
  min-height: 140px;
  background: rgba(12, 12, 20, 0.85);
  border: 1px solid var(--border);
  border-radius: 3px;
  position: relative;
  overflow: hidden;
  cursor: ns-resize;
}
.console-vu-fill {
  position: absolute;
  inset: 0;
  --vu-level: 0;
  background: linear-gradient(to top,
    #2a8a4a 0%, #5fc080 50%,
    #ffd84a 75%, #ff8a3a 88%,
    #ff3030 95%);
  clip-path: inset(calc((100 - var(--vu-level)) * 1%) 0 0 0);
  transition: clip-path 60ms ease-out;
  pointer-events: none;
}
.console-fader-handle {
  position: absolute;
  left: -2px;
  right: -2px;
  height: 4px;
  background: currentColor;
  border-radius: 1px;
  box-shadow: 0 0 6px currentColor;
  bottom: 50%;
  pointer-events: none;
  z-index: 2;
}
.console-fader .label { display: none; }
.console-fader:hover { border-color: currentColor; }

.console-vol-num {
  font-size: 9px;
  font-weight: 700;
  text-align: center;
  color: var(--text-dim);
  padding: 2px 0;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 2px;
  letter-spacing: 0.08em;
}

/* Bouton mute aligné sur le style site (btn-mini) */
.console-mute {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-dim);
  font-family: inherit;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.18em;
  padding: 4px 0;
  border-radius: 2px;
  cursor: pointer;
  transition: all 120ms ease;
}
.console-mute:hover { border-color: var(--magenta-dim); color: var(--magenta-dim); }
.console-mute.active {
  background: rgba(255, 58, 165, 0.16);
  border-color: var(--magenta);
  color: var(--magenta);
  box-shadow: 0 0 6px rgba(255, 58, 165, 0.35);
}

/* SOLO button (sous le mute) — jaune pour distinguer du mute rose */
.console-solo {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-dim);
  font-family: inherit;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.18em;
  padding: 4px 0;
  border-radius: 2px;
  cursor: pointer;
  transition: all 120ms ease;
  margin-top: 3px;
}
.console-solo:hover { border-color: #ffd84a; color: #ffd84a; }
.console-solo.active {
  background: rgba(255, 216, 74, 0.18);
  border-color: #ffd84a;
  color: #ffd84a;
  box-shadow: 0 0 6px rgba(255, 216, 74, 0.4);
}

.console-fx-section {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin-top: 2px;
  padding: 4px 3px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 2px;
}
.console-fx-title {
  font-size: 7px;
  letter-spacing: 0.25em;
  font-weight: 700;
  color: var(--text-dim);
  text-align: center;
  padding: 1px 0 3px;
}
.console-fx {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.console-fx-empty {
  color: var(--text-dim);
  font-size: 7px;
  letter-spacing: 0.18em;
  text-align: center;
  padding: 3px 0;
  font-style: italic;
  opacity: 0.5;
}
.console-fx-chip {
  position: relative;
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 2px;
  padding: 2px 4px;
  background: rgba(0, 0, 0, 0.35);
  border: 1px solid currentColor;
  border-radius: 2px;
  overflow: hidden;
  z-index: 1;
  cursor: context-menu;
  transition: background 120ms ease, transform 120ms ease;
}
.console-fx-chip:hover {
  background: rgba(0, 0, 0, 0.6);
  transform: translateY(-1px);
}
.console-fx-chip-name {
  font-size: 7px;
  letter-spacing: 0.12em;
  font-weight: 700;
  position: relative;
  z-index: 2;
}
.console-fx-chip-pct {
  font-size: 7px;
  font-weight: 700;
  color: var(--text);
  position: relative;
  z-index: 2;
  letter-spacing: 0;
  opacity: 0.85;
}
.console-fx-chip-bar {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  opacity: 0.22;
  z-index: 0;
  pointer-events: none;
}

/* Séparateur visuel entre instruments et FX buses */
.console-separator {
  flex-shrink: 0;
  width: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0 4px;
  position: relative;
}
.console-separator::before {
  content: '';
  position: absolute;
  top: 8px;
  bottom: 8px;
  left: 50%;
  width: 1px;
  background: linear-gradient(180deg, transparent, var(--border) 20%, var(--border) 80%, transparent);
}
.console-separator span {
  font-size: 7px;
  letter-spacing: 0.3em;
  font-weight: 700;
  color: var(--text-dim);
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  background: var(--bg);
  padding: 6px 2px;
  z-index: 1;
}

/* FX bus strip — unique, plus large pour contenir la liste des FX */
.console-fx-strip {
  display: flex;
  flex-direction: column;
  width: 78px;
  flex-shrink: 0;
  padding: 6px 4px;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-top: 2px solid currentColor;
  border-radius: 3px;
  gap: 6px;
  color: currentColor;
}
.console-fx-bus {
  width: 160px;
  /* Sticky à droite : reste visible même quand on scrolle, comme la pile
     master sur une vraie console. Ça résout le "je vois pas le FX bus". */
  position: sticky;
  right: 0;
  z-index: 2;
  box-shadow: -8px 0 16px rgba(0, 0, 0, 0.55);
}
.console-fx-bus + *,
.console-separator + .console-fx-bus {
  /* (séparateur juste avant le FX BUS) — pas de sticky sur le sep, juste
     l'ombre du FX BUS suffit à le distinguer visuellement */
}
.console-fx-bus-fader {
  flex: 0 0 auto;
  height: 80px;
  min-height: 80px;
}
.console-fx-bus-list {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
}
.console-fx-strip .console-name {
  color: currentColor;
}
.console-fx-sources {
  display: flex;
  flex-wrap: wrap;
  gap: 3px;
  justify-content: center;
  align-items: center;
  padding: 4px;
  min-height: 24px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 2px;
}
.console-fx-source-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  cursor: help;
}
.console-fx-sources-empty {
  font-size: 7px;
  letter-spacing: 0.18em;
  color: var(--text-dim);
  font-style: italic;
  opacity: 0.55;
}
.console-bypass.active {
  background: rgba(90, 90, 112, 0.18);
  border-color: var(--text-dim);
  color: var(--text-dim);
  box-shadow: none;
}

/* MASTER section (mm-section-master) — styles génériques */

/* ============================================================
   MATRIX VIEW — instruments × FX heatmap
   ============================================================ */
.matrix-wrap {
  height: 100%;
  overflow: auto;
  padding: 12px;
  background: rgba(8, 6, 14, 0.6);
  border-radius: 4px;
}
.matrix-table {
  border-collapse: separate;
  border-spacing: 2px;
  width: 100%;
}
.matrix-table th,
.matrix-table td {
  padding: 0;
  text-align: center;
  vertical-align: middle;
}
.matrix-corner {
  font-size: 9px;
  letter-spacing: 0.2em;
  font-weight: 700;
  color: var(--text-dim);
  padding: 6px 8px !important;
  width: 100px;
}
.matrix-fx-header {
  width: 50px;
  font-size: 9px;
  letter-spacing: 0.12em;
  font-weight: 800;
  padding: 6px 4px !important;
  background: rgba(255, 255, 255, 0.02);
  border-radius: 2px;
  cursor: pointer;
  text-shadow: 0 0 4px currentColor;
}
.matrix-fx-header:hover { background: rgba(255, 255, 255, 0.06); }
.matrix-vol-header,
.matrix-mute-header {
  font-size: 9px;
  letter-spacing: 0.15em;
  color: var(--text-dim);
  font-weight: 700;
  padding: 6px 4px !important;
}
.matrix-track {
  font-size: 9px;
  letter-spacing: 0.15em;
  font-weight: 800;
  text-align: left !important;
  padding: 6px 8px !important;
  background: rgba(255, 255, 255, 0.04);
  border-radius: 2px;
  text-shadow: 0 0 4px currentColor;
}
.matrix-cell {
  width: 50px;
  height: 28px;
  background: rgba(255, 255, 255, 0.025);
  border-radius: 3px;
  cursor: ew-resize;
  transition: filter 120ms ease, box-shadow 120ms ease, transform 100ms ease;
  position: relative;
  overflow: hidden;
  user-select: none;
}
.matrix-cell:hover { filter: brightness(1.4); transform: scale(1.05); }
/* Jauge horizontale = wet level. Left = 0% wet, right = 100% wet. */
.matrix-cell-wet {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 100%;
  background: linear-gradient(90deg,
    rgba(255, 255, 255, 0.18) 0%,
    rgba(255, 255, 255, 0.55) 100%);
  pointer-events: none;
  transition: width 60ms linear;
  z-index: 1;
}
.matrix-cell.off .matrix-cell-wet { display: none; }
.matrix-cell.on::after {
  content: attr(data-pct);
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 9px;
  font-weight: 800;
  color: #0a0a0a;
  letter-spacing: 0;
  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.45);
  z-index: 2;
}
.matrix-cell.off::after {
  content: '+';
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  color: #3a3a3a;
  transition: color 120ms ease;
}
.matrix-cell.off:hover::after { color: #6a6a6a; }
.matrix-vol {
  width: 100px;
  padding: 0 6px !important;
}
.matrix-vol-slider { height: 14px; }
.matrix-mute {
  width: 28px;
  padding: 0 !important;
}
.matrix-mute-btn {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-dim);
  font-family: inherit;
  font-size: 9px;
  font-weight: 700;
  width: 22px;
  height: 20px;
  padding: 0;
  border-radius: 2px;
  cursor: pointer;
  transition: all 120ms ease;
}
.matrix-mute-btn:hover { border-color: var(--magenta-dim); color: var(--magenta-dim); }
.matrix-mute-btn.active {
  background: rgba(255, 58, 165, 0.18);
  border-color: var(--magenta);
  color: var(--magenta);
}

/* "+ DROP FX HERE" placeholder pour les zones FX vides */
.bass-strip-fx:empty,
.lane-strip-fx:empty {
  position: relative;
}
.bass-strip-fx:empty::before,
.lane-strip-fx:empty::before {
  content: '+ DROP FX HERE';
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: rgba(255, 168, 74, 0.7);            /* + lisible (était 0.4) */
  font-size: 8px;
  letter-spacing: 0.25em;
  font-weight: 700;
  pointer-events: none;
  text-transform: uppercase;
  white-space: nowrap;                       /* empêche "HERE" de wrap sur 2 lignes */
  text-shadow: 0 1px 1px rgba(0, 0, 0, 0.6); /* contraste sur le fond sombre */
}

/* Hover indicator sur le master-box header pour signaler qu'il s'ouvre */
.master-box .master-box-header {
  transition: background 140ms ease;
  cursor: pointer;
}
.master-box .master-box-header:hover {
  background: rgba(176, 122, 208, 0.10);
  border-radius: 4px;
}
.master-box-mixer-btn {
  /* Bouton MIXER clair et proéminent : gradient violet, plus gros, bordure brighter */
  background: linear-gradient(135deg, rgba(176, 122, 208, 0.35), rgba(216, 168, 232, 0.45));
  border: 1px solid #b07ad0;
  color: #fff;
  font-family: inherit;
  font-size: 10px;
  letter-spacing: 0.22em;
  font-weight: 700;
  padding: 5px 12px;
  border-radius: 3px;
  cursor: pointer;
  transition: all 140ms ease;
  flex-shrink: 0;
  text-shadow: 0 0 4px rgba(255, 255, 255, 0.3);
  box-shadow: 0 0 8px rgba(176, 122, 208, 0.25), inset 0 1px 0 rgba(255, 255, 255, 0.15);
}
.master-box-mixer-btn:hover {
  background: linear-gradient(135deg, rgba(176, 122, 208, 0.55), rgba(216, 168, 232, 0.7));
  color: #fff;
  border-color: #d8a8e8;
  box-shadow: 0 0 14px rgba(216, 168, 232, 0.7), inset 0 1px 0 rgba(255, 255, 255, 0.25);
  transform: translateY(-1px);
}
.master-box-mixer-btn:active {
  transform: translateY(0);
  box-shadow: 0 0 6px rgba(176, 122, 208, 0.4), inset 0 1px 2px rgba(0, 0, 0, 0.3);
}

.center-col {
  display: grid;
  /* header / main(knobs) / bottom-row(1fr).
     Le bottom-row prend tout l'espace vertical restant — c'est le canva
     modulaire complet. Le DRUM RACK est lui-même un module dans ce canvas. */
  grid-template-rows: auto auto 1fr;
  /* 1 colonne, contrainte à la largeur disponible (= colonne #app 1fr).
     Sans ça, le grid auto-column peut s'étendre au-delà → enfants débordent. */
  grid-template-columns: minmax(0, 1fr);
  gap: 8px;
  min-height: 0;
  min-width: 0;
  /* PAS de overflow:hidden ici — le SVG patch-bay (position:fixed) doit
     pouvoir s'étendre au viewport entier pour dessiner les câbles vers le
     SEQ qui vit dans la colonne gauche. Le clip drum rack est géré par
     bottom-row qui a déjà overflow:hidden. */
}
.center-col > header        { grid-row: 1; }
.center-col > main          { grid-row: 2; }
.center-col > .bottom-row   { grid-row: 3; }

/* ---------- Header ---------- */
header {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.title {
  font-size: 17px;
  font-weight: 700;
  letter-spacing: 0.4em;
  color: var(--accent);
  text-shadow: 0 0 12px rgba(0, 240, 255, 0.5);
}
.controls {
  display: flex;
  gap: 20px;
  align-items: center;
  font-size: 10px;
  letter-spacing: 0.25em;
  color: var(--text-dim);
}
.meter-control, .kit-control {
  display: flex;
  gap: 8px;
  align-items: center;
}
#meter-select {
  background: var(--bg-elev);
  border: 1px solid var(--border);
  color: var(--text);
  font-family: inherit;
  font-size: 11px;
  letter-spacing: 0.08em;
  padding: 6px 10px;
  border-radius: 3px;
  cursor: pointer;
}
#meter-select:hover, #meter-select:focus {
  border-color: var(--accent-dim);
  outline: none;
}
#kit-label {
  color: var(--accent);
  font-size: 11px;
  letter-spacing: 0.1em;
}

/* BPM input dans le header */
.bpm-control {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 10px;
  letter-spacing: 0.2em;
  color: var(--text-dim);
}
.bpm-control input {
  background: var(--bg-elev);
  border: 1px solid var(--border);
  color: var(--accent);
  font-family: inherit;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.05em;
  padding: 5px 8px;
  width: 64px;
  border-radius: 3px;
  text-align: center;
  -moz-appearance: textfield;
}
.bpm-control input::-webkit-outer-spin-button,
.bpm-control input::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}
.bpm-control input:hover,
.bpm-control input:focus {
  border-color: var(--accent-dim);
  outline: none;
  box-shadow: 0 0 6px rgba(0, 240, 255, 0.2);
}

/* Swing slider dans le header */
.swing-control, .chaos-control {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 10px;
  letter-spacing: 0.2em;
  color: var(--text-dim);
}
/* Stack SWING + CHAOS verticalement dans le header pour économiser la largeur */
.swing-chaos-stack {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.swing-chaos-stack .swing-control,
.swing-chaos-stack .chaos-control {
  font-size: 9px;
  letter-spacing: 0.15em;
  gap: 6px;
}
.swing-chaos-stack .swing-control > span,
.swing-chaos-stack .chaos-control > span {
  min-width: 42px;
  text-align: right;
}
.swing-chaos-stack .slider.swing,
.swing-chaos-stack .slider.chaos {
  height: 11px;
}
.slider.swing {
  width: 110px;
  height: 14px;
}
.slider.swing .fill {
  background: #ffa84a;
}
.slider.swing:hover .fill {
  background: #ffc070;
  box-shadow: 0 0 8px rgba(255, 168, 74, 0.4);
}
/* Tick visible au milieu = straight (50%) */
.slider.swing::before {
  content: '';
  position: absolute;
  top: 2px;
  bottom: 2px;
  left: 50%;
  width: 1px;
  background: var(--text-dim);
  opacity: 0.5;
  pointer-events: none;
}

/* Chaos slider — rouge pour signaler le danger */
.slider.chaos {
  width: 110px;
  height: 14px;
}
.slider.chaos .fill {
  background: #8a2020;
  transition: background 140ms ease;
}
.slider.chaos:hover .fill {
  background: #ff3030;
  box-shadow: 0 0 12px rgba(255, 48, 48, 0.5);
}

/* ---------- Main : autrefois le stage des knobs, maintenant vide
   (knobs déplacés dans les bandes latérales). On le cache. */
main { display: none; }

/* ============================================================================
   DRUMB GATE — overlay plein écran avant l'app. Logo animé + password input.
   Disparaît avec un fade quand le bon mot de passe est entré.
   ============================================================================ */
.drumb-gate {
  position: fixed;
  inset: 0;
  z-index: 9999;
  background:
    radial-gradient(ellipse at 50% 30%, rgba(199, 255, 46, 0.08), transparent 60%),
    radial-gradient(ellipse at 50% 80%, rgba(255, 58, 165, 0.06), transparent 60%),
    #07070b;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: inherit;
  transition: opacity 600ms ease, visibility 600ms ease;
}
.drumb-gate.drumb-gate-fade {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}
.drumb-gate-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 36px;
  padding: 48px 56px;
  max-width: 90vw;
}
.drumb-gate-logo {
  font-family: 'Evol', monospace;
  font-size: 120px;
  letter-spacing: 0.06em;
  line-height: 0.9;
  color: #c7ff2e;
  text-shadow:
    0 0 16px rgba(199, 255, 46, 0.55),
    0 0 32px rgba(199, 255, 46, 0.25),
    0 4px 0 rgba(0, 0, 0, 0.8);
  user-select: none;
  text-transform: uppercase;
  white-space: nowrap;
}
.drumb-gate-logo > span {
  display: inline-block;
  font-family: inherit;
  transition: font-family 200ms ease, transform 280ms cubic-bezier(0.34, 1.56, 0.64, 1);
}
.drumb-gate-logo > span.pop {
  transform: translateY(-6px) scale(1.08);
}
.drumb-gate-form {
  display: flex;
  gap: 8px;
  align-items: center;
  position: relative;
}
.drumb-gate-input {
  width: 280px;
  height: 38px;
  padding: 0 14px;
  background: rgba(12, 12, 20, 0.85);
  border: 1px solid rgba(199, 255, 46, 0.4);
  border-radius: 3px;
  color: #fff;
  font-family: inherit;
  font-size: 14px;
  letter-spacing: 0.08em;
  outline: none;
  transition: border-color 160ms ease, box-shadow 160ms ease;
}
.drumb-gate-input:focus {
  border-color: #c7ff2e;
  box-shadow: 0 0 12px rgba(199, 255, 46, 0.35);
}
.drumb-gate-input::placeholder { color: rgba(199, 255, 46, 0.35); }
.drumb-gate-btn {
  height: 38px;
  padding: 0 18px;
  background: rgba(199, 255, 46, 0.12);
  border: 1px solid #c7ff2e;
  color: #c7ff2e;
  font-family: inherit;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.3em;
  border-radius: 3px;
  cursor: pointer;
  transition: all 160ms ease;
}
.drumb-gate-btn:hover {
  background: #c7ff2e;
  color: #000;
  box-shadow: 0 0 12px rgba(199, 255, 46, 0.5);
}
.drumb-gate-error {
  position: absolute;
  left: 0;
  right: 0;
  bottom: -22px;
  text-align: center;
  font-size: 10px;
  letter-spacing: 0.2em;
  color: #ff5070;
  text-transform: uppercase;
  opacity: 0;
  transition: opacity 200ms ease;
}
.drumb-gate-error.show { opacity: 1; }
.drumb-gate-shake { animation: drumb-gate-shake 380ms ease; }
@keyframes drumb-gate-shake {
  0%, 100% { transform: translateX(0); }
  20%      { transform: translateX(-8px); }
  40%      { transform: translateX(6px); }
  60%      { transform: translateX(-4px); }
  80%      { transform: translateX(2px); }
}

/* Custom font EVOL — utilisée pour le logo DRUMB (font par défaut).
   font-display: block = block text render jusqu'à font ready (up to 3s).
   Combiné au <link rel="preload"> dans le head, Evol est dispo dès le 1er paint. */
@font-face {
  font-family: 'Evol';
  src: url('assets/fonts/evol/evol.ttf') format('truetype');
  font-display: block;
  font-weight: 400;
  font-style: normal;
}

/* Pool de fonts random pour le swap aléatoire des lettres du logo (en PLAY) */
@font-face { font-family: 'CrackmanBack';  src: url('assets/fonts/archive/Crackman%20Back.otf') format('opentype'); font-display: swap; }
@font-face { font-family: 'CrackmanFront'; src: url('assets/fonts/archive/Crackman%20Front.otf') format('opentype'); font-display: swap; }
@font-face { font-family: 'Crackman';      src: url('assets/fonts/archive/Crackman.otf') format('opentype'); font-display: swap; }
@font-face { font-family: 'ExtraBlur';     src: url('assets/fonts/archive/ExtraBlur.ttf') format('truetype'); font-display: swap; }
@font-face { font-family: 'PacmaniaItalic';src: url('assets/fonts/archive/Pacmania%20Italic.otf') format('opentype'); font-display: swap; }
@font-face { font-family: 'Pacmania';      src: url('assets/fonts/archive/Pacmania.otf') format('opentype'); font-display: swap; }
@font-face { font-family: 'Popstars';      src: url('assets/fonts/archive/POPSTARS.TTF') format('truetype'); font-display: swap; }
@font-face { font-family: 'QuakerShaker';  src: url('assets/fonts/archive/Quaker%20Shaker.ttf') format('truetype'); font-display: swap; }
@font-face { font-family: 'Rosethorns';    src: url('assets/fonts/archive/ROSETHORNS.ttf') format('truetype'); font-display: swap; }
@font-face { font-family: 'SlimeExtra';    src: url('assets/fonts/archive/SLIME%20EXTRA%20PERSONAL%20USE.ttf') format('truetype'); font-display: swap; }
@font-face { font-family: 'Slime';         src: url('assets/fonts/archive/SLIME%20PERSONAL%20USE.ttf') format('truetype'); font-display: swap; }
@font-face { font-family: 'UrbanOil';      src: url('assets/fonts/archive/Urban%20Oil%20Typeface(Personal%20Use).otf') format('opentype'); font-display: swap; }
@font-face { font-family: 'WatchBreaker';  src: url('assets/fonts/archive/WatchBreaker.ttf') format('truetype'); font-display: swap; }

/* Logo DRUMB — texte rendu avec la font evol, ancré au-dessus des knobs X/Y/OCC.
   Transit smooth entre expanded (~44px) et collapsed (~18px) : font-size,
   letter-spacing et padding se rétractent ensemble pour donner l'effet d'un
   logo qui "se ramasse" vers le haut de la mini-sidebar. */
.drumb-logo > span {
  display: inline-block;
  font-family: inherit;
  transition: font-family 200ms ease;
}
.drumb-logo {
  width: 100%;
  text-align: center;
  padding: 6px 4px 4px;
  flex-shrink: 0;
  font-family: 'Evol', monospace;
  font-size: 44px;
  line-height: 0.9;
  letter-spacing: 0.06em;
  color: #c7ff2e;
  text-shadow: 0 0 8px rgba(199, 255, 46, 0.35), 0 2px 0 rgba(0, 0, 0, 0.8);
  user-select: none;
  pointer-events: none;
  text-transform: uppercase;
  overflow: hidden;
  white-space: nowrap;
  transition:
    font-size 320ms cubic-bezier(0.2, 0.7, 0.2, 1),
    letter-spacing 320ms cubic-bezier(0.2, 0.7, 0.2, 1),
    padding 320ms cubic-bezier(0.2, 0.7, 0.2, 1),
    text-shadow 320ms ease;
}
/* En mode kit browser collapsed : logo réduit, lettres serrées, padding minimal.
   Devient cliquable (= bouton d'expansion). */
.kit-browser.collapsed .drumb-logo {
  font-size: 17px;
  letter-spacing: 0.02em;
  padding: 4px 2px 2px;
  text-shadow: 0 0 4px rgba(199, 255, 46, 0.45), 0 1px 0 rgba(0, 0, 0, 0.8);
  pointer-events: auto;
  cursor: pointer;
}
.kit-browser.collapsed .drumb-logo:hover {
  color: #d8ff66;
  text-shadow: 0 0 10px rgba(199, 255, 46, 0.85), 0 1px 0 rgba(0, 0, 0, 0.8);
  transform: scale(1.05);
}

/* ============================================================================
   FILMSTRIP KNOBS — X / Y / OCC en haut de la colonne gauche.
   PNG HISE 180×23040 = 128 frames de 180×180. background-size: 100% 12800%
   pour que 1 frame remplisse exactement la div ; background-position-y déplace
   le filmstrip selon la valeur (cf. setFilmstripKnob côté JS).
   ============================================================================ */
.session-knobs-xy {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: space-around;
  gap: 4px;
  padding: 4px;
  /* Override le style "session-knobs" générique : pas de fond/bordure pour
     les knobs X/Y/OCC — juste les knobs flottants sur le fond du kit-browser. */
  background: none !important;
  border: none !important;
  border-radius: 0 !important;
}
.filmstrip-knob-wrap {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  flex: 1 1 0;
  min-width: 0;
}
.filmstrip-knob-top {
  font-size: 11px;
  letter-spacing: 0.22em;
  color: #c7ff2e;
  text-shadow: 0 0 4px rgba(199, 255, 46, 0.45);
  text-transform: uppercase;
  font-weight: 700;
}
.filmstrip-knob {
  position: relative;
  width: 64px;
  height: 64px;
  max-width: 100%;
  /* Knob généré en CSS — pas de PNG. Style sombre métallique inspiré HISE :
       1) gradient radial du centre clair vers bord sombre
       2) gradient linéaire du haut clair vers bas sombre (lumière simulée)
       3) inset shadow pour la profondeur (cuvette légère) */
  background:
    radial-gradient(circle at 50% 38%, rgba(255, 255, 255, 0.08), transparent 50%),
    linear-gradient(180deg, #2a2a30 0%, #0d0d12 100%);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.08),
    inset 0 -2px 4px rgba(0, 0, 0, 0.6),
    inset 0 0 0 1px rgba(0, 0, 0, 0.5),
    0 2px 4px rgba(0, 0, 0, 0.55);
  cursor: ns-resize;
  border-radius: 50%;
  /* --knob-rot est mis à jour par setFilmstripKnob côté JS : -135deg (val=0)
     → +135deg (val=1), range 270deg = typique d'un potard rotatif. */
  --knob-rot: -135deg;
  transition: filter 120ms ease, transform 120ms ease, box-shadow 120ms ease;
  flex-shrink: 0;
}
/* Indicateur (le "petit pointeur" sur le knob) : trait fin sombre qui pointe
   la position courante. Sous l'arc lime, donc on le voit en superposition. */
.filmstrip-knob::after {
  content: '';
  position: absolute;
  left: 50%;
  top: 50%;
  width: 2px;
  height: 34%;
  margin-left: -1px;
  background: linear-gradient(180deg, #c7ff2e 0%, #8aa01a 100%);
  border-radius: 1px;
  transform-origin: 50% 100%;
  transform: translate(0, -100%) rotate(var(--knob-rot));
  box-shadow: 0 0 3px rgba(199, 255, 46, 0.7);
  pointer-events: none;
  z-index: 2;
}
/* Jauge SVG : arc lime-DRUMB qui se remplit autour du knob jusqu'à la
   position courante. Comme les knobs FX/OCC/LFO en haut à droite. */
.filmstrip-knob-arc {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  pointer-events: none;
}
.filmstrip-knob-arc path {
  fill: none;
  stroke: #c7ff2e;
  stroke-width: 3;
  stroke-linecap: round;
  filter: drop-shadow(0 0 4px rgba(199, 255, 46, 0.55));
  transition: stroke 120ms ease;
}
.filmstrip-knob:hover {
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.12),
    inset 0 -2px 4px rgba(0, 0, 0, 0.6),
    inset 0 0 0 1px rgba(199, 255, 46, 0.25),
    0 2px 6px rgba(0, 0, 0, 0.6),
    0 0 8px rgba(199, 255, 46, 0.2);
}
.filmstrip-knob:active {
  cursor: grabbing;
  transform: scale(0.97);
}
.filmstrip-knob:hover .filmstrip-knob-arc path {
  filter: drop-shadow(0 0 6px rgba(199, 255, 46, 0.9));
}

/* État LFO-assigned : tout passe en couleur LFO (magenta). Le cursor reste à
   la position BASE (cf. renderKnobs côté JS) pour ne pas jitter visuellement. */
.filmstrip-knob.lfo-assigned::after {
  background: linear-gradient(180deg, #ff3aa5 0%, #a01a6a 100%);
  box-shadow: 0 0 4px rgba(255, 58, 165, 0.75);
}
.filmstrip-knob.lfo-assigned .filmstrip-knob-arc path {
  stroke: var(--magenta);
  filter: drop-shadow(0 0 4px rgba(255, 58, 165, 0.55));
}
.filmstrip-knob.lfo-assigned:hover {
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.12),
    inset 0 -2px 4px rgba(0, 0, 0, 0.6),
    inset 0 0 0 1px rgba(255, 58, 165, 0.4),
    0 2px 6px rgba(0, 0, 0, 0.6),
    0 0 8px rgba(255, 58, 165, 0.3);
}
.filmstrip-knob.lfo-assigned:hover .filmstrip-knob-arc path {
  filter: drop-shadow(0 0 6px rgba(255, 58, 165, 0.9));
}
/* Top label X/Y/OCC passe aussi en magenta quand le knob est LFO-assigned.
   :has() permet de styler le label (sibling AVANT) en fonction du .lfo-assigned. */
.filmstrip-knob-wrap:has(.filmstrip-knob.lfo-assigned) .filmstrip-knob-top {
  color: var(--magenta);
  text-shadow: 0 0 4px rgba(255, 58, 165, 0.55);
}
.filmstrip-knob:active {
  cursor: grabbing;
  transform: scale(0.97);
}
.filmstrip-knob.lfo-assigned {
  filter: drop-shadow(0 0 6px rgba(255, 58, 165, 0.6));
}
.filmstrip-knob-value {
  font-size: 11px;
  font-weight: 700;
  color: #ffffff;
  font-variant-numeric: tabular-nums;
  min-height: 12px;
}
/* COLLAPSED : stack vertical des 3 knobs. Parent fait ~195px de haut, donc on
   distribue 3 knobs avec leur label top + value bottom dans cette zone. */
.kit-browser.collapsed .session-knobs-xy {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-around;
  gap: 4px;
  width: 100%;
  height: 100%;
  padding: 2px 0;
  box-sizing: border-box;
}
.kit-browser.collapsed .filmstrip-knob-wrap {
  flex: 0 0 auto;
  gap: 1px;
}
.kit-browser.collapsed .filmstrip-knob {
  width: 44px;
  height: 44px;
}
.kit-browser.collapsed .filmstrip-knob-top {
  font-size: 7px;
  letter-spacing: 0.2em;
}
.kit-browser.collapsed .filmstrip-knob-value {
  font-size: 9px;
  min-height: 10px;
}

/* Bloc knobs session — haut de la bande gauche (X/Y/OCC) et haut de la
   bande droite (FX), au-dessus de la palette FX. */
.session-knobs {
  width: 100%;
  padding: 6px 4px;
  background: rgba(12, 12, 20, 0.5);
  border: 1px solid var(--border);
  border-radius: 4px;
  flex-shrink: 0;
}
.session-knobs svg {
  display: block;
  width: 100%;
  height: auto;
  max-height: 88px;
}
/* Stage FX + OCC : 2 SVGs séparés flex côte-à-côte (horizontal toujours,
   même en mode collapsed) pour garantir l'absence de chevauchement. */
.session-knobs-fx {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  gap: 8px;
}
.session-knobs-fx > svg {
  flex: 1 1 50%;
  width: auto;
  height: auto;
  max-height: 80px;
  min-width: 0;
}
.right-rack.collapsed .session-knobs-fx {
  flex-direction: row;
  gap: 4px;
}
.right-rack.collapsed .session-knobs-fx > svg {
  max-height: 60px;
}

/* Right rack : bande latérale droite, pleine hauteur de la page. Empile FX
   palette + LFO panel verticalement. Border-left = séparateur visuel du centre. */
.right-rack {
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-width: 0;
  overflow-y: auto;
  border-left: 1px solid var(--border);
  padding: 8px 0 8px 10px;
  /* Stacking : au-dessus du patch-bay (z=5) pour masquer les câbles qui
     traversent visuellement la colonne (e.g. modules dans le canvas vers
     les LFOs encore attachés au rack). */
  position: relative;
  z-index: 7;
  background: var(--bg);
}

/* ============================================================
   RIGHT RACK — RETRACT / EXPAND
   ============================================================ */
.right-rack-toggle {
  position: absolute;
  top: 4px;
  left: 4px;
  width: 18px;
  height: 18px;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: 50%;
  color: var(--text-dim);
  font-size: 10px;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  z-index: 10;
  transition: all 200ms ease;
}
.right-rack-toggle:hover {
  border-color: var(--accent-dim);
  color: var(--accent);
  box-shadow: 0 0 8px rgba(0, 240, 255, 0.4);
  transform: scale(1.15);
}
.right-rack-toggle-arrow {
  display: inline-block;
  transition: transform 380ms cubic-bezier(0.65, 0.05, 0.36, 1);
}
.right-rack.collapsed .right-rack-toggle-arrow {
  transform: rotate(180deg);
}

.right-rack.collapsed {
  padding: 8px 4px;
  align-items: center;
  gap: 6px;
  overflow-y: auto;
  overflow-x: hidden;
}

/* Knob FX en collapsed : big, prend toute la largeur de la col 88px */
.right-rack.collapsed .session-knobs {
  margin-top: 22px;
  padding: 0;
  width: 100%;
  height: 110px;
  min-height: 110px;
  max-height: 110px;
  flex-shrink: 0;
  flex-grow: 0;
  background: none;
  border: none;
  box-shadow: none;
}
.right-rack.collapsed .session-knobs #stage-fx,
.right-rack.collapsed .session-knobs svg {
  width: 100%;
  height: 110px;
  max-height: 110px;
  display: block;
}

/* FX palette en collapsed : cellules en colonne, chip + chance + VU vertical */
.right-rack.collapsed .fx-palette-row {
  flex-direction: column;
  gap: 4px;
  padding: 0 2px;
  width: 100%;
  align-items: center;
  border: none;
}
.right-rack.collapsed .fx-palette-label {
  display: none;
}
.right-rack.collapsed .fx-add-btn {
  width: 100%;
  margin: 2px 0;
}
.right-rack.collapsed .fx-add-menu {
  /* Le menu reste positionné absolument et fonctionne normalement */
  left: auto !important;
  right: 100%;
  margin-right: 4px;
}
.right-rack.collapsed .fx-cells-container {
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 4px;
  flex: 0 0 auto;
}
/* Chaque FX cell en collapsed : compact (chip + remove uniquement, sliders cachés) */
.right-rack.collapsed .fx-global-cell {
  width: 100%;
  min-width: 0;
}
.right-rack.collapsed .fx-cell-row-dense {
  padding: 1px;
  justify-content: center;
}
/* PAS de resize sur le chip → garde sa taille d'origine, juste replacé */
.right-rack.collapsed .fx-cell-row-dense .fx-all-btn,
.right-rack.collapsed .fx-cell-row-dense .slider.fxc,
.right-rack.collapsed .fx-cell-row-dense .slider.fxv,
.right-rack.collapsed .fx-cell-row-dense .fx-cell-vu-vert,
.right-rack.collapsed .fx-cell-row-dense .fx-cell-vu-spacer,
.right-rack.collapsed .fx-cell-row-dense .fx-cell-remove {
  display: none;
}
/* ALT cell, params panels, et le bouton CLR LFO sont cachés en collapsed */
.right-rack.collapsed .fx-alt-cell,
.right-rack.collapsed .lfo-clear-all,
.right-rack.collapsed .fxp-slot {
  display: none;
}

/* LFO stack en collapsed : chaque LFO réduit (chip + preview waveform compact) */
.right-rack.collapsed .lfo-stack {
  width: 100%;
  gap: 4px;
}
.right-rack.collapsed .lfo-stack .mod-section {
  padding: 3px 2px;
}
.right-rack.collapsed .lfo-stack .lfo-header {
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: 0;
}
/* Cache les selects + sliders détaillés des LFOs en collapsed — on garde le
   chip drag (l'élément qu'on drop sur les params) et la preview waveform. */
.right-rack.collapsed .lfo-stack .mod-rows,
.right-rack.collapsed .lfo-stack .mod-line .mod-line-label,
.right-rack.collapsed .lfo-stack .lfo-toggle-btn,
.right-rack.collapsed .lfo-stack .lfo-detach-btn,
.right-rack.collapsed .lfo-stack .lfo-rate-select,
.right-rack.collapsed .lfo-stack .lfo-shape-select {
  display: none;
}
.right-rack.collapsed .lfo-stack .lfo-preview {
  width: 100%;
  height: 22px;
}
.right-rack.collapsed .lfo-stack .fx-chip.lfo-source {
  width: 100%;
  font-size: 9px;
  text-align: center;
  padding: 3px 0;
}

/* Master bus en collapsed : VU vertical + bouton MIXER, reste caché */
.right-rack.collapsed .master-box {
  width: 100%;
  padding: 6px 4px;
  flex-shrink: 0;
  margin-top: auto;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: 4px;
  box-sizing: border-box;
  /* + long verticalement pour bien afficher les VU */
  min-height: 240px;
}
.right-rack.collapsed .master-box-header {
  flex-direction: column;
  gap: 4px;
  padding: 0 0 4px;
  border-bottom: 1px solid rgba(255,255,255,0.06);
  margin-bottom: 4px;
}
.right-rack.collapsed .master-box-title {
  font-size: 7px;
  letter-spacing: 0.18em;
  text-align: center;
  color: var(--text-dim);
}
.right-rack.collapsed .master-box-mixer-btn {
  width: 100%;
  font-size: 8px;
  padding: 4px 0;
  letter-spacing: 0.15em;
}
.right-rack.collapsed .master-widget {
  width: 100%;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  flex: 1;
  display: flex;
}
/* VU stéréo VERTICAL : 2 barres côte à côte, GROSSES et BIEN VISIBLES.
   Hauteur ~ 170px pour qu'on voie l'évolution des niveaux clairement. */
.right-rack.collapsed .master-vu-stereo {
  flex-direction: row;
  gap: 6px;
  width: 100%;
  height: 170px;
  align-items: stretch;
  justify-content: center;
  padding: 0 4px;
  box-sizing: border-box;
}
.right-rack.collapsed .master-vu-stereo .master-vu-row {
  flex-direction: column;
  flex: 1;
  height: 100%;
  align-items: center;
  gap: 3px;
  max-width: 28px;
}
.right-rack.collapsed .master-vu-stereo .master-vu-label {
  font-size: 8px;
  margin-bottom: 0;
  color: var(--text-dim);
  letter-spacing: 0.1em;
  font-weight: 700;
  flex: 0 0 auto;
}
.right-rack.collapsed .master-vu-stereo .master-vu-track {
  flex: 1;
  width: 14px;                 /* plus large = mieux visible */
  height: auto;
  min-height: 140px;
  position: relative;
  background: rgba(0, 0, 0, 0.6);
  border: 1px solid var(--border);
  border-radius: 3px;
  overflow: hidden;
  box-shadow: inset 0 0 4px rgba(0, 0, 0, 0.8);
}
/* master-vu-fill garde son inset:0 + clip-path basé sur --vu-level → bottom-up
   automatiquement avec le clip top du système existant. Pas besoin d'override. */
.right-rack.collapsed .master-vol-host,
.right-rack.collapsed .master-box-body {
  display: none;
}
.stage-wrap {
  min-width: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}
#stage {
  display: block;
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: 100%;
}

/* ---------- KIT BROWSER (bande latérale gauche, pleine hauteur) ---------- */
.kit-browser {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 8px 10px 8px 0;
  border-right: 1px solid var(--border);
  min-height: 0;
  max-height: 100%;
  overflow: hidden;          /* colonne strictement bornée */
  font-size: 10px;
  letter-spacing: 0.08em;
  /* Stacking : au-dessus du patch-bay (z=5) pour masquer les câbles qui
     traversent visuellement la colonne (e.g. SEQ → synth dans le canvas). */
  position: relative;
  z-index: 7;
  background: var(--bg);
}

/* ============================================================
   COLONNE GAUCHE — RETRACT / EXPAND
   ============================================================ */
/* Bouton toggle : pastille discrète positionnée en haut à droite de la
   colonne, qui retract/expand l'ensemble. Fixée pour qu'on puisse toujours
   l'atteindre même en mode collapsed (56px). */
.kit-browser-toggle {
  position: absolute;
  /* Ancré sous le logo DRUMB pour ne plus le chevaucher. Top transit en sync
     avec la rétractation du logo (44px expanded → 17px collapsed). */
  top: 60px;
  right: 4px;
  width: 18px;
  height: 18px;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: 50%;
  color: var(--text-dim);
  font-size: 10px;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  z-index: 10;
  transition: top 320ms cubic-bezier(0.2, 0.7, 0.2, 1),
              right 320ms cubic-bezier(0.2, 0.7, 0.2, 1),
              border-color 200ms ease,
              color 200ms ease,
              box-shadow 200ms ease,
              transform 200ms ease;
}
.kit-browser.collapsed .kit-browser-toggle {
  /* Caché en mode collapsed : le logo lui-même devient le bouton d'expansion. */
  display: none;
}
.kit-browser-toggle:hover {
  border-color: var(--accent-dim);
  color: var(--accent);
  box-shadow: 0 0 8px rgba(0, 240, 255, 0.4);
  transform: scale(1.15);
}
.kit-browser-toggle-arrow {
  display: inline-block;
  transition: transform 380ms cubic-bezier(0.65, 0.05, 0.36, 1);
}
.kit-browser.collapsed .kit-browser-toggle-arrow {
  transform: rotate(180deg);
}

/* État COLLAPSED — animation de retrait fluide.
   Stratégie : la grille (#app) anime grid-template-columns ; à l'intérieur
   chaque enfant fade + slide légèrement vers la gauche. Les enfants masqués
   sont retirés du flux avec display:none APRÈS la fin de la transition
   (sinon ils sautent visuellement). */
.kit-browser.collapsed {
  /* Padding HORIZONTAL uniforme : tous les enfants partagent les mêmes
     marges de 6px de chaque côté → centrage parfait. */
  padding: 8px 6px;
  align-items: center;
  gap: 6px;
  min-width: 0;
  width: 100%;
  box-sizing: border-box;
}
/* Tous les enfants visibles (sauf session-knobs qui escape via neg margin)
   fillent la colonne pour éviter tout offset horizontal */
.kit-browser.collapsed > .sidebar-transport,
.kit-browser.collapsed > .seq-box-sidebar,
.kit-browser.collapsed > .transport-bottom {
  width: 100%;
  box-sizing: border-box;
  margin-left: 0 !important;
  margin-right: 0 !important;
  flex-shrink: 0;
  flex-grow: 0;
}
.kit-browser.collapsed > .session-knobs {
  flex-shrink: 0;
  flex-grow: 0;
}
/* Tue le flex-grow des éléments cachés pour qu'ils n'occupent aucune place
   verticale (sinon le kit-list flex: 1 1 auto bouffe l'espace même collapse). */
.kit-browser.collapsed .kit-list,
.kit-browser.collapsed .kit-search,
.kit-browser.collapsed .kit-load-bar,
.kit-browser.collapsed .preset-row {
  flex: 0 0 0 !important;
}
/* Enfants à cacher en mode mini : SLIDENT vers la gauche + fade + squeeze
   vertical. Combiné, ça donne l'effet "ils se rangent vers la gauche jusqu'à
   disparaître", pas juste un fade froid. */
.kit-browser.collapsed .kit-search,
.kit-browser.collapsed .kit-load-bar,
.kit-browser.collapsed .kit-list,
.kit-browser.collapsed .preset-row,
.kit-browser.collapsed .seq-box-body,
.kit-browser.collapsed .auto-btn,
.kit-browser.collapsed .melody-mode,
.kit-browser.collapsed .melody-enable,
.kit-browser.collapsed .dice-label,
.kit-browser.collapsed .transport-play-label,
.kit-browser.collapsed .transport-rec-label {
  opacity: 0;
  /* Pixel-based translate (pas % qui dépend de la width — qui change avec
     la col en même temps). -300px garantit que l'élément sort entièrement à
     gauche, peu importe sa largeur courante. */
  transform: translateX(-300px);
  pointer-events: none;
  max-height: 0;
  overflow: hidden;
  padding-top: 0 !important;
  padding-bottom: 0 !important;
  margin-top: 0 !important;
  margin-bottom: 0 !important;
  border-width: 0 !important;
  /* Slide-out long et visible (600ms) avec opacity synchro. La squeeze
     verticale (max-height) ne démarre qu'APRÈS la fin du slide (delay 600ms). */
  transition:
    opacity 600ms cubic-bezier(0.55, 0.0, 0.5, 1.0),
    transform 600ms cubic-bezier(0.55, 0.0, 0.5, 1.0),
    max-height 280ms cubic-bezier(0.65, 0.05, 0.36, 1) 600ms,
    padding 280ms cubic-bezier(0.65, 0.05, 0.36, 1) 600ms,
    margin 280ms cubic-bezier(0.65, 0.05, 0.36, 1) 600ms;
}
/* Réciproque : éléments visibles ré-apparaissent à l'expand → slident depuis
   la gauche avec overshoot, max-height s'ouvre en premier puis fade-in. */
.kit-browser .kit-search,
.kit-browser .kit-load-bar,
.kit-browser .kit-list,
.kit-browser .preset-row,
.kit-browser .seq-box-body,
.kit-browser .auto-btn,
.kit-browser .melody-mode,
.kit-browser .melody-enable,
.kit-browser .dice-label,
.kit-browser .transport-play-label,
.kit-browser .transport-rec-label {
  max-height: 999px;
  transform: translateX(0);
  transition:
    opacity 300ms ease-in 220ms,
    transform 540ms cubic-bezier(0.34, 1.56, 0.64, 1) 80ms,
    max-height 460ms cubic-bezier(0.65, 0.05, 0.36, 1);
}

/* Stagger top→bottom : chaque ligne part avec un petit décalage pour donner
   un effet "domino" quand on retracte. Format = opacity, transform, max-height,
   padding, margin. La max-height a une base delay de 240ms (laisser le slide
   se finir) + le stagger de l'élément. */
.kit-browser.collapsed .kit-search       { transition-delay: 0ms,   0ms,   600ms, 600ms, 600ms; }
.kit-browser.collapsed .kit-load-bar     { transition-delay: 50ms,  50ms,  650ms, 650ms, 650ms; }
.kit-browser.collapsed .kit-list         { transition-delay: 100ms, 100ms, 700ms, 700ms, 700ms; }
.kit-browser.collapsed .seq-box-body     { transition-delay: 150ms, 150ms, 750ms, 750ms, 750ms; }
.kit-browser.collapsed .preset-row       { transition-delay: 200ms, 200ms, 800ms, 800ms, 800ms; }
.kit-browser.collapsed .auto-btn         { transition-delay: 0ms,   0ms,   500ms, 500ms, 500ms; }
.kit-browser.collapsed .transport-play-label,
.kit-browser.collapsed .transport-rec-label {
  transition-delay: 250ms, 250ms, 850ms, 850ms, 850ms;
}
/* Stagger inverse à l'expand : du bas vers le haut (les élements du bas
   ré-apparaissent en premier pour révéler progressivement la sidebar). */
.kit-browser:not(.collapsed) .preset-row     { transition-delay: 100ms, 100ms, 100ms; }
.kit-browser:not(.collapsed) .seq-box-body   { transition-delay: 140ms, 140ms, 140ms; }
.kit-browser:not(.collapsed) .kit-list       { transition-delay: 180ms, 180ms, 180ms; }
.kit-browser:not(.collapsed) .kit-load-bar   { transition-delay: 220ms, 220ms, 220ms; }
.kit-browser:not(.collapsed) .kit-search     { transition-delay: 260ms, 260ms, 260ms; }

/* === SESSION KNOBS (X / Y / OCC) en mode collapsed ===
   SVG passe d'un format paysage (240×90) à portrait (64×220) via JS.
   Encadré subtil cyan pour signaler qu'ils sont actifs. */
.kit-browser .session-knobs {
  transition: max-height 480ms cubic-bezier(0.65, 0.05, 0.36, 1),
              padding 380ms ease,
              margin 380ms ease;
}
/* Knobs en collapsed : pas de container/cadre — juste le SVG nu, taille
   identique à l'expanded (outerR=34, diamètre 68px). */
.kit-browser.collapsed .session-knobs {
  margin-top: 22px;          /* sous le bouton toggle */
  margin-left: -6px;         /* escape le padding horizontal du kit-browser */
  margin-right: -6px;        /* → SVG spanne la FULL col, pas réduite par padding */
  padding: 0;
  width: calc(100% + 12px);
  height: 195px;
  min-height: 195px;
  max-height: 195px;
  flex-shrink: 0;              /* essentiel : kit-browser flex column shrinkrait sinon */
  flex-grow: 0;
  background: none;
  border: none;
  box-shadow: none;
  position: relative;
  overflow: visible;
}
.kit-browser.collapsed .session-knobs #stage-xy,
.kit-browser.collapsed .session-knobs svg {
  width: 100%;
  height: 100%;
  max-height: 100%;            /* override le cap 88px du selector global */
  display: block;
  overflow: visible;
}

/* === DICE/SMPL/KIT en mode collapsed : boutons carrés icon-only.
   Les 3 dice-groups passent de 3-cols → 1-col (transition de grid-template-
   columns native). Le label est caché → seul l'icône reste, bouton carré. */
.kit-browser .sidebar-transport {
  transition: grid-template-columns 460ms cubic-bezier(0.65, 0.05, 0.36, 1);
}
.kit-browser.collapsed .sidebar-transport {
  grid-template-columns: 1fr;
  padding: 4px 0 2px;              /* horizontal padding hérité du parent kit-browser */
  width: 100%;
  box-sizing: border-box;
}
.kit-browser.collapsed .sidebar-transport .dice-group {
  width: 100%;
  align-items: stretch;            /* le bouton stretch sur toute la dice-group */
}
.kit-browser.collapsed .sidebar-transport .btn.big {
  /* Stretché sur la col (56 - 6×2 = 44px), icône strictement centrée */
  width: 100%;
  height: 34px;
  padding: 0 !important;           /* override .sidebar-transport .btn.big padding */
  margin: 0;
  display: flex !important;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  gap: 0 !important;
  position: relative;
  text-align: center;
  box-sizing: border-box;
}
.kit-browser.collapsed .sidebar-transport .btn.big .dice-icon {
  font-size: 16px;
  line-height: 1;
  display: block;
  margin: 0;
  text-align: center;
}
/* Sort le label du flex flow → l'icône reste seul et centré dans le carré. */
.kit-browser.collapsed .sidebar-transport .btn.big .dice-label {
  position: absolute;
  left: 0;
  top: 0;
  margin: 0 !important;
}

/* SEQ NOTES en collapsed : box réduite mais style original conservé,
   titre vertical pour gagner de la place, port-out toujours accessible. */
.kit-browser.collapsed .seq-box-sidebar {
  padding: 4px;
  width: 100%;                     /* margin horizontal hérité du kit-browser */
  margin: 0;
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  min-height: 70px;
  max-height: 100px;
  box-sizing: border-box;
  flex-shrink: 0;
}

/* En collapsed : seq-box-body reste visible mais on ne garde QUE les selects
   ROOT et SCALE — le canvas, octave/len, et les boutons d'action sont cachés.
   Les vrais <select> sont conservés donc le système LFO (data-mod-key) marche
   tel quel et la modulation est visible. */
.seq-box-title {
  transition: opacity 220ms ease;
}
.kit-browser.collapsed .seq-box-title {
  opacity: 0;
  pointer-events: none;
}
.kit-browser.collapsed .seq-box-header {
  min-height: 0;
  padding: 0;
  border-bottom: none;
}
/* Override le hide global de .seq-box-body : on le réaffiche en collapsed
   (mais uniquement pour les fields melody-root et melody-scale). */
.kit-browser.collapsed .seq-box-sidebar .seq-box-body {
  opacity: 1 !important;
  transform: none !important;
  pointer-events: auto !important;
  max-height: none !important;
  padding: 4px 0 2px !important;
  margin: 0 !important;
  border-width: 0 !important;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  width: 100%;
  transition: opacity 260ms ease 80ms;
}
/* Cache tout dans le body SAUF la grid melody (qui contient root/scale) */
.kit-browser.collapsed .seq-box-body > .bass-box-row-melody-actions,
.kit-browser.collapsed .seq-box-body > .melody-canvas-wrap {
  display: none;
}
/* Grid en 1 col, gap réduit, taille fit content */
.kit-browser.collapsed .seq-box-body .bass-box-grid-melody {
  display: flex;
  flex-direction: column;
  gap: 4px;
  width: 100%;
  padding: 0;
  margin: 0;
}
/* Chaque melody-field = un petit "card" centré (label tiny + value big) */
.kit-browser.collapsed .seq-box-body .melody-field {
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0;
  padding: 0;
  margin: 0;
  position: relative;
}
.kit-browser.collapsed .seq-box-body .melody-field > span {
  font-size: 6px;
  letter-spacing: 0.18em;
  color: var(--text-dim);
  text-transform: uppercase;
  font-weight: 600;
  line-height: 1;
  margin-bottom: 2px;
  opacity: 0.7;
}
/* Selects : appearance none → on supprime l'arrow natif (qui décentrait le texte).
   Centrage strict via text-align-center + padding égal des 2 côtés. */
.kit-browser.collapsed .seq-box-body .melody-field select {
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  width: 100%;
  background: transparent;
  border: none;
  outline: none;
  color: #d6a8ee;
  font-family: inherit;
  font-weight: 700;
  text-align: center;
  text-align-last: center;
  padding: 1px 0;
  cursor: pointer;
  text-shadow: 0 0 8px rgba(176, 122, 208, 0.55);
  line-height: 1;
  transition: color 140ms ease, text-shadow 140ms ease;
}
.kit-browser.collapsed .seq-box-body .melody-field select:hover {
  color: #e8c2f6;
  text-shadow: 0 0 12px rgba(176, 122, 208, 0.8);
}
.kit-browser.collapsed .seq-box-body #melody-root {
  font-size: 18px;
  letter-spacing: 0.05em;
}
.kit-browser.collapsed .seq-box-body #melody-scale {
  font-size: 9px;
  text-transform: lowercase;
  color: #a890b8;
  text-shadow: 0 0 4px rgba(176, 122, 208, 0.3);
  letter-spacing: 0.08em;
  font-weight: 600;
}
/* Hide OCT + LEN (uniquement root et scale visibles) */
.kit-browser.collapsed .seq-box-body .melody-field:nth-child(3),
.kit-browser.collapsed .seq-box-body .melody-field:nth-child(4) {
  display: none;
}
/* Style du seq-box-sidebar en collapsed : violet box plus polished */
.kit-browser.collapsed .seq-box-sidebar {
  padding: 6px 0 !important;
  background: linear-gradient(180deg, rgba(176, 122, 208, 0.08), rgba(60, 30, 80, 0.04)) !important;
  border: 1px solid rgba(176, 122, 208, 0.30) !important;
  border-radius: 6px !important;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.04), 0 2px 6px rgba(0,0,0,0.3) !important;
}
.kit-browser.collapsed .seq-box-header {
  padding: 2px;
  justify-content: center;
  border-bottom: none;
  flex: 1;
  gap: 0;
}
.kit-browser.collapsed .seq-box-title {
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  white-space: nowrap;
  text-align: center;
  flex: none;
}
.kit-browser.collapsed .seq-box-sidebar .module-port-out[data-port-side="right"] {
  opacity: 1;
  top: 50%;
  right: 1px;
  transform: translateY(-50%);
}

/* TRANSPORT en collapsed : PLAY + REC en colonne au lieu de grid 2-cols.
   Conserve le style original des boutons (rectangulaire icon + label). */
.kit-browser .transport-bottom {
  transition: grid-template-columns 460ms cubic-bezier(0.65, 0.05, 0.36, 1),
              gap 400ms ease;
}
/* Transport pinned au bas du kit-browser via position absolute → garantie
   d'être TOUJOURS visible, jamais cropped par overflow:hidden ou squeeze
   flex. Le kit-browser a position: relative donc l'ancrage marche. */
.kit-browser.collapsed .transport-bottom {
  position: absolute;
  bottom: 8px;
  left: 6px;                /* aligné avec les autres composants (kit-browser padding 6px) */
  right: 6px;
  grid-template-columns: 1fr;
  margin: 0;
  padding: 0;
  gap: 4px;
  box-sizing: border-box;
  flex-shrink: 0;
  width: auto;
  background: transparent;
  border: none;
}
.kit-browser.collapsed .transport-bottom .transport-play,
.kit-browser.collapsed .transport-bottom .transport-rec {
  width: 100%;
  height: 32px;
  min-height: 32px;
  padding: 0 !important;
  margin: 0;
  display: flex !important;
  flex-direction: row !important;     /* override flex-direction: column de l'original */
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  gap: 0 !important;
  position: relative;
  overflow: hidden;
  min-width: 0;
  flex-shrink: 0;
}
/* Sort les labels du flex flow → icône strictement centrée */
.kit-browser.collapsed .transport-bottom .transport-play-label,
.kit-browser.collapsed .transport-bottom .transport-rec-label {
  position: absolute;
  left: 0;
  top: 0;
  margin: 0 !important;
}
.kit-browser.collapsed .transport-bottom .transport-play-icon {
  font-size: 14px;
  line-height: 1;
  margin: 0;
}
.kit-browser.collapsed .transport-bottom .transport-rec-dot {
  margin: 0;
}

/* Anim "wave" sur les enfants visibles pendant la retract — fait glisser
   chaque enfant légèrement vers la gauche puis re-position. Pure cosmetic
   pour donner du tactile. */
@keyframes left-col-collapse-wave {
  0%   { transform: translateX(0)    scale(1);   }
  40%  { transform: translateX(-4px) scale(0.96); }
  100% { transform: translateX(0)    scale(1);   }
}
@keyframes left-col-expand-wave {
  0%   { transform: translateX(-8px) scale(0.92); opacity: 0.0; }
  60%  { transform: translateX(2px)  scale(1.02); opacity: 1.0; }
  100% { transform: translateX(0)    scale(1);    opacity: 1.0; }
}
.kit-browser.kb-anim-collapse > *:not(.kit-browser-toggle) { animation: left-col-collapse-wave 460ms cubic-bezier(0.65, 0.05, 0.36, 1) both; }
.kit-browser.kb-anim-collapse > *:nth-child(2) { animation-delay:   0ms; }   /* session-knobs (X/Y/OCC) */
.kit-browser.kb-anim-collapse > *:nth-child(3) { animation-delay:  30ms; }   /* sidebar-transport (DICE/SMPL/KIT) */
.kit-browser.kb-anim-collapse > *:nth-child(4) { animation-delay:  60ms; }   /* kit-search */
.kit-browser.kb-anim-collapse > *:nth-child(5) { animation-delay:  90ms; }   /* kit-load-bar */
.kit-browser.kb-anim-collapse > *:nth-child(6) { animation-delay: 120ms; }   /* kit-list */
.kit-browser.kb-anim-collapse > *:nth-child(7) { animation-delay: 150ms; }   /* seq-box-sidebar */
.kit-browser.kb-anim-collapse > *:nth-child(8) { animation-delay: 180ms; }   /* preset-row */
.kit-browser.kb-anim-collapse > *:nth-child(9) { animation-delay: 210ms; }   /* transport-bottom */

.kit-browser.kb-anim-expand > *:not(.kit-browser-toggle) { animation: left-col-expand-wave 520ms cubic-bezier(0.34, 1.56, 0.64, 1) both; }
.kit-browser.kb-anim-expand > *:nth-child(2) { animation-delay:   0ms; }
.kit-browser.kb-anim-expand > *:nth-child(3) { animation-delay:  40ms; }
.kit-browser.kb-anim-expand > *:nth-child(4) { animation-delay:  80ms; }
.kit-browser.kb-anim-expand > *:nth-child(5) { animation-delay: 120ms; }
.kit-browser.kb-anim-expand > *:nth-child(6) { animation-delay: 160ms; }
.kit-browser.kb-anim-expand > *:nth-child(7) { animation-delay: 200ms; }
.kit-browser.kb-anim-expand > *:nth-child(8) { animation-delay: 240ms; }
.kit-browser.kb-anim-expand > *:nth-child(9) { animation-delay: 280ms; }


.kit-search input {
  width: 100%;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  color: var(--text);
  font-family: inherit;
  font-size: 10px;
  letter-spacing: 0.15em;
  padding: 6px 10px;
  border-radius: 3px;
}

.kit-load-bar {
  padding: 0;
}
#kit-load-btn {
  width: 100%;
  font-size: 9px;
  letter-spacing: 0.2em;
  padding: 5px 8px;
  color: #ffa84a;
  border-color: #8a5a2a;
  background: transparent;
  cursor: pointer;
}
#kit-load-btn:hover {
  border-color: #ffa84a;
  box-shadow: 0 0 8px rgba(255, 168, 74, 0.3);
}
.kit-search input::placeholder { color: var(--text-dim); }
.kit-search input:focus {
  outline: none;
  border-color: var(--accent-dim);
}

.kit-list {
  flex: 1 1 auto;
  overflow-y: auto;
  min-height: 0;
  padding-right: 4px;
}
.kit-list::-webkit-scrollbar       { width: 6px; }
.kit-list::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }
.kit-list::-webkit-scrollbar-thumb:hover { background: var(--accent-dim); }

.kit-item {
  border-bottom: 1px solid rgba(30, 30, 42, 0.5);
}
.kit-item-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 5px 6px;
  cursor: pointer;
  color: var(--text-dim);
  transition: color 140ms ease, background 140ms ease;
}
.kit-item-header:hover {
  color: var(--accent);
  background: rgba(0, 240, 255, 0.04);
}
.kit-item.open .kit-item-header {
  color: var(--accent);
  background: rgba(0, 240, 255, 0.08);
}
.kit-item-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  flex: 1;
}
.kit-item-count {
  font-size: 9px;
  color: var(--text-dim);
  margin-left: 6px;
}

.kit-samples {
  display: none;
  padding: 2px 0 6px 16px;
}
.kit-item.open .kit-samples { display: block; }

.kit-sample {
  padding: 3px 6px;
  font-size: 9px;
  color: var(--text-dim);
  cursor: grab;
  border-radius: 2px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  user-select: none;
  transition: color 120ms ease, background 120ms ease;
}
.kit-sample:hover {
  color: var(--accent);
  background: rgba(0, 240, 255, 0.06);
}
.kit-sample:active { cursor: grabbing; }

/* Lane strips deviennent drop-target pour les samples */
.lane-strip.drag-over-sample {
  border-color: #5fc080;
  background: rgba(95, 192, 128, 0.08);
  box-shadow: 0 0 10px rgba(95, 192, 128, 0.2);
}

/* Lane-board : piano-roll au-dessus + sidebar mixer en dessous, mêmes 8 cols
   pour aligner chaque strip sous son dot. Compact maximum : rangée du bas. */
.lane-board {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
  overflow: hidden;          /* contention horizontale stricte */
}
.lane-board .piano-roll,
.lane-board .sidebar {
  display: grid;
  /* minmax(0, 1fr) au lieu de juste 1fr → autorise les colonnes à shrinker
     en-dessous de leur min-content (sinon le grid s'expand jusqu'à pouvoir
     contenir le plus large enfant, ce qui débordait la rack). */
  grid-template-columns: repeat(8, minmax(0, 1fr));
  gap: 3px;
  padding: 3px 6px;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: 3px;
  min-width: 0;
  overflow: hidden;
}
/* Lane cell : 2 boîtes empilées — VU fader au-dessus (étroit + centré),
   labels (kit + sample) dans leur propre carré en dessous (pleine largeur). */
.lane-board .pr-cell {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  min-width: 0;
  position: relative;       /* ancrage du port trig OUT en haut */
}

/* Box VU = fader vertical du volume style Ableton — étroite, haute, centrée.
   Drag dessus → adjust volume. LFO-droppable via data-mod-key. */
.lane-board .pr-vu {
  position: relative;
  width: 22px;
  height: 80px;
  background: rgba(12, 12, 20, 0.85);
  border: 1px solid #2a2a3a;
  border-radius: 3px;
  overflow: hidden;
  cursor: ns-resize;
  user-select: none;
  flex-shrink: 0;
}
.lane-board .pr-vu:hover {
  border-color: var(--accent-dim);
}
/* LFO assigné → outline magenta pour signaler la modulation */
.lane-board .pr-vu.lfo-assigned {
  outline: 1px solid var(--magenta-dim);
  outline-offset: -1px;
  animation: pr-vu-lfo-pulse 1.6s ease-in-out infinite;
}
@keyframes pr-vu-lfo-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(255, 58, 165, 0); }
  50%      { box-shadow: 0 0 8px 1px rgba(255, 58, 165, 0.35); }
}
/* Fill = niveau audio temps réel. Reste à taille pleine (100% du track) avec
   gradient ancré aux niveaux ABSOLUS. clip-path révèle uniquement la portion
   basse jusqu'au niveau --vu-level (0..100). Volume bas = signal bas =
   jaune/rouge invisibles puisque hors zone clippée. */
.lane-board .pr-vu-fill {
  position: absolute;
  inset: 0;
  --vu-level: 0;
  background: linear-gradient(to top,
    #5fc080 0%,   #5fc080 65%,
    #ffd84a 75%,  #ffd84a 86%,
    #ff3030 92%,  #ff3030 100%);
  clip-path: inset(calc((100 - var(--vu-level)) * 1%) 0 0 0);
  transition: clip-path 35ms ease-out;
  pointer-events: none;
}
/* Handle = curseur fader, position du volume slider (= max possible audio).
   Petit trait horizontal qui dépasse légèrement les bords pour la prise visuelle. */
.lane-board .pr-vu-handle {
  position: absolute;
  left: -3px;
  right: -3px;
  bottom: 0%;
  height: 3px;
  background: var(--accent);
  border-radius: 1px;
  transform: translateY(50%);
  box-shadow: 0 0 5px rgba(0, 240, 255, 0.85);
  pointer-events: none;
  transition: bottom 60ms ease-out;
  z-index: 2;
}
/* Glow déclenchement déplacé sur le carré du nom du sample (pr-label-box).
   Voir .lane-board .pr-label-box.firing plus bas. */

/* Box labels : kit (haut, dim) + sample basename (bas, gras) — full cell width.
   Reçoit le glow box cyan à chaque déclenchement (.firing). */
.lane-board .pr-label-box {
  align-self: stretch;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1px;
  padding: 3px 4px;
  background: rgba(18, 18, 26, 0.55);
  border: 1px solid var(--border);
  border-radius: 3px;
  min-height: 22px;
  min-width: 0;
  cursor: pointer;
  transition: border-color 140ms ease, background 140ms ease;
}
.lane-board .pr-label-box:hover {
  border-color: var(--accent-dim);
  background: rgba(0, 240, 255, 0.04);
}
/* Flash visuel au preview (kit-sample ET pr-label-box) */
.kit-sample.preview-flash,
.lane-board .pr-label-box.preview-flash {
  animation: sample-preview-flash 380ms ease-out;
}
@keyframes sample-preview-flash {
  0%   { background: rgba(0, 240, 255, 0.55); box-shadow: 0 0 12px 2px rgba(0, 240, 255, 0.6); }
  100% { background: rgba(18, 18, 26, 0.55); box-shadow: 0 0 0 0 rgba(0, 240, 255, 0); }
}
/* Synth box title : click pour preview (quand en pause). Hover indicator + flash */
.bass-box-title-main:hover {
  text-shadow: 0 0 6px currentColor;
  filter: brightness(1.3);
}
.bass-box-title-main.preview-flash {
  animation: title-preview-flash 420ms ease-out;
}
@keyframes title-preview-flash {
  0%   { text-shadow: 0 0 12px currentColor; filter: brightness(1.8); transform: scale(1.05); }
  100% { text-shadow: 0 0 0 currentColor;    filter: brightness(1);   transform: scale(1);    }
}
.lane-board .pr-label-box.firing {
  animation: pr-label-fire 380ms ease-out forwards;
}
@keyframes pr-label-fire {
  0%   { box-shadow: 0 0 14px 2px rgba(0, 240, 255, 0.85); border-color: var(--accent); }
  100% { box-shadow: 0 0 0   0   rgba(0, 240, 255, 0);     border-color: var(--border); }
}
.lane-board .pr-label-box.firing.fire-ghost  { animation-duration: 240ms; }
.lane-board .pr-label-box.firing.fire-normal { animation-duration: 320ms; }
.lane-board .pr-label-box.firing.fire-accent { animation-duration: 420ms; }
.lane-board .pr-label-kit,
.lane-board .pr-label {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.lane-board .pr-label-kit {
  font-size: 6px;
  letter-spacing: 0.1em;
  color: var(--text-dim);
  text-transform: uppercase;
  opacity: 0.85;
}
.lane-board .pr-label {
  font-size: 7px;
  letter-spacing: 0.08em;
  font-weight: 600;
  color: var(--text);
}

/* Strip mixer ultra-compact : pas de label name (déjà sous le dot), 4 sliders
   fins, mute mini, OCC -/+ avec valeur centrale, FX chips zone droppable. */
.lane-strip {
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding: 2px 3px;
  border: 1px solid var(--border);
  border-radius: 2px;
  background: rgba(18, 18, 26, 0.4);
  transition: opacity 160ms ease, border-color 160ms ease;
  min-width: 0;
  max-width: 100%;
  overflow: hidden;
}
/* Le name est déjà affiché dans le piano-roll au-dessus. */
.lane-strip .name { display: none; }
.lane-strip .slider { height: 10px; }
.lane-strip .slider .label { font-size: 7px; padding: 0 2px; letter-spacing: 0; }
.lane-strip .mute-btn { width: 10px; height: 10px; }
.solo-btn {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-dim);
  font-family: inherit;
  font-size: 8px;
  font-weight: 700;
  line-height: 1;
  width: 14px;
  height: 14px;
  padding: 0;
  border-radius: 2px;
  cursor: pointer;
  transition: all 120ms ease;
}
.solo-btn:hover { border-color: #ffd84a; color: #ffd84a; }
.solo-btn.active {
  background: rgba(255, 216, 74, 0.18);
  border-color: #ffd84a;
  color: #ffd84a;
  box-shadow: 0 0 6px rgba(255, 216, 74, 0.45);
}
/* Lane soloée : border jaune visible */
.lane-strip.soloed {
  border-color: #ffd84a;
  box-shadow: 0 0 6px rgba(255, 216, 74, 0.25);
}
/* Lane silenced par solo (= au moins un solo actif ailleurs) : opacité réduite */
.lane-strip.solo-silenced {
  opacity: 0.35;
}
.lane-strip-toggles {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
}
.choke-btn {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-dim);
  font-family: inherit;
  font-size: 8px;
  font-weight: 700;
  line-height: 1;
  width: 14px;
  height: 14px;
  padding: 0;
  border-radius: 2px;
  cursor: pointer;
  transition: all 120ms ease;
}
.choke-btn:hover { border-color: var(--accent-dim); color: var(--accent-dim); }
.choke-btn.active {
  border-color: var(--accent);
  color: var(--accent);
  background: rgba(0, 240, 255, 0.10);
  box-shadow: 0 0 4px rgba(0, 240, 255, 0.4);
}
/* Couleurs par groupe pour distinguer A/B/C/D visuellement */
.choke-btn[data-group="A"] { border-color: #ff3aa5; color: #ff3aa5; background: rgba(255,58,165,0.12); box-shadow: 0 0 4px rgba(255,58,165,0.4); }
.choke-btn[data-group="B"] { border-color: #ffa84a; color: #ffa84a; background: rgba(255,168,74,0.12); box-shadow: 0 0 4px rgba(255,168,74,0.4); }
.choke-btn[data-group="C"] { border-color: #5fc080; color: #5fc080; background: rgba(95,192,128,0.12); box-shadow: 0 0 4px rgba(95,192,128,0.4); }
.choke-btn[data-group="D"] { border-color: #00f0ff; color: #00f0ff; background: rgba(0,240,255,0.12); box-shadow: 0 0 4px rgba(0,240,255,0.4); }
.lane-strip-source { padding-top: 0; gap: 2px; }
.lane-occ-btn { font-size: 8px; padding: 0 3px; line-height: 1.1; }
.lane-occ-val { font-size: 7px; min-width: 14px; }
.lane-source-text { display: none; }      /* drop le texte source pour gagner de la place */
.lane-strip-fx { min-height: 2px; gap: 2px; }
.lane-fx-chip { padding: 0 2px; min-width: 0; }
.lane-fx-chip .name { display: inline; font-size: 7px; min-width: 0; }
.lane-fx-chip .slider.chance { height: 6px; }

/* Source row : −/+ OCC boost buttons + indicator + source text.
   Padding-bottom + border-bottom subtil pour la séparer visuellement
   de la zone FX en dessous. */
.lane-strip-source {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  gap: 3px;
  font-size: 8px;
  letter-spacing: 0.06em;
  color: var(--text-dim);
  padding: 2px 0 4px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.04);
}
.lane-source-text {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  pointer-events: none;
}
.lane-occ-btn {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-dim);
  font-family: inherit;
  font-size: 10px;
  font-weight: 700;
  line-height: 1;
  padding: 1px 5px;
  border-radius: 2px;
  cursor: pointer;
  transition: all 120ms ease;
}
.lane-occ-btn:hover {
  border-color: var(--accent);
  color: var(--accent);
}
.lane-occ-val {
  min-width: 22px;
  text-align: center;
  font-size: 8px;
  font-weight: 700;
  color: var(--text-dim);
}
.lane-occ-val.positive { color: #5fc080; }
.lane-occ-val.negative { color: var(--magenta); }

/* Row 3 : container dynamique de chips FX per-lane (drop target pour palette).
   Zone clairement séparée des boutons OCC (-/+) au-dessus + min-height suffisante
   pour que le placeholder "DROP FX HERE" tienne sur une ligne. */
.lane-strip-fx {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  gap: 3px;
  padding: 3px 4px;
  margin-top: 4px;
  min-height: 18px;
  border: 1px dashed rgba(255, 168, 74, 0.22);
  border-radius: 3px;
  background: rgba(0, 0, 0, 0.18);
  transition: background 140ms ease, box-shadow 140ms ease, border-color 140ms ease;
}
.lane-strip-fx:hover {
  border-color: rgba(255, 168, 74, 0.4);
}
.lane-strip-fx.drag-over-fx {
  background: rgba(255, 168, 74, 0.14);
  box-shadow: inset 0 0 0 1px #ffa84a;
  border-color: #ffa84a;
  border-style: solid;
}

/* Chip FX assigné à une lane : nom + slider chance + × */
.lane-fx-chip {
  display: flex;
  align-items: center;
  gap: 3px;
  padding: 1px 3px;
  border: 1px solid #8a5a2a;
  border-radius: 2px;
  background: rgba(255, 168, 74, 0.06);
  flex: 1 1 0;              /* basis 0 = shrinks complètement si nécessaire */
  min-width: 0;
  max-width: 100%;
  overflow: hidden;
}
.lane-fx-chip .name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.lane-fx-chip .name {
  font-size: 8px;
  letter-spacing: 0.1em;
  font-weight: 700;
  color: #ffa84a;
  min-width: 20px;
}
.lane-fx-chip .slider.chance {
  flex: 1;
  height: 10px;
  min-width: 18px;
}
.lane-fx-chip .slider.chance .fill {
  background: #8a5a2a;
}
.lane-fx-chip .slider.chance:hover .fill {
  background: #ffa84a;
}
.lane-fx-chip .remove {
  color: var(--text-dim);
  cursor: pointer;
  font-size: 12px;
  line-height: 1;
  padding: 0 2px;
}
.lane-fx-chip .remove:hover { color: var(--magenta); }
.lane-strip.muted .lane-strip-source { color: var(--magenta-dim); }

/* Sidebar (mixer) : drop target pour kits entiers */
.sidebar.drag-over-kit {
  background: rgba(255, 168, 74, 0.06);
  box-shadow: inset 0 0 0 1px #ffa84a;
}

/* Kit header : cursor grab quand draggable */
.kit-item-header {
  cursor: grab;
}
.kit-item-header:active { cursor: grabbing; }
.lane-strip.muted {
  opacity: 0.45;
  border-color: #40182a;
}
.lane-strip .name {
  color: var(--text-dim);
  font-size: 9px;
  letter-spacing: 0.18em;
  font-weight: 700;
  text-align: center;
  text-transform: uppercase;
}
.lane-strip .mute-btn { align-self: center; }
.lane-strip .slider { width: 100%; }
.lane-strip .lane-strip-source {
  justify-content: center;
  flex-wrap: wrap;
}
.lane-strip .lane-source-text {
  flex-basis: 100%;
  text-align: center;
  font-size: 7px;
}
.lane-strip.muted .name { color: var(--magenta-dim); }

/* Mute button = petit carré, cyan-dim au repos, magenta plein si muté */
.mute-btn {
  width: 14px;
  height: 14px;
  border: 1px solid var(--accent-dim);
  border-radius: 2px;
  background: transparent;
  cursor: pointer;
  padding: 0;
  transition: all 140ms ease;
}
.mute-btn:hover { border-color: var(--magenta); }
.mute-btn.active {
  background: var(--magenta);
  border-color: var(--magenta);
  box-shadow: 0 0 6px rgba(255, 58, 165, 0.5);
}

/* FX toggle (F) — même taille que M mais couleur cyan quand actif */
.fx-toggle-btn {
  width: 14px;
  height: 14px;
  border: 1px solid var(--accent-dim);
  border-radius: 2px;
  background: transparent;
  cursor: pointer;
  padding: 0;
  transition: all 140ms ease;
  font-size: 8px;
  font-weight: 700;
  color: var(--text-dim);
  line-height: 1;
}
.fx-toggle-btn:hover { border-color: var(--accent); }
.fx-toggle-btn.active {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--bg);
  box-shadow: 0 0 6px rgba(0, 240, 255, 0.5);
}

/* Slider : barre horizontale click-drag. Fill coloré, label overlay. */
.slider {
  position: relative;
  height: 14px;
  background: #0c0c14;
  border: 1px solid var(--border);
  border-radius: 2px;
  cursor: ew-resize;
  overflow: hidden;
  user-select: none;
}
.slider:hover { border-color: var(--accent-dim); }
.slider .fill {
  position: absolute;
  top: 0; left: 0; bottom: 0;
  background: var(--accent-dim);
  transition: width 40ms linear;
}
.slider.random .fill {
  background: var(--magenta-dim);
}
/* EVOLVE slider : vert acide pour distinguer de vol/random */
.slider.evolve .fill {
  background: #3a7a4a;
}
.slider.evolve:hover .fill {
  background: #5fc080;
  box-shadow: 0 0 8px rgba(95, 192, 128, 0.3);
}

/* P slider (Pitch per-lane) : violet, bipolar (tick au milieu pour 0 semi) */
.slider.pitch .fill {
  background: #6a3aa5;
}
.slider.pitch:hover .fill {
  background: #b66aff;
  box-shadow: 0 0 8px rgba(182, 106, 255, 0.35);
}
.slider.pitch::before {
  content: '';
  position: absolute;
  top: 2px;
  bottom: 2px;
  left: 50%;
  width: 1px;
  background: var(--text-dim);
  opacity: 0.5;
  pointer-events: none;
  z-index: 1;
}

/* D slider (Decay per-lane) : jaune-ambre pour le distinguer */
.slider.decay .fill {
  background: #7a6a2a;
}
.slider.decay:hover .fill {
  background: #ffd84a;
  box-shadow: 0 0 8px rgba(255, 216, 74, 0.3);
}

/* X slider (FX chance) : orange-ish pour le distinguer des 3 autres */
.slider.fx .fill {
  background: #8a5a2a;
}
.slider.fx:hover .fill {
  background: #ffa84a;
  box-shadow: 0 0 8px rgba(255, 168, 74, 0.3);
}
.slider .label {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 5px;
  font-size: 8px;
  letter-spacing: 0.1em;
  color: var(--text);
  pointer-events: none;
  font-weight: 500;
}
.slider .label .tag { color: var(--text-dim); }
.slider.random:hover .fill { background: var(--magenta); box-shadow: 0 0 8px rgba(255, 58, 165, 0.3); }
.slider.vol:hover .fill    { background: var(--accent);  box-shadow: 0 0 8px rgba(0, 240, 255, 0.3); }

/* ---------- Rings ---------- */
.ring-bg {
  fill: none;
  stroke: #3a3a50;           /* plus lumineux pour être visible sur dark bg */
  stroke-width: 1;
  stroke-dasharray: 2 4;
  opacity: 0.7;
}
/* Ticks d'accent : petites barres radiales où tombent les downbeats du meter */
.ring-tick {
  stroke: var(--accent-dim);
  stroke-width: 1;
  opacity: 0.5;
  pointer-events: none;
}

/* ---------- Zones (trigger points sur les rings) ---------- */
/* Une zone est un point fixe sur l'orbite qui déclenche un hit quand la
   planète passe dessus. Couleur par velocity tier, flash à l'impact. */
.zone {
  fill: var(--accent);
  opacity: 0.9;
  pointer-events: none;
  transition: opacity 160ms ease;
}
.zone.ghost {
  fill: var(--accent-dim);
  opacity: 0.65;
}
.zone.normal {
  fill: var(--accent);
  filter: drop-shadow(0 0 3px rgba(0, 240, 255, 0.55));
}
.zone.accent {
  fill: var(--accent);
  filter: drop-shadow(0 0 8px rgba(0, 240, 255, 0.95));
}
.zone.flashing {
  animation: zone-flash 280ms ease;
}
@keyframes zone-flash {
  0%   { filter: drop-shadow(0 0 14px rgba(255, 255, 255, 1)); transform: scale(1.8); }
  100% { filter: drop-shadow(0 0 3px rgba(0, 240, 255, 0.55)); transform: scale(1); }
}

/* ---------- Planets (dots mobiles qui suivent l'orbite) ---------- */
.planet {
  fill: var(--magenta);
  opacity: 0.85;
  pointer-events: none;
  filter: drop-shadow(0 0 6px rgba(255, 58, 165, 0.7));
}

/* ---------- Lane labels ---------- */
.lane-label {
  fill: var(--text-dim);
  font-family: inherit;
  font-size: 9px;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-anchor: start;
  dominant-baseline: middle;
  pointer-events: none;
}

/* ---------- Knobs (MAGIC + FX, côte à côte au centre) ---------- */
.knob-group { cursor: ns-resize; }
.knob-group:hover .knob-outer { stroke: var(--accent-dim); }
/* FX knob (2e du groupe) : teinte magenta au hover pour le distinguer */
/* FX knob : orange (couleur thématique des FX dans la palette) */
#knob-fx:hover .knob-outer { stroke: #ffa84a; }
#knob-fx .knob-arc        { stroke: #ffa84a; filter: drop-shadow(0 0 5px rgba(255, 168, 74, 0.65)); }
#knob-fx .knob-value      { fill: #ffd84a; }
#knob-fx .knob-inner      { stroke: #8a5a2a; }
#knob-fx .knob-top-label   { fill: #ffa84a; }

/* OCC FX knob : cyan (accent par défaut, donc on garde le style de base — pas d'override) */

/* LFO CHAOS knob : magenta/violet (couleur thématique LFO) */
#knob-lfochaos:hover .knob-outer { stroke: var(--magenta-dim); }
#knob-lfochaos .knob-arc        { stroke: var(--magenta); filter: drop-shadow(0 0 5px rgba(255, 58, 165, 0.65)); }
#knob-lfochaos .knob-value      { fill: var(--magenta); }
#knob-lfochaos .knob-inner      { stroke: var(--magenta-dim); }
#knob-lfochaos .knob-top-label  { fill: var(--magenta); }


.knob-outer {
  fill: var(--bg-elev);
  stroke: var(--border);
  stroke-width: 2;
  transition: stroke 140ms ease;
}
.knob-inner {
  fill: #0a0a10;
  stroke: var(--accent-dim);
  stroke-width: 1;
}
.knob-arc {
  fill: none;
  stroke: var(--accent);
  stroke-width: 2.5;
  stroke-linecap: round;
  filter: drop-shadow(0 0 5px rgba(0, 240, 255, 0.6));
  pointer-events: none;
}
.knob-value {
  fill: var(--accent);
  font-family: inherit;
  font-size: 18px;
  font-weight: 700;
  text-anchor: middle;
  dominant-baseline: middle;
  pointer-events: none;
  letter-spacing: 0;
}
.knob-top-label {
  fill: var(--text-dim);
  font-size: 7px;
  letter-spacing: 0.3em;
  text-anchor: middle;
  dominant-baseline: middle;
  pointer-events: none;
}
.knob-bot-label {
  fill: var(--text-dim);
  font-size: 6px;
  letter-spacing: 0.25em;
  text-anchor: middle;
  dominant-baseline: middle;
  pointer-events: none;
}
/* Valeurs knob plus petites (knobs sont réduits à 34px radius) */
.knob-value {
  font-size: 14px;
}
.knob-top-label {
  font-size: 6px;
}

/* Preset name au centre des 4 knobs */
.preset-name-text {
  fill: var(--accent);
  font-family: inherit;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-anchor: middle;
  dominant-baseline: middle;
  pointer-events: none;
  text-shadow: 0 0 6px rgba(0, 240, 255, 0.5);
}

/* ---------- Playhead ---------- */
.playhead {
  stroke: var(--accent);
  stroke-width: 2;
  stroke-linecap: round;
  filter: drop-shadow(0 0 6px rgba(0, 240, 255, 0.9));
  pointer-events: none;
  /* pas de CSS transition: on jump d'un step au suivant (feel drum machine) */
}

/* ---------- FX Palette (drag source + global chance sliders, dans right rack) ----------
   Layout en plusieurs lignes : un FX par row, chip + ALL à gauche, slider à droite. */
.fx-palette-row {
  display: flex;
  flex-direction: column;
  gap: 5px;
  padding: 8px;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: 4px;
}
.fx-palette-label {
  font-size: 10px;
  letter-spacing: 0.35em;
  color: var(--text-dim);
  text-align: center;
  font-weight: 700;
  padding-bottom: 2px;
}
.fx-palette-row .fx-global-cell {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
  padding: 1px 0;
}
.fx-palette-row .fx-cell-row {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 4px;
  min-width: 0;
}
/* Layout dense : chip · ALL · chance · VOL · VU · × tout sur une ligne */
.fx-palette-row .fx-cell-row-dense {
  gap: 3px;
  padding: 1px 2px;
}
.fx-palette-row .fx-cell-row-dense .fx-chip {
  width: 42px;
  padding: 3px 0;
  font-size: 9px;
}
.fx-palette-row .fx-cell-row-dense .fx-all-btn {
  width: 24px;
  padding: 2px 0;
  font-size: 7px;
}
.fx-palette-row .slider.fxc,
.fx-palette-row .slider.fxv {
  flex: 1;
  min-width: 0;
  height: 12px;
}
.fx-palette-row .slider.fxc .label .tag,
.fx-palette-row .slider.fxv .label .tag {
  font-size: 7px;
  font-weight: 700;
  letter-spacing: 0.1em;
  opacity: 0.6;
  margin-right: 3px;
}
.fx-palette-row .slider.fxc .label .tag { color: #ffa84a; }
.fx-palette-row .slider.fxv .label .tag { color: #5fc080; }
.fx-palette-row .slider.fxv .fill {
  background: rgba(95, 192, 128, 0.45);
}
.fx-palette-row .slider.fxv:hover .fill {
  background: #5fc080;
  box-shadow: 0 0 6px rgba(95, 192, 128, 0.4);
}
/* VU vertical à droite — 4px wide, hauteur du row */
.fx-palette-row .fx-cell-vu-vert {
  width: 4px;
  height: 14px;
  background: rgba(8, 8, 12, 0.85);
  border: 1px solid var(--border);
  border-radius: 1px;
  overflow: hidden;
  position: relative;
  display: flex;
  align-items: flex-end;
  flex-shrink: 0;
}
.fx-palette-row .fx-cell-vu-vert .fx-cell-vu-fill {
  width: 100%;
  height: 0%;
  background: linear-gradient(to top,
    #2a8a4a 0%, #5fc080 50%,
    #ffd84a 75%, #ff8a3a 88%,
    #ff3030 95%);
  transition: height 60ms linear;
}
.fx-palette-row .fx-cell-vu-spacer {
  width: 4px;
  flex-shrink: 0;
}
/* Slot params inline sous chaque FX (caché par défaut, populé à l'édition). */
.fx-palette-row .fxp-slot {
  display: none;
}
.fx-palette-row .fxp-slot.open {
  display: flex;
  flex-direction: column;
  gap: 5px;
  padding: 6px 8px;
  margin-left: 8px;
  border-left: 2px solid #8a5a2a;
  background: rgba(255, 168, 74, 0.05);
  border-radius: 0 3px 3px 0;
  animation: fx-params-slide 180ms ease;
}
.fx-palette-row .fxp-slot .mod-field { width: 100%; }
.fx-palette-row .fxp-slot .mod-field-slider .slider { flex: 1; }
.fx-palette-row .fxp-slot .fxp-close {
  align-self: flex-end;
  margin-top: 2px;
}
.fx-palette-row .fx-alt-cell {
  display: flex;
  align-items: center;
  gap: 10px;
  padding-top: 6px;
  border-top: 1px solid var(--border);
}
.fx-palette-row .fx-alt-cell .mod-field-slider {
  flex: 1;
}
.fx-global-cell {
  display: flex;
  flex-direction: column;
  gap: 3px;
  align-items: stretch;
  min-width: 62px;
}
.fx-palette-row .fx-chip {
  /* Largeur fixe pour que tous les chips (DIST/REV/DLY/FLG/PHS/PITCH) aient
     la même taille → alignement parfait du slider à droite. */
  width: 48px;
  flex-shrink: 0;
  padding: 4px 0;
  font-size: 10px;
  letter-spacing: 0.15em;
  font-weight: 700;
  color: #ffa84a;
  background: var(--bg-elev);
  border: 1px solid #8a5a2a;
  border-radius: 3px;
  cursor: grab;
  user-select: none;
  text-align: center;
  transition: all 140ms ease;
}
.fx-palette-row .fx-all-btn {
  width: 32px;
  flex-shrink: 0;
  text-align: center;
  padding: 4px 0;
}
.fx-palette-row .fx-chip:hover {
  border-color: #ffa84a;
  box-shadow: 0 0 10px rgba(255, 168, 74, 0.3);
}
.fx-palette-row .fx-chip:active { cursor: grabbing; }

.fx-palette-row .slider.fxc {
  height: 12px;
}

/* FX chip + ALL button side-by-side */
.fx-chip-wrap {
  display: flex;
  gap: 2px;
  align-items: stretch;
}
.fx-all-btn {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-dim);
  font-family: inherit;
  font-size: 8px;
  letter-spacing: 0.12em;
  font-weight: 700;
  padding: 0 5px;
  border-radius: 3px;
  cursor: pointer;
  transition: all 140ms ease;
}
.fx-all-btn:hover {
  border-color: #ffa84a;
  color: #ffa84a;
}
.fx-all-btn.active {
  background: rgba(255, 168, 74, 0.2);
  border-color: #ffa84a;
  color: #ffa84a;
  box-shadow: 0 0 6px rgba(255, 168, 74, 0.3);
}

/* ALT cell (toggle + jitter slider) à la fin de la palette */
.fx-alt-cell {
  display: flex;
  flex-direction: column;
  gap: 3px;
  align-items: stretch;
  min-width: 82px;
  padding-left: 10px;
  border-left: 1px dashed var(--border);
}
.btn.fx-alt-toggle {
  font-size: 9px;
  letter-spacing: 0.2em;
  padding: 4px 10px;
  color: var(--text-dim);
  border-color: var(--border);
}
.btn.fx-alt-toggle.active {
  background: rgba(255, 58, 165, 0.12);
  border-color: var(--magenta);
  color: var(--magenta);
  box-shadow: 0 0 8px rgba(255, 58, 165, 0.3);
}
.slider.fx-alt-jtr {
  height: 12px;
}
.slider.fx-alt-jtr .fill {
  background: #6a1a4a;
}
.slider.fx-alt-jtr:hover .fill {
  background: var(--magenta);
  box-shadow: 0 0 6px rgba(255, 58, 165, 0.4);
}

/* Panel d'édition params FX (apparait au click d'un chip) */
.fx-params-panel {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 8px 14px;
  background: rgba(255, 168, 74, 0.05);
  border: 1px solid #8a5a2a;
  border-radius: 4px;
  margin: 4px 40px 0;
  animation: fx-params-slide 180ms ease;
}
@keyframes fx-params-slide {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: translateY(0); }
}
.fx-params-title {
  font-size: 11px;
  letter-spacing: 0.3em;
  font-weight: 700;
  color: #ffa84a;
  min-width: 80px;
}
.slider.fxp {
  height: 12px;
}
.slider.fxp .fill {
  background: #8a5a2a;
}
.slider.fxp:hover .fill {
  background: #ffa84a;
  box-shadow: 0 0 8px rgba(255, 168, 74, 0.4);
}
#fx-params-close {
  margin-left: auto;
  padding: 3px 8px !important;
  font-size: 11px !important;
}

/* Toggle et dropdown dans le fx params panel */
.fxp-toggle-field, .fxp-division-field {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 9px;
  letter-spacing: 0.2em;
  color: var(--text-dim);
}
.btn.fxp-toggle {
  padding: 3px 10px;
  font-size: 9px;
}
.btn.fxp-toggle.active {
  background: rgba(255, 168, 74, 0.15);
  border-color: #ffa84a;
  color: #ffa84a;
  box-shadow: 0 0 6px rgba(255, 168, 74, 0.3);
}
.fxp-division {
  background: var(--bg-elev);
  border: 1px solid #8a5a2a;
  color: #ffa84a;
  font-family: inherit;
  font-size: 10px;
  letter-spacing: 0.1em;
  padding: 3px 6px;
  border-radius: 3px;
  cursor: pointer;
}
.fxp-division:hover, .fxp-division:focus {
  border-color: #ffa84a;
  outline: none;
}

/* Field désactivé (DELAY : DIV grise si SYNC off, TIME grise si SYNC on) :
   visuellement greyed + non-interactif. Reste cliquable techniquement pour
   ne pas casser le layout ; juste plus contrastée. */
.fxp-field-disabled {
  opacity: 0.32;
  filter: saturate(0.3);
  pointer-events: none;
  transition: opacity 180ms ease, filter 180ms ease;
}

/* === Reverb MODE pills : row de boutons cliquables, active = orange glow === */
.fxp-mode-field {
  display: flex !important;
  flex-direction: column;
  gap: 6px;
  align-items: flex-start !important;
  font-size: 9px;
  letter-spacing: 0.2em;
  color: var(--text-dim);
  width: 100%;
}
.fxp-mode-field > .mod-label {
  font-size: 9px;
  letter-spacing: 0.2em;
  color: var(--text-dim);
}
.fxp-mode-pills {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 4px;
  width: 100%;
}
.fxp-mode-pill {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1px;
  padding: 5px 4px;
  background: var(--bg-elev);
  border: 1px solid #4a3320;
  color: rgba(255, 168, 74, 0.55);
  font-family: inherit;
  border-radius: 4px;
  cursor: pointer;
  transition: all 140ms ease;
  user-select: none;
  min-width: 0;
}
.fxp-mode-pill-name {
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.1em;
  line-height: 1;
}
.fxp-mode-pill-sub {
  font-size: 6.5px;
  letter-spacing: 0.05em;
  opacity: 0.6;
  text-transform: lowercase;
  line-height: 1;
}
.fxp-mode-pill:hover {
  border-color: #ffa84a;
  color: #ffa84a;
  box-shadow: 0 0 6px rgba(255, 168, 74, 0.25);
}
.fxp-mode-pill.active {
  background: linear-gradient(180deg, rgba(255, 168, 74, 0.25), rgba(255, 168, 74, 0.12));
  border-color: #ffa84a;
  color: #ffd84a;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.1),
    0 0 12px rgba(255, 168, 74, 0.45);
}
.fxp-mode-pill.active .fxp-mode-pill-sub {
  opacity: 0.85;
  color: #ffa84a;
}
.fxp-mode-pill:active {
  transform: scale(0.96);
}
.fx-palette-row .slider.fxc .fill {
  background: #8a5a2a;
}
.fx-palette-row .slider.fxc:hover .fill {
  background: #ffa84a;
  box-shadow: 0 0 6px rgba(255, 168, 74, 0.3);
}

/* ---------- FX Rack (legacy, kept below for reference if reintroduced) ---------- */
.fx-rack {
  display: flex;
  gap: 16px;
  justify-content: center;
  align-items: center;
  padding: 4px 0;
}

.fx-palette {
  display: flex;
  gap: 6px;
  padding: 6px 10px;
  border: 1px dashed var(--border);
  border-radius: 4px;
}
.fx-chip {
  padding: 5px 10px;
  font-size: 10px;
  letter-spacing: 0.2em;
  font-weight: 600;
  color: var(--text);
  background: var(--bg-elev);
  border: 1px solid var(--accent-dim);
  border-radius: 3px;
  cursor: grab;
  transition: all 140ms ease;
  user-select: none;
}
.fx-chip:hover {
  border-color: var(--accent);
  color: var(--accent);
  box-shadow: 0 0 8px rgba(0, 240, 255, 0.25);
}
.fx-chip:active { cursor: grabbing; }

.fx-slots {
  display: flex;
  gap: 10px;
  align-items: center;
}
.fx-slot {
  width: 80px;
  height: 58px;
  border: 1.5px dashed var(--border);
  border-radius: 4px;
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  transition: all 140ms ease;
  background: rgba(18, 18, 26, 0.3);
}
.fx-slot.drag-over {
  border-color: var(--accent);
  background: rgba(0, 240, 255, 0.08);
  box-shadow: 0 0 14px rgba(0, 240, 255, 0.25);
}
.fx-slot.filled {
  border-style: solid;
  border-color: var(--accent-dim);
  cursor: pointer;
}
.fx-slot-drop {
  color: var(--text-dim);
  font-size: 9px;
  letter-spacing: 0.2em;
  pointer-events: none;
}
.fx-slot.filled .fx-slot-drop { display: none; }

.fx-slot-content {
  display: none;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  width: 100%;
  padding: 3px 6px;
}
.fx-slot.filled .fx-slot-content { display: flex; }

.fx-slot-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 100%;
  font-size: 9px;
  letter-spacing: 0.15em;
  color: var(--accent);
  font-weight: 700;
}
.fx-slot-remove {
  cursor: pointer;
  color: var(--text-dim);
  padding: 0 2px;
  line-height: 1;
  font-size: 12px;
}
.fx-slot-remove:hover { color: var(--magenta); }

.fx-slot-row {
  display: flex;
  gap: 4px;
  align-items: center;
  width: 100%;
}
.fx-slot-amount {
  flex: 1;
  height: 10px;
  position: relative;
  background: #0c0c14;
  border: 1px solid var(--border);
  border-radius: 2px;
  cursor: ew-resize;
  overflow: hidden;
}
.fx-slot-amount .fill {
  position: absolute;
  top: 0; left: 0; bottom: 0;
  background: var(--accent-dim);
  transition: width 40ms linear;
}
.fx-slot-lfo {
  width: 22px;
  height: 14px;
  border: 1px solid var(--border);
  border-radius: 2px;
  background: transparent;
  font-size: 8px;
  letter-spacing: 0.1em;
  color: var(--text-dim);
  cursor: pointer;
  padding: 0;
  line-height: 1;
}
.fx-slot-lfo.active {
  background: var(--magenta);
  border-color: var(--magenta);
  color: var(--bg);
  font-weight: 700;
  box-shadow: 0 0 6px rgba(255, 58, 165, 0.5);
}
.fx-slot-amount .fill.lfo-active {
  background: var(--magenta-dim);
  animation: lfo-pulse 900ms ease-in-out infinite;
}

/* ---------- Mod bar (LFOs) ---------- */
.mod-bar {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 16px;
  padding: 4px 0;
}
/* Dans le right rack : stack des 3 LFOs empilés verticalement. */
.right-rack .lfo-stack {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
/* FX palette : container des cells (built dynamically), bouton + et menu add */
.fx-cells-container {
  display: contents;     /* laisse les enfants se laidouter dans le parent flex */
}
.fx-add-btn {
  position: relative;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: 1px solid #6a4a8a;
  background: rgba(20, 12, 28, 0.6);
  color: #b07ad0;
  font-size: 14px;
  font-weight: 700;
  font-family: inherit;
  cursor: pointer;
  transition: all 140ms ease;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  line-height: 1;
  padding: 0;
  align-self: center;
}
.fx-add-btn:hover {
  background: rgba(176, 122, 208, 0.18);
  border-color: #b07ad0;
  color: #d8a8e8;
  box-shadow: 0 0 6px rgba(176, 122, 208, 0.4);
}
.fx-add-btn.open {
  background: rgba(176, 122, 208, 0.25);
  color: #fff;
  transform: rotate(45deg);
}
.fx-add-menu {
  position: absolute;
  background: rgba(15, 10, 22, 0.96);
  border: 1px solid #6a4a8a;
  border-radius: 4px;
  padding: 4px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.6);
  z-index: 100;
  margin-top: 28px;
  min-width: 90px;
}
.fx-add-menu[hidden] { display: none; }
.fx-add-menu button {
  background: transparent;
  border: 1px solid transparent;
  color: #b07ad0;
  font-family: inherit;
  font-size: 9px;
  letter-spacing: 0.15em;
  font-weight: 700;
  padding: 6px 10px;
  text-align: left;
  cursor: pointer;
  border-radius: 2px;
  transition: all 120ms ease;
}
.fx-add-menu button:hover {
  background: rgba(176, 122, 208, 0.15);
  border-color: #b07ad0;
  color: #d8a8e8;
}
/* X delete sur chaque fx-global-cell (positionné en haut à droite) */
.fx-global-cell { position: relative; }
.fx-cell-remove {
  position: absolute;
  top: 1px;
  right: 1px;
  width: 14px;
  height: 14px;
  border-radius: 2px;
  border: 1px solid transparent;
  background: transparent;
  color: rgba(255, 255, 255, 0.25);
  font-size: 11px;
  font-weight: 700;
  cursor: pointer;
  padding: 0;
  line-height: 1;
  transition: all 120ms ease;
  z-index: 5;
}
.fx-cell-remove:hover {
  border-color: #ff5050;
  color: #ff5050;
  background: rgba(255, 80, 80, 0.12);
}
/* Layout dense : X inline (override absolute) */
.fx-cell-row-dense .fx-cell-remove {
  position: static;
  flex-shrink: 0;
}

/* Bouton + ADD LFO en fin de stack (cap à 6) — discret, dashed border */
.lfo-add-btn {
  background: transparent;
  border: 1px dashed #4a3a6a;
  color: rgba(176, 122, 208, 0.7);
  font-family: inherit;
  font-size: 9px;
  letter-spacing: 0.18em;
  font-weight: 700;
  padding: 6px 10px;
  border-radius: 3px;
  cursor: pointer;
  transition: all 140ms ease;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  user-select: none;
}
.lfo-add-btn:hover {
  border-color: #b07ad0;
  border-style: solid;
  background: rgba(176, 122, 208, 0.08);
  color: #d8a8e8;
  box-shadow: 0 0 8px rgba(176, 122, 208, 0.25);
}
.lfo-add-plus {
  font-size: 13px;
  line-height: 1;
}
.lfo-add-count {
  font-size: 8px;
  color: rgba(255, 255, 255, 0.35);
  letter-spacing: 0.1em;
}
.right-rack .mod-section.lfo-v2 {
  display: flex;
  width: 100%;
  box-sizing: border-box;
  position: relative;       /* ancrage du port trig-in (.lfo-trig-port) */
}
/* Port trig-in sur LFO : décalé sur le bord gauche du panel, vertical center */
.lfo-trig-port {
  top: 14px !important;
  left: -7px !important;
  transform: none !important;
}
/* Bouton détach (↗ / ↙) */
.lfo-recall-btn {
  background: rgba(176, 122, 208, 0.12);
  color: #b07ad0;
  border: 1px dashed #6a4a8a;
  border-radius: 3px;
  padding: 6px 8px;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.12em;
  cursor: pointer;
  margin-top: 4px;
  transition: all 120ms ease;
}
.lfo-recall-btn:hover {
  background: rgba(176, 122, 208, 0.25);
  border-color: #b07ad0;
  color: #d8a8e8;
}
.lfo-recall-btn[hidden] { display: none; }
.lfo-recall-count {
  display: inline-block;
  min-width: 14px;
  padding: 0 4px;
  margin-left: 4px;
  font-size: 9px;
  font-weight: 800;
  color: #fff;
  background: rgba(176, 122, 208, 0.45);
  border-radius: 8px;
}
.lfo-detach {
  background: rgba(255, 138, 58, 0.15);
  color: #ff8a3a;
  border: 1px solid #4a3a20;
  border-radius: 2px;
  font-size: 9px;
  padding: 1px 5px;
  cursor: pointer;
  transition: all 120ms ease;
  flex: 0 0 auto;        /* taille fixe, ne flex-grow pas */
  order: 5;              /* placé avant le ▾ collapse (qui n'a pas d'order = défaut 0) */
}
.lfo-detach:hover { background: rgba(255, 138, 58, 0.35); border-color: #ff8a3a; color: #ffd84a; }
/* Stabilise le header : hauteur min pour éviter shift quand le preview/labels changent */
.lfo-v2 .lfo-header { min-height: 24px; }
.lfo-v2 .lfo-collapse { order: 10; }   /* toujours en dernier */
/* Module-grip sur LFO : visible seulement quand détaché */
.lfo-v2 .lfo-grip { display: none; }
.lfo-v2.lfo-detached .lfo-grip { display: block; }
/* LFO détaché : style module flottant dans le canvas. Plus carré, gros preview waveform. */
.modular-canvas-inner .lfo-v2.lfo-detached,
.bottom-row .lfo-v2.lfo-detached {
  position: absolute;
  width: 220px;
  background: rgba(12, 12, 20, 0.92);
  border: 1px solid #4a3a8a;
  border-radius: 4px;
  padding: 8px;
  z-index: 10;
  display: flex;
  flex-direction: column;
  gap: 6px;
  box-sizing: border-box;
  overflow: visible;
}
.lfo-v2.lfo-detached .lfo-tab-label { color: #b07ad0; flex: 0 1 auto; }
/* Header en flex-wrap : labels/boutons sur la 1ère ligne, preview wave en 2e ligne */
.lfo-v2.lfo-detached .lfo-header {
  flex-wrap: wrap;
  gap: 4px;
  padding: 0;
  width: 100%;
}
/* Preview wave : prend toute la largeur du panel (220 - 16 padding = 204px), 60px de haut */
.lfo-v2.lfo-detached .lfo-header .lfo-preview {
  flex: 0 0 100%;
  width: 100%;
  height: 60px;
  min-width: 0;
  max-width: 100%;
  border: 1px solid #4a3a6a;
  background: rgba(8, 8, 14, 0.7);
  order: 99;
  box-sizing: border-box;
}
/* En mode détaché, le toggle expand/collapse fonctionne comme dans le rack. */

/* Layout compact pour le body des LFOs détachés (panel 220px) :
   - Row 1 (SHAPE/RATE/STEPS) : 3 selects en grille avec selects compactés
   - Row 2 (DEPTH/OFFSET/PHASE/JITTER/SMOOTH) : grille 2 colonnes (5 items → 3 lignes) */
.lfo-v2.lfo-detached .lfo-body {
  width: 100%;
}
.lfo-v2.lfo-detached .lfo-row-1 {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 5px;
  flex-wrap: nowrap;
}
/* Chaque field SHAPE / RATE / STEPS : label au-dessus, select en dessous */
.lfo-v2.lfo-detached .lfo-row-1 .mod-field {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
  align-items: stretch;
}
.lfo-v2.lfo-detached .lfo-row-1 .mod-field .mod-label {
  font-size: 7px;
  letter-spacing: 0.18em;
  color: rgba(176, 122, 208, 0.7);
  text-align: center;
  line-height: 1;
}
/* Dropdown style cohérent avec les autres modules (fm / bouncer) */
.lfo-v2.lfo-detached .lfo-row-1 select {
  width: 100%;
  min-width: 0;
  font-family: inherit;
  font-size: 9px;
  font-weight: 600;
  letter-spacing: 0.05em;
  padding: 3px 16px 3px 5px;
  background: rgba(8, 8, 14, 0.85);
  color: #d8a8e8;
  border: 1px solid #4a3a6a;
  border-radius: 3px;
  cursor: pointer;
  transition: border-color 120ms ease, box-shadow 120ms ease;
  appearance: none;
  -webkit-appearance: none;
  /* Petite flèche custom à droite (SVG inline) */
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='8' height='5' viewBox='0 0 8 5'><path d='M0 0 L4 5 L8 0Z' fill='%23b07ad0'/></svg>");
  background-repeat: no-repeat;
  background-position: right 4px center;
}
.lfo-v2.lfo-detached .lfo-row-1 select:hover {
  border-color: #b07ad0;
  color: #fff;
}
.lfo-v2.lfo-detached .lfo-row-1 select:focus {
  outline: none;
  border-color: #d8a8e8;
  box-shadow: 0 0 6px rgba(176, 122, 208, 0.4);
}
.lfo-v2.lfo-detached .lfo-row-2 {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 3px 4px;
}
.lfo-v2.lfo-detached .lfo-row-2 .mod-field-slider {
  flex: none;
  min-width: 0;
  max-width: none;
  width: 100%;
}
.lfo-v2.lfo-detached .lfo-row-2 .slider.lfo-param {
  width: 100%;
  height: 10px;
}
.lfo-v2.lfo-detached .lfo-row .mod-label {
  font-size: 7px;
  letter-spacing: 0.08em;
}
.right-rack .mod-field-slider { width: auto; }
.lfo-header {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 2px 0;
  cursor: pointer;
  user-select: none;
}
.lfo-header .lfo-tab-label {
  color: var(--magenta);
  font-weight: 700;
  letter-spacing: 0.2em;
  font-size: 10px;
  flex-shrink: 0;
}
.lfo-header .fx-chip.lfo-source {
  min-width: 32px;
  text-align: center;
  padding: 5px 10px;
  font-size: 14px;
  line-height: 1;
  font-weight: 700;
  border-color: var(--magenta-dim);
  color: var(--magenta);
  background: rgba(255, 58, 165, 0.10);
  cursor: grab;
  flex-shrink: 0;
}
.lfo-header .fx-chip.lfo-source:hover {
  background: rgba(255, 58, 165, 0.18);
  box-shadow: 0 0 10px rgba(255, 58, 165, 0.35);
}
.lfo-header .fx-chip.lfo-source:active { cursor: grabbing; }

/* Preview de l'onde — toujours visible dans le header (même collapsed) */
.lfo-header .lfo-preview {
  flex: 1;
  height: 22px;
  min-width: 40px;
  border: 1px solid var(--border);
  border-radius: 2px;
  background: rgba(10, 10, 16, 0.5);
}

/* Bouton expand/collapse — rotation 0° = expandé, -90° = collapsed */
.lfo-collapse {
  background: transparent;
  border: none;
  color: var(--text-dim);
  font-size: 11px;
  cursor: pointer;
  padding: 0 4px;
  flex-shrink: 0;
  transition: transform 160ms ease, color 140ms ease;
}
.lfo-collapse:hover { color: var(--magenta); }

/* Body = row-1 (selects) + row-2 (sliders), caché quand collapsed */
.lfo-body {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding-top: 4px;
}
.mod-section.lfo-v2.collapsed .lfo-body { display: none; }
.mod-section.lfo-v2.collapsed .lfo-collapse { transform: rotate(-90deg); }
.mod-section {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 6px 12px;
  border: 1px solid var(--border);
  border-radius: 4px;
  background: rgba(18, 18, 26, 0.4);
  font-size: 10px;
  letter-spacing: 0.15em;
  color: var(--text-dim);
}
.mod-section.active {
  border-color: var(--magenta-dim);
  box-shadow: 0 0 10px rgba(255, 58, 165, 0.15);
}
.mod-title {
  color: var(--magenta);
  font-weight: 700;
  letter-spacing: 0.25em;
}
.mod-field {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.mod-field-slider { width: 140px; }
.mod-field-slider .slider { flex: 1; }
.mod-label {
  font-size: 9px;
  letter-spacing: 0.2em;
  color: var(--text-dim);
}

.btn-mini {
  padding: 5px 10px;
  font-size: 10px;
  letter-spacing: 0.2em;
}
.btn.lfo-toggle.active,
.btn.lfo-target.active {
  background: rgba(255, 58, 165, 0.12);
  border-color: var(--magenta);
  color: var(--magenta);
  box-shadow: 0 0 10px rgba(255, 58, 165, 0.3);
}

/* Dropdowns LFO (shape / rate / steps) — custom-stylés au lieu du natif */
.lfo-stack select {
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  background-color: var(--bg-elev-2);
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 6'><path fill='%23ff3aa5' d='M0 0l5 6 5-6z'/></svg>");
  background-repeat: no-repeat;
  background-position: right 5px center;
  background-size: 7px 5px;
  border: 1px solid var(--border);
  color: var(--text);
  font-family: inherit;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.1em;
  padding: 3px 16px 3px 6px;
  border-radius: 2px;
  cursor: pointer;
  transition: all 140ms ease;
}
.lfo-stack select:hover {
  border-color: var(--magenta-dim);
  background-color: rgba(255, 58, 165, 0.06);
}
.lfo-stack select:focus {
  outline: none;
  border-color: var(--magenta);
  box-shadow: 0 0 6px rgba(255, 58, 165, 0.3);
}
.lfo-stack select option {
  background: var(--bg-elev-2);
  color: var(--text);
  font-weight: 700;
}

/* LFO wave preview (SVG) — visualisateur d'onde temps réel */
.lfo-preview {
  border: 1px solid var(--border);
  border-radius: 3px;
  background:
    linear-gradient(to bottom, rgba(255,58,165,0.04) 0%, transparent 50%, rgba(255,58,165,0.04) 100%),
    rgba(10, 10, 16, 0.7);
  overflow: visible;
}
/* Ligne médiane (zero crossing) — repère discret */
.lfo-preview-mid {
  stroke: var(--text-dim);
  stroke-width: 0.5;
  stroke-dasharray: 2 2;
  opacity: 0.4;
}
.lfo-preview-path {
  fill: none;
  stroke: var(--magenta);
  stroke-width: 1.6;
  stroke-linejoin: round;
  stroke-linecap: round;
  filter: drop-shadow(0 0 3px rgba(255, 58, 165, 0.6));
}
/* Indicateur "now" : barre verticale fixe au bord droit. La courbe scrolle
   vers la gauche, donc le bord droit = moment présent. */
.lfo-preview-now {
  stroke: var(--accent);
  stroke-width: 1.2;
  opacity: 0.6;
  filter: drop-shadow(0 0 3px rgba(0, 240, 255, 0.6));
  pointer-events: none;
}

/* LFO v2 : layout 2-rangées type Ableton + tabs de sélection */
.mod-section.lfo-v2 {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 5px 10px;
}

/* Tabs LFO : un par LFO, chacun avec son drag chip */
.lfo-tabs {
  display: flex;
  gap: 6px;
  align-items: center;
}
.lfo-tab {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 8px 3px 3px;
  border: 1px solid var(--border);
  border-radius: 3px;
  font-size: 10px;
  letter-spacing: 0.2em;
  cursor: pointer;
  color: var(--text-dim);
  background: rgba(18, 18, 26, 0.4);
  transition: all 140ms ease;
}
.lfo-tab:hover { border-color: var(--magenta-dim); }
.lfo-tab.active {
  border-color: var(--magenta);
  color: var(--magenta);
  background: rgba(255, 58, 165, 0.08);
  box-shadow: 0 0 8px rgba(255, 58, 165, 0.15);
}
.lfo-tab .fx-chip.lfo-source {
  padding: 2px 6px;
  font-size: 11px;
  margin: 0;
}
.lfo-tab-label {
  font-weight: 700;
  pointer-events: none;
}
.lfo-row {
  display: flex;
  gap: 10px;
  align-items: center;
  flex-wrap: wrap;
}
.lfo-row-2 .mod-field-slider {
  flex: 1;
  min-width: 90px;
  max-width: 160px;
}
.lfo-row-2 .slider.lfo-param {
  height: 12px;
  flex: 1;
}
.lfo-row-2 .slider.lfo-param .fill {
  background: var(--magenta-dim);
}
.lfo-row-2 .slider.lfo-param:hover .fill {
  background: var(--magenta);
  box-shadow: 0 0 6px rgba(255, 58, 165, 0.3);
}

/* Offset slider : montre le tick central = 0 */
#lfo-offset::before {
  content: '';
  position: absolute;
  top: 2px;
  bottom: 2px;
  left: 50%;
  width: 1px;
  background: var(--text-dim);
  opacity: 0.5;
  pointer-events: none;
}

/* LFO actif : arc du knob pulse en magenta pour le signaler */
.knob-group.lfo-active .knob-arc {
  animation: lfo-pulse 900ms ease-in-out infinite;
}

/* Drop target LFO — feedback visuel pendant le dragover */
[data-mod-key].drag-over-lfo {
  outline: 2px solid var(--magenta);
  outline-offset: 2px;
  filter: drop-shadow(0 0 8px rgba(255, 58, 165, 0.5));
}
/* Preview broadcast (shift+drag) — outline plus léger, dashed, pour signaler
   les autres targets qui recevront aussi l'assignment au drop. */
[data-mod-key].drag-over-lfo-broadcast {
  outline: 1px dashed var(--magenta);
  outline-offset: 2px;
  filter: drop-shadow(0 0 4px rgba(255, 58, 165, 0.35));
}
/* Flash bref quand un LFO est unassigné via right-click (confirmation visuelle) */
[data-mod-key].lfo-unassigned-flash {
  animation: lfo-unassign-flash 380ms ease-out;
}
@keyframes lfo-unassign-flash {
  0%   { outline: 2px solid #ff3030; outline-offset: 2px; filter: drop-shadow(0 0 8px rgba(255, 48, 48, 0.85)); }
  100% { outline: 0 solid transparent; outline-offset: 0; filter: none; }
}

/* Target assigné : pulse magenta permanent pour signaler LFO actif */
.slider.lfo-assigned .fill {
  background: var(--magenta-dim) !important;
  animation: lfo-pulse 900ms ease-in-out infinite;
}
.fx-slot-amount.lfo-assigned .fill {
  background: var(--magenta-dim) !important;
  animation: lfo-pulse 900ms ease-in-out infinite;
}

/* Chip LFO source — cursor drag */
.fx-chip.lfo-source {
  cursor: grab;
  color: var(--magenta);
  border-color: var(--magenta-dim);
}
.fx-chip.lfo-source:hover {
  border-color: var(--magenta);
  color: var(--magenta);
  box-shadow: 0 0 8px rgba(255, 58, 165, 0.3);
}
.fx-chip.lfo-source:active { cursor: grabbing; }
@keyframes lfo-pulse {
  0%   { filter: drop-shadow(0 0 3px rgba(255, 58, 165, 0.4)); opacity: 0.75; }
  50%  { filter: drop-shadow(0 0 12px rgba(255, 58, 165, 1));  opacity: 1; }
  100% { filter: drop-shadow(0 0 3px rgba(255, 58, 165, 0.4)); opacity: 0.75; }
}

/* ---------- Footer ---------- */
/* ---------- Viz hits (remplace l'UI orbite) : une ligne de 8 dots, 1 par lane ---------- */
.piano-roll {
  display: flex;
  align-items: center;
  justify-content: space-around;
  gap: 12px;
  padding: 14px 16px;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: 4px;
}
.pr-cell {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  flex: 1;
  min-width: 0;
}
.pr-dot {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: #14141f;
  border: 1px solid #2a2a3a;
}
.pr-label {
  font-size: 9px;
  letter-spacing: 0.15em;
  color: var(--text-dim);
  font-weight: 700;
  text-transform: uppercase;
  white-space: nowrap;
}
/* Flash sur hit : animation one-shot avec intensité par tier de velocity.
   forwards = se fige dans le state final (= dot éteint) pour que le fade ait
   l'air "naturel" même si le tick suivant ne re-flash pas. */
.pr-dot.hit.ghost  { animation: pr-flash-ghost  180ms ease-out forwards; }
.pr-dot.hit.normal { animation: pr-flash-normal 220ms ease-out forwards; }
.pr-dot.hit.accent { animation: pr-flash-accent 280ms ease-out forwards; }

@keyframes pr-flash-ghost {
  0%   { background: rgba(0, 240, 255, 0.5);  box-shadow: 0 0 8px  rgba(0,240,255,0.4);  }
  100% { background: #14141f;                 box-shadow: 0 0 0    rgba(0,240,255,0);    }
}
@keyframes pr-flash-normal {
  0%   { background: rgba(0, 240, 255, 0.9);  box-shadow: 0 0 14px rgba(0,240,255,0.7);  }
  100% { background: #14141f;                 box-shadow: 0 0 0    rgba(0,240,255,0);    }
}
@keyframes pr-flash-accent {
  0%   { background: #00f0ff;                 box-shadow: 0 0 20px rgba(0,240,255,0.95); }
  100% { background: #14141f;                 box-shadow: 0 0 0    rgba(0,240,255,0);    }
}

/* ---------- Preset matrix 3×3 (en bas de la bande gauche, sous le browser) ---------- */
.preset-row {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 6px;
  padding: 8px 6px;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: 4px;
  /* Le preset-row peut shrink + scroll quand expandé, pour laisser le
     transport-bottom ancré en bas. Sans ça les boutons PLAY/REC sortaient
     hors viewport. */
  flex: 0 1 auto;
  min-height: 0;
  margin-top: auto;       /* pousse en bas de la bande (au dessus du transport) */
  max-height: calc(100% - 90px);   /* garde au moins ~90px pour transport-bottom */
  overflow-y: auto;
  width: 100%;
}
.preset-row-label {
  font-size: 9px;
  letter-spacing: 0.25em;
  color: var(--text-dim);
  font-weight: 700;
  text-align: center;
}
/* Bouton collapse — devient le label cliquable */
.preset-collapse-btn {
  background: transparent;
  border: none;
  font-family: inherit;
  font-size: 9px;
  letter-spacing: 0.25em;
  color: var(--text-dim);
  font-weight: 700;
  text-align: center;
  cursor: pointer;
  width: 100%;
  padding: 4px 6px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  transition: color 120ms ease;
  border-radius: 2px;
}
.preset-collapse-btn:hover { color: var(--accent-dim); background: rgba(0, 240, 255, 0.04); }
.preset-collapse-caret {
  display: inline-block;
  font-size: 8px;
  transition: transform 180ms ease;
}
.preset-collapse-btn.active .preset-collapse-caret { transform: rotate(-90deg); }
/* Collapsed : on cache tout sauf le bouton-label, et on réduit le padding */
.preset-row.collapsed { padding: 4px 6px; gap: 0; }
.preset-row.collapsed > *:not(.preset-collapse-btn) { display: none; }

/* TRANSPORT bottom : PLAY + REC en bas de la colonne gauche, redesign large.
   ANCRÉ : flex-shrink: 0 + position: sticky pour rester visible peu importe la
   hauteur de preset-row (qui scroll en interne). */
.transport-bottom {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 6px;
  margin-top: 6px;
  padding: 6px;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: 4px;
  flex-shrink: 0;
  position: sticky;
  bottom: 0;
  z-index: 8;
}
/* PLAY = même style que REC mais vert */
.transport-play {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  background: rgba(95, 192, 128, 0.06);
  border: 1px solid #1a5a3a;
  color: #5fc080;
  font-family: inherit;
  font-size: 9px;
  letter-spacing: 0.25em;
  font-weight: 700;
  padding: 10px 14px;
  border-radius: 4px;
  cursor: pointer;
  transition: all 140ms ease;
}
.transport-play:hover {
  background: rgba(95, 192, 128, 0.18);
  border-color: #5fc080;
  box-shadow: 0 0 12px rgba(95, 192, 128, 0.4);
}
.transport-play .transport-play-icon { font-size: 14px; line-height: 1; }
/* STOP (active) — bascule en rouge avec le même traitement */
.transport-play.active {
  background: rgba(255, 80, 80, 0.18);
  border-color: #ff5050;
  color: #ff5050;
  box-shadow: 0 0 12px rgba(255, 80, 80, 0.4);
}

.transport-rec {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  background: rgba(255, 80, 80, 0.06);
  border: 1px solid #6a2a2a;
  color: #ff5050;
  font-family: inherit;
  font-size: 9px;
  letter-spacing: 0.25em;
  font-weight: 700;
  padding: 0 14px;
  border-radius: 4px;
  cursor: pointer;
  transition: all 140ms ease;
  min-width: 54px;
}
.transport-rec:hover {
  background: rgba(255, 80, 80, 0.18);
  border-color: #ff5050;
  box-shadow: 0 0 12px rgba(255, 80, 80, 0.4);
}
.transport-rec-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: #ff5050;
  box-shadow: 0 0 4px rgba(255, 80, 80, 0.5);
}
.transport-rec.recording {
  background: rgba(255, 80, 80, 0.28);
  border-color: #ff5050;
  box-shadow: 0 0 16px rgba(255, 80, 80, 0.6);
}
.transport-rec.recording .transport-rec-dot {
  animation: transport-rec-pulse 0.8s ease-in-out infinite;
}
@keyframes transport-rec-pulse {
  0%, 100% { background: #ff5050; box-shadow: 0 0 4px rgba(255, 80, 80, 0.6); }
  50%      { background: #ff8a8a; box-shadow: 0 0 12px rgba(255, 80, 80, 1); }
}
.preset-matrix {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 4px;
  width: 100%;
}
.preset-slot { aspect-ratio: 1; min-width: 0; }
/* Tabs A / B / C / D au-dessus du pad — switch entre les 4 banques de 16. */
.preset-page-tabs {
  display: flex;
  gap: 4px;
  margin-bottom: 2px;
  width: 100%;
}
.preset-page-tab {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-dim);
  font-family: inherit;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.1em;
  line-height: 1;
  flex: 1;
  height: 22px;
  border-radius: 2px;
  cursor: pointer;
  transition: all 120ms ease;
}
.preset-page-tab:hover { border-color: var(--accent-dim); color: var(--accent-dim); }
.preset-page-tab.active {
  background: rgba(0, 240, 255, 0.18);
  border-color: var(--accent);
  color: var(--accent);
  box-shadow: 0 0 6px rgba(0, 240, 255, 0.4);
}
.preset-slot {
  position: relative;
  border: 1px dashed var(--border);
  border-radius: 3px;
  background: transparent;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 13px;
  letter-spacing: 0.08em;
  color: var(--text-dim);
  cursor: pointer;
  transition: all 140ms ease;
  user-select: none;
}
.preset-slot:hover { border-color: var(--accent-dim); color: var(--accent-dim); }
.preset-slot-label {
  font-weight: 700;
  pointer-events: none;
}
.preset-slot.filled {
  border: 1px solid #5fc080;
  background: rgba(95, 192, 128, 0.12);
  color: #5fc080;
  cursor: grab;
}
.preset-slot.filled:active { cursor: grabbing; }
.preset-slot.drag-over {
  border-color: var(--magenta);
  background: rgba(255, 58, 165, 0.14);
  color: var(--magenta);
}
/* Slot dans le range du séquenceur (FROM..TO) — outline magenta dim */
.preset-slot.in-range:not(.active-by-seq) {
  outline: 1px solid var(--magenta-dim);
  outline-offset: -2px;
}
/* Slot actif sélectionné par le séquenceur — magenta plein + glow */
.preset-slot.active-by-seq {
  border-color: var(--magenta);
  background: rgba(255, 58, 165, 0.20);
  color: var(--magenta);
  box-shadow: 0 0 10px rgba(255, 58, 165, 0.6);
}

/* Controls du séquenceur de presets (ON / RATE / RND / FROM / TO) */
.preset-seq-controls {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 3px;
  width: 100%;
  padding-top: 4px;
  border-top: 1px solid var(--border);
}
.preset-seq-btn {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-dim);
  font-family: inherit;
  font-size: 9px;
  letter-spacing: 0.15em;
  font-weight: 700;
  padding: 4px 0;
  border-radius: 2px;
  cursor: pointer;
  transition: all 120ms ease;
  text-align: center;
}
.preset-seq-btn:hover {
  border-color: var(--magenta-dim);
  color: var(--magenta-dim);
}
.preset-seq-btn.active {
  background: rgba(255, 58, 165, 0.15);
  border-color: var(--magenta);
  color: var(--magenta);
  box-shadow: 0 0 6px rgba(255, 58, 165, 0.35);
}
.preset-seq-field {
  display: flex;
  align-items: center;
  gap: 3px;
  font-size: 8px;
  letter-spacing: 0.1em;
  color: var(--text-dim);
  font-weight: 700;
}
.preset-seq-field span { min-width: 26px; }
.preset-seq-field select {
  flex: 1;
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
  font-family: inherit;
  font-size: 9px;
  padding: 2px 3px;
  border-radius: 2px;
  cursor: pointer;
  min-width: 0;
}
.preset-seq-field select:hover { border-color: var(--magenta-dim); }

/* QUANTIZE row : à côté du séquenceur, sous le pad. */
.preset-quantize-controls {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 3px;
  margin-top: 2px;
}

/* Bar counter : affiche "BAR N" pendant le play, et "BAR N → M" quand un
   preset est armé en attente de quantize boundary. Placé dans le header
   à droite du bouton PLAY pour rester toujours visible. */
.bar-counter {
  font-family: inherit;
  font-size: 10px;
  letter-spacing: 0.2em;
  font-weight: 700;
  color: var(--text-dim);
  padding: 5px 10px;
  border: 1px solid var(--border);
  border-radius: 3px;
  background: rgba(0, 0, 0, 0.35);
  min-width: 96px;
  text-align: center;
  white-space: nowrap;
  align-self: center;
}
.bar-counter.pending {
  border-color: #ffd84a;
  color: #ffd84a;
  background: rgba(255, 216, 74, 0.14);
  animation: bar-counter-pulse 0.8s ease-in-out infinite;
}
@keyframes bar-counter-pulse {
  0%, 100% { box-shadow: 0 0 4px rgba(255, 216, 74, 0.3); }
  50%      { box-shadow: 0 0 14px rgba(255, 216, 74, 0.7); }
}

/* Preset en attente d'être appliqué (quantize armé) : pulse jaune */
.preset-slot.pending {
  border-color: #ffd84a !important;
  background: rgba(255, 216, 74, 0.18);
  color: #ffd84a;
  animation: preset-pending-pulse 0.8s ease-in-out infinite;
}
@keyframes preset-pending-pulse {
  0%, 100% { box-shadow: 0 0 6px rgba(255, 216, 74, 0.45); }
  50%      { box-shadow: 0 0 14px rgba(255, 216, 74, 0.85); }
}
/* × delete : visible seulement sur les slots remplis, en haut à droite */
.preset-slot-delete {
  position: absolute;
  top: -1px;
  right: 0;
  width: 12px;
  height: 12px;
  background: transparent;
  border: none;
  color: var(--text-dim);
  font-size: 11px;
  line-height: 1;
  font-weight: 700;
  cursor: pointer;
  padding: 0;
  display: none;
  border-radius: 2px;
}
.preset-slot.filled .preset-slot-delete { display: block; }
.preset-slot-delete:hover {
  color: var(--magenta);
  background: rgba(255, 58, 165, 0.18);
}
/* Flash vert bref à la save (dblclick) */
.preset-slot.flash-save { animation: preset-flash 420ms ease-out; }
@keyframes preset-flash {
  0%   { box-shadow: 0 0 14px 3px rgba(95, 192, 128, 0.95); transform: scale(1.05); }
  100% { box-shadow: 0 0 0   0   rgba(95, 192, 128, 0);     transform: scale(1);    }
}
.header-reset,
.header-save,
.header-load,
.header-rec,
.header-fullscreen,
.header-map {
  background: transparent;
  font-family: inherit;
  font-size: 10px;
  letter-spacing: 0.18em;
  font-weight: 700;
  padding: 6px 12px;
  border-radius: 3px;
  cursor: pointer;
  transition: all 140ms ease;
  margin-left: 4px;
}
.header-reset {
  border: 1px solid #6a1a4a;
  color: #ff3aa5;
}
.header-reset:hover {
  background: rgba(255, 58, 165, 0.12);
  border-color: var(--magenta);
  box-shadow: 0 0 8px rgba(255, 58, 165, 0.3);
}
.header-save {
  border: 1px solid #1a6a3a;
  color: #5fc080;
}
.header-save:hover {
  background: rgba(95, 192, 128, 0.12);
  border-color: #5fc080;
  box-shadow: 0 0 8px rgba(95, 192, 128, 0.3);
}
.header-load {
  border: 1px solid #1a5a6a;
  color: #5fc0d0;
}
.header-load:hover {
  background: rgba(95, 192, 208, 0.12);
  border-color: #5fc0d0;
  box-shadow: 0 0 8px rgba(95, 192, 208, 0.3);
}
.header-rec {
  border: 1px solid #6a2a2a;
  color: #ff5050;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.header-fullscreen {
  border: 1px solid #4a3a6a;
  color: #b0a0e0;
}
.header-fullscreen:hover {
  background: rgba(176, 160, 224, 0.12);
  border-color: #b0a0e0;
  box-shadow: 0 0 8px rgba(176, 160, 224, 0.3);
}
.header-fullscreen.active {
  background: rgba(176, 160, 224, 0.18);
  border-color: #b0a0e0;
  color: #fff;
  box-shadow: 0 0 8px rgba(176, 160, 224, 0.45);
}
.header-map {
  border: 1px solid #6a5a1a;
  color: #e0c050;
}
.header-map:hover {
  background: rgba(224, 192, 80, 0.12);
  border-color: #e0c050;
  box-shadow: 0 0 8px rgba(224, 192, 80, 0.3);
}
.header-map.active {
  background: rgba(224, 192, 80, 0.22);
  border-color: #ffd840;
  color: #fff8d0;
  box-shadow: 0 0 14px rgba(255, 216, 64, 0.55);
  animation: map-pulse 1.2s ease-in-out infinite;
}
@keyframes map-pulse {
  0%, 100% { box-shadow: 0 0 10px rgba(255, 216, 64, 0.45); }
  50%      { box-shadow: 0 0 18px rgba(255, 216, 64, 0.75); }
}

/* Learn mode global : tous les <button> reçoivent un outline subtle pour
   signaler qu'ils sont mappables. Le bouton armé pulse en jaune vif. */
body.map-learn button:not(.header-map):not(.map-armed) {
  outline: 1px dashed rgba(224, 192, 80, 0.55);
  outline-offset: 1px;
  cursor: crosshair !important;
}
body.map-learn button.map-armed {
  outline: 2px solid #ffd840 !important;
  outline-offset: 2px;
  box-shadow: 0 0 14px rgba(255, 216, 64, 0.85) !important;
  animation: map-armed-pulse 0.6s ease-in-out infinite;
}
@keyframes map-armed-pulse {
  0%, 100% { box-shadow: 0 0 10px rgba(255, 216, 64, 0.65); }
  50%      { box-shadow: 0 0 22px rgba(255, 216, 64, 1); }
}

/* Petit badge "K" en haut-droite du bouton mappé. data-mapped-key contient
   le label court ("A", "5", "F1", "↑"...). pointer-events:none pour ne pas
   intercepter les clicks. */
button.key-mapped { position: relative; }
button.key-mapped::after {
  content: attr(data-mapped-key);
  position: absolute;
  top: -4px;
  right: -4px;
  font-size: 8px;
  font-weight: 700;
  line-height: 1;
  padding: 2px 3px;
  border-radius: 2px;
  background: #ffd840;
  color: #1a1a1a;
  font-family: inherit;
  letter-spacing: 0;
  pointer-events: none;
  box-shadow: 0 0 4px rgba(255, 216, 64, 0.6);
  z-index: 5;
}
.header-rec::before {
  content: '';
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #ff5050;
  box-shadow: 0 0 4px rgba(255, 80, 80, 0.5);
}
.header-rec:hover {
  background: rgba(255, 80, 80, 0.12);
  border-color: #ff5050;
  box-shadow: 0 0 8px rgba(255, 80, 80, 0.3);
}
.header-rec.recording {
  background: rgba(255, 30, 30, 0.18);
  border-color: #ff2020;
  color: #ff6060;
  animation: rec-pulse 1s ease-in-out infinite;
}
.header-rec.recording::before {
  animation: rec-dot-pulse 1s ease-in-out infinite;
}
@keyframes rec-pulse {
  0%, 100% { box-shadow: 0 0 6px rgba(255, 32, 32, 0.35); }
  50%      { box-shadow: 0 0 14px rgba(255, 32, 32, 0.75); }
}
@keyframes rec-dot-pulse {
  0%, 100% { background: #ff2020; box-shadow: 0 0 4px rgba(255, 32, 32, 0.6); transform: scale(1); }
  50%      { background: #ff6060; box-shadow: 0 0 10px rgba(255, 32, 32, 1);  transform: scale(1.2); }
}


/* ---------- Bottom row : canvas du patch-bay. Prend tout l'espace vertical
   restant via grid 1fr. Anchor pour le SVG des câbles. ---------- */
.bottom-row {
  position: relative;
  width: 100%;
  height: 100%;             /* Remplit la row 1fr du center-col */
  overflow: hidden;         /* Modules confinés au canvas — clip mask */
  min-height: 0;
  /* Variables pour le snap visuel — synchro avec MODULE_SNAP en JS (12px) */
  --snap-size: 12px;
  --snap-dot: rgba(255, 255, 255, 0.06);
  cursor: default;
}
.bottom-row.panning { cursor: grabbing; }
/* Inner wrapper : reçoit le transform (pan + zoom). Les modules vivent dedans
   (sauf le DRUM RACK ancré qui reste viewport-fixed à l'extérieur). */
.modular-canvas-inner {
  position: absolute;
  inset: 0;
  transform-origin: 0 0;
  will-change: transform;
  /* Doit être AU-DESSUS du SVG patch-bay (z-index 5) pour que les modules
     internes recouvrent les câbles — sinon les cables passent devant. */
  z-index: 6;
}
/* Zoom indicator + reset btn : petit overlay en bas-droite (au-dessus de tout) */
.canvas-zoom-indicator {
  position: absolute;
  left: 8px;
  top: 8px;
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 3px 6px;
  background: rgba(15, 10, 22, 0.85);
  border: 1px solid var(--border);
  border-radius: 3px;
  font-size: 9px;
  letter-spacing: 0.18em;
  font-weight: 700;
  color: var(--text-dim);
  z-index: 1000;
  pointer-events: auto;
  user-select: none;
}
.canvas-zoom-indicator button {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-dim);
  font-family: inherit;
  font-size: 10px;
  font-weight: 700;
  line-height: 1;
  width: 18px;
  height: 16px;
  border-radius: 2px;
  cursor: pointer;
  padding: 0;
  transition: all 120ms ease;
}
.canvas-zoom-indicator button:hover { border-color: var(--accent-dim); color: var(--accent-dim); }
.canvas-zoom-indicator .pct { min-width: 32px; text-align: center; color: var(--accent-dim); }
/* Grille de snap visible UNIQUEMENT pendant un drag. Pattern de points
   discret aligné sur MODULE_SNAP — donne le repère sans surcharger l'UI. */
.bottom-row.snapping::before {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image:
    radial-gradient(circle, var(--snap-dot) 1px, transparent 1.5px);
  background-size: var(--snap-size) var(--snap-size);
  background-position: 0 0;
  animation: snap-grid-fade 180ms ease;
  z-index: 0;
}
@keyframes snap-grid-fade {
  from { opacity: 0; }
  to   { opacity: 1; }
}
/* Modules en positionnement absolu — JS écrit style.left / style.top via
   applyAllModulePositions(). Largeur fixe pour cohérence visuelle.
   z-index de base 10 pour passer au-dessus du lane-board (z-index 1/2 sur
   certains de ses enfants), sinon le bord supérieur d'un module au top du
   canvas serait recouvert et impossible à attraper avant un premier click. */
.bottom-row .seq-box,
.bottom-row .bass-box,
.bottom-row .poly-box,
.bottom-row .slicer-box {
  position: absolute;
  width: 276px;
  top: 0;
  left: 0;
  z-index: 10;
}
.bottom-row .drum-rack-box {
  position: absolute;
  width: 720px;          /* large pour accueillir 8 lane strips + sidebar */
  max-width: 100%;       /* ne dépasse jamais bottom-row */
  box-sizing: border-box;
  top: 0;
  left: 0;
  z-index: 10;
  /* overflow: visible pour que les ports trig OUT (positionnés au-dessus
     du header avec top: -36px sur les pr-cell) ne soient pas clippés.
     Le clipping du contenu interne est géré par .lane-board { overflow: hidden }. */
  overflow: visible;
}
.drum-rack-box {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 4px 6px 6px;
  background: rgba(12, 12, 20, 0.85);
  border: 1px solid var(--border);
  border-radius: 4px;
  min-width: 0;
}
.drum-rack-header {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1px 4px 2px;
}
.drum-rack-title {
  font-family: inherit;
  font-size: 10px;
  letter-spacing: 0.35em;
  font-weight: 700;
  color: var(--text-dim);
  text-transform: uppercase;
}
.drum-rack-box:hover .drum-rack-title { color: var(--accent-dim); }
.drum-rack-box .module-grip:hover { color: #ffa84a; }

/* Drum rack header buttons : mute (ON/OFF), solo (S), choke (—/A..D). Anchored
   left side, mirror du dock à droite. Style cohérent avec .bass-enable / .module-solo. */
.drum-rack-header .drum-rack-mute,
.drum-rack-header .module-solo,
.drum-rack-header .module-choke {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-dim);
  font-family: inherit;
  font-size: 9px;
  font-weight: 700;
  line-height: 1;
  height: 16px;
  min-width: 22px;
  padding: 0 5px;
  border-radius: 2px;
  cursor: pointer;
  letter-spacing: 0.1em;
  transition: all 120ms ease;
}
.drum-rack-header .drum-rack-mute        { left: 6px; }
.drum-rack-header .module-solo           { left: 36px; }
.drum-rack-header .module-choke          { left: 60px; min-width: 18px; padding: 0 3px; }

.drum-rack-header .drum-rack-mute:hover  { border-color: #ffa84a; color: #ffa84a; }
.drum-rack-header .drum-rack-mute.active {
  background: rgba(255, 168, 74, 0.22);
  border-color: #ffa84a;
  color: #ffa84a;
}
.drum-rack-header .drum-rack-mute.muted  {
  background: rgba(120, 120, 120, 0.15);
  border-color: #555;
  color: #888;
  text-decoration: line-through;
}
/* Bouton dock : icône ⇿ pour basculer entre free et full-width ancré */
.drum-rack-dock {
  position: absolute;
  right: 4px;
  top: 50%;
  transform: translateY(-50%);
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-dim);
  font-family: inherit;
  font-size: 11px;
  font-weight: 700;
  line-height: 1;
  width: 22px;
  height: 16px;
  border-radius: 2px;
  cursor: pointer;
  padding: 0;
  transition: all 120ms ease;
}
.drum-rack-dock:hover { border-color: #ffa84a; color: #ffa84a; }
.drum-rack-dock.active {
  background: rgba(255, 168, 74, 0.22);
  border-color: #ffa84a;
  color: #ffa84a;
  box-shadow: 0 0 6px rgba(255, 168, 74, 0.55);
}

/* État docked : ancre full-width en BAS du canvas (override la règle absolute
   width:720px). C'est le défaut. Cursor "default" sur le grip pour signaler
   que c'est verrouillé. */
.bottom-row .drum-rack-box.docked {
  left: 0 !important;
  right: 0 !important;             /* ancrage explicite au bord droit du canvas */
  top: auto !important;
  bottom: 0 !important;
  width: auto !important;          /* derived from left:0 + right:0 */
  max-width: 100% !important;
  box-sizing: border-box !important;
  z-index: 11;
}
/* NOTE : on a déjà overflow:hidden sur bottom-row. Surtout PAS de
   `contain: layout paint` ici — ça créerait un containing block pour les
   éléments position:fixed descendants, et le SVG patch-bay (position:fixed)
   ne pourrait plus spanner le viewport. Cables → SEQ dans la colonne gauche
   seraient cassés. */
.drum-rack-box.docked .module-grip {
  cursor: default;
  opacity: 0.35;
}
.drum-rack-box.docked .module-grip:hover {
  color: rgba(255, 255, 255, 0.22);   /* pas de hover effect en docked */
  background-color: transparent;
}
/* Grip handle : petite bande dotted en haut de chaque module = drag handle */
.module-grip {
  height: 12px;
  margin: -2px -2px 4px;        /* déborde légèrement pour s'aligner au top du module */
  cursor: grab;
  border-radius: 4px 4px 0 0;
  user-select: none;
  /* Pattern de points horizontal centré (radial gradient répété) */
  background:
    radial-gradient(circle, currentColor 1px, transparent 1.5px) 0 50% / 7px 100% repeat-x;
  background-position: center;
  color: rgba(255, 255, 255, 0.22);
  background-clip: padding-box;
  transition: color 120ms ease, background-color 120ms ease;
}
.module-grip:hover {
  color: rgba(255, 255, 255, 0.65);
  background-color: rgba(255, 255, 255, 0.04);
}
.module-grip:active {
  cursor: grabbing;
  color: rgba(255, 255, 255, 0.9);
  background-color: rgba(255, 255, 255, 0.08);
}
/* Variations de teinte selon le module (subtil, hover seulement) */
.seq-box    .module-grip:hover { color: #b07ad0; }
.bass-box   .module-grip:hover { color: var(--accent); }
.poly-box   .module-grip:hover { color: #ff7ad0; }
.slicer-box .module-grip:hover { color: #ffa84a; }
/* Pendant un drag de module, désactive les transitions et highlight */
.bottom-row .module-dragging {
  opacity: 0.92;
  z-index: 20;
  box-shadow: 0 4px 20px rgba(176, 122, 208, 0.4);
  transition: none !important;
}

/* ---------- Bouton + (add module) + menu popover ---------- */
.patch-add-btn {
  position: absolute;
  right: 8px;
  top: 8px;             /* ancré en haut, hors du canva pan/zoom */
  width: 32px;
  height: 32px;
  border-radius: 50%;
  border: 1px solid #6a4a8a;
  background: rgba(20, 12, 28, 0.85);
  color: #b07ad0;
  font-size: 18px;
  font-weight: 700;
  font-family: inherit;
  cursor: pointer;
  transition: all 140ms ease;
  z-index: 15;
  display: flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
}
.patch-add-btn:hover {
  background: rgba(176, 122, 208, 0.18);
  border-color: #b07ad0;
  color: #d8a8e8;
  box-shadow: 0 0 10px rgba(176, 122, 208, 0.5);
  transform: scale(1.08);
}
.patch-add-btn.open {
  background: rgba(176, 122, 208, 0.25);
  color: #fff;
  transform: rotate(45deg);
}
.patch-add-menu {
  position: absolute;
  right: 8px;
  top: 46px;            /* dropdown sous le bouton + (qui est en haut) */
  z-index: 16;
  background: rgba(15, 10, 22, 0.95);
  border: 1px solid #6a4a8a;
  border-radius: 4px;
  padding: 4px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.6);
  min-width: 140px;
}
.patch-add-menu[hidden] { display: none; }
.patch-add-category {
  font-size: 8px;
  letter-spacing: 0.2em;
  font-weight: 700;
  color: #6a4a8a;
  padding: 6px 12px 2px;
  border-top: 1px solid #2a1a4a;
  margin-top: 2px;
}
.patch-add-category:first-child {
  border-top: none;
  margin-top: 0;
}
.patch-add-menu button {
  background: transparent;
  border: 1px solid transparent;
  color: #b07ad0;
  font-family: inherit;
  font-size: 10px;
  letter-spacing: 0.15em;
  font-weight: 700;
  padding: 8px 12px;
  text-align: left;
  cursor: pointer;
  border-radius: 2px;
  transition: all 120ms ease;
}
.patch-add-menu button:hover {
  background: rgba(176, 122, 208, 0.15);
  border-color: #b07ad0;
  color: #d8a8e8;
}

/* ---------- SLICER module (sample slicer 16-step) ---------- */
.slicer-box {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 6px;
  background: rgba(12, 12, 20, 0.85);
  border: 1px solid #8a6a2a;       /* orange/ambre — couleur signature slicer */
  border-radius: 4px;
  min-width: 0;
}
.slicer-box .slicer-title { color: #ffa84a; }
.slicer-box-body {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 4px 2px 2px;
}
.slicer-sample-drop {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 4px;
  background: rgba(20, 14, 8, 0.7);
  border: 1px dashed #6a4a2a;
  border-radius: 3px;
  cursor: pointer;
  transition: all 140ms ease;
}
.slicer-sample-drop:hover {
  border-color: #ffa84a;
  background: rgba(255, 168, 74, 0.04);
}
.slicer-sample-drop.drag-over {
  border-color: #ffa84a;
  border-style: solid;
  background: rgba(255, 168, 74, 0.18);
  box-shadow: 0 0 8px rgba(255, 168, 74, 0.4);
}
/* Waveform SVG — pleine largeur, hauteur fixe */
.slicer-waveform {
  display: block;
  width: 100%;
  height: 48px;
  pointer-events: none;        /* le drop est sur le parent */
}
.slicer-waveform-path {
  fill: none;
  stroke: #ffa84a;
  stroke-width: 0.5;
  stroke-linecap: round;
  opacity: 0.85;
}
.slicer-slice-boundary {
  stroke: rgba(255, 255, 255, 0.18);
  stroke-width: 0.5;
  stroke-dasharray: 2 2;
}
.slicer-slice-boundary.is-bar {
  /* Boundary de fin de bar : trait continu plus visible */
  stroke: rgba(255, 168, 74, 0.55);
  stroke-width: 0.8;
  stroke-dasharray: none;
}
.slicer-waveform-placeholder {
  fill: rgba(255, 168, 74, 0.5);
  font-family: inherit;
  font-size: 8px;
  letter-spacing: 0.15em;
}
.slicer-sample-name {
  font-size: 8px;
  letter-spacing: 0.1em;
  color: rgba(255, 168, 74, 0.7);
  white-space: nowrap;
  text-overflow: ellipsis;
  overflow: hidden;
  padding: 0 4px;
  text-align: center;
  font-style: italic;
}
.slicer-sample-name:empty::before {
  content: '— no sample —';
  color: rgba(255, 255, 255, 0.2);
}
/* File input is hidden but functional */
.slicer-file-input { display: none; }
/* BARS selector row : compact à droite du label, info "N slices" à côté */
.slicer-bars-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0 2px;
}
.slicer-bars-row .bass-field {
  flex-shrink: 0;
}
.slicer-bars-row select {
  font-size: 9px;
  padding: 2px 4px;
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 2px;
}
.slicer-slices-info {
  font-size: 8px;
  letter-spacing: 0.15em;
  color: rgba(255, 168, 74, 0.55);
  font-style: italic;
}

/* BREAKS row : select + dice random pour piocher un break dans /loops/Breaks */
.slicer-breaks-row {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 0 2px;
}
.slicer-breaks-row .bass-field {
  flex: 1;
  min-width: 0;
}
.slicer-breaks-row select {
  font-size: 9px;
  padding: 2px 4px;
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 2px;
  width: 100%;
  min-width: 0;
}
.slicer-break-dice-group {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 2px;
  flex-shrink: 0;
}
.slicer-break-dice {
  background: rgba(255, 168, 74, 0.12);
  border: 1px solid #8a5a2a;
  color: #ffa84a;
  font-size: 12px;
  line-height: 1;
  width: 22px;
  height: 18px;
  padding: 0;
  border-radius: 2px;
  cursor: pointer;
  transition: all 120ms ease;
  flex-shrink: 0;
}
.slicer-break-dice:hover {
  background: rgba(255, 168, 74, 0.25);
  border-color: #ffa84a;
  color: #ffd84a;
  box-shadow: 0 0 6px rgba(255, 168, 74, 0.4);
}
.slicer-break-dice-group .auto-btn {
  /* compact pour fit sous le 🎲 (largeur 22px) */
  font-size: 7px;
  padding: 1px 0;
  width: 22px;
  height: 14px;
  letter-spacing: 0.08em;
}

/* Grain : ligne nom de sample + badge de note détectée à droite */
.grain-sample-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
  min-width: 0;
}
.grain-sample-row .slicer-sample-name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.grain-key-badge {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 28px;
  height: 16px;
  padding: 0 5px;
  border-radius: 3px;
  background: rgba(255, 168, 74, 0.10);
  border: 1px solid #6a4a20;
  color: #888;
  font-family: inherit;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.05em;
  cursor: help;
  transition: all 120ms ease;
}
.grain-key-badge.detected {
  background: rgba(255, 168, 74, 0.22);
  border-color: #ffa84a;
  color: #ffd84a;
  box-shadow: 0 0 4px rgba(255, 168, 74, 0.35);
}

/* ============================================================================
   GRAIN · FOLDER UPLOAD — bouton FOLDER + dropdown picker + DICE.
   Style cohérent avec slicer-breaks-row.
   ============================================================================ */
.grain-folder-row {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 2px;
}
.grain-folder-btn {
  background: rgba(255, 168, 74, 0.10);
  border: 1px solid #6a4a20;
  color: #ffa84a;
  font-family: inherit;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.15em;
  padding: 4px 8px;
  border-radius: 2px;
  cursor: pointer;
  transition: all 120ms ease;
  align-self: stretch;
}
.grain-folder-btn:hover {
  background: rgba(255, 168, 74, 0.22);
  border-color: #ffa84a;
  color: #ffd84a;
  box-shadow: 0 0 6px rgba(255, 168, 74, 0.35);
}
.grain-folder-wrap {
  display: flex;
  align-items: center;
  gap: 4px;
  min-width: 0;
}
.grain-folder-wrap[hidden] { display: none; }
.grain-folder-select {
  flex: 1;
  min-width: 0;
  font-size: 9px;
  padding: 2px 4px;
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 2px;
}
.grain-folder-dice-group {
  display: flex;
  align-items: center;
  gap: 2px;
  flex-shrink: 0;
}
.grain-folder-dice-group button {
  background: rgba(255, 168, 74, 0.12);
  border: 1px solid #8a5a2a;
  color: #ffa84a;
  font-size: 10px;
  line-height: 1;
  width: 20px;
  height: 18px;
  padding: 0;
  border-radius: 2px;
  cursor: pointer;
  transition: all 120ms ease;
  flex-shrink: 0;
}
.grain-folder-dice-group button:hover {
  background: rgba(255, 168, 74, 0.25);
  border-color: #ffa84a;
  color: #ffd84a;
  box-shadow: 0 0 6px rgba(255, 168, 74, 0.4);
}
.grain-folder-dice-group .grain-folder-rand {
  font-size: 12px;
}
.grain-folder-dice-group .grain-folder-clear {
  background: rgba(255, 80, 112, 0.10);
  border-color: #6a2030;
  color: #ff8090;
}
.grain-folder-dice-group .grain-folder-clear:hover {
  background: rgba(255, 80, 112, 0.22);
  border-color: #ff5070;
  color: #ffb0b8;
  box-shadow: 0 0 6px rgba(255, 80, 112, 0.4);
}

.slicer-pattern-grid {
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  gap: 2px;
}
/* Pour bars > 1 (= pattern length 32 ou 64), affiche 16 cells par row pour
   garder un visuel "1 row = 1 bar" et limiter la hauteur. */
.slicer-pattern-grid.grid-wide {
  grid-template-columns: repeat(16, 1fr);
  gap: 1px;
}
.slicer-pattern-grid.grid-wide .slicer-pattern-cell {
  height: 22px;
}
.slicer-pattern-grid.grid-wide .step-num { font-size: 5px; top: 0; left: 1px; }
.slicer-pattern-grid.grid-wide .slice-num { font-size: 8px; }
.slicer-pattern-cell {
  position: relative;
  height: 28px;
  border: 1px solid #3a3a4a;
  border-radius: 2px;
  background: rgba(20, 14, 8, 0.7);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: all 100ms ease;
  user-select: none;
}
.slicer-pattern-cell:hover {
  border-color: #ffa84a;
  background: rgba(255, 168, 74, 0.18);
}
.slicer-pattern-cell .step-num {
  position: absolute;
  top: 1px;
  left: 2px;
  font-size: 6px;
  color: rgba(255, 255, 255, 0.25);
  pointer-events: none;
}
.slicer-pattern-cell .slice-num {
  font-size: 11px;
  font-weight: 700;
  color: #ffa84a;
  letter-spacing: 0;
}
.slicer-pattern-cell.skip {
  background: rgba(10, 10, 16, 0.6);
  border-color: #2a2a3a;
}
.slicer-pattern-cell.skip .slice-num {
  color: rgba(255, 255, 255, 0.2);
}
/* Pattern actions : RESET + DICE row */
.slicer-actions {
  display: flex;
  gap: 4px;
  padding: 0 2px;
}
.slicer-action {
  flex: 1;
  background: transparent;
  border: 1px solid #6a4a2a;
  color: #ffa84a;
  font-family: inherit;
  font-size: 9px;
  letter-spacing: 0.15em;
  font-weight: 700;
  padding: 4px 6px;
  border-radius: 2px;
  cursor: pointer;
  transition: all 120ms ease;
}
.slicer-action:hover {
  background: rgba(255, 168, 74, 0.14);
  border-color: #ffa84a;
  box-shadow: 0 0 6px rgba(255, 168, 74, 0.3);
}
.slicer-action:active {
  background: rgba(255, 168, 74, 0.25);
}
/* Petits −/+ random buttons (à côté de DICE) — plus étroits pour ne pas dominer */
.slicer-action.slicer-occ {
  flex: 0 0 24px;
  padding: 4px 0;
  font-size: 11px;
  letter-spacing: 0;
}
.slicer-dice.rolling {
  animation: slicer-dice-roll 420ms ease-out;
}
@keyframes slicer-dice-roll {
  0%   { transform: rotate(0deg)   scale(1);    box-shadow: 0 0 0   0 rgba(255, 168, 74, 0);   }
  40%  { transform: rotate(180deg) scale(1.12); box-shadow: 0 0 14px 2px rgba(255, 168, 74, 0.8); }
  100% { transform: rotate(360deg) scale(1);    box-shadow: 0 0 0   0 rgba(255, 168, 74, 0);   }
}

.slicer-sliders {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr 1fr;
  gap: 3px;
}
.slicer-sliders .bass-field span.mod-label { min-width: 22px; }
.slicer-box .bass-field { font-size: 7px; gap: 3px; }
.slicer-box .bass-slider { height: 10px; }
.slicer-box .bass-field span.mod-label { min-width: 28px; }
.slicer-box .slider .fill { background: #6a4a2a; }
.slicer-box .slider:hover .fill {
  background: #ffa84a;
  box-shadow: 0 0 8px rgba(255, 168, 74, 0.45);
}
.slicer-box .slider.bipolar::before {
  content: '';
  position: absolute;
  top: 2px;
  bottom: 2px;
  left: 50%;
  width: 1px;
  background: rgba(255, 168, 74, 0.6);
  pointer-events: none;
  z-index: 1;
}

/* ---------- Mono trigger XY pad + cells (Euclidean rhythm generator) ---------- */
.bass-trig-section { padding: 4px 6px; }
.bass-trig-row {
  display: flex;
  align-items: center;
  gap: 8px;
}
.bass-trig-xy {
  position: relative;
  width: 60px;
  height: 60px;
  /* Grid 8×8 background (12.5% spacing) pour visualiser les cells discrètes */
  background:
    linear-gradient(to right, rgba(0,240,255,0.05) 1px, transparent 1px) 0 0 / 12.5% 100%,
    linear-gradient(to top,   rgba(0,240,255,0.05) 1px, transparent 1px) 0 0 / 100% 12.5%,
    rgba(10, 10, 16, 0.7);
  border: 1px solid #2a4a5a;
  border-radius: 3px;
  cursor: crosshair;
  flex-shrink: 0;
  user-select: none;
  overflow: visible;
}
.bass-trig-xy:hover { border-color: var(--accent-dim); }
.bass-trig-xy-dot {
  position: absolute;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 8px rgba(0, 240, 255, 0.7);
  transform: translate(-50%, 50%);
  pointer-events: none;
  transition: left 50ms ease, bottom 50ms ease;
}
.bass-trig-xy-label {
  position: absolute;
  top: 2px;
  left: 4px;
  font-size: 7px;
  letter-spacing: 0.15em;
  color: rgba(0, 240, 255, 0.5);
  font-weight: 700;
  pointer-events: none;
}
.bass-trig-info {
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-family: inherit;
  flex-shrink: 0;
  flex: 1;
}
.bass-trig-style {
  font-size: 10px;
  letter-spacing: 0.16em;
  font-weight: 700;
  color: var(--accent);
  text-align: center;
  padding: 3px 4px;
  background: rgba(0, 240, 255, 0.08);
  border: 1px solid rgba(0, 240, 255, 0.3);
  border-radius: 2px;
}
.bass-trig-pulses-info {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 3px;
  font-size: 8px;
  letter-spacing: 0.08em;
  color: var(--text);
}
.bass-trig-pulses-info span:first-child {
  font-size: 12px;
  font-weight: 700;
  color: var(--accent);
}
.bass-trig-info-suffix {
  color: var(--text-dim);
  letter-spacing: 0.18em;
}
.bass-trig-cells {
  display: grid;
  grid-template-columns: repeat(16, 1fr);
  gap: 1px;
  margin-top: 3px;
}
.bass-trig-cell {
  position: relative;
  height: 9px;
  background: rgba(10, 10, 16, 0.6);
  border: 1px solid #2a2a3a;
  border-radius: 1px;
  cursor: pointer;
  transition: border-color 120ms ease, box-shadow 120ms ease;
  --prob: 0;
  overflow: hidden;
}
/* Le fill probabilistique : opacity reflète la valeur de --prob (0..1) */
.bass-trig-cell::before {
  content: '';
  position: absolute;
  inset: 0;
  background: rgba(0, 240, 255, 0.85);
  opacity: var(--prob);
  transition: opacity 320ms ease;        /* smooth breathing au drift */
  border-radius: 1px;
}
.bass-trig-cell:hover { border-color: var(--accent-dim); }
.bass-trig-cell.lock-on {
  /* Locked ON : bord cyan vif, certitude de fire */
  border-color: var(--accent);
  box-shadow: 0 0 5px rgba(0, 240, 255, 0.7);
}
.bass-trig-cell.lock-off {
  /* Locked OFF : bord rouge sombre, force silence */
  border-color: #6a2a2a;
}
.bass-trig-cell.lock-off::before {
  background: rgba(80, 30, 30, 0.6);
}
.bass-trig-cell.current {
  /* Playhead : halo magenta sur la cell en cours */
  border-color: var(--magenta);
  box-shadow: 0 0 6px rgba(255, 58, 165, 0.8);
}
.bass-trig-cell.current::after {
  /* Petit overlay magenta pour bien marquer le playhead */
  content: '';
  position: absolute;
  inset: 0;
  background: rgba(255, 58, 165, 0.25);
  border-radius: 1px;
  pointer-events: none;
}

/* Choke group button : cycle —/A/B/C/D, couleur par groupe pour clarté */
.module-choke {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-dim);
  font-family: inherit;
  font-size: 9px;
  letter-spacing: 0.1em;
  font-weight: 700;
  width: 20px;
  height: 18px;
  border-radius: 2px;
  cursor: pointer;
  padding: 0;
  line-height: 1;
  transition: all 120ms ease;
  flex-shrink: 0;
}
.module-choke:hover {
  border-color: var(--accent-dim);
  color: var(--accent-dim);
}
.module-choke.active { border-color: currentColor; }
.module-choke[data-group="A"] { color: #ff5070; border-color: #ff5070; background: rgba(255, 80, 112, 0.12); }
.module-choke[data-group="B"] { color: #5fc080; border-color: #5fc080; background: rgba(95, 192, 128, 0.12); }
.module-choke[data-group="C"] { color: #5fa8e0; border-color: #5fa8e0; background: rgba(95, 168, 224, 0.12); }
.module-choke[data-group="D"] { color: #ffd84a; border-color: #ffd84a; background: rgba(255, 216, 74, 0.12); }

/* SOLO button per-module (bass, poly, slicer, grain, extras). Quand actif,
   tous les modules non-soloés reçoivent .module-solo-silenced (opacity réduite). */
.module-solo {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-dim);
  font-family: inherit;
  font-size: 9px;
  letter-spacing: 0.1em;
  font-weight: 700;
  width: 18px;
  height: 18px;
  border-radius: 2px;
  cursor: pointer;
  padding: 0;
  line-height: 1;
  transition: all 120ms ease;
  flex-shrink: 0;
}
.module-solo:hover { border-color: #ffd84a; color: #ffd84a; }
.module-solo.active {
  background: rgba(255, 216, 74, 0.22);
  border-color: #ffd84a;
  color: #ffd84a;
  box-shadow: 0 0 6px rgba(255, 216, 74, 0.55);
}
/* Module soloed : bordure jaune sur la box entière */
.bass-box.module-soloed,
.poly-box.module-soloed,
.slicer-box.module-soloed,
.grain-box.module-soloed {
  box-shadow: 0 0 10px rgba(255, 216, 74, 0.35), inset 0 0 0 1px rgba(255, 216, 74, 0.5);
}
/* Module silenced par solo d'un autre module : grisé */
.bass-box.module-solo-silenced,
.poly-box.module-solo-silenced,
.slicer-box.module-solo-silenced,
.grain-box.module-solo-silenced {
  opacity: 0.35;
  filter: saturate(0.4);
}

/* X delete button sur les modules clonés (extras seulement) */
.module-delete {
  background: transparent;
  border: 1px solid transparent;
  color: #6a6a8a;
  font-family: inherit;
  font-size: 14px;
  font-weight: 700;
  width: 18px;
  height: 18px;
  border-radius: 2px;
  cursor: pointer;
  padding: 0;
  line-height: 1;
  margin-left: auto;
  transition: all 120ms ease;
}
.module-delete:hover {
  border-color: #ff5050;
  color: #ff5050;
  background: rgba(255, 80, 80, 0.12);
}

/* ---------- Patch bay (SVG overlay pour les câbles modulaires) ----------
   En position fixed full-viewport pour spanner le lane-board (haut)
   ET les modules (bas) — câbles drum→synth visibles à travers la page. */
.patch-bay {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  overflow: visible;
  z-index: 5;
}
.patch-bay .cable {
  fill: none;
  stroke: #b07ad0;            /* Violet du SEQ */
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  /* pointer-events: none = câble n'intercepte JAMAIS la souris → drag des modules
     en-dessous fonctionne même si un câble traverse. Disconnect = click sur port. */
  pointer-events: none;
  transition: stroke 120ms ease, stroke-width 120ms ease;
  filter: drop-shadow(0 0 3px rgba(176, 122, 208, 0.4));
}
.patch-bay .cable-temp {
  /* Câble en cours de drag (pointillé violet pour note) */
  stroke: #b07ad0;
  stroke-width: 2;
  stroke-dasharray: 4 3;
  pointer-events: none;
  fill: none;
  filter: drop-shadow(0 0 3px rgba(176, 122, 208, 0.5));
}
.patch-bay .cable-temp-trig {
  /* Câble en cours de drag pour trigger : jaune */
  stroke: #ffd84a;
  filter: drop-shadow(0 0 3px rgba(255, 216, 74, 0.5));
}
/* Cable jaune pour les connexions trigger (lane → top port) */
/* Pulse glow sur les câbles trig quand un signal passe. CSS animation 250ms. */
.patch-bay .cable-trig.cable-pulse {
  animation: cable-trig-pulse 280ms cubic-bezier(0.2, 0.7, 0.4, 1) forwards;
}
@keyframes cable-trig-pulse {
  0% {
    stroke-width: 3.5;
    filter: drop-shadow(0 0 6px #ffd84a) drop-shadow(0 0 10px rgba(255, 216, 74, 0.6));
  }
  60% {
    stroke-width: 2.2;
    filter: drop-shadow(0 0 3px rgba(255, 216, 74, 0.5));
  }
  100% {
    stroke-width: 2;
    filter: drop-shadow(0 0 1.5px rgba(255, 216, 74, 0.25));
  }
}

/* LFO connections : pointillés rose qui relient un LFO détaché à ses targets */
.patch-bay .lfo-conn {
  fill: none;
  stroke: #ff3aa5;            /* magenta clair */
  stroke-width: 1;
  stroke-dasharray: 3 3;
  stroke-linecap: round;
  opacity: 0.5;
  pointer-events: none;
}
.patch-bay .cable-trig {
  stroke: #ffd84a;
  filter: drop-shadow(0 0 3px rgba(255, 216, 74, 0.5));
}

/* Hit-zone : path invisible large pour capter les clicks sur câble note.
   stroke-width 14 = facile à viser sans gêner le drag de modules (le câble visible
   reste 2px). pointer-events:stroke = seule la ligne, pas l'aire intérieure. */
.patch-bay .cable-hit {
  fill: none;
  stroke: transparent;
  stroke-width: 14;
  pointer-events: stroke;
  cursor: pointer;
}
.patch-bay .cable-hit:hover ~ .cable,
.patch-bay .cable-hit:hover {
  /* Pas de change visible — feedback via le curseur uniquement */
}

/* Chips d'ops affichés sur la cubic bezier du câble note */
.patch-bay .cable-op-chip {
  cursor: pointer;
  pointer-events: all;
}
.patch-bay .cable-op-chip circle {
  transition: r 120ms ease, stroke-width 120ms ease;
}
.patch-bay .cable-op-chip:hover circle {
  stroke: #fff;
  stroke-width: 1.5;
  filter: drop-shadow(0 0 4px currentColor);
}

/* Phase 1 : petit bouton + qui apparaît à la position du click sur un câble.
   Click sur ce + → ouvre la popup de shortcuts (phase 2). */
.cable-plus-btn {
  position: fixed;
  z-index: 1500;
  width: 28px;
  height: 28px;
  background: rgba(12, 12, 20, 0.96);
  border: 1.5px solid var(--accent);
  color: var(--accent);
  border-radius: 50%;
  font-family: inherit;
  font-size: 18px;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 0 12px rgba(0, 240, 255, 0.45), 0 2px 8px rgba(0, 0, 0, 0.6);
  animation: cable-plus-pop 180ms cubic-bezier(0.34, 1.56, 0.64, 1);
  transition: transform 120ms ease, box-shadow 120ms ease, background 120ms ease;
}
.cable-plus-btn:hover {
  background: var(--accent);
  color: #000;
  transform: scale(1.15);
  box-shadow: 0 0 16px rgba(0, 240, 255, 0.75), 0 2px 10px rgba(0, 0, 0, 0.7);
}
@keyframes cable-plus-pop {
  0%   { transform: scale(0.4); opacity: 0; }
  60%  { transform: scale(1.15); opacity: 1; }
  100% { transform: scale(1); opacity: 1; }
}

/* Popup d'insertion d'operator sur un câble — floating au-dessus du canvas.
   Grid de shortcuts (TRANSPOSE +12, MULT ×2, etc.) qui créent un vrai module
   operator et split le câble en source→op→dest. */
.cable-insert-popup {
  position: fixed;
  z-index: 1500;
  min-width: 260px;
  max-width: 340px;
  background: rgba(12, 12, 20, 0.96);
  border: 1px solid var(--accent-dim);
  border-radius: 4px;
  padding: 6px 8px;
  font-family: inherit;
  color: var(--text);
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.6), 0 0 8px rgba(0, 240, 255, 0.2);
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.cable-insert-popup-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 9px;
  letter-spacing: 0.15em;
  color: var(--text-dim);
  border-bottom: 1px solid var(--border);
  padding-bottom: 4px;
  text-transform: uppercase;
}
.cable-insert-close {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-dim);
  width: 18px; height: 16px;
  font-size: 11px;
  cursor: pointer;
  border-radius: 2px;
  padding: 0; line-height: 1;
}
.cable-insert-close:hover { color: #ff5070; border-color: #ff5070; }
.cable-insert-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 4px;
}
.cable-insert-btn {
  background: transparent;
  border: 1px solid var(--op-color, var(--border));
  color: var(--op-color, var(--text));
  font-family: inherit;
  font-size: 9px;
  letter-spacing: 0.08em;
  font-weight: 700;
  padding: 5px 4px;
  cursor: pointer;
  border-radius: 2px;
  transition: all 120ms ease;
  text-align: center;
}
.cable-insert-btn:hover {
  background: var(--op-color, var(--accent));
  color: #000;
  transform: scale(1.05);
}

/* Popup d'édition des ops — floating au-dessus du canvas */
.cable-ops-popup {
  position: fixed;
  z-index: 1500;
  min-width: 260px;
  max-width: 320px;
  background: rgba(12, 12, 20, 0.96);
  border: 1px solid var(--accent-dim);
  border-radius: 4px;
  padding: 6px 8px;
  font-family: inherit;
  color: var(--text);
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.6), 0 0 8px rgba(0, 240, 255, 0.2);
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.cable-ops-popup-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 9px;
  letter-spacing: 0.15em;
  color: var(--text-dim);
  border-bottom: 1px solid var(--border);
  padding-bottom: 4px;
  text-transform: uppercase;
}
.cable-ops-close {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-dim);
  width: 18px; height: 16px;
  font-size: 11px;
  cursor: pointer;
  border-radius: 2px;
  padding: 0; line-height: 1;
}
.cable-ops-close:hover { color: #ff5070; border-color: #ff5070; }

.cable-ops-row {
  display: grid;
  grid-template-columns: 22px 60px 1fr 50px 18px;
  align-items: center;
  gap: 6px;
  padding: 3px 0;
}
.cable-ops-tag {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px; height: 18px;
  background: var(--op-color, #b07ad0);
  color: #000;
  border-radius: 2px;
  font-size: 10px;
  font-weight: 700;
}
.cable-ops-name {
  font-size: 8px;
  letter-spacing: 0.12em;
  color: var(--text-dim);
}
.cable-ops-slider {
  width: 100%;
  margin: 0;
  height: 4px;
  accent-color: var(--op-color, #b07ad0);
}
.cable-ops-value {
  font-size: 10px;
  text-align: right;
  color: var(--text);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.cable-ops-remove {
  background: transparent;
  border: 1px solid #6a2030;
  color: #ff5070;
  width: 18px; height: 16px;
  font-size: 11px;
  cursor: pointer;
  border-radius: 2px;
  padding: 0; line-height: 1;
}
.cable-ops-remove:hover { background: rgba(255, 80, 112, 0.2); }

.cable-ops-add-row {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  align-items: center;
  border-top: 1px solid var(--border);
  padding-top: 6px;
  margin-top: 2px;
}
.cable-ops-add-label {
  font-size: 8px;
  letter-spacing: 0.2em;
  color: var(--text-dim);
}
.cable-ops-add-btn {
  background: transparent;
  border: 1px solid var(--op-color, var(--border));
  color: var(--op-color, var(--text));
  font-family: inherit;
  font-size: 8px;
  letter-spacing: 0.12em;
  font-weight: 700;
  padding: 3px 6px;
  cursor: pointer;
  border-radius: 2px;
  transition: all 120ms ease;
}
.cable-ops-add-btn:hover {
  background: var(--op-color, var(--accent));
  color: #000;
}

/* ---------- Module ports (jacks I/O sur les bords des modules) ---------- */
.module-port {
  position: absolute;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: #1a1a24;
  border: 2px solid #6a6a8a;
  z-index: 10;
  cursor: crosshair;
  transition: all 120ms ease;
  /* Position calée en JS via getPortPosition pour rester en sync avec le câble */
}
.module-port::after {
  /* Petit point central (jack visuel) */
  content: '';
  position: absolute;
  inset: 2px;
  border-radius: 50%;
  background: #3a3a4a;
  transition: background 120ms ease;
}
.module-port:hover {
  border-color: #ffd84a;
  box-shadow: 0 0 8px rgba(255, 216, 74, 0.6);
  transform: scale(1.15);
}
.module-port:hover::after { background: #ffd84a; }
.module-port.port-connected::after { background: #b07ad0; }
.module-port.port-drop-target {
  /* Highlight pendant un drag de câble compatible */
  border-color: #5fc080;
  box-shadow: 0 0 10px rgba(95, 192, 128, 0.8);
  animation: port-target-pulse 0.8s ease-in-out infinite;
}
.module-port.port-drop-target::after { background: #5fc080; }
@keyframes port-target-pulse {
  0%, 100% { box-shadow: 0 0 8px rgba(95, 192, 128, 0.6); }
  50%      { box-shadow: 0 0 14px rgba(95, 192, 128, 1);  }
}
/* Port out côté BAS — legacy (drum rack avant le déplacement vers le haut) */
.module-port-out[data-port-side="bottom"] {
  left: 50%;
  bottom: -7px;
  transform: translateX(-50%);
}
.module-port-out[data-port-side="bottom"]:hover {
  transform: translateX(-50%) scale(1.15);
}
/* Port out côté HAUT — drum lanes : sortie trig en haut de chaque strip,
   visuellement entre le piano-roll (VU + label) et la strip mixer. */
.module-port-out[data-port-side="top"] {
  left: 50%;
  top: -7px;
  transform: translateX(-50%);
}
.module-port-out[data-port-side="top"]:hover {
  transform: translateX(-50%) scale(1.15);
}
/* Ligne dédiée pour les ports trig OUT du DRUM RACK — 8 colonnes alignées
   sur les lanes, placée EN BAS du lane-board (standard du système : trig OUT
   en bas). Visible sous les strips de mixer. */
.lane-port-row {
  display: grid;
  grid-template-columns: repeat(8, minmax(0, 1fr));
  gap: 3px;
  padding: 6px 6px 4px;
  min-width: 0;
}
.lane-port-cell {
  position: relative;
  height: 14px;
  display: flex;
  align-items: center;
  justify-content: center;
}
/* Le port est en position relative dans sa cell (pas absolute) → centré */
.lane-port-cell .lane-port-out[data-port-side="top"],
.lane-port-cell .lane-port-out[data-port-side="bottom"] {
  position: relative;
  top: auto;
  bottom: auto;
  left: auto;
  transform: none;
}
.lane-port-cell .lane-port-out[data-port-side="top"]:hover,
.lane-port-cell .lane-port-out[data-port-side="bottom"]:hover {
  transform: scale(1.15);
}
/* Port in côté HAUT — trigger input (reçoit drum hits) */
.module-port-in[data-port-side="top"] {
  left: 50%;
  top: -7px;
  transform: translateX(-50%);
}
.module-port-in[data-port-side="top"]:hover {
  transform: translateX(-50%) scale(1.15);
}
/* Trigger ports (top + lane out) : couleur jaune pour les distinguer des notes */
.module-port-trig,
.module-port-in[data-port-kind="trigger"],
.module-port-out[data-port-kind="trigger"] {
  border-color: #ffd84a;
}
.module-port-trig::after,
.module-port-in[data-port-kind="trigger"]::after,
.module-port-out[data-port-kind="trigger"]::after {
  background: #5a4a1a;
}
.module-port-trig:hover,
.module-port-in[data-port-kind="trigger"]:hover,
.module-port-out[data-port-kind="trigger"]:hover {
  border-color: #ffd84a;
  box-shadow: 0 0 10px rgba(255, 216, 74, 0.7);
}
.module-port-trig:hover::after,
.module-port-in[data-port-kind="trigger"]:hover::after,
.module-port-out[data-port-kind="trigger"]:hover::after {
  background: #ffd84a;
}
.module-port-trig.port-connected::after,
.module-port-in[data-port-kind="trigger"].port-connected::after,
.module-port-out[data-port-kind="trigger"].port-connected::after {
  background: #ffd84a;
}
/* Drop target highlight pour ports trigger : vert (compatible) reste,
   mais on garde la teinte trigger en sub-couche pour clarté */
/* Lane strip doit être position:relative pour ancrer le port-out */
.sidebar .lane-strip { position: relative; }
/* Lane port-out est un peu plus petit pour ne pas dominer la strip */
.lane-port-out {
  width: 10px;
  height: 10px;
}

/* Port out (côté droit) — décalé sur le bord externe */
.module-port-out[data-port-side="right"] {
  right: -7px;
  top: 50%;
  transform: translateY(-50%);
}
.module-port-out[data-port-side="right"]:hover {
  transform: translateY(-50%) scale(1.15);
}
/* Port in (côté gauche) */
.module-port-in[data-port-side="left"] {
  left: -7px;
  top: 50%;
  transform: translateY(-50%);
}
.module-port-in[data-port-side="left"]:hover {
  transform: translateY(-50%) scale(1.15);
}
/* Les boxes parents doivent être position:relative pour que les ports soient ancrés */
.seq-box, .bass-box, .poly-box, .slicer-box, .grain-box, .drum-rack-box, .op-box, .fm-box, .bouncer-box, .cellular-box, .ext-box { position: relative; }

/* ---------- GRAIN module (granular pad / drone synth) ---------- */
.bottom-row .grain-box {
  position: absolute;
  width: 276px;
  top: 0;
  left: 0;
  z-index: 10;
}
.grain-box {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 6px;
  background: rgba(12, 12, 20, 0.85);
  border: 1px solid #2a6a8a;       /* bleu cyan-pale, distinct */
  border-radius: 4px;
  min-width: 0;
}
.grain-box .grain-title { color: #5fc0d8; }
/* Sous-module TRIG ENV : apparaît quand un câble drum trig → grain est branché.
   ATK / LEN / DENS shapent la rafale de grains déclenchée par chaque hit. */
.grain-trig-env {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 4px 6px 5px;
  margin-top: 2px;
  background: rgba(255, 216, 74, 0.05);
  border: 1px solid #6a5520;
  border-radius: 3px;
  animation: grain-trig-env-fade 200ms ease;
}
.grain-trig-env[hidden] { display: none; }
.grain-trig-env-label {
  font-size: 8px;
  letter-spacing: 0.25em;
  font-weight: 700;
  color: #ffd84a;
  text-align: center;
  padding-bottom: 2px;
}
.grain-trig-env .bass-field { font-size: 9px; gap: 4px; }
.grain-trig-env .bass-field .slider { height: 8px; }
.grain-trig-env .bass-field .slider .fill { background: rgba(255, 216, 74, 0.45); }
.grain-trig-env .bass-field .slider:hover .fill {
  background: #ffd84a;
  box-shadow: 0 0 4px rgba(255, 216, 74, 0.4);
}
@keyframes grain-trig-env-fade {
  from { opacity: 0; transform: translateY(-2px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Note SEQ courante affichée quand un câble seq-1 → grain est branché */
.grain-seq-note {
  font-family: inherit;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.08em;
  color: #b07ad0;
  background: rgba(176, 122, 208, 0.14);
  border: 1px solid #6a4a8a;
  border-radius: 2px;
  padding: 1px 5px;
  line-height: 1;
  min-width: 28px;
  text-align: center;
}
.grain-seq-note[hidden] { display: none; }
.grain-box-body {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 4px 2px 2px;
}
.grain-sample-drop {
  border-color: #2a4a5a;
}
.grain-sample-drop:hover { border-color: #5fc0d8; }
.grain-sample-drop.drag-over {
  border-color: #5fc0d8;
  background: rgba(95, 192, 216, 0.15);
  box-shadow: 0 0 8px rgba(95, 192, 216, 0.4);
}
.grain-waveform-path { stroke: #5fc0d8; }
/* Playhead line dans le waveform : montre la position de base */
.grain-position-line {
  stroke: rgba(255, 216, 74, 0.7);
  stroke-width: 1;
  stroke-dasharray: 2 2;
  pointer-events: none;
}
.grain-sliders {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr 1fr;
  gap: 3px;
}
.grain-box .bass-field { font-size: 7px; gap: 3px; }
.grain-box .bass-slider { height: 10px; }
.grain-box .bass-field span.mod-label { min-width: 22px; }
.grain-box .slider .fill { background: #2a6a8a; }
.grain-box .slider:hover .fill {
  background: #5fc0d8;
  box-shadow: 0 0 8px rgba(95, 192, 216, 0.45);
}
.grain-box .slider.bipolar::before {
  content: '';
  position: absolute;
  top: 2px;
  bottom: 2px;
  left: 50%;
  width: 1px;
  background: rgba(95, 192, 216, 0.6);
  pointer-events: none;
  z-index: 1;
}
.grain-box .module-grip:hover { color: #5fc0d8; }
/* Slicer-style strip-fx scoping */
.grain-box .bass-strip-fx {
  flex: 1;
  display: flex;
  flex-wrap: wrap;
  gap: 3px;
  min-height: 16px;
  padding: 2px 4px;
  border: 1px dashed var(--border);
  border-radius: 2px;
  transition: background 140ms ease, box-shadow 140ms ease, border-color 140ms ease;
}
.grain-box .bass-strip-fx.drag-over-fx {
  background: rgba(95, 192, 216, 0.10);
  border-color: #5fc0d8;
  box-shadow: inset 0 0 0 1px #5fc0d8;
}
.grain-box .lane-fx-chip { min-width: 0; flex: 1 1 auto; }

/* ---------- FM SYNTH (2-opérateur classique) ---------- */
.bottom-row .fm-box {
  position: absolute;
  width: 270px;
  top: 0;
  left: 0;
  z-index: 10;
}
.fm-box {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 6px;
  background: rgba(12, 12, 20, 0.85);
  border: 1px solid #c08a3a;          /* orange ambré, distinct */
  border-radius: 4px;
  min-width: 0;
}
.fm-box .fm-title { color: #ff8a3a; }
.fm-box .module-grip:hover { color: #ff8a3a; }
.fm-box.module-soloed { box-shadow: 0 0 0 2px #ff8a3a, 0 0 12px rgba(255, 138, 58, 0.45); }
.fm-box.module-solo-silenced { opacity: 0.35; filter: saturate(0.4); }
.fm-box-body {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 4px 2px 2px;
}
.fm-topo {
  width: 100%;
  height: 30px;
  background: rgba(8, 8, 12, 0.6);
  border: 1px solid #3a2a1a;
  border-radius: 3px;
  padding: 1px;
}
.fm-topo svg { display: block; width: 100%; height: 100%; }

/* DX7 module : largeur étendue */
.bottom-row .fm-dx7-box { width: 360px; }
/* Empêche tout texte d'un slider de déborder en dehors de son rail */
.fm-dx7-box .slider { overflow: hidden; }
.fm-dx7-box .slider .label {
  padding: 0 3px;
  font-size: 7px;
  letter-spacing: 0.05em;
}
.fm-dx7-box .slider .label .val {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: clip;
  max-width: 100%;
}
/* PAS d'overflow:hidden sur la box elle-même — sinon les ports cable bottom/top/
   left sont clippés. Clipping appliqué uniquement aux .slider et bass-field-slider. */
.fm-dx7-box .bass-field-slider {
  min-width: 0;
  overflow: hidden;
}
.fm-dx7-box .slider .label {
  overflow: hidden;
  white-space: nowrap;
}
/* Drop highlight quand on drag un .syx sur le module entier */
.fm-box.fm-drag-over-syx {
  box-shadow: 0 0 0 2px #ffd84a, 0 0 16px rgba(255, 216, 74, 0.55);
}
.fm-box.fm-drag-over-syx::after {
  content: 'DROP .SYX HERE';
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  background: rgba(255, 216, 74, 0.92);
  color: #1a1a24;
  font-size: 14px;
  font-weight: 700;
  letter-spacing: 0.1em;
  padding: 10px 16px;
  border-radius: 4px;
  pointer-events: none;
  z-index: 100;
}

/* Patch row : prev / name / next / DICE / sysex */
.fm-patch-row {
  display: grid;
  grid-template-columns: 22px 1fr 22px 38px 38px;
  gap: 3px;
  align-items: center;
  padding: 3px 5px;
  background: rgba(255, 138, 58, 0.05);
  border: 1px solid #3a2a1a;
  border-radius: 3px;
}
.fm-patch-dice {
  background: rgba(255, 216, 74, 0.15);
  color: #ffd84a;
  border: 1px solid #6a5520;
  border-radius: 2px;
  padding: 3px 2px;
  font-size: 8px;
  font-weight: 700;
  letter-spacing: 0.1em;
  cursor: pointer;
  transition: all 120ms ease;
}
.fm-patch-dice:hover {
  background: rgba(255, 216, 74, 0.35);
  border-color: #ffd84a;
  color: #fff;
  box-shadow: 0 0 8px rgba(255, 216, 74, 0.5);
}
.fm-patch-dice:active { transform: scale(0.95); }
.fm-patch-btn {
  background: rgba(255, 138, 58, 0.15);
  color: #ff8a3a;
  border: 1px solid #6a4a20;
  border-radius: 2px;
  padding: 2px 0;
  font-size: 9px;
  cursor: pointer;
  transition: all 120ms ease;
}
.fm-patch-btn:hover { background: rgba(255, 138, 58, 0.3); border-color: #ff8a3a; }
.fm-patch-name {
  font-size: 10px;
  font-weight: 700;
  color: #ffd84a;
  letter-spacing: 0.08em;
  text-align: center;
  background: rgba(0, 0, 0, 0.35);
  border-radius: 2px;
  padding: 3px 4px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.fm-load-syx {
  background: rgba(255, 138, 58, 0.2);
  color: #ff8a3a;
  border: 1px solid #6a4a20;
  border-radius: 2px;
  padding: 3px 2px;
  font-size: 8px;
  font-weight: 700;
  letter-spacing: 0.1em;
  cursor: pointer;
  transition: all 120ms ease;
}
.fm-load-syx:hover, .fm-load-syx.drag-over {
  background: rgba(255, 138, 58, 0.4);
  border-color: #ff8a3a;
  color: #fff;
  box-shadow: 0 0 8px rgba(255, 138, 58, 0.5);
}

/* Master row */
.fm-master-row {
  display: grid;
  /* Algo box à gauche span 2 rangées, 3 sliders par rangée sur 2 rangées */
  grid-template-columns: 64px repeat(3, 1fr);
  grid-auto-rows: auto;
  gap: 4px 4px;
  align-items: center;
}
.fm-master-row .fm-algo-box {
  grid-row: span 2;
}
.fm-master-row .bass-field { font-size: 8px; gap: 3px; min-width: 0; overflow: hidden; }
.fm-master-row .bass-field span.mod-label { min-width: 30px; }
.fm-master-row .bass-slider { height: 11px; }
.fm-master-row .bass-slider .label .val { font-size: 8px; }
.fm-algo-box {
  display: flex;
  flex-direction: column;
  gap: 1px;
  align-items: stretch;
  padding: 3px 2px;
  background: rgba(255, 138, 58, 0.08);
  border: 1px solid #4a3a20;
  border-radius: 3px;
}
.fm-algo-svg {
  display: block;
  width: 100%;
  height: 56px;
  background: rgba(0, 0, 0, 0.4);
  border-radius: 2px;
}
.fm-algo-steppers {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 2px;
}
.fm-algo-stepper {
  background: rgba(255, 138, 58, 0.1);
  border: 1px solid #4a3a20;
  color: #ff8a3a;
  font-size: 8px;
  border-radius: 2px;
  cursor: pointer;
  padding: 1px 0;
  transition: all 120ms ease;
}
.fm-algo-stepper:hover {
  background: rgba(255, 138, 58, 0.3);
  border-color: #ff8a3a;
  color: #ffd84a;
}
.fm-algo-label {
  font-size: 7px;
  font-weight: 700;
  letter-spacing: 0.1em;
  color: #ffd84a;
  text-align: center;
  line-height: 1.2;
}
.fm-algo-num { font-size: 10px; color: #ff8a3a; font-weight: 700; }

/* Filter + Amp ENV row : 6 sliders compacts (CUT/RES/ATK/DEC/SUS/REL) */
.fm-filter-row {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 3px;
  padding: 3px 4px;
  background: rgba(95, 192, 216, 0.05);
  border: 1px solid #1a3a4a;
  border-radius: 3px;
}
.fm-filter-row .bass-field { font-size: 7px; gap: 2px; }
.fm-filter-row .bass-field span.mod-label {
  min-width: 22px;
  color: #5fc0d8;
}
.fm-filter-row .slider .fill { background: #2a6a8a; }
.fm-filter-row .slider:hover .fill {
  background: #5fc0d8;
  box-shadow: 0 0 8px rgba(95, 192, 216, 0.45);
}

/* Chord / arp row : 5 selects compacts inspirés du poly */
.fm-chord-row {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 3px;
  padding: 3px 4px;
  background: rgba(176, 122, 208, 0.05);
  border: 1px solid #3a2a4a;
  border-radius: 3px;
}
.fm-chord-row .fm-chord-dir-field {
  transition: opacity 140ms ease;
}
/* Second row : SEQ mode + MORPH rate + TRIG subdiv + RAND button */
.fm-chord-seq-row {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr 48px;
  gap: 3px;
  padding: 3px 4px;
  background: rgba(176, 122, 208, 0.04);
  border: 1px solid #3a2a4a;
  border-top: none;
  border-radius: 0 0 3px 3px;
  margin-top: -3px;
  align-items: center;
}
.fm-chord-reroll {
  background: rgba(176, 122, 208, 0.2);
  color: #d8a8e8;
  border: 1px solid #6a4a8a;
  border-radius: 2px;
  padding: 4px 2px;
  font-size: 8px;
  font-weight: 700;
  letter-spacing: 0.05em;
  cursor: pointer;
  transition: all 120ms ease;
}
.fm-chord-reroll:hover {
  background: rgba(176, 122, 208, 0.4);
  border-color: #b07ad0;
  color: #fff;
  box-shadow: 0 0 6px rgba(176, 122, 208, 0.4);
}
.fm-chord-reroll:active { transform: scale(0.95); }
.fm-chord-row .bass-field {
  font-size: 7px;
  gap: 2px;
}
.fm-chord-row .bass-field span {
  color: #b07ad0;
  letter-spacing: 0.1em;
  font-weight: 700;
  text-align: center;
}
.fm-chord-row select {
  font-size: 8px;
  padding: 1px 2px;
  background: rgba(0,0,0,0.5);
  color: #e0e0f0;
  border: 1px solid #4a3a5a;
  border-radius: 2px;
  width: 100%;
}
.fm-chord-row select:hover { border-color: #b07ad0; }
.fm-chord-row select:focus { outline: none; border-color: #b07ad0; box-shadow: 0 0 4px rgba(176, 122, 208, 0.4); }

/* OP tabs */
.fm-op-tabs {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 3px;
}
.fm-op-tab {
  background: rgba(255, 138, 58, 0.06);
  color: #c08a4a;
  border: 1px solid #4a3a20;
  border-radius: 2px;
  padding: 3px 0;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.05em;
  cursor: pointer;
  transition: all 120ms ease;
}
.fm-op-tab:hover { background: rgba(255, 138, 58, 0.2); color: #ff8a3a; }
.fm-op-tab.active {
  background: rgba(255, 138, 58, 0.35);
  color: #fff;
  border-color: #ff8a3a;
  box-shadow: inset 0 0 4px rgba(255, 138, 58, 0.5);
}

/* OP params grid : 4 cols × 3 rows */
.fm-op-grid {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 4px 4px 5px;
  background: rgba(255, 138, 58, 0.03);
  border-radius: 3px;
}
/* Top row : COARSE / FINE / DET / LVL */
.fm-op-toprow {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr 1fr;
  gap: 3px;
}
/* Envelope SVG viz : 4-stage curve + 4 points */
.fm-op-env-viz {
  height: 50px;
  background: rgba(0, 0, 0, 0.4);
  border: 1px solid #3a2a1a;
  border-radius: 3px;
  overflow: hidden;
}
.fm-op-env-viz svg {
  display: block;
  width: 100%;
  height: 100%;
}
/* Grid 4 cols × 3 rows : labels ATK/DEC1/DEC2/REL + Rate sliders + Level sliders */
.fm-op-envgrid {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr 1fr;
  gap: 3px 4px;
}
.fm-env-stage-label {
  font-size: 7px;
  font-weight: 700;
  letter-spacing: 0.1em;
  color: #ffd84a;
  text-align: center;
  padding-top: 2px;
}
.fm-op-envgrid .bass-field span.mod-label {
  min-width: 12px;
  color: #ff8a3a;
}

.fm-sliders {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 4px;
}
.fm-box .bass-field { font-size: 7px; gap: 3px; }
.fm-box .bass-slider { height: 10px; }
.fm-box .bass-field span.mod-label { min-width: 30px; }
.fm-box .slider .fill { background: #8a5520; }
.fm-box .slider:hover .fill {
  background: #ff8a3a;
  box-shadow: 0 0 8px rgba(255, 138, 58, 0.45);
}
.fm-box .slider.bipolar::before {
  content: '';
  position: absolute;
  top: 2px;
  bottom: 2px;
  left: 50%;
  width: 1px;
  background: rgba(255, 138, 58, 0.6);
  pointer-events: none;
  z-index: 1;
}
.fm-box .bass-strip-fx {
  flex: 1;
  display: flex;
  flex-wrap: wrap;
  gap: 3px;
  min-height: 16px;
  padding: 2px 4px;
  border: 1px dashed var(--border);
  border-radius: 2px;
  transition: background 140ms ease, box-shadow 140ms ease, border-color 140ms ease;
}
.fm-box .bass-strip-fx.drag-over-fx {
  background: rgba(255, 138, 58, 0.10);
  border-color: #ff8a3a;
  box-shadow: inset 0 0 0 1px #ff8a3a;
}
.fm-box .lane-fx-chip { min-width: 0; flex: 1 1 auto; }
.fm-box .slider.slider-disabled {
  opacity: 0.35;
  filter: saturate(0.4);
}
.fm-box .slider.slider-disabled::after {
  content: 'TRIG';
  position: absolute;
  right: 2px;
  top: 50%;
  transform: translateY(-50%);
  font-size: 7px;
  letter-spacing: 0.1em;
  color: #ffd84a;
  pointer-events: none;
  z-index: 2;
}
.fm-seq-note {
  font-family: inherit;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.08em;
  color: #b07ad0;
  background: rgba(176, 122, 208, 0.14);
  border: 1px solid #6a4a8a;
  border-radius: 2px;
  padding: 1px 5px;
  line-height: 1;
  min-width: 28px;
  text-align: center;
}
.fm-seq-note[hidden] { display: none; }

/* ---------- OPERATORS (transformers de signal trig / note) ---------- */
.bottom-row .op-box {
  position: absolute;
  width: 160px;
  top: 0;
  left: 0;
  z-index: 10;
}
.op-box {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 6px;
  background: rgba(12, 12, 20, 0.85);
  border: 1px solid var(--op-color, #5fc080);
  border-radius: 4px;
  min-width: 0;
}
.op-box-header {
  display: flex;
  align-items: center;
  gap: 4px;
  padding-bottom: 2px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.05);
}
.op-box-title {
  flex: 1;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.15em;
  color: var(--op-color, #5fc080);
}
.op-box .op-enable, .op-box .module-delete {
  font-size: 8px;
  padding: 1px 6px;
  background: rgba(0, 0, 0, 0.4);
  color: #999;
  border: 1px solid #3a3a4a;
  border-radius: 2px;
  cursor: pointer;
}
.op-box .op-enable.active { color: var(--op-color, #5fc080); border-color: var(--op-color, #5fc080); }
.op-box-body {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding-top: 2px;
}
.op-box .bass-field { font-size: 7px; gap: 3px; }
.op-box .bass-slider { height: 10px; }
.op-box .bass-field span.mod-label { min-width: 36px; color: var(--op-color, #5fc080); }
.op-box .slider .fill {
  background: color-mix(in srgb, var(--op-color, #5fc080) 50%, #2a2a3a 50%);
}
.op-box .slider:hover .fill {
  background: var(--op-color, #5fc080);
  box-shadow: 0 0 6px color-mix(in srgb, var(--op-color, #5fc080) 60%, transparent);
}
.op-box .slider.bipolar::before {
  content: '';
  position: absolute;
  top: 2px; bottom: 2px;
  left: 50%;
  width: 1px;
  background: rgba(255, 255, 255, 0.3);
  pointer-events: none;
  z-index: 1;
}

/* LOOP operator : boutons REC/STOP/CLEAR + status display */
.op-loop-status {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.2em;
  text-align: center;
  padding: 4px;
  background: rgba(0, 0, 0, 0.4);
  border: 1px solid #3a2a1a;
  border-radius: 3px;
  color: #999;
}
.op-loop-status.rec  { color: #ff3030; border-color: #ff3030; animation: op-loop-blink 0.6s infinite; }
.op-loop-status.play { color: #5fc080; border-color: #5fc080; }
@keyframes op-loop-blink { 0%, 50% { opacity: 1; } 51%, 100% { opacity: 0.4; } }
.op-loop-len-row {
  display: grid;
  grid-template-columns: 36px 1fr;
  gap: 4px;
  align-items: center;
  font-size: 8px;
  letter-spacing: 0.1em;
  font-weight: 700;
}
.op-loop-len-row span { color: #ff8a3a; }
.op-loop-len {
  font-size: 8px;
  padding: 2px 4px;
  background: rgba(0, 0, 0, 0.5);
  color: #e0e0f0;
  border: 1px solid #4a3a20;
  border-radius: 2px;
  width: 100%;
}
.op-loop-len:hover  { border-color: #ff8a3a; }
.op-loop-len:focus  { outline: none; border-color: #ff8a3a; box-shadow: 0 0 4px rgba(255, 138, 58, 0.4); }
.op-loop-buttons {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 3px;
}
.op-loop-btn {
  font-size: 8px;
  font-weight: 700;
  letter-spacing: 0.1em;
  padding: 4px 0;
  background: rgba(0, 0, 0, 0.4);
  color: #ccc;
  border: 1px solid #3a3a4a;
  border-radius: 2px;
  cursor: pointer;
  transition: all 120ms ease;
}
.op-loop-rec:hover   { background: rgba(255, 48, 48, 0.2); color: #ff5050; border-color: #ff3030; }
.op-loop-stop:hover  { background: rgba(95, 192, 128, 0.2); color: #5fc080; border-color: #5fc080; }
.op-loop-clear:hover { background: rgba(176, 122, 208, 0.2); color: #b07ad0; border-color: #b07ad0; }

/* ---------- BOUNCER SEQ (séquenceur gravitationnel) ---------- */
.bottom-row .bouncer-box {
  position: absolute;
  width: 296px;
  top: 0;
  left: 0;
  z-index: 10;
}
.bottom-row .cellular-box {
  position: absolute;
  width: 220px;
  top: 0;
  left: 0;
  z-index: 10;
}
.bottom-row .ext-box {
  position: absolute;
  width: 240px;
  top: 0;
  left: 0;
  z-index: 10;
}

/* ============================================================
   EXT INSTRUMENT — bridge MIDI OUT + AUDIO IN
   ============================================================ */
.ext-box {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 6px;
  background: rgba(12, 12, 20, 0.85);
  border: 1px solid #ffa84a;       /* orange = "external/hardware" */
  border-radius: 4px;
  min-width: 0;
}
.ext-box .bass-box-title-main { color: #ffa84a; letter-spacing: 0.22em; }
.ext-box .module-grip:hover   { color: #ffa84a; }
.ext-box.module-soloed { box-shadow: 0 0 0 2px #ffa84a, 0 0 12px rgba(255, 168, 74, 0.45); }
.ext-box-body {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.ext-section {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 5px 6px;
  background: rgba(255, 168, 74, 0.04);
  border: 1px solid rgba(255, 168, 74, 0.18);
  border-radius: 3px;
}
.ext-section-label {
  font-size: 7px;
  letter-spacing: 0.22em;
  font-weight: 700;
  color: #ffa84a;
  opacity: 0.8;
}
.ext-row {
  display: flex;
  flex-direction: row;
  gap: 5px;
  align-items: stretch;
}
.ext-row .bass-field {
  flex: 1;
  min-width: 0;
}
.ext-row .bass-field select {
  width: 100%;
  font-size: 9px;
}
.ext-port-select,
.ext-device-select {
  width: 100%;
  font-size: 9px;
  padding: 3px 4px;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: 2px;
}
.ext-audio-enable-btn {
  background: rgba(255, 168, 74, 0.08);
  border: 1px solid rgba(255, 168, 74, 0.3);
  color: #ffa84a;
  font-family: inherit;
  font-size: 9px;
  letter-spacing: 0.18em;
  font-weight: 700;
  padding: 4px 10px;
  border-radius: 3px;
  cursor: pointer;
  transition: all 140ms ease;
  flex: 0 0 auto;
}
.ext-audio-enable-btn:hover {
  border-color: #ffa84a;
  box-shadow: 0 0 8px rgba(255, 168, 74, 0.4);
}
.ext-audio-enable-btn.active {
  background: rgba(255, 80, 80, 0.18);
  border-color: #ff5050;
  color: #ff5050;
  box-shadow: 0 0 8px rgba(255, 80, 80, 0.4);
}

/* FX drop zone sur Ext.Inst : hauteur explicite + alignement label/strip
   horizontaux (comme les autres synths) → "DROP FX HERE" centré dans la
   bande, pas en overlap avec le label "FX". */
.ext-box .bass-box-fx-section { padding: 4px 2px; }
.ext-box .bass-box-row {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 6px;
}
.ext-box .bass-fx-label {
  font-size: 8px;
  letter-spacing: 0.18em;
  font-weight: 700;
  color: #ffa84a;
  flex: 0 0 auto;
}
.ext-box .bass-strip-fx {
  flex: 1;
  display: flex;
  flex-wrap: wrap;
  gap: 3px;
  min-height: 20px;
  padding: 2px 4px;
  border: 1px dashed rgba(255, 168, 74, 0.3);
  border-radius: 2px;
  position: relative;
  transition: background 140ms ease, border-color 140ms ease;
}
.ext-box .bass-strip-fx.drag-over-fx {
  background: rgba(255, 168, 74, 0.10);
  border-color: #ffa84a;
  box-shadow: inset 0 0 0 1px #ffa84a;
}
/* Empêche tout texte d'un slider de déborder en dehors de son rail */
.bouncer-box .slider { overflow: hidden; }
.bouncer-box .slider .label {
  padding: 0 3px;
  font-size: 7px;
  letter-spacing: 0.05em;
}
.bouncer-box .slider .label .val {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: clip;
  max-width: 100%;
}
.bouncer-box {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 6px;
  background: rgba(12, 12, 20, 0.85);
  border: 1px solid #8a5fc0;          /* violet doux, distinct */
  border-radius: 4px;
  min-width: 0;
  /* PAS d'overflow:hidden ici — sinon les ports (cables) qui poke out via
     bottom:-7px / top:-7px / left:-7px sont clippés. Le clipping de valeurs
     overflow est appliqué au niveau .slider seulement. */
}

/* ============================================================
   CELLULAR — Game of Life sequenceur (grille 8×8)
   ============================================================ */
.cellular-box {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 6px;
  background: rgba(12, 12, 20, 0.85);
  border: 1px solid #5fc080;       /* vert pour distinguer (life !) */
  border-radius: 4px;
  min-width: 0;
  width: 200px;
}
.cellular-box .bass-box-title-main { color: #5fc080; letter-spacing: 0.22em; }
.cellular-box .module-grip:hover   { color: #5fc080; }
.cellular-box.module-soloed { box-shadow: 0 0 0 2px #5fc080, 0 0 12px rgba(95, 192, 128, 0.45); }
.cellular-box-body {
  display: flex;
  flex-direction: column;
  gap: 5px;
}
.cellular-grid-wrap {
  background: rgba(0, 0, 0, 0.4);
  border: 1px solid rgba(95, 192, 128, 0.25);
  border-radius: 3px;
  padding: 2px;
}
.cellular-grid-svg {
  display: block;
  width: 100%;
  height: auto;
}
.cellular-cell {
  fill: rgba(95, 192, 128, 0.06);
  stroke: rgba(95, 192, 128, 0.10);
  stroke-width: 0.2;
  cursor: pointer;
  transition: fill 80ms ease, stroke 80ms ease;
}
.cellular-cell:hover {
  fill: rgba(95, 192, 128, 0.20);
  stroke: rgba(95, 192, 128, 0.5);
}
.cellular-cell.alive {
  fill: #5fc080;
  stroke: rgba(180, 240, 200, 0.7);
  stroke-width: 0.3;
  filter: drop-shadow(0 0 1px rgba(95, 192, 128, 0.8));
}
.cellular-cell.alive:hover {
  fill: #7fd0a0;
}
.cellular-playhead {
  fill: rgba(255, 216, 74, 0.10);
  stroke: rgba(255, 216, 74, 0.45);
  stroke-width: 0.3;
  pointer-events: none;
  transition: x 120ms ease-out;
}
.cellular-controls-row,
.cellular-actions-row,
.cellular-preset-row {
  display: flex;
  flex-direction: row;
  gap: 4px;
  align-items: stretch;
}
.cellular-controls-row .bass-field,
.cellular-actions-row .bass-field {
  flex: 1;
  min-width: 0;
}
.cellular-controls-row select,
.cellular-actions-row select {
  width: 100%;
  font-size: 9px;
}
.cellular-btn {
  flex: 1;
  background: rgba(95, 192, 128, 0.08);
  border: 1px solid rgba(95, 192, 128, 0.3);
  color: #5fc080;
  font-family: inherit;
  font-size: 9px;
  letter-spacing: 0.15em;
  font-weight: 700;
  padding: 4px 6px;
  border-radius: 3px;
  cursor: pointer;
  transition: all 140ms ease;
}
.cellular-btn:hover {
  background: rgba(95, 192, 128, 0.18);
  border-color: #5fc080;
  box-shadow: 0 0 8px rgba(95, 192, 128, 0.4);
}
.cellular-btn.active {
  background: rgba(255, 216, 74, 0.20);
  border-color: #ffd84a;
  color: #ffd84a;
}
.cellular-preset {
  font-size: 8px;
  letter-spacing: 0.1em;
}
.bouncer-box .bouncer-title { color: #b07ad0; }
.bouncer-box .module-grip:hover { color: #b07ad0; }
.bouncer-box.module-soloed { box-shadow: 0 0 0 2px #b07ad0, 0 0 12px rgba(176, 122, 208, 0.45); }
.bouncer-box.module-solo-silenced { opacity: 0.35; filter: saturate(0.4); }

.bouncer-box-body {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 4px 2px 2px;
}
.bouncer-viz {
  position: relative;
  width: 100%;
  height: 140px;
  background: #0a0a14;
  border: 1px solid #2a1a3a;
  border-radius: 3px;
  overflow: hidden;
}
.bouncer-svg {
  display: block;
  width: 100%;
  height: 100%;
}
.bouncer-seg {
  stroke-linecap: round;
  stroke-linejoin: round;
}

.bouncer-segs {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.bouncer-seg-row {
  display: grid;
  grid-template-columns: 30px repeat(4, 1fr);
  gap: 3px;
  align-items: center;
  padding: 3px 5px;
  background: rgba(176, 122, 208, 0.04);
  border-left: 2px solid var(--seg-color, #b07ad0);
  border-radius: 2px;
}
.bouncer-seg-row .bass-field { font-size: 7px; gap: 2px; }
.bouncer-seg-row .bass-field span.mod-label { min-width: 18px; }
.bouncer-seg-label {
  font-size: 8px;
  font-weight: 700;
  letter-spacing: 0.12em;
  color: var(--seg-color, #b07ad0);
}
.bouncer-sliders {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 3px;
}
.bouncer-box .bass-field { font-size: 7px; gap: 3px; }
.bouncer-box .bass-slider { height: 10px; }
.bouncer-box .bass-field span.mod-label { min-width: 22px; }
.bouncer-box .slider .fill { background: #6a4a8a; }
.bouncer-box .slider:hover .fill {
  background: #b07ad0;
  box-shadow: 0 0 8px rgba(176, 122, 208, 0.45);
}
.bouncer-box .slider.bipolar::before {
  content: '';
  position: absolute;
  top: 2px;
  bottom: 2px;
  left: 50%;
  width: 1px;
  background: rgba(176, 122, 208, 0.6);
  pointer-events: none;
  z-index: 1;
}
.bouncer-box .bass-strip-fx {
  flex: 1;
  display: flex;
  flex-wrap: wrap;
  gap: 3px;
  min-height: 16px;
  padding: 2px 4px;
  border: 1px dashed var(--border);
  border-radius: 2px;
  transition: background 140ms ease, box-shadow 140ms ease, border-color 140ms ease;
}
.bouncer-box .bass-strip-fx.drag-over-fx {
  background: rgba(176, 122, 208, 0.10);
  border-color: #b07ad0;
  box-shadow: inset 0 0 0 1px #b07ad0;
}
.bouncer-box .lane-fx-chip { min-width: 0; flex: 1 1 auto; }
/* Slider désactivé : drag toujours possible mais visuellement greyé. Utilisé
   pour DROP quand un câble trig IN est branché (le trig externe pilote alors). */
.bouncer-box .slider.slider-disabled {
  opacity: 0.35;
  filter: saturate(0.4);
}
.bouncer-box .slider.slider-disabled::after {
  content: 'TRIG';
  position: absolute;
  right: 2px;
  top: 50%;
  transform: translateY(-50%);
  font-size: 7px;
  letter-spacing: 0.1em;
  color: #ffd84a;
  pointer-events: none;
  z-index: 2;
}

/* MONO synth : quand un câble trig IN est branché, le séquenceur euclidien
   (XY pad + cellules + boutons OCC) est désactivé. Grey-out visuel + label
   TRIG pour signaler que c'est le trig externe qui pilote. */
.bass-box.seq-trig-driven .bass-trig-xy,
.bass-box.seq-trig-driven .bass-trig-cells,
.bass-box.seq-trig-driven .melody-occ {
  opacity: 0.32;
  filter: saturate(0.3);
  pointer-events: none;
  position: relative;
}
.bass-box.seq-trig-driven .bass-trig-xy::after {
  content: 'EXT TRIG';
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 9px;
  letter-spacing: 0.18em;
  color: #ffd84a;
  font-weight: 700;
  text-shadow: 0 0 6px rgba(255, 216, 74, 0.6);
  opacity: 1;
  filter: none;
  pointer-events: none;
  z-index: 3;
}
.bouncer-survive-row {
  grid-column: span 3;
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 2px 4px;
}
.bouncer-survive-row .bass-enable {
  font-size: 9px;
  padding: 2px 8px;
}

/* ---------- SEQ · NOTES (module sequencer standalone) ---------- */
.seq-box {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 6px;
  background: rgba(12, 12, 20, 0.85);
  border: 1px solid #6a4a8a;       /* violet pour distinguer du bass (cyan) et poly (rose) */
  border-radius: 4px;
  min-width: 0;
}
.seq-box-header {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 2px 4px 4px;
  border-bottom: 1px solid #2a2a3a;
}
.seq-box-title {
  font-size: 10px;
  letter-spacing: 0.22em;
  font-weight: 700;
  color: #b07ad0;
  flex: 1;
}
.seq-box-body {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 4px 2px 2px;
}
.seq-box .melody-canvas-wrap {
  /* hérite du style melody existant, juste un margin pour respirer */
  margin: 2px 0;
}

/* SEQ ancré dans la colonne gauche : pas de position absolue, on le rend
   compact, et son port-out déborde sur la droite pour pendre dans le canvas. */
.kit-browser .seq-box-sidebar {
  position: relative;
  width: 100%;
  flex-shrink: 0;
  margin-top: 6px;
}
.kit-browser .seq-box-sidebar .module-port-out[data-port-side="right"] {
  /* Le port-out est positionné juste à l'intérieur du bord droit du seq-box.
     Pas d'overhang (kit-browser a overflow:hidden — toute partie débordant
     serait clippée). Les câbles partent depuis ce point côté canvas. */
  right: 0;
  z-index: 30;
}

/* ---------- Master Bus box (placé en bas du right-rack sous les LFOs) ---------- */
.right-rack .master-box {
  margin-top: auto;          /* pousse en bas du right-rack */
  position: sticky;
  bottom: 0;
  /* Background 100% opaque + z-index élevé pour MASQUER les LFOs qui scrollent
     derrière (sinon ils transparaissaient à travers le master-box). */
  background: var(--bg);
  z-index: 20;
  box-shadow: 0 -6px 16px rgba(0, 0, 0, 0.7);
}
.master-box {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 6px;
  background: rgba(12, 12, 20, 0.85);
  border: 1px solid #2a8a6a;
  border-radius: 4px;
  min-width: 0;
}
.master-box-header {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 2px 0;
}
.master-box-title {
  font-size: 10px;
  letter-spacing: 0.22em;
  font-weight: 700;
  color: #5fc080;
  flex-shrink: 0;
}
/* VU stéréo verticale L/R en mini, à droite du titre */
.master-vu-stereo {
  display: flex;
  gap: 3px;
  flex: 1;
  justify-content: flex-end;
}
.master-vu-track {
  position: relative;
  width: 5px;
  height: 26px;
  background: rgba(10, 10, 16, 0.85);
  border: 1px solid #2a2a3a;
  border-radius: 1px;
  overflow: hidden;
}
.master-vu-fill {
  position: absolute;
  inset: 0;
  --vu-level: 0;
  background: linear-gradient(to top,
    #5fc080 0%,   #5fc080 65%,
    #ffd84a 75%,  #ffd84a 86%,
    #ff3030 92%,  #ff3030 100%);
  clip-path: inset(calc((100 - var(--vu-level)) * 1%) 0 0 0);
  transition: clip-path 60ms ease-out;
}

.master-box-body {
  display: flex;
  flex-direction: column;
  gap: 3px;
}
/* Widget compact en bas-droite : VU stéréo XL + slider volume horizontal */
.master-widget {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 6px 2px 4px;
}
/* VU stéréo XL en VERTICAL : 2 bars côte à côte, fill bottom-up, gradient
   vertical (vert en bas → rouge en haut). */
.master-vu-stereo-xl {
  display: flex;
  flex-direction: row;
  gap: 8px;
  width: 100%;
  height: 130px;
  align-items: stretch;
  justify-content: center;
  padding: 0 4px;
  box-sizing: border-box;
}
.master-vu-row {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  flex: 1;
  max-width: 28px;
  height: 100%;
}
.master-vu-label {
  font-size: 8px;
  font-weight: 700;
  letter-spacing: 0.1em;
  color: rgba(216, 168, 232, 0.7);
  flex: 0 0 auto;
  text-align: center;
}
.master-vu-stereo-xl .master-vu-track {
  flex: 1;
  width: 14px;
  height: auto;
  min-height: 100px;
  border-radius: 3px;
  background: rgba(0, 0, 0, 0.6);
  border: 1px solid var(--border);
  box-shadow: inset 0 0 4px rgba(0, 0, 0, 0.8);
  overflow: hidden;
}
/* Le fill default (.master-vu-fill) utilise déjà un gradient vertical + clip-path
   inset(top right bottom left) qui clippe le TOP → fill bottom-up automatiquement.
   Pas d'override nécessaire. */
.master-vol-host {
  width: 100%;
}
/* Le slider master-volume DÉPLACÉ dans le widget : forcer pleine largeur */
.master-vol-host .bass-field,
.master-vol-host label {
  display: flex;
  align-items: center;
  gap: 6px;
  width: 100%;
}
.master-vol-host .mod-label {
  font-size: 9px;
  letter-spacing: 0.15em;
  color: #5fc080;
  font-weight: 700;
  flex-shrink: 0;
  min-width: 32px;
}
.master-vol-host .slider {
  flex: 1;
  height: 14px;
  min-width: 0;
}
.master-vol-host .slider .fill { background: #2a6a4a; }
.master-vol-host .slider:hover .fill {
  background: #5fc080;
  box-shadow: 0 0 8px rgba(95, 192, 128, 0.5);
}

/* Section MASTER BUS dans le mixer modal (sliders drive/EQ/comp/etc) */
.mm-section-master .master-row {
  display: flex;
  gap: 8px;
  padding: 4px 0;
}
.mm-section-master .bass-field {
  flex: 1;
  min-width: 0;
}
.master-row {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 4px;
}
/* Row à 2 cols (DRIVE / FILTER puis DUCK/LIMIT/VOL utilisent 3 cols, etc.) */
.master-row:has(> :nth-child(2):last-child) { grid-template-columns: 1fr 1fr; }
.master-row:has(> :nth-child(4)) { grid-template-columns: 1fr 1fr 1fr 1fr; }

.master-box .bass-field { font-size: 7px; gap: 3px; min-width: 0; }
.master-box .bass-field span.mod-label { min-width: 28px; }
.master-box .bass-slider { height: 10px; }
.master-box .slider.master-slider .fill { background: #2a6a4a; }
.master-box .slider.master-slider:hover .fill {
  background: #5fc080;
  box-shadow: 0 0 8px rgba(95, 192, 128, 0.45);
}
/* Bipolar marker (mid = 0 / bypass) sur FILTER, EQ */
.master-box .slider.master-slider.bipolar::before {
  content: '';
  position: absolute;
  top: 2px;
  bottom: 2px;
  left: 50%;
  width: 1px;
  background: var(--text-dim);
  opacity: 0.5;
  pointer-events: none;
  z-index: 1;
}
/* POLY box : même style que bass-box mais accent magenta-rose */
.poly-box {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 6px;
  background: rgba(12, 12, 20, 0.85);
  border: 1px solid #8a2a6a;
  border-radius: 4px;
}
.poly-box .bass-box-title-main.poly-title { color: #ff7ad0; }
.poly-box .bass-enable:hover { border-color: #ff7ad0; color: #ff7ad0; }
.poly-box .bass-enable.active {
  background: rgba(255, 122, 208, 0.18);
  border-color: #ff7ad0;
  color: #ff7ad0;
  box-shadow: 0 0 6px rgba(255, 122, 208, 0.45);
}
.poly-box .bass-box-vu { cursor: ew-resize; }
.poly-box .bass-box-vu:hover { border-color: #ff7ad0; }
.poly-box .bass-field { font-size: 7px; gap: 3px; }
.poly-box .bass-field span.mod-label { min-width: 30px; }
.poly-box .bass-field select { font-size: 9px; padding: 2px 4px; }
.poly-box .bass-slider { height: 10px; }
.poly-box .slider.poly-slider .fill { background: #6a2a5a; }
.poly-box .slider.poly-slider:hover .fill {
  background: #ff7ad0;
  box-shadow: 0 0 8px rgba(255, 122, 208, 0.4);
}
.poly-box .bass-strip-fx { flex: 1; }

/* ---------- Bass box (style lane-cell agrandi, en bas à gauche du centre) ----------
   Structure : header avec mini VU strip violet + titre + OCC, body avec params
   synth en grille 2-col puis le séquenceur melody en dessous. */
.bass-box {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 6px;
  background: rgba(12, 12, 20, 0.85);
  border: 1px solid #4a2a8a;
  border-radius: 4px;
}
/* OCC rythmique dans le header — visible directement, propre à la 303 */
.bass-occ {
  display: flex;
  gap: 2px;
}
.bass-occ-btn {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-dim);
  font-family: inherit;
  font-size: 13px;
  font-weight: 700;
  line-height: 1;
  width: 22px;
  height: 22px;
  padding: 0;
  border-radius: 2px;
  cursor: pointer;
  transition: all 120ms ease;
}
.bass-occ-btn:hover {
  border-color: #b66aff;
  color: #b66aff;
  box-shadow: 0 0 4px rgba(182, 106, 255, 0.35);
}
.bass-box-header {
  display: flex;
  flex-direction: column;
  gap: 3px;
}
/* VU horizontal en haut = fader volume (drag pour ajuster). Fill = audio level,
   handle = position du volume (LFO-modulable). */
.bass-box-vu {
  position: relative;
  height: 12px;
  background: rgba(10, 10, 16, 0.8);
  border: 1px solid #2a2a3a;
  border-radius: 2px;
  overflow: visible;
  cursor: ew-resize;
  user-select: none;
}
.bass-box-vu:hover { border-color: var(--accent-dim); }
.bass-box-vu-fill {
  position: absolute;
  inset: 0;
  --vu-level: 0;
  background: linear-gradient(to right,
    #5fc080 0%,   #5fc080 65%,
    #ffd84a 75%,  #ffd84a 86%,
    #ff3030 92%,  #ff3030 100%);
  clip-path: inset(0 calc((100 - var(--vu-level)) * 1%) 0 0);
  transition: clip-path 60ms ease-out;
  border-radius: 1px;
  pointer-events: none;
}
/* Handle = curseur fader. Petit trait vertical qui dépasse au-dessus et
   en dessous, position selon le volume slider. */
.bass-box-vu-handle {
  position: absolute;
  top: -3px;
  bottom: -3px;
  left: 0%;
  width: 2.5px;
  background: var(--accent);
  border-radius: 1px;
  transform: translateX(-50%);
  box-shadow: 0 0 5px rgba(0, 240, 255, 0.85);
  pointer-events: none;
  transition: left 60ms ease-out;
  z-index: 2;
}
/* Poly MORPH slider : le label affiche le nom du wavetable (texte court).
   On agrandit légèrement le font pour la lisibilité. */
.poly-box .slider#poly-morph .label .val {
  font-size: 8px;
  font-weight: 700;
  letter-spacing: 0.05em;
}

/* WAVE field + SEQ melody-field : LFO assigné = pulse magenta autour de la field */
.bass-wave-field.lfo-assigned,
.melody-field.lfo-assigned,
.fm-lfo-field.lfo-assigned {
  outline: 1px solid var(--magenta-dim);
  outline-offset: 2px;
  border-radius: 2px;
  animation: pr-vu-lfo-pulse 1.6s ease-in-out infinite;
}
/* DX7 chord/algo/patch fields : LFO assigné = label texte + valeur dropdown roses */
.fm-lfo-field.lfo-assigned > span,
.fm-lfo-field.lfo-assigned select,
.fm-lfo-field.lfo-assigned.fm-patch-name,
.fm-lfo-field.lfo-assigned .fm-algo-label,
.fm-lfo-field.lfo-assigned .fm-algo-num {
  color: var(--magenta);
}
.bass-box-vu.lfo-assigned {
  outline: 1px solid var(--magenta-dim);
  outline-offset: 2px;
  animation: pr-vu-lfo-pulse 1.6s ease-in-out infinite;
}
.bass-box-title {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
}
.bass-box-title-main {
  font-size: 10px;
  letter-spacing: 0.22em;
  font-weight: 700;
  color: #b66aff;
}
.bass-box-body {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.bass-box-section {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 4px;
  background: rgba(18, 18, 26, 0.45);
  border: 1px solid var(--border);
  border-radius: 3px;
}
.bass-box-row {
  display: flex;
  align-items: center;
  gap: 6px;
}
.bass-box-row-wave { justify-content: flex-start; }
.bass-box-row-melody-actions { justify-content: space-between; }
.bass-box-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 3px;
}
.bass-box-grid-melody {
  grid-template-columns: 1fr 1fr;
}
/* Réutilise les anciennes classes bass-field / bass-slider */
.bass-box .bass-slider { height: 10px; }
.bass-box .bass-field-slider { min-width: 0; flex: 1; }
.bass-box .bass-field { font-size: 7px; gap: 3px; }
.bass-box .bass-field span.mod-label { min-width: 30px; }
.bass-box .bass-field select { font-size: 9px; padding: 2px 4px; }
.bass-box .melody-field,
.seq-box  .melody-field { font-size: 7px; gap: 3px; min-width: 0; }
.bass-box .melody-field span,
.seq-box  .melody-field span { min-width: 28px; }
.bass-box .melody-field select,
.seq-box  .melody-field select,
.bass-box .melody-field input[type="number"],
.seq-box  .melody-field input[type="number"] { font-size: 9px; padding: 2px 4px; min-width: 0; width: 100%; }
/* Width un peu plus large pour le LEN (3 chiffres possibles) */
.melody-field-len input[type="number"] { width: 48px; min-width: 0; -moz-appearance: textfield; }
.melody-field-len input[type="number"]::-webkit-outer-spin-button,
.melody-field-len input[type="number"]::-webkit-inner-spin-button { opacity: 1; }
.bass-box .melody-canvas-wrap,
.seq-box  .melody-canvas-wrap { height: 40px; }
.bass-box .melody-strip-label,
.seq-box  .melody-strip-label {
  font-size: 9px;
  letter-spacing: 0.2em;
  font-weight: 700;
  color: #b66aff;
}
.bass-box .melody-rand,
.bass-box .melody-clear,
.seq-box  .melody-rand,
.seq-box  .melody-clear { padding: 3px 6px; font-size: 8px; }
.bass-box .melody-occ-btn,
.seq-box  .melody-occ-btn { width: 18px; height: 18px; font-size: 11px; }

/* Section FX dans la bass-box : label + drop zone pour les chips */
.bass-box-fx-section { padding: 4px 6px; }
.bass-fx-label {
  font-size: 9px;
  letter-spacing: 0.2em;
  font-weight: 700;
  color: #ffa84a;
  flex-shrink: 0;
}
.bass-box   .bass-strip-fx,
.poly-box   .bass-strip-fx,
.slicer-box .bass-strip-fx {
  flex: 1;
  display: flex;
  flex-wrap: wrap;
  gap: 3px;
  min-height: 16px;
  padding: 2px 4px;
  border: 1px dashed var(--border);
  border-radius: 2px;
  transition: background 140ms ease, box-shadow 140ms ease, border-color 140ms ease;
}
.bass-box   .bass-strip-fx.drag-over-fx,
.poly-box   .bass-strip-fx.drag-over-fx,
.slicer-box .bass-strip-fx.drag-over-fx {
  background: rgba(255, 168, 74, 0.10);
  border-color: #ffa84a;
  box-shadow: inset 0 0 0 1px #ffa84a;
}
.bass-box   .lane-fx-chip,
.poly-box   .lane-fx-chip,
.slicer-box .lane-fx-chip { min-width: 0; flex: 1 1 auto; }

/* Garde compat ancien .bass-strip si encore référencé ailleurs */
.bass-strip {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 6px 10px;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: 4px;
}
.bass-strip-label {
  font-size: 10px;
  letter-spacing: 0.25em;
  font-weight: 700;
  color: #b66aff;
  padding-right: 4px;
}
.bass-enable {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-dim);
  font-family: inherit;
  font-size: 9px;
  letter-spacing: 0.15em;
  font-weight: 700;
  padding: 5px 10px;
  border-radius: 3px;
  cursor: pointer;
  transition: all 120ms ease;
  flex-shrink: 0;
}
.bass-enable:hover { border-color: #b66aff; color: #b66aff; }
.bass-enable.active {
  background: rgba(182, 106, 255, 0.15);
  border-color: #b66aff;
  color: #b66aff;
  box-shadow: 0 0 6px rgba(182, 106, 255, 0.4);
}
.bass-field {
  display: flex;
  align-items: center;
  gap: 5px;
  font-size: 8px;
  letter-spacing: 0.12em;
  color: var(--text-dim);
  font-weight: 700;
  flex-shrink: 0;
}
.bass-field-slider { flex: 1; min-width: 60px; }
.bass-field select {
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
  font-family: inherit;
  font-size: 9px;
  font-weight: 700;
  padding: 3px 5px;
  border-radius: 2px;
  cursor: pointer;
}
.bass-field select:hover { border-color: #b66aff; }
.slider.bass-slider {
  flex: 1;
  height: 14px;
}
.slider.bass-slider .fill {
  background: #5a2a8a;
}
.slider.bass-slider:hover .fill {
  background: #b66aff;
  box-shadow: 0 0 8px rgba(182, 106, 255, 0.4);
}
/* Bipolar marker (centre) — visuel "0" pour TUNE qui va de -12 à +12 semis */
.slider.bass-slider.bipolar::before {
  content: '';
  position: absolute;
  top: 2px;
  bottom: 2px;
  left: 50%;
  width: 1px;
  background: var(--text-dim);
  opacity: 0.5;
  pointer-events: none;
  z-index: 1;
}

/* ---------- Melody strip (TAPE / PROB pour bass synth) ---------- */
.melody-strip {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 10px;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: 4px;
}
.melody-strip-label {
  font-size: 10px;
  letter-spacing: 0.25em;
  font-weight: 700;
  color: #b66aff;
  flex-shrink: 0;
}
.melody-enable, .melody-mode, .melody-rand, .melody-clear {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-dim);
  font-family: inherit;
  font-size: 9px;
  letter-spacing: 0.12em;
  font-weight: 700;
  padding: 4px 8px;
  border-radius: 2px;
  cursor: pointer;
  transition: all 120ms ease;
  flex-shrink: 0;
}
.melody-enable:hover, .melody-mode:hover, .melody-rand:hover, .melody-clear:hover {
  border-color: #b66aff;
  color: #b66aff;
}
.melody-enable.active, .melody-mode.active {
  background: rgba(182, 106, 255, 0.18);
  border-color: #b66aff;
  color: #b66aff;
  box-shadow: 0 0 6px rgba(182, 106, 255, 0.4);
}
.melody-field {
  display: flex;
  align-items: center;
  gap: 4px;
  font-size: 8px;
  letter-spacing: 0.12em;
  color: var(--text-dim);
  font-weight: 700;
  flex-shrink: 0;
}
.melody-field select,
.melody-field input[type="number"] {
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
  font-family: inherit;
  font-size: 9px;
  font-weight: 700;
  padding: 3px 4px;
  border-radius: 2px;
  cursor: pointer;
}
.melody-field select:hover { border-color: #b66aff; }
.melody-canvas-wrap {
  flex: 1;
  min-width: 0;
  height: 48px;
  background: rgba(10, 10, 16, 0.7);
  border: 1px solid #2a2a3a;
  border-radius: 3px;
  overflow: hidden;
  cursor: crosshair;
  user-select: none;
}
.melody-canvas {
  display: block;
  width: 100%;
  height: 100%;
}
/* Légendes (numéros de step en tape, noms de note en prob) sous les bars */
.melody-canvas .melody-axis-label {
  fill: var(--text-dim);
  font-family: inherit;
  font-size: 3.2px;
  font-weight: 700;
  letter-spacing: 0.05em;
  opacity: 0.7;
}

/* Boutons OCC −/+ pour ajouter / retirer une note de la séquence */
.melody-occ {
  display: flex;
  gap: 2px;
  flex-shrink: 0;
}
.melody-occ-btn {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-dim);
  font-family: inherit;
  font-size: 12px;
  font-weight: 700;
  line-height: 1;
  width: 20px;
  height: 22px;
  padding: 0;
  border-radius: 2px;
  cursor: pointer;
  transition: all 120ms ease;
}
.melody-occ-btn:hover {
  border-color: #b66aff;
  color: #b66aff;
  box-shadow: 0 0 4px rgba(182, 106, 255, 0.3);
}

footer {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 16px;
  padding-top: 8px;
}
/* Variante sidebar : 3 boutons DICE/SMPL/KIT en row, juste sous les knobs */
.sidebar-transport {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 6px;
  padding: 4px 0 2px;
}
.sidebar-transport .dice-group { gap: 3px; }
.sidebar-transport .btn.big { padding: 6px 4px; font-size: 10px; gap: 3px; }
.sidebar-transport .btn.big .dice-icon  { font-size: 16px; }
.sidebar-transport .btn.big .dice-label { font-size: 9px; }
.sidebar-transport .auto-btn { font-size: 8px; padding: 2px 0; }

.dice-group {
  display: flex;
  flex-direction: column;
  gap: 3px;
  align-items: stretch;
}
.auto-btn {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-dim);
  font-family: inherit;
  font-size: 9px;
  letter-spacing: 0.15em;
  font-weight: 700;
  padding: 2px 0;
  border-radius: 2px;
  cursor: pointer;
  transition: all 140ms ease;
  text-align: center;
}
.auto-btn:hover { border-color: var(--magenta-dim); color: var(--magenta-dim); }
.auto-btn.active {
  background: rgba(255, 58, 165, 0.12);
  border-color: var(--magenta);
  color: var(--magenta);
  box-shadow: 0 0 6px rgba(255, 58, 165, 0.3);
}

.btn {
  background: var(--bg-elev);
  border: 1px solid var(--border);
  color: var(--text);
  font-family: inherit;
  font-size: 12px;
  letter-spacing: 0.25em;
  padding: 10px 22px;
  cursor: pointer;
  border-radius: 4px;
  transition: border-color 140ms ease, color 140ms ease, box-shadow 140ms ease, background 140ms ease;
  display: inline-flex;
  align-items: center;
  gap: 10px;
}
.btn.big { font-size: 13px; padding: 12px 28px; }

.btn:hover {
  border-color: var(--accent);
  color: var(--accent);
  box-shadow: 0 0 12px rgba(0, 240, 255, 0.28);
}

.btn.dice:hover {
  border-color: var(--magenta);
  color: var(--magenta);
  box-shadow: 0 0 14px rgba(255, 58, 165, 0.3);
}

/* SMPL button — vert acide pour le distinguer du DICE pattern */
.btn.smpl:hover {
  border-color: #5fc080;
  color: #5fc080;
  box-shadow: 0 0 14px rgba(95, 192, 128, 0.3);
}
.btn.smpl.rolling .dice-icon {
  animation: dice-spin 350ms cubic-bezier(0.2, 0.7, 0.3, 1);
}

/* KIT button — orange pour le distinguer (random kit cohérent) */
.btn.kit:hover {
  border-color: #ffa84a;
  color: #ffa84a;
  box-shadow: 0 0 14px rgba(255, 168, 74, 0.3);
}
.btn.kit.rolling .dice-icon {
  animation: dice-spin 350ms cubic-bezier(0.2, 0.7, 0.3, 1);
}

.btn.play.active {
  background: rgba(0, 240, 255, 0.08);
  border-color: var(--accent);
  color: var(--accent);
}

/* dice: icône rotation quand on clique */
.dice-icon {
  display: inline-block;
  font-size: 16px;
  line-height: 1;
  transition: transform 300ms ease;
}
.btn.dice.rolling .dice-icon {
  animation: dice-spin 350ms cubic-bezier(0.2, 0.7, 0.3, 1);
}
@keyframes dice-spin {
  0%   { transform: rotate(0deg) scale(1); }
  50%  { transform: rotate(180deg) scale(1.25); }
  100% { transform: rotate(360deg) scale(1); }
}

/* ============================================================
   DRUM SYNTH module — WeirdDrums/Microtonic style 1-voix
   ============================================================ */
.drumsynth-box {
  border-color: #ff5050;
  /* Container : fit-content pour grandir avec les sections actives. */
  width: fit-content;
  min-width: 260px;        /* default : seule la section VOICES (240 + padding) */
  max-width: 90vw;
  position: relative;
  /* Padding pour que les ports en haut/bas (qui dépassent de 8px) ne soient pas coupés */
  margin-top: 8px;
  margin-bottom: 8px;
}
/* MORPH on : voices + morph */
.drumsynth-box.morph-mode {
  min-width: 410px;        /* 240 + 140 + gaps */
}
/* EDIT on : voices + OSC/NOISE/MIX */
.drumsynth-box.edit-mode {
  min-width: 580px;        /* 240 + 3*100 + gaps */
}
/* EDIT + MORPH on : tout visible */
.drumsynth-box.edit-mode.morph-mode {
  min-width: 740px;
}
/* Header buttons : wrap sur 2 lignes pour ne pas overflow le container.
   La title-main reste sur la 1ère ligne, les boutons wrap selon largeur dispo. */
.drumsynth-box .bass-box-title {
  flex-wrap: wrap;
  row-gap: 3px;
  justify-content: flex-start;
  align-items: center;
}
.drumsynth-box .bass-box-title-main {
  flex: 0 0 100%;          /* titre prend une ligne entière */
  margin-bottom: 2px;
}
.drumsynth-box .bass-box-title .module-delete {
  margin-left: auto;        /* le × reste à droite */
}
/* Le header reste vertical (titre + buttons) mais largeur full du container */
.drumsynth-box .bass-box-header {
  width: 100%;
}
/* FX strip : match la largeur du body horizontal */
.drumsynth-box .bass-strip-fx.drumsynth-strip-fx {
  width: auto;
  margin: 0 6px 6px;
}
.drumsynth-box .drumsynth-title { color: #ff5050; }
.drumsynth-header .drum-init-btn,
.drumsynth-header .drum-rand-btn {
  background: transparent;
  border: 1px solid rgba(255, 80, 80, 0.4);
  color: rgba(255, 80, 80, 0.9);
  font-family: inherit;
  font-size: 8px;
  letter-spacing: 0.15em;
  font-weight: 700;
  padding: 3px 6px;
  border-radius: 2px;
  cursor: pointer;
  margin-left: 3px;
}
.drumsynth-header .drum-init-btn:hover,
.drumsynth-header .drum-rand-btn:hover {
  background: rgba(255, 80, 80, 0.15);
  border-color: #ff5050;
  color: #fff;
}
.drumsynth-header .drum-rand-btn {
  border-color: rgba(255, 168, 74, 0.4);
  color: rgba(255, 168, 74, 0.9);
}
.drumsynth-header .drum-rand-btn:hover {
  background: rgba(255, 168, 74, 0.15);
  border-color: #ffa84a;
}
.drumsynth-header .drum-autoseq-btn {
  background: transparent;
  border: 1px solid rgba(95, 192, 128, 0.4);
  color: rgba(95, 192, 128, 0.7);
  font-family: inherit;
  font-size: 8px;
  letter-spacing: 0.15em;
  font-weight: 700;
  padding: 3px 6px;
  border-radius: 2px;
  cursor: pointer;
  margin-left: 3px;
}
.drumsynth-header .drum-autoseq-btn:hover {
  border-color: #5fc080;
  color: #5fc080;
}
.drumsynth-header .drum-autoseq-btn.active {
  background: rgba(95, 192, 128, 0.2);
  border-color: #5fc080;
  color: #fff;
  box-shadow: 0 0 6px rgba(95, 192, 128, 0.4);
}
.drumsynth-header .drum-dice-all-btn {
  background: transparent;
  border: 1px solid rgba(255, 168, 74, 0.4);
  color: rgba(255, 168, 74, 0.9);
  font-family: inherit;
  font-size: 8px;
  letter-spacing: 0.15em;
  font-weight: 700;
  padding: 3px 6px;
  border-radius: 2px;
  cursor: pointer;
  margin-left: 3px;
  transition: all 100ms ease;
}
.drumsynth-header .drum-dice-all-btn:hover {
  background: rgba(255, 168, 74, 0.15);
  border-color: #ffa84a;
  color: #fff;
}
.drumsynth-header .drum-dice-all-btn.rolled {
  background: #ffa84a;
  color: #0a0a0a;
  box-shadow: 0 0 8px rgba(255, 168, 74, 0.7);
}
.drumsynth-header .drum-edit-btn,
.drumsynth-header .drum-morph-btn {
  background: transparent;
  font-family: inherit;
  font-size: 8px;
  letter-spacing: 0.15em;
  font-weight: 700;
  padding: 3px 6px;
  border-radius: 2px;
  cursor: pointer;
  margin-left: 3px;
  border: 1px solid;
}
.drumsynth-header .drum-edit-btn {
  border-color: rgba(176, 160, 224, 0.4);
  color: rgba(176, 160, 224, 0.85);
}
.drumsynth-header .drum-edit-btn:hover {
  border-color: #b0a0e0;
  background: rgba(176, 160, 224, 0.12);
}
.drumsynth-header .drum-edit-btn.active {
  background: rgba(176, 160, 224, 0.3);
  border-color: #b0a0e0;
  color: #fff;
  box-shadow: 0 0 6px rgba(176, 160, 224, 0.5);
}
.drumsynth-header .drum-morph-btn {
  border-color: rgba(255, 122, 208, 0.45);
  color: rgba(255, 122, 208, 0.9);
}
.drumsynth-header .drum-morph-btn:hover {
  border-color: #ff7ad0;
  background: rgba(255, 122, 208, 0.15);
}
.drumsynth-header .drum-morph-btn.active {
  background: rgba(255, 122, 208, 0.3);
  border-color: #ff7ad0;
  color: #fff;
  box-shadow: 0 0 6px rgba(255, 122, 208, 0.55);
}

/* === Per-voice chance mini sliders (MUT/DRIFT/WILD) === */
.drumsynth-voice-row {
  grid-template-columns: 50px 42px 1fr 54px 22px !important;
}
.drumsynth-voice-ms {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 1px;
  height: 18px;
}
.drumsynth-voice-mute,
.drumsynth-voice-solo {
  background: transparent;
  border: 1px solid rgba(255, 255, 255, 0.2);
  color: rgba(255, 255, 255, 0.55);
  font-family: inherit;
  font-size: 8px;
  font-weight: 700;
  padding: 0;
  border-radius: 2px;
  cursor: pointer;
  transition: all 80ms ease;
  display: flex;
  align-items: center;
  justify-content: center;
}
.drumsynth-voice-mute:hover,
.drumsynth-voice-solo:hover {
  border-color: rgba(255, 255, 255, 0.5);
  color: #fff;
}
.drumsynth-voice-mute.active {
  background: rgba(255, 80, 80, 0.35);
  border-color: #ff5050;
  color: #fff;
  box-shadow: 0 0 4px rgba(255, 80, 80, 0.6);
}
.drumsynth-voice-solo.active {
  background: rgba(255, 216, 74, 0.4);
  border-color: #ffd84a;
  color: #0a0a0a;
  box-shadow: 0 0 4px rgba(255, 216, 74, 0.7);
}
.drumsynth-voice-fx {
  background: transparent;
  border: 1px solid rgba(255, 255, 255, 0.2);
  color: rgba(255, 255, 255, 0.55);
  font-family: inherit;
  font-size: 8px;
  font-weight: 700;
  padding: 0;
  border-radius: 2px;
  cursor: pointer;
  transition: all 80ms ease;
  display: flex;
  align-items: center;
  justify-content: center;
}
.drumsynth-voice-fx:hover {
  border-color: rgba(0, 240, 255, 0.6);
  color: #00f0ff;
}
.drumsynth-voice-fx.active {
  background: rgba(0, 240, 255, 0.25);
  border-color: #00f0ff;
  color: #fff;
  box-shadow: 0 0 4px rgba(0, 240, 255, 0.6);
}
/* Labels discrets pour les rangées de ports trig (haut/bas) */
.drumsynth-trig-label {
  position: absolute;
  font-size: 6.5px;
  letter-spacing: 0.3em;
  font-weight: 700;
  color: rgba(255, 255, 255, 0.35);
  pointer-events: none;
  z-index: 5;
  font-family: inherit;
  white-space: nowrap;
}
.drumsynth-trig-label.drumsynth-trig-in {
  top: -7px;
  left: 6px;                    /* ancré à gauche, devant le port K */
  background: rgba(12, 12, 20, 0.85);
  padding: 0 3px;
}
.drumsynth-trig-label.drumsynth-trig-out {
  bottom: -7px;
  left: 6px;
  background: rgba(12, 12, 20, 0.85);
  padding: 0 3px;
}

/* === 4 ports trig per-voice (top IN / bottom OUT) === */
.drum-voice-port {
  /* override le default centered. left/bottom/top sont set inline ou via [side] */
  background: rgba(10, 10, 16, 0.85);
  border: 2px solid var(--voice-color, #fff);
  width: 14px;
  height: 14px;
  font-size: 7px;
  font-weight: 700;
  color: var(--voice-color, #fff);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: inherit;
  text-shadow: 0 0 2px #000;
  line-height: 1;
}
.drum-voice-port::after {
  display: none;            /* on garde le label texte (K/S/H/P) à la place du jack */
}
.drum-voice-port:hover {
  background: var(--voice-color, #fff);
  color: #000;
  box-shadow: 0 0 8px var(--voice-color, #fff);
  transform: translateX(-50%) scale(1.2);
}
/* Top IN ports : on override le default `left: 50%` via inline style.left% */
.module-port-in[data-port-side="top"].drum-voice-port {
  top: -8px;
  transform: translateX(-50%);
}
.module-port-in[data-port-side="top"].drum-voice-port:hover {
  transform: translateX(-50%) scale(1.2);
}
/* Bottom OUT ports : 4 colorés en bas */
.module-port-out[data-port-side="bottom"].drum-voice-port {
  bottom: -8px;
  top: auto;
  left: 0;                  /* override, position set inline */
  transform: translateX(-50%);
}
.module-port-out[data-port-side="bottom"].drum-voice-port:hover {
  transform: translateX(-50%) scale(1.2);
}
.drum-voice-port.port-connected {
  background: var(--voice-color, #fff);
  color: #000;
  box-shadow: 0 0 6px var(--voice-color, #fff);
}

/* DICE×4 dans la kit-row (au dessus des kits, plus en haut du module) */
.drumsynth-kit-dice-row {
  display: flex;
  gap: 4px;
  margin-bottom: 4px;
}
.drumsynth-kit-dice-btn {
  flex: 1;
  background: transparent;
  border: 1px solid rgba(255, 168, 74, 0.45);
  color: rgba(255, 168, 74, 0.9);
  font-family: inherit;
  font-size: 8px;
  letter-spacing: 0.18em;
  font-weight: 700;
  padding: 4px 6px;
  border-radius: 2px;
  cursor: pointer;
  transition: all 100ms ease;
}
.drumsynth-kit-dice-btn:hover {
  background: rgba(255, 168, 74, 0.15);
  border-color: #ffa84a;
  color: #fff;
}
.drumsynth-kit-dice-btn.rolled {
  background: #ffa84a;
  color: #0a0a0a;
  box-shadow: 0 0 8px rgba(255, 168, 74, 0.7);
}
.drumsynth-voice-chance {
  display: flex;
  gap: 2px;
  height: 18px;
}
.drumsynth-mini-slider {
  position: relative;
  width: 16px;
  height: 18px;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 2px;
  cursor: ns-resize;
  overflow: hidden;
  transition: border-color 80ms ease;
}
.drumsynth-mini-slider:hover {
  border-color: var(--voice-color, #fff);
}
.drumsynth-mini-slider.lfo-assigned {
  border-color: #ff7ad0;
  box-shadow: 0 0 3px rgba(255, 122, 208, 0.5);
}
.drumsynth-mini-fill {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 0%;
  background: var(--voice-color, #fff);
  opacity: 0.65;
  pointer-events: none;
  transition: height 80ms ease;
}
.drumsynth-mini-label {
  position: absolute;
  top: 1px;
  left: 0;
  right: 0;
  text-align: center;
  font-size: 7px;
  font-weight: 700;
  color: rgba(255, 255, 255, 0.85);
  letter-spacing: 0;
  pointer-events: none;
  text-shadow: 0 0 2px #000;
  z-index: 1;
}

/* CHAOS slider (master) sous les voices */
.drumsynth-chaos-row {
  display: grid;
  grid-template-columns: 50px 1fr;
  align-items: center;
  gap: 6px;
  padding-top: 6px;
  margin-top: 4px;
  border-top: 1px solid var(--border);
}
.drumsynth-chaos-label {
  font-size: 8px;
  letter-spacing: 0.18em;
  font-weight: 700;
  color: rgba(255, 168, 74, 0.85);
}
.drumsynth-chaos-slider {
  height: 14px;
}
.drumsynth-chaos-slider .fill {
  background: linear-gradient(90deg, rgba(255, 168, 74, 0.9), rgba(255, 80, 80, 0.9)) !important;
}

/* === Sections togglées indépendamment par EDIT et MORPH ===
   Default : seule la section VOICES est visible.
   EDIT  → ajoute OSC / NOISE / MIX (sections avec data-ds-base-title)
   MORPH → ajoute la section morph (drumsynth-morph)
   Les deux peuvent être on en même temps. */
.drumsynth-box .drumsynth-body .drumsynth-section:not(.drumsynth-voices) {
  display: none;
}
.drumsynth-box.edit-mode .drumsynth-body .drumsynth-section[data-ds-base-title] {
  display: flex;
}
.drumsynth-box.morph-mode .drumsynth-body .drumsynth-section.drumsynth-morph {
  display: flex;
}
.drumsynth-body {
  display: flex;
  flex-direction: row;
  gap: 5px;
  padding: 6px;
  flex-wrap: nowrap;
  align-items: stretch;
}
.drumsynth-section {
  flex: 0 1 auto;
  min-width: 100px;
  background: rgba(12, 12, 20, 0.6);
  border: 1px solid var(--border);
  border-top: 2px solid var(--ds-color, #fff);
  border-radius: 3px;
  padding: 5px 6px 6px;
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.drumsynth-section-title {
  font-size: 8px;
  letter-spacing: 0.28em;
  font-weight: 700;
  color: var(--ds-color, #fff);
  text-align: center;
  padding-bottom: 3px;
  border-bottom: 1px solid var(--border);
}
.drumsynth-knobs {
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.drumsynth-knob-row {
  display: grid;
  grid-template-columns: 40px 1fr;
  align-items: center;
  gap: 4px;
}
.drumsynth-knob-label {
  font-size: 8px;
  letter-spacing: 0.15em;
  font-weight: 700;
  color: rgba(255, 255, 255, 0.7);
}
.drumsynth-knob-row .slider { height: 12px; }
.drumsynth-pillrow .drumsynth-pills {
  display: flex;
  gap: 2px;
}
.drumsynth-pill {
  flex: 1;
  background: transparent;
  border: 1px solid rgba(255, 255, 255, 0.2);
  color: rgba(255, 255, 255, 0.6);
  font-family: inherit;
  font-size: 8px;
  letter-spacing: 0.1em;
  font-weight: 700;
  padding: 3px 0;
  border-radius: 2px;
  cursor: pointer;
}
.drumsynth-pill:hover { border-color: rgba(255, 255, 255, 0.5); color: #fff; }
.drumsynth-pill.active {
  background: var(--ds-color, #fff);
  border-color: var(--ds-color, #fff);
  color: #0a0a0a;
}
/* === 4 VOICES section : VU + step pattern preview live === */
.drumsynth-voices {
  min-width: 240px;
  flex: 0 0 240px;
}
/* Kit picker pills (banque de drum kits) */
.drumsynth-kit-row {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 4px 0 6px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 5px;
}
.drumsynth-kit-label {
  font-size: 8px;
  letter-spacing: 0.2em;
  font-weight: 700;
  color: rgba(255, 80, 80, 0.85);
  flex: 0 0 22px;
}
.drumsynth-kit-pills {
  display: flex;
  flex-wrap: wrap;
  gap: 2px;
  flex: 1;
}
.drumsynth-kit-pill {
  flex: 1 1 auto;
  background: transparent;
  border: 1px solid rgba(255, 80, 80, 0.3);
  color: rgba(255, 80, 80, 0.7);
  font-family: inherit;
  font-size: 7.5px;
  letter-spacing: 0.1em;
  font-weight: 700;
  padding: 3px 5px;
  border-radius: 2px;
  cursor: pointer;
  transition: all 80ms ease;
  white-space: nowrap;
}
.drumsynth-kit-pill:hover {
  border-color: #ff5050;
  color: #ff5050;
}
.drumsynth-kit-pill.active {
  background: rgba(255, 80, 80, 0.25);
  border-color: #ff5050;
  color: #fff;
  box-shadow: 0 0 5px rgba(255, 80, 80, 0.5);
}
.drumsynth-kit-pill.drumsynth-kit-reset {
  border-style: dashed;
  border-color: rgba(255, 168, 74, 0.5);
  color: rgba(255, 168, 74, 0.9);
}
.drumsynth-kit-pill.drumsynth-kit-reset:hover {
  background: rgba(255, 168, 74, 0.18);
  border-color: #ffa84a;
  color: #fff;
}
.drumsynth-voice-row {
  display: grid;
  grid-template-columns: 50px 1fr 22px;
  align-items: center;
  gap: 6px;
  padding: 3px 4px;
  border-radius: 3px;
  cursor: pointer;
  transition: background 100ms ease, box-shadow 100ms ease;
  border: 1px solid transparent;
}
.drumsynth-voice-row:hover {
  background: rgba(255, 255, 255, 0.04);
}
.drumsynth-voice-row.editing {
  background: rgba(255, 255, 255, 0.08);
  border-color: var(--voice-color, #fff);
  box-shadow: 0 0 8px var(--voice-color, #fff), inset 0 0 4px rgba(255, 255, 255, 0.06);
}
.drumsynth-voice-row.editing .drumsynth-voice-label::after {
  content: ' ✎';
  font-size: 0.8em;
  color: #fff;
}
.drumsynth-voice-label {
  font-size: 8px;
  letter-spacing: 0.18em;
  font-weight: 700;
  color: var(--voice-color, #fff);
  cursor: pointer;
  transition: text-shadow 100ms ease, transform 80ms ease;
  user-select: none;
}
.drumsynth-voice-label:hover {
  text-shadow: 0 0 8px var(--voice-color, #fff);
  transform: scale(1.05);
}
.drumsynth-voice-label.previewing {
  text-shadow: 0 0 12px var(--voice-color, #fff), 0 0 6px #fff;
  transform: scale(1.15);
}
.drumsynth-section-active {
  /* color is set inline via DS_VOICE_COLORS (rouge/orange/jaune/blanc) */
  font-weight: 700;
  margin-left: 4px;
}
.drumsynth-voice-vu {
  height: 14px;
  background: rgba(255, 255, 255, 0.08);
  border-radius: 2px;
  overflow: hidden;
  position: relative;
  cursor: ew-resize;
}
/* Fader thumb superposé : barre verticale draggable horizontalement */
.drumsynth-voice-fader {
  position: absolute;
  top: -1px;
  bottom: -1px;
  left: 100%;
  width: 3px;
  background: #fff;
  border-radius: 1px;
  box-shadow: 0 0 4px var(--voice-color, #fff), 0 0 2px rgba(0, 0, 0, 0.8);
  transform: translateX(-50%);
  pointer-events: none;
  z-index: 2;
}
.drumsynth-voice-vu:hover .drumsynth-voice-fader {
  width: 4px;
  box-shadow: 0 0 6px var(--voice-color, #fff), 0 0 3px rgba(0, 0, 0, 0.9);
}
.drumsynth-voice-vu-fill {
  height: 100%;
  width: 0%;
  background: linear-gradient(90deg, var(--voice-color, #fff), rgba(255, 255, 255, 0.5));
  transition: width 60ms linear;
  box-shadow: 0 0 5px var(--voice-color, #fff);
}
.drumsynth-voice-dice {
  background: transparent;
  border: 1px solid rgba(255, 255, 255, 0.2);
  color: rgba(255, 255, 255, 0.6);
  font-family: inherit;
  font-size: 13px;
  font-weight: 700;
  width: 22px;
  height: 18px;
  padding: 0;
  border-radius: 2px;
  cursor: pointer;
  transition: all 100ms ease;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
}
.drumsynth-voice-dice:hover {
  background: rgba(255, 255, 255, 0.1);
  border-color: var(--voice-color, #fff);
  color: var(--voice-color, #fff);
  transform: scale(1.1);
}
.drumsynth-voice-dice.rolled {
  background: var(--voice-color, #fff);
  color: #0a0a0a;
  transform: rotate(180deg) scale(1.2);
}
.drumsynth-voice-hint {
  font-size: 7px;
  letter-spacing: 0.15em;
  color: rgba(255, 255, 255, 0.4);
  font-style: italic;
  text-align: center;
  margin-top: 4px;
  padding-top: 4px;
  border-top: 1px solid var(--border);
}

/* === Preset morphing section === */
.drumsynth-morph {
  min-width: 140px;
  flex: 0 0 140px;
  margin-left: auto;       /* pousse le morph à droite */
}
.drumsynth-morph-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 3px;
  margin-bottom: 4px;
}
.drumsynth-slot {
  background: transparent;
  border: 1px dashed rgba(255, 122, 208, 0.4);
  color: rgba(255, 122, 208, 0.7);
  font-family: inherit;
  font-size: 8px;
  letter-spacing: 0.2em;
  font-weight: 700;
  padding: 5px 0;
  border-radius: 2px;
  cursor: pointer;
  transition: all 100ms ease;
}
.drumsynth-slot:hover {
  border-color: #ff7ad0;
  color: #ff7ad0;
}
.drumsynth-slot.has-preset {
  background: rgba(255, 122, 208, 0.25);
  border-style: solid;
  border-color: #ff7ad0;
  color: #fff;
  box-shadow: 0 0 4px rgba(255, 122, 208, 0.5);
}
.drumsynth-xy-pad {
  position: relative;
  width: 100%;
  aspect-ratio: 1 / 1;
  background: radial-gradient(circle at center,
    rgba(255, 122, 208, 0.08) 0%,
    rgba(12, 12, 20, 0.9) 70%);
  border: 1px solid rgba(255, 122, 208, 0.3);
  border-radius: 4px;
  cursor: crosshair;
  user-select: none;
  margin-bottom: 4px;
}
.drumsynth-xy-handle {
  position: absolute;
  width: 12px;
  height: 12px;
  background: #ff7ad0;
  border-radius: 50%;
  transform: translate(-50%, -50%);
  pointer-events: none;
  box-shadow: 0 0 8px rgba(255, 122, 208, 0.8);
}
.drumsynth-xy-label {
  position: absolute;
  font-size: 7px;
  letter-spacing: 0.18em;
  font-weight: 700;
  color: rgba(255, 122, 208, 0.4);
  pointer-events: none;
}
.drumsynth-xy-nw { top: 2px; left: 4px; }
.drumsynth-xy-ne { top: 2px; right: 4px; }
.drumsynth-xy-sw { bottom: 2px; left: 4px; }
.drumsynth-xy-se { bottom: 2px; right: 4px; }
.drumsynth-morph-hint {
  font-size: 7px;
  letter-spacing: 0.1em;
  color: rgba(255, 122, 208, 0.4);
  font-style: italic;
  text-align: center;
}
.drumsynth-auto-row {
  display: grid;
  grid-template-columns: 50px 1fr;
  gap: 4px;
  align-items: center;
  margin: 4px 0 2px;
}
.drumsynth-auto-btn {
  background: transparent;
  border: 1px solid rgba(255, 122, 208, 0.5);
  color: rgba(255, 122, 208, 0.85);
  font-family: inherit;
  font-size: 8px;
  letter-spacing: 0.2em;
  font-weight: 700;
  padding: 4px 0;
  border-radius: 2px;
  cursor: pointer;
  transition: all 100ms ease;
}
.drumsynth-auto-btn:hover {
  border-color: #ff7ad0;
  color: #ff7ad0;
}
.drumsynth-auto-btn.active {
  background: rgba(255, 122, 208, 0.35);
  border-color: #ff7ad0;
  color: #fff;
  box-shadow: 0 0 8px rgba(255, 122, 208, 0.6);
  animation: drumsynth-auto-pulse 1.5s ease-in-out infinite;
}
@keyframes drumsynth-auto-pulse {
  0%, 100% { box-shadow: 0 0 6px rgba(255, 122, 208, 0.5); }
  50%      { box-shadow: 0 0 14px rgba(255, 122, 208, 0.85); }
}
.drumsynth-auto-speed {
  height: 14px;
}
.drumsynth-auto-speed .fill {
  background: linear-gradient(90deg, rgba(255, 122, 208, 0.9), rgba(255, 168, 74, 0.9)) !important;
}
/* Quand AUTO actif, le handle XY a un glow rose qui pulse */
.drumsynth-xy-pad:has(.drumsynth-auto-btn.active) .drumsynth-xy-handle {
  animation: drumsynth-handle-pulse 1s ease-in-out infinite;
}
@keyframes drumsynth-handle-pulse {
  0%, 100% { box-shadow: 0 0 6px rgba(255, 122, 208, 0.7); }
  50%      { box-shadow: 0 0 14px rgba(255, 122, 208, 1); }
}
.drumsynth-strip-fx {
  margin: 0 6px 6px;
}

/* Console mixer strip colors for drumsynth */
.console-strip.kind-drumsynth { color: #ff5050; }

/* ---------- Scrollbars (au cas où, pas censé apparaître vu le overflow:hidden) ---------- */
::-webkit-scrollbar { display: none; }
