/* =========================================================================
   Choir Practice — design tokens
   One calm palette, adapted automatically to the system appearance.
   ========================================================================= */

:root {
  color-scheme: light dark;

  /* Surfaces and text */
  --bg: #f5f5f7;
  --surface: #ffffff;
  --surface-sunken: #f0f0f3;
  --surface-hover: rgba(0, 0, 0, 0.04);
  --surface-active: rgba(0, 0, 0, 0.07);
  --text: #1d1d1f;
  --text-secondary: #4a4a4f;
  --text-muted: #6e6e73;
  --separator: rgba(0, 0, 0, 0.09);
  --separator-strong: rgba(0, 0, 0, 0.16);

  /* Accents */
  --accent: #0071e3;
  --accent-hover: #0a84ff;
  --accent-soft: rgba(0, 113, 227, 0.1);
  --accent-ring: rgba(0, 113, 227, 0.35);
  --on-accent: #ffffff;
  --danger: #c9251c;
  --danger-soft: rgba(201, 37, 28, 0.1);
  --success: #17803d;

  /* Elevation */
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.06);
  --shadow-md: 0 1px 2px rgba(0, 0, 0, 0.05), 0 6px 18px rgba(0, 0, 0, 0.07);
  --shadow-lg: 0 12px 40px rgba(0, 0, 0, 0.16);
  --paper-shadow: 0 1px 2px rgba(0, 0, 0, 0.05), 0 10px 30px rgba(0, 0, 0, 0.06);

  /* Shape and rhythm */
  --radius-sm: 8px;
  --radius-md: 12px;
  --radius-lg: 16px;
  --radius-xl: 22px;
  --radius-pill: 999px;
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;
  --space-7: 48px;

  /* Score canvas palette (read by js/theme.js) */
  --score-paper: #ffffff;
  --score-staff-line: #c9c9ce;
  --score-barline: #97979d;
  --score-ledger: #b4b4b9;
  --score-ink: #2b2b2f;
  --score-label: #86868b;
  --score-cursor: #0071e3;
  --score-selection-fill: rgba(0, 113, 227, 0.06);
  --score-selection-edge: rgba(0, 113, 227, 0.5);
  --score-muted: #86868b;

  /* Pitch feedback */
  --pitch-listening: #86868b;
  --pitch-correct: #17803d;
  --pitch-close: #b26a00;
  --pitch-off: #c9251c;

  /* The light on the home screen: a cool wash, a warm one, and the ruled
     staves underneath them. Kept as finished colours rather than hues plus a
     strength, because the two appearances want different amounts of each. */
  --wash-cool: rgba(0, 113, 227, 0.13);
  --wash-warm: rgba(255, 149, 92, 0.12);
  --wash-deep: rgba(124, 58, 237, 0.10);
  --wash-lift: rgba(255, 255, 255, 0.6);
  --wash-staff: rgba(0, 0, 0, 0.055);

  /* Card accents, so a shelf of scores is not three of the same blue tile. */
  --tint-a: #0071e3;
  --tint-b: #7c3aed;
  --tint-c: #c2410c;

  --transition: 180ms cubic-bezier(0.32, 0.72, 0, 1);
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #000000;
    --surface: #1c1c1e;
    --surface-sunken: #2c2c2e;
    --surface-hover: rgba(255, 255, 255, 0.07);
    --surface-active: rgba(255, 255, 255, 0.12);
    --text: #f5f5f7;
    --text-secondary: #d1d1d6;
    --text-muted: #9a9aa0;
    --separator: rgba(255, 255, 255, 0.12);
    --separator-strong: rgba(255, 255, 255, 0.22);

    --accent: #0a84ff;
    --accent-hover: #409cff;
    --accent-soft: rgba(10, 132, 255, 0.16);
    --accent-ring: rgba(10, 132, 255, 0.45);
    --danger: #ff6961;
    --danger-soft: rgba(255, 105, 97, 0.16);
    --success: #30d158;

    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.5);
    --shadow-md: 0 2px 10px rgba(0, 0, 0, 0.5);
    --shadow-lg: 0 16px 48px rgba(0, 0, 0, 0.6);
    --paper-shadow: 0 1px 3px rgba(0, 0, 0, 0.6);

    --score-paper: #141417;
    --score-staff-line: #4a4a4f;
    --score-barline: #6f6f76;
    --score-ledger: #5a5a60;
    --score-ink: #e8e8ed;
    --score-label: #98989d;
    --score-cursor: #0a84ff;
    --score-selection-fill: rgba(10, 132, 255, 0.12);
    --score-selection-edge: rgba(10, 132, 255, 0.6);
    --score-muted: #98989d;

    --pitch-listening: #98989d;
    --pitch-correct: #30d158;
    --pitch-close: #ffd60a;
    --pitch-off: #ff6961;

    /* Against black the wash has to be stronger to read as light at all. */
    --wash-cool: rgba(10, 132, 255, 0.32);
    --wash-warm: rgba(255, 138, 76, 0.18);
    --wash-deep: rgba(126, 78, 255, 0.30);
    --wash-lift: rgba(255, 255, 255, 0.07);
    --wash-staff: rgba(255, 255, 255, 0.075);

    --tint-a: #4a9eff;
    --tint-b: #a78bfa;
    --tint-c: #fb923c;
  }
}

/* =========================================================================
   Base
   ========================================================================= */

*,
*::before,
*::after {
  box-sizing: border-box;
}

* {
  margin: 0;
  padding: 0;
}

html {
  -webkit-text-size-adjust: 100%;
}

body {
  /* A definite height keeps the middle grid row bounded, so the scrolling
     score cannot stretch the page instead of scrolling inside its frame. */
  height: 100vh;
  height: 100dvh;
  display: grid;
  grid-template-rows: auto minmax(0, 1fr) auto;
  background: var(--bg);
  color: var(--text);
  font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  font-size: 15px;
  line-height: 1.5;
  letter-spacing: -0.01em;
  -webkit-font-smoothing: antialiased;
  overflow: hidden;
}

h1, h2, h3 {
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.2;
}

button,
input,
output,
legend,
fieldset {
  font: inherit;
  color: inherit;
}

fieldset {
  border: 0;
  min-inline-size: 0;
}

button {
  background: none;
  border: 0;
  cursor: pointer;
}

kbd {
  display: inline-block;
  min-width: 1.5em;
  padding: 1px 5px;
  border: 1px solid var(--separator-strong);
  border-radius: 5px;
  background: var(--surface-sunken);
  color: var(--text-secondary);
  font-family: inherit;
  font-size: 0.78em;
  text-align: center;
}

