/* Guitar Auto-Strum — Phase 3 polished UI */

:root {
  --bg: #0a0705;
  --bg-elevated: #120e0b;
  --bg-panel: #1a1410;
  --bg-panel-deep: #0d0a08;
  --border: rgba(121, 85, 72, 0.45);
  --border-strong: rgba(255, 193, 7, 0.55);
  --amber: #ffc107;
  --amber-dim: rgba(255, 193, 7, 0.16);
  --amber-text: #ffe082;
  --text: rgba(255, 255, 255, 0.9);
  --text-muted: rgba(255, 255, 255, 0.45);
  --text-faint: rgba(255, 255, 255, 0.3);
  --chord-idle: #2a221c;
  --chord-selected: rgba(255, 193, 7, 0.22);
  --danger: #ff8a65;
  --radius: 12px;
  --font: system-ui, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --focus: 0 0 0 2px var(--bg), 0 0 0 4px rgba(255, 193, 7, 0.75);
  --shadow-panel: 0 8px 28px rgba(0, 0, 0, 0.35);

  /* The notch, named.
     `viewport-fit=cover` plus `black-translucent` puts the page *under* the
     status bar and the home indicator — that is what makes the app look full
     screen, and also what put the hamburger behind the clock.
     The indirection is not decoration: `env(safe-area-inset-*)` reads 0 in
     every desktop browser, so a notch cannot be reproduced without the device.
     Overriding these four on `:root` simulates one, which is how every rule
     below was checked. Do not inline `env()` at the use site or that goes
     away. */
  --safe-top: env(safe-area-inset-top, 0px);
  --safe-right: env(safe-area-inset-right, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  --safe-left: env(safe-area-inset-left, 0px);
}

/* ── Introduction / quick guide ────────────────────────── */

/* The help action remains outside the mobile drawer: a first-time visitor
   should not need to know where the menu is before they can learn the app. */
.help-button {
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  flex: 0 0 auto;
  padding: 0;
  border: 1px solid rgba(255, 193, 7, 0.5);
  border-radius: 50%;
  background:
    radial-gradient(circle at 35% 30%, rgba(255, 224, 130, 0.16), transparent 42%),
    rgba(255, 193, 7, 0.07);
  color: var(--amber-text);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.025);
  cursor: pointer;
  font-family: Georgia, "Times New Roman", serif;
  font-size: 1rem;
  font-weight: 700;
  line-height: 1;
  transition: transform 0.18s ease, border-color 0.18s ease,
    background 0.18s ease, box-shadow 0.18s ease;
}

.help-button:hover {
  transform: translateY(-1px);
  border-color: rgba(255, 224, 130, 0.9);
  background: rgba(255, 193, 7, 0.16);
  box-shadow: 0 0 22px rgba(255, 193, 7, 0.14);
}

.help-button[aria-expanded="true"] {
  background: var(--amber);
  color: #1a1005;
}

@media (min-width: 801px) {
  .top-bar-primary {
    grid-template-columns: auto minmax(0, 1fr) auto;
  }

  .help-button {
    grid-column: 3;
  }
}

body.guide-open {
  overflow: hidden;
  touch-action: none;
}

.guide {
  --guide-gold: #d7a83b;
  --guide-gold-bright: #f4d77b;
  --guide-cream: #f4ead7;
  --guide-paper: rgba(244, 234, 215, 0.72);
  --guide-line: rgba(215, 168, 59, 0.24);
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
  flex-direction: column;
  color: var(--guide-cream);
  background:
    radial-gradient(circle at 80% 10%, rgba(135, 69, 26, 0.2), transparent 32rem),
    #080605;
  isolation: isolate;
}

.guide[hidden] {
  display: none !important;
}

.guide::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  opacity: 0.18;
  background-image:
    repeating-linear-gradient(115deg, transparent 0 6px, rgba(255, 255, 255, 0.018) 7px),
    radial-gradient(circle at 20% 30%, rgba(255, 255, 255, 0.035) 0 1px, transparent 1.5px);
  background-size: auto, 9px 9px;
  mix-blend-mode: soft-light;
}

.guide-header {
  display: grid;
  grid-template-columns: minmax(190px, 1fr) auto minmax(190px, 1fr);
  align-items: center;
  gap: 20px;
  flex: 0 0 auto;
  min-height: 68px;
  padding:
    calc(10px + var(--safe-top))
    calc(22px + var(--safe-right))
    10px
    calc(22px + var(--safe-left));
  border-bottom: 1px solid rgba(215, 168, 59, 0.2);
  background: rgba(7, 5, 4, 0.88);
  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.24);
  backdrop-filter: blur(16px);
}

.guide-brand {
  display: inline-flex;
  align-items: center;
  justify-self: start;
  gap: 10px;
  min-width: 0;
  color: inherit;
  text-decoration: none;
}

.guide-brand img {
  flex: 0 0 auto;
}

.guide-brand span {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.guide-brand strong {
  color: var(--guide-gold-bright);
  font-family: Georgia, "Times New Roman", serif;
  font-size: 0.86rem;
  letter-spacing: 0.04em;
  white-space: nowrap;
}

.guide-brand small {
  margin-top: 1px;
  color: rgba(244, 234, 215, 0.4);
  font-size: 0.54rem;
  font-weight: 750;
  letter-spacing: 0.2em;
}

.guide-nav {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  padding: 4px;
  border: 1px solid rgba(215, 168, 59, 0.15);
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.025);
}

.guide-nav button {
  min-height: 34px;
  padding: 6px 14px;
  border: 0;
  border-radius: 999px;
  color: rgba(244, 234, 215, 0.56);
  background: transparent;
  cursor: pointer;
  font-size: 0.75rem;
  font-weight: 700;
  transition: color 0.16s ease, background 0.16s ease;
}

.guide-nav button:hover {
  color: var(--guide-gold-bright);
  background: rgba(215, 168, 59, 0.1);
}

.guide-close {
  display: inline-flex;
  align-items: center;
  justify-self: end;
  gap: 8px;
  min-height: 40px;
  padding: 7px 13px;
  border: 1px solid rgba(215, 168, 59, 0.3);
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.035);
  color: rgba(244, 234, 215, 0.7);
  cursor: pointer;
  font-size: 0.72rem;
  font-weight: 700;
  transition: color 0.16s ease, border-color 0.16s ease,
    background 0.16s ease;
}

.guide-close:hover {
  color: var(--guide-gold-bright);
  border-color: rgba(215, 168, 59, 0.65);
  background: rgba(215, 168, 59, 0.1);
}

.guide-scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior: contain;
  scroll-behavior: smooth;
  scrollbar-color: rgba(215, 168, 59, 0.45) rgba(255, 255, 255, 0.03);
}

.guide-content {
  width: 100%;
}

.guide-anchor {
  scroll-margin-top: 20px;
}

.guide-hero {
  position: relative;
  display: flex;
  align-items: center;
  width: min(100% - 32px, 1440px);
  min-height: clamp(600px, calc(100dvh - 100px), 860px);
  margin: 16px auto 0;
  overflow: hidden;
  border: 1px solid rgba(215, 168, 59, 0.2);
  border-radius: 22px;
  background: #090705;
  box-shadow: 0 30px 90px rgba(0, 0, 0, 0.45);
}

.guide-hero-image,
.guide-hero-shade {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.guide-hero-image {
  object-fit: cover;
  object-position: 60% center;
  filter: saturate(0.92) contrast(1.04);
  animation: guide-image-arrive 1.2s cubic-bezier(0.2, 0.72, 0.2, 1) both;
}

.guide-hero-shade {
  background:
    linear-gradient(90deg, rgba(5, 4, 3, 0.95) 0%, rgba(5, 4, 3, 0.78) 34%, rgba(5, 4, 3, 0.1) 67%, rgba(5, 4, 3, 0.28) 100%),
    linear-gradient(0deg, rgba(5, 4, 3, 0.72) 0%, transparent 32%, rgba(5, 4, 3, 0.12) 100%);
}

.guide-hero-copy {
  position: relative;
  z-index: 1;
  width: min(700px, 58%);
  padding: clamp(42px, 7vw, 108px);
  animation: guide-copy-arrive 0.8s 0.12s cubic-bezier(0.2, 0.72, 0.2, 1) both;
}

.guide-eyebrow,
.guide-kicker,
.guide-step-label {
  margin: 0;
  color: var(--guide-gold);
  font-size: 0.68rem;
  font-weight: 800;
  letter-spacing: 0.22em;
  text-transform: uppercase;
}

.guide-eyebrow {
  display: flex;
  align-items: center;
  gap: 10px;
}

.guide-eyebrow span {
  width: 34px;
  height: 1px;
  background: var(--guide-gold);
  box-shadow: 0 0 10px rgba(215, 168, 59, 0.5);
}

.guide-hero h1 {
  margin: 22px 0 20px;
  color: var(--guide-cream);
  font-family: "Iowan Old Style", "Palatino Linotype", "Book Antiqua", Georgia,
    "Noto Serif KR", serif;
  font-size: clamp(2.8rem, 4.2vw, 5.2rem);
  font-weight: 500;
  letter-spacing: -0.055em;
  line-height: 1.03;
  text-wrap: balance;
}

.guide-hero h1 span,
.guide-hero h1 em {
  display: block;
  white-space: nowrap;
}

.guide-hero h1 em {
  color: var(--guide-gold-bright);
  font-style: normal;
  text-shadow: 0 0 42px rgba(215, 168, 59, 0.18);
}

.guide-hero-lead {
  max-width: 580px;
  margin: 0;
  color: rgba(244, 234, 215, 0.7);
  font-size: clamp(0.96rem, 1.3vw, 1.15rem);
  line-height: 1.9;
}

.guide-hero-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 34px;
}

.guide-action {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  min-height: 50px;
  padding: 12px 20px;
  border-radius: 999px;
  cursor: pointer;
  font-size: 0.84rem;
  font-weight: 800;
  transition: transform 0.18s ease, box-shadow 0.18s ease,
    background 0.18s ease, border-color 0.18s ease;
}

.guide-action:hover {
  transform: translateY(-2px);
}

.guide-action-primary {
  border: 1px solid #f1cf6e;
  color: #170e04;
  background: linear-gradient(135deg, #f4d77b, #c98b24);
  box-shadow: 0 12px 30px rgba(201, 139, 36, 0.22);
}

.guide-action-primary:hover {
  box-shadow: 0 16px 40px rgba(201, 139, 36, 0.32);
}

.guide-action-ghost {
  border: 1px solid rgba(244, 234, 215, 0.24);
  color: rgba(244, 234, 215, 0.78);
  background: rgba(7, 5, 4, 0.46);
  backdrop-filter: blur(8px);
}

.guide-action-ghost:hover {
  border-color: rgba(244, 215, 123, 0.55);
  background: rgba(215, 168, 59, 0.1);
}

.guide-hero-note {
  position: absolute;
  z-index: 1;
  right: clamp(24px, 4vw, 64px);
  bottom: 28px;
  display: flex;
  align-items: center;
  gap: 7px;
  color: rgba(244, 234, 215, 0.45);
  font-size: 0.56rem;
  font-weight: 750;
  letter-spacing: 0.18em;
}

.guide-pulse {
  width: 7px;
  height: 7px;
  margin-right: 3px;
  border-radius: 50%;
  background: var(--guide-gold-bright);
  box-shadow: 0 0 14px rgba(244, 215, 123, 0.72);
  animation: guide-pulse 1.8s ease-in-out infinite;
}

.guide-hero-note i {
  width: 2px;
  height: 11px;
  border-radius: 2px;
  background: var(--guide-gold);
  opacity: 0.45;
  animation: guide-meter 1s ease-in-out infinite alternate;
}

.guide-hero-note i:nth-last-child(3) { animation-delay: -0.35s; }
.guide-hero-note i:nth-last-child(2) { animation-delay: -0.7s; }
.guide-hero-note i:last-child { animation-delay: -0.15s; }

.guide-section {
  width: min(100% - 40px, 1180px);
  margin: 0 auto;
  padding: clamp(92px, 11vw, 160px) 0;
}

.guide-section-heading {
  display: grid;
  grid-template-columns: minmax(0, 0.85fr) minmax(260px, 1fr);
  gap: 16px clamp(30px, 7vw, 100px);
  align-items: end;
  margin-bottom: 54px;
}

.guide-section-heading .guide-kicker {
  grid-column: 1 / -1;
}

.guide-section-heading h2 {
  margin: 0;
  color: var(--guide-cream);
  font-family: "Iowan Old Style", "Palatino Linotype", "Book Antiqua", Georgia,
    "Noto Serif KR", serif;
  font-size: clamp(2rem, 4vw, 3.8rem);
  font-weight: 500;
  letter-spacing: -0.045em;
  line-height: 1.12;
  text-wrap: balance;
}

.guide-section-heading > p:last-child {
  max-width: 500px;
  margin: 0;
  color: var(--guide-paper);
  font-size: 0.98rem;
  line-height: 1.85;
}

.guide-section-heading-compact {
  grid-template-columns: 1fr;
  max-width: 680px;
}

.guide-benefit-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1px;
  overflow: hidden;
  border: 1px solid var(--guide-line);
  border-radius: 18px;
  background: var(--guide-line);
}

.guide-benefit {
  position: relative;
  min-height: 270px;
  padding: 30px;
  background:
    radial-gradient(circle at 100% 0%, rgba(215, 168, 59, 0.06), transparent 52%),
    #100c09;
  transition: background 0.2s ease, transform 0.2s ease;
}

.guide-benefit:hover {
  z-index: 1;
  background:
    radial-gradient(circle at 100% 0%, rgba(215, 168, 59, 0.14), transparent 58%),
    #15100c;
}

.guide-benefit-featured {
  background:
    radial-gradient(circle at 78% 28%, rgba(244, 215, 123, 0.17), transparent 42%),
    linear-gradient(145deg, #2b190e, #100b08 70%);
}

.guide-benefit-number {
  position: absolute;
  top: 20px;
  right: 22px;
  color: rgba(244, 234, 215, 0.2);
  font-family: Georgia, serif;
  font-size: 0.66rem;
  letter-spacing: 0.15em;
}

.guide-benefit-mark {
  display: grid;
  place-items: center;
  width: 46px;
  height: 46px;
  margin-bottom: 42px;
  border: 1px solid rgba(215, 168, 59, 0.35);
  border-radius: 50%;
  color: var(--guide-gold-bright);
  background: rgba(215, 168, 59, 0.08);
  font-family: Georgia, serif;
  font-size: 1.1rem;
}

.guide-benefit h3,
.guide-mode-card h3,
.guide-step h3,
.guide-deeper h3 {
  margin: 0;
  color: var(--guide-cream);
  font-size: 1.08rem;
  line-height: 1.45;
}

.guide-benefit p,
.guide-mode-card p,
.guide-step-copy > p:last-child,
.guide-deeper article p {
  margin: 12px 0 0;
  color: rgba(244, 234, 215, 0.56);
  font-size: 0.86rem;
  line-height: 1.75;
}

.guide-modes {
  width: min(100% - 32px, 1360px);
  padding-inline: clamp(4px, 4vw, 62px);
  border-top: 1px solid rgba(215, 168, 59, 0.12);
  border-bottom: 1px solid rgba(215, 168, 59, 0.12);
  background:
    linear-gradient(90deg, transparent, rgba(93, 46, 23, 0.12), transparent);
}

.guide-mode-stage {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 80px;
}

.guide-mode-card {
  min-width: 0;
  padding: clamp(26px, 4vw, 48px);
  border: 1px solid rgba(215, 168, 59, 0.22);
  border-radius: 18px;
  background:
    linear-gradient(155deg, rgba(255, 255, 255, 0.04), transparent 40%),
    rgba(12, 9, 7, 0.84);
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.22);
}

.guide-mode-topline {
  display: flex;
  align-items: center;
  gap: 9px;
  color: var(--guide-gold-bright);
  font-size: 0.75rem;
  font-weight: 850;
  letter-spacing: 0.18em;
}

.guide-mode-topline small {
  margin-left: auto;
  color: rgba(244, 234, 215, 0.38);
  font-size: 0.65rem;
  font-weight: 650;
  letter-spacing: 0;
}

.guide-mode-light {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: #81c784;
  box-shadow: 0 0 12px rgba(129, 199, 132, 0.72);
}

.guide-live-chords,
.guide-song-bars {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 8px;
  margin: 46px 0 32px;
}

.guide-live-chords span,
.guide-song-bars span {
  position: relative;
  display: grid;
  place-items: center;
  min-height: 68px;
  border: 1px solid rgba(244, 234, 215, 0.14);
  border-radius: 10px;
  color: rgba(244, 234, 215, 0.68);
  background: rgba(255, 255, 255, 0.035);
  font-family: Georgia, serif;
  font-size: 1rem;
  font-weight: 700;
}

.guide-live-chords .is-active,
.guide-song-bars .is-playing {
  border-color: rgba(244, 215, 123, 0.82);
  color: var(--guide-gold-bright);
  background: rgba(215, 168, 59, 0.18);
  box-shadow: inset 0 0 28px rgba(215, 168, 59, 0.08);
}

.guide-song-bars span small {
  position: absolute;
  top: 6px;
  left: 8px;
  color: rgba(244, 234, 215, 0.3);
  font-family: var(--font);
  font-size: 0.55rem;
}

.guide-mode-divider {
  position: absolute;
  top: 50%;
  left: 50%;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 10px;
  width: 80px;
  height: 160px;
  transform: translate(-50%, -50%);
  pointer-events: none;
}

.guide-mode-divider span {
  width: 100%;
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(215, 168, 59, 0.42), transparent);
}

.guide-mode-divider span:nth-child(3) {
  box-shadow: 0 0 14px rgba(215, 168, 59, 0.34);
}

.guide-quickstart {
  padding-bottom: clamp(80px, 9vw, 130px);
}

.guide-steps {
  margin: 0;
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--guide-line);
}

.guide-step {
  display: grid;
  grid-template-columns: 90px minmax(260px, 0.9fr) minmax(340px, 1.1fr);
  gap: clamp(24px, 4vw, 64px);
  align-items: center;
  min-height: 270px;
  padding: 42px 0;
  border-bottom: 1px solid var(--guide-line);
}

.guide-step-index {
  align-self: stretch;
  display: flex;
  flex-direction: column;
  align-items: center;
  color: var(--guide-gold);
  font-family: Georgia, serif;
  font-size: 0.86rem;
  letter-spacing: 0.16em;
}

.guide-step-index span {
  display: grid;
  place-items: center;
  width: 52px;
  height: 52px;
  border: 1px solid rgba(215, 168, 59, 0.42);
  border-radius: 50%;
  background: rgba(215, 168, 59, 0.06);
}

.guide-step-index i {
  width: 1px;
  flex: 1;
  min-height: 70px;
  margin-top: 14px;
  background: linear-gradient(rgba(215, 168, 59, 0.32), transparent);
}

.guide-step h3 {
  margin-top: 12px;
  font-size: clamp(1.25rem, 2vw, 1.7rem);
}

.guide-step-copy b {
  color: rgba(244, 215, 123, 0.86);
  font-weight: 750;
}

.guide-demo {
  position: relative;
  overflow: hidden;
  min-height: 156px;
  padding: 18px;
  border: 1px solid rgba(215, 168, 59, 0.22);
  border-radius: 14px;
  background:
    radial-gradient(circle at 85% 10%, rgba(215, 168, 59, 0.1), transparent 42%),
    linear-gradient(160deg, #17100c, #0d0a08);
  box-shadow: 0 18px 42px rgba(0, 0, 0, 0.2);
}

.guide-demo::after {
  content: "";
  position: absolute;
  inset: auto -10% 18px;
  height: 1px;
  opacity: 0.25;
  background: repeating-linear-gradient(90deg, var(--guide-gold) 0 12%, transparent 12% 16%);
}

.guide-settings-demo {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 9px;
}

.guide-settings-demo > div {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 7px;
  min-width: 0;
  padding: 13px;
  border: 1px solid rgba(244, 234, 215, 0.12);
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.035);
}

.guide-settings-demo .guide-demo-wide {
  grid-column: span 2;
}

.guide-demo small {
  color: rgba(244, 234, 215, 0.34);
  font-size: 0.53rem;
  font-weight: 800;
  letter-spacing: 0.14em;
}

