.guitar-stage {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 8px 16px 24px;
  align-items: center;
  justify-content: center;
}

.fretboard {
  /* `flex-shrink: 0` is critical — `.guitar-stage` is `flex: 1` so
   * the column can be height-bounded by the viewport, and without
   * this the fretboard would absorb all the shrink (the chord-builder
   * has rigid text content that won't compress). Combined with our
   * own `overflow-y: hidden`, that quietly clipped the lowest string
   * (or two) on phones — the player sees an "E A D G B" guitar with
   * no low-E. flex-shrink: 0 lets the page scroll instead. */
  flex-shrink: 0;
  /* Shared knobs so the string rows and the inlay overlay stay aligned
   * even when the open-string label cell shrinks on mobile. */
  --label-col-width: 60px;
  --fretboard-pad-top: 18px;
  --fretboard-pad-right: 12px;
  --fretboard-pad-bottom: 22px;
  --fretboard-pad-left: 12px;
  /* Minimum width per fret column. When (fret-count × this) exceeds the
   * available width, the .fretboard scrolls horizontally instead of
   * shrinking the cells into unreadable slivers. */
  --fret-min-cell: 52px;
  --fret-count: 19;

  width: min(100%, 1100px);
  background:
    radial-gradient(circle at 30% 30%, rgba(180, 83, 9, 0.18), transparent 50%),
    linear-gradient(180deg, #3f1d0e, #2a1006);
  border: 1px solid #2a1006;
  border-radius: 12px;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.06),
    0 24px 40px -20px rgba(0, 0, 0, 0.6);
  user-select: none;
  -webkit-user-select: none;
  /* The fretboard itself is the horizontal scroll container — when the
   * inner grid's min-width exceeds the visible width, swiping the neck
   * scrolls through the upper register. `overflow-y: hidden` keeps a
   * stray vertical scrollbar from appearing. */
  overflow-x: auto;
  overflow-y: hidden;
  /* Smooth wheel/touch scrolling and a less jarring scroll snap on
   * inertial swipes. */
  scroll-behavior: smooth;
  -webkit-overflow-scrolling: touch;
}

/* Inner wrapper that owns the layout (and the absolute-positioning
 * containing block for the inlay overlay). Its `min-width` is what
 * makes the outer .fretboard scroll horizontally on narrow viewports;
 * on wide screens the strings stretch via the `1fr` columns to fill
 * the available width. */
.fretboard-grid {
  position: relative;
  padding: var(--fretboard-pad-top) var(--fretboard-pad-right) var(--fretboard-pad-bottom)
    var(--fretboard-pad-left);
  /* `1fr` columns inside the strings stretch to fill any extra space
   * past min-width on desktop, so the neck looks the same as before
   * on a 1100px viewport. */
  min-width: calc(
    var(--label-col-width) + var(--fret-min-cell) * var(--fret-count) + var(--fretboard-pad-left) +
      var(--fretboard-pad-right)
  );
}

.fretboard-string {
  position: relative;
  display: grid;
  /* Two-part track: the open-string label, then N fret columns sized
   * `minmax(<min>, 1fr)`. The minmax floor keeps cells tappable; the
   * 1fr ceiling stretches them on wide screens. */
  grid-template-columns:
    var(--label-col-width)
    repeat(var(--fret-count), minmax(var(--fret-min-cell), 1fr));
  align-items: center;
  height: clamp(34px, 5vw, 46px);
  z-index: 1; /* keep cells above the inlay overlay */
}

/* Open-string label cell on the left.
 * `position: sticky; left: 0` pins the label (E A D G B E) in place
 * during horizontal scroll on mobile so the player can always see
 * which string they're on while plucking the upper register. The
 * z-index keeps it above the metallic string line + neighbouring fret
 * cells as they scroll under it. */
