/*
 * app.css — the M04 front panel: the header, the transport strip, the step grid, the
 * MIXER, the Timing Lab, the PATTERN BAY, the SONG BAY, the PROJECT BAY, the tour
 * chapter picker and the manual modal. base.css owns the tokens and the reusable
 * control shapes; everything here is layout and the pieces specific to this
 * milestone. Later milestones append to this file, they do not rewrite it.
 *
 * M03 added one panel and moved nothing. The grid gained a cursor state and a silenced
 * state on its rows; everything else was exactly as M02 left it, which is why eight
 * tracks appearing in the rack cost this file four lines.
 *
 * M04 appends four blocks and still moves nothing — see "patterns, song and project"
 * below. Two of them are worth knowing about before you read them:
 *
 *   .patbar is `repeat(auto-fit, minmax(54px, 1fr))` rather than sixteen fixed
 *   columns, and that is not taste. Sixteen fixed pads overflow the panel on a
 *   1366 x 768 laptop, an overflowing panel pushes the whole page sideways, and gate
 *   assertion 9 is exactly that check: scrollWidth must not exceed clientWidth. The
 *   bar wraps to two rows instead, and nothing else on the page moves.
 *
 *   .tourpicker is position:fixed at --z-modal because the tour SPOTLIGHTS it: it has
 *   to sit inside the hole the spotlight cuts rather than under the dim. It is a
 *   panel and not a modal — DM.Manual owns the only focus trap in DRUMLAB, and a
 *   second one would fight it into an infinite focus loop.
 */

.app {
  max-width: 1240px;
  margin: 0 auto;
  padding: 18px 20px 26px;
  display: flex;
  flex-direction: column;
  gap: var(--gap);
}

/* ------------------------------------------------------------------ header */

.topbar {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 12px 16px;
}

.brand { display: flex; align-items: center; gap: 9px; }

/* The lit power lamp: the one place the accent colour is allowed to just sit there. */
.brand__mark {
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, #ffb199 0%, var(--accent) 55%, #7a1c0c 100%);
  box-shadow: 0 0 12px rgba(255, 90, 60, .65);
}

.brand__name {
  font: 700 13px/1 var(--font);
  letter-spacing: .28em;
  color: var(--muted);
}

.topbar__title {
  font: 600 17px/1 var(--font-ui);
  letter-spacing: .01em;
  padding-left: 14px;
  border-left: 1px solid var(--edge);
}

.topbar__progress {
  padding: 4px 9px;
  border: 1px solid var(--edge);
  border-radius: 999px;
  font: 11px/1 var(--font);
  color: var(--muted);
}

.topbar__actions { margin-left: auto; display: flex; gap: 8px; }

/* --------------------------------------------------------------- transport */

.transport {
  display: flex;
  align-items: stretch;
  gap: 18px;
  padding: 12px 16px;
  flex-wrap: wrap;
}

.unit { display: flex; flex-direction: column; gap: 7px; }
.unit + .unit { padding-left: 18px; border-left: 1px solid var(--edge); }
.unit__body { display: flex; align-items: center; gap: 8px; }
.unit--tempo { flex: 1 1 300px; min-width: 280px; }
.unit--tempo .slider { flex: 1 1 auto; min-width: 110px; }
.unit--swing { flex: 1 1 240px; min-width: 220px; }
.unit--swing .slider { flex: 1 1 auto; min-width: 96px; }

/* TAP is a momentary button, so it is short and square-ish rather than a label with
   a verb on it — you hit it in time with the music, you do not read it. */
.btn--tap {
  padding: 9px 12px;
  font: 700 12px/1 var(--font);
  letter-spacing: .12em;
}

/* Label beside the field instead of above it: "Steps 16" reads as one control. */
.field--inline { flex-direction: row; align-items: center; gap: 8px; }
.field__input--tiny { width: 58px; text-align: center; }

/* Swing off is not a fault, so the readout only lights up once it is engaged. */
.lcd__value.is-engaged { color: var(--warn); }