.guide-settings-demo strong {
  overflow: hidden;
  color: rgba(244, 234, 215, 0.82);
  font-size: 0.78rem;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.guide-chords-demo {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  align-items: center;
  gap: 8px;
}

.guide-chords-demo > span {
  position: relative;
  display: grid;
  place-items: center;
  min-height: 78px;
  border: 1px solid rgba(244, 234, 215, 0.12);
  border-radius: 9px;
  color: rgba(244, 234, 215, 0.68);
  background: rgba(255, 255, 255, 0.045);
  font-family: Georgia, serif;
  font-weight: 700;
}

.guide-chords-demo > span small {
  position: absolute;
  top: 6px;
  left: 7px;
}

.guide-chords-demo > .is-active {
  border-color: rgba(244, 215, 123, 0.78);
  color: var(--guide-gold-bright);
  background: rgba(215, 168, 59, 0.17);
}

.guide-mode-demo {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 20px;
}

.guide-demo-switch {
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-self: flex-start;
  padding: 4px;
  border: 1px solid rgba(244, 234, 215, 0.12);
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.28);
}

.guide-demo-switch span {
  padding: 7px 18px;
  border-radius: 999px;
  color: rgba(244, 234, 215, 0.42);
  font-size: 0.7rem;
  font-weight: 750;
}

.guide-demo-switch .is-active {
  color: #1a1005;
  background: var(--guide-gold-bright);
}

.guide-demo-bars {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 6px;
}

.guide-demo-bars span {
  padding: 12px 8px;
  border: 1px solid rgba(244, 234, 215, 0.12);
  border-radius: 7px;
  color: rgba(244, 234, 215, 0.66);
  text-align: center;
  font-family: Georgia, serif;
  font-size: 0.75rem;
}

.guide-play-demo {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
}

.guide-demo-play {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin-right: 10px;
  padding: 13px 24px;
  border: 1px solid var(--guide-gold-bright);
  border-radius: 999px;
  color: #1a1005;
  background: linear-gradient(135deg, #f4d77b, #c98b24);
  font-size: 0.85rem;
  font-weight: 850;
  box-shadow: 0 0 28px rgba(215, 168, 59, 0.17);
}

.guide-count-label {
  color: rgba(244, 234, 215, 0.3);
  font-size: 0.52rem;
  font-weight: 800;
  letter-spacing: 0.14em;
}

.guide-count {
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border: 1px solid rgba(244, 234, 215, 0.14);
  border-radius: 50%;
  color: rgba(244, 234, 215, 0.4);
  font-size: 0.66rem;
}

.guide-count.is-done {
  color: var(--guide-gold);
  border-color: rgba(215, 168, 59, 0.45);
}

.guide-count.is-now {
  color: #1a1005;
  border-color: var(--guide-gold-bright);
  background: var(--guide-gold-bright);
  box-shadow: 0 0 18px rgba(244, 215, 123, 0.46);
}

.guide-save-demo {
  display: flex;
  flex-wrap: wrap;
  align-content: center;
  justify-content: center;
  gap: 8px;
}

.guide-save-demo > span {
  min-width: 88px;
  padding: 11px 18px;
  border: 1px solid rgba(244, 234, 215, 0.16);
  border-radius: 999px;
  color: rgba(244, 234, 215, 0.63);
  text-align: center;
  font-size: 0.72rem;
  font-weight: 750;
}

.guide-save-demo > span.is-active {
  border-color: rgba(244, 215, 123, 0.74);
  color: var(--guide-gold-bright);
  background: rgba(215, 168, 59, 0.12);
}

.guide-save-demo > small {
  flex-basis: 100%;
  margin-top: 10px;
  text-align: center;
  letter-spacing: 0.18em;
}

.guide-deeper {
  width: 100%;
  max-width: none;
  padding-inline: max(20px, calc((100% - 1180px) / 2));
  background:
    radial-gradient(circle at 10% 100%, rgba(109, 52, 22, 0.2), transparent 32rem),
    linear-gradient(180deg, rgba(255, 255, 255, 0.018), transparent);
  border-top: 1px solid rgba(215, 168, 59, 0.12);
}

.guide-deeper-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
}

.guide-deeper article {
  min-height: 250px;
  padding: 30px;
  border: 1px solid rgba(215, 168, 59, 0.19);
  border-radius: 15px;
  background: rgba(11, 8, 6, 0.68);
}

.guide-deeper article > span {
  display: block;
  margin-bottom: 70px;
  color: var(--guide-gold-bright);
  font-family: Georgia, serif;
  font-size: 1.7rem;
}

/* Notices. Deliberately the quietest section in the guide — smaller type and
   less contrast than `.guide-deeper`, because this is reference the reader
   consults rather than a feature being sold. */
.guide-notice {
  padding-top: 0;
}

.guide-notice-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
}

.guide-notice article {
  padding: 26px 28px;
  border: 1px solid rgba(215, 168, 59, 0.14);
  border-radius: 15px;
  background: rgba(11, 8, 6, 0.5);
}

.guide-notice-kicker {
  margin: 0 0 14px;
  color: rgba(215, 168, 59, 0.62);
  font-size: 0.56rem;
  font-weight: 750;
  letter-spacing: 0.2em;
}

.guide-notice h3 {
  margin: 0 0 12px;
  color: var(--guide-cream);
  font-size: 1.02rem;
  font-weight: 600;
  letter-spacing: -0.01em;
}

.guide-notice article p:last-child {
  margin: 0;
  color: rgba(244, 234, 215, 0.56);
  font-size: 0.87rem;
  line-height: 1.85;
}

/* The technology list wraps as chips rather than sitting in a row, so a name
   added later takes a second line instead of overflowing. */
.guide-notice-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin: 18px 0 0;
}

.guide-notice-foot span {
  padding: 5px 12px;
  border: 1px solid rgba(215, 168, 59, 0.16);
  border-radius: 999px;
  color: rgba(244, 234, 215, 0.5);
  font-size: 0.66rem;
  font-weight: 700;
  letter-spacing: 0.06em;
}

.guide-notice-foot small {
  flex: 1 1 260px;
  color: rgba(244, 234, 215, 0.32);
  font-size: 0.74rem;
  line-height: 1.7;
}

.guide-finale {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  min-height: 600px;
  padding: 150px 24px 120px;
  overflow: hidden;
  text-align: center;
  background:
    radial-gradient(circle at 50% 65%, rgba(136, 67, 24, 0.26), transparent 28rem),
    #080605;
}

.guide-finale h2 {
  margin: 18px 0 14px;
  color: var(--guide-cream);
  font-family: "Iowan Old Style", "Palatino Linotype", "Book Antiqua", Georgia,
    "Noto Serif KR", serif;
  font-size: clamp(2.2rem, 5vw, 4.7rem);
  font-weight: 500;
  letter-spacing: -0.05em;
}

.guide-finale > p:not(.guide-kicker) {
  max-width: 620px;
  margin: 0;
  color: rgba(244, 234, 215, 0.58);
  line-height: 1.8;
}

.guide-finale-action {
  margin-top: 36px;
}

.guide-finale-lines {
  position: absolute;
  top: 74px;
  left: 50%;
  display: flex;
  flex-direction: column;
  gap: 12px;
  width: min(760px, 85vw);
  transform: translateX(-50%) perspective(240px) rotateX(56deg);
  opacity: 0.28;
}

.guide-finale-lines i {
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--guide-gold), transparent);
}

.guide-links {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px 20px;
  padding: 24px calc(24px + var(--safe-right)) 20px calc(24px + var(--safe-left));
  border-top: 1px solid rgba(215, 168, 59, 0.14);
  font-size: 0.85rem;
}

.guide-links a {
  color: rgba(244, 234, 215, 0.62);
  text-decoration: none;
  white-space: nowrap;
}

.guide-links a:hover,
.guide-links a:focus-visible {
  color: var(--guide-gold-bright);
}

.guide-footer {
  display: flex;
  justify-content: space-between;
  gap: 20px;
  padding:
    20px
    calc(24px + var(--safe-right))
    calc(20px + var(--safe-bottom))
    calc(24px + var(--safe-left));
  border-top: 1px solid rgba(215, 168, 59, 0.14);
  color: rgba(244, 234, 215, 0.3);
  font-size: 0.56rem;
  font-weight: 750;
  letter-spacing: 0.18em;
  text-transform: uppercase;
}

@keyframes guide-image-arrive {
  from { opacity: 0; transform: scale(1.035); }
  to { opacity: 1; transform: scale(1); }
}

@keyframes guide-copy-arrive {
  from { opacity: 0; transform: translateY(24px); }
  to { opacity: 1; transform: translateY(0); }
}

@keyframes guide-pulse {
  0%, 100% { opacity: 0.45; transform: scale(0.8); }
  50% { opacity: 1; transform: scale(1); }
}

@keyframes guide-meter {
  from { height: 5px; opacity: 0.25; }
  to { height: 16px; opacity: 0.72; }
}

@media (max-width: 900px) {
  .guide-header {
    grid-template-columns: 1fr auto;
  }

  .guide-nav {
    display: none;
  }

  .guide-hero-copy {
    width: min(680px, 76%);
  }

  .guide-benefit-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .guide-mode-stage {
    gap: 24px;
  }

  .guide-mode-divider {
    display: none;
  }

  .guide-step {
    grid-template-columns: 68px minmax(230px, 0.85fr) minmax(300px, 1.15fr);
    gap: 24px;
  }
}

@media (max-width: 800px) {
  .help-button {
    width: 44px;
    height: 44px;
    border-radius: 10px;
    font-size: 1.08rem;
  }

  .guide-header {
    min-height: 62px;
    padding:
      calc(8px + var(--safe-top))
      calc(12px + var(--safe-right))
      8px
      calc(12px + var(--safe-left));
  }

  .guide-brand strong {
    font-size: 0.78rem;
  }

  .guide-brand small {
    display: none;
  }

  .guide-close {
    width: 42px;
    height: 42px;
    padding: 0;
    border-radius: 11px;
  }

  .guide-close-label {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
  }

  .guide-anchor {
    scroll-margin-top: 12px;
  }

  .guide-hero {
    align-items: flex-start;
    width: calc(100% - 20px);
    min-height: min(760px, calc(100dvh - 82px));
    margin-top: 10px;
    border-radius: 16px;
  }

  .guide-hero-image {
    object-position: 63% center;
  }

  .guide-hero-shade {
    background:
      linear-gradient(180deg, rgba(5, 4, 3, 0.94) 0%, rgba(5, 4, 3, 0.68) 47%, rgba(5, 4, 3, 0.24) 72%, rgba(5, 4, 3, 0.82) 100%),
      linear-gradient(90deg, rgba(5, 4, 3, 0.54), transparent 70%);
  }

  .guide-hero-copy {
    width: 100%;
    padding: clamp(34px, 10vw, 54px) 26px;
  }

  .guide-hero h1 {
    margin-top: 18px;
    font-size: clamp(2rem, 8.9vw, 4.2rem);
  }

  .guide-hero-lead br {
    display: none;
  }

  .guide-hero-note {
    right: 20px;
    bottom: 18px;
  }

  .guide-section {
    width: calc(100% - 32px);
    padding: 84px 0;
  }

  .guide-section-heading {
    grid-template-columns: 1fr;
    gap: 20px;
    margin-bottom: 38px;
  }

  .guide-section-heading h2 {
    font-size: clamp(2rem, 9.5vw, 3.1rem);
  }

  .guide-benefit {
    min-height: 250px;
    padding: 25px;
  }

  .guide-mode-stage {
    grid-template-columns: 1fr;
  }

  .guide-modes {
    width: 100%;
    padding-inline: 16px;
  }

  .guide-step {
    grid-template-columns: 52px minmax(0, 1fr);
    min-height: 0;
    gap: 18px;
    padding: 42px 0;
  }

  .guide-step-index {
    grid-row: 1 / span 2;
  }

  .guide-step-index span {
    width: 46px;
    height: 46px;
  }

  .guide-demo {
    grid-column: 2;
    width: 100%;
  }

  .guide-deeper {
    width: 100%;
    padding-inline: 16px;
  }

  .guide-deeper-grid {
    grid-template-columns: 1fr;
  }

  .guide-deeper article {
    min-height: 210px;
  }

  .guide-deeper article > span {
    margin-bottom: 48px;
  }

  .guide-notice-grid {
    grid-template-columns: 1fr;
  }

  .guide-notice article {
    padding: 22px;
  }
}

@media (max-width: 560px) {
  .guide-brand img {
    width: 25px;
    height: 25px;
  }

  .guide-brand strong {
    font-size: 0.72rem;
  }

  .guide-hero {
    min-height: 690px;
  }

  .guide-hero-copy {
    padding-inline: 22px;
  }

  .guide-eyebrow {
    font-size: 0.56rem;
    letter-spacing: 0.16em;
  }

  .guide-eyebrow span {
    width: 22px;
  }

  .guide-hero-actions {
    flex-direction: column;
    align-items: stretch;
  }

  .guide-action {
    width: 100%;
  }

  .guide-benefit-grid {
    grid-template-columns: 1fr;
  }

  .guide-benefit {
    min-height: 225px;
  }

  .guide-benefit-mark {
    margin-bottom: 30px;
  }

  .guide-mode-card {
    padding: 24px 20px;
  }

  .guide-mode-topline small {
    display: none;
  }

  .guide-live-chords,
  .guide-song-bars {
    margin: 34px 0 26px;
  }

  .guide-live-chords span,
  .guide-song-bars span {
    min-height: 58px;
  }

  .guide-step {
    grid-template-columns: 44px minmax(0, 1fr);
    gap: 14px;
  }

  .guide-step-index span {
    width: 42px;
    height: 42px;
    font-size: 0.72rem;
  }

  .guide-settings-demo {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .guide-settings-demo .guide-demo-wide {
    grid-column: span 1;
  }

  .guide-chords-demo {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .guide-chords-demo > span {
    min-height: 60px;
  }

  .guide-chords-demo > span:nth-child(n + 4) {
    display: none;
  }

  .guide-play-demo {
    flex-wrap: wrap;
  }

  .guide-demo-play {
    flex-basis: 100%;
    margin: 0 0 4px;
  }

  .guide-finale {
    min-height: 540px;
    padding-inline: 20px;
  }

  .guide-footer {
    flex-direction: column;
    align-items: center;
    text-align: center;
  }
}

@media (prefers-reduced-motion: reduce) {
  .guide *,
  .guide *::before,
  .guide *::after {
    scroll-behavior: auto !important;
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

html,
body {
  height: 100%;
  margin: 0;
}

body {
  font-family: var(--font);
  background:
    radial-gradient(ellipse 80% 50% at 50% -10%, rgba(255, 160, 0, 0.07), transparent),
    var(--bg);
  color: var(--text);
  line-height: 1.4;
  -webkit-font-smoothing: antialiased;
}

body.menu-open {
  overflow: hidden;
  touch-action: none;
}

button,
select {
  font: inherit;
  color: inherit;
}

button:disabled,
select:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}

:focus {
  outline: none;
}

:focus-visible {
  outline: none;
  box-shadow: var(--focus);
}

.app {
  min-height: 100%;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  /* Only the bottom. The sides belong to whichever child touches the edge —
     the top bar has its own background to carry under the notch, and padding
     here would inset that background too. */
  padding-bottom: var(--safe-bottom);
}

.app[data-transport="countdown"] {
  --transport-accent: #ffb74d;
}

.app[data-transport="playing"] {
  --transport-accent: #81c784;
}

.app[data-transport="off"] {
  --transport-accent: var(--text-muted);
}

/* ── Header ─────────────────────────────────────────────── */

/* The padding is built from variables rather than written as a shorthand so
   the narrow-screen rule can move the numbers without having to restate the
   safe-area terms. A `padding:` shorthand further down the file would drop
   them silently, and the symptom — a hamburger under the iPhone clock — does
   not look like a CSS shorthand problem. */
.top-bar {
  --bar-pad-y: 10px;
  --bar-pad-bottom: var(--bar-pad-y);
  --bar-pad-x: 18px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 8px 12px;
  min-height: 56px;
  padding:
    calc(var(--bar-pad-y) + var(--safe-top))
    calc(var(--bar-pad-x) + var(--safe-right))
    var(--bar-pad-bottom)
    calc(var(--bar-pad-x) + var(--safe-left));
  border-bottom: 1px solid var(--border);
  position: relative;
  z-index: 40;
}

/* The blur lives on a pseudo-element, not on `.top-bar` itself. A
   `backdrop-filter` makes its element the containing block for every
   `position: fixed` descendant — which shrank the mobile drawer from the
   viewport to the header's own 120px box, so only its first row survived the
   drawer's `overflow-x: clip` and the rest was cut away. */
.top-bar::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: rgba(0, 0, 0, 0.4);
  backdrop-filter: blur(8px);
  pointer-events: none;
}

/* Row 1: brand + menu chrome / desktop actions */
.top-bar-primary {
  display: flex;
  flex: 1 1 auto;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  min-width: 0;
}

/* Desktop: menu chrome is invisible; contents stay in the bar */
.menu-toggle,
.menu-close,
.top-bar-menu-header,
.top-bar-menu-backdrop {
  display: none;
}

.top-bar-menu {
  display: flex;
  flex: 1 1 auto;
  align-items: center;
  justify-content: flex-end;
  gap: 12px;
  min-width: 0;
}

.top-bar-menu-panel {
  display: flex;
  flex: 1 1 auto;
  align-items: center;
  justify-content: flex-end;
  gap: 12px;
  min-width: 0;
  width: 100%;
}

/* Save / Load / New (desktop: with menu actions; mobile: inside drawer) */
.song-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 8px;
}

/* Song title — always outside the hamburger, and always on its own row.
   Centred *over* row 1 it sat on top of the last menu button as soon as the
   button row grew; a row of its own cannot collide with anything. */
.song-name-row {
  display: flex;
  flex: 1 0 100%;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-width: 0;
  order: 1;
  padding-top: 2px;
  border-top: 1px solid rgba(255, 255, 255, 0.05);
}

.song-name-button {
  appearance: none;
  border: 1px solid transparent;
  background: transparent;
  color: var(--amber-text);
  font-size: 1rem;
  font-weight: 750;
  letter-spacing: 0.04em;
  padding: 6px 12px;
  border-radius: 8px;
  cursor: text;
  max-width: min(280px, 40vw);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.song-name-button:hover {
  border-color: rgba(255, 193, 7, 0.35);
  background: rgba(255, 193, 7, 0.08);
}

.song-name-input {
  min-width: 10rem;
  max-width: min(280px, 40vw);
  min-height: 36px;
  padding: 6px 12px;
  border-radius: 8px;
  border: 1px solid rgba(255, 193, 7, 0.55);
  background: var(--bg-panel);
  color: var(--amber-text);
  font-size: 1rem;
  font-weight: 700;
}

.song-dirty-dot {
  color: var(--amber);
  font-size: 0.65rem;
  line-height: 1;
  flex-shrink: 0;
}

/* Desktop: row 1 — brand | Save/Load/New + actions · row 2 — song name */
@media (min-width: 801px) {
  .top-bar {
    gap: 6px 12px;
  }

  .top-bar-primary {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    align-items: center;
    gap: 12px;
    width: 100%;
    min-width: 0;
  }

  .top-bar-menu {
    grid-column: 2;
    justify-content: flex-end;
  }

  .help-button {
    grid-column: 3;
  }

  .top-bar-menu-panel {
    justify-content: flex-end;
    gap: 10px;
  }

  .top-bar-menu .song-bar {
    margin-right: auto;
    margin-left: clamp(0px, 6vw, 96px);
  }

  .song-name-row .song-name-button,
  .song-name-row .song-name-input {
    max-width: min(420px, 60vw);
  }
}

.header-button.is-emphasis {
  border-color: rgba(255, 193, 7, 0.85);
  box-shadow: 0 0 0 1px rgba(255, 193, 7, 0.2);
}

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
}

/* No plate behind it: the icon is a gold pick on transparent, so it carries
   its own shape and outline. The amber rounded square this used to sit in
   would read as a badge behind a badge. */
.brand-icon {
  width: 2rem;
  height: 2rem;
  object-fit: contain;
  flex-shrink: 0;
}

.brand-text {
  min-width: 0;
}

.brand-title {
  margin: 0;
  font-size: 0.95rem;
  font-weight: 650;
  letter-spacing: 0.04em;
  color: var(--amber-text);
}

.brand-sub {
  margin: 1px 0 0;
  font-size: 0.7rem;
  color: var(--text-faint);
  letter-spacing: 0.02em;
}

.work-mode {
  display: flex;
  flex-shrink: 0;
  margin-left: 8px;
  padding: 2px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.25);
}

