/* ==========================================================================
   Synth Controls Library
   Knobs, switches, and sliders for patch editors
   ========================================================================== */

/* --- Knob (rotary potentiometer) --- */

.knob {
  position: relative;
  display: inline-block;
  cursor: grab;
}

.knob:active {
  cursor: grabbing;
}

.knob__inner {
  border-radius: 50%;
}

.knob__inner svg {
  width: 100%;
  height: 100%;
}

.knob--a .knob__inner {
  width: 75px;
  height: 75px;
}

.knob--b .knob__inner {
  width: 80px;
  height: 80px;
}

.knob--c .knob__inner {
  width: 98px;
  height: 98px;
}

/* --- Switch (multi-position toggle) --- */

.switch {
  position: relative;
  display: inline-block;
  cursor: pointer;
}

.switch__inner {
  background-repeat: no-repeat;
  overflow: hidden;
}

/* Round switch: SVG inline rendering */
.switch--round .switch__inner {
  width: 120px;
  height: 120px;
}

.switch--round .switch__inner svg {
  width: 100%;
  height: 100%;
}

/* Toggle switch: 64x64, SVG inline rendering */
.switch--toggle .switch__inner {
  width: 64px;
  height: 64px;
}

.switch--toggle .switch__inner svg {
  width: 100%;
  height: 100%;
}

/* Toggle frames: show/hide based on data-value. The `.switch__inner` prefix
   raises specificity above `.placed-component svg { display:block }` (used in the
   rack), which would otherwise force every frame visible. */
.switch__inner .switch__toggle-frame { display: none; }
.switch__inner[data-value="0"] .switch__toggle-frame--0 { display: block; }
.switch__inner[data-value="1"] .switch__toggle-frame--1 { display: block; }

/* Round switch frames: show/hide based on data-value (same specificity note). */
.switch__inner .switch__round-frame { display: none; }
.switch__inner[data-value="0"] .switch__round-frame--0 { display: block; }
.switch__inner[data-value="1"] .switch__round-frame--1 { display: block; }
.switch__inner[data-value="2"] .switch__round-frame--2 { display: block; }

/* Flat lever (Michigan SY-1): same mechanism, one frame per position. The
   plate is part of the drawing, so the frame fills its box rather than keeping
   a square ratio. */
.switch--lever .switch__inner svg {
  width: 100%;
  height: 100%;
}
.switch__inner .switch__lever-frame { display: none; }
.switch__inner[data-value="0"] .switch__lever-frame--0 { display: block; }
.switch__inner[data-value="1"] .switch__lever-frame--1 { display: block; }
.switch__inner[data-value="2"] .switch__lever-frame--2 { display: block; }

/* --- LED button (small clickable indicator with glow when ON) --- */

.led-button {
  position: relative;
  display: block;
  cursor: pointer;
}

.led-button__inner {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.led-button__inner svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
}

.led-button__frame { display: none; }
.led-button__inner[data-value="0"] .led-button__frame--0 { display: block; }
.led-button__inner[data-value="1"] .led-button__frame--1 { display: block; }
/* A third state, for a lamp that reports more than on and off: the Labyrinth's
   sequencer bits are unlit, armed, or under the play head. */
.led-button__inner[data-value="2"] .led-button__frame--2 { display: block; }

/* --- Jack socket --- */

.jack {
  display: inline-block;
  width: 34px;
  height: 34px;
}

.jack svg {
  width: 100%;
  height: 100%;
}

/* --- Jack point anchor (SVG circle for CableManager) --- */

@keyframes jack-blink {
  0%, 100% { stroke-opacity: 1; }
  50% { stroke-opacity: 0.3; }
}

.jack-point {
  cursor: pointer;
}

.jack-point--active {
  animation: jack-blink 0.8s ease-in-out infinite;
}

/* --- Interactive controls override panel scroll grab cursor --- */

.switch,
.switch__inner,
.jack,
.led-button,
.led-button__inner {
  cursor: pointer;
}

.switch--toggle,
.switch--toggle .switch__inner {
  cursor: pointer;
}

/* --- Slider (vertical fader) --- */

.slider {
  position: relative;
  width: 70px;
  height: 243px;
  display: inline-block;
  cursor: grab;
  /* Track groove */
  background: linear-gradient(
    to right,
    transparent 30px,
    #555 30px,
    #555 32px,
    #333 32px,
    #333 38px,
    #555 38px,
    #555 40px,
    transparent 40px
  );
}