code {
  padding: 1px 5px;
  border-radius: 5px;
  background: var(--surface-sunken);
  font-size: 0.85em;
}

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* Native controls follow the accent so focus and fill stay consistent. */
input[type="range"],
input[type="checkbox"] {
  accent-color: var(--accent);
}

/* Anything the app hides with the attribute has to actually go.
   The user-agent rule for [hidden] is display: none, but it loses to any author
   rule, so a component with a display of its own — a grid row, a flex bar, an
   inline SVG — would stay on screen. This is declared once so every hideable
   element behaves, rather than each class repeating the same override. */
[hidden] {
  display: none !important;
}

.visually-hidden {
  position: absolute !important;
  width: 1px !important;
  height: 1px !important;
  margin: -1px !important;
  padding: 0 !important;
  overflow: hidden !important;
  clip-path: inset(50%) !important;
  white-space: nowrap !important;
  border: 0 !important;
}

.skip-link {
  position: fixed;
  top: var(--space-2);
  left: 50%;
  z-index: 200;
  padding: 10px 16px;
  border-radius: var(--radius-pill);
  background: var(--surface);
  box-shadow: var(--shadow-md);
  color: var(--accent);
  font-weight: 600;
  text-decoration: none;
  transform: translate(-50%, calc(-100% - var(--space-4)));
  transition: transform var(--transition);
}

.skip-link:focus-visible {
  transform: translate(-50%, 0);
}

/* =========================================================================
   Buttons
   ========================================================================= */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-height: 34px;
  padding: 0 14px;
  border: 1px solid transparent;
  border-radius: var(--radius-pill);
  color: var(--text);
  font-size: 14px;
  font-weight: 550;
  white-space: nowrap;
  transition: background var(--transition), border-color var(--transition), color var(--transition), transform var(--transition);
}

.btn-small {
  min-height: 28px;
  padding: 0 11px;
  font-size: 13px;
}

.btn-quiet {
  border-color: var(--separator);
  background: var(--surface);
  color: var(--text-secondary);
}

.btn-quiet:hover {
  background: var(--surface-hover);
  color: var(--text);
}

.btn-primary {
  background: var(--accent);
  color: var(--on-accent);
}

.btn-primary:hover {
  background: var(--accent-hover);
}

.btn:active {
  transform: scale(0.98);
}

.btn:disabled {
  cursor: default;
  opacity: 0.5;
  transform: none;
}

.btn-icon {
  width: 16px;
  height: 16px;
}

.icon-btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border-radius: var(--radius-pill);
  color: var(--text-secondary);
  transition: background var(--transition), color var(--transition);
}

.icon-btn:hover {
  background: var(--surface-hover);
  color: var(--text);
}

.icon-btn:active {
  background: var(--surface-active);
}

.icon-btn[aria-pressed="true"] {
  background: var(--accent-soft);
  color: var(--accent);
}

.icon-btn:disabled {
  opacity: 0.4;
  cursor: default;
}

.icon-btn .icon,
.icon {
  width: 20px;
  height: 20px;
  flex-shrink: 0;
}

/* =========================================================================
   App bar
   ========================================================================= */

.app-bar {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-4);
  padding-top: max(var(--space-2), env(safe-area-inset-top));
  background: color-mix(in srgb, var(--bg) 82%, transparent);
  backdrop-filter: saturate(180%) blur(20px);
  -webkit-backdrop-filter: saturate(180%) blur(20px);
  border-bottom: 1px solid var(--separator);
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: 6px 10px 6px 8px;
  border-radius: var(--radius-pill);
  color: var(--text);
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -0.02em;
  transition: background var(--transition);
}

.brand:hover {
  background: var(--surface-hover);
}

.brand-mark {
  width: 19px;
  height: 19px;
  color: var(--accent);
}

.app-bar-meta {
  flex: 1;
  min-width: 0;
  display: flex;
  justify-content: center;
}

.score-meta {
  display: flex;
  align-items: baseline;
  gap: 8px;
  min-width: 0;
  font-size: 14px;
}

