/* The controllers on the floor under the console (UI-SPEC.md §17): one per port, drawn as a wireframe like the
   console (the SVG in pad-template, 600 × 310 units, without any maker's marks), with a button over each
   control showing the key or gamepad control that plays it. While something plays as a player, a plug sits
   in its port and a cable runs from it down the page to the controller. Places on the drawing are fractions
   of it. Loaded after console-bar.css. */

/* ---------------------------------------------------------------- the plug in a port, and the cables */

/* The plug covers the port's opening. Its cable comes out of the boot at its centre, towards you: the cable
   starts there and lies in front of the plug (.cables-front), the boot over its end. */
.ps2bar .bar-port .plug {
  position: absolute;
  inset: -14% -3%;
  border: 1px solid #8a847b;
  border-radius: 9px / 50%;
  background: linear-gradient(180deg, #2f2d2a, #1f1e1c);
  opacity: 0;
  translate: 0 40%;
  pointer-events: none;
}

/* The boot, over the cable's end: its own element, so that it sits above the cable while the plug lies below. */
.ps2bar .bar-port .plug-boot {
  position: absolute;
  z-index: 1;
  left: 50%;
  top: 50%;
  width: 13px;
  height: 13px;
  margin: -6.5px 0 0 -6.5px;
  border: 1px solid #8a847b;
  border-radius: 50%;
  background: #2a2825;
  opacity: 0;
  translate: 0 40%;
  pointer-events: none;
}

.ps2bar .bar-port[data-plugged="true"] :is(.plug, .plug-boot) {
  opacity: 1;
  translate: 0 0;
}

/* Plugging in: the cable comes up from the controller to the port (600 ms), then the plug goes in. Pulling out:
   the plug comes out, then the cable slides back down to the controller. Nothing moves at load (.live comes
   after the first drawing). */
.ps2bar.live .bar-port :is(.plug, .plug-boot) {
  transition: opacity 180ms var(--ease-in) 80ms, translate 260ms var(--ease-in);
}

.ps2bar.live .bar-port[data-plugged="true"] :is(.plug, .plug-boot) {
  transition: opacity 120ms var(--ease-out) 540ms, translate 380ms cubic-bezier(0.3, 0, 0.15, 1) 540ms;
}

/* Behind everything on the page (z-index -1, under the console's face, the drawers and the remote), above the
   floor. cable-worker.js lays each rope from its port to its controller, in page coordinates. */
.cables {
  position: absolute;
  left: 0;
  top: 0;
  width: 1px;
  height: 1px;
  overflow: visible;
  z-index: -1;
  pointer-events: none;
  transition: opacity var(--d-chrome-show) var(--ease-out);
}

/* Laid out for an older layout (the window was resized): hidden until the current layout's cables come. */
.cables.stale {
  opacity: 0;
  transition: opacity 80ms linear;
}

/* The copy in front, clipped to the console's face: over the plug, under the boot and the remote. */
.cables-front {
  z-index: 0;
}

/* Each path is 1 long (pathLength): a dash as long as it, moved along it, draws it from the controller's end. */
.cables path {
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: 1 1;
  stroke-dashoffset: -1;
  opacity: 0;
}

.cables path[data-on="true"] {
  stroke-dashoffset: 0;
  opacity: 1;
}

.cables.live path {
  transition: stroke-dashoffset 520ms var(--ease-in) 200ms, opacity 0s 720ms;
}

.cables.live path[data-on="true"] {
  transition: stroke-dashoffset 600ms var(--ease-out), opacity 0s;
}

.cables path:not([d]),
.cables path[d=""] {
  opacity: 0;
}

.cable-wall {
  stroke: #6f6a63;
  stroke-width: 5;
}

.cable-core {
  stroke: #2a2825;
  stroke-width: 3;
}

body[data-chrome="hidden"] .cables {
  opacity: 0;
  transition: opacity var(--d-chrome-hide) var(--ease-in);
}

/* ---------------------------------------------------------------- the controllers */

.pads {
  width: min(100% - 2 * var(--gutter), 1080px);
  margin: 0 auto;
  /* The floor above the controllers holds the cables' loops. */
  padding: 128px 0 80px;
}

.pads-title {
  margin: 0 0 12px;
}

.pads-row {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 40px 56px;
}

@media (max-width: 719px) {
  /* One controller under the other: the first cable has the second's way round to make up, in its loops. */
  .pads {
    padding-top: 240px;
  }

  .pads-row {
    grid-template-columns: minmax(0, 520px);
    justify-content: center;
  }
}

.pad-unit {
  min-width: 0;
}

.pad-art {
  position: relative;
  aspect-ratio: 600 / 310;
  container-type: inline-size;
}

.pad-svg {
  display: block;
  width: 100%;
  height: 100%;
  overflow: visible;
  transition: opacity 240ms var(--ease-out);
}

.pad-svg * {
  vector-effect: non-scaling-stroke;
  stroke-width: 1;
}

/* One line colour over one fill, like a line drawing. Where shapes merge into one outline (the wings and the
   sticks' housings, the plus-shaped plates), they are drawn 2 px wide (.p-shell), then filled over (.p-body,
   .p-plate), so that half of the line shows, outside. */
.pad-svg .p-shell { fill: #6f6a63; stroke: #6f6a63; stroke-width: 2; }
.p-body,
.p-plate { fill: #151413; stroke: none; }
.p-sh,
.p-part,
.p-relief,
.p-key,
.p-stick { fill: #151413; stroke: #6f6a63; }
.p-line { fill: none; stroke: #6f6a63; }
.p-stick { stroke: #8a847b; }
.p-lead { fill: none; stroke: #4a4743; stroke-dasharray: 2 3; }

.p-name {
  font-family: var(--sans);
  stroke: none;
}

.p-name { fill: #77726b; font-size: 12px; font-weight: 560; letter-spacing: 0.04em; }
.p-name-l { text-anchor: end; }

/* Nothing plays as this player: the controller lies there, unplugged. */
.pad-unit[data-plugged="false"] .pad-svg {
  opacity: 0.4;
}

.pad-unit[data-plugged="false"] .pad-spots {
  display: none;
}

/* A control: its centre, width and height (--x, --y, --w, --h) in the drawing's units. Wider when what plays it
   needs more room ("Bksp"). */
.pad-spot {
  position: absolute;
  left: calc(var(--x) / 6 * 1%);
  top: calc(var(--y) / 3.1 * 1%);
  min-width: calc(var(--w) / 6 * 1%);
  height: calc(var(--h) / 3.1 * 1%);
  translate: -50% -50%;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0;
  padding: 0 2px;
  border: 0;
  border-radius: 4px;
  background: transparent;
  color: var(--ink);
  font-family: var(--mono);
  font-size: clamp(8px, 2.2cqw, 13px);
  font-weight: 500;
  line-height: 1;
  cursor: pointer;
  transition: background-color var(--d-line) var(--ease-out), color var(--d-line) var(--ease-out);
}

.pad-spot.round {
  border-radius: 50%;
}

/* The shoulder buttons' labels, at the end of their lines. */
.pad-spot.lead {
  border: 1px solid #6f6a63;
  background: #1a1917;
}

.pad-spot kbd {
  font: inherit;
  white-space: nowrap;
}

.pad-spot .icon {
  width: 1.1em;
  height: 1.1em;
}

.pad-spot.unbound {
  color: var(--ink-3);
}

.pad-spot:hover {
  background: rgb(236 232 225 / 0.1);
}

.pad-spot:focus-visible {
  outline: 2px solid var(--amber);
  outline-offset: 2px;
}

/* Waiting for the key, or the gamepad's control, that will play it. */
.pad-spot.listening {
  outline: 2px solid var(--amber);
  outline-offset: 2px;
  color: var(--amber);
  animation: pad-listen 1s steps(2, jump-none) infinite;
}

@keyframes pad-listen {
  50% {
    outline-color: transparent;
  }
}

/* Pressed now, on the keyboard or the gamepad. */
.pad-spot:has(kbd.down),
.pad-spot.down {
  background: var(--amber);
  color: var(--amber-ink);
  transition: none;
}

.pad-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0 20px;
  margin-top: 8px;
}

.pad-title {
  margin: 0;
  font-size: 15px;
  line-height: 24px;
  font-weight: 600;
}

.pad-dev {
  margin: 0;
  padding: 0;
  border: 0;
  min-inline-size: 0;
}

.pad-dev-list {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0 16px;
}

.pad-dev .check input:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
}

.pad-rumble input:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
}

.pad-rumble {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0 12px;
}

.pad-rumble[hidden] {
  display: none;
}

.pad-dev-hint {
  font-size: 13px;
  color: var(--ink-3);
}

.pad-status,
.pad-also {
  margin: 2px 0 0;
  font-size: 13px;
  line-height: 18px;
  color: var(--ink-2);
}

.pad-also {
  color: var(--ink-3);
}

.pad-also:empty {
  display: none;
}

.pad-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0 8px;
  margin: 4px 0 0 -12px;
}

/* ---------------------------------------------------------------- the cable tuner (?tune-cables) */

/* A tool for the owner, not part of the player: sliders for how the cables lie (app.js, buildCableTuner). */
.cable-tuner {
  position: fixed;
  right: 12px;
  bottom: 12px;
  z-index: 50;
  width: min(360px, calc(100vw - 24px));
  max-height: calc(100dvh - 24px);
  overflow: auto;
  padding: 8px 12px 12px;
  border: 1px solid var(--line-2);
  border-radius: 6px;
  background: var(--slate);
  font-size: 12px;
  line-height: 16px;
  color: var(--ink-2);
}

.cable-tuner summary {
  cursor: pointer;
  font-size: 13px;
  font-weight: 600;
  color: var(--ink);
}

.cable-tuner-note {
  margin: 6px 0 8px;
}

.cable-tuner-row {
  display: grid;
  grid-template-columns: 1fr 120px 52px;
  align-items: center;
  gap: 8px;
  min-height: 26px;
}

.cable-tuner-row input {
  width: 100%;
  margin: 0;
  accent-color: var(--amber);
}

.cable-tuner-row input[type="number"] {
  padding: 2px 4px;
  border: 1px solid var(--line-2);
  border-radius: 3px;
  background: var(--house);
  color: var(--ink);
  font: inherit;
}

.cable-tuner-row output {
  font-family: var(--mono);
  text-align: right;
  color: var(--ink);
}

.cable-tuner-row .btn-quiet {
  min-height: 26px;
  padding: 0 6px;
}

.cable-tuner-actions {
  display: flex;
  gap: 4px;
  margin: 8px 0 6px -12px;
}

.cable-tuner-out {
  width: 100%;
  resize: vertical;
  border: 1px solid var(--line-2);
  border-radius: 3px;
  background: var(--house);
  color: var(--ink-2);
  font: 11px/15px var(--mono);
}

@media (prefers-reduced-motion: reduce) {
  .ps2bar.live .bar-port :is(.plug, .plug-boot),
  .ps2bar.live .bar-port[data-plugged="true"] :is(.plug, .plug-boot),
  .cables,
  .cables.live path,
  .cables.live path[data-on="true"],
  .pad-svg,
  .pad-spot {
    transition: none;
  }

  .pad-spot.listening {
    animation: none;
  }
}

@media (forced-colors: active) {
  .pad-spot:has(kbd.down),
  .pad-spot.down {
    forced-color-adjust: none;
    background: Highlight;
    color: HighlightText;
  }
}