.work-mode-btn {
  appearance: none;
  border: 0;
  background: transparent;
  color: var(--text-muted);
  font-size: 0.72rem;
  font-weight: 650;
  letter-spacing: 0.04em;
  padding: 6px 10px;
  border-radius: 999px;
  cursor: pointer;
}

.work-mode-btn.is-active {
  background: rgba(255, 193, 7, 0.18);
  color: var(--amber-text);
}

.work-mode-short {
  display: none;
}

.app[data-work-mode="score"] .play-panel,
.app[data-work-mode="score"] .transport-panel,
.app[data-work-mode="score"] .chords-panel,
.app[data-work-mode="score"] .prog-panel,
.app[data-work-mode="score"] .song-name-row,
.app[data-work-mode="score"] .visualizer-actions,
.app[data-work-mode="score"] .preview-hint,
.app[data-work-mode="score"] .chord-caption,
.app[data-work-mode="score"] .voicing-hint {
  display: none;
}

.top-bar-actions {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}

.transport-pill {
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 4px 10px;
  border-radius: 999px;
  border: 1px solid color-mix(in srgb, var(--transport-accent) 50%, transparent);
  color: var(--transport-accent);
  background: color-mix(in srgb, var(--transport-accent) 12%, transparent);
  transition: color 0.15s ease, border-color 0.15s ease, background 0.15s ease;
}

/* ── Main ───────────────────────────────────────────────── */

/* Same variable trick as `.top-bar`: the sides matter when the phone is held
   sideways and the notch eats one of them. */
.main {
  --main-pad: 18px;
  --main-pad-x: var(--main-pad);
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 18px;
  padding:
    var(--main-pad)
    calc(var(--main-pad-x) + var(--safe-right))
    var(--main-pad)
    calc(var(--main-pad-x) + var(--safe-left));
  max-width: 1120px;
  width: 100%;
  margin: 0 auto;
}

.visualizer-panel {
  position: relative;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: linear-gradient(180deg, var(--bg-panel), var(--bg-panel-deep));
  overflow: hidden;
  min-height: 220px;
  height: clamp(200px, 32vh, 340px);
  box-shadow: var(--shadow-panel);
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
}

.app[data-transport="playing"] .visualizer-panel {
  border-color: rgba(129, 199, 132, 0.35);
  box-shadow:
    var(--shadow-panel),
    0 0 0 1px rgba(129, 199, 132, 0.08),
    0 0 40px rgba(255, 193, 7, 0.06);
}

.app[data-transport="countdown"] .visualizer-panel {
  border-color: rgba(255, 183, 77, 0.4);
}

#strings-canvas {
  display: block;
  width: 100%;
  height: 100%;
  touch-action: manipulation;
  cursor: default;
}

/* Idle + chord selected: body-zone preview is available */
#strings-canvas.is-previewable {
  cursor: crosshair;
}

#strings-canvas.is-previewable.is-over-body {
  cursor: pointer;
}

#strings-canvas:not(.is-previewable) {
  cursor: default;
}

.visualizer-overlay {
  position: absolute;
  /* Near the body (left); open-string names stay on the canvas right edge */
  left: 14px;
  bottom: 12px;
  text-align: left;
  pointer-events: none;
  /* Keep caption out of the sound-hole band a little */
  max-width: min(42%, 280px);
}

.visualizer-actions {
  position: absolute;
  top: 10px;
  right: 12px;
  z-index: 2;
  pointer-events: auto;
}

.preview-arpeggio-button {
  appearance: none;
  border: 1px solid rgba(255, 193, 7, 0.35);
  background: rgba(20, 12, 8, 0.72);
  color: rgba(255, 224, 130, 0.92);
  font: inherit;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  padding: 0.4rem 0.7rem;
  border-radius: 999px;
  cursor: pointer;
  backdrop-filter: blur(6px);
  transition:
    background 0.15s ease,
    border-color 0.15s ease,
    opacity 0.15s ease,
    color 0.15s ease;
}

.preview-arpeggio-button:hover:not(:disabled) {
  background: rgba(255, 193, 7, 0.16);
  border-color: rgba(255, 193, 7, 0.55);
}

.preview-arpeggio-button:active:not(:disabled) {
  background: rgba(255, 193, 7, 0.24);
}

.preview-arpeggio-button:disabled {
  opacity: 0.35;
  cursor: not-allowed;
  border-color: rgba(255, 255, 255, 0.1);
  color: var(--text-faint);
}

.app[data-transport="playing"] .preview-arpeggio-button,
.app[data-transport="countdown"] .preview-arpeggio-button {
  opacity: 0.3;
}

.preview-hint {
  margin: 6px 0 0;
  font-size: 0.68rem;
  line-height: 1.35;
  color: rgba(255, 224, 130, 0.55);
  max-width: 16rem;
  transition: opacity 0.15s ease, color 0.15s ease;
}

.app[data-transport="playing"] .preview-hint,
.app[data-transport="countdown"] .preview-hint,
.preview-hint.is-hidden {
  opacity: 0;
}

.chord-caption {
  margin: 0;
  font-size: clamp(1.4rem, 3vw, 2rem);
  font-weight: 750;
  letter-spacing: 0.04em;
  color: rgba(255, 224, 130, 0.75);
  text-shadow: 0 2px 12px rgba(0, 0, 0, 0.55);
  transition: color 0.15s ease, transform 0.15s ease;
}

.app[data-transport="playing"] .chord-caption {
  color: rgba(255, 236, 179, 0.92);
}

.voicing-hint {
  margin: 4px 0 0;
  font-size: 0.7rem;
  font-family: ui-monospace, "Cascadia Mono", Consolas, monospace;
  letter-spacing: 0.12em;
  color: var(--text-faint);
}

.count-in-overlay {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  background: rgba(8, 5, 3, 0.35);
  pointer-events: none;
  animation: fade-in 0.2s ease;
}

.count-in-overlay[hidden] {
  display: none;
}

.count-in-big {
  font-size: clamp(4rem, 14vw, 7rem);
  font-weight: 800;
  letter-spacing: 0.06em;
  color: var(--amber);
  text-shadow: 0 0 40px rgba(255, 193, 7, 0.35);
  font-variant-numeric: tabular-nums;
  animation: count-pulse 0.9s ease;
}

@keyframes count-pulse {
  0% {
    transform: scale(0.7);
    opacity: 0.4;
  }
  40% {
    transform: scale(1.05);
    opacity: 1;
  }
  100% {
    transform: scale(1);
    opacity: 0.92;
  }
}

@keyframes fade-in {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

/* ── Play panel ─────────────────────────────────────────────────────────────
   Play, and the four cues that decide what happens at the next boundary. Its
   own panel because it is the one control a player uses *while playing*, and
   everything else on screen is something they set up beforehand.           */

.play-panel {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

/* Play fills the row and Pause sits inside it. Side by side they would be two
   flex items at min-content width, and the secondary one would decide where
   the primary one starts — see `song-load-dialog.js` for the same fix. */
.play-row {
  position: relative;
  display: flex;
}

.play-row .play-button {
  flex: 1 1 auto;
  width: 100%;
}

.play-pause-button {
  position: absolute;
  top: 50%;
  right: 8px;
  transform: translateY(-50%);
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  padding: 0;
  border: 1px solid rgba(255, 193, 7, 0.45);
  border-radius: 999px;
  background: rgba(20, 14, 6, 0.55);
  color: var(--amber);
  cursor: pointer;
  transition:
    background 0.12s ease,
    border-color 0.12s ease,
    color 0.12s ease;
}

.play-pause-button:hover {
  background: rgba(255, 193, 7, 0.18);
}

/* Held. The button is the only thing on screen that says so, since the panel
   deliberately keeps reading "Stop" — the song is still loaded, not ended. */
.play-pause-button.is-active {
  border-color: rgba(255, 193, 7, 0.9);
  background: rgba(255, 193, 7, 0.24);
}

/* Four equal tracks, not a flex row. A flex item will not shrink below its
   min-content width, so a longer label pushes the last one off a phone; a
   `1fr` track cannot be pushed by its contents at all. Measured at 375px: the
   four come to 279px of the 351px available. */
.play-cues {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 6px;
}

.cue-button {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  position: relative;
  min-width: 0;
  padding: 6px 4px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.02);
  color: var(--text-muted);
  font: inherit;
  font-size: 0.7rem;
  letter-spacing: 0.02em;
  cursor: pointer;
  transition:
    border-color 0.15s ease,
    background 0.15s ease,
    color 0.15s ease;
}

.cue-button:not(:disabled):hover {
  border-color: rgba(255, 193, 7, 0.45);
  color: var(--amber-text);
}

.cue-button:disabled {
  opacity: 0.4;
  cursor: default;
}

/* Waiting for its boundary. The label never changes — swapping the word would
   reflow four tracks mid-song — so the frame carries the whole message. */
.cue-button.is-armed {
  border-color: rgba(255, 193, 7, 0.85);
  background: rgba(255, 193, 7, 0.14);
  color: var(--amber);
}

.cue-glyph {
  display: grid;
  place-items: center;
  width: 18px;
  height: 18px;
}

/* Drawn, not typed. The obvious spelling of a repeat is `𝄆 𝄇` (U+1D106/7),
   which is in the Musical Symbols block and absent from the default iOS and
   Android fonts — it renders as two empty boxes on exactly the phones this
   panel is for. */
.cue-glyph svg {
  width: 100%;
  height: 100%;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.cue-label {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* How many more passes are queued. Hidden until it means something: `+1` on an
   idle button would read as the count rather than as the offer. */
.cue-badge {
  position: absolute;
  top: 2px;
  right: 4px;
  font-size: 0.6rem;
  font-weight: 700;
  line-height: 1;
  opacity: 0;
}

.cue-button.is-armed .cue-badge {
  opacity: 1;
}

/* ── Transport / settings ───────────────────────────────── */

.transport-panel {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.transport-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 16px 20px;
}

/* Play mode + instrument: song settings, so they live with the transport
   rather than in the app menu. Pushed to the far end of the row. */
.transport-instrument {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-left: auto;
  flex: 0 0 auto;
}

.transport-instrument select {
  min-width: 9.5rem;
}

/* Shown at every width. It used to be phone-only, on the assumption that a
   bigger screen has room for the settings — but an iPad has room and still has
   a player looking at the neck, and a row of selects under the transport is in
   the way whatever the width. What differs by width is the *policy* around it
   (see shell-chrome.js), not whether the control exists. */
.transport-details {
  display: block;
}

/* At any width, collapsing folds the settings away. Only these — the narrow
   layout also hides the meta and instrument rows, but that is a phone running
   out of room, not what the control means. */
.transport-panel.is-collapsed .transport-details {
  display: none;
}

.play-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-width: 8.5rem;
  min-height: 48px;
  padding: 12px 22px;
  border-radius: 999px;
  border: 1px solid rgba(255, 193, 7, 0.75);
  background: linear-gradient(
    180deg,
    rgba(255, 193, 7, 0.22),
    rgba(255, 193, 7, 0.1)
  );
  color: var(--amber);
  font-weight: 750;
  letter-spacing: 0.04em;
  cursor: pointer;
  transition:
    background 0.12s ease,
    border-color 0.12s ease,
    transform 0.1s ease,
    color 0.12s ease;
}

.play-button:not(:disabled):hover {
  background: rgba(255, 193, 7, 0.3);
}

.play-button:not(:disabled):active {
  transform: scale(0.97);
}

.play-button.is-active {
  border-color: rgba(255, 138, 101, 0.85);
  color: var(--danger);
  background: rgba(255, 138, 101, 0.12);
}

.play-button-icon {
  font-size: 0.85rem;
  line-height: 1;
}

.transport-meta {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-height: 2.5rem;
  justify-content: center;
}

.count-in {
  min-height: 1.25rem;
  font-size: 1.15rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  color: var(--amber);
  font-variant-numeric: tabular-nums;
}

.now-playing {
  margin: 0;
  font-size: 0.85rem;
  color: var(--text-muted);
}

.now-playing strong {
  color: var(--amber-text);
  font-weight: 650;
}

.settings-row {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 12px;
  padding: 12px;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: rgba(0, 0, 0, 0.22);
}

.field {
  display: flex;
  flex-direction: column;
  gap: 5px;
  min-width: 0;
}

.field-inline {
  flex-direction: row;
  align-items: center;
  gap: 8px;
}

.field-label {
  font-size: 0.68rem;
  font-weight: 650;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.field select,
.field .key-select-btn {
  width: 100%;
  min-height: 40px;
  padding: 8px 10px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--bg-panel);
  color: var(--text);
  cursor: pointer;
  transition: border-color 0.12s ease;
}

/* Key button: full name + accidentals (E Major ####, Bb Major bb, …) */
.field .key-select-btn {
  appearance: none;
  font-family: ui-monospace, "Cascadia Mono", "Segoe UI Mono", Consolas, monospace;
  font-size: 0.85rem;
  font-weight: 650;
  letter-spacing: 0.01em;
  text-align: left;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.field .key-select-btn::after {
  content: "◉";
  font-size: 0.7rem;
  opacity: 0.45;
  font-family: var(--font);
  font-weight: 400;
}

.field select:hover:not(:disabled),
.field .key-select-btn:hover:not(:disabled) {
  border-color: rgba(255, 193, 7, 0.4);
}

.field .key-select-btn:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}

/* ── Chords ─────────────────────────────────────────────── */

.chords-panel {
  margin-top: 2px;
}

.section-title {
  margin: 0;
  font-size: 0.75rem;
  font-weight: 650;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.section-hint {
  font-size: 0.7rem;
  color: var(--text-faint);
}

.chord-grid {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 10px;
}

.chords-header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 12px;
  margin-bottom: 10px;
}

.chords-header .section-title {
  margin: 0;
}

.chords-header .section-hint {
  margin-left: auto;
}

@media (max-width: 800px) {
  .chords-header {
    gap: 8px;
  }

  .chords-header .rhythm-field {
    flex: 1 1 64px;
    min-width: 0;
    max-width: 220px;
    margin-left: auto;
  }

  .chords-header .rhythm-field .field-label {
    display: none;
  }

  .chords-header .pattern-select-btn {
    display: block;
    position: relative;
    min-height: 44px;
    padding-right: 25px;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .chords-header .pattern-select-btn::after {
    content: "▾";
    position: absolute;
    right: 9px;
    top: 50%;
    transform: translateY(-50%);
    opacity: 0.8;
  }

  .chords-panel > .section-hint {
    display: none;
  }

  .chords-panel.is-editing:not(.is-collapsed) > .section-hint {
    display: block;
    margin-top: 8px;
  }
}

/* Same fold as the progression and the transport — one `.panel-fold`
   shared by all three, so they cannot drift apart. */
.chords-panel.is-collapsed .chords-header {
  margin-bottom: 0;
}

.chord-grid[hidden] {
  display: none;
}

.chords-edit-btn.is-active {
  border-color: rgba(129, 199, 132, 0.75);
  background: rgba(129, 199, 132, 0.15);
  color: #a5d6a7;
}

.chord-button {
  appearance: none;
  position: relative;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--chord-idle);
  color: var(--text);
  padding: 20px 8px 16px;
  font-size: clamp(1rem, 2.4vw, 1.25rem);
  font-weight: 750;
  letter-spacing: 0.02em;
  cursor: pointer;
  min-height: 64px;
  transition:
    background 0.12s ease,
    border-color 0.12s ease,
    transform 0.1s ease,
    box-shadow 0.12s ease;
}

.chord-button .chord-slot {
  position: absolute;
  top: 6px;
  left: 8px;
  font-size: 0.62rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  color: var(--text-faint);
  font-variant-numeric: tabular-nums;
}

.chord-button:hover:not(:disabled) {
  border-color: rgba(255, 193, 7, 0.55);
  background: #322820;
}

.chord-button:active:not(:disabled) {
  transform: scale(0.98);
}

.chord-button.is-selected {
  background: var(--chord-selected);
  border-color: rgba(255, 193, 7, 0.9);
  color: var(--amber-text);
  box-shadow: 0 0 0 1px rgba(255, 193, 7, 0.15), 0 6px 18px rgba(0, 0, 0, 0.25);
}

.chord-button.is-selected .chord-slot {
  color: rgba(255, 224, 130, 0.55);
}

.chord-button.is-empty {
  border-style: dashed;
  opacity: 0.75;
}

.chord-button.is-empty .chord-name {
  color: var(--text-faint);
  font-weight: 600;
}

.chord-button.is-editing:not(:disabled) {
  cursor: pointer;
}

.chord-button.is-editing:hover:not(:disabled) {
  border-color: rgba(129, 199, 132, 0.65);
}

.chord-grid.is-editing .chord-button {
  cursor: grab;
}

.chord-button.is-dragging {
  opacity: 0.45;
  cursor: grabbing;
}

.chord-button.is-drop-target {
  border-color: rgba(129, 199, 132, 0.9) !important;
  box-shadow: 0 0 0 2px rgba(129, 199, 132, 0.35);
  background: rgba(129, 199, 132, 0.12);
}

.chords-reset-btn {
  border-color: rgba(255, 138, 101, 0.55);
  color: #ffab91;
}

.chords-reset-btn:hover:not(:disabled) {
  background: rgba(255, 138, 101, 0.15);
}

.app[data-transport="playing"] .chord-button.is-selected {
  animation: chord-glow 1.6s ease-in-out infinite;
}

@keyframes chord-glow {
  0%,
  100% {
    box-shadow: 0 0 0 1px rgba(255, 193, 7, 0.2), 0 6px 18px rgba(0, 0, 0, 0.25);
  }
  50% {
    box-shadow:
      0 0 0 1px rgba(255, 193, 7, 0.45),
      0 0 18px rgba(255, 193, 7, 0.12),
      0 6px 18px rgba(0, 0, 0, 0.25);
  }
}

.chord-button:disabled {
  cursor: default;
}

/* ── Footer ─────────────────────────────────────────────── */

.bottom-bar {
  padding: 12px 18px 16px;
  border-top: 1px solid var(--border);
  background: rgba(0, 0, 0, 0.45);
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px 16px;
}

.status-line {
  margin: 0;
  font-size: 0.8rem;
  color: var(--text-muted);
}

.hint {
  margin: 0;
  font-size: 0.75rem;
  color: var(--text-faint);
}

.hint kbd {
  display: inline-block;
  padding: 1px 6px;
  border-radius: 4px;
  border: 1px solid rgba(255, 255, 255, 0.12);
  background: rgba(255, 255, 255, 0.06);
  font-family: inherit;
  font-size: 0.7rem;
  color: var(--text-muted);
}

/* ── Responsive ─────────────────────────────────────────── */

/* Mobile / narrow: hamburger menu, compact transport, chords under visualizer */
@media (max-width: 800px) {
  .brand-sub {
    display: none;
  }

  .top-bar {
    flex-direction: column;
    align-items: stretch;
    flex-wrap: nowrap;
    --bar-pad-y: 8px;
    --bar-pad-bottom: 10px;
    --bar-pad-x: 12px;
    gap: 4px;
  }

  .top-bar-primary {
    width: 100%;
    flex: 0 0 auto;
    flex-wrap: nowrap;
  }

  .brand {
    flex: 1 1 auto;
    min-width: 0;
  }

  /* Mobile row 2: song title always visible under brand + ☰ */
  .song-name-row {
    order: 2;
    width: 100%;
    flex: 0 0 auto;
    justify-content: center;
    padding: 2px 4px 4px;
    border-top: 1px solid rgba(121, 85, 72, 0.25);
    margin-top: 2px;
  }

  .song-name-row .song-name-button {
    max-width: 100%;
    width: auto;
    min-width: 0;
    font-size: 1.05rem;
    padding: 8px 14px;
  }

  .song-name-row .song-name-input {
    max-width: 100%;
    width: min(100%, 280px);
    min-width: 0;
  }

  .menu-toggle {
    display: grid;
    place-items: center;
    width: 44px;
    height: 44px;
    flex-shrink: 0;
    margin-left: auto;
    border: 1px solid var(--border);
    border-radius: 10px;
    background: rgba(255, 255, 255, 0.04);
    color: var(--amber-text);
    cursor: pointer;
    padding: 0;
  }

  .menu-toggle:hover {
    border-color: rgba(255, 193, 7, 0.45);
    background: rgba(255, 193, 7, 0.1);
  }

  .menu-toggle.is-open {
    border-color: rgba(255, 193, 7, 0.55);
    background: rgba(255, 193, 7, 0.14);
  }

  .menu-toggle-bars,
  .menu-toggle-bars::before,
  .menu-toggle-bars::after {
    display: block;
    width: 18px;
    height: 2px;
    border-radius: 1px;
    background: currentColor;
    position: relative;
    transition: transform 0.15s ease, opacity 0.15s ease;
  }

  .menu-toggle-bars::before,
  .menu-toggle-bars::after {
    content: "";
    position: absolute;
    left: 0;
  }

  .menu-toggle-bars::before {
    top: -6px;
  }

  .menu-toggle-bars::after {
    top: 6px;
  }

  .menu-toggle.is-open .menu-toggle-bars {
    background: transparent;
  }

  .menu-toggle.is-open .menu-toggle-bars::before {
    top: 0;
    transform: rotate(45deg);
  }

  .menu-toggle.is-open .menu-toggle-bars::after {
    top: 0;
    transform: rotate(-45deg);
  }

  .top-bar-menu {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 50;
    pointer-events: none;
    visibility: hidden;
    /* The closed drawer waits one panel-width to the right of the viewport,
       and `visibility: hidden` does not take it out of the scroll area — so
       the page had a horizontal scrollbar with nothing visible in it. Clip
       rather than hide: this must not become a scroll container itself, or it
       takes over the panel's own `overflow-y`. Open, the panel sits at
       translateX(0), fully inside, so nothing real is ever clipped. */
    overflow-x: clip;
  }

  .top-bar-menu.is-open {
    pointer-events: auto;
    visibility: visible;
  }

  .top-bar-menu-backdrop {
    display: block;
    position: absolute;
    inset: 0;
    background: rgba(0, 0, 0, 0.55);
    opacity: 0;
    transition: opacity 0.2s ease;
  }

  .top-bar-menu.is-open .top-bar-menu-backdrop {
    opacity: 1;
  }

  .top-bar-menu-backdrop[hidden] {
    display: none;
  }

  .top-bar-menu.is-open .top-bar-menu-backdrop[hidden] {
    display: block;
  }

  .top-bar-menu-panel {
    position: absolute;
    top: 0;
    right: 0;
    width: min(320px, 88vw);
    height: 100%;
    height: 100dvh;
    flex-direction: column;
    align-items: stretch;
    justify-content: flex-start;
    gap: 18px;
    /* It is `100dvh` against the right edge, so it meets the notch at the top,
       the home indicator at the bottom, and the rounded corner on the side. */
    padding:
      calc(14px + var(--safe-top))
      calc(16px + var(--safe-right))
      calc(24px + var(--safe-bottom))
      16px;
    background: linear-gradient(180deg, #16110d 0%, #0c0907 100%);
    border-left: 1px solid var(--border);
    box-shadow: -12px 0 40px rgba(0, 0, 0, 0.45);
    transform: translateX(100%);
    transition: transform 0.22s ease;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
  }

  .top-bar-menu.is-open .top-bar-menu-panel {
    transform: translateX(0);
  }

  .top-bar-menu-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding-bottom: 4px;
    border-bottom: 1px solid var(--border);
  }

  .top-bar-menu-title {
    font-size: 0.85rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-muted);
  }

  .menu-close {
    display: grid;
    place-items: center;
    width: 40px;
    height: 40px;
    border: 1px solid var(--border);
    border-radius: 10px;
    background: transparent;
    color: var(--text-muted);
    cursor: pointer;
    font-size: 1rem;
    line-height: 1;
  }

  .menu-close:hover {
    color: var(--amber-text);
    border-color: rgba(255, 193, 7, 0.4);
  }

  .top-bar-menu .song-bar {
    flex-direction: column;
    align-items: stretch;
    justify-content: flex-start;
    min-width: 0;
    gap: 10px;
  }

  .top-bar-menu .song-bar .header-button {
    width: 100%;
    min-height: 44px;
  }

  .top-bar-menu .top-bar-actions {
    flex-direction: column;
    align-items: stretch;
    gap: 12px;
  }

  .top-bar-menu .field-inline {
    width: 100%;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 6px;
  }

  .top-bar-menu .field-inline select {
    width: 100%;
    min-height: 44px;
  }

  .top-bar-menu .transport-pill {
    align-self: flex-start;
  }

  /* Main stack: visualizer → chords → transport → progression.
     Every panel needs an order once any of them has one: the default is 0,
     which would sort an unnumbered panel above all of them. */
  .main {
    gap: 14px;
  }

  .visualizer-panel {
    order: 1;
    height: clamp(160px, 26vh, 240px);
    min-height: 160px;
  }

  .chords-panel {
    order: 2;
  }

  /* An unnumbered panel defaults to `order: 0` and sorts above every numbered
     one, so a new panel here needs a number of its own or it silently jumps to
     the top of a phone screen. */
  .play-panel {
    order: 3;
  }

  .transport-panel {
    order: 4;
  }

  .prog-panel {
    order: 5;
  }

  .score-panel {
    order: 6;
  }

  .work-mode-long {
    display: none;
  }

  .work-mode-short {
    display: inline;
  }

  .work-mode {
    margin-left: auto;
  }

  /* Hide preview hint on mobile — save space */
  .preview-hint {
    display: none !important;
  }

  .settings-row {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .chord-grid {
    grid-template-columns: repeat(5, minmax(0, 1fr));
  }

  /* Settings + meta keep one line; the instrument pair wraps under it. Fixed
     bases rather than `auto` so a long "now playing" line cannot push the
     fold off the row. */
  .transport-row {
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
  }

  .transport-meta {
    flex: 1 1 6rem;
    min-width: 0;
  }

  .transport-instrument {
    order: 5;
    flex: 1 0 100%;
    margin-left: 0;
  }

  .transport-instrument .field-inline {
    flex: 1 1 auto;
    min-width: 0;
  }

  .transport-instrument select {
    min-width: 0;
    width: 100%;
  }

  .transport-panel.is-collapsed .transport-meta,
  .transport-panel.is-collapsed .transport-instrument,
  .transport-panel.is-collapsed .transport-details {
    display: none;
  }

  /* While playing / count-in the whole settings panel steps aside, so the
     screen is Play and the cues and nothing else.

     This used to be eight `!important` selectors blanking the pieces of a
     shared row one at a time, because Play lived in that row and had to
     survive. It does not any more, so the rule is what it always meant. */
  .app[data-transport="playing"] .transport-panel,
  .app[data-transport="countdown"] .transport-panel {
    display: none;
  }

  .transport-details {
    overflow: hidden;
  }
}

@media (max-width: 480px) {
  .main {
    --main-pad: 12px;
    gap: 12px;
  }

  .settings-row {
    grid-template-columns: 1fr;
    padding: 10px;
  }

  .chord-grid {
    grid-template-columns: repeat(5, minmax(0, 1fr));
    gap: 6px;
  }

  .chord-button {
    min-height: 52px;
    font-size: 0.85rem;
    padding: 14px 4px 10px;
  }

  .visualizer-panel {
    height: clamp(150px, 24vh, 220px);
  }

  .bottom-bar .hint {
    display: none;
  }

  .visualizer-actions .preview-arpeggio-button {
    font-size: 0.65rem;
    padding: 0.35rem 0.55rem;
  }
}

@media (min-width: 960px) and (min-height: 700px) {
  .visualizer-panel {
    height: clamp(240px, 34vh, 360px);
  }

  .chord-button {
    min-height: 72px;
    padding-top: 22px;
  }
}

/* Landscape phones: keep chords reachable */
@media (max-height: 480px) and (orientation: landscape) {
  .visualizer-panel {
    height: 140px;
    min-height: 120px;
  }

  .chord-button {
    min-height: 48px;
    padding: 12px 6px 10px;
    font-size: 1rem;
  }

  /* Sideways is exactly when a notch takes a side, so this one must go through
     the variable rather than restate the padding — a shorthand here silently
     drops the inset and slides the chord grid under the notch. */
  .main {
    gap: 10px;
    --main-pad: 10px;
    --main-pad-x: 14px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .count-in-big,
  .count-in-overlay,
  .chord-button.is-selected,
  .play-button {
    animation: none !important;
    transition: none !important;
  }
}

/* ── Header button ──────────────────────────────────────── */

.header-button {
  appearance: none;
  border: 1px solid rgba(255, 193, 7, 0.45);
  background: var(--amber-dim);
  color: var(--amber-text);
  border-radius: 999px;
  padding: 6px 12px;
  font-size: 0.75rem;
  font-weight: 650;
  letter-spacing: 0.04em;
  cursor: pointer;
}

.header-button:hover {
  background: rgba(255, 193, 7, 0.28);
}

.header-button:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

/* Segmented strum/arpeggio switch (rhythm editor header) */
.mode-switch {
  display: inline-flex;
  padding: 2px;
  gap: 2px;
  border: 1px solid rgba(255, 193, 7, 0.35);
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.28);
}

.mode-switch-option {
  appearance: none;
  border: 0;
  background: transparent;
  color: var(--text-dim);
  border-radius: 999px;
  padding: 5px 14px;
  font-size: 0.72rem;
  font-weight: 650;
  letter-spacing: 0.04em;
  cursor: pointer;
  white-space: nowrap;
}

.mode-switch-option:hover {
  color: var(--text);
}

.mode-switch-option.is-active {
  background: var(--amber-dim);
  color: var(--amber-text);
  box-shadow: inset 0 0 0 1px rgba(255, 193, 7, 0.45);
}

#re-mode-arpeggio.is-active {
  background: rgba(100, 181, 246, 0.2);
  color: #bbdefb;
  box-shadow: inset 0 0 0 1px rgba(100, 181, 246, 0.6);
}

/* Play mode: strumming vs plucking one string at a time */
.play-mode-button {
  min-width: 5.5rem;
}

.play-mode-button.is-arpeggio {
  border-color: rgba(100, 181, 246, 0.75);
  background: rgba(100, 181, 246, 0.18);
  color: #bbdefb;
}

.play-mode-button.is-arpeggio:hover:not(:disabled) {
  background: rgba(100, 181, 246, 0.28);
}

/* ── Rhythm editor overlay ──────────────────────────────── */

/* `inset: 0` on a cover-fit viewport means it reaches under the status bar and
   the home indicator, so the whole overlay carries the insets and everything
   inside it keeps the layout it already had. */
.rhythm-editor {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  flex-direction: column;
  padding: var(--safe-top) var(--safe-right) var(--safe-bottom) var(--safe-left);
  background: rgba(8, 5, 3, 0.97);
  color: var(--text);
}

.rhythm-editor[hidden] {
  display: none !important;
}

.re-header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--border);
  background: rgba(0, 0, 0, 0.35);
}