.score-name {
  overflow: hidden;
  color: var(--text);
  font-weight: 550;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.score-composer {
  flex-shrink: 0;
  color: var(--text-muted);
}

.score-composer:not(:empty)::before {
  content: "·";
  margin-right: 8px;
}

.app-bar-actions {
  display: flex;
  align-items: center;
  gap: var(--space-1);
}

.menu {
  position: relative;
}

/* =========================================================================
   Home
   ========================================================================= */

.app-main {
  min-height: 0;
  display: flex;
  flex-direction: column;
}

/* The home screen is the first impression, and a flat sheet of background
   colour is a poor one. Two layers sit behind the content: washes of stage
   light, and ruled staves drifting slowly upward like a score going past. Both
   are decoration, so they are painted by pseudo-elements, take no pointer
   events, and are gone the moment the practice screen replaces this one. */
.home {
  position: relative;
  isolation: isolate;
  flex: 1;
  overflow-y: auto;
  padding: var(--space-6) var(--space-5) var(--space-7);
}

.home::before,
.home::after {
  content: "";
  /* Fixed rather than absolute: the light stays where it is while the page
     scrolls, which is what keeps it feeling like light on a room. */
  position: fixed;
  z-index: -1;
  pointer-events: none;
}

.home::before {
  inset: 0;
  background:
    radial-gradient(46% 34% at 50% 4%, var(--wash-lift), transparent 70%),
    radial-gradient(72% 58% at 4% -12%, var(--wash-cool), transparent 74%),
    radial-gradient(64% 52% at 104% -2%, var(--wash-warm), transparent 74%),
    radial-gradient(58% 46% at 98% 76%, var(--wash-cool), transparent 74%),
    radial-gradient(100% 78% at 46% 118%, var(--wash-deep), transparent 76%);
}

/* Five lines, a gap, five lines: the page is ruled like manuscript paper. The
   layer is taller than the frame so it can drift one whole stave and loop. */
.home::after {
  inset: -170px 0;
  background-image: repeating-linear-gradient(
    to bottom,
    transparent 0 40px,
    var(--wash-staff) 40px 41px,
    transparent 41px 55px,
    var(--wash-staff) 55px 56px,
    transparent 56px 70px,
    var(--wash-staff) 70px 71px,
    transparent 71px 85px,
    var(--wash-staff) 85px 86px,
    transparent 86px 100px,
    var(--wash-staff) 100px 101px,
    transparent 101px 160px
  );
  /* Fade the ruling out towards the edges so it reads as texture rather than
     as a grid drawn over the page. */
  mask-image: radial-gradient(115% 95% at 50% 42%, #000 25%, transparent 80%);
  -webkit-mask-image: radial-gradient(115% 95% at 50% 42%, #000 25%, transparent 80%);
}

/* One stave per 90 seconds: enough to feel alive, slow enough to read over. */
@media (prefers-reduced-motion: no-preference) {
  .home::after {
    animation: staves-drift 90s linear infinite;
  }
}

@keyframes staves-drift {
  from { transform: translateY(0); }
  to { transform: translateY(-160px); }
}

.home-inner {
  display: flex;
  flex-direction: column;
  gap: var(--space-7);
  max-width: 940px;
  margin: 0 auto;
}

.home-intro {
  text-align: center;
}

.eyebrow {
  color: var(--accent);
  font-size: 12px;
  font-weight: 650;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.home-intro h1 {
  margin-top: var(--space-3);
  font-size: clamp(30px, 5vw, 46px);
  letter-spacing: -0.035em;
}

.lede {
  max-width: 30em;
  margin: var(--space-3) auto 0;
  color: var(--text-secondary);
  font-size: clamp(15px, 1.6vw, 18px);
}

.steps {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--space-2) var(--space-5);
  margin-top: var(--space-5);
  list-style: none;
  color: var(--text-muted);
  font-size: 14px;
}

.steps li {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}

.step-index {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: var(--radius-pill);
  background: var(--accent-soft);
  color: var(--accent);
  font-size: 12px;
  font-weight: 650;
}

.section-title {
  margin-bottom: var(--space-4);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.sample-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--space-4);
}

/* Slightly translucent, so the light behind them shows through and the shelf
   belongs to the page instead of being pasted on top of it. */
.sample {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-2);
  padding: var(--space-4);
  border: 1px solid var(--separator);
  border-radius: var(--radius-lg);
  background: color-mix(in srgb, var(--surface) 82%, transparent);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  box-shadow: var(--shadow-sm);
  text-align: left;
  transition: transform var(--transition), box-shadow var(--transition),
    border-color var(--transition), background var(--transition);
}

.sample:hover {
  border-color: color-mix(in srgb, var(--accent) 40%, var(--separator));
  background: var(--surface);
  box-shadow: var(--shadow-md);
  transform: translateY(-2px);
}

.sample:active {
  transform: translateY(0);
}

.sample:disabled {
  cursor: progress;
  opacity: 0.6;
  transform: none;
}

.sample-art {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  margin-bottom: var(--space-2);
  border-radius: var(--radius-md);
  /* The tile takes its wash from its own colour, so one rule covers both
     appearances and every accent below. */
  background: color-mix(in srgb, currentColor 15%, transparent);
  color: var(--accent);
  font-family: Georgia, 'Times New Roman', serif;
  font-size: 22px;
  line-height: 1;
  transition: transform var(--transition);
}

/* A shelf of scores reads better with a little variety in it. */
.sample:nth-child(3n + 1) .sample-art { color: var(--tint-a); }
.sample:nth-child(3n + 2) .sample-art { color: var(--tint-b); }
.sample:nth-child(3n) .sample-art { color: var(--tint-c); }

.sample:hover .sample-art {
  transform: scale(1.06) rotate(-3deg);
}

.sample-title {
  font-size: 16px;
  font-weight: 600;
  letter-spacing: -0.02em;
}

.sample-composer {
  color: var(--text-muted);
  font-size: 13px;
}

.sample-open {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  margin-top: var(--space-3);
  color: var(--accent);
  font-size: 13px;
  font-weight: 600;
}

.sample-open svg {
  width: 14px;
  height: 14px;
  transition: transform var(--transition);
}

.sample:hover .sample-open svg {
  transform: translateX(3px);
}

.dropzone {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  width: 100%;
  padding: var(--space-5) var(--space-4);
  border: 1.5px dashed var(--separator-strong);
  border-radius: var(--radius-lg);
  background: color-mix(in srgb, var(--surface) 45%, transparent);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  color: var(--text);
  text-align: center;
  transition: background var(--transition), border-color var(--transition);
}

.dropzone:hover,
.dropzone.is-drag-over {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 10%, var(--surface));
}

.dropzone-icon {
  transition: transform var(--transition);
}

.dropzone:hover .dropzone-icon,
.dropzone.is-drag-over .dropzone-icon {
  transform: translateY(-2px);
}

.dropzone[aria-disabled="true"] {
  cursor: progress;
  opacity: 0.6;
}

.dropzone-icon {
  width: 26px;
  height: 26px;
  color: var(--accent);
}

.dropzone-label {
  font-weight: 550;
}

.dropzone-hint {
  color: var(--text-muted);
  font-size: 13px;
}

.home-credit {
  color: var(--text-muted);
  font-size: 12px;
  text-align: center;
}

/* =========================================================================
   Practice layout
   ========================================================================= */

.practice {
  flex: 1;
  min-height: 0;
  display: grid;
  grid-template-columns: 300px minmax(0, 1fr);
  /* A bounded row keeps the scrolling score from stretching the layout. */
  grid-template-rows: minmax(0, 1fr);
}

/* --- Parts panel ------------------------------------------------------- */

.parts-panel {
  position: static;
  display: flex;
  flex-direction: column;
  width: auto;
  max-width: none;
  max-height: none;
  height: 100%;
  margin: 0;
  padding: 0;
  overflow: hidden;
  border: 0;
  border-right: 1px solid var(--separator);
  background: var(--surface);
  color: inherit;
}

.parts-panel:not([open]) {
  display: none;
}

.panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  padding: var(--space-4) var(--space-4) var(--space-2);
}

.panel-title {
  font-size: 17px;
}

.panel-close {
  display: none;
}

.panel-scroll {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  padding: var(--space-2) var(--space-4) var(--space-5);
  overflow-y: auto;
  overscroll-behavior: contain;
}

.panel-label {
  display: block;
  margin-bottom: var(--space-2);
  padding: 0;
  color: var(--text-muted);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.coach {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2) var(--space-3);
  padding: var(--space-3) var(--space-3) var(--space-3) var(--space-4);
  border-radius: var(--radius-md);
  background: var(--accent-soft);
  color: var(--text);
  font-size: 13.5px;
}

