/* The harmonic grid itself. */

.grid-scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow: auto;
  padding: 8px;
  border-radius: var(--radius);
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.012), transparent 40%), var(--panel);
  border: 1px solid var(--line-soft);
  box-shadow: var(--shadow-1);
  overscroll-behavior: contain;
}

/* The grid fills the stage when it can and overflows when it cannot: the
   `minmax(min, 1fr)` tracks stretch to the container, and the minimums are the
   point at which a cell stops being tappable. Below that the scroller takes
   over, driven by the timing bar (horizontal) and the note bar (vertical). */
.grid {
  display: grid;
  grid-template-columns: 58px repeat(var(--steps, 16), minmax(var(--cell-min, 30px), 1fr));
  grid-template-rows: 20px repeat(var(--rows, 12), minmax(var(--row-min, 30px), 1fr));
  gap: 4px;
  min-height: 100%;
  min-width: 100%;
  /* Panning is allowed here so the strips can scroll the container. Cells
     override this with `touch-action: none`, so painting never scrolls. */
  touch-action: pan-x pan-y;
  user-select: none;
  -webkit-user-select: none;
}

.grid-corner {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 8px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--dim);
  font-weight: 800;
  touch-action: pan-x pan-y;
  cursor: move;
}

/* The timing bar: drag it to scroll the grid sideways. */
.step-head {
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 4px;
  font-family: var(--mono);
  font-size: 9px;
  color: var(--dim);
  touch-action: pan-x;
  cursor: ew-resize;
  transition: background var(--fast) var(--ease), color var(--fast) var(--ease);
}

.step-head.beat {
  color: var(--muted);
  background: rgba(255, 255, 255, 0.025);
}

.step-head.is-playing {
  color: var(--accent-ink);
  background: var(--accent);
  box-shadow: 0 0 12px var(--accent-line);
}

/* The note bar: drag it to scroll the grid up and down. */
.row-label {
  position: sticky;
  left: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 4px;
  padding: 0 7px;
  border-radius: 6px;
  background: #141821;
  border: 1px solid transparent;
  overflow: hidden;
  touch-action: pan-y;
  cursor: ns-resize;
}

.row-note {
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 700;
  color: var(--text-2);
  white-space: nowrap;
}

.row-deg {
  font-size: 8px;
  color: var(--dim);
  font-weight: 700;
  white-space: nowrap;
}

.row-label.root {
  background: var(--panel-2);
  border-color: var(--accent-line);
}

.row-label.root .row-note {
  color: var(--accent-hi);
}

.cell {
  position: relative;
  border-radius: 7px;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.045), rgba(255, 255, 255, 0.012));
  border: 1px solid rgba(255, 255, 255, 0.05);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03);
  touch-action: none;
  transition: background var(--fast) var(--ease), box-shadow var(--fast) var(--ease),
    border-color var(--fast) var(--ease), transform 60ms var(--ease);
}

.cell.beat {
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.07), rgba(255, 255, 255, 0.02));
}

.cell.root {
  border-color: var(--accent-line);
}

.cell:hover {
  border-color: rgba(255, 255, 255, 0.16);
}

.cell.on {
  background: linear-gradient(180deg, var(--accent-hi), var(--accent-lo));
  border-color: var(--accent-line);
  box-shadow:
    0 0 0 1px var(--accent-line),
    0 0 16px var(--accent-soft),
    inset 0 1px 0 rgba(255, 255, 255, 0.4);
}

.cell.on::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: radial-gradient(60% 60% at 50% 28%, rgba(255, 255, 255, 0.55), transparent 70%);
  opacity: 0.45;
  pointer-events: none;
}

.cell.is-playing {
  box-shadow: inset 0 0 0 1px var(--accent-2-line);
}

.cell.on.is-playing {
  box-shadow:
    0 0 0 1px var(--accent-2-line),
    0 0 22px var(--accent-2-glow),
    inset 0 1px 0 rgba(255, 255, 255, 0.4);
}

.cell.flash {
  animation: cell-flash 200ms var(--ease);
}

/* A note that is actually sounding right now. Driven by the scheduler so the
   grid shows what the active patch is playing, not just what is painted. */