.slider:active {
  cursor: grabbing;
}

/* Verbos-style slot fader: a thin black vertical slot (the "fente") the oval
   handle slides in. The slot is a centred pill with rounded ends (top/bottom),
   drawn as a ::before so only the slot is rounded, not the whole box. */
.slider--slot {
  background: none;
  position: relative;
}
.slider--slot::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: 24%;
  transform: translateX(-50%);
  background: #0a0a0a;
  border-radius: 999px;
}
/* The handle is a compact vertical oval, narrower than the mixer cap. */
.slider--slot .slider__inner {
  width: 14px;
  height: 20px;
  left: 50%;
  transform: translateX(-50%);
}
/* Keep the slot handle compact even when placed (overrides the generic
   .placed-component .slider__inner { width/height: 100% !important }). */
.placed-component .slider--slot .slider__inner {
  width: 45% !important;
  height: auto !important;
  aspect-ratio: 20 / 28;
  left: 50%;
  transform: translateX(-50%);
}

/* Michigan SY-1 fader. Its stem is a part bolted through the panel, not a
   printed track, so the panel template draws it and the component contributes
   only the cap — deeper than the mixer one, at the proportions measured on the
   instrument. */
.slider--syncussion {
  background: none;
}
.slider-handle-only .slider--syncussion .slider__inner {
  width: 100%;
  left: 0;
  aspect-ratio: 75 / 56;
  height: auto;
}

/* Handle-only variant — no track background, handle scales to its container at ~90% width with native ratio */
.slider-handle-only .slider {
  background: none;
  width: 100%;
  height: 100%;
  cursor: default;
}
.slider-handle-only .slider__inner {
  width: 90%;
  left: 5%;
  aspect-ratio: 70 / 28;
  height: auto;
  cursor: grab;
}
.slider-handle-only .slider__inner:active {
  cursor: grabbing;
}

.slider__inner {
  display: block;
  width: 70px;
  height: 28px;
  position: absolute;
  bottom: 0;
  left: 0;
}

.slider__inner svg {
  width: 100%;
  height: 100%;
}

/* Force every component's inner SVG to fill its foreignObject box, so the
   drawing matches its mm footprint instead of rendering at its intrinsic size
   (which made components overflow / be mis-cropped). */
.placed-component > div {
  display: block;
}

.placed-component svg {
  width: 100%;
  height: 100%;
  display: block;
}

/* On a module panel, every control must fill its box. The rules above give
   Knob/Slider/Switch fixed px sizes (for the Pulsar/Matriarch panels) — override
   them here only, scoped, so we don't break those panels. */
.placed-component .knob,
.placed-component .knob__inner,
.placed-component .slider,
.placed-component .slider__inner,
.placed-component .switch,
.placed-component .switch__inner,
.placed-component .jack,
.placed-component .led,
.placed-component .trimmer,
.placed-component .button,
.placed-component .xlr-socket,
.placed-component .bnc-socket {
  width: 100% !important;
  height: 100% !important;
  /* block (not inline-block) so no baseline gap pushes the SVG down when the
     box is resized — this is what made the switch float/clip out of its box. */
  display: block !important;
}

/* ===== INTERFACE — TOKENS ONLY BELOW =====
   Everything above this line draws physical matter: a slider's slot, a knob's
   body, a jack's ring. Those colours belong to the object and are exempt.
   Everything below is interface, and must name no colour of its own — only
   tokens. The colour-literal spec reads this marker and scans only what follows.

   Most of what used to sit here was the panel editor's chrome: selection
   outline, palette, properties panel, zone and text modes, marquee. It went with
   the editor. */

/* In a rack, a placed module must fill its row box exactly. The shared thumbnail
   wrapper is inline-block sized to the SVG's intrinsic height, which left a ~2px
   gap; force the wrapper and its SVG to 100% of the placement box. The thumbnail
   SVG's own border is dropped here (it double-framed against the row border and
   made modules look like they didn't fill the height). */
.placed-module .module-thumbnail,
.placed-module .module-thumbnail > svg {
  width: 100%;
  height: 100%;
  display: block;
}

.placed-module .module-thumbnail > svg {
  border: none !important;
  border-radius: 0 !important;
}