.fret-cell.open {
  background:
    linear-gradient(90deg, rgba(0, 0, 0, 0.35), transparent),
    linear-gradient(180deg, #5b2810, #381606);
  border-right: 4px solid #d4d4d8;
  font-weight: 700;
  color: #fef3c7;
  position: sticky;
  left: 0;
  z-index: 2;
}

.fret-cell {
  position: relative;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  font-size: 11px;
  letter-spacing: 0.04em;
  color: rgba(254, 243, 199, 0.7);
  border-right: 1px solid rgba(212, 212, 216, 0.4);
  transition: background 100ms ease;
  /* `pan-x` lets the browser handle horizontal swipes natively — the
   * fretboard's `overflow-x: auto` then gets momentum / inertia for
   * free, instead of being driven choppily from JS. Vertical drags
   * stay with us so a string-to-string slide still strums.
   * `touch-action: none` (the previous value) blocked native scroll
   * entirely and forced JS-driven scrollLeft, which felt jerky on
   * a long neck. */
  touch-action: pan-x;
}

.fret-cell:last-child {
  border-right: none;
}

/* Subtle highlight on hover */
.fret-cell:hover {
  background: rgba(245, 158, 11, 0.18);
  color: #fef3c7;
}

.fret-cell.active {
  background: linear-gradient(90deg, rgba(244, 114, 182, 0.45), rgba(129, 140, 248, 0.45));
  color: #fff;
  animation: fret-pulse 280ms ease-out;
}

/* Persistent chord-shape highlight — drawn as a solid disc inside the
 * cell to mimic a real chord chart's "press here" dot, with the finger
 * number written inside it. Cleared when another chord is selected or
 * the explicit "clear" control is hit.
 *
 * Implementation: a ::before pseudo on the cell is the disc; the finger
 * badge sits on top of it. The cell's own background stays neutral so
 * the wood grain still reads behind the dot. */
.fret-cell.in-chord {
  color: transparent; /* hide the under-the-dot note name */
}

.fret-cell.in-chord::before {
  content: '';
  position: absolute;
  inset: 4px 6px;
  border-radius: 999px;
  background: radial-gradient(circle at 35% 30%, #c084fc, #7e22ce 70%, #581c87);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.35),
    0 2px 6px rgba(0, 0, 0, 0.45);
  z-index: 1;
}

/* Fretted root cell: just hide the under-the-marker note name. The
 * actual red disc is rendered as an OVERLAY element in
 * `.fretboard-grid` (see .chord-root-marker below) so it can sit
 * above the barre overlay's stacking context. We can't win the
 * z-index race from inside `.fret-cell` because the strings row has
 * its own z-index that's strictly below the barre. */
.fret-cell.in-chord-root {
  color: transparent;
}

/* Finger number inside the chord-tone disc. White, bold, centred. The
 * z-index puts it above the disc pseudo-element. */
.finger-badge {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 14px;
  font-weight: 800;
  color: #fff;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
  pointer-events: none;
  z-index: 2;
}

.fret-cell.in-chord-root .finger-badge {
  color: #fff;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.7);
}

/* Active flash on top of in-chord — disc gets a pink overlay so the
 * strum pulse is still readable. */
.fret-cell.active.in-chord::before,
.fret-cell.active.in-chord-root::before {
  filter: brightness(1.25) saturate(1.3);
}

/* Open chord-tone marker: a small ○ over the open-string label cell.
 * Intentionally NO full-cell tint — open notes don't need a finger so
 * they shouldn't visually compete with the fretted disc shapes. */
.fret-cell.in-chord-open {
  /* Subtle outline so it reads as "in the chord" without shouting. */
  box-shadow: inset 0 0 0 2px rgba(168, 85, 247, 0.45);
}

.fret-cell.in-chord-open::after {
  content: '○';
  position: absolute;
  top: 2px;
  right: 4px;
  font-size: 14px;
  font-weight: 700;
  color: #c084fc;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
  pointer-events: none;
}

/* If the open chord-tone IS the root, swap the marker to an "R" inside
 * a small red pill so it still reads as the tonal centre even without
 * a full-cell disc. */
.fret-cell.in-chord-root.open .finger-badge {
  position: absolute;
  inset: auto;
  top: 2px;
  right: 4px;
  width: 18px;
  height: 18px;
  background: radial-gradient(circle at 35% 30%, #fecaca, #ef4444 55%, #7f1d1d);
  border-radius: 50%;
  font-size: 11px;
  color: #fff;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.45);
}

.fret-cell.in-chord-root.open::before {
  /* Don't draw the giant disc on the sticky open-label cell — the small
   * R pill above is enough. */
  content: none;
}

/* Muted strings — the player needs to skip these when strumming, so the
 * × should be UNMISSABLE. Big, centred, with a faint disc behind it for
 * contrast against the open-cell wood grain. */
.fret-cell.muted::after {
  content: '×';
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 28px;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 26px;
  line-height: 1;
  font-weight: 900;
  color: #fecaca;
  background: radial-gradient(circle, rgba(127, 29, 29, 0.85), rgba(127, 29, 29, 0.3) 70%);
  border-radius: 50%;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
  pointer-events: none;
}

.fret-cell.muted .note {
  /* Hide the open-string letter (E A D G B E) when the string is
   * muted — the big × is the message; the letter just adds noise. */
  opacity: 0.25;
}

/* ---------- Barre overlay ----------
 *
 * Drawn as a single absolutely-positioned pill across the strings the
 * index finger covers on barre chords. Geometry is computed in JS from
 * the cell DOM rects (see drawBarreOverlay in guitar.js) so the bar
 * stays glued to its cells across resize / scroll / orientation
 * changes — no hardcoded fret-column maths in CSS. */
.chord-barre {
  position: absolute;
  border-radius: 999px;
  background: linear-gradient(180deg, #fde68a, #f59e0b 50%, #b45309);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.5),
    0 4px 10px rgba(0, 0, 0, 0.45),
    0 0 0 2px rgba(254, 243, 199, 0.45);
  z-index: 3; /* above .in-chord discs */
  pointer-events: none;
  display: flex;
  align-items: center;
  justify-content: center;
}

.chord-barre-label {
  font-size: 14px;
  font-weight: 800;
  color: #422006;
  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.4);
}

/* Root-cell marker overlay — same trick as the barre, but for the
 * root note. Drawn into `.fretboard-grid` so it competes in the same
 * stacking context as the barre and can sit on top via z-index. The
 * red hue is intentionally distinct from both the purple chord-tone
 * discs and the amber barre so the player's eye lands on the tonal
 * centre first. */
.chord-root-marker {
  position: absolute;
  border-radius: 999px;
  background: radial-gradient(circle at 35% 30%, #fecaca, #ef4444 55%, #7f1d1d);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.45),
    0 2px 8px rgba(239, 68, 68, 0.55),
    0 0 0 2px rgba(254, 243, 199, 0.55);
  z-index: 5; /* above .chord-barre (3) */
  pointer-events: none;
  display: flex;
  align-items: center;
  justify-content: center;
}

.chord-root-marker-label {
  font-size: 14px;
  font-weight: 800;
  color: #fff;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.55);
  display: flex;
  align-items: baseline;
  gap: 2px;
}

.chord-root-marker-label small {
  font-size: 9px;
  opacity: 0.9;
  font-weight: 700;
}

@keyframes fret-pulse {
  0% {
    box-shadow: inset 0 0 0 0 rgba(244, 114, 182, 0.7);
  }
  50% {
    box-shadow: inset 0 0 0 18px rgba(244, 114, 182, 0);
  }
  100% {
    box-shadow: inset 0 0 0 0 rgba(244, 114, 182, 0);
  }
}

.fret-cell .note {
  pointer-events: none;
  font-weight: 600;
}

.fretboard.hide-notes .fret-cell .note {
  opacity: 0;
}

/* Each string is a thin horizontal line drawn on top of the cell row.
 *
 * `--start-offset` is the number of fret columns to skip from the
 * leftmost playable cell — used by banjo's "short" 5th drone string
 * (startFret: 5). At default 0, the line spans the whole neck. */
.fretboard-string {
  --start-offset: 0;
}

.fretboard-string::after {
  content: '';
  position: absolute;
  left: calc(
    var(--label-col-width) + (100% - var(--label-col-width)) * var(--start-offset) /
      var(--fret-count)
  );
  right: 0;
  top: 50%;
  height: var(--string-thickness, 2px);
  background: linear-gradient(
    180deg,
    rgba(255, 255, 255, 0.65),
    rgba(255, 255, 255, 0.25) 40%,
    rgba(0, 0, 0, 0.4)
  );
  border-radius: 2px;
  transform: translateY(-50%);
  pointer-events: none;
  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.5);
}

/* Paired courses (mandolin) — render two thin strings ~3px apart so the
 * visual reads as a doubled course. The audio engine fires a quick
 * tremolo retrigger to match (see StringEngine.pluck in engine.js). The
 * ::after string is shifted up; ::before draws the second string below. */
.fretboard-string.paired::after {
  top: calc(50% - 3px);
}

.fretboard-string.paired::before {
  content: '';
  position: absolute;
  left: calc(
    var(--label-col-width) + (100% - var(--label-col-width)) * var(--start-offset) /
      var(--fret-count)
  );
  right: 0;
  top: calc(50% + 3px);
  height: var(--string-thickness, 2px);
  background: linear-gradient(
    180deg,
    rgba(255, 255, 255, 0.65),
    rgba(255, 255, 255, 0.25) 40%,
    rgba(0, 0, 0, 0.4)
  );
  border-radius: 2px;
  transform: translateY(-50%);
  pointer-events: none;
  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.5);
  z-index: 0;
}

/* Unavailable cells — used for banjo's 5th-string drone where the short
 * string physically doesn't reach frets 0..4. Visually fade the cell out
 * and disable interaction; we also skip drawing the string line up to
 * the start fret with the .fret-cell.drone-start adornment below. */
.fret-cell.unavailable {
  cursor: default;
  pointer-events: none;
  background: linear-gradient(180deg, rgba(0, 0, 0, 0.18), rgba(0, 0, 0, 0.32));
  border-right-color: rgba(212, 212, 216, 0.15);
}

.fret-cell.unavailable:hover {
  background: linear-gradient(180deg, rgba(0, 0, 0, 0.18), rgba(0, 0, 0, 0.32));
}

/* The cell where a "short" drone string actually starts (banjo's 5th
 * string at fret 5). Marked with a thicker left border + the open-style
 * accent so players see "this is the start of the string". */
.fret-cell.drone-start {
  border-left: 4px solid #d4d4d8;
  background:
    linear-gradient(90deg, rgba(0, 0, 0, 0.35), transparent),
    linear-gradient(180deg, #5b2810, #381606);
  font-weight: 700;
  color: #fef3c7;
}

/* ---------- Fret inlays ----------
 *
 * On a real guitar the position-marker dots sit in the wood between the
 * strings, not on top of any string. We replicate that with an overlay
 * layer that grids the same 12 fret columns the strings use, sized to the
 * inner padding box of the fretboard so its `align-items: center` lands
 * vertically between the two middle strings (3rd ↔ 4th). Pointer-events:
 * none keeps the dots out of the way of clicks.
 */
.fretboard-inlays {
  /* Positioned relative to .fretboard-grid (the new inner wrapper) so
   * the overlay extends the full scrollable neck width and stays
   * aligned with the string fret cells under it. */
  position: absolute;
  top: var(--fretboard-pad-top);
  bottom: var(--fretboard-pad-bottom);
  left: calc(var(--fretboard-pad-left) + var(--label-col-width));
  right: var(--fretboard-pad-right);
  display: grid;
  /* Mirror the strings' fret-column sizing exactly so dots line up with
   * the cells they mark, regardless of whether we're stretched to fill
   * a desktop viewport or scrolling at the cell-min-width on mobile. */
  grid-template-columns: repeat(var(--fret-count), minmax(var(--fret-min-cell), 1fr));
  /* One row that spans the full height of the strings area, so single-dot
   * inlays can be centred via `align-items: center` and the double-dot
   * inlay can stretch to position ::before / ::after at percentages.
   * Plain `1fr` resolves to `minmax(auto, 1fr)` and collapses to content
   * height when no item has intrinsic size; `100%` forces full height. */
  grid-template-rows: 100%;
  align-items: center;
  justify-items: center;
  pointer-events: none;
  z-index: 0;
}

.inlay {
  width: 11px;
  height: 11px;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 35%, rgba(254, 243, 199, 0.85), rgba(180, 110, 40, 0.55));
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.4),
    0 1px 2px rgba(0, 0, 0, 0.5);
}

/* Double-dot inlay (12th fret traditionally) — two stacked dots, one
 * sitting roughly between strings 1↔2 (high) and the other between
 * strings 5↔6 (low), without overlapping the middle strings' note
 * labels. The container stretches the full inlay-overlay height
 * (`align-self: stretch` — overriding the grid's `align-items: center`
 * which would otherwise size it to its 0px intrinsic content) so
 * percentage offsets on the ::before/::after pseudo-dots resolve
 * relative to a meaningful height instead of collapsing to 0. */
.inlay.double {
  /* `align-self: stretch` alone doesn't work here — the element has no
   * in-flow content (the dots are positioned via ::before / ::after)
   * so the grid row can't infer a height to stretch into. With JS
   * forcing every inlay into row 1 (height: 100% of the container),
   * `height: 100%` resolves correctly. */
  align-self: stretch;
  justify-self: center;
  background: transparent;
  box-shadow: none;
  width: 11px;
  height: 100%;
  position: relative;
}

.inlay.double::before,
.inlay.double::after {
  content: '';
  position: absolute;
  left: 50%;
  width: 11px;
  height: 11px;
  border-radius: 50%;
  transform: translateX(-50%);
  background: radial-gradient(circle at 35% 35%, rgba(254, 243, 199, 0.85), rgba(180, 110, 40, 0.55));
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.4),
    0 1px 2px rgba(0, 0, 0, 0.5);
}