.re-header-left {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}

.re-header-brand {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 14px 20px;
}

.re-title {
  margin: 0;
  font-size: 1.15rem;
  font-weight: 750;
  letter-spacing: 0.04em;
  color: var(--amber-text);
}

.re-header-time {
  margin: 0;
}

.re-play-row {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
}

.re-play-button {
  appearance: none;
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  width: 38px;
  height: 38px;
  padding: 0;
  border-radius: 999px;
  border: 1px solid rgba(129, 199, 132, 0.55);
  background: rgba(129, 199, 132, 0.14);
  color: #a5d6a7;
  font-size: 0.85rem;
  line-height: 1;
  cursor: pointer;
}

.re-play-button:not(:disabled):hover {
  border-color: rgba(129, 199, 132, 0.85);
  background: rgba(129, 199, 132, 0.24);
}

.re-play-button:disabled {
  opacity: 0.35;
  cursor: not-allowed;
}

/* Playing reads as the stop it now does, and matches the playhead's green. */
.re-play-button.is-playing {
  border-color: rgba(129, 199, 132, 0.9);
  background: rgba(129, 199, 132, 0.32);
  color: #e8f5e9;
}

/* The glyphs do not share an optical centre: ▶ has its mass to the left. */
.re-play-button:not(.is-playing) .re-play-icon {
  margin-left: 2px;
}

.re-header-time select {
  min-width: 5.5rem;
  min-height: 36px;
  padding: 6px 10px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--bg-panel);
  color: var(--text);
  cursor: pointer;
}

.re-status {
  margin: 0;
  font-size: 0.78rem;
  color: var(--text-muted);
}

.re-header-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.re-btn {
  appearance: none;
  border-radius: 8px;
  padding: 8px 14px;
  font-size: 0.8rem;
  font-weight: 650;
  cursor: pointer;
  border: 1px solid var(--border);
  background: var(--bg-panel);
  color: var(--text);
}

.re-btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

.re-btn-primary {
  border-color: rgba(255, 193, 7, 0.65);
  background: var(--amber-dim);
  color: var(--amber);
}

.re-btn-primary:not(:disabled):hover {
  background: rgba(255, 193, 7, 0.28);
}

.re-btn-ghost:not(:disabled):hover {
  border-color: rgba(255, 255, 255, 0.2);
}

.re-body {
  flex: 1;
  display: grid;
  grid-template-columns: minmax(180px, 240px) 1fr;
  min-height: 0;
}

.re-sidebar {
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  min-height: 0;
  background: rgba(0, 0, 0, 0.25);
}

.re-sidebar-label {
  margin: 0;
  padding: 10px 12px 6px;
  font-size: 0.68rem;
  font-weight: 650;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.re-sidebar-actions {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 0 8px 10px;
}

.re-btn-block {
  width: 100%;
  text-align: center;
}

.re-list {
  flex: 1;
  overflow: auto;
  padding: 4px 8px 12px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.re-list-empty {
  margin: 8px 4px;
  font-size: 0.78rem;
  color: var(--text-faint);
}

/* Sticky so the family stays named while you scroll its variants — with 60
   rhythms in 4/4 the heading would otherwise be gone by the third one. */
.re-list-family {
  position: sticky;
  top: 0;
  z-index: 1;
  margin: 10px 0 2px;
  padding: 4px 10px 3px;
  background: var(--bg-panel);
  font-size: 0.66rem;
  font-weight: 700;
  color: var(--text-faint);
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.re-list-family:first-child {
  margin-top: 0;
}

.re-name-field {
  flex: 1 1 12rem;
  min-width: 10rem;
}

.re-name-input {
  width: 100%;
  min-height: 40px;
  padding: 8px 10px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--bg-panel);
  color: var(--text);
}

.re-name-input:focus {
  border-color: rgba(255, 193, 7, 0.55);
}

.re-list-item {
  appearance: none;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
  width: 100%;
  text-align: left;
  border: 1px solid transparent;
  border-radius: 8px;
  padding: 10px 10px;
  background: transparent;
  color: var(--text);
  cursor: pointer;
}

.re-list-item:hover {
  background: rgba(255, 255, 255, 0.04);
}

.re-list-item.is-selected {
  border-color: rgba(255, 193, 7, 0.5);
  background: var(--amber-dim);
}

.re-list-name {
  font-weight: 650;
  font-size: 0.9rem;
}

.re-list-meta {
  font-size: 0.68rem;
  color: var(--text-faint);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

/* Under the name rather than beside it. The picker dialog gives a row 483px
   and can put the 148px figure next to a 267px name; this list has 188px of
   content in a 240px sidebar, so side by side would mean shrinking the drawing
   to about 90px — and at that size eight strokes are 11px apart, which is
   where reading a figure by eye stops working. */
.re-list-art {
  display: block;
  margin-top: 4px;
  line-height: 0;
}

.re-list-item.is-dirty .re-list-meta {
  color: var(--amber);
}

.re-detail {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  padding: 12px 20px 20px;
  gap: 12px;
}

.re-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px 16px;
}

.re-toolbar .field-inline select,
.re-toolbar .field-inline input[type="range"] {
  min-width: 7rem;
}

/* Transparent on a wide screen: the pair sits in the toolbar row exactly as it
   did before it was wrapped. The wrapper earns its keep on a phone, where the
   two are shown or dropped together. */
.re-stroke-controls {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px 16px;
  min-width: 0;
}

/* Fixed width and tabular figures so the toolbar does not reflow as the
   number goes 5 → 100 while the slider is being dragged. */
.re-velocity-value {
  min-width: 3ch;
  font-size: 0.82rem;
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);
  text-align: right;
}

input[type="range"]:not(:disabled) + .re-velocity-value {
  color: var(--text);
}

.re-mute-stroke.is-active {
  color: #1a1410;
  background: var(--amber);
  border-color: var(--amber);
}

.re-hint {
  margin: 0;
  font-size: 0.78rem;
  color: var(--text-muted);
}

.re-canvas-wrap {
  flex: 1;
  min-height: 220px;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  overflow: hidden;
  background: #0d0a08;
  /* Outer inset so labels near canvas edges stay visible */
  padding: 18px 20px 20px 16px;
  box-sizing: border-box;
}

#re-canvas {
  display: block;
  width: 100%;
  height: 100%;
  min-height: 280px;
  touch-action: none;
  cursor: crosshair;
}

/* Takes focus on click so Delete reaches the editor. The global focus ring
   sits outside the element, which .re-canvas-wrap clips, so this one is inset. */
#re-canvas:focus-visible {
  box-shadow: inset 0 0 0 2px rgba(255, 193, 7, 0.75);
}

/* Phone: three panels — library, properties, grid — compete for one screen,
   and only the grid is the work. At 375x812 the other two plus the header took
   70% of the height and left the canvas 220px, clipped below the fold. Each
   supporting panel collapses to a single scrolling row, and anything the app
   has already disabled is dropped rather than shown greyed, so the chrome
   shrinks as the task narrows. */
