/* Spaghetti — forké du thème "modulaire" de Scotch (panneaux eurorack, vis,
   câbles de patch, voir spaghetti.js). Dans Scotch, le CSS global du site
   donnait à html/body/#sc-canvas leur hauteur ; ici Spaghetti est autonome,
   donc c'est cette feuille qui doit le faire — sinon body reste à hauteur 0
   (tout son contenu est en position absolute/fixed) et les clics sur le
   fond du canvas (double-clic = nouveau bloc, clic = désélectionner) ne
   touchent jamais #sc-canvas puisqu'il n'occupe aucune surface réelle. */
@import url('https://fonts.googleapis.com/css2?family=Martian+Mono:wght,wdth@700,75&family=Silkscreen&family=VT323&display=swap');

/* ── Système pixel ──
   --px est l'unité de la grille : tout trait, bordure, marge visible doit
   en être un multiple, sinon le rendu cesse d'être "pixel". Silkscreen n'est
   net qu'à 8px (sa grille native) : toute l'interface s'y tient. Le code des
   blocs, lui, doit rester confortable à lire et à taper : même famille
   bitmap, mais VT323 (chasse fixe, vraies minuscules).
   --px-border : quatre copies de la boîte décalées d'une case (haut, bas,
   gauche, droite). Leur union forme la bordure SAUF les quatre coins — d'où
   les angles en escalier. Dessinée hors du layout : elle ne coupe pas les
   enfants (clip-path le ferait) mais déborde de 3px de chaque côté, à
   compter dans les espacements.
   Couleurs : jamais de valeur en dur dans les composants, seulement les
   jetons sémantiques --surface (fond des panneaux) / --line (traits, texte)
   / --band (bandeaux de titre) — le thème se règle ici, en un seul endroit. */
:root {
  --px: 3px;
  --paper: #f4f1e8;          /* palette brute */
  --ink: #0b0b0d;
  --surface: #232429;        /* thème sombre */
  --line: #e8e4d8;
  --line-2: #8f8b80;
  --band: #0b0b0d;
  --hot: #d8453a;
  --go: #3aa65a;
  --pixfont: 'Silkscreen', 'Courier New', monospace;
  --codefont: 'VT323', 'Courier New', monospace;
  --px-border:
    0 calc(-1 * var(--px)) 0 0 var(--line), 0 var(--px) 0 0 var(--line),
    calc(-1 * var(--px)) 0 0 0 var(--line), var(--px) 0 0 0 var(--line);
  --thin-border: 0 0 0 1px var(--line);   /* blocs et leurs barrettes */
}

html, body { height: 100%; margin: 0; }
#sc-canvas { min-height: 100vh; }
/* Sans ça, .sc-bloc/.sc-image (bordure 1px) mesurent large via
   getBoundingClientRect() (border-box) mais s'écrivent en content-box via
   style.width/height (spaghetti.js, sync + redimensionnement) : chaque
   aller-retour mesure→écrit rajoutait la bordure par-dessus, et les blocs
   grossissaient tout seuls de 2px à chaque tick de synchro. border-box aligne
   lecture et écriture sur la même boîte. */