/* Play latches: while the transport runs, the button reads as pressed-in. */
.btn--play.is-active {
  background: linear-gradient(180deg, #ff7a5f 0%, #d33c22 100%);
  border-color: #8f2a17;
  color: #140603;
  box-shadow: inset 0 2px 6px rgba(0, 0, 0, .45), 0 0 16px rgba(255, 90, 60, .35);
}
.btn--warn { border-color: rgba(255, 204, 68, .45); color: var(--warn); }

/* ------------------------------------------------------------- step grid */

.rack { padding: 12px 16px 16px; }

.rack__head {
  display: flex;
  align-items: baseline;
  gap: 12px;
  margin-bottom: 10px;
}
.rack__title {
  font: 600 12px/1 var(--font);
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--muted);
}
.rack__hint { font-size: 12px; color: var(--muted); }
.rack__hint strong { color: var(--text); font-weight: 600; }
/* The pattern bay's hint is rewritten from state (it says what a click will do RIGHT
   now), so its emphasis cannot be markup. The whole clause after the last separator is
   the answer, and it is the sentence's only job — so the line as a whole reads at full
   strength rather than one bold fragment inside a dim one. */
.patbay .rack__hint { color: var(--text); }

.grid { display: flex; flex-direction: column; gap: 6px; }

/*
 * One row = one track. The head is fixed width so every row's pads line up; the
 * pad strip is the flexible part and is the only thing allowed to scroll
 * horizontally on a narrow screen (min-width:0 is what makes that work inside a
 * flex row — without it the strip refuses to shrink and the PAGE scrolls instead).
 */
.row { display: flex; align-items: center; gap: 12px; }

.row__head {
  flex: 0 0 176px;
  min-width: 0;              /* without this a long name widens ONE row's head and
                                knocks that row's pads out of line with the others */
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 8px;
  background: rgba(0, 0, 0, .22);
  border: 1px solid var(--edge);
  border-radius: 8px;
}

.row__lamp {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--track-hue);
  box-shadow: 0 0 8px var(--track-hue);
  flex: 0 0 auto;
}

.row__name {
  font: 600 12px/1.2 var(--font-ui);
  flex: 1 1 auto;
  min-width: 0;              /* a flex item's default min-width is its content, so
                                text-overflow never fires until you say this */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.row__voice {
  font: 10px/1 var(--font);
  color: var(--muted);
  letter-spacing: .06em;
}

/* Audition: hear one voice on its own, without running the sequencer. */
.row__audition {
  flex: 0 0 auto;
  width: 24px;
  height: 24px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--edge);
  border-radius: 6px;
  background: rgba(255, 255, 255, .04);
  color: var(--muted);
  font-size: 9px;
  cursor: pointer;
}
.row__audition:hover { color: var(--track-hue); border-color: var(--track-hue); }

.row.is-selected .row__head { border-color: var(--track-hue); }

.row__steps,
.ruler__steps {
  flex: 1 1 auto;
  min-width: 0;
  display: grid;
  grid-template-columns: repeat(16, minmax(28px, 1fr));
  gap: 5px;
  overflow-x: auto;
  padding-bottom: 2px;
}

/*
 * The beat marker. Every fourth column gets a rule down the gap to its left, so the
 * eye can count in fours without reading the ruler. It is drawn as a pseudo-element
 * in the GAP rather than as a border on the pad, because a border would eat into the
 * pad's rounded corner and shift the column by a pixel. Column 1 is skipped: the
 * panel edge already marks the start of the bar.
 */
.cell.is-beat:not(:first-child)::before,
.ruler__tick.is-beat:not(:first-child)::before {
  content: '';
  position: absolute;
  left: -3px;
  top: -3px;
  bottom: -3px;
  border-left: 1px solid rgba(138, 144, 166, .6);
}
.ruler__tick { position: relative; }
.ruler__tick.is-beat { color: var(--text); }

/*
 * A pad. Off = unlit rubber. On = backlit in the track's hue. Playing = the
 * column under the playhead, which brightens whether or not the pad is lit, so a
 * silent step still shows you where the bar is.
 */