/* 25% in from each edge centres each dot on its respective string-pair
 * gap on a six-string guitar (top dot lands between strings 2↔3, bottom
 * between 4↔5 — a more visually central placement than the 18% offset
 * we used to use, which felt cramped against the edges). */
.inlay.double::before {
  top: 25%;
}

.inlay.double::after {
  bottom: 25%;
}

/* ---------- Chord builder ----------
 *
 * Three pickable rows: Root × Quality × Voicing. Voicing is populated
 * dynamically based on what's in the chord library for the chosen
 * Root + Quality combo, then clicking a voicing strums and parks the
 * shape on the fretboard.
 */
.chord-builder {
  width: min(100%, 1100px);
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 12px 14px;
  background: rgba(15, 23, 42, 0.55);
  border: 1px solid var(--border);
  border-radius: 12px;
}

/* The chord builder is guitar-only for now. JS toggles `[hidden]` when
 * the active instrument changes; this rule beats `display: flex` above
 * so it actually disappears for bass / uke / banjo / mandolin. */
.chord-builder[hidden] {
  display: none;
}

.chord-builder-row {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}

/* ------------------------------------------------------------------
 * Strum Bar — primary play surface
 *
 * Big named chord pads with full chord names on them ("Em", "A",
 * "Cmaj7"). Tapping a pad strums that chord with one finger; the row
 * auto-fills as the player plays chords (LRU, max 8 per instrument)
 * and persists across sessions via Prefs.
 *
 * Visually demotes the matrix below ("Build a chord ▾") into a
 * supporting role: matrix = configure / explore, Strum Bar = play.
 * ------------------------------------------------------------------ */

.strum-bar {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 12px;
  background: linear-gradient(180deg, rgba(99, 102, 241, 0.1), rgba(15, 23, 42, 0.4));
  border: 1px solid rgba(99, 102, 241, 0.35);
  border-radius: 12px;
  position: relative;
}

.strum-bar-header {
  display: flex;
  align-items: baseline;
  gap: 12px;
  flex-wrap: wrap;
  font-size: 11px;
}