.sc-el { box-sizing: border-box; }
body {
  background:
    repeating-linear-gradient(0deg, #1c1d21 0px, #1c1d21 118px, #0b0b0d 118px, #0b0b0d 126px) !important;
}
/* ── Blocs : même langage que le rack, en plus épuré ──
   Le fond reste la couleur propre du bloc (elle a un sens : teinte → onde,
   voir blockCharacter). Cadre d'un trait fin (1px, --thin-border) plutôt que
   la bordure pixel des modules. Il est porté par ::before et pas par le
   bloc : le JS écrit style.boxShadow (éclat d'apparition), qui écraserait
   une bordure posée au même endroit. */
.sc-el.sc-bloc {
  border: none;
  font-family: var(--codefont);
  font-size: 20px;
  line-height: 1.05;
  color: var(--ink);
  white-space: pre-wrap;   /* les retours à la ligne doivent rester visibles même
                               avant que le bloc soit reconnu comme "codé" */
  /* Bandeau de titre, comme les modules du rack : 7 cases (21px) de --band en
     haut du bloc, par-dessus sa couleur (posée en background-color inline par
     le JS, donc l'image de fond CSS s'y superpose sans l'écraser). Il porte
     la case mute, la LED de boucle et la croix : le code commence dessous.
     !important : le JS pose padding:10px 12px en inline (createLiveBlock). */
  padding-top: 30px !important;
  background-image: linear-gradient(var(--band), var(--band));
  background-size: 100% 21px;
  background-repeat: no-repeat;
}
.sc-el.sc-image, .sc-el.sc-iframe { border: none; }
.sc-el.sc-bloc::before, .sc-el.sc-image::before, .sc-el.sc-iframe::before {
  content: '';
  position: absolute; inset: 0;
  pointer-events: none;
  box-shadow: var(--thin-border);
}

/* Câbles : masqués sur mobile et en preview mobile */
@media (max-width:768px) { #sc-patch-cables, .sc-jack { display:none !important; } }
body.sc-mobile-view #sc-patch-cables { display:none !important; }

/* Barrettes de connexion sous les blocs (visiteurs) */
/* La barrette pend sous le bloc : placeBar la pose 1px sous sa boîte, si
   bien que sa bordure du haut coïncide avec la bordure du bas du bloc
   (un seul trait commun). Même trait fin que le bloc. */
.sc-jackbar {
  position: absolute;
  z-index: 600;
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 9px;
  background: var(--surface);
  border: none;
  box-shadow: var(--thin-border);
}
/* Trous = jacks du rack : anneau pixel, point central coloré (--c) pour les
   trous MOD (jaune) et CAR (orange). */
.sc-hole {
  --c: transparent; --ring: var(--line);
  width: 9px; height: 9px;
  margin: var(--px);
  flex-shrink: 0;
  border: none; border-radius: 0;
  background:
    linear-gradient(var(--c), var(--c)) center / var(--px) var(--px) no-repeat,
    var(--surface);
  box-shadow:
    0 calc(-1 * var(--px)) 0 0 var(--ring), 0 var(--px) 0 0 var(--ring),
    calc(-1 * var(--px)) 0 0 0 var(--ring), var(--px) 0 0 0 var(--ring);
  cursor: pointer;
}
.sc-hole:hover { --ring: #f0c030; }
.sc-hole-mod { --c: #f0c030; }
.sc-hole-car { --c: #ff8c28; }

/* Sélecteur d'onde du bloc */
.sc-wave-btn {
  margin: var(--px);
  padding: var(--px);
  display: flex; align-items: center; justify-content: center;
  line-height: 0;
  color: #7dd8a8;
  background: var(--surface);
  border: none; border-radius: 0;
  box-shadow: var(--px-border);
  cursor: pointer;
}
.sc-wave-btn:hover { background: var(--line); color: var(--surface); }

/* Mini-potards pitch / niveau / punch : gabarit pixel de 7 cases (voir
   pxKnobSvg), l'aiguille garde la couleur qui les distinguait — jaune pour
   le pitch, vert pour le niveau, orange comme CRUSH-03 pour le punch. */
.sc-pitch, .sc-level, .sc-punch {
  width: 21px; height: 21px;
  cursor: ns-resize;
  position: relative;
  touch-action: none;
  flex-shrink: 0;
}
.sc-pitch svg, .sc-level svg, .sc-punch svg { display: block; width: 100%; height: 100%; }
.sc-jackbar .pk-disc { fill: var(--surface); }
.sc-jackbar .pk-ring { fill: var(--line); }
.sc-pitch .pk-needle { fill: #f0c030; }
.sc-level .pk-needle { fill: #4ad07a; }
.sc-punch .pk-needle { fill: #e06030; }
.sc-pitch:hover .pk-ring, .sc-level:hover .pk-ring, .sc-punch:hover .pk-ring { fill: var(--hot); }

body.sc-edit-mode .sc-jackbar { display: none; }

/* ── Mute / play par bloc : une case pleine, verte ou rouge ──
   Le ● posé par le JS n'est plus qu'un repère invisible : c'est la couleur
   de la case qui parle. Posée dans le bandeau du bloc (21px : 3 + 15 + 3),
   anneau --line comme les jacks du rack. */
.sc-block-mute {
  position: absolute;
  top: 6px; left: 6px;
  width: 9px; height: 9px;
  font-size: 0; color: transparent;
  background: var(--go);
  box-shadow: var(--px-border);
  cursor: pointer;
  z-index: 20;
  touch-action: none;
}
.sc-block-mute:hover { background: #45bb68; }
.sc-block-mute.sc-muted { background: var(--hot); }
/* En attente de bascule (au prochain début de mesure) : clignote */
.sc-block-mute.sc-mute-pending { animation: sc-mute-blink .5s steps(2) infinite; }
@keyframes sc-mute-blink { 0%{opacity:1} 50%{opacity:.3} }
/* Bloc muté : légèrement estompé */
.sc-el.sc-block-muted { opacity: .5; }

/* ── Tiroir des modules ── */
.sc-module {
  transition: transform .34s cubic-bezier(.4,0,.2,1), opacity .28s ease;
}
body.sc-rack-hidden .sc-module {
  transform: translateY(140vh) !important;
  opacity: 0;
  pointer-events: none;
}
#sc-rack-toggle {
  position: fixed;
  bottom: 19px; left: 150px;
  z-index: 10003;
  display: flex; align-items: center; gap: 6px;
  height: 24px; padding: 0 9px;
  background: var(--surface); color: var(--line);
  border: none; border-radius: 0;
  box-shadow: var(--px-border);
  font-family: var(--pixfont); font-size: 8px;
  cursor: pointer;
}
#sc-rack-toggle:hover, #sc-rack-toggle.closed { background: var(--line); color: var(--surface); }
#sc-rack-toggle .sc-rack-icon { display: flex; line-height: 0; }

/* ── Contrôles de zoom ── */
.sc-zoom-ctrl {
  position: fixed;
  bottom: 19px; left: 19px;
  display: flex; gap: 0;
  z-index: 10002;
  background: var(--surface);
  box-shadow: var(--px-border);
}
.sc-zoom-ctrl button {
  background: transparent; color: var(--line);
  border: none; border-radius: 0;
  font-family: var(--pixfont); font-size: 8px;
  width: 24px; height: 24px; padding: 0;
  cursor: pointer;
}
.sc-zoom-ctrl button:hover { background: var(--line); color: var(--surface); }
.sc-zoom-ctrl button:active { transform: translateY(var(--px)); }
#sc-zoom-label-btn {
  width: auto; padding: 0 8px;
  border-left: var(--px) solid var(--line); border-right: var(--px) solid var(--line);
}
#sc-zoom-label { font-size: 8px; color: inherit; }

/* Le canvas se transforme (zoom/pan) : scotch.css met overflow-x:hidden sur
   <main> pour le rendu normal, mais ici le clip se figerait dans l'espace
   local du canvas et resterait borné à la largeur d'origine même après un
   dézoom — il faut laisser le débordement libre pour que le pan/zoom donne
   bien accès à tout le contenu placé hors du cadre initial. */
#sc-canvas { will-change: transform; position: relative; z-index: 1; overflow: visible; }

/* Bloc verrouillé (sélectionné) : cadenas visible, animation figée */
.sc-el.sc-locked::after {
  content: '';   /* cadenas pixel 5×5, même dessin que les icônes du rack (pxIcon) */
  position: absolute;
  top: 3px; right: 42px;   /* dans le bandeau, à gauche de la LED et de la croix */
  width: 15px; height: 15px;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 5 5' shape-rendering='crispEdges' fill='%23e8e4d8'%3E%3Cpath d='M1 0h3v1H1zM1 1h1v1H1zM3 1h1v1H3zM0 2h5v1H0zM0 3h2v1H0zM3 3h2v1H3zM0 4h5v1H0z'/%3E%3C/svg%3E") center / 15px 15px no-repeat;
  pointer-events: none;
  z-index: 21;
}

/* ── Panneau d'animation (bloc sélectionné) : un mini-module du rack ──
   Bandeau de titre, boutons de mouvement en groupe segmenté (écart d'une
   case → bordures communes), curseurs pixel. Posé sous la barrette de jacks :
   elle commence 3px sous le bloc et mesure 33px + 3px de bordure (39px), puis
   une case d'air et la bordure du panneau → 48px. */
.sc-anim-panel {
  --pad: 9px;
  position: absolute;
  top: 100%; left: 0; margin-top: 48px;
  width: max-content;
  background: var(--surface);
  color: var(--line);
  border: none; border-radius: 0;
  box-shadow: var(--px-border);
  padding: 0 var(--pad) var(--pad);
  z-index: 40;
  display: none;
  font-family: var(--pixfont); font-size: 8px; line-height: 1;
}
.sc-anim-panel.visible { display: block; }
.sc-anim-title {
  margin: 0 calc(-1 * var(--pad)) 9px;
  padding: 4px var(--pad) 3px;
  background: var(--band); color: var(--line);
  letter-spacing: .08em;
}
.sc-anim-moves { display: flex; gap: var(--px); margin: 0 var(--px) 12px; }
.sc-anim-move {
  width: 21px; height: 21px; padding: 0;
  display: flex; align-items: center; justify-content: center;
  background: var(--surface); color: var(--line);
  border: none; border-radius: 0;
  box-shadow: var(--px-border);
  cursor: pointer;
}
.sc-anim-move .px-ico { display: block; }
.sc-anim-move:hover, .sc-anim-move.on { background: var(--line); color: var(--surface); }
.sc-anim-move.on { background: #f0c030; }
.sc-anim-move:active { transform: translateY(var(--px)); }
.sc-anim-row { display: flex; align-items: center; gap: 9px; margin: 0 var(--px); height: 15px; }
.sc-anim-row + .sc-anim-row { margin-top: 6px; }
.sc-anim-ico { display: flex; color: var(--line-2); flex-shrink: 0; }
/* Curseur pixel : rail de 1 case, remplissage jaune jusqu'à --v (rangeFill),
   poignée pleine de 3×5 cases. */
.sc-anim-row input[type=range] {
  -webkit-appearance: none; appearance: none;
  flex: 1 1 0; width: 0; min-width: 0; height: 15px; margin: 0;   /* largeur 0 : c'est la rangée de boutons qui fixe celle du panneau */
  background:
    linear-gradient(#f0c030, #f0c030) 0 50% / var(--v, 50%) var(--px) no-repeat,
    linear-gradient(var(--line-2), var(--line-2)) 0 50% / 100% var(--px) no-repeat;
  cursor: pointer;
}
.sc-anim-row input[type=range]:focus { outline: none; }
.sc-anim-row input[type=range]::-webkit-slider-runnable-track { height: 15px; background: transparent; }
.sc-anim-row input[type=range]::-moz-range-track { height: 15px; background: transparent; }
.sc-anim-row input[type=range]::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 9px; height: 15px; border: none; border-radius: 0;
  background: var(--line);
}
.sc-anim-row input[type=range]::-moz-range-thumb {
  width: 9px; height: 15px; border: none; border-radius: 0;
  background: var(--line);
}
.sc-anim-row input[type=range]:hover::-webkit-slider-thumb { background: #f0c030; }
.sc-anim-row input[type=range]:hover::-moz-range-thumb { background: #f0c030; }

/* ── Boutons des modules : un seul vocabulaire ──
   Papier + bordure pixel, inversion encre au survol, enfoncement d'une case
   au clic, encre pleine pour l'état actif. Les marges verticales valent 3
   cases : les bordures débordent de 1 case de chaque côté, il en reste 1
   de papier entre deux boutons. */
.sc-module button:not(#sc-synth-pwr) {
  display: flex; align-items: center; justify-content: center; gap: 6px;
  width: 100%;
  margin: 0 0 9px; padding: 4px 3px 3px;
  background: var(--surface); color: var(--line);
  border: none; border-radius: 0;
  box-shadow: var(--px-border);
  font-family: var(--pixfont); font-size: 8px; letter-spacing: .04em;
  text-align: center; white-space: nowrap;
  cursor: pointer;
}
.sc-module button:not(#sc-synth-pwr):hover,
.sc-module button.on { background: var(--line); color: var(--surface); }
.sc-module button:not(#sc-synth-pwr):active { transform: translateY(var(--px)); }
.sc-module button:not(#sc-synth-pwr):last-child { margin-bottom: 0; }
/* Icônes pixel 1-bit (pxIcon) : 5×5 cases de 3px, couleur du texte */
.px-ico { display: block; flex-shrink: 0; }
/* Bouton à icône : icône à gauche, alignée d'un bouton à l'autre dans une
   colonne ; hauteur = icône (15px) + une case de chaque côté */
.sc-module button.sc-ibtn:not(#sc-synth-pwr) { justify-content: flex-start; padding: var(--px) 6px; }
.sc-module #sc-turn-fxcut:not(#sc-synth-pwr) { margin-top: 9px; }   /* :not() : même poids que la règle générale des boutons, sinon ignorée */
/* Actions destructives : rouge au repos comme au survol */
#sc-synth-clear, #sc-turn-fxcut { color: var(--hot); }
#sc-synth-clear:hover, #sc-turn-fxcut:hover { background: var(--hot); color: var(--surface); }

/* Groupes segmentés : écart d'une case exactement → les bordures voisines
   se superposent et forment un seul trait commun. */
.sc-turn-dens, .sc-turn-div, .sc-bar-pick {
  display: flex; gap: var(--px);
  margin: 0 var(--px) 9px;
}
.sc-turn-dens button, .sc-turn-div button, .sc-bar-pick button {
  flex: 1; width: auto; min-width: 0;
  margin: 0 !important; padding: 4px 0 3px;
  letter-spacing: 0;   /* "VIVANT", "MOITIÉ" : quatre boutons dans 170px, chaque pixel compte */
}

/* Légendes : gris encre, pas de capitales forcées (Silkscreen a ses propres
   minuscules, en petites capitales) */
.sc-gen-hint, .sc-turn-lbl, #sc-turn-count {
  font-family: var(--pixfont); font-size: 8px; letter-spacing: .02em;
  color: var(--line-2); text-align: center; text-transform: none;
}
.sc-gen-hint { margin-top: 3px; white-space: normal; line-height: 1.4; }
.sc-turn-lbl { margin-bottom: 6px; }

/* ── Module CARREFOUR ── */
.sc-turn-ins {
  display: flex; gap: 9px; justify-content: center;
  margin: 3px 0 9px;
}
.sc-turn-in {
  --c: #ff8c28;   /* même orange que les câbles du carrefour */
  font-size: 0;   /* masque le numéro : on garde le jack */
  flex: 0 0 auto;
}
.sc-turn-jackrow { display: flex; align-items: center; gap: 8px; margin-bottom: 9px; justify-content: center; }
.sc-turn-ctrl { margin-bottom: 6px; }
#sc-turn-members { display: flex; flex-wrap: wrap; gap: 9px; margin: 9px var(--px) 3px; }
.sc-turn-chip {
  min-width: 12px; height: 12px; line-height: 12px;
  padding: 0 2px; text-align: center;
  font-family: var(--pixfont); font-size: 8px;
  background: var(--surface); color: var(--line);
  border: none; border-radius: 0;
  box-shadow: var(--px-border);
  cursor: pointer;
}
.sc-turn-chip.on { background: var(--line); color: var(--surface); }
.sc-turn-chip:hover { background: var(--hot); color: var(--surface); }
/* Blocs pilotés par le carrefour */
.sc-el.sc-turn-on  { outline: 1px solid #e0a030; outline-offset: var(--px); }
.sc-el.sc-turn-off { opacity: .45; }

/* Points de mesure : où on en est dans la mesure courante, et quand un
   mute/démute en attente va tomber (1er point, en rouge) */
.sc-bar-dots { display: flex; gap: var(--px); justify-content: center; margin: 0 0 9px; }
.sc-bar-dot { width: 6px; height: 6px; background: #3a3b41; }
.sc-bar-dot.on { background: var(--line); }
.sc-bar-dot.sc-bar-dot-hit { background: var(--hot); }

.sc-el.sc-coding {
  font-family: var(--codefont);
  white-space: pre-wrap;
  line-height: 1.05;
}

/* Poignée de redimensionnement des blocs codés (visiteur) : un triangle de
   six cases jaunes, dessiné en SVG 5×5 agrandi à 15px (3px par case) */
.sc-live-resize {
  position: absolute;
  width: 15px; height: 15px;
  z-index: 700;
  cursor: nwse-resize;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 5 5' shape-rendering='crispEdges' fill='%23f0c030'%3E%3Cpath d='M4 0h1v1H4zM2 2h1v1H2zM4 2h1v1H4zM0 4h1v1H0zM2 4h1v1H2zM4 4h1v1H4z'/%3E%3C/svg%3E") center / 15px 15px no-repeat;
  touch-action: none;
}
@media (max-width:768px) { .sc-live-resize { display: none !important; } }
.sc-el.sc-live-edit {
  outline: 1px dashed #f0c030 !important;
  outline-offset: var(--px);
  cursor: text !important;
  user-select: text !important;
}
/* Boucle live en cours : case verte qui clignote dans le bandeau, à gauche
   de la croix (même rangée que la case mute) */
.sc-live-led {
  position: absolute;
  top: 6px; right: 27px;
  width: 9px; height: 9px;
  background: #30d060;
  animation: sc-live-pulse 1s steps(2) infinite;
  pointer-events: none;
}
@keyframes sc-live-pulse { 0%,100%{opacity:1} 50%{opacity:.2} }

/* Pulsation du bloc à chaque note jouée */
.sc-el.sc-note-on {
  filter: brightness(1.4) saturate(1.2);
}
.sc-el.sc-bloc { transition: filter .06s ease, box-shadow .12s ease; }

/* ── Modules (SCOTCH-01 + minis) ── */
/* Panneau papier, bordure pixel, pas de vis ni de relief. --pad-t/--pad-x
   décrivent le rembourrage du module : le bandeau de titre s'en sert pour
   s'étendre jusqu'aux bords (marges négatives) quelle que soit la taille. */
.sc-module {
  position: fixed;
  bottom: 14px; right: 14px;
  z-index: 9997;
  --pad-t: 9px; --pad-x: 12px;
  padding: var(--pad-t) var(--pad-x) 12px;
  width: 168px;
  background: var(--surface);
  border: none;
  box-shadow: var(--px-border);
  font-family: var(--pixfont);
  font-size: 8px;
  color: var(--line);
  user-select: none;
}
.sc-mini {
  --pad-t: 9px; --pad-x: 9px;
  width: 86px;
  padding: var(--pad-t) var(--pad-x) 9px;
}
.sc-mod-tiny {
  --pad-t: 6px; --pad-x: 6px;
  width: 58px;
  padding: var(--pad-t) var(--pad-x) 6px;
}
.sc-mini .sc-knob-wrap { margin: 0 auto; }

/* Bandeau inversé : c'est aussi la poignée de déplacement du module */
.sc-module-title {
  margin: calc(-1 * var(--pad-t)) calc(-1 * var(--pad-x)) 9px;
  padding: 4px 6px 3px;
  background: var(--band);
  color: var(--line);
  font-size: 8px;
  letter-spacing: .06em;
  text-align: left;
  white-space: nowrap;
  overflow: hidden;
  cursor: move;
  touch-action: none;
}
.sc-mod-tiny .sc-module-title { margin-bottom: 6px; text-align: center; padding: 4px 0 3px; }

/* Sections du module — séparées par un pointillé d'une case de haut */
.sc-sec {
  padding: 9px 0;
  background: linear-gradient(to right, var(--line-2) 50%, transparent 0) left bottom / 6px var(--px) repeat-x;
}
.sc-sec:last-child { background: none; padding-bottom: 0; }
.sc-sec:first-of-type { padding-top: 0; }
.sc-sec-lbl {
  font-size: 8px;
  color: var(--line-2);
  text-align: center;
  margin-bottom: 6px;
}
/* Section transport : bouton power + potard VOL alignés */
.sc-sec:first-of-type {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
}
.sc-pwr-col { display: flex; flex-direction: column; align-items: center; }
.sc-sec:first-of-type #sc-synth-pwr { margin: 0; }
.sc-sec:first-of-type .sc-pwr-label { width: 52px; margin: 4px 0 0; }
.sc-sec:first-of-type .sc-synth-knobs { flex: 0 0 auto; }

/* Sorties de modulation */
.sc-synth-outs {
  display: flex;
  justify-content: space-between;
  margin-top: 0;
  padding-top: 0;
  border-top: none;
}
.sc-modjack-wrap {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
}
.sc-modjack-wrap span { font-size: 8px; color: var(--line); }
/* Jack pixel : boîte de 3×3 cases + bordure en escalier = un rond de 5×5
   cases. Le point central porte la couleur de l'effet (--c) ; branché, tout
   l'intérieur se remplit de cette couleur. Survol : l'anneau prend la
   couleur (--ring ne peut pas passer par --px-border, figée à :root). */
.sc-modjack {
  --ring: var(--line);
  width: 9px; height: 9px;
  margin: var(--px);
  border: none; border-radius: 0;
  background:
    linear-gradient(var(--c, var(--line)), var(--c, var(--line))) center / var(--px) var(--px) no-repeat,
    var(--surface);
  box-shadow:
    0 calc(-1 * var(--px)) 0 0 var(--ring), 0 var(--px) 0 0 var(--ring),
    calc(-1 * var(--px)) 0 0 0 var(--ring), var(--px) 0 0 0 var(--ring);
  cursor: pointer;
}
.sc-modjack:hover { --ring: var(--c, var(--line)); }
.sc-modjack.on    { background: var(--c, var(--line)); }

/* Interrupteur : aplat rouge (éteint) / vert (allumé), bordure pixel.
   L'invite à lancer clignote en marches (steps) — un halo doux jurerait
   avec la grille : ici c'est un anneau rouge d'une case qui apparaît et
   disparaît au-delà de la bordure. */
#sc-synth-pwr {
  display: block;
  margin: 0 auto 3px;
  width: 48px; height: 30px;
  background: var(--hot);
  border: none; border-radius: 0;
  box-shadow: var(--px-border);
  cursor: pointer;
  position: relative;
  animation: sc-pwr-invite 1s steps(1) infinite;
}
#sc-synth-pwr:hover { background: #e8564a; }
#sc-synth-pwr:active { transform: translateY(var(--px)); }
.sc-pwr-glyph {
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%,-50%);
  line-height: 0;
  color: var(--paper);   /* clair fixe : posé sur l'aplat rouge/vert, pas sur un panneau */
  pointer-events: none;
}
#sc-synth-led {
  position: absolute;
  top: var(--px); right: var(--px);
  width: var(--px); height: var(--px);
  background: var(--paper);
  opacity: .5;
}
/* 3 cases sous le bouton : bordure (1) + anneau d'invite (1) + 1 de marge,
   sinon l'anneau clignotant raye le haut du texte */
.sc-pwr-label {
  text-align: center;
  font-size: 8px;
  color: var(--hot);
  margin: 9px 0 6px;
}
/* État allumé : vert, l'invite s'arrête */
#sc-synth.on #sc-synth-pwr { background: var(--go); animation: none; }
#sc-synth.on #sc-synth-pwr:hover { background: #45bb68; }
#sc-synth.on .sc-pwr-label { color: var(--go); }

@keyframes sc-pwr-invite {
  0%   { box-shadow: var(--px-border); }
  50%  { box-shadow: var(--px-border), 0 0 0 calc(2 * var(--px)) var(--hot); }
}

/* Croix de suppression d'un bloc (visiteur) : pendant de la case mute, en
   haut à droite du bandeau. Le ✕ du JS est masqué, la croix est une grille
   3×3 en SVG (3px par case) — rouge sur panneau, papier sur rouge au survol. */
.sc-block-del {
  position: absolute;
  top: 6px; right: 6px;
  width: 9px; height: 9px;
  font-size: 0; color: transparent;
  background: var(--surface) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 3 3' shape-rendering='crispEdges' fill='%23d8453a'%3E%3Cpath d='M0 0h1v1H0zM2 0h1v1H2zM1 1h1v1H1zM0 2h1v1H0zM2 2h1v1H2z'/%3E%3C/svg%3E") center / 9px 9px no-repeat;
  box-shadow: var(--px-border);
  cursor: pointer;
  opacity: 0;
  z-index: 20;
  touch-action: none;
}
.sc-el:hover .sc-block-del { opacity: 1; }
.sc-block-del:hover {
  background: var(--hot) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 3 3' shape-rendering='crispEdges' fill='%23f4f1e8'%3E%3Cpath d='M0 0h1v1H0zM2 0h1v1H2zM1 1h1v1H1zM0 2h1v1H0zM2 2h1v1H2z'/%3E%3C/svg%3E") center / 9px 9px no-repeat;
}

/* Panneau d'aide */
#sc-help {
  position: fixed;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  width: min(440px, 90vw);
  max-height: 82vh;
  overflow-y: auto;
  background: #1a1a2e;
  border: 1px solid #55565c;
  box-shadow: 0 8px 40px rgba(0,0,0,.6);
  color: #d8d5cc;
  font-family: 'Martian Mono', 'Courier New', monospace;
  font-size: 12px;
  line-height: 1.5;
  padding: 22px 24px;
  z-index: 10001;
}
#sc-help h4 {
  margin: 0 0 12px; font-size: 14px; color: #7dd8a8;
  letter-spacing: .06em;
}
#sc-help p { margin: 0 0 10px; }
#sc-help b { color: #f0c030; }
#sc-help i { color: #8ab8ff; font-style: normal; }
#sc-help pre {
  background: #0d0d18; border: 1px solid #33343a;
  padding: 8px 10px; margin: 0 0 10px;
  font-size: 11px; color: #a8d8b8; white-space: pre-wrap;
}
#sc-help-x {
  position: absolute; top: 10px; right: 12px;
  background: none; border: none; color: #999;
  font-size: 16px; cursor: pointer; line-height: 1;
}
#sc-help-x:hover { color: #fff; }

/* Bloc sélectionné pour le clavier live : un second trait fin, décollé */
.sc-el.sc-kb-sel {
  outline: 1px solid var(--line) !important;
  outline-offset: var(--px);
}

/* Notification "lien copié" */
#sc-share-note {
  position: fixed;
  bottom: 20px; left: 50%;
  transform: translateX(-50%) translateY(20px);
  background: #1a1a2e;
  color: #7dd8a8;
  font-family: 'Martian Mono', 'Courier New', monospace;
  font-size: 12px;
  padding: 9px 18px;
  border: 1px solid #7dd8a8;
  opacity: 0;
  pointer-events: none;
  transition: opacity .3s ease, transform .3s ease;
  z-index: 10000;
}
#sc-share-note.sc-share-show {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

.sc-synth-knobs {
  display: flex;
  justify-content: center;
  gap: 16px;
}
.sc-knob-wrap {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
}
.sc-knob-wrap span { font-size: 8px; color: var(--line); }
/* 11 cases × 3px : le SVG (voir knobHtml) est dessiné en unités de case,
   crispEdges garde chaque case nette. */
.sc-knob {
  width: 33px; height: 33px;
  cursor: ns-resize;
  position: relative;
  touch-action: none;
}
.sc-knob svg { display: block; width: 100%; height: 100%; }
.sc-knob .pk-disc { fill: var(--surface); }
.sc-knob .pk-ring, .sc-knob .pk-needle { fill: var(--line); }
.sc-knob:hover .pk-ring { fill: var(--hot); }

/* Module TEMPO : lecture/écriture du BPM au chiffre */
.sc-bpm-row {
  display: flex; align-items: center; justify-content: center;
  gap: 6px; margin-top: 9px;
}
.sc-bpm-row input {
  width: 30px;
  margin: var(--px);
  padding: 4px 0 3px;
  background: var(--surface); color: var(--line);
  border: none; border-radius: 0;
  box-shadow: var(--px-border);
  font-family: var(--pixfont); font-size: 8px;
  text-align: center;
  -moz-appearance: textfield;
}
.sc-bpm-row input::-webkit-inner-spin-button,
.sc-bpm-row input::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
.sc-bpm-row input:focus { outline: none; background: var(--line); color: var(--surface); }
.sc-bpm-row span { font-size: 8px; color: var(--line-2); }

/* Masquer le synthé sur mobile (le jouet est desktop) */
@media (max-width:768px) { .sc-module, .sc-jackbar { display: none !important; } }

/* ── Multijoueur : curseurs des autres joueurs ──
   Enfants de #sc-canvas pour hériter gratuitement du pan/zoom (même logique
   que les blocs) ; jamais interactifs. */
/* ── Curseurs des autres joueurs ──
   Les éléments vivent DANS #sc-canvas, donc ils subissent le zoom : on annule
   ce facteur (--sp-zoom, posé par applyView) pour qu'un curseur reste lisible
   à 40% comme à 250%. La transition sur left/top fait glisser le curseur entre
   deux synchros (150ms) au lieu de le faire sauter de position en position. */
.sp-cursor {
  position: absolute;
  pointer-events: none;
  z-index: 9500;
  transform-origin: 0 0;
  transform: scale(calc(1 / var(--sp-zoom, 1))) translate(-3px, -3px);
  transition: left .15s linear, top .15s linear;
}
.sp-cursor-arrow {
  display: block;
  filter: drop-shadow(0 0 5px var(--sp-color, #fff)) drop-shadow(0 2px 3px rgba(0,0,0,.6));
}
.sp-cursor-arrow path {
  fill: var(--sp-color, #fff);
  stroke: #0b0b0d;
  stroke-width: 1.6;
  stroke-linejoin: round;
}
.sp-cursor-label {
  display: inline-block;
  margin: -2px 0 0 14px;
  padding: 3px 8px;
  border-radius: 10px;
  background: var(--sp-color, #fff);
  color: #0b0b0d;
  font-family: 'Martian Mono', 'Courier New', monospace;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .04em;
  white-space: nowrap;
  box-shadow: 0 2px 6px rgba(0,0,0,.55);
}

/* ── Bulle de tchat éphémère, ancrée au-dessus du curseur ── */
.sp-cursor-bubble, .sp-self-bubble {
  padding: 7px 11px;
  border-radius: 12px;
  background: #f4f1e8;
  color: #1a1a1e;
  border: 2px solid var(--sp-color, #fff);
  font-family: 'Martian Mono', 'Courier New', monospace;
  font-size: 11px;
  line-height: 1.35;
  max-width: 220px;
  word-wrap: break-word;
  box-shadow: 0 4px 14px rgba(0,0,0,.5);
}
.sp-cursor-bubble {
  position: absolute;
  left: 12px; bottom: 100%;
  margin-bottom: 8px;
  /* Sans width:max-content, une boîte absolue se réduit à la largeur de son
     parent (.sp-cursor ≈ la largeur du pseudo) et le texte s'émiette sur
     une lettre ou deux par ligne. */
  width: max-content;
  opacity: 0;
  transform: translateY(5px) scale(.95);
  transform-origin: 0 100%;
  transition: opacity .18s ease, transform .18s ease;
}
.sp-cursor-bubble.on { opacity: 1; transform: none; }
/* Curseur près du bord droit : la bulle bascule de l'autre côté, sinon elle
   sort de l'écran et le message est illisible (posé par renderRemoteCursors,
   qui seul peut mesurer le débordement). */
.sp-cursor-bubble.flip { left: auto; right: 12px; transform-origin: 100% 100%; }
.sp-cursor-bubble.flip::after { left: auto; right: 12px; }
/* Queue de la bulle, pointée vers le curseur */
.sp-cursor-bubble::after {
  content: '';
  position: absolute;
  left: 12px; top: 100%;
  border: 7px solid transparent;
  border-top-color: var(--sp-color, #fff);
  border-bottom: 0;
}

/* Saisie du message : suit ta propre souris, en coordonnées écran */
.sp-self-bubble {
  position: fixed;
  z-index: 10050;
  pointer-events: none;
  transform: translate(14px, -130%);
}
.sp-chat-input {
  background: transparent;
  border: none;
  outline: none;
  color: #1a1a1e;
  font-family: inherit;
  font-size: 11px;
  width: 190px;
  pointer-events: auto;
}
.sp-chat-input::placeholder { color: #8a8578; }