/* --- Part rows --------------------------------------------------------- */

.part-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.part {
  --part-color: var(--accent);
  display: grid;
  /* Name, then the solo and rename buttons; the volume row spans all three. */
  grid-template-columns: minmax(0, 1fr) auto auto;
  gap: var(--space-2);
  padding: var(--space-3);
  border: 1px solid var(--separator);
  border-radius: var(--radius-md);
  background: var(--surface);
  transition: border-color var(--transition), background var(--transition), box-shadow var(--transition);
}

.part.is-mine {
  border-color: color-mix(in srgb, var(--part-color) 60%, transparent);
  background: color-mix(in srgb, var(--part-color) 8%, var(--surface));
}

.part.is-muted .part-name,
.part.is-muted .part-level {
  opacity: 0.45;
}

.part-pick {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-width: 0;
  cursor: pointer;
}

.part-pick input {
  width: 17px;
  height: 17px;
  flex-shrink: 0;
  accent-color: var(--part-color);
}

.part-dot {
  width: 9px;
  height: 9px;
  flex-shrink: 0;
  border-radius: var(--radius-pill);
  background: var(--part-color);
}

.part-name {
  overflow: hidden;
  font-size: 14px;
  font-weight: 550;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.part-name-input {
  width: 100%;
  min-width: 0;
  padding: 1px 6px;
  border: 1px solid var(--accent);
  border-radius: 6px;
  background: var(--surface);
  font-size: 14px;
  font-weight: 550;
}

.part-rename {
  width: 28px;
  height: 28px;
  opacity: 0;
  transition: opacity var(--transition), background var(--transition);
}

.part-solo {
  width: 28px;
  height: 28px;
}

.part-solo .icon {
  width: 16px;
  height: 16px;
}

.part-solo[aria-pressed="true"] {
  background: var(--accent-soft);
  color: var(--accent);
}

.part.is-soloed {
  border-color: color-mix(in srgb, var(--accent) 55%, transparent);
}

/* While something is soloed, the parts that are not become visibly secondary,
   so the mix you are hearing matches the panel you are looking at. */
.part-list.has-solo .part:not(.is-soloed) .part-name,
.part-list.has-solo .part:not(.is-soloed) .part-level {
  opacity: 0.45;
}

.part-rename .icon {
  width: 15px;
  height: 15px;
}

.part:hover .part-rename,
.part:focus-within .part-rename {
  opacity: 1;
}

.part-volume-row {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: 28px minmax(0, 1fr) 38px;
  align-items: center;
  gap: var(--space-2);
}

.part-mute {
  width: 28px;
  height: 28px;
}

.part-mute .icon {
  width: 16px;
  height: 16px;
}

.part-mute[aria-pressed="true"] {
  background: var(--danger-soft);
  color: var(--danger);
}

/* Part volumes are drawn explicitly so every voice colour gets the same
   treatment; browsers pick their own track shade from accent-color, which
   looks inconsistent across a colourful set of voices. */
.part input.part-volume {
  width: 100%;
  height: 20px;
  appearance: none;
  -webkit-appearance: none;
  background:
    linear-gradient(
      to right,
      var(--part-color) var(--fill, 100%),
      var(--separator-strong) var(--fill, 100%)
    ) center / 100% 4px no-repeat;
  border-radius: var(--radius-pill);
}

.part input.part-volume::-webkit-slider-runnable-track {
  height: 20px;
  background: transparent;
}

.part input.part-volume::-webkit-slider-thumb {
  width: 14px;
  height: 14px;
  margin-top: 3px;
  border: 0;
  border-radius: var(--radius-pill);
  background: var(--part-color);
  box-shadow: var(--shadow-sm);
  appearance: none;
  -webkit-appearance: none;
}

.part input.part-volume::-moz-range-track {
  height: 20px;
  border: 0;
  background: transparent;
}

.part input.part-volume::-moz-range-progress {
  background: transparent;
}

.part input.part-volume::-moz-range-thumb {
  width: 14px;
  height: 14px;
  border: 0;
  border-radius: var(--radius-pill);
  background: var(--part-color);
}

.part-level {
  color: var(--text-muted);
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  text-align: right;
}

/* --- Mix -------------------------------------------------------------- */

.mix-options {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 4px;
  border-radius: var(--radius-md);
  background: var(--surface-sunken);
}

.mix-option {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: 7px 10px;
  border-radius: var(--radius-sm);
  color: var(--text-secondary);
  font-size: 13.5px;
  cursor: pointer;
  transition: background var(--transition), color var(--transition);
}

.mix-option:hover {
  background: var(--surface-hover);
}

.mix-option input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.mix-option .mix-check {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  opacity: 0;
  color: var(--accent);
}

.mix-option:has(input:checked) {
  background: var(--surface);
  box-shadow: var(--shadow-sm);
  color: var(--text);
  font-weight: 550;
}

.mix-option:has(input:checked) .mix-check {
  opacity: 1;
}

.mix-option:has(input:focus-visible) {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

.others-level {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) 38px;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-3);
  color: var(--text-secondary);
  font-size: 13px;
}

.others-level output {
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
  text-align: right;
}

/* --- Switch ----------------------------------------------------------- */

.switch-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-3) 0 0;
  border-top: 1px solid var(--separator);
  cursor: pointer;
}

.switch-label {
  display: flex;
  flex-direction: column;
  font-size: 14px;
}

.switch-hint {
  color: var(--text-muted);
  font-size: 12px;
}

.switch {
  position: relative;
  flex-shrink: 0;
  width: 44px;
  height: 26px;
  margin: 0;
  border-radius: var(--radius-pill);
  background: var(--separator-strong);
  appearance: none;
  -webkit-appearance: none;
  cursor: pointer;
  transition: background var(--transition);
}

.switch::after {
  content: "";
  position: absolute;
  top: 3px;
  left: 3px;
  width: 20px;
  height: 20px;
  border-radius: var(--radius-pill);
  background: #fff;
  box-shadow: var(--shadow-sm);
  transition: transform var(--transition);
}

.switch:checked {
  background: var(--accent);
}

.switch:checked::after {
  transform: translateX(18px);
}

/* --- Sliders ----------------------------------------------------------- */

/* Sliders are drawn here rather than left to the browser's accent colour, so
   the track, the fill and the thumb look the same in every browser and the same
   in every part of the app. The filled length comes from a custom property the
   owning module keeps in step with the value.
   Every dimension is fixed, so nothing resizes as a value changes. */