@media (max-width: 720px) {
  .re-header {
    flex-wrap: wrap;
    gap: 8px;
    padding: 8px 12px;
  }

  /* Not full width: given a row of its own the action buttons cost another
     44px, and with the disabled ones hidden there is usually just Close. */
  .re-header-left {
    flex: 1 1 10rem;
    min-width: 0;
    gap: 6px;
  }

  .re-header-actions {
    flex: 0 0 auto;
    align-self: flex-start;
  }

  .re-header-brand {
    gap: 8px 12px;
  }

  .re-title {
    font-size: 1rem;
  }

  /* The same 44px the drawer's buttons take. Free in the header, where the row
     is already the height of the Time select. */
  .rhythm-editor .re-btn {
    min-height: 44px;
  }

  .re-header-time {
    flex: 1 1 auto;
  }

  .re-header-time select {
    min-width: 4.5rem;
  }

  /* One line. The name is in the Name field, the figure in the switch and the
     snap in its own select — what is not already on screen is "unsaved". */
  .re-status {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  /* Play and the figure switch share the row they already had: the button is
     a fixed 44 square on the left, the switch takes the rest. No new height. */
  .re-play-row {
    flex: 1 1 100%;
  }

  .re-play-button {
    width: 44px;
    height: 44px;
    font-size: 0.95rem;
  }

  .mode-switch {
    flex: 1;
    min-height: 44px;
  }

  .mode-switch-option {
    flex: 1;
  }

  /* A disabled button is not a control, it is a row of dead height. Save comes
     back when there is something to save, Reset when there is something to
     reset — the same signal the greying carried. */
  .re-header-actions .re-btn:disabled {
    display: none;
  }

  .re-body {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto minmax(0, 1fr);
  }

  /* This was a 160px cap over content that measured 219, with overflow left
     visible — the library buttons painted straight over the panel below. Rows
     that size to their content cannot spill.

     `min-width: 0` is what makes the scrolling rows below scroll: a grid item
     defaults to min-width auto, so the sidebar grew to its widest row — 607px
     inside a 375px screen — and the chips past the edge were simply
     unreachable rather than scrollable. */
  .re-sidebar {
    max-height: none;
    min-height: 0;
    min-width: 0;
    border-right: none;
    border-bottom: 1px solid var(--border);
  }

  .re-sidebar-label {
    padding: 8px 12px 4px;
  }

  /* Four full-width buttons and a vertical list are ~300px of a phone screen.
     One scrolling row each keeps every item reachable in a quarter of that. */
  .re-sidebar-actions,
  .re-list {
    flex-direction: row;
    flex-wrap: nowrap;
    overflow-x: auto;
    overflow-y: hidden;
    scrollbar-width: none;
    padding: 0 12px 8px;
  }

  .re-sidebar-actions::-webkit-scrollbar,
  .re-list::-webkit-scrollbar {
    display: none;
  }

  .re-list {
    flex: 0 0 auto;
    gap: 6px;
    padding-bottom: 10px;
  }

  .re-btn-block,
  .re-list-item {
    width: auto;
    flex: 0 0 auto;
    white-space: nowrap;
  }

  .re-list-item {
    border-color: var(--border);
    padding: 8px 12px;
  }

  /* Sideways the list is a strip of chips, not rows. A 148px figure per chip
     takes the strip from 4.4 chips visible to 2.3 and grows it from 84px to
     ~120px — on a screen where the canvas already wants 409 of 812. The chip's
     job here is to be reachable in one swipe; choosing by picture is what the
     main page's picker is for. */
  .re-list-art {
    display: none;
  }

  /* Sideways the heading is a divider you swipe past, not a row above, so it
     sticks to the left edge instead of the top and turns on its side. Writing
     it vertically costs one character of width rather than a whole chip. */
  .re-list-family {
    position: sticky;
    left: 0;
    top: auto;
    flex: 0 0 auto;
    align-self: stretch;
    display: flex;
    align-items: center;
    margin: 0;
    padding: 0 2px;
    writing-mode: vertical-rl;
    font-size: 0.58rem;
    letter-spacing: 0.04em;
  }

  .re-detail {
    padding: 10px 12px 12px;
    gap: 10px;
  }

  .re-toolbar {
    gap: 8px 10px;
  }

  /* Name and Snap share a row; the min-widths that keep them comfortable on a
     desktop are what force them onto four. */
  .re-name-field {
    flex: 1 1 7rem;
    min-width: 0;
  }

  .re-toolbar .field-inline select,
  .re-toolbar .field-inline input[type="range"] {
    min-width: 0;
  }

  /* One row, not two: the slider is the only thing here that can give up
     width, so it is the only thing allowed to shrink. */
  .re-stroke-controls {
    flex: 1 1 100%;
    flex-wrap: nowrap;
    gap: 10px;
  }

  .re-stroke-controls .field-inline {
    flex: 1 1 auto;
    min-width: 0;
  }

  .re-stroke-controls .re-btn {
    flex: 0 0 auto;
  }

  .rhythm-editor:not(.re-stroke-selected) .re-stroke-controls {
    display: none;
  }

  /* Three lines explaining the grid, taken out of the grid's own height. */
  .re-hint {
    display: none;
  }

  /* The floors below are what pushed the canvas past the bottom of the screen;
     on a phone the grid takes what is left rather than asking for a minimum. */
  .re-canvas-wrap {
    min-height: 0;
    padding: 12px 12px 12px 8px;
  }

  #re-canvas {
    min-height: 0;
  }
}

/* A phone held sideways is wide enough for the two-column layout but not tall
   enough for the grid's floor, so the canvas hung 88px below the screen with
   no way to scroll to it. The floors are a minimum for a window that has the
   room; keyed on height, they simply do not apply when it does not. */
@media (max-height: 560px) {
  .re-hint {
    display: none;
  }

  .re-canvas-wrap {
    min-height: 0;
  }

  #re-canvas {
    min-height: 0;
  }
}

/* ── Key picker (circle of fifths) ──────────────────────── */

.key-picker-backdrop {
  position: fixed;
  inset: 0;
  z-index: 125;
  display: grid;
  place-items: center;
  padding:
    calc(16px + var(--safe-top))
    calc(16px + var(--safe-right))
    calc(16px + var(--safe-bottom))
    calc(16px + var(--safe-left));
  background: rgba(0, 0, 0, 0.72);
  animation: key-picker-fade 0.18s ease-out;
}

@keyframes key-picker-fade {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

.key-picker-panel {
  width: min(720px, 100%);
  max-height: min(94vh, 640px);
  display: flex;
  flex-direction: column;
  border-radius: 14px;
  border: 1px solid rgba(255, 193, 7, 0.28);
  background:
    radial-gradient(ellipse 70% 50% at 30% 40%, rgba(255, 160, 0, 0.06), transparent),
    #100c0a;
  box-shadow: 0 20px 56px rgba(0, 0, 0, 0.55);
  overflow: hidden;
}

.key-picker-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 14px 18px;
  border-bottom: 1px solid var(--border);
}

.key-picker-title {
  margin: 0;
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.key-picker-body {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(160px, 0.75fr);
  gap: 8px 12px;
  padding: 12px 16px 18px;
  align-items: center;
  overflow: auto;
}

.key-picker-wheel-wrap {
  display: grid;
  place-items: center;
  min-height: 280px;
  padding: 8px;
}

.key-picker-svg {
  width: min(100%, 380px);
  height: auto;
  overflow: visible;
  filter: drop-shadow(0 4px 20px rgba(0, 0, 0, 0.35));
}

.key-picker-ring {
  fill: none;
  stroke: rgba(255, 255, 255, 0.06);
  stroke-width: 1;
  pointer-events: none;
}

.key-picker-hub {
  fill: #0a0705;
  stroke: rgba(255, 255, 255, 0.08);
  stroke-width: 1;
  pointer-events: none;
}

.key-picker-wedge {
  stroke: rgba(0, 0, 0, 0.45);
  stroke-width: 1.25;
  cursor: pointer;
  transition: fill 0.12s ease, filter 0.12s ease;
}

.key-picker-wedge-major {
  fill: rgba(42, 34, 28, 0.95);
}

.key-picker-wedge-minor {
  fill: rgba(28, 22, 18, 0.98);
}

.key-picker-wedge:hover {
  fill: rgba(255, 193, 7, 0.14);
}

.key-picker-slice.is-selected .key-picker-wedge-major {
  fill: rgba(186, 104, 200, 0.28);
  stroke: rgba(206, 147, 216, 0.55);
}

.key-picker-slice.is-selected .key-picker-wedge-minor {
  fill: rgba(156, 84, 170, 0.22);
  stroke: rgba(206, 147, 216, 0.4);
}

.key-picker-slice.is-selected .key-picker-wedge.is-active-label,
.key-picker-wedge.is-active-label {
  fill: rgba(186, 104, 200, 0.42);
  stroke: rgba(225, 190, 231, 0.75);
  filter: drop-shadow(0 0 10px rgba(186, 104, 200, 0.35));
}

.key-picker-label {
  fill: rgba(255, 255, 255, 0.78);
  font-family: var(--font);
  font-weight: 700;
  pointer-events: none;
  user-select: none;
}

.key-picker-label-major {
  font-size: 15px;
  letter-spacing: 0.02em;
}

.key-picker-label-minor {
  font-size: 12px;
  fill: rgba(255, 255, 255, 0.5);
  font-weight: 650;
}

.key-picker-label.is-active-label {
  fill: #f3e5f5;
}

/* The rim counts are drawn in the SVG's own units, and the wheel is scaled to
   fit — 380px of a 404 viewBox on a desktop, 320 on a phone. So a size that
   reads here is about 20% smaller by the time it is on the screen it matters
   on, which is what made 10px unreadable at 320. The dim amber was the other
   half of it: this is small text on near-black, where opacity costs more than
   it does on a filled label. */
.key-picker-sig {
  fill: rgba(255, 193, 7, 0.78);
  font-size: 13px;
  font-weight: 700;
  font-family: ui-monospace, "Cascadia Mono", Consolas, monospace;
  pointer-events: none;
  user-select: none;
}

.key-picker-side {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 12px 8px 12px 4px;
  min-width: 0;
}

.key-picker-selected-label {
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(206, 147, 216, 0.85);
}

.key-picker-selected-name {
  font-size: clamp(1.25rem, 3.5vw, 1.65rem);
  font-weight: 750;
  color: var(--text);
  line-height: 1.2;
  letter-spacing: 0.01em;
}

.key-picker-selected-compact {
  font-family: ui-monospace, "Cascadia Mono", "Segoe UI Mono", Consolas, monospace;
  font-size: 1.35rem;
  font-weight: 700;
  color: var(--amber-text);
  letter-spacing: 0.04em;
}

.key-picker-selected-desc {
  font-size: 0.9rem;
  color: var(--text-muted);
  margin-top: 2px;
}

.key-picker-hint {
  margin: 14px 0 0;
  font-size: 0.72rem;
  line-height: 1.45;
  color: var(--text-faint);
}

@media (max-width: 560px) {
  .key-picker-body {
    grid-template-columns: 1fr;
    gap: 4px;
  }

  .key-picker-side {
    order: -1;
    padding: 4px 4px 8px;
    text-align: center;
    align-items: center;
  }

  .key-picker-wheel-wrap {
    min-height: 240px;
  }

  .key-picker-svg {
    width: min(100%, 320px);
  }

  /* The wheel is down to about 293px of a 404 viewBox here — a 0.72 scale, so
     13px arrives as 9.4. Up again to land in the same place the desktop does;
     the rim counts have 14px of clearance inside the padding to spend. */
  .key-picker-sig {
    font-size: 15px;
  }
}

/* ── Chord picker dialog ────────────────────────────────── */

.chord-picker-backdrop {
  position: fixed;
  inset: 0;
  z-index: 120;
  display: grid;
  place-items: center;
  padding:
    calc(16px + var(--safe-top))
    calc(16px + var(--safe-right))
    calc(16px + var(--safe-bottom))
    calc(16px + var(--safe-left));
  background: rgba(0, 0, 0, 0.65);
}

.chord-picker-panel {
  /* ~30% wider than original; height +10% again to avoid grid scrollbar */
  width: min(676px, 100%);
  max-height: min(92vh, 915px);
  display: flex;
  flex-direction: column;
  border-radius: 12px;
  border: 1px solid var(--border);
  background: #14100c;
  box-shadow: 0 16px 48px rgba(0, 0, 0, 0.5);
  overflow: hidden;
}

.chord-picker-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 14px 18px;
  border-bottom: 1px solid var(--border);
}

.chord-picker-title {
  margin: 0;
  font-size: 1.1rem;
  color: var(--amber-text);
}

.chord-picker-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 8px;
  padding: 16px;
  /* Prefer growing the panel (max-height) over scrolling; keep auto only for very short viewports */
  overflow-y: auto;
  flex: 0 1 auto;
}

.chord-picker-item {
  appearance: none;
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 13px 8px;
  background: var(--chord-idle);
  color: var(--text);
  font-weight: 700;
  font-size: 1rem;
  cursor: pointer;
}

.chord-picker-item:hover {
  border-color: rgba(255, 193, 7, 0.55);
}

/* Step 2: the chord name carries a quality caption, so rows are taller */
.chord-picker-grid.is-qualities {
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
}

/* High voicings carry shape, fret and tab — give that information room. */
.chord-picker-grid.is-voicings {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

@media (max-width: 520px) {
  .chord-picker-grid.is-voicings {
    grid-template-columns: 1fr;
  }
}

.chord-picker-quality {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
  padding: 10px 12px;
  text-align: left;
}

.chord-picker-name {
  font-size: 1.05rem;
  font-weight: 700;
  line-height: 1.2;
}

.chord-picker-label {
  font-size: 0.7rem;
  font-weight: 500;
  letter-spacing: 0.02em;
  color: var(--text-dim);
}

.chord-picker-quality.is-current .chord-picker-label {
  color: var(--amber-text);
  opacity: 0.85;
}

.chord-picker-back {
  margin-right: 8px;
}

.chord-picker-position {
  margin-left: auto;
  margin-right: 8px;
}

.chord-picker-position[hidden] {
  display: none;
}

/* Fret a barre chord starts at, on its slot button */
.chord-position {
  position: absolute;
  top: 4px;
  right: 6px;
  font-size: 0.6rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  color: var(--amber-text);
  opacity: 0.75;
  pointer-events: none;
}

.chord-button.is-high {
  border-style: dashed;
}

.chord-picker-item.is-current {
  border-color: rgba(255, 193, 7, 0.85);
  background: var(--chord-selected);
  color: var(--amber-text);
}

.chord-picker-footer {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  padding: 10px 14px 14px;
  border-top: 1px solid var(--border);
}

/* ── Song load dialog ───────────────────────────────────── */
/*
 * Root cause of mobile overflow:
 * Side-by-side <button> Load + Delete used flex/grid. Buttons size to
 * min-content of their text (long meta), so the row grew past the
 * viewport and panel { overflow:hidden } clipped Delete.
 *
 * Fix: single full-width card; Delete is position:absolute inside the card.
 * Parent chain uses min-width:0 so flex children cannot expand the panel.
 */

body.song-dialog-open {
  overflow: hidden;
  touch-action: none;
}

.song-dialog-backdrop {
  position: fixed;
  inset: 0;
  z-index: 130;
  display: grid;
  place-items: center;
  padding:
    calc(16px + var(--safe-top))
    calc(16px + var(--safe-right))
    calc(16px + var(--safe-bottom))
    calc(16px + var(--safe-left));
  background: rgba(0, 0, 0, 0.65);
  box-sizing: border-box;
  overflow: hidden;
}

.song-dialog-panel {
  width: min(520px, calc(100% - 0px));
  max-width: 100%;
  max-height: min(80vh, 560px);
  min-width: 0;
  display: flex;
  flex-direction: column;
  border-radius: 12px;
  border: 1px solid var(--border);
  background: #14100c;
  box-shadow: 0 16px 48px rgba(0, 0, 0, 0.5);
  overflow: hidden;
  box-sizing: border-box;
}

.song-dialog-header {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 12px 14px;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
  min-width: 0;
  box-sizing: border-box;
}

.song-dialog-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  min-width: 0;
}

/* One song on the left of the rule, every song on the right. A grid rather
   than a flex row: equal tracks keep a label that grows from pushing its
   neighbours off a 320px screen, the trap this project keeps re-learning. */
.song-dialog-files {
  display: grid;
  grid-template-columns: 1fr auto 1fr 1fr;
  align-items: center;
  gap: 8px;
  min-width: 0;
}