.cell.is-sounding {
  background: linear-gradient(180deg, var(--accent-2), var(--accent-2-soft));
  border-color: var(--accent-2-line);
  box-shadow:
    0 0 0 1px var(--accent-2-line),
    0 0 18px var(--accent-2-glow),
    inset 0 1px 0 rgba(255, 255, 255, 0.35);
}

.cell.on.is-sounding {
  filter: brightness(1.25);
}

.row-label.is-sounding {
  border-color: var(--accent-2-line);
  box-shadow: 0 0 12px var(--accent-2-soft);
}

.row-label.is-sounding .row-note {
  color: var(--accent-2);
}

@keyframes cell-flash {
  0% {
    transform: scale(0.94);
    filter: brightness(1.5);
  }
  100% {
    transform: scale(1);
    filter: brightness(1);
  }
}

/* Live mode gets a different cursor affordance. */
.grid.is-live .cell {
  cursor: pointer;
}

.grid.is-live .cell:hover {
  background: linear-gradient(180deg, var(--accent-2-soft), transparent);
  border-color: var(--accent-2-line);
}

@media (max-width: 860px) {
  .grid {
    --cell-min: 22px;
    --row-min: 22px;
    grid-template-columns: 44px repeat(var(--steps, 16), minmax(var(--cell-min), 1fr));
    grid-template-rows: 22px repeat(var(--rows, 12), minmax(var(--row-min), 1fr));
    gap: 2px;
  }

  .row-label {
    padding: 0 5px;
  }

  .row-deg {
    display: none;
  }

  .grid-scroll {
    padding: 4px;
  }
}

/* ------------------------------------------------------- playable pad grid */

/* The play surface is edge-to-edge: no padding, no gaps, no labels. Every
   pixel inside the panel is a pad, and the 1px grid line is drawn inside the
   hit area so there is no dead zone between notes. */

.play-scroll {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;
  border-radius: var(--radius);
  background: var(--panel);
  border: 1px solid var(--line-soft);
  box-shadow: var(--shadow-1);
  overscroll-behavior: contain;
}

.play-stage {
  position: relative;
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100%;
}

.play-grid {
  flex: 1 1 auto;
  min-height: 0;
  display: grid;
  grid-template-columns: repeat(var(--cols, 7), minmax(0, 1fr));
  grid-template-rows: repeat(var(--rows, 4), minmax(0, 1fr));
  gap: 0;
  width: 100%;
  height: 100%;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
}

.play-cell {
  position: relative;
  display: grid;
  place-items: center;
  min-width: 0;
  min-height: 0;
  overflow: hidden;
  border: 0;
  border-radius: 0;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.045), rgba(255, 255, 255, 0.012));
  /* 1px line inside the hit area: visible grid, no dead zone. */
  box-shadow: inset -1px -1px 0 rgba(255, 255, 255, 0.1);
  touch-action: none;
  container-type: size;
  transition: background var(--fast) var(--ease), box-shadow var(--fast) var(--ease);
}

/* The note name is the only label, and it scales with the pad. */
.play-cell .note {
  font-family: var(--mono);
  font-size: 14px;
  font-size: clamp(9px, 24cqmin, 30px);
  font-weight: 700;
  line-height: 1;
  color: var(--text-2);
  pointer-events: none;
  user-select: none;
  -webkit-user-select: none;
}

.play-cell.root {
  background: linear-gradient(180deg, var(--accent-soft), transparent);
  box-shadow: inset -1px -1px 0 var(--accent-line);
}

.play-cell.root .note {
  color: var(--accent-hi);
}

.play-cell:hover {
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.08), rgba(255, 255, 255, 0.03));
}

.play-cell.is-down {
  background: linear-gradient(180deg, var(--accent-hi), var(--accent-lo));
  box-shadow:
    inset 0 0 0 1px var(--accent-line),
    inset 0 0 30px rgba(255, 255, 255, 0.25);
}

.play-cell.is-down .note {
  color: var(--accent-ink);
}

.play-cell.is-selected {
  box-shadow:
    inset 0 0 0 2px var(--accent-2),
    inset 0 0 24px var(--accent-2-soft);
}

.play-grid.is-editing .play-cell {
  cursor: crosshair;
}

.play-grid.is-editing .play-cell:hover {
  background: var(--accent-2-soft);
}