.slider {
  display: block;
  width: 100%;
  height: 22px;
  margin: 0;
  border-radius: var(--radius-pill);
  background:
    linear-gradient(
      to right,
      var(--accent) var(--fill, 50%),
      var(--separator-strong) var(--fill, 50%)
    ) center / 100% 4px no-repeat;
  appearance: none;
  -webkit-appearance: none;
  cursor: pointer;
}

.slider::-webkit-slider-runnable-track {
  height: 22px;
  background: transparent;
}

.slider::-webkit-slider-thumb {
  width: 16px;
  height: 16px;
  margin-top: 3px;
  border: 0;
  border-radius: var(--radius-pill);
  background: #fff;
  box-shadow: var(--shadow-sm), 0 0 0 1px var(--separator-strong);
  appearance: none;
  -webkit-appearance: none;
  transition: transform var(--transition), box-shadow var(--transition);
}

.slider:hover::-webkit-slider-thumb,
.slider:active::-webkit-slider-thumb {
  transform: scale(1.15);
}

/* The focus ring belongs on the thumb. Around the whole control it was a box
   the width of the dialog, which read as an error state. */
.slider:focus-visible {
  outline: none;
}

.slider:focus-visible::-webkit-slider-thumb {
  box-shadow: 0 0 0 4px var(--accent-ring);
}

.slider::-moz-range-track {
  height: 22px;
  border: 0;
  background: transparent;
}

.slider::-moz-range-progress {
  background: transparent;
}

.slider::-moz-range-thumb {
  width: 16px;
  height: 16px;
  border: 0;
  border-radius: var(--radius-pill);
  background: #fff;
  box-shadow: var(--shadow-sm), 0 0 0 1px var(--separator-strong);
}

.slider:focus-visible::-moz-range-thumb {
  box-shadow: 0 0 0 4px var(--accent-ring);
}

/* =========================================================================
   Stage and score
   ========================================================================= */

.stage {
  position: relative;
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  padding: var(--space-4);
  background: var(--bg);
}

.score-frame {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  border: 1px solid var(--separator);
  border-radius: var(--radius-lg);
  background: var(--score-paper);
  box-shadow: var(--paper-shadow);
  overscroll-behavior: contain;
  scrollbar-width: thin;
}

.score-canvas {
  display: block;
  width: 100%;
  cursor: grab;
  touch-action: pan-y;
}

.score-canvas:active,
.score-canvas.is-scrubbing {
  cursor: grabbing;
}

.score-canvas:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
  border-radius: var(--radius-lg);
}

/* Fixed rather than stage-relative so it is also visible while the first score
   is being opened from the home screen. */
.loading {
  position: fixed;
  top: calc(56px + var(--space-3));
  left: 50%;
  z-index: 120;
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: 8px 16px;
  border: 1px solid var(--separator);
  border-radius: var(--radius-pill);
  background: var(--surface);
  box-shadow: var(--shadow-md);
  font-size: 13px;
  transform: translateX(-50%);
}

.spinner {
  width: 14px;
  height: 14px;
  border: 2px solid var(--separator-strong);
  border-top-color: var(--accent);
  border-radius: var(--radius-pill);
  animation: spin 0.7s linear infinite;
}

@keyframes spin {
  to { transform: rotate(360deg); }
}

/* --- Pitch guidance --------------------------------------------------- */

.pitch-pill {
  --pitch-color: var(--pitch-listening);
  --pitch-shift: 0px;
  position: absolute;
  right: var(--space-5);
  bottom: var(--space-5);
  z-index: 5;
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: 8px 14px;
  border: 1px solid var(--separator);
  border-radius: var(--radius-pill);
  background: color-mix(in srgb, var(--surface) 88%, transparent);
  box-shadow: var(--shadow-md);
  backdrop-filter: blur(20px) saturate(180%);
  -webkit-backdrop-filter: blur(20px) saturate(180%);
}

.pitch-pill[data-state="correct"] { --pitch-color: var(--pitch-correct); }
.pitch-pill[data-state="close"] { --pitch-color: var(--pitch-close); }
.pitch-pill[data-state="off"] { --pitch-color: var(--pitch-off); }

/* Wide enough for the longest guidance ("Sing higher"), so the pill keeps one
   size and one position while the advice changes inside it. */
.pitch-label {
  min-width: 6.6em;
  color: var(--pitch-color);
  font-size: 13px;
  font-weight: 600;
  white-space: nowrap;
  transition: color var(--transition);
}

.pitch-scale {
  position: relative;
  width: 96px;
  height: 22px;
  flex-shrink: 0;
}

.pitch-scale::before {
  content: "";
  position: absolute;
  top: 50%;
  right: 6px;
  left: 6px;
  height: 2px;
  border-radius: var(--radius-pill);
  background: var(--separator-strong);
  transform: translateY(-50%);
}

.pitch-center {
  position: absolute;
  top: 4px;
  bottom: 4px;
  left: 50%;
  width: 2px;
  border-radius: var(--radius-pill);
  background: var(--separator-strong);
  transform: translateX(-50%);
}

.pitch-orb {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 12px;
  height: 12px;
  border-radius: var(--radius-pill);
  background: var(--pitch-color);
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--pitch-color) 18%, transparent);
  transform: translate(calc(-50% + var(--pitch-shift)), -50%);
  transition: transform 150ms cubic-bezier(0.22, 1, 0.36, 1), background var(--transition);
}

.pitch-pill[data-state="listening"] .pitch-orb {
  animation: pulse 1.9s ease-in-out infinite;
}

@keyframes pulse {
  0%, 100% { opacity: 0.5; }
  50% { opacity: 1; }
}

/* =========================================================================
   Transport
   ========================================================================= */

.transport {
  background: color-mix(in srgb, var(--surface) 90%, transparent);
  backdrop-filter: saturate(180%) blur(20px);
  -webkit-backdrop-filter: saturate(180%) blur(20px);
  border-top: 1px solid var(--separator);
  padding-bottom: env(safe-area-inset-bottom);
}

.transport-seek {
  padding: 0;
  line-height: 0;
}

.seek {
  display: block;
  width: 100%;
  height: 18px;
  margin: 0;
  background: linear-gradient(to right, var(--accent) 0%, var(--separator) 0%) center / 100% 3px no-repeat;
  appearance: none;
  -webkit-appearance: none;
  cursor: pointer;
  transition: background-size var(--transition);
}