.song-dialog-files .re-btn {
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.song-dialog-rule {
  width: 1px;
  height: 20px;
  background: var(--border);
}

/* The title shrinks and ellipsises rather than pushing Cancel off its row. */
.song-dialog-title {
  margin: 0;
  font-size: 1.05rem;
  color: var(--amber-text);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.song-dialog-list {
  overflow-x: clip;
  overflow-y: auto;
  padding: 8px;
  display: block; /* not flex — avoid flex min-content expansion */
  flex: 1 1 auto;
  min-width: 0;
  min-height: 0;
  width: 100%;
  max-width: 100%;
  box-sizing: border-box;
  -webkit-overflow-scrolling: touch;
}

.song-dialog-empty {
  margin: 16px 8px;
  color: var(--text-muted);
  font-size: 0.85rem;
}

.song-dialog-row {
  display: block;
  width: 100%;
  max-width: 100%;
  min-width: 0;
  box-sizing: border-box;
  margin-bottom: 6px;
}

.song-dialog-row:last-child {
  margin-bottom: 0;
}

/* Card shell: establishes width; Delete sits on top of the right edge */
.song-dialog-card {
  position: relative;
  display: block;
  width: 100%;
  max-width: 100%;
  min-width: 0;
  box-sizing: border-box;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--chord-idle);
  overflow: hidden;
}

.song-dialog-row.is-current .song-dialog-card {
  border-color: rgba(255, 193, 7, 0.55);
  background: var(--amber-dim);
}

/* Load control fills the card; right padding reserves space for the actions */
.song-dialog-item {
  appearance: none;
  -webkit-appearance: none;
  display: block;
  margin: 0;
  width: 100%;
  max-width: 100%;
  min-width: 0;
  box-sizing: border-box;
  border: none;
  border-radius: 0;
  padding: 10px 8.5rem 10px 12px;
  background: transparent;
  color: var(--text);
  text-align: left;
  cursor: pointer;
  overflow: hidden;
  white-space: normal;
  font: inherit;
}

.song-dialog-item:hover {
  background: rgba(255, 193, 7, 0.06);
}

.song-dialog-name {
  display: block;
  font-weight: 700;
  font-size: 0.95rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.song-dialog-meta {
  display: block;
  margin-top: 2px;
  font-size: 0.72rem;
  color: var(--text-faint);
  line-height: 1.35;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Download and Delete ride the card's right edge as one absolutely-positioned
   box. One box rather than two so the card reserves space once, and a box
   rather than two buttons in the row itself because a button will not shrink
   below its min-content width — which is the trap this dialog's header comment
   is about, and the reason the card is a div with controls laid over it. */
.song-dialog-actions {
  position: absolute;
  right: 6px;
  top: 50%;
  transform: translateY(-50%);
  z-index: 2;
  display: flex;
  align-items: center;
  gap: 4px;
  max-width: calc(100% - 12px);
}

.song-dialog-delete {
  margin: 0;
  box-sizing: border-box;
  white-space: nowrap;
}

/* An arrow, not the word: "Download" beside "Delete" is 11rem of a 375px row
   and leaves the song name nowhere to go. U+2193 is a basic arrow every system
   font has — the same reason the staff spells its accidentals and draws its
   clef. The label lives in `aria-label` and the tooltip. */
.song-dialog-download {
  margin: 0;
  padding: 6px 10px;
  font-size: 1rem;
  line-height: 1;
}

/* Mobile: full-screen Load dialog */
@media (max-width: 800px) {
  .song-dialog-backdrop {
    display: block;
    padding: 0;
    background: #0a0705;
    overflow: hidden;
  }

  .song-dialog-panel {
    display: flex;
    flex-direction: column;
    width: 100%;
    max-width: 100%;
    min-width: 0;
    height: 100%;
    max-height: 100%;
    border-radius: 0;
    border: none;
    box-shadow: none;
    background: linear-gradient(180deg, #16110d 0%, #0c0907 100%);
    overflow: hidden;
    /* Through the named vars like everything else, so simulating a notch on
       `:root` reaches this one too. */
    padding: var(--safe-top) var(--safe-right) var(--safe-bottom) var(--safe-left);
    box-sizing: border-box;
  }

  .song-dialog-header {
    padding: 14px 16px;
    min-height: 56px;
    width: 100%;
    max-width: 100%;
    background: rgba(0, 0, 0, 0.25);
  }

  .song-dialog-title {
    font-size: 1.15rem;
    font-weight: 750;
  }

  .song-dialog-cancel {
    min-height: 44px;
    min-width: 72px;
    flex-shrink: 0;
    padding: 8px 14px;
  }

  .song-dialog-list {
    flex: 1 1 auto;
    padding: 12px 14px 20px;
    width: 100%;
    max-width: 100%;
    min-width: 0;
    overflow-x: clip;
    overflow-y: auto;
    box-sizing: border-box;
  }

  .song-dialog-row {
    margin-bottom: 8px;
  }

  .song-dialog-card {
    border-radius: 10px;
  }

  /* Reserves for the *pair* now, not just Delete. Left at 5.5rem the name ran
     under the download arrow, which is the one thing this row's absolute
     positioning cannot be told about automatically. */
  .song-dialog-item {
    min-height: 56px;
    padding: 12px 8.75rem 12px 12px;
  }

  /* Both right-hand controls are real touch targets on a phone. */
  .song-dialog-download {
    min-height: 44px;
    min-width: 44px;
    padding: 8px 10px;
  }

  .song-dialog-files .re-btn {
    min-height: 44px;
    padding: 8px 6px;
  }

  .song-dialog-name {
    font-size: 1.05rem;
  }

  .song-dialog-meta {
    font-size: 0.75rem;
  }

  .song-dialog-delete {
    right: 8px;
    min-height: 40px;
    padding-left: 10px;
    padding-right: 10px;
  }

  .song-dialog-empty {
    margin: 24px 12px;
    font-size: 0.9rem;
    line-height: 1.45;
  }
}

/* ── Backup import dialog ──────────────────────────────────────────────────
   Reuses the song dialog's chrome. Its rows have no Delete button, so the
   reserved right padding is dropped, and the descriptions are sentences that
   must wrap rather than be clipped to one line. */

.backup-dialog .song-dialog-item {
  padding-right: 12px;
}

.backup-dialog .song-dialog-meta,
.backup-dialog .backup-dialog-line,
.backup-dialog .backup-dialog-warning {
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
}

.backup-dialog .backup-dialog-file {
  margin: 0 0 4px;
  font-family: var(--mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  word-break: break-all;
}

.backup-dialog .backup-dialog-line {
  margin: 0 0 10px;
  font-size: 0.9rem;
  line-height: 1.45;
}

.backup-dialog .backup-dialog-warning {
  margin: 0 0 10px;
  padding: 8px 10px;
  border: 1px solid rgba(255, 193, 7, 0.45);
  border-radius: 6px;
  background: var(--amber-dim, rgba(255, 193, 7, 0.08));
  font-size: 0.8rem;
  line-height: 1.45;
}

.backup-dialog .song-dialog-item.is-danger .song-dialog-name {
  color: var(--danger, #ff6b6b);
}

.backup-dialog .song-dialog-item.is-danger:hover {
  background: rgba(255, 107, 107, 0.08);
}

/* ── Progression ───────────────────────────────────────────────────────────
   Bars sit in a wrapping row the way they do on a chart, so four bars of a
   verse read as one line. Cells are square-ish and touch-sized; the remove
   affordance sits inside the cell rather than beside it, for the same reason
   the song dialog keeps Delete out of the flex row. */

.prog-panel {
  margin-top: 18px;
}

.prog-header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 8px 10px;
  margin-bottom: 8px;
}

.prog-header-actions {
  display: flex;
  align-items: center;
  gap: 8px;
}

/* The heading is the fold control: a separate button beside it would be one
   more thing in a row that already carries two. */
.panel-fold {
  appearance: none;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 6px 4px 2px;
  margin-left: -2px;
  border: 1px solid transparent;
  border-radius: 6px;
  background: transparent;
  color: inherit;
  font: inherit;
  cursor: pointer;
}

.panel-fold:hover {
  border-color: var(--line, rgba(255, 255, 255, 0.16));
  background: rgba(255, 255, 255, 0.03);
}

.panel-fold .section-title {
  cursor: inherit;
}

/* A drawn chevron in a box of its own, rather than a 12px `▾` in the text.
   The glyph was legible but did not read as a control — the thing that says
   "this opens and shuts" is the bounded shape, not the arrow's size. Rotating
   a rounded square looks like rotating only the arrow, so the box costs the
   animation nothing. */
.panel-fold-chevron {
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  flex: none;
  border: 1px solid var(--border);
  border-radius: 8px;
  color: var(--text-muted);
  background: rgba(255, 255, 255, 0.03);
  transition:
    transform 0.18s ease,
    color 0.15s ease,
    border-color 0.15s ease;
}

.panel-fold-chevron svg {
  width: 18px;
  height: 18px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2.2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.panel-fold:hover .panel-fold-chevron {
  color: var(--amber-text);
  border-color: rgba(255, 193, 7, 0.4);
  background: rgba(255, 193, 7, 0.08);
}

/* One rule for all three panels: the fold is the same control everywhere, so
   the state that turns it should not be written out three times. */
.is-collapsed .panel-fold-chevron {
  transform: rotate(-90deg);
}

.prog-panel.is-collapsed .prog-header {
  margin-bottom: 0;
}

.prog-body[hidden] {
  display: none;
}

/* One section at a time, so something has to say which one and how to reach
   the others — otherwise everything after the first is unreachable here. It
   sits in the panel header; `margin-left: auto` puts it against the Edit /
   Live pair rather than letting `space-between` strand it in the middle. */
.prog-nav-slot {
  display: flex;
  align-items: center;
  margin-left: auto;
}

/* Stepping sections you cannot see is not a control, it is a puzzle. */
.prog-panel.is-collapsed .prog-nav-slot {
  display: none;
}

.prog-nav {
  display: flex;
  align-items: center;
  gap: 4px;
  flex: 0 0 auto;
}

.prog-nav-step {
  appearance: none;
  flex: 0 0 auto;
  min-width: 1.9rem;
  min-height: 1.9rem;
  padding: 0;
  border: 1px solid var(--line, rgba(255, 255, 255, 0.18));
  border-radius: 6px;
  background: transparent;
  color: var(--text-muted);
  font: inherit;
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
}

.prog-nav-step:hover:not(:disabled) {
  border-color: rgba(255, 193, 7, 0.45);
  color: var(--amber-text);
}

.prog-nav-step:disabled {
  opacity: 0.3;
  cursor: not-allowed;
}

.prog-nav-count {
  font-size: 0.72rem;
  color: var(--text-faint);
  font-variant-numeric: tabular-nums;
}

/* Live mode has no time axis to draw, so the chart is not shown — only what
   the song has, and the way back into the editor. */
.prog-live {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 12px;
  padding: 10px 12px;
  border: 1px solid var(--line, rgba(255, 255, 255, 0.12));
  border-radius: 8px;
  color: var(--text-faint);
  font-size: 0.82rem;
}

.song-mode-button.is-song {
  border-color: rgba(255, 193, 7, 0.55);
  background: var(--amber-dim);
  color: var(--amber, #ffc107);
}

.prog-view {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.prog-empty {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 10px;
  padding: 14px;
  border: 1px dashed var(--line, rgba(255, 255, 255, 0.16));
  border-radius: 8px;
}

.prog-empty-text {
  margin: 0;
  color: var(--text-faint);
  font-size: 0.85rem;
  line-height: 1.5;
}

.prog-section {
  position: relative;
  border: 1px solid var(--line, rgba(255, 255, 255, 0.14));
  border-radius: 8px;
  padding: 10px;
}

.prog-section-header {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 8px;
}

/* Reorder controls, kept together on the left so "how do I move this" is one
   place rather than two. */
.prog-section-move {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 2px;
}

/* Drag needs a pointer, and under 800px there is not one — a grip that cannot
   be dragged is worse than no grip, and hiding it is what pays for the two
   step buttons in a header that already holds four controls. */
.prog-section-grip {
  padding: 0 2px;
  color: var(--text-faint);
  font-size: 1rem;
  line-height: 1;
  cursor: grab;
  user-select: none;
}

.prog-section-grip:active {
  cursor: grabbing;
}

.prog-section-step {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 1.75rem;
  height: 2rem;
  padding: 0;
  font-size: 0.7rem;
  line-height: 1;
}

.prog-section.is-dragging {
  opacity: 0.4;
}

/* Laid over the boundary rather than sitting in the column: a row of its own
   would take the chart's 12px gap on both sides and push every section apart.
   Absolute costs no layout, so a chart with nothing in flight is unchanged. */
.pe-section-gap {
  position: absolute;
  left: -1px;
  right: -1px;
  height: 12px;
  border-radius: 6px;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.12s ease;
}

.pe-section-gap.is-above {
  top: -13px;
}

.pe-section-gap.is-below {
  bottom: -13px;
}

/* Only a section in flight opens them — set as a class at `dragstart`, because
   re-rendering the chart there would destroy the element being dragged. */
.pe-chart.is-moving-section .pe-section-gap {
  /* Taller than the gap it covers, so a mouse can find it: 12px of true gap
     plus 6px into each neighbour's 10px padding, which nothing else claims. */
  height: 24px;
  pointer-events: auto;
  opacity: 1;
  border: 1px dashed var(--line, rgba(255, 255, 255, 0.28));
}

.pe-chart.is-moving-section .pe-section-gap.is-above {
  top: -19px;
}

.pe-chart.is-moving-section .pe-section-gap.is-below {
  bottom: -19px;
}

.pe-section-gap.is-drop-target {
  border-color: var(--amber, #ffc107);
  background: rgba(255, 193, 7, 0.18);
}

.prog-section-name {
  flex: 1 1 auto;
  min-width: 0;
  padding: 4px 8px;
  border: 1px solid transparent;
  border-radius: 6px;
  background: transparent;
  color: var(--text);
  font: inherit;
  font-weight: 700;
}

.prog-section-name:hover,
.prog-section-name:focus {
  border-color: var(--line, rgba(255, 255, 255, 0.2));
  background: rgba(255, 255, 255, 0.03);
  outline: none;
}

.prog-repeat {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  color: var(--text-faint);
  font-size: 0.85rem;
}

.prog-repeat-input {
  width: 3.2rem;
  padding: 4px 6px;
  border: 1px solid var(--line, rgba(255, 255, 255, 0.2));
  border-radius: 6px;
  background: transparent;
  color: var(--text);
  font: inherit;
  text-align: center;
}

/* A square `+` rather than a word: the name field beside it needs the width,
   and it has to survive being next to Remove on a 375px screen. */
.prog-section-insert {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 2rem;
  height: 2rem;
  padding: 0;
  font-size: 1.1rem;
  line-height: 1;
}

/* Make, copy, unmake — one box, so a narrow screen moves all three to the next
   line together rather than splitting them across the wrap. Above 800px it
   changes nothing: the same gap, the same order, one line. */
.prog-section-actions {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 8px;
}

/* Square like the `+` beside it, and the same size: they are two answers to
   "another section like this one", so one of them looking heavier would be
   saying something the buttons do not mean. */
.prog-section-duplicate {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 2rem;
  height: 2rem;
  padding: 0;
  font-size: 1.05rem;
  line-height: 1;
}

.prog-section-remove {
  flex: 0 0 auto;
}

/* Which of the song's rhythms this section plays. Narrow on purpose: it sits on
   the one row with no slack, where the name field pays for every pixel spent —
   so the chip carries a glyph and a number and the full name lives in the strip
   at the top of the editor and in the button's own label. */
.prog-section-rhythm {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  min-width: 2.4rem;
  height: 2rem;
  padding: 0 6px;
  border: 1px dashed var(--line, rgba(255, 255, 255, 0.2));
  border-radius: 6px;
  background: transparent;
  color: var(--text-faint);
  font: inherit;
  font-size: 0.85rem;
  line-height: 1;
  cursor: pointer;
}

/* Dashed and faint while the section follows the song, solid once it does not:
   the border is what says "this section has been given something of its own",
   which is the only state worth spotting from across the chart. */
.prog-section-rhythm.is-set {
  border-style: solid;
  border-color: var(--accent, #e0a44b);
  color: var(--accent, #e0a44b);
  font-weight: 700;
}

.prog-section-rhythm:hover,
.prog-section-rhythm:focus-visible {
  border-color: var(--accent, #e0a44b);
  color: var(--accent, #e0a44b);
  outline: none;
}

.prog-section-remove-short {
  display: none;
}

.prog-bars {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

/* The long heading is what crowds the panel header on a phone, so the short
   one takes over there. Both are in the DOM; the button's aria-label is what
   keeps the accessible name the same either way. */
.panel-title-short {
  display: none;
}

.prog-bar {
  position: relative;
  flex: 0 0 auto;
  width: 5.25rem;
  min-height: 3.25rem;
  padding: 6px 8px;
  border: 1px solid var(--line, rgba(255, 255, 255, 0.2));
  border-radius: 6px;
  background: rgba(255, 255, 255, 0.02);
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.prog-bar:hover {
  border-color: rgba(255, 193, 7, 0.45);
  background: rgba(255, 193, 7, 0.06);
}

.prog-bar.is-playing {
  border-color: var(--amber, #ffc107);
  background: var(--amber-dim, rgba(255, 193, 7, 0.14));
  box-shadow: 0 0 0 1px var(--amber, #ffc107) inset;
}

.prog-bar.is-hold .prog-bar-chord {
  color: var(--text-faint);
}

.prog-bar-number {
  display: block;
  font-size: 0.66rem;
  color: var(--text-faint);
  line-height: 1;
}

.prog-bar-chord {
  display: block;
  margin-top: 4px;
  font-weight: 700;
  font-size: 1rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.prog-bar-remove {
  position: absolute;
  top: 2px;
  right: 4px;
  padding: 0 4px;
  color: var(--text-faint);
  font-size: 0.85rem;
  line-height: 1.2;
  opacity: 0;
  cursor: pointer;
}

.prog-bar:hover .prog-bar-remove,
.prog-bar:focus-within .prog-bar-remove {
  opacity: 1;
}

.prog-bar-remove:hover {
  color: var(--danger, #ff8a65);
}

.prog-bar-add {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 3rem;
  border-style: dashed;
  color: var(--text-faint);
  font-size: 1.25rem;
}

.prog-footer {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}

.prog-summary {
  color: var(--text-faint);
  font-size: 0.78rem;
}

/* The chart on the main page only reads — every edit is in the dialog, so the
   cells carry no affordance to click. */
.prog-bar.is-static {
  cursor: default;
}

.prog-bar.is-static:hover {
  border-color: var(--line, rgba(255, 255, 255, 0.2));
  background: rgba(255, 255, 255, 0.02);
}

.prog-bar.is-static.is-playing:hover {
  border-color: var(--amber, #ffc107);
  background: var(--amber-dim, rgba(255, 193, 7, 0.14));
}

/* Only drawn when a bar is not a whole one — the common chart stays quiet. */
.prog-bar-length {
  position: absolute;
  top: 3px;
  right: 5px;
  font-size: 0.62rem;
  font-weight: 700;
  line-height: 1;
  color: var(--amber-text, #ffe082);
  opacity: 0.8;
  pointer-events: none;
}

@media (max-width: 800px) {
  /* Touch targets stay finger-sized, and the remove affordance cannot rely on
     hover, so it is always visible on small screens. */
  .prog-bar {
    width: 4.75rem;
    min-height: 3.5rem;
  }

  .prog-bar-remove {
    opacity: 0.55;
  }

  .prog-section-insert {
    width: 2.75rem;
    height: 2.75rem;
  }

  /* The step buttons are the only way to reorder a section here, so they take
     a finger's height. The width stays narrow — same trade as `.prog-nav-step`,
     which the section header has even less room for than the panel header. */
  .prog-section-step {
    height: 2.75rem;
  }

  .prog-section-grip {
    display: none;
  }

  /* Two digits at most (the repeat caps at 16), so the desktop width is slack
     the name field can have back. */
  .prog-repeat-input {
    width: 2.5rem;
    padding: 4px 2px;
  }

  /* Six controls and a text field do not fit a phone, and the field is what
     pays: measured at 18px on a 320px screen, which is not a name box but a
     sliver. So this is the one row here allowed to wrap — the name and the
     repeat keep the first line and the three make/unmake buttons take the
     second, which is a shape rather than a squeeze. The alternative was
     dropping Duplicate under 800px, and a section is *harder* to rebuild by
     hand on a phone, not easier. */
  .prog-section-header {
    flex-wrap: wrap;
  }

  /* What the wrap is for. The basis matters as much as the minimum: wrapping is
     decided on the base size, and an `auto` text field bases on its own default
     character width — wide enough to push everything off the row and then grow
     into a line of its own. A small basis lets the row be measured honestly and
     the field takes what is left over. */
  .prog-section-name {
    flex: 1 1 5.5rem;
    min-width: 5.5rem;
  }

  .prog-section-duplicate {
    width: 2.75rem;
    height: 2.75rem;
  }

  /* Taller for a thumb, but *not* wider: it shares line one with the name field,
     and width here comes straight out of the box a section name is typed into. */
  .prog-section-rhythm {
    height: 2.75rem;
  }

  /* A square `×`, matching the `+` beside it and the `×` on every bar. */
  .prog-section-remove {
    display: grid;
    place-items: center;
    width: 2.75rem;
    height: 2.75rem;
    padding: 0;
    font-size: 1.2rem;
    line-height: 1;
  }

  .prog-section-remove-long {
    display: none;
  }

  .prog-section-remove-short {
    display: inline;
  }

  /* `Progression` is 99px of a 351px row that also has to hold the stepper and
     two buttons. `Prog` is the same word at the width that is available. */
  .panel-title-long {
    display: none;
  }

  .panel-title-short {
    display: inline;
  }

  /* Four controls on one row leaves no slack, and the row is not allowed to
     wrap — a second line here is the whole thing this was meant to remove.
     80 + 86 + 115 is 281 of the 296 a 320px phone has, so the gaps are what
     decides it. Measured at 320 and 375; both stay on one line. */
  .prog-header {
    column-gap: 8px;
  }

  .prog-nav {
    gap: 2px;
  }

  .prog-nav-step {
    min-width: 1.75rem;
  }

  /* `.main` already puts an 18px gap between panels; the extra margin made it
     36px, which on a phone is a band of nothing between Settings and the chart
     a player is reading. */
  .prog-panel {
    margin-top: 0;
  }

  /* One line that scrolls, rather than as many rows as the section needs. Five
     bars wrapped to two rows and a nav line of its own put this panel at 252px
     on a 375px phone — most of it saying what the highlight says in one place.
     The view scrolls the sounding bar into itself, so the row a player wants is
     the row that is there.

     Scoped to the main page's view: the editor's `.prog-bars` is a different
     surface where wrapping is what you want, because you are reading the whole
     chart rather than following one bar through it. */
  .prog-view .prog-bars {
    flex-wrap: nowrap;
    overflow-x: auto;
    overflow-y: hidden;
    /* Room for the highlight's ring, which a tight box would clip. */
    padding-bottom: 2px;
    scrollbar-width: none;
  }

  .prog-view .prog-bars::-webkit-scrollbar {
    display: none;
  }

  /* The scrollbar is hidden, so the edge says it instead. `data-edge` names the
     side that has more behind it — set by the view, because CSS cannot ask
     whether a box overflows. Absent means the whole section fits and neither
     edge should fade. */
  .prog-view .prog-bars[data-edge='start'] {
    mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent);
  }

  .prog-view .prog-bars[data-edge='end'] {
    mask-image: linear-gradient(to left, #000 calc(100% - 28px), transparent);
  }

  .prog-view .prog-bars[data-edge='both'] {
    mask-image: linear-gradient(
      to right,
      transparent,
      #000 28px calc(100% - 28px),
      transparent
    );
  }
}

/* ── Progression editor (full-screen overlay) ───────────────────────────────
   Same shape as the rhythm editor: header, a body that scrolls, and a fixed
   band at the bottom. The band is the chord palette — bars are filled by
   dragging from it, so it has to stay in reach of every bar above it. */

.prog-editor {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  flex-direction: column;
  padding: var(--safe-top) var(--safe-right) var(--safe-bottom) var(--safe-left);
  background: var(--bg, #0a0705);
}

.prog-editor[hidden] {
  display: none;
}

.pe-header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 10px 16px;
  padding: 12px 18px;
  border-bottom: 1px solid var(--border);
  background: rgba(0, 0, 0, 0.4);
}

.pe-header-left {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.pe-header-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
}

/* The song's rhythms. One row that scrolls sideways, never wraps: this sits
   above the chart, so a fourth entry wrapping onto a second line would push the
   chart down the screen — the cost the chord palette avoids by being a column. */
.pe-rhythms {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 18px;
  border-bottom: 1px solid var(--border);
  background: rgba(0, 0, 0, 0.22);
}

.pe-rhythms-label {
  flex: 0 0 auto;
  color: var(--text-faint);
  font-size: 0.78rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.pe-rhythm-list {
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  overflow-x: auto;
  scrollbar-width: none;
}

.pe-rhythm-list::-webkit-scrollbar {
  display: none;
}

.pe-rhythm-add {
  flex: 0 0 auto;
}

.pe-rhythm-hint {
  color: var(--text-faint);
  font-size: 0.85rem;
}

.pe-rhythm-chip {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 4px 6px 4px 4px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.04);
  font-size: 0.85rem;
  white-space: nowrap;
}

/* A rhythm the library no longer holds. The section still plays — it falls back
   to the song's own — so this is an explanation, not an error. */
.pe-rhythm-chip.is-missing {
  border-color: var(--warn, #d08a2c);
  color: var(--warn, #d08a2c);
}

.pe-rhythm-tag {
  display: grid;
  place-items: center;
  min-width: 1.6rem;
  padding: 0 4px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.08);
  color: var(--accent, #e0a44b);
  font-weight: 700;
  font-size: 0.8rem;
}

.pe-rhythm-name {
  color: var(--text);
}

/* How many sections play it — which is also the reason removing it is refused. */
.pe-rhythm-used {
  color: var(--text-faint);
  font-size: 0.78rem;
}

.pe-rhythm-remove {
  display: grid;
  place-items: center;
  width: 1.4rem;
  height: 1.4rem;
  padding: 0;
  border: none;
  border-radius: 999px;
  background: transparent;
  color: var(--text-faint);
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
}

.pe-rhythm-remove:hover,
.pe-rhythm-remove:focus-visible {
  background: rgba(255, 255, 255, 0.1);
  color: var(--text);
  outline: none;
}

/* Chart left, palette right. The palette was a band under the chart, which put
   it furthest from bar 1 exactly as the chart grew — beside it, every bar is
   the same short drag away. Only the chart scrolls. */
.pe-main {
  flex: 1 1 auto;
  display: flex;
  align-items: stretch;
  min-height: 0;
}

.pe-body {
  flex: 1 1 auto;
  overflow-y: auto;
  padding: 16px 18px;
  min-width: 0;
}

.pe-chart {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

/* Bars in the editor are containers, not buttons: a length control lives
   inside each one and a button cannot hold another control. */
.pe-bar {
  position: relative;
  flex: 0 0 auto;
  width: 6.25rem;
  padding: 4px;
  border: 1px solid var(--line, rgba(255, 255, 255, 0.2));
  border-radius: 6px;
  background: rgba(255, 255, 255, 0.02);
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.pe-bar.is-drop-target {
  border-color: var(--amber, #ffc107);
  background: rgba(255, 193, 7, 0.12);
}

.pe-bar.is-selected {
  border-color: rgba(129, 199, 132, 0.8);
  background: rgba(129, 199, 132, 0.1);
  box-shadow: 0 0 0 1px rgba(129, 199, 132, 0.35) inset;
}

.pe-bar.is-dragging {
  opacity: 0.4;
}

.pe-bar-face {
  appearance: none;
  border: 0;
  background: transparent;
  color: var(--text);
  font: inherit;
  text-align: left;
  padding: 4px 6px 2px;
  border-radius: 4px;
  cursor: grab;
  min-height: 2.75rem;
}

.pe-bar-face:hover {
  background: rgba(255, 193, 7, 0.08);
}

.pe-bar.is-hold .pe-bar-chord {
  color: var(--text-faint);
}

.pe-bar-number {
  display: block;
  font-size: 0.64rem;
  color: var(--text-faint);
  line-height: 1;
}

.pe-bar-chord {
  display: block;
  margin-top: 4px;
  font-weight: 700;
  font-size: 1rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.pe-bar-length {
  width: 100%;
  min-height: 26px;
  padding: 2px 4px;
  border: 1px solid var(--line, rgba(255, 255, 255, 0.14));
  border-radius: 4px;
  background: var(--bg-panel);
  color: var(--text-muted);
  font: inherit;
  font-size: 0.72rem;
  cursor: pointer;
}

.pe-bar-length:hover {
  border-color: rgba(255, 193, 7, 0.4);
}

/* The rhythm-restart chip and the marks it leaves.

   Amber rather than the selection green: this is not a chord and not a
   selection, it is a note about the chart's own metre, and it has to read as a
   different kind of thing from everything else in the palette. */
.pe-reset-figure-chip {
  width: 100%;
  margin: 8px 0 4px;
  padding: 6px 8px;
  border: 1px dashed rgba(255, 193, 7, 0.5);
  border-radius: 6px;
  background: rgba(255, 193, 7, 0.06);
  color: var(--amber, #ffc107);
  font: inherit;
  font-size: 0.78rem;
  text-align: center;
  cursor: grab;
}

.pe-reset-figure-chip:hover {
  border-style: solid;
  background: rgba(255, 193, 7, 0.14);
}

.pe-reset-figure-chip:active {
  cursor: grabbing;
}

/* Top-left, because the remove × already owns the top-right corner. */
.pe-bar-restart,
.pe-bar-phase-warn {
  position: absolute;
  top: 1px;
  left: 3px;
  padding: 0 3px;
  font-size: 0.8rem;
  line-height: 1.2;
  cursor: pointer;
}

.pe-bar-restart {
  color: var(--amber, #ffc107);
}

/* The offer, not the mark: dimmer, and it carries a `?` so it reads as
   something to press rather than a state already set. */
.pe-bar-phase-warn {
  color: rgba(255, 193, 7, 0.55);
}

.pe-bar-phase-warn::after {
  content: '?';
  font-size: 0.7rem;
}

.pe-bar-phase-warn:hover {
  color: var(--amber, #ffc107);
}

.pe-bar.is-figure-restart {
  border-left: 2px solid var(--amber, #ffc107);
}

.pe-bar.is-phase-break {
  border-left: 2px dashed rgba(255, 193, 7, 0.45);
}

/* A bar that plays written notes rather than the rhythm.

   Bottom-right of the face, which is the one corner of a bar cell nothing else
   claims — the restart mark is top-left, remove is top-right, and the length
   select owns the row underneath. Green rather than the restart's amber: amber
   is this chart's colour for "something about the metre needs attention", and a
   melody is a thing the user asked for, not a warning. */
.pe-bar-melody {
  position: absolute;
  right: 4px;
  bottom: 32px;
  padding: 0 3px;
  color: rgba(129, 199, 132, 0.95);
  font-size: 0.85rem;
  line-height: 1.2;
  cursor: pointer;
}

/* Stored but not played: the length it was written for no longer matches the
   bar. Struck through rather than hidden, because the notes are still there and
   the user is the one who decides whether to rewrite or restore the length. */
.pe-bar.is-melody-stale .pe-bar-melody {
  color: rgba(255, 193, 7, 0.6);
  text-decoration: line-through;
}

/* Written, playing, and wrong about something — a note past the bar line, or two
   notes sounding at once in a line that is meant to be one. Amber, because this
   is the chart's colour for "the metre needs attention", which is exactly what
   these are; the glyph itself changes to say which kind of mark it is. */
.pe-bar-melody.is-warned {
  color: rgba(255, 193, 7, 0.95);
}

.pe-bar.is-melodic {
  border-bottom: 2px solid rgba(129, 199, 132, 0.75);
}

.pe-bar.is-melody-stale {
  border-bottom: 2px dashed rgba(255, 193, 7, 0.45);
}

.pe-bar-remove {
  position: absolute;
  top: 1px;
  right: 3px;
  padding: 0 4px;
  color: var(--text-faint);
  font-size: 0.85rem;
  line-height: 1.2;
  opacity: 0;
  cursor: pointer;
}

.pe-bar:hover .pe-bar-remove,
.pe-bar:focus-within .pe-bar-remove {
  opacity: 1;
}

.pe-bar-remove:hover {
  color: var(--danger, #ff8a65);
}

.pe-bar-add {
  align-self: stretch;
  width: 3.5rem;
  min-height: 5rem;
  border: 1px dashed var(--line, rgba(255, 255, 255, 0.25));
  border-radius: 6px;
  background: transparent;
  color: var(--text-faint);
  font-size: 1.35rem;
  cursor: pointer;
}

.pe-bar-add:hover,
.pe-bar-add.is-drop-target {
  border-color: var(--amber, #ffc107);
  color: var(--amber, #ffc107);
  background: rgba(255, 193, 7, 0.08);
}

/* Standing in for the selection after the last bar of a section was filled, so
   it is drawn the way a selected bar is — solid rather than dashed, and lit.
   `:focus-visible` cannot carry this: the focus arrives programmatically from a
   mouse click on a chord, where the browser's heuristic says draw nothing. */
.pe-bar-add.is-next {
  border-style: solid;
  border-color: var(--amber, #ffc107);
  color: var(--amber, #ffc107);
  background: rgba(255, 193, 7, 0.14);
  box-shadow: 0 0 0 2px rgba(255, 193, 7, 0.28);
}

.pe-palette {
  flex: 0 0 auto;
  width: clamp(13rem, 22vw, 17rem);
  overflow-y: auto;
  border-left: 1px solid var(--border);
  background: rgba(0, 0, 0, 0.42);
  padding: 12px 14px 16px;
}

/* Stacked, not a row: in a column this narrow two buttons side by side take
   min-content width and the second one loses its label. */
.pe-palette-header {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 8px;
  margin-bottom: 10px;
}

.pe-palette-header .section-hint {
  line-height: 1.4;
}

/* Equal shares, so three buttons in a narrow column cannot squeeze each other
   down to min-content the way a flex row would. */
.pe-selection-actions {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 6px;
}

.pe-selection-actions[hidden] {
  display: none;
}

.pe-selection-actions .header-button {
  padding-left: 4px;
  padding-right: 4px;
  text-align: center;
}

/* Two to a row — wide enough for a chord name, narrow enough that the whole
   palette stands beside the chart without scrolling. */
.pe-chord-grid {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 6px;
}

/* The palette is a drag source, so its cells are shorter than the main grid —
   fifteen full-height chord buttons would not fit the column. */
.pe-chord-grid .chord-button {
  min-height: 0;
  padding: 14px 6px 8px;
  font-size: clamp(0.85rem, 1.8vw, 1.05rem);
  cursor: grab;
}

.pe-chord-grid .chord-slot {
  top: 3px;
  left: 6px;
}

.pe-chord-grid .chord-button:active {
  cursor: grabbing;
}

@media (max-width: 800px) {
  .pe-header {
    padding: 10px 12px;
  }

  .pe-body {
    padding: 12px;
  }

  /* A sidebar and a chart cannot both have a usable width on a phone, so the
     palette goes back under the chart — five to a row, as it reads there. */
  .pe-main {
    flex-direction: column;
  }

  .pe-palette {
    width: auto;
    overflow-y: visible;
    border-left: 0;
    border-top: 1px solid var(--border);
    padding: 8px 12px 12px;
  }

  .pe-palette-header {
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 12px;
  }

  .pe-palette-header .section-hint {
    margin-left: auto;
  }

  .pe-chord-grid {
    grid-template-columns: repeat(5, minmax(0, 1fr));
  }

  .pe-bar {
    width: 5.5rem;
  }

  /* Hover cannot reveal anything on a touch screen. */
  .pe-bar-remove {
    opacity: 0.55;
  }

  /* The glyph stays 15px — a bigger ↻ would crowd the chord under it — so the
     tap area is grown with padding and pulled back with a negative offset. The
     badge is how a phone user fixes a chart that has gone out of phase, which
     makes it worth more than the `×` it sits opposite. */
  .pe-bar-restart,
  .pe-bar-phase-warn {
    top: -4px;
    left: -1px;
    padding: 6px 8px;
  }

  /* Same trick for the melody badge, and it has to keep clear of the length
     select below it — so the padding is grown upward and the offset follows. */
  .pe-bar-melody {
    right: -1px;
    bottom: 30px;
    padding: 6px 8px;
  }

  .pe-chord-grid .chord-button {
    padding: 8px 4px 6px;
  }
}

/* ── Touch targets ──────────────────────────────────────────────────────────
   The small controls sit between 27 and 34px tall, which a mouse hits exactly
   and a thumb does not. Raised to 44px at the touch breakpoint only: on
   desktop the compact row is worth keeping, and this is comfort rather than
   compliance — WCAG 2.2 AA asks 24px, which they already clear.

   Height only. Widening them would put two buttons in a flex row over a phone's
   width, which is the layout rule this UI keeps breaking.                    */
@media (max-width: 800px) {
  .header-button,
  .panel-fold,
  .song-name-button,
  .preview-arpeggio-button {
    min-height: 44px;
  }

  /* The settings rows: `.field select` and the key button already carry a
     40px floor at two-class specificity, so these have to match it to win. */
  .field select,
  .field .key-select-btn {
    min-height: 44px;
  }

  /* The section stepper sits among the header buttons now, so it is a thumb
     target like them. Height only — its width is what the row cannot spare. */
  .prog-nav-step {
    min-height: 44px;
  }

  /* Square icon buttons need the width too — they have no label to stretch. */
  .menu-close {
    min-width: 44px;
    min-height: 44px;
  }

  /* The cues are already in equal grid tracks, so height is all they need —
     widening them is what the `1fr` is for. */
  .cue-button {
    min-height: 44px;
  }

  .play-pause-button {
    width: 40px;
    height: 40px;
  }
}

/* ── Rhythm picker ──────────────────────────────────────────────────────────
   A list of rows rather than a wheel: each rhythm carries a picture of its
   figure, which is the whole reason this replaced a `<select>`. Backdrop and
   panel follow the key picker so the two read as the same kind of thing.   */

.rhythm-picker-backdrop {
  position: fixed;
  inset: 0;
  z-index: 125;
  display: grid;
  place-items: center;
  padding:
    calc(16px + var(--safe-top))
    calc(16px + var(--safe-right))
    calc(16px + var(--safe-bottom))
    calc(16px + var(--safe-left));
  background: rgba(0, 0, 0, 0.72);
  animation: key-picker-fade 0.18s ease-out;
}

.rhythm-picker-panel {
  width: min(520px, 100%);
  max-height: min(94vh, 720px);
  display: flex;
  flex-direction: column;
  border-radius: 14px;
  border: 1px solid var(--border);
  background: var(--panel, #14161a);
  box-shadow: 0 20px 56px rgba(0, 0, 0, 0.55);
  overflow: hidden;
}

.rhythm-picker-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 14px 18px;
  border-bottom: 1px solid var(--border);
}

.rhythm-picker-title {
  margin: 0;
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text-muted);
}

/* Strum / Arpeggio, when the mode is part of what is being chosen. Two equal
   tracks rather than a flex row: the labels are fixed and short, and equal tracks
   keep the pair reading as one switch instead of two buttons. */
.rhythm-picker-modes {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 6px;
  margin: 12px 14px 0;
}

.rhythm-picker-mode {
  padding: 9px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: transparent;
  color: var(--text-muted);
  font: inherit;
  cursor: pointer;
}

.rhythm-picker-mode.is-active {
  border-color: var(--accent, #e0a44b);
  background: rgba(224, 164, 75, 0.14);
  color: var(--text);
  font-weight: 700;
}

.rhythm-picker-search {
  margin: 12px 14px 6px;
  padding: 9px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.04);
  color: var(--text);
  font: inherit;
  font-size: 0.9rem;
}

.rhythm-picker-list {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 4px 10px 12px;
}

.rhythm-picker-family {
  padding: 12px 6px 4px;
  font-size: 0.64rem;
  font-weight: 650;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-faint);
}

.rhythm-picker-row {
  display: flex;
  align-items: center;
  gap: 6px;
  border-radius: 9px;
}

.rhythm-picker-row.is-current {
  background: rgba(129, 199, 132, 0.14);
  box-shadow: inset 0 0 0 1px rgba(129, 199, 132, 0.5);
}

/* The row is the button. A separate "select" control beside the name would be
   the two-buttons-in-a-flex-row trap, and the whole row is the target a thumb
   wants anyway. */
.rhythm-picker-pick {
  appearance: none;
  flex: 1;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 6px 8px;
  border: 1px solid transparent;
  border-radius: 9px;
  background: transparent;
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.rhythm-picker-pick:hover {
  background: rgba(255, 255, 255, 0.05);
}

.rhythm-picker-pick:focus-visible {
  outline: none;
  border-color: rgba(129, 199, 132, 0.8);
}

.rhythm-picker-name {
  flex: 1;
  min-width: 0;
  font-size: 0.92rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.rhythm-picker-art {
  flex: none;
  display: block;
  line-height: 0;
}

.rhythm-picker-play {
  appearance: none;
  flex: none;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: transparent;
  color: var(--text-faint);
  font-size: 0.7rem;
  cursor: pointer;
}

.rhythm-picker-play:hover:not(:disabled) {
  color: #a5d6a7;
  border-color: rgba(129, 199, 132, 0.7);
}

.rhythm-picker-play.is-playing {
  color: #a5d6a7;
  border-color: rgba(129, 199, 132, 0.9);
  background: rgba(129, 199, 132, 0.16);
}

.rhythm-picker-play:disabled {
  opacity: 0.3;
  cursor: not-allowed;
}

.rhythm-picker-note,
.rhythm-picker-empty {
  margin: 0;
  padding: 10px 18px calc(12px + var(--safe-bottom, 0px));
  font-size: 0.76rem;
  color: var(--text-faint);
}

.rhythm-picker-empty {
  padding: 24px 8px;
  text-align: center;
}

/* The glyph's own parts. Kept in CSS rather than baked into the SVG so the
   preview inherits the app's palette wherever it is dropped. */
.rhythm-preview {
  display: block;
  color: var(--text);
}

.rhythm-preview .rp-string {
  stroke: rgba(255, 255, 255, 0.09);
  stroke-width: 0.6;
}

.rhythm-preview .rp-beat {
  stroke: rgba(255, 255, 255, 0.15);
  stroke-width: 0.7;
}

.rhythm-preview .rp-beat-edge {
  stroke: rgba(255, 255, 255, 0.28);
  stroke-width: 1.1;
}

.rhythm-preview .rp-stroke {
  stroke: currentColor;
  stroke-linecap: round;
  stroke-linejoin: round;
  fill: none;
}

.rhythm-preview .rp-note {
  fill: currentColor;
  stroke: none;
}

.rhythm-preview .rp-mute {
  fill: currentColor;
  font-family: system-ui, sans-serif;
  font-weight: 700;
  text-anchor: middle;
  dominant-baseline: central;
}

/* ── Melody dialog ────────────────────────────────────────────────────────────

   One bar on a five-line staff, with the toolbar that makes it usable without a
   keyboard. Taller than the rhythm editor's dialog and no wider: the staff's
   height is a constant (the writable range is three ledger lines each way) and
   its width is whatever the snap grid needs, so the wrapper scrolls sideways
   rather than the columns shrinking below a fingertip. */

.melody-backdrop {
  position: fixed;
  inset: 0;
  /* Above the chart editor, which is what opened it. */
  z-index: 130;
  display: grid;
  place-items: center;
  padding:
    calc(16px + var(--safe-top))
    calc(16px + var(--safe-right))
    calc(16px + var(--safe-bottom))
    calc(16px + var(--safe-left));
  background: rgba(0, 0, 0, 0.72);
  animation: key-picker-fade 0.18s ease-out;
}

.melody-panel {
  width: min(760px, 100%);
  max-height: min(96vh, 680px);
  display: flex;
  flex-direction: column;
  border-radius: 14px;
  border: 1px solid var(--border);
  background: var(--panel, #14161a);
  box-shadow: 0 20px 56px rgba(0, 0, 0, 0.55);
  /* Scrolls rather than clips once the staff's own floor stops fitting — see
     `.melody-canvas-wrap`. On a landscape phone the footer is then below the
     fold, which is the right thing to give up: you can scroll to a button, you
     cannot aim at a staff squeezed to a sliver. */
  overflow-y: auto;
}

.melody-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  padding: 14px 18px 10px;
  border-bottom: 1px solid var(--border);
}

.melody-headings {
  min-width: 0;
}

.melody-title {
  margin: 0;
  font-size: 1rem;
}

.melody-subtitle {
  margin: 2px 0 0;
  color: var(--text-muted);
  font-size: 0.8rem;
}

.melody-play {
  flex: 0 0 auto;
}

.melody-tools {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 10px 14px 4px;
}

/* Six note values on equal tracks rather than a flex row. A button will not
   shrink below its min-content width, and "32" is wider than "1" — equal tracks
   are what keep the row one line at 320px instead of wrapping one button. */
.melody-values {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 6px;
}

.melody-value {
  min-width: 0;
  padding: 8px 0;
  font-variant-numeric: tabular-nums;
}

.melody-value.is-active,
.melody-action.is-active {
  border-color: rgba(255, 193, 7, 0.7);
  color: rgba(255, 224, 130, 0.95);
  background: rgba(255, 193, 7, 0.14);
}

.melody-actions {
  display: flex;
  align-items: center;
  gap: 6px;
}

.melody-action {
  padding: 8px 10px;
  min-height: 36px;
}

.melody-action:disabled {
  opacity: 0.4;
}

/* The one thing on this row that is not an action; pushed away from them so a
   thumb aiming for Delete cannot land on a select instead. */
.melody-snap {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 6px;
  color: var(--text-muted);
  font-size: 0.78rem;
}

.melody-snap .re-select {
  padding: 6px 8px;
}

/* The staff sizes its own element, so this only has to let it overflow. Both
   axes scroll: the width grows with the snap grid, and a short dialog can be
   shorter than the staff is tall.

   The floor is the part that matters. With `min-height: 0` this box is the one
   flex item that yields, so on an 812x375 landscape phone it collapsed to 45px
   of a 295px staff — 15% of it, measured — while the header, toolbar and footer
   kept every pixel they asked for. The staff is the thing being edited; it gets
   a floor and the panel scrolls instead. */
.melody-canvas-wrap {
  flex: 1 1 auto;
  min-height: 200px;
  overflow: auto;
  padding: 10px 14px;
}

.melody-canvas {
  display: block;
  border-radius: 8px;
  border: 1px solid var(--line, rgba(255, 255, 255, 0.14));
  background: rgba(0, 0, 0, 0.25);
  /* It takes focus for Delete, and a ring around a drawing surface reads as a
     border the drawing does not have. */
  outline-offset: -2px;
  touch-action: none;
}

.melody-status {
  margin: 0;
  padding: 4px 18px 0;
  color: var(--text);
  font-size: 0.82rem;
  font-weight: 600;
}

/* Holds its line whether or not there is anything to say. Collapsing it moves
   the staff the moment the first note is written — the panel gets a line taller
   and everything above the footer shifts — so the next click lands a staff
   position off from where it was aimed. A blank line costs 15px; a staff that
   jumps under the pointer costs the note. The repair button shares the row for
   the same reason: appearing on a line of its own would move the staff too. */
.melody-warnrow {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 2px 18px 0;
  min-height: 1.6rem;
}

.melody-warning {
  margin: 0;
  min-width: 0;
  color: var(--text-muted);
  font-size: 0.78rem;
}

.melody-refit {
  flex: 0 0 auto;
  margin-left: auto;
  padding: 3px 9px;
  font-size: 0.72rem;
  border-color: rgba(255, 193, 7, 0.6);
  color: rgba(255, 224, 130, 0.95);
}

.melody-warning.is-error {
  color: rgba(239, 83, 80, 0.95);
}

.melody-help {
  margin: 0;
  padding: 4px 18px 8px;
  color: var(--text-muted);
  font-size: 0.72rem;
}

.melody-footer {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  padding: 12px 18px;
  border-top: 1px solid var(--border);
}

/* Clear is destructive and sits away from Save, which is the one the thumb is
   aiming for. */
.melody-footer .re-btn:first-child {
  margin-right: auto;
}

/* A landscape phone is not narrow, so the width rules below never fire there —
   but it is short, and the help line is as redundant there as it is on a phone:
   every shortcut it names is a button two rows up. */
@media (max-height: 560px) {
  .melody-help {
    display: none;
  }

  .melody-header {
    padding: 10px 18px 8px;
  }
}

/* ── Score player ───────────────────────────────────────── */

/* Score mode keeps nothing of the accompaniment's chrome but the fretboard.
   The header's rhythm button and transport pill describe the other mode, and
   on a phone the drawer holds only accompaniment song actions, so its toggle
   goes too. The bottom bar's hint names chord keys score mode does not use;
   score messages have their own line over the score. */
.app[data-work-mode="score"] .top-bar-actions,
.app[data-work-mode="score"] .menu-toggle,
.app[data-work-mode="score"] .bottom-bar {
  display: none;
}

/* The fretboard is a companion here, not the stage: half height, and one
   tap folds it away entirely. */
.app[data-work-mode="score"] .visualizer-panel {
  height: 112px;
  min-height: 0;
}

.app[data-work-mode="score"][data-score-fretboard="hidden"] .visualizer-panel {
  display: none;
}

.score-panel {
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-height: 0;
}

.score-panel[hidden] {
  display: none;
}

/* Our icons only. alphaTab draws the score as SVG inside .score-view, and a
   rule reaching it strips every notehead, clef and fret number of its fill —
   the staff lines survive, so it looks like a rendering bug, not a CSS one. */
.score-bar svg,
.score-transport svg {
  width: 20px;
  height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* ── Top bar: files ── */

.score-bar {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
}

.score-icon-btn {
  appearance: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-width: 40px;
  height: 40px;
  padding: 0 8px;
  border: 1px solid transparent;
  border-radius: 10px;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
  flex: 0 0 auto;
}

.score-icon-btn:hover:not(:disabled) {
  color: var(--amber-text);
  background: rgba(255, 193, 7, 0.08);
}

/* display: inline-flex above would otherwise win over [hidden]. */
.score-icon-btn[hidden] {
  display: none;
}

.score-icon-btn:disabled {
  opacity: 0.35;
  cursor: default;
}

.score-icon-btn[aria-pressed='true'],
.score-icon-btn[aria-expanded='true'],
.score-icon-btn.is-active {
  color: var(--amber-text);
  border-color: rgba(255, 193, 7, 0.45);
  background: rgba(255, 193, 7, 0.14);
}

/* Unsaved work is the one state on this bar worth drawing the eye to. */
.score-icon-btn.is-emphasis {
  color: var(--amber);
  border-color: rgba(255, 193, 7, 0.55);
}

.score-file-btn {
  border-color: var(--border);
  color: var(--text);
}

.score-btn-label {
  font-size: 0.8rem;
  font-weight: 600;
}

.score-meta {
  display: flex;
  flex-direction: column;
  min-width: 0;
  flex: 1 1 auto;
  padding: 0 4px;
  line-height: 1.25;
}

.score-title {
  font-weight: 700;
  color: var(--amber-text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.score-sub {
  font-size: 0.72rem;
  color: var(--text-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ── Popovers ── */

.score-pop-anchor {
  position: relative;
  flex: 0 0 auto;
}

.score-pop {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  z-index: 30;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 200px;
  padding: 6px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--bg-panel);
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.45);
}

.score-pop[hidden] {
  display: none;
}

.score-pop-end {
  left: auto;
  right: 0;
}

.score-pop-up {
  top: auto;
  bottom: calc(100% + 6px);
}

.score-pop-wide {
  width: min(300px, calc(100vw - 32px));
  padding: 10px 12px;
  gap: 6px;
}

.score-pop > button {
  appearance: none;
  text-align: left;
  padding: 10px 12px;
  border: 0;
  border-radius: 8px;
  background: transparent;
  color: var(--text);
  font: inherit;
  font-size: 0.85rem;
  cursor: pointer;
}

.score-pop > button:hover:not(:disabled) {
  background: rgba(255, 193, 7, 0.1);
  color: var(--amber-text);
}

.score-pop > button:disabled {
  opacity: 0.4;
  cursor: default;
}

.score-pop-row {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 0.8rem;
  color: var(--text-muted);
}

.score-pop-row input[type='range'] {
  flex: 1 1 auto;
}

.score-pop-heading {
  margin: 6px 0 0;
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.score-pop-note {
  margin: 0;
  font-size: 0.75rem;
  line-height: 1.6;
  color: var(--text-muted);
}

.score-pop-note kbd {
  font-size: 0.7rem;
}

.score-tracks {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.score-track {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  gap: 4px;
}

.score-track-name,
.score-track-btn {
  appearance: none;
  border: 1px solid var(--border);
  background: transparent;
  color: var(--text);
  font-size: 0.75rem;
  padding: 6px 8px;
  border-radius: 8px;
  cursor: pointer;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  text-align: left;
}

.score-track-name.is-selected,
.score-track-btn[aria-pressed='true'] {
  border-color: rgba(255, 193, 7, 0.55);
  background: rgba(255, 193, 7, 0.16);
  color: var(--amber-text);
}

/* ── Stage: the score ── */

.score-stage {
  position: relative;
  min-height: 240px;
  /* alphaTab puts its cursor layer at z-index 1000. Contained here, it stays
     under the popovers that open over the score instead of painting the
     playback line across the settings. */
  isolation: isolate;
}

.score-view {
  height: 100%;
  /* The gutter is reserved before alphaTab measures, or it lays out to the
     width without a scrollbar, the scrollbar then appears, and the last few
     pixels of every system hide behind a horizontal one. */
  overflow-x: hidden;
  overflow-y: auto;
  scrollbar-gutter: stable;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: #fff;
  color: #111;
}

/* alphaTab creates its cursors and marks played notes with .at-highlight,
   but ships no colours for any of them — unstyled, playback draws nothing
   and the score looks as though it were not following along. */
.score-view .at-cursor-bar {
  background: rgba(255, 193, 7, 0.16);
}

.score-view .at-cursor-beat {
  background: rgba(230, 81, 0, 0.85);
  width: 3px;
}

.score-view .at-highlight * {
  fill: #e65100;
  stroke: #e65100;
}

/* alphaTab's drag selection, and the loop drawn with it. */
.score-view .at-selection div {
  background: rgba(255, 170, 0, 0.22);
}

.midi-timeline {
  display: flex;
  flex-direction: column;
  height: 100%;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  background: #120e0b;
}

.midi-timeline[hidden] {
  display: none;
}

.midi-tab-toolbar {
  display: flex;
  flex: none;
  align-items: center;
  gap: 8px;
  padding: 6px 10px;
  border-bottom: 1px solid var(--border);
  font-size: 0.75rem;
  color: rgba(255, 255, 255, 0.6);
}

.midi-tab-toolbar .midi-tab-zoom {
  flex: 1 1 80px;
  min-width: 60px;
  max-width: 260px;
  accent-color: #ffc107;
}

.midi-tab-tool {
  flex: none;
  min-width: 28px;
  height: 26px;
  padding: 0 8px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: transparent;
  color: inherit;
  font: inherit;
  cursor: pointer;
}

.midi-tab-tool:hover:not(:disabled) {
  color: #ffc107;
  border-color: #ffc107;
}

.midi-tab-tool[aria-pressed='true'] {
  color: #ffc107;
  border-color: #ffc107;
}

.midi-tab-tool:disabled {
  opacity: 0.4;
  cursor: default;
}

.midi-tab-readout {
  flex: none;
  margin-left: auto;
  font-variant-numeric: tabular-nums;
}

@media (max-width: 480px) {
  .midi-tab-zoom-label {
    display: none;
  }
}

/* The tab takes what the overview strip leaves. flex-basis 0 keeps the
   canvas's own pixel height from deciding the size it is drawn at. */
.midi-tab-canvas {
  display: block;
  flex: 1 1 0;
  min-height: 0;
  width: 100%;
  cursor: pointer;
}

.midi-mini-canvas {
  display: block;
  flex: none;
  width: 100%;
  height: 48px;
  border-top: 1px solid var(--border);
  cursor: pointer;
  touch-action: none;
}

.score-empty {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 24px;
  text-align: center;
  border: 1px dashed var(--border);
  border-radius: var(--radius);
  background: var(--bg-panel);
}

.score-empty[hidden] {
  display: none;
}

.score-empty-title {
  margin: 0;
  font-weight: 700;
  color: var(--amber-text);
}

.score-empty-body {
  margin: 0 0 10px;
  font-size: 0.8rem;
  color: var(--text-muted);
}

.score-empty-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px;
}

/* Over the foot of the score rather than a row of its own, so a message
   arriving never moves the bars the player is reading. */
.score-toast {
  position: absolute;
  left: 50%;
  bottom: 12px;
  transform: translateX(-50%);
  max-width: calc(100% - 24px);
  margin: 0;
  padding: 7px 14px;
  border-radius: 999px;
  background: rgba(20, 14, 6, 0.9);
  border: 1px solid rgba(255, 193, 7, 0.35);
  color: var(--amber-text);
  font-size: 0.78rem;
  text-align: center;
  pointer-events: none;
  z-index: 5;
}

.score-toast[hidden] {
  display: none;
}

/* ── Bottom bar: playback ── */

.score-transport {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 8px 12px 6px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg-panel);
}

/* A tall hit area around a thin track: the line is 4px, the target is 20. */
.score-progress {
  position: relative;
  height: 20px;
  cursor: pointer;
  touch-action: none;
}

.score-progress::before,
.score-progress-fill,
.score-progress-loop {
  position: absolute;
  top: 8px;
  height: 4px;
  border-radius: 2px;
}

.score-progress::before {
  content: '';
  left: 0;
  right: 0;
  background: rgba(255, 255, 255, 0.1);
}

.score-progress-fill {
  left: 0;
  width: 0;
  background: var(--amber);
}

.score-progress-loop {
  top: 5px;
  height: 10px;
  border-radius: 3px;
  background: rgba(255, 193, 7, 0.28);
  border: 1px solid rgba(255, 193, 7, 0.6);
}

.score-progress-loop.is-off {
  background: transparent;
  border-style: dashed;
  opacity: 0.6;
}

.score-progress-loop[hidden] {
  display: none;
}

.score-progress:focus-visible {
  outline: 2px solid var(--amber);
  outline-offset: 2px;
  border-radius: 4px;
}

.score-transport-meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  min-height: 22px;
}

.score-time,
.score-bpm {
  font-size: 0.75rem;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

.score-loop-chip {
  appearance: none;
  display: inline-flex;
  gap: 6px;
  align-items: center;
  padding: 2px 10px;
  border: 1px solid rgba(255, 193, 7, 0.45);
  border-radius: 999px;
  background: rgba(255, 193, 7, 0.1);
  color: var(--amber-text);
  font-size: 0.72rem;
  cursor: pointer;
  white-space: nowrap;
}

.score-loop-chip[hidden] {
  display: none;
}

/* Equal side tracks keep Play dead centre whatever the sides hold. */
.score-transport-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: center;
  gap: 8px;
}

.score-transport-main {
  display: flex;
  align-items: center;
  gap: 14px;
}

.score-transport-end {
  justify-self: end;
}

.score-play {
  appearance: none;
  display: grid;
  place-items: center;
  width: 52px;
  height: 52px;
  border: 0;
  border-radius: 999px;
  background: var(--amber);
  color: #1a1206;
  cursor: pointer;
}

.score-play svg {
  width: 24px;
  height: 24px;
  stroke-width: 2.4;
}

.score-play .score-play-icon {
  fill: currentColor;
}

.score-play .score-pause-icon,
.score-play.is-playing .score-play-icon {
  display: none;
}

.score-play.is-playing .score-pause-icon {
  display: block;
}

.score-play:disabled {
  opacity: 0.35;
  cursor: default;
}

/* Waiting for the second press: the end of the loop is what it wants. */
.score-icon-btn.is-marking {
  color: var(--amber);
  border-color: rgba(255, 193, 7, 0.7);
  border-style: dashed;
}

.score-chip {
  appearance: none;
  min-width: 56px;
  height: 34px;
  padding: 0 12px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: transparent;
  color: var(--text);
  font-size: 0.8rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  cursor: pointer;
}

.score-chip[aria-expanded='true'] {
  border-color: rgba(255, 193, 7, 0.55);
  color: var(--amber-text);
}

.score-chip:disabled {
  opacity: 0.35;
  cursor: default;
}

.score-speed-presets {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 4px;
  margin-bottom: 6px;
}

.score-speed-presets button {
  appearance: none;
  padding: 8px 0;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: transparent;
  color: var(--text);
  font-size: 0.78rem;
  cursor: pointer;
}

.score-speed-presets button.is-active {
  border-color: rgba(255, 193, 7, 0.55);
  background: rgba(255, 193, 7, 0.16);
  color: var(--amber-text);
}

.score-sound-choices {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  gap: 4px;
}

.score-sound-choices button {
  appearance: none;
  padding: 8px 0;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: transparent;
  color: var(--text);
  font-size: 0.78rem;
  cursor: pointer;
}

.score-ring-toggle {
  appearance: none;
  width: 100%;
  margin-top: 6px;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: transparent;
  color: var(--text);
  font-size: 0.78rem;
  text-align: left;
  cursor: pointer;
}

/* The state reads as a word, not only a colour. */
.score-ring-toggle::after {
  content: 'Off';
  float: right;
  color: var(--text-muted);
}

.score-ring-toggle[aria-pressed='true']::after {
  content: 'On';
  color: inherit;
}

.score-ring-toggle[aria-pressed='true'],
.score-sound-choices button[aria-pressed='true'] {
  border-color: rgba(255, 193, 7, 0.55);
  background: rgba(255, 193, 7, 0.16);
  color: var(--amber-text);
}

.score-lib-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  padding: 4px 8px 8px;
}

@media (max-width: 800px) {
  .app[data-work-mode="score"] .visualizer-panel {
    height: 84px;
  }

  /* The label is the first thing to give up; the folder says it alone. */
  .score-btn-label {
    display: none;
  }

  .score-icon-btn {
    min-width: 38px;
    padding: 0 6px;
  }
}

@media (max-width: 800px) {
  .melody-panel {
    width: 100%;
    max-height: 100%;
  }

  /* The help line is the first thing to go: every shortcut it names is also a
     button two rows up, and on a phone the buttons are the way in anyway. */
  .melody-help {
    display: none;
  }

  .melody-action {
    padding: 8px 8px;
    min-height: 40px;
  }

  /* Five actions and a select do not share a line at 320px — measured, that
     leaves 28px tracks, and "Rest" does not fit one. The select drops to its own
     row instead, which buys the buttons 46px each. Equal tracks rather than a
     flex row for the usual reason: a button will not shrink below its
     min-content width, so flex would push one of them off the end. */
  .melody-actions {
    display: grid;
    grid-template-columns: repeat(6, 1fr);
    gap: 4px;
  }

  .melody-snap {
    grid-column: 1 / -1;
    margin-left: 0;
    justify-content: flex-end;
  }

  /* Three buttons on one line at 320px, and Clear must not squeeze the pair
     that closes the dialog — equal tracks take min-content out of it, the same
     rule the play cues follow. */
  .melody-footer {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
  }

  .melody-footer .re-btn:first-child {
    margin-right: 0;
  }

  .rhythm-picker-panel {
    width: 100%;
    max-height: 100%;
  }

  .rhythm-picker-play {
    width: 44px;
    height: 44px;
  }

  .rhythm-picker-pick {
    min-height: 44px;
  }

  /* The glyph gives the name back its last few characters: at 375px the full
     148 leaves 95px for the text, and "8-Beat Ballad 2" wants 98. It scales
     rather than crops — the viewBox carries the geometry. */
  .rhythm-picker-art svg {
    width: 112px;
    height: auto;
  }
}

/* ── Song controls: icons on a desktop, words in the drawer ─────────────────
   The same five buttons in both places (see `syncSongBarHome`). Below 801px
   nothing here applies and they read exactly as they always have: full-width
   labelled buttons down the drawer.                                        */

.song-bar-button {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}

.song-bar-icon {
  width: 21px;
  height: 21px;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
  /* The drawer keeps the plain worded buttons it had before this existed. */
  display: none;
}

@media (min-width: 801px) {
  /* The title stays centred on the row, not on what is left of it — pushing it
     half the controls' width to the left is visible. So the row reserves the
     same width at both ends and the controls sit in the right one. The width
     is a constant because the icons are: 3 × 36 + 2 gaps. A
     `margin-left: auto` would have been shorter and put the title off centre;
     absolute positioning without the matching padding would let a long title
     run under the icons at 801px. */
  .song-name-row {
    --song-controls-w: 112px;
    position: relative;
    justify-content: center;
    padding-left: var(--song-controls-w);
    padding-right: var(--song-controls-w);
  }

  .song-name-row .song-bar {
    position: absolute;
    right: 0;
    top: 50%;
    transform: translateY(-50%);
    flex: none;
    flex-wrap: nowrap;
    gap: 2px;
  }

  .song-name-row .song-bar-icon {
    display: block;
  }

  /* The word is still there for a screen reader; the tooltip and the label
     say the same thing to everyone else. */
  .song-name-row .song-bar-label {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  .song-name-row .song-bar-button {
    width: 36px;
    height: 36px;
    padding: 0;
    display: grid;
    place-items: center;
    border-color: transparent;
    background: transparent;
    color: var(--text-muted);
  }

  .song-name-row .song-bar-button:hover:not(:disabled) {
    color: var(--amber-text);
    border-color: rgba(255, 193, 7, 0.35);
    background: rgba(255, 193, 7, 0.08);
  }

  /* All three glyphs share one neutral colour. Unsaved state already has the
     adjacent dirty dot, so Save does not need a second colour vocabulary. */
  .song-name-row .song-bar-button.is-emphasis {
    color: var(--text-muted);
    border-color: transparent;
    box-shadow: none;
  }

  /* It is no longer in the drawer, so the spacing that put it there goes too. */
  .top-bar-menu .song-bar {
    margin-right: 0;
    margin-left: 0;
  }
}