.cell {
  position: relative;
  height: 34px;
  padding: 0;
  border: 1px solid var(--edge);
  border-radius: 6px;
  background: linear-gradient(180deg, #232735 0%, #171a24 100%);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .05);
  cursor: pointer;
  transition: background-color .08s linear, box-shadow .08s linear;
}
.cell:hover { background: linear-gradient(180deg, #2c3143 0%, #1d212d 100%); }

.cell.on {
  background: var(--track-hue);
  border-color: var(--track-hue);
  box-shadow: 0 0 14px -2px var(--track-hue), inset 0 1px 0 rgba(255, 255, 255, .4);
}

/*
 * Accent. A brighter pad would be ambiguous next to the playhead's brightening, so
 * an accent also gets a hard white bar across its top edge: level is carried by the
 * glow, and the marker is what you actually scan for when you read a pattern.
 */
.cell.accent {
  box-shadow: 0 0 18px -1px var(--track-hue), inset 0 1px 0 rgba(255, 255, 255, .6);
  filter: brightness(1.18) saturate(1.08);
}
.cell.accent::after {
  content: '';
  position: absolute;
  left: 5px;
  right: 5px;
  top: 3px;
  height: 3px;
  border-radius: 2px;
  background: rgba(255, 255, 255, .92);
}

/*
 * Past the pattern length. The pad keeps its hit and its colour, it is simply never
 * reached — so it dims rather than clearing, and setting the length back to 16
 * brings the whole bar straight back.
 */
.cell.is-beyond,
.ruler__tick.is-beyond { opacity: .26; }
.cell.is-beyond { cursor: pointer; }

.cell.playing {
  border-color: var(--text);
  box-shadow: inset 0 0 0 1px var(--text);
}
.cell.on.playing {
  filter: brightness(1.45) saturate(1.1);
  box-shadow: 0 0 20px 1px var(--track-hue), inset 0 0 0 1px #fff;
}
.cell.on.accent.playing {
  filter: brightness(1.6) saturate(1.15);
  box-shadow: 0 0 26px 2px var(--track-hue), inset 0 0 0 1px #fff;
}

/* The ruler carries the step numbers and the same beat marks as the pads. */
.ruler { display: flex; align-items: center; gap: 12px; margin-bottom: 2px; }
.ruler__spacer { flex: 0 0 176px; }
.ruler__tick {
  height: 16px;
  display: flex;
  align-items: center;
  justify-content: center;
  font: 10px/1 var(--font);
  color: #565c72;
}
.ruler__tick.playing { color: var(--accent); }

/*
 * The step cursor (new in M03). Arrow keys move it and it takes DOM focus with it, so
 * Space then places a hit purely because the pad is a focused <button> — no key had
 * to be stolen from the transport. The dashed ring is what tells you the keyboard is
 * pointing here even when the pad is lit.
 */
.cell.is-cursor {
  outline: 2px dashed var(--accent-2);
  outline-offset: 1px;
}

/*
 * A row whose track cannot be heard right now — muted, or not soloed while another
 * track is. It is dimmed rather than hidden: you still need to edit a muted part.
 *
 * The dim is applied to the LABELS and the PADS, never to the containers holding
 * them. `opacity` composites the whole subtree, outline included, so dimming
 * `.row__head` would render the :focus-visible ring at 38 % as well — and on a pad
 * past the loop end the two would multiply to about 10 %, on exactly the row a
 * keyboard user is most likely to be working. The audition button keeps full
 * strength for the same reason: a silenced track is still one you can hear on its own.
 */
.row.is-silent .row__lamp,
.row.is-silent .row__name,
.row.is-silent .row__voice,
.row.is-silent .cell { opacity: .38; }

/* Past the loop end is already the dimmest a pad gets. Silencing the row must not
   multiply the two dims together into something unreadable. */
.row.is-silent .cell.is-beyond { opacity: .26; }

/* Whatever has keyboard focus comes back to full strength, so the ring is always
   drawn at the contrast base.css intended. */
.row.is-silent .cell:focus-visible { opacity: 1; }

/* ------------------------------------------------------------------ mixer */

.mixer { padding: 12px 16px 14px; }

/* The head carries the kit bank and the mix A/B beside the title, because both are
   "what the whole rack sounds like" controls rather than per-channel ones. */
.mixer .rack__head { flex-wrap: wrap; align-items: flex-end; row-gap: 10px; }
.kitbay { display: flex; flex-direction: column; gap: 6px; }
.kitbay:first-of-type { margin-left: auto; }

.strips {
  display: flex;
  flex-direction: column;
  gap: 6px;
  /* A mixer needs width. Below about 760px of usable panel the strips scroll
     sideways INSIDE this box rather than pushing the page wider — the same
     containment rule the step grid uses. */
  overflow-x: auto;
  padding-bottom: 2px;
}

/*
 * One channel. A grid rather than a flex row, because the whole point of a mixer is
 * that the eight faders line up: with flex, a longer track name would shove one
 * channel's fader out of column and the eye could no longer compare levels.
 *
 * id | voice knobs | pan | fader + readout | meter | mute/solo
 */
.strip {
  display: grid;
  /* id | voice knobs | pan | fader + readout | meter | mute/solo.
     The knob bay is FIXED at three knobs' worth even on a two-knob voice, so PAN
     sits in the same place on every channel and the eye can sweep the column. */
  grid-template-columns: 150px 152px 46px minmax(180px, 1fr) 116px auto;
  align-items: center;
  gap: 10px;
  min-width: 740px;
  padding: 5px 8px;
  background: rgba(0, 0, 0, .22);
  border: 1px solid var(--edge);
  border-left: 3px solid var(--track-hue);
  border-radius: 8px;
}

.strip.is-selected { background: rgba(255, 255, 255, .045); }

/*
 * Silenced by its own mute, or by somebody else's solo. Same dimming as the grid row
 * above it, so the two views never disagree about what you can hear.
 *
 * And the same rule about where the dim goes. `.strip.is-silent { opacity }` on the
 * container would fade the M and S buttons — including the M you have to find in
 * order to un-mute — and their focus rings with them, at the one moment you need
 * them most. So the dim lands on the parts that only report a value, the channel
 * buttons stay at full strength (their lit amber state already says "silenced"), and
 * anything holding keyboard focus comes back to 1.
 */
.strip.is-silent .strip__id,
.strip.is-silent .knob,
.strip.is-silent .strip__fader,
.strip.is-silent .meter { opacity: .42; }

.strip.is-silent .knob:focus-within,
.strip.is-silent .strip__fader:focus-within { opacity: 1; }

.strip__id { display: flex; align-items: center; gap: 8px; min-width: 0; }
.strip__lamp {
  width: 9px;
  height: 9px;
  flex: 0 0 auto;
  border-radius: 50%;
  background: var(--track-hue);
  box-shadow: 0 0 8px var(--track-hue);
}
.strip__name {
  font: 600 12px/1.2 var(--font-ui);
  flex: 1 1 auto;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.strip__voice { font: 9px/1 var(--font); letter-spacing: .08em; color: var(--muted); }

.strip__knobs { display: flex; align-items: flex-start; gap: 4px; }

.strip__fader { display: flex; align-items: center; gap: 8px; }
.strip__fader .slider { flex: 1 1 auto; min-width: 80px; }

.strip__buttons { display: flex; gap: 5px; }

/* ================================================ patterns, song and project (M04) */

.patbay { padding: 12px 16px 14px; }

/*
 * Sixteen pads on one line at 1280 px, wrapping to two on a laptop. `auto-fit` with a
 * minimum rather than a fixed sixteen columns, because a bar that overflowed the panel
 * horizontally would push the whole page sideways — and gate assertion 9 is exactly
 * that check.
 */
.patbar {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(54px, 1fr));
  gap: 6px;
  margin-bottom: 12px;
}

/* The bank break: a stronger gap between A8 and B1, which is the same trick the step
   grid plays every four columns. You navigate by shape before you read a label. */
.patbar .patpad:nth-child(9) { margin-left: 6px; box-shadow: inset 2px 0 0 -1px var(--edge); }

.patbay__body {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 14px 18px;
  margin-bottom: 12px;
}
.patbay__body .unit + .unit { padding-left: 18px; border-left: 1px solid var(--edge); }

.songbay { padding: 12px 16px 14px; }
.songbay .rack__head { flex-wrap: wrap; align-items: flex-end; row-gap: 10px; }
.songbay .kitbay { margin-left: auto; }

.songrows {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-bottom: 10px;
}

/*
 * Rows recede until Song mode is armed. An arrangement you cannot hear yet is
 * reference material; the moment the transport can run it, it is the thing you are
 * looking at. Same idea as the mixer dimming a silenced channel.
 */
.songrows:not(.is-armed) { opacity: .78; }
/* Focus always comes back to full strength, so the ring is never drawn on a dimmed
   control — the same rule the mixer applies to a silenced channel. */
.songrows:not(.is-armed):focus-within { opacity: 1; }

.songrow {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 6px 10px;
  background: var(--panel-2);
  border: 1px solid var(--edge);
  border-left: 3px solid var(--edge);
  border-radius: 8px;
}
.songrow.is-playing {
  border-left-color: var(--accent);
  background: rgba(255, 90, 60, .09);
}

.songrow__num {
  min-width: 18px;
  font: 600 12px/1 var(--font);
  color: var(--muted);
  text-align: right;
}
.songrow__pick { width: 118px; }
.songrow__repeats .field__label { color: var(--muted); }
.songrow__progress { min-width: 74px; text-align: center; }
.songrow__buttons { display: flex; gap: 5px; margin-left: auto; }

/* Square, like the mixer's M and S — they are the same class of control. The glyphs
   are arrows rather than letters, and a thin arrow at --muted is genuinely hard to
   see, so these carry full text colour. */
.chanbtn--row { min-width: 26px; padding: 0 6px; color: var(--text); font-weight: 400; }
.chanbtn--row:hover { color: var(--accent-2); border-color: var(--accent-2); }

.songbay__foot { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }

.projectbay {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 14px 18px;
  padding: 12px 16px;
}
.projectbay .unit + .unit { padding-left: 18px; border-left: 1px solid var(--edge); }

/* --------------------------------------------------------- the tour picker */

/*
 * Centred, above the app but BELOW the tour overlay's own chrome — the tour
 * spotlights this panel, so it has to sit inside the hole the spotlight cuts rather
 * than on top of the dim.
 */
.tourpicker {
  position: fixed;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  z-index: var(--z-modal);
  width: min(560px, calc(100vw - 48px));
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 16px;
  background: linear-gradient(180deg, var(--panel-2) 0%, var(--panel) 100%);
  border: 1px solid var(--edge);
  border-radius: var(--radius);
  box-shadow: 0 24px 60px rgba(0, 0, 0, .6);
}

.tourpicker__all { align-self: flex-start; }
.tourpicker__list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 6px;
  max-height: 40vh;
  overflow-y: auto;
}
.tourpicker__chapter { justify-content: flex-start; text-align: left; }

/* ---------------------------------------------------------- master section */

.master {
  display: flex;
  align-items: flex-end;
  gap: 14px 18px;
  flex-wrap: wrap;
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid var(--edge);
}

.master .unit + .unit { padding-left: 18px; border-left: 1px solid var(--edge); }

.master__id { display: flex; flex-direction: column; gap: 5px; }
/* The signal path, silk-screened onto the panel the way a hardware mixer prints its
   block diagram next to the master fader. */
.master__path {
  font: 10px/1.4 var(--font);
  letter-spacing: .04em;
  color: var(--accent-2);
  opacity: .75;
}

/* -------------------------------------------------------------- timing lab */

.clockbay { padding: 12px 16px 14px; }

.clockbay__head {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 10px;
}

/* Six instruments on one bench. They wrap onto as many rows as the window needs;
   nothing here is allowed to force the page itself to scroll sideways. */
.clockbay__body {
  display: flex;
  align-items: flex-end;
  gap: 16px 18px;
  flex-wrap: wrap;
}

.stressbay { display: flex; flex-direction: column; gap: 7px; }

/*
 * The jitter trace: one bar per scheduled step, up for late and down for early,
 * centred on a line that means "exactly on the grid". It is a canvas rather than
 * DOM because it redraws once per step and a canvas costs one paint instead of
 * thirty-two style recalculations.
 */
.jitter {
  width: 100%;
  max-width: 260px;
  height: 56px;
  background: #0a0c11;
  border: 1px solid #000;
  border-radius: 6px;
  box-shadow: inset 0 2px 8px rgba(0, 0, 0, .8);
}

/* Label across the top, value and its coach mark side by side underneath. */
.readout {
  display: grid;
  grid-template-columns: auto auto;
  align-items: center;
  gap: 6px;
}
.readout__label { grid-column: 1 / -1; }

/* Drift is signed: late is the common case, but which way a machine leans depends
   on how its timer and its sound card disagree, so both colours exist. */
.lcd.is-late { color: var(--warn); text-shadow: 0 0 12px rgba(255, 204, 68, .35); }
.lcd.is-early { color: var(--accent); text-shadow: 0 0 12px rgba(255, 90, 60, .3); }

.verdict {
  flex: 1 1 320px;
  min-width: 260px;
  margin: 0;
  padding: 9px 12px;
  border: 1px dashed var(--edge);
  border-radius: 8px;
  font-size: 12.5px;
  color: var(--muted);
}
.verdict.is-answered { border-style: solid; border-color: var(--accent-2); color: var(--text); }

.footer {
  padding: 2px 4px;
  font-size: 12px;
  color: var(--muted);
}

/* ------------------------------------------------------------ manual modal */

.manual { position: fixed; inset: 0; z-index: var(--z-modal); }
.manual[hidden] { display: none; }

.manual__scrim { position: absolute; inset: 0; background: rgba(6, 7, 10, .68); }

.manual__dialog {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: min(760px, calc(100vw - 32px));
  max-height: min(640px, calc(100vh - 48px));
  display: flex;
  flex-direction: column;
  background: linear-gradient(180deg, var(--panel-2) 0%, var(--panel) 100%);
  border: 1px solid var(--edge);
  border-radius: var(--radius);
  box-shadow: 0 30px 70px rgba(0, 0, 0, .65);
}

.manual__head {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--edge);
}
.manual__title {
  font: 600 12px/1 var(--font);
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--muted);
}
.manual__close { margin-left: auto; }