.seek:hover,
.seek:focus-visible {
  background-size: 100% 5px;
}

.seek::-webkit-slider-runnable-track {
  height: 18px;
  background: transparent;
}

.seek::-webkit-slider-thumb {
  width: 11px;
  height: 11px;
  margin-top: 4px;
  border: 0;
  border-radius: var(--radius-pill);
  background: var(--accent);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
  appearance: none;
  -webkit-appearance: none;
  transition: transform var(--transition);
}

.seek:hover::-webkit-slider-thumb,
.seek:focus-visible::-webkit-slider-thumb {
  transform: scale(1.25);
}

.seek::-moz-range-track {
  height: 18px;
  background: transparent;
  border: 0;
}

.seek::-moz-range-thumb {
  width: 11px;
  height: 11px;
  border: 0;
  border-radius: var(--radius-pill);
  background: var(--accent);
}

.seek::-moz-range-progress {
  background: transparent;
}

.transport-row {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: var(--space-3);
  padding: 10px var(--space-4) 12px;
}

.transport-side {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-width: 0;
}

.transport-right {
  justify-content: flex-end;
  gap: 2px;
}

/* Both readouts hold their own width. Otherwise the tempo slider slid sideways
   as 9 BPM became 10, and again when a piece passed ten minutes. */
.time {
  min-width: 7.4em;
  color: var(--text-muted);
  font-size: 12.5px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.tempo {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-width: 0;
}

/* The width is the only thing the transport decides; the look is shared with
   every other slider in the app. */
.tempo-range {
  width: clamp(70px, 12vw, 130px);
}

.tempo-value {
  min-width: 4.9em;
  color: var(--text-secondary);
  font-size: 12.5px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.transport-center {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.play-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 46px;
  height: 46px;
  border-radius: var(--radius-pill);
  background: var(--accent);
  color: var(--on-accent);
  box-shadow: 0 2px 10px color-mix(in srgb, var(--accent) 32%, transparent);
  transition: transform var(--transition), background var(--transition);
}

.play-btn:hover {
  background: var(--accent-hover);
  transform: scale(1.05);
}

.play-btn:active {
  transform: scale(0.96);
}

.play-btn .icon {
  width: 22px;
  height: 22px;
}

.beat-dot {
  position: absolute;
  right: 5px;
  bottom: 5px;
  width: 6px;
  height: 6px;
  border-radius: var(--radius-pill);
  background: transparent;
  transition: background 60ms linear, transform 60ms linear;
}

.beat-dot.is-beat {
  background: var(--accent);
  transform: scale(1.35);
}

.beat-dot.is-downbeat {
  background: var(--success);
  transform: scale(1.6);
}

.panel-trigger {
  display: none;
}

/* =========================================================================
   Popovers, dialogs, toasts
   ========================================================================= */

/* Positioned from script: an element in the top layer is laid out against the
   viewport, not against its DOM ancestor, so CSS offsets alone cannot anchor it
   to its trigger. */
.popover {
  position: fixed;
  inset: auto;
  top: 0;
  left: 0;
  width: max-content;
  min-width: 230px;
  max-width: min(320px, calc(100vw - 2 * var(--space-4)));
  margin: 0;
  padding: var(--space-3);
  border: 1px solid var(--separator);
  border-radius: var(--radius-md);
  background: var(--surface);
  box-shadow: var(--shadow-lg);
  color: inherit;
}

/* Hidden by default so browsers without the popover API keep it closed until
   the scripted fallback opens it. Separate rules keep the unknown pseudo-class
   from invalidating the fallback selector. */
.popover {
  display: none;
}

.popover:popover-open {
  display: block;
}

.popover.is-open {
  display: block;
}

.popover:popover-open {
  animation: popover-in 140ms ease-out;
}

@keyframes popover-in {
  from { opacity: 0; transform: translateY(4px); }
  to { opacity: 1; transform: translateY(0); }
}

.popover-title {
  margin-bottom: var(--space-2);
  color: var(--text-muted);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.popover-label {
  color: var(--text-secondary);
  font-size: 13px;
}

.popover-row {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) 40px;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-3);
}

.popover-row output {
  color: var(--text-muted);
  font-size: 12.5px;
  font-variant-numeric: tabular-nums;
  text-align: right;
}

.popover-row input[type="range"] {
  width: 100%;
}

.popover-note {
  margin-bottom: var(--space-3);
  color: var(--text);
  font-size: 13px;
}

.popover-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: var(--space-3);
}

/* --- Loop range -------------------------------------------------------- */

/* The toggle and its range menu read as one control, so they sit in a single
   rounded group with a hairline between them. */
.loop-group {
  position: relative;
  display: inline-flex;
  align-items: center;
}

.caret-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 34px;
  margin-left: -4px;
  border-radius: var(--radius-sm);
  color: var(--text-muted);
  transition: background var(--transition), color var(--transition);
}

.caret-btn:hover {
  background: var(--surface-hover);
  color: var(--text);
}

.caret {
  width: 16px;
  height: 16px;
}

/* A dot on the loop button shows a range is set without needing a second icon. */
.loop-badge {
  position: absolute;
  top: 5px;
  right: 5px;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent);
}

.loop-fields {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-2);
}

.loop-field {
  display: flex;
  flex-direction: column;
  gap: 4px;
  color: var(--text-secondary);
  font-size: 12.5px;
}

.loop-field input {
  width: 100%;
  min-height: 32px;
  padding: 0 8px;
  border: 1px solid var(--separator-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--text);
  font-variant-numeric: tabular-nums;
}

.segmented-field {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}

.segmented {
  display: flex;
  padding: 2px;
  border-radius: var(--radius-sm);
  background: var(--surface-sunken);
}

.segment {
  position: relative;
  padding: 4px 12px;
  border-radius: 6px;
  color: var(--text-secondary);
  font-size: 13px;
  cursor: pointer;
  transition: background var(--transition), color var(--transition);
}

.segment input {
  position: absolute;
  inset: 0;
  opacity: 0;
  cursor: pointer;
}

.segment:has(input:checked) {
  background: var(--surface);
  box-shadow: var(--shadow-sm);
  color: var(--text);
  font-weight: 550;
}