/* The hint is only useful on the empty state — once the player has
 * pinned even one pad the meaning of the row is obvious from the pads
 * themselves. JS toggles `.has-pads` so the hint vanishes (and we
 * reclaim ~20-30 px of vertical space, which matters a lot on phones).
 *
 * Exception: when the player has tapped a pad to edit it, we
 * temporarily repurpose the hint slot to surface "you're editing X"
 * guidance — so override the hide rule for `.editing`. */
.strum-bar.has-pads .strum-bar-hint {
  display: none;
}

.strum-bar.editing .strum-bar-hint {
  display: inline;
  color: rgb(94, 234, 212);
}

.strum-bar.editing .strum-bar-hint strong {
  color: #fff;
  font-weight: 800;
}

.strum-bar-title {
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--fg);
  font-weight: 800;
}

.strum-bar-hint {
  color: var(--fg-dim);
  font-size: 11px;
  letter-spacing: 0.02em;
}

.strum-bar-hint kbd {
  display: inline-block;
  padding: 0 5px;
  background: rgba(99, 102, 241, 0.18);
  border: 1px solid rgba(99, 102, 241, 0.4);
  border-radius: 4px;
  font-family: inherit;
  font-size: 10px;
  font-weight: 700;
  color: var(--fg);
}

/* Transpose group — ♭ / ♯ pair that shifts every pinned chord by one
 * semitone (capo-style). Lives in the header right edge, immediately
 * before Clear. `margin-left: auto` here claims the right side of the
 * flex container for the whole actions group; Clear's own margin-left
 * then sits flush against it. Hidden alongside Clear when the bar is
 * empty (toggled by JS — same `[hidden]` mechanism). */
.strum-bar-transpose {
  margin-left: auto;
  display: inline-flex;
  gap: 4px;
}

.strum-bar-transpose[hidden] {
  display: none;
}

.strum-bar-transpose-btn {
  /* `position: relative` is the anchor for the [data-tooltip]
   * pseudo-element bubble below — the bubble is absolutely
   * positioned against this button. */
  position: relative;
  background: transparent;
  color: var(--fg-dim);
  border: 1px solid rgba(148, 163, 184, 0.35);
  border-radius: 6px;
  /* Symbol fonts (♭ / ♯) tend to render tall — a touch more vertical
   * padding keeps the buttons the same visual height as Clear (which
   * uses a Latin glyph). */
  padding: 1px 9px 3px;
  font-size: 14px;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
  transition:
    color 120ms ease,
    border-color 120ms ease,
    background 120ms ease;
  touch-action: manipulation;
  min-width: 30px;
}

.strum-bar-transpose-btn:hover,
.strum-bar-transpose-btn:focus-visible {
  color: rgb(125, 247, 230);
  border-color: rgba(94, 234, 212, 0.6);
  background: rgba(94, 234, 212, 0.08);
  outline: none;
}

/* Fast, styled tooltip — reads `data-tooltip` and pops above the
 * button on hover / keyboard focus. Custom instead of relying on the
 * native `title` attribute because the OS-level tooltip has a
 * noticeable 0.5–1s reveal delay (and doesn't surface at all on
 * touch). `aria-label` is the authoritative accessible name, so we
 * intentionally do NOT also set `title` — screen readers wouldn't
 * benefit, and dual tooltips would just overlap on hover. */
.strum-bar-transpose-btn[data-tooltip]::after {
  content: attr(data-tooltip);
  position: absolute;
  bottom: calc(100% + 6px);
  left: 50%;
  transform: translateX(-50%) translateY(2px);
  padding: 4px 8px;
  background: rgba(15, 23, 42, 0.96);
  color: var(--fg);
  border: 1px solid rgba(94, 234, 212, 0.45);
  border-radius: 4px;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: none;
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  transition:
    opacity 120ms ease-out 30ms,
    transform 120ms ease-out 30ms;
  /* Above the popovers but below modal-grade UI. The popovers
   * underneath top out around z-index 5; sit at 20 here so a tooltip
   * over a transpose button is never occluded by a sibling popover
   * peeking in from the row below. */
  z-index: 20;
}