.manual__tabs { display: flex; gap: 6px; padding: 10px 16px 0; flex-wrap: wrap; }
.manual__tab {
  padding: 7px 12px;
  background: transparent;
  border: 1px solid transparent;
  border-bottom: 0;
  border-radius: 8px 8px 0 0;
  color: var(--muted);
  font: 600 12px/1 var(--font-ui);
  cursor: pointer;
}
.manual__tab[aria-selected="true"] {
  color: var(--text);
  background: rgba(255, 255, 255, .04);
  border-color: var(--edge);
}

.manual__body {
  padding: 14px 16px 18px;
  overflow-y: auto;
  border-top: 1px solid var(--edge);
  margin-top: -1px;
}
/* The panel is a scroll container and therefore a real tab stop (tabindex="0" in
   manual.js). Its ring goes INSIDE, or the dialog's own edge clips it. */
.manual__body:focus-visible { outline-offset: -2px; }
.manual__body h3 {
  font: 600 12px/1 var(--font);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--accent-2);
  margin: 0 0 8px;
}
.manual__body p { margin: 0 0 10px; }

.manual__list { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.manual__list li {
  display: grid;
  grid-template-columns: 150px 1fr;
  gap: 12px;
  align-items: baseline;
  padding-bottom: 8px;
  border-bottom: 1px solid rgba(255, 255, 255, .05);
}
.manual__list dfn,
.manual__list .keys {
  font: 600 12px/1.4 var(--font);
  color: var(--warn);
  font-style: normal;
}
.manual__list .keys { color: var(--accent-2); }
.manual__note { color: var(--muted); font-size: 12.5px; }

/* --------------------------------------------------------------- narrower */

@media (max-width: 1100px) {
  .row__head, .ruler__spacer { flex-basis: 136px; }
  .unit + .unit { padding-left: 12px; }
  .kitbay:first-of-type { margin-left: 0; }
  .songbay .kitbay { margin-left: 0; }
  .songrow { flex-wrap: wrap; }
  .songrow__buttons { margin-left: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .cell { transition: none; }
}