.segment:has(input:focus-visible) {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

.menu-item {
  display: flex;
  flex-direction: column;
  gap: 1px;
  width: 100%;
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  text-align: left;
  transition: background var(--transition);
}

.menu-item:hover {
  background: var(--surface-hover);
}

.menu-item-label {
  font-size: 14px;
  font-weight: 550;
}

.menu-item-hint {
  color: var(--text-muted);
  font-size: 12px;
}

.menu-item:disabled {
  cursor: default;
  opacity: 0.55;
}

/* Modal dialogs. The reset above clears the user-agent `margin: auto`, so
   centring is restored explicitly. */
.modal {
  width: min(560px, calc(100vw - 2 * var(--space-4)));
  max-height: calc(100dvh - 2 * var(--space-5));
  margin: auto;
  padding: 0;
  border: 0;
  border-radius: var(--radius-xl);
  background: var(--surface);
  box-shadow: var(--shadow-lg);
  color: inherit;
  overflow: auto;
  /* Reserve the scrollbar so a dialog that grows past the viewport does not
     narrow its own contents, moving every control sideways as it appears. */
  scrollbar-gutter: stable;
}

.modal::backdrop {
  background: rgba(0, 0, 0, 0.35);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
}

.modal[open] {
  animation: modal-in 180ms cubic-bezier(0.32, 0.72, 0, 1);
}

@keyframes modal-in {
  from { opacity: 0; transform: translateY(8px) scale(0.98); }
  to { opacity: 1; transform: translateY(0) scale(1); }
}

.modal-compact {
  width: min(430px, calc(100vw - 2 * var(--space-4)));
}

.modal-card {
  padding: var(--space-6);
  text-align: center;
}

.modal-card-wide {
  padding: var(--space-5);
  text-align: left;
}

.modal-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
}

.modal-card h2 {
  font-size: 20px;
}

.modal-card p {
  margin-top: var(--space-3);
  color: var(--text-secondary);
  font-size: 14px;
}

.modal-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 46px;
  height: 46px;
  margin: 0 auto var(--space-4);
  border-radius: var(--radius-pill);
  background: var(--accent-soft);
  color: var(--accent);
}

.modal-icon svg {
  width: 24px;
  height: 24px;
}

.checkbox-row {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-4);
  color: var(--text-secondary);
  font-size: 13.5px;
  cursor: pointer;
}

.modal-actions {
  display: flex;
  justify-content: center;
  gap: var(--space-2);
  margin-top: var(--space-5);
}

/* Destructive on one side, confirming on the other, so they are not confused
   for each other under a hurried tap. */
.modal-actions-split {
  justify-content: space-between;
}

/* --- Settings ---------------------------------------------------------- */

/* A sheet is a dialog long enough to scroll: its title, and its actions if it
   has any, stay in place while the content moves under them. */
.modal-sheet {
  padding: 0;
}

.modal-sheet .modal-head {
  position: sticky;
  top: 0;
  z-index: 2;
  margin: 0;
  padding: var(--space-5) var(--space-5) var(--space-3);
  border-bottom: 1px solid var(--separator);
  background: var(--surface);
}

.modal-sheet .modal-actions {
  position: sticky;
  bottom: 0;
  z-index: 2;
  margin: 0;
  padding: var(--space-3) var(--space-5) var(--space-5);
  border-top: 1px solid var(--separator);
  background: var(--surface);
}

.modal-settings {
  width: min(680px, calc(100vw - 2 * var(--space-4)));
}

.settings-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(248px, 1fr));
  align-items: start;
  gap: var(--space-5);
  padding: var(--space-5);
}

.settings-group {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  min-width: 0;
}

.settings-heading {
  padding-left: 2px;
  color: var(--text-muted);
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* One card per group, with hairlines between its settings. Grouping is what
   turns a long column of controls into four short, readable lists. */
.settings-card {
  display: flex;
  flex-direction: column;
  padding: 0 var(--space-4);
  border: 1px solid var(--separator);
  border-radius: var(--radius-lg);
  background: var(--surface-sunken);
}

.settings-card > * {
  padding: var(--space-3) 0;
  border-top: 1px solid var(--separator);
}

.settings-card > *:first-child {
  border-top: 0;
}

.settings-label {
  color: var(--text-secondary);
  font-size: 13.5px;
}

/* The readout sits above the track rather than beside it.
   A value beside the slider makes the track as wide as the text is short, so
   "As written" and "2 semitones down" gave the transpose slider two different
   lengths: the thumb moved out from under the finger mid-drag and the next
   step of the drag landed somewhere else. Stacked, the track is always the
   full width of the column and the text can say whatever it likes. */
.settings-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 6px;
}

.settings-row-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
  /* Holds the line open for rows whose readout is empty, so a row never
     changes height when its value appears or clears. */
  min-height: 16px;
}

.settings-row .settings-value {
  color: var(--text);
  font-size: 12.5px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  text-align: right;
  white-space: nowrap;
}

/* A hint explains a setting whose effect is not obvious from its name. It sits
   inside the setting it belongs to, so there is never a question of which
   control it is talking about. */
.settings-hint {
  color: var(--text-muted);
  font-size: 12px;
  line-height: 1.45;
}

.settings-group .segmented-field {
  flex-direction: column;
  align-items: stretch;
  gap: var(--space-2);
}

/* Inside a card the group is the raised surface, so the segments sit on the
   card colour and the chosen one is tinted rather than lifted. */
.settings-card .segmented {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  padding: 3px;
  border-radius: 10px;
  background: var(--surface);
  box-shadow: inset 0 0 0 1px var(--separator);
}

.settings-card .segment {
  padding: 5px 10px;
  border-radius: 7px;
  text-align: center;
}

.settings-card .segment:has(input:checked) {
  background: var(--accent-soft);
  box-shadow: none;
  color: var(--accent);
}

.select {
  width: 100%;
  min-height: 34px;
  padding: 0 32px 0 10px;
  border: 1px solid var(--separator-strong);
  border-radius: var(--radius-sm);
  background-color: var(--surface);
  /* A drawn chevron, because the platform one cannot be positioned and looks
     different on every browser. */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238a8a8f' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 9px center;
  background-size: 15px 15px;
  color: var(--text);
  font-size: 13.5px;
  appearance: none;
  -webkit-appearance: none;
  cursor: pointer;
  transition: border-color var(--transition), background-color var(--transition);
}

.select:hover {
  border-color: var(--accent);
}

/* Help is laid out like settings: a small heading, then one card of related
   lines, so both sheets are read the same way. */
.help-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  align-items: start;
  gap: var(--space-5);
  padding: var(--space-5);
}