.strum-bar-transpose-btn[data-tooltip]:hover::after,
.strum-bar-transpose-btn[data-tooltip]:focus-visible::after {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

/* Little caret notch under the bubble, pointing back at the button.
 * Same dark fill as the bubble; the border is faked with a 1px
 * thinner triangle clipped behind the main shape so we don't need a
 * second pseudo-element. */
.strum-bar-transpose-btn[data-tooltip]::before {
  content: '';
  position: absolute;
  bottom: calc(100% + 1px);
  left: 50%;
  transform: translateX(-50%) translateY(2px);
  width: 0;
  height: 0;
  border-left: 5px solid transparent;
  border-right: 5px solid transparent;
  border-top: 5px solid rgba(94, 234, 212, 0.45);
  pointer-events: none;
  opacity: 0;
  transition:
    opacity 120ms ease-out 30ms,
    transform 120ms ease-out 30ms;
  z-index: 20;
}

.strum-bar-transpose-btn[data-tooltip]:hover::before,
.strum-bar-transpose-btn[data-tooltip]:focus-visible::before {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

/* "Clear" lives in the strum-bar header (right edge) so a wandering
 * tap on the pad area can't fire it. Subtle red tint on hover/focus
 * to read as a destructive action without screaming for attention.
 * When the transpose group is present its `margin-left: auto` already
 * pushed the whole actions cluster to the right, so Clear's own
 * auto-margin is a no-op (margins flatten when there's no slack); when
 * the transpose group is hidden, Clear's auto-margin claims the right
 * edge by itself. Either way the layout reads the same. */
/* "♪ Title — Artist" link surfaced after a song load. Sits between
 * the title/hint and the Clear button. Underlined on hover so it
 * looks like the link it is, but stays visually quiet at rest so it
 * doesn't compete with the chord pads below. Truncates on narrow
 * screens — long song titles shouldn't push Clear off-screen. */
.strum-bar-song {
  color: rgb(94, 234, 212);
  text-decoration: none;
  font-weight: 600;
  font-size: 11px;
  max-width: 60%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.strum-bar-song[hidden] {
  display: none;
}

.strum-bar-song:hover,
.strum-bar-song:focus-visible {
  text-decoration: underline;
  color: rgb(125, 247, 230);
  outline: none;
}

.strum-bar-clear {
  margin-left: auto;
  background: transparent;
  color: var(--fg-dim);
  border: 1px solid rgba(148, 163, 184, 0.35);
  border-radius: 6px;
  padding: 3px 10px;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  cursor: pointer;
  transition:
    color 120ms ease,
    border-color 120ms ease,
    background 120ms ease;
  touch-action: manipulation;
}

.strum-bar-clear[hidden] {
  display: none;
}

.strum-bar-clear:hover,
.strum-bar-clear:focus-visible {
  color: #fecaca;
  border-color: rgba(248, 113, 113, 0.6);
  background: rgba(248, 113, 113, 0.08);
  outline: none;
}

.strum-bar-row {
  display: flex;
  align-items: stretch;
  gap: 8px;
  min-height: 56px;
}

.strum-bar-pads {
  display: flex;
  align-items: stretch;
  gap: 8px;
  flex: 1 1 auto;
  /* `min-width: 0` is the missing piece — without it, the flex item's
   * default `min-width: auto` resolves to the intrinsic width of the
   * pads inside (e.g. 8 pads × 64px + gaps = ~570px), which forces
   * the container itself to widen rather than scroll. With min-width:
   * 0 the container can shrink to its parent's width and the
   * overflow-x kicks in on a long progression. */
  min-width: 0;
  /* Horizontal scroll on overflow keeps a long progression usable on
   * narrow screens without wrapping pads onto a second line (which
   * breaks the "play left-to-right" mental model). `pan-x` plus
   * native overflow-x: auto gives momentum scrolling on touch
   * devices; pads themselves use `touch-action: pan-y` so the
   * vertical/horizontal axes don't fight each other. */
  overflow-x: auto;
  scroll-behavior: smooth;
  -webkit-overflow-scrolling: touch;
  touch-action: pan-x;
  padding: 2px 0;
}

.strum-bar-pads:empty::before {
  content: 'No chords yet — tap a Root below to add one.';
  color: var(--fg-dim);
  font-size: 12px;
  font-style: italic;
  align-self: center;
  padding: 0 4px;
}

.strum-pad {
  position: relative;
  flex: 0 0 auto;
  min-width: 64px;
  min-height: 56px;
  padding: 8px 16px;
  background: linear-gradient(160deg, rgba(99, 102, 241, 0.85), rgba(168, 85, 247, 0.75));
  color: #fff;
  border: 1px solid rgba(168, 85, 247, 0.85);
  border-radius: 12px;
  font-size: 18px;
  font-weight: 800;
  letter-spacing: 0.02em;
  cursor: grab;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition:
    transform 80ms ease,
    box-shadow 120ms ease,
    border-color 120ms ease,
    opacity 120ms ease;
  box-shadow: 0 4px 12px -8px rgba(168, 85, 247, 0.7);
  /* `touch-action: pan-x pan-y` lets the browser handle BOTH axes of
   * native scroll (vertical for the chord-builder, horizontal for
   * the strum-bar pads container) on touch devices. To preserve
   * drag-to-reorder, the JS handler now requires a long-press
   * (~400ms hold) before promoting a touch gesture to a drag — any
   * finger movement before the timer fires hands the gesture back
   * to the browser for scrolling. Mouse / pen skip the long-press
   * (desktop users scroll with the wheel or trackpad, not by
   * dragging on a pad) and instead use the horizontal-direction
   * gate. */
  touch-action: pan-x pan-y;
  user-select: none;
  -webkit-user-select: none;
  /* Without this, iOS Safari pops up the text-selection callout
   * (magnifier / "Copy" menu) on long-press, which kills our
   * pointer events before the long-press timer can fire. */
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
}

.strum-pad:active {
  cursor: grabbing;
}

/* Touch long-press in progress — the player just put a finger down
 * and we're waiting out the long-press window before promoting to a
 * drag. A subtle scale + animated outline confirms "I see your
 * finger, keep holding". If the player moves before the timer
 * fires, this class is removed and the gesture becomes a scroll. */
.strum-pad.long-press-pending {
  animation: strum-pad-press-pending 400ms ease-out forwards;
}

@keyframes strum-pad-press-pending {
  0% {
    transform: scale(1);
    box-shadow: 0 4px 12px -8px rgba(168, 85, 247, 0.7);
  }
  100% {
    transform: scale(1.04);
    box-shadow: 0 0 0 3px rgba(254, 243, 199, 0.45),
      0 10px 20px -6px rgba(168, 85, 247, 0.7);
  }
}

/* Touch long-press is "armed" — the player has held a finger on the
 * pad past the long-press threshold and is now in reorder mode. The
 * scale + glow is the visual confirmation that says "I picked it up,
 * now drag me". Any horizontal scroll attempt during this time will
 * still work because we only set this once the long-press timer
 * fires AFTER the user has held still. */
.strum-pad.long-press-active {
  transform: scale(1.06);
  box-shadow: 0 14px 28px -6px rgba(168, 85, 247, 0.7);
}

/* The original pad stays in place but dims while a drag-clone of it
 * floats with the cursor — gives the player a "the pad is being
 * carried" feel without leaving a hole that other pads have to slide
 * across. */
.strum-pad.drag-source {
  opacity: 0.35;
  box-shadow: none;
}

.strum-pad.drag-ghost {
  cursor: grabbing;
  box-shadow: 0 18px 36px -10px rgba(0, 0, 0, 0.7);
  opacity: 0.95;
  /* Disable the pulse animation on the floating clone — its motion
   * is the pointer's, not a CSS keyframe. */
  animation: none !important;
}

/* While a drag is in flight, kill text selection / iOS callouts
 * across the page so nothing fights with the drag for the gesture. */
body.strum-dragging {
  cursor: grabbing;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
}

.strum-pad:hover {
  border-color: rgba(244, 114, 182, 0.95);
  box-shadow: 0 8px 18px -8px rgba(168, 85, 247, 0.9);
}

.strum-pad:active {
  transform: translateY(1px);
}

.strum-pad.playing {
  /* Brief flash when the pad is the chord that just strummed. JS
   * removes the class on a timer; CSS handles the visual decay. */
  animation: strum-pad-flash 380ms ease-out;
}

/* "Editing" outline — the player has tapped this pad most recently,
 * so a Shape click in the matrix below will rewrite THIS pad's
 * voicing instead of pinning a new one. Teal accent matches the
 * load-song button so the same colour means "the chord builder is
 * pointed at something I already have". The outline doesn't
 * displace layout (uses `outline`, not `border`) so the bar stays
 * stable as the highlight moves between pads. */
.strum-pad.editing {
  outline: 2px solid rgba(45, 212, 191, 0.85);
  outline-offset: 2px;
  box-shadow: 0 0 0 4px rgba(45, 212, 191, 0.18);
}

@keyframes strum-pad-flash {
  0% {
    box-shadow: 0 0 0 0 rgba(244, 114, 182, 0.9);
    transform: translateY(0) scale(1);
  }
  20% {
    transform: translateY(-1px) scale(1.04);
  }
  100% {
    box-shadow: 0 4px 12px -8px rgba(168, 85, 247, 0.7);
    transform: translateY(0) scale(1);
  }
}

@media (prefers-reduced-motion: reduce) {
  .strum-pad.playing {
    animation: none;
  }
}

.strum-pad-name {
  pointer-events: none;
}

/* Fret-position superscript shown next to the chord name when the
 * pad's voicing isn't open (e.g. `C³` for C Barre 3, `F⁵` for F Pos
 * 5). The `<sup>` default vertical-align gets visually swallowed by
 * the large bold chord name, so we explicitly nudge it up via
 * `position: relative` + negative `top` to read like a real
 * superscript. The superscript convention reads as a single token
 * `C³` distinct from the chord-extension convention `C7`/`Cmaj7`. */
.strum-pad-fret {
  pointer-events: none;
  display: inline-block;
  position: relative;
  top: -0.55em;
  font-size: 0.55em;
  font-weight: 800;
  line-height: 1;
  margin-left: 2px;
  letter-spacing: 0;
  color: rgba(254, 243, 199, 0.95);
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.55);
  vertical-align: baseline;
}

.strum-pad-remove {
  position: absolute;
  top: -6px;
  right: -6px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: rgba(15, 23, 42, 0.95);
  color: #fca5a5;
  border: 1px solid rgba(244, 114, 182, 0.5);
  font-size: 12px;
  font-weight: 900;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  opacity: 0;
  transform: scale(0.85);
  transition:
    opacity 120ms ease,
    transform 120ms ease;
  /* Keep tap targets reachable on touch — the × is small visually but
   * still ≥ 18px hit area, padded out by the pad's own breathing room. */
}

.strum-pad:hover .strum-pad-remove,
.strum-pad:focus-within .strum-pad-remove,
.strum-pad-remove:focus-visible {
  opacity: 1;
  transform: scale(1);
}

.strum-pad-remove:hover {
  background: #7f1d1d;
  color: #fff;
  border-color: #fecaca;
}

.strum-pad-add {
  flex: 0 0 auto;
  min-width: 48px;
  min-height: 56px;
  background: transparent;
  color: var(--fg-dim);
  border: 2px dashed rgba(148, 163, 184, 0.45);
  border-radius: 12px;
  font-size: 24px;
  font-weight: 700;
  cursor: pointer;
  transition:
    color 120ms ease,
    border-color 120ms ease,
    background 120ms ease;
  touch-action: manipulation;
}

.strum-pad-add:hover,
.strum-pad-add[aria-expanded='true'] {
  color: var(--fg);
  border-color: rgba(99, 102, 241, 0.75);
  background: rgba(99, 102, 241, 0.08);
}

/* Add-by-name popover. Anchored beneath the + button via JS-set
 * absolute positioning isn't worth it here — the popover is full-width
 * inside the strum bar so the on-screen keyboard doesn't shove it off
 * the visible viewport on phones. */
.strum-bar-add-popover {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 10px;
  background: rgba(15, 23, 42, 0.95);
  border: 1px solid rgba(99, 102, 241, 0.55);
  border-radius: 10px;
  box-shadow: 0 10px 30px -12px rgba(0, 0, 0, 0.6);
}

.strum-bar-add-popover[hidden] {
  display: none;
}

.strum-bar-add-popover input {
  background: rgba(15, 23, 42, 0.85);
  color: var(--fg);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 10px 12px;
  font-size: 16px;
  font-weight: 700;
  letter-spacing: 0.04em;
  width: 100%;
  outline: none;
}

.strum-bar-add-popover input:focus {
  border-color: rgba(168, 85, 247, 0.85);
  box-shadow: 0 0 0 3px rgba(168, 85, 247, 0.18);
}

.strum-bar-suggestions {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  max-height: 156px;
  overflow-y: auto;
}

.strum-bar-suggestions:empty {
  display: none;
}

.strum-bar-suggestion {
  background: rgba(30, 41, 59, 0.85);
  color: var(--fg);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 6px 10px;
  font-size: 13px;
  font-weight: 700;
  cursor: pointer;
  user-select: none;
}

.strum-bar-suggestion:hover,
.strum-bar-suggestion[aria-selected='true'] {
  border-color: rgba(168, 85, 247, 0.85);
  background: rgba(168, 85, 247, 0.25);
  color: #fff;
}

/* Load-song button — sibling to the "+" pad-add. Styled with the
 * same dashed frame so they read as a matched pair, but hover/active
 * tints to a teal/emerald accent so the player can tell at a glance
 * that this one DOES something different (loads a whole song's
 * worth of chords rather than typing one). The "↧" glyph sits a hair
 * smaller than the "+" because it has more vertical mass. */
.strum-pad-load {
  /* Inner SVG icon is sized via `em` (see .strum-pad-load-icon) so
   * font-size still drives the visual icon size — matches the "+"
   * button's font-size-driven sizing. */
  font-size: 22px;
  line-height: 1;
}

.strum-pad-load-icon {
  width: 1em;
  height: 1em;
  /* Optical centering: the magnifier sits a hair high inside the
   * 24×24 viewBox because the handle stops mid-cell. Nudge down so
   * it reads as vertically centred next to the "+" sibling. */
  vertical-align: -0.05em;
}

.strum-pad-load:hover,
.strum-pad-load[aria-expanded='true'] {
  color: var(--fg);
  border-color: rgba(45, 212, 191, 0.75);
  background: rgba(45, 212, 191, 0.1);
}

/* Load-song popover. Same skeleton as the chord-name popover above;
 * accent colour shifts to teal so it visually echoes the load
 * button. Includes a hint line under the input (telling the player
 * which site we accept) and a status line below (used for fetch
 * progress, success summaries, and error messages). */
.strum-bar-load-popover {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 10px;
  background: rgba(15, 23, 42, 0.95);
  border: 1px solid rgba(45, 212, 191, 0.55);
  border-radius: 10px;
  box-shadow: 0 10px 30px -12px rgba(0, 0, 0, 0.6);
}

.strum-bar-load-popover[hidden] {
  display: none;
}

.strum-bar-load-popover input {
  background: rgba(15, 23, 42, 0.85);
  color: var(--fg);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 10px 12px;
  font-size: 14px;
  letter-spacing: 0;
  width: 100%;
  outline: none;
}

.strum-bar-load-popover input:focus {
  border-color: rgba(45, 212, 191, 0.85);
  box-shadow: 0 0 0 3px rgba(45, 212, 191, 0.2);
}

.strum-bar-load-popover input:disabled {
  opacity: 0.5;
  cursor: progress;
}

.strum-bar-load-hint {
  margin: 0;
  font-size: 12px;
  color: var(--fg-dim);
  line-height: 1.4;
}

.strum-bar-load-hint a {
  color: rgb(94, 234, 212);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.strum-bar-load-status {
  margin: 0;
  padding: 6px 8px;
  font-size: 12.5px;
  border-radius: 6px;
  background: rgba(30, 41, 59, 0.7);
  color: var(--fg);
  border: 1px solid var(--border);
  line-height: 1.35;
}

.strum-bar-load-status[hidden] {
  display: none;
}

.strum-bar-load-status.is-success {
  border-color: rgba(45, 212, 191, 0.55);
  background: rgba(45, 212, 191, 0.12);
}

.strum-bar-load-status.is-error {
  border-color: rgba(248, 113, 113, 0.55);
  background: rgba(248, 113, 113, 0.1);
  color: #fecaca;
}

/* Live-search results inside the load popover. List behaves like a
 * compact two-line picker — title/artist on the left, popularity
 * pill on the right — with a max-height + scroll so a popular query
 * (say "house") doesn't push the chord builder off the page on a
 * phone. Hover/keyboard-highlight share the same teal accent as the
 * load button so it reads as the same surface. */
.strum-bar-load-results {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
  max-height: 240px;
  overflow-y: auto;
  background: rgba(15, 23, 42, 0.6);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 4px;
}

.strum-bar-load-results[hidden] {
  display: none;
}

.strum-bar-load-result {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 8px 10px;
  border-radius: 6px;
  cursor: pointer;
  user-select: none;
  border: 1px solid transparent;
  transition:
    background 100ms ease,
    border-color 100ms ease;
}

.strum-bar-load-result:hover,
.strum-bar-load-result.is-highlighted,
.strum-bar-load-result[aria-selected='true'] {
  background: rgba(45, 212, 191, 0.12);
  border-color: rgba(45, 212, 191, 0.55);
}

.strum-bar-load-result-main {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.strum-bar-load-result-title {
  font-size: 13.5px;
  font-weight: 700;
  color: var(--fg);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}

.strum-bar-load-result-artist {
  font-size: 11.5px;
  color: var(--fg-dim);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.strum-bar-load-result-meta {
  flex: 0 0 auto;
  font-size: 10.5px;
  color: var(--fg-dim);
  background: rgba(30, 41, 59, 0.7);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 2px 8px;
  white-space: nowrap;
}

/* Reading-the-shape legend. Sits below the chord-builder rows; mini
 * icons mirror the real fretboard graphics so the player can match
 * symbol-to-meaning at a glance. Items wrap on narrow screens. */
.chord-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 18px;
  margin-top: 4px;
  padding: 8px 10px;
  border-radius: 8px;
  background: rgba(15, 23, 42, 0.45);
  border: 1px solid rgba(148, 163, 184, 0.18);
  font-size: 12px;
  color: var(--fg);
}

.chord-legend-item {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.chord-legend-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  font-weight: 800;
  font-size: 12px;
  flex-shrink: 0;
}

/* Each icon variant intentionally mirrors the corresponding fretboard
 * graphic — same gradients / colors / shapes so visual transfer is
 * immediate. Sizes are scaled down to ~22px to fit the legend row. */
.chord-legend-icon.legend-root {
  border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, #fecaca, #ef4444 55%, #7f1d1d);
  color: #fff;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.55);
  box-shadow: 0 1px 4px rgba(239, 68, 68, 0.45);
}

.chord-legend-icon.legend-finger {
  border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, #c084fc, #7e22ce 70%, #581c87);
  color: #fff;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.55);
  box-shadow: 0 1px 4px rgba(126, 34, 206, 0.4);
}

.chord-legend-icon.legend-barre {
  border-radius: 999px;
  width: 30px;
  height: 12px;
  background: linear-gradient(180deg, #fde68a, #f59e0b 50%, #b45309);
  box-shadow: 0 1px 3px rgba(245, 158, 11, 0.45);
}

.chord-legend-icon.legend-open {
  color: #c084fc;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
  font-size: 18px;
  line-height: 1;
}

.chord-legend-icon.legend-mute {
  color: #fca5a5;
  font-size: 22px;
  line-height: 1;
  font-weight: 900;
}

.chord-legend-text {
  display: inline-flex;
  align-items: baseline;
  gap: 5px;
}

.chord-legend-hint {
  font-size: 10.5px;
  color: var(--fg-dim);
  letter-spacing: 0.01em;
}

.chord-builder-label {
  text-transform: uppercase;
  letter-spacing: 0.12em;
  font-size: 11px;
  color: var(--fg-dim);
  width: 64px;
  flex: 0 0 64px;
  text-align: right;
}

.chord-options {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  flex: 1 1 auto;
}

.chord-options button {
  background: linear-gradient(160deg, rgba(30, 41, 59, 0.85), rgba(15, 23, 42, 0.85));
  color: var(--fg);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 6px 12px;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.04em;
  cursor: pointer;
  min-width: 40px;
  transition:
    border-color 120ms ease,
    background 120ms ease,
    transform 80ms ease;
}

.chord-options button:hover {
  border-color: var(--accent);
}

.chord-options button:active {
  transform: translateY(1px);
}

.chord-options button.selected {
  background: linear-gradient(160deg, rgba(168, 85, 247, 0.45), rgba(129, 140, 248, 0.4));
  border-color: rgba(168, 85, 247, 0.85);
  color: #fff;
  box-shadow: 0 6px 16px -10px rgba(168, 85, 247, 0.7);
}

.chord-options button[disabled] {
  opacity: 0.35;
  cursor: not-allowed;
}

/* Enharmonic root buttons (C♯/D♭, D♯/E♭, F♯/G♭, G♯/A♭, A♯/B♭).
 * Stack the canonical sharp on top with the flat as a smaller
 * "also-known-as" hint underneath, so the player sees flats are
 * supported without making the button two characters wider than the
 * naturals (which would push the row to wrap on narrow screens). */
.root-button {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  line-height: 1.05;
  padding-top: 4px;
  padding-bottom: 4px;
}
.root-button .root-button-sharp {
  font-size: inherit;
}
.root-button .root-button-flat {
  font-size: 0.72em;
  font-weight: 600;
  opacity: 0.72;
  margin-top: 1px;
  letter-spacing: 0;
}
.root-button.selected .root-button-flat {
  opacity: 0.92;
}

.chord-options-empty {
  font-size: 12px;
  color: var(--fg-dim);
  font-style: italic;
}

.chord-builder-actions {
  display: flex;
  align-items: center;
  gap: 10px;
}

/* Actions row: chord name on the left (eats free space via the
 * margin-right: auto on .chord-current below), Strum + Clear pinned
 * to the right. Always present at a fixed height so the matrix below
 * the strum bar never shifts when the player flips between chords
 * with different voicing counts. */
.chord-builder-actions-row {
  min-height: 40px;
}

.chord-builder-actions-row .chord-current {
  margin-right: auto;
}

.chord-builder-actions button {
  background: linear-gradient(160deg, rgba(99, 102, 241, 0.85), rgba(168, 85, 247, 0.75));
  color: #fff;
  border: 1px solid rgba(168, 85, 247, 0.85);
  border-radius: 10px;
  padding: 8px 16px;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.06em;
  cursor: pointer;
}

.chord-builder-actions .chord-clear {
  background: transparent;
  color: var(--fg-dim);
  border: 1px solid var(--border);
}

.chord-current {
  font-size: 13px;
  color: var(--fg-dim);
  font-weight: 600;
  letter-spacing: 0.04em;
}

.chord-current strong {
  color: var(--fg);
  font-size: 16px;
  letter-spacing: 0;
  margin-right: 4px;
}

@media (prefers-reduced-motion: reduce) {
  .fret-cell {
    transition: none !important;
  }
  .fret-cell.active {
    animation: none !important;
  }
}

/* Landscape phones (e.g. iPhone rotated to 844×390) — width is too
 * wide for the `max-width: 640px` mobile rules below, but height is
 * too short for the desktop `flex: 1` layout (which would crush the
 * fretboard down to a few pixels). Treat them like phones for stage
 * sizing so the body grows and the user can scroll, and shrink the
 * fretboard so the squat viewport still has room for the controls
 * underneath. */
@media (orientation: landscape) and (max-height: 540px) {
  /* Same "fixed header" layout as the portrait block — fretboard is
   * pinned at the top of the stage, only `.chord-builder` scrolls. */
  .guitar-stage {
    flex: 1;
    min-height: 0;
    overflow: hidden;
    padding: 6px 16px 16px;
    gap: 10px;
    justify-content: flex-start;
  }
  .fretboard {
    flex: 0 0 auto;
    --label-col-width: 36px;
    --fretboard-pad-top: 12px;
    --fretboard-pad-bottom: 14px;
    --fret-min-cell: 44px;
  }
  .chord-builder {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    box-shadow: inset 0 6px 8px -6px rgba(0, 0, 0, 0.4);
  }
  .fretboard-string {
    height: 26px;
  }
  .fret-cell,
  .fret-cell .note {
    font-size: 9px;
  }
}

@media (max-width: 640px) {
  /* "Fixed header" layout — fretboard stays glued to the top of the
   * available stage, chord-builder is the ONLY scrollable region.
   *
   * The shared `/play/style.css` already gives us a viewport-bounded
   * `.instrument-body` (100dvh, overflow hidden) and a flex-grow
   * stage. Here we just push the scroll one level deeper: the stage
   * stops being scrollable (overflow: hidden) and instead lays its
   * children out as a column where the fretboard takes its natural
   * height (flex: none) and the chord-builder consumes the rest
   * with its own overflow-y. Result: chord shape always visible
   * while the player thumbs through Root / Quality / Voicing /
   * Strum Bar without losing sight of the fingering. */
  .guitar-stage {
    flex: 1;
    min-height: 0;
    overflow: hidden;
    padding: 6px 10px 16px;
    gap: 10px;
    justify-content: flex-start;
  }
  .fretboard {
    flex: 0 0 auto;
  }
  .chord-builder {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    /* Subtle inset shadow at the top edge hints that the area below
     * the fretboard scrolls — without this the seam between
     * "fretboard area" and "scroll area" is invisible until the user
     * actually scrolls. */
    box-shadow: inset 0 6px 8px -6px rgba(0, 0, 0, 0.4);
  }

  /* Mobile fretboard pass — about 20% smaller all round so the chord
   * shape uses ~1/3 of the viewport instead of half, leaving the
   * chord-builder controls (now in their own scroll container) more
   * room to breathe. */
  .fretboard {
    --label-col-width: 32px;
    --fretboard-pad-top: 14px;
    --fretboard-pad-bottom: 18px;
    --fret-min-cell: 42px;
  }
  .fretboard-string {
    height: 28px;
  }
  .fret-cell {
    font-size: 9px;
  }
  .fret-cell .note {
    font-size: 9px;
  }
  .finger-badge {
    font-size: 11px;
  }
  .inlay,
  .inlay.double::before,
  .inlay.double::after {
    width: 8px;
    height: 8px;
  }

  .chord-builder {
    padding: 10px;
  }
  .chord-builder-row {
    gap: 8px;
  }
  .chord-builder-label {
    width: 48px;
    flex-basis: 48px;
    font-size: 10px;
  }
  .chord-options button {
    padding: 6px 10px;
    font-size: 12px;
    min-width: 36px;
  }
  .chord-builder-actions {
    width: 100%;
    margin-left: 0;
    justify-content: flex-end;
  }

  /* Strum Bar mobile pass: keep pads tappable but a touch slimmer so
   * 4-5 fit on an iPhone-SE without horizontal scrolling. */
  .strum-bar {
    padding: 10px;
  }
  .strum-bar-row {
    min-height: 50px;
  }
  .strum-pad {
    min-width: 56px;
    min-height: 50px;
    font-size: 16px;
    padding: 6px 12px;
  }
  .strum-pad-add {
    min-width: 44px;
    min-height: 50px;
    font-size: 22px;
  }
  .strum-bar-hint {
    font-size: 10.5px;
  }

  /* Hide the edit-mode hint on mobile. The 90-char "Editing X · pick
   * Root / Quality / Shape… (Esc) to stop" string wraps to 2-3 lines
   * on a phone-width header, and every edit-mode toggle then yanks
   * the rest of the bar up or down — disorienting in the middle of a
   * strumming session. The teal outline + halo on `.strum-pad.editing`
   * (~line 1014) is already an unmistakable "this pad is armed for
   * editing" cue, and the "(Esc) to stop" half of the hint only makes
   * sense on desktop (no keyboard on mobile anyway). Desktop keeps
   * the verbose hint because the wider header fits it on one line. */
  .strum-bar.editing .strum-bar-hint {
    display: none;
  }

  /* Drop the parenthetical hints on narrow screens so each legend item
   * fits in a compact "icon + word" pair and the row wraps neatly.
   * The full text (1=index, 2=middle, …) is still visible via the
   * long-form description in the "How to play" section just below. */
  .chord-legend {
    gap: 8px 14px;
    font-size: 11px;
  }
  .chord-legend-hint {
    display: none;
  }
}