.help-grid h3 {
  margin-bottom: var(--space-2);
  padding-left: 2px;
  color: var(--text-muted);
  font-size: 11.5px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.help-list {
  display: flex;
  flex-direction: column;
  padding: 0 var(--space-4);
  border: 1px solid var(--separator);
  border-radius: var(--radius-lg);
  background: var(--surface-sunken);
  list-style: none;
  color: var(--text-secondary);
  font-size: 13.5px;
}

.help-list li {
  padding: 9px 0;
}

.help-list li + li {
  border-top: 1px solid var(--separator);
}

.help-list.keys li {
  display: flex;
  align-items: center;
  gap: 6px;
}

.modal-footnote {
  margin: 0 var(--space-5) var(--space-5);
  padding-top: var(--space-4);
  border-top: 1px solid var(--separator);
  color: var(--text-muted);
  font-size: 12px;
}

/* Toasts */
.toasts {
  position: fixed;
  right: var(--space-4);
  bottom: var(--space-4);
  z-index: 300;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  max-width: min(380px, calc(100vw - 2 * var(--space-4)));
  pointer-events: none;
}

.toast {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: 12px 12px 12px 14px;
  border: 1px solid var(--separator);
  border-radius: var(--radius-md);
  background: var(--surface);
  box-shadow: var(--shadow-lg);
  font-size: 13.5px;
  pointer-events: auto;
  animation: toast-in 200ms cubic-bezier(0.32, 0.72, 0, 1);
}

.toast-error {
  border-color: color-mix(in srgb, var(--danger) 45%, transparent);
}

.toast-error .toast-text {
  color: var(--text);
}

.toast-text {
  flex: 1;
}

.toast-dismiss {
  flex-shrink: 0;
  width: 22px;
  height: 22px;
  border-radius: var(--radius-pill);
  color: var(--text-muted);
  font-size: 16px;
  line-height: 1;
}

.toast-dismiss:hover {
  background: var(--surface-hover);
  color: var(--text);
}

@keyframes toast-in {
  from { opacity: 0; transform: translateY(10px); }
  to { opacity: 1; transform: translateY(0); }
}

/* =========================================================================
   Responsive
   ========================================================================= */

@media (max-width: 1000px) {
  .practice {
    grid-template-columns: 264px minmax(0, 1fr);
  }
}

/* Tablet and phone: the parts panel becomes a sheet over the score. */
@media (max-width: 899px) {
  .practice {
    grid-template-columns: minmax(0, 1fr);
  }

  .stage {
    padding: 0;
  }

  .score-frame {
    border: 0;
    border-radius: 0;
    box-shadow: none;
  }

  .score-canvas:focus-visible {
    border-radius: 0;
  }

  .pitch-pill {
    right: 50%;
    bottom: var(--space-3);
    transform: translateX(50%);
  }

  .panel-trigger {
    display: inline-flex;
  }

  .parts-panel {
    position: fixed;
    inset: auto 0 0 0;
    width: 100%;
    height: auto;
    max-height: min(78dvh, 620px);
    border: 0;
    border-top: 1px solid var(--separator);
    border-radius: var(--radius-xl) var(--radius-xl) 0 0;
    box-shadow: var(--shadow-lg);
    padding-bottom: env(safe-area-inset-bottom);
    animation: sheet-in 240ms cubic-bezier(0.32, 0.72, 0, 1);
  }

  .parts-panel::backdrop {
    background: rgba(0, 0, 0, 0.35);
    backdrop-filter: blur(3px);
    -webkit-backdrop-filter: blur(3px);
  }

  .parts-panel .panel-head {
    position: relative;
    padding-top: var(--space-5);
  }

  .parts-panel .panel-head::before {
    content: "";
    position: absolute;
    top: 8px;
    left: 50%;
    width: 38px;
    height: 4px;
    border-radius: var(--radius-pill);
    background: var(--separator-strong);
    transform: translateX(-50%);
  }

  .panel-close {
    display: inline-flex;
  }

  .part-rename {
    opacity: 1;
  }
}

@keyframes sheet-in {
  from { transform: translateY(100%); }
  to { transform: translateY(0); }
}

@media (max-width: 700px) {
  .home {
    padding: var(--space-5) var(--space-4) var(--space-6);
  }

  .home-inner {
    gap: var(--space-6);
  }

  .transport-row {
    grid-template-columns: auto minmax(0, 1fr);
    grid-template-areas:
      "time tempo"
      "center right";
    row-gap: var(--space-2);
    padding: 8px var(--space-3) 10px;
  }

  .transport-left {
    display: contents;
  }

  .time {
    grid-area: time;
  }

  .tempo {
    grid-area: tempo;
    justify-content: flex-end;
  }

  /* Keep the tempo slider clearly narrower than the progress bar above it. */
  .tempo-range {
    width: clamp(72px, 28vw, 130px);
  }

  .transport-center {
    grid-area: center;
    justify-content: flex-start;
  }

  .transport-right {
    grid-area: right;
  }

  #prev-bar,
  #next-bar {
    display: none;
  }

  .brand-name {
    display: none;
  }

  .app-bar {
    padding-inline: var(--space-3);
  }

  .modal-card {
    padding: var(--space-5);
  }

  .toasts {
    right: var(--space-3);
    left: var(--space-3);
    bottom: var(--space-3);
    max-width: none;
  }
}

@media (max-width: 380px) {
  #loop-btn {
    display: none;
  }
}

/* Touch devices: no hover to reveal the rename affordance. */
@media (hover: none) {
  .part-rename {
    opacity: 1;
  }
}

/* =========================================================================
   Accessibility preferences
   ========================================================================= */

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }

  .sample:hover,
  .play-btn:hover {
    transform: none;
  }
}

@media (prefers-contrast: more) {
  :root {
    --separator: rgba(0, 0, 0, 0.28);
    --separator-strong: rgba(0, 0, 0, 0.5);
    --text-muted: #45454a;
  }

  @media (prefers-color-scheme: dark) {
    :root {
      --separator: rgba(255, 255, 255, 0.32);
      --separator-strong: rgba(255, 255, 255, 0.55);
      --text-muted: #c4c4c9;
    }
  }
}

@media (forced-colors: active) {
  .part,
  .sample,
  .popover,
  .modal,
  .toast,
  .score-frame {
    border: 1px solid CanvasText;
  }

  .icon-btn[aria-pressed="true"],
  .mix-option:has(input:checked),
  .segment:has(input:checked) {
    outline: 2px solid Highlight;
  }
}
