/* =========================================================================
   Mazmazika — modern notation editor
   Three aesthetics: paper (default), studio (dark), linen (monochrome)
   ========================================================================= */

:root {
  /* Paper aesthetic */
  --bg:        #f6f5f1;
  --bg-tint:   #efece4;
  --surface:   #ffffff;
  --surface-2: #fbfaf6;
  --ink:       #15161a;
  --ink-2:     #4a4d57;
  --ink-3:     #8a8e99;
  --ink-4:     #c3c0b5;
  --line:      #e6e3da;
  --line-strong: #d6d2c5;
  --accent:    #b4361c;       /* burgundy — editorial mark */
  --accent-soft: #f4d8d0;
  --selection: #b4361c;
  --staff-bg:  #ffffff;
  --staff-ink: #15161a;

  /* Density (rows/buttons) */
  --row-h:     34px;
  --btn:       30px;
  --btn-sm:    26px;
  --gap:       4px;
  --pad-lg:    16px;
  --pad-md:    12px;
  --pad-sm:    8px;

  /* Radii */
  --r-sm:      6px;
  --r-md:      8px;
  --r-lg:      12px;

  /* Type */
  --font-sans: "Geist", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-serif: "Instrument Serif", "Times New Roman", serif;
  --font-music: "Bravura Text", "Bravura", "Petaluma", "Sebastian", serif;
  --font-mono: "Geist Mono", "JetBrains Mono", ui-monospace, SFMono-Regular, monospace;

  --shadow-1: 0 1px 0 rgba(20,20,22,.04), 0 1px 2px rgba(20,20,22,.04);
  --shadow-2: 0 1px 0 rgba(20,20,22,.04), 0 8px 24px -12px rgba(20,20,22,.16);
  --shadow-card: 0 1px 0 rgba(20,20,22,.03), 0 24px 60px -28px rgba(20,20,22,.22);
}

html[data-aesthetic="studio"] {
  --bg:        #14141a;
  --bg-tint:   #1c1c25;
  --surface:   #1a1a23;
  --surface-2: #20202b;
  --ink:       #f1ede5;
  --ink-2:     #aaa9b3;
  --ink-3:     #74737d;
  --ink-4:     #45454f;
  --line:      #2a2a35;
  --line-strong: #353541;
  --accent:    #e07a4f;
  --accent-soft: #2d211b;
  --selection: #e07a4f;
  --staff-bg:  #1a1a23;
  --staff-ink: #f1ede5;
  --shadow-1: 0 1px 0 rgba(0,0,0,.4), 0 1px 2px rgba(0,0,0,.25);
  --shadow-2: 0 1px 0 rgba(0,0,0,.4), 0 12px 28px -10px rgba(0,0,0,.45);
  --shadow-card: 0 1px 0 rgba(0,0,0,.4), 0 30px 60px -30px rgba(0,0,0,.55);
}

/* Mazmazika brand aesthetic — matches the rest of the site (dark navy chrome,
   cyan accent). The score page itself stays a real "manuscript paper" white
   so notation reads at maximum contrast — same pattern Dorico/MuseScore
   dark modes use. */
html[data-aesthetic="mazmazika"] {
  --bg:        #0f0f23;
  --bg-tint:   #1a1a2e;
  --surface:   #16213e;
  --surface-2: #2a2a3a;
  --ink:       #ffffff;
  --ink-2:     #e0e0e0;
  --ink-3:     #b0b0b0;
  --ink-4:     #6b7280;
  --line:      rgba(255,255,255,0.10);
  --line-strong: rgba(255,255,255,0.18);
  --accent:    #4fc3f7;
  --accent-soft: rgba(79,195,247,0.18);
  --selection: #4fc3f7;
  --staff-bg:  #fbfaf6;
  --staff-ink: #15161a;
  --shadow-1: 0 1px 0 rgba(0,0,0,.4), 0 1px 2px rgba(0,0,0,.25);
  --shadow-2: 0 1px 0 rgba(0,0,0,.4), 0 12px 28px -10px rgba(0,0,0,.45);
  --shadow-card: 0 1px 0 rgba(0,0,0,.4), 0 30px 60px -30px rgba(0,0,0,.55);
}
html[data-aesthetic="mazmazika"] .brand-mark { background: var(--accent); color: #0f0f23; }
html[data-aesthetic="mazmazika"] .share-btn  { background: var(--accent); color: #0f0f23; }
html[data-aesthetic="mazmazika"] .tr-play    { background: var(--accent); color: #0f0f23; }
html[data-aesthetic="mazmazika"] .tr-scrub .fill { background: var(--accent); }
html[data-aesthetic="mazmazika"] .tr-scrub .head { border-color: var(--accent); }
html[data-aesthetic="mazmazika"] .chip[aria-pressed="true"] { background: var(--accent); color: #0f0f23; }

/* Light ("paper") aesthetic: mirror the accent-coloured chrome. Without these the
   controls fall back to the ink-coloured base rule (background:var(--ink)), which
   on the light page reads as opaque black blobs (Share button, transport play,
   brand mark). White ink on the saturated light-theme accent gives clean contrast.
   Now that the editor honours the site-wide light/dark (mergeSharedTweaks), light
   mode is reachable by default, so its always-visible chrome must be themed too. */
html[data-aesthetic="paper"] .brand-mark { background: var(--accent); color: #fff; }
html[data-aesthetic="paper"] .share-btn  { background: var(--accent); color: #fff; }
html[data-aesthetic="paper"] .tr-play    { background: var(--accent); color: #fff; }
html[data-aesthetic="paper"] .tr-scrub .fill { background: var(--accent); }
html[data-aesthetic="paper"] .tr-scrub .head { border-color: var(--accent); }
html[data-aesthetic="paper"] .chip[aria-pressed="true"] { background: var(--accent); color: #fff; }

/* White-paper score page: override the inherited light text so the titles
   and tempo render dark on the manuscript surface. Verovio's own SVG is
   black-on-transparent so it reads naturally — no filter needed. */
html[data-aesthetic="mazmazika"] .score-page { color: var(--staff-ink); }
html[data-aesthetic="mazmazika"] .score-page .score-titles input,
html[data-aesthetic="mazmazika"] .score-page .score-titles .title,
html[data-aesthetic="mazmazika"] .score-page .score-titles .subtitle,
html[data-aesthetic="mazmazika"] .score-page .score-titles .byline { color: var(--staff-ink); }
html[data-aesthetic="mazmazika"] .score-page .score-titles input:hover,
html[data-aesthetic="mazmazika"] .score-page .score-titles input:focus { background: rgba(15,22,26,0.06); }
html[data-aesthetic="mazmazika"] .score-page .score-tempo { color: #4a4d57; }
html[data-aesthetic="mazmazika"] .canvas-status { background: var(--surface); color: var(--ink-2); }
/* Stronger card shadow so the paper sits clearly on the dark desk */
html[data-aesthetic="mazmazika"] .score-page {
  box-shadow:
    0 1px 0 rgba(0,0,0,.5),
    0 30px 80px -20px rgba(0,0,0,.6);
  border-color: rgba(0,0,0,.2);
}

html[data-aesthetic="linen"] {
  --bg:        #fafaf9;
  --bg-tint:   #f4f4f3;
  --surface:   #ffffff;
  --surface-2: #f7f7f6;
  --ink:       #0e0e10;
  --ink-2:     #54545a;
  --ink-3:     #8d8d93;
  --ink-4:     #c8c8cc;
  --line:      #ececec;
  --line-strong: #dcdcdc;
  --accent:    #1a1a1c;
  --accent-soft: #ececec;
  --selection: #1a1a1c;
  --staff-bg:  #ffffff;
  --staff-ink: #0e0e10;
}

html[data-density="compact"] {
  --row-h: 30px; --btn: 26px; --btn-sm: 22px;
  --pad-lg: 12px; --pad-md: 10px; --pad-sm: 6px;
}
html[data-density="comfy"] {
  --row-h: 38px; --btn: 34px; --btn-sm: 30px;
  --pad-lg: 20px; --pad-md: 14px; --pad-sm: 10px;
}

.notes-editor-page,
.notes-editor-page *,
.notes-editor-page *::before,
.notes-editor-page *::after { box-sizing: border-box; }

/* Notes editor scope only — don't touch site-wide html/body styles. */
.notes-editor-page {
  font-family: var(--font-sans);
  color: var(--ink);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
.notes-editor-page button { font: inherit; color: inherit; }
.notes-editor-page input  { font: inherit; color: inherit; }
/* Sliders are interactive controls — same pointer affordance as buttons
   (the swing + playback-speed sliders used to fall back to the text arrow). */
.notes-editor-page input[type="range"] { cursor: pointer; }
.keyboard-toggle-pill,
.page-view-toggle-pill,
.score-details-pill,
.parts-toggle-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 32px;
  padding: 0 10px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--bg-tint);
  color: var(--ink-2);
  cursor: pointer;
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
}
.keyboard-toggle-pill:hover,
.keyboard-toggle-pill[aria-pressed="true"],
.page-view-toggle-pill:hover,
.page-view-toggle-pill[aria-pressed="true"],
.score-details-pill:hover,
.parts-toggle-pill:hover {
  color: var(--ink);
  background: var(--accent-soft);
  border-color: color-mix(in srgb, var(--accent) 45%, var(--line));
}

/* ───────────── App shell grid ─────────────────────────────────────────── */

.app {
  /* Site header is ~80px on desktop, ~60px on mobile. Use a CSS variable
     populated by the page so changes flow through naturally. */
  height: calc(100dvh - var(--site-header-h, 80px));
  display: grid;
  grid-template-rows: 44px auto 1fr var(--piano-dock-h, 0px) 64px;
  grid-template-columns: 240px 1fr 320px;
  grid-template-areas:
    "topbar  topbar  topbar"
    "palette palette palette"
    "left    canvas  right"
    "piano   piano   piano"
    "transport transport transport";
  background: var(--bg);
}

html[data-layout="floating"] .app {
  grid-template-rows: 44px 1fr var(--piano-dock-h, 0px) 64px;
  grid-template-areas:
    "topbar  topbar  topbar"
    "left    canvas  right"
    "piano   piano   piano"
    "transport transport transport";
}

/* ───────────── Topbar ─────────────────────────────────────────────────── */

.topbar {
  grid-area: topbar;
  display: flex; align-items: center; gap: 12px;
  padding: 0 14px;
  border-bottom: 1px solid var(--line);
  background: var(--surface);
  position: relative; z-index: 5;
}
.brand {
  display: inline-flex; align-items: center; gap: 8px;
  font-weight: 600; letter-spacing: -0.01em;
  font-size: 14px;
  padding-right: 12px;
  margin-right: 4px;
  border-right: 1px solid var(--line);
  height: 100%;
}
.brand-mark {
  width: 22px; height: 22px; border-radius: 6px;
  background: var(--ink); color: var(--bg);
  display: grid; place-items: center;
  font-family: var(--font-serif); font-style: italic; font-size: 15px;
  line-height: 1;
}
html[data-aesthetic="studio"] .brand-mark { background: var(--accent); color: #fff; }

.doc-name {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 5px 9px;
  border-radius: var(--r-sm);
  cursor: text;
  font-size: 13.5px;
  color: var(--ink);
  background: transparent;
  border: 1px solid transparent;
  transition: background .12s, border-color .12s;
  outline: none;
  min-width: 0;
}
.doc-name:hover { background: var(--bg-tint); }
.doc-name:focus { background: var(--surface); border-color: var(--line-strong); }
.doc-name .em { font-family: var(--font-serif); font-style: italic; font-weight: 400; }

.menus {
  display: flex; align-items: center; gap: 2px;
  font-size: 13px; color: var(--ink-2);
}
.menus .menu {
  padding: 4px 9px; border-radius: 5px; cursor: default;
}
.menus .menu:hover { background: var(--bg-tint); color: var(--ink); }

.topbar .spacer { flex: 1; }

.tab-group {
  display: inline-flex;
  background: var(--bg-tint);
  border-radius: var(--r-sm);
  padding: 2px;
  font-size: 12.5px;
}
.tab-group button {
  padding: 4px 10px;
  border: 0; background: transparent; cursor: pointer;
  border-radius: 4px;
  color: var(--ink-2);
}
.tab-group button[aria-selected="true"] {
  background: var(--surface);
  color: var(--ink);
  box-shadow: var(--shadow-1);
}

.topbar .icon-btn { color: var(--ink-2); }
.icon-btn {
  width: 30px; height: 30px;
  display: inline-grid; place-items: center;
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--r-sm);
  cursor: pointer;
  color: var(--ink-2);
  transition: background .12s, color .12s, border-color .12s;
}
.icon-btn:hover { background: var(--bg-tint); color: var(--ink); }
.icon-btn[aria-pressed="true"] { background: var(--accent-soft); color: var(--accent); }

.share-btn {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 12px;
  background: var(--ink); color: var(--bg);
  border: 0; border-radius: var(--r-sm);
  font-size: 13px; font-weight: 500;
  cursor: pointer;
  white-space: nowrap;
  flex-shrink: 0;
}
html[data-aesthetic="studio"] .share-btn { background: var(--accent); color: #fff; }
.share-btn:hover { filter: brightness(.92); }

.topbar-tools { display: inline-flex; align-items: center; gap: 2px; flex-shrink: 0; }
.topbar-sep { width: 1px; height: 18px; background: var(--line); margin: 0 4px; }

.doc-name { max-width: 200px; flex-shrink: 1; min-width: 80px; }

@media (max-width: 1280px) {
  .hide-md { display: none !important; }
  .app { grid-template-columns: 200px 1fr 280px; }
  .transport { grid-template-columns: 200px 1fr 280px; }
}
@media (max-width: 1100px) {
  .app { grid-template-columns: 180px 1fr 260px; }
  .transport { grid-template-columns: 180px 1fr 260px; }
  .doc-name { display: none; }
}

.avatar {
  width: 28px; height: 28px; border-radius: 50%;
  background: linear-gradient(135deg, var(--accent), var(--ink));
  color: #fff;
  display: grid; place-items: center;
  font-size: 11px; font-weight: 600;
}

/* ───────────── Palette (top) ──────────────────────────────────────────── */

.palette {
  grid-area: palette;
  background: var(--surface);
  border-bottom: 1px solid var(--line);
  padding: 10px 14px 12px;
  display: flex; flex-direction: column; gap: 8px;
  position: relative;
}
.palette-row {
  display: flex; align-items: center; gap: 14px;
  flex-wrap: wrap;
  row-gap: 8px;
  min-height: var(--btn);
}
/* The Staff group always owns a COMPLETE palette row (all viewports): its
   chip count changes as staves are added/removed, and sharing a wrap line
   made every addition re-flow the neighbouring groups (layout shift). */
.palette-cluster--staff { flex: 1 0 100%; }
.palette-label {
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--ink-3);
  font-weight: 500;
  min-width: 64px;
  flex-shrink: 0;
}
.palette-section-toggle {
  appearance: none;
  border: 0;
  background: transparent;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  font-family: inherit;
  gap: 5px;
  padding: 3px 0;
  text-align: left;
}
.palette-section-toggle:hover,
.palette-section-toggle:focus-visible {
  color: var(--ink);
  outline: none;
}
.palette-section-toggle[aria-expanded="false"] {
  color: var(--accent);
}
.palette-section-caret {
  font-size: 9px;
  line-height: 1;
  transition: transform .12s ease;
}
.palette-section-toggle[aria-expanded="false"] .palette-section-caret {
  transform: rotate(-90deg);
}
.palette-group {
  display: inline-flex; align-items: center;
  background: var(--bg-tint);
  border-radius: var(--r-sm);
  padding: 3px;
  gap: 2px;
  position: relative;
  flex-shrink: 0;
}
/* MS-337 — opt-in wrap modifier for palette groups with many chips
   (currently the Articulation group with 19 entries). Lets the chips
   wrap inline within the group instead of pushing the row's later
   groups off-screen. */
.palette-group.wrap {
  flex-wrap: wrap;
  row-gap: 3px;
}
.palette-divider {
  width: 1px; height: 18px;
  background: var(--line-strong);
  margin: 0 6px;
}
.palette-btn {
  height: var(--btn-sm);
  min-width: var(--btn-sm);
  padding: 0 8px;
  display: inline-flex; align-items: center; justify-content: center;
  gap: 4px;
  background: transparent; border: 0; cursor: pointer;
  border-radius: 5px;
  color: var(--ink-2);
  transition: background .1s, color .1s;
  font-size: 12px;
}
.palette-btn:hover { background: var(--surface); color: var(--ink); }
.palette-btn[aria-pressed="true"] {
  background: var(--accent);
  color: #fff;
  box-shadow: 0 0 0 1px var(--accent), var(--shadow-1);
}
.palette-btn[aria-pressed="true"]:hover {
  background: var(--accent);
  color: #fff;
}
.palette-btn[aria-pressed="true"][data-accent="true"] {
  background: var(--accent);
  color: #fff;
}
/* Draggable chips still CLICK first and foremost — keep the pointer cursor
   (the grab hand read as "not clickable" and hid the primary interaction). */
.palette-btn.draggable { cursor: pointer; }
.palette-btn svg.glyph,
.palette-btn .glyph { font-family: var(--font-music), var(--font-serif); font-size: 16px; }
.palette-btn.wide { padding: 0 10px; font-size: 12.5px; }
.swing-palette-row {
  gap: 10px;
}
.swing-control-group {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}
.swing-slider {
  min-width: 210px;
  display: grid;
  grid-template-columns: minmax(94px, auto) minmax(90px, 1fr) 42px;
  align-items: center;
  gap: 8px;
  font-size: 11.5px;
  color: var(--ink-2);
}
.swing-slider input {
  width: 100%;
  accent-color: var(--accent);
  cursor: pointer;
}
.swing-slider strong {
  color: var(--ink);
  font-size: 11.5px;
  text-align: right;
}
.swing-preset-group {
  gap: 5px;
}
.swing-preset-btn {
  min-height: 28px;
  padding: 0 9px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--bg-tint);
  color: var(--ink-2);
  font-size: 11.5px;
  font-weight: 600;
  cursor: pointer;
}
.swing-preset-btn:hover,
.swing-preset-btn[aria-pressed="true"] {
  border-color: var(--accent);
  color: var(--accent);
  background: var(--accent-soft);
}
.color-palette-group {
  max-width: 214px;
  flex-wrap: wrap;
  row-gap: 3px;
}
.color-palette-group .palette-btn {
  min-width: 24px;
  width: 24px;
  height: 24px;
  padding: 0;
}
.note-color-swatch {
  width: 14px;
  height: 14px;
  border-radius: 50%;
  border: 1px solid rgba(255,255,255,0.7);
  box-shadow: 0 0 0 1px rgba(15, 22, 26, 0.22);
}
.note-color-swatch--custom {
  background: conic-gradient(#b4361c, #d9a441, #1f8a5b, #2a6fdb, #7a5ae0, #b4361c);
}
.note-color-clear {
  width: 14px;
  height: 14px;
  display: inline-grid;
  place-items: center;
  border-radius: 50%;
  border: 1px solid var(--line-strong);
  color: var(--ink-2);
  font-size: 13px;
  line-height: 1;
}
.note-color-input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}
.note-color-inspector {
  display: grid;
  gap: 10px;
}
.note-color-current {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--bg-tint);
  cursor: pointer;
  text-align: left;
}
.note-color-current span {
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: var(--note-color);
  box-shadow: 0 0 0 1px rgba(15, 22, 26, 0.22);
}
.note-color-current strong {
  min-width: 0;
  font-size: 12px;
  overflow-wrap: anywhere;
}
.note-color-mini-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
}
.note-color-mini {
  width: 22px;
  height: 22px;
  border: 1px solid rgba(255,255,255,0.7);
  border-radius: 50%;
  box-shadow: 0 0 0 1px rgba(15, 22, 26, 0.2);
  cursor: pointer;
}
.note-color-mini[aria-pressed="true"] {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* MS-335 — print preview modal */
.print-preview-modal {
  position: fixed; inset: 0; z-index: 100;
  background: rgba(0,0,0,0.55);
  display: flex; align-items: center; justify-content: center;
  padding: 24px;
}
.print-preview-card {
  background: #fff;
  color: var(--ink);
  border-radius: 10px;
  box-shadow: 0 12px 48px rgba(0,0,0,0.45);
  width: min(960px, 100%);
  max-height: 90vh;
  display: flex; flex-direction: column;
  overflow: hidden;
}
.print-preview-head {
  display: flex; justify-content: space-between; align-items: center;
  padding: 10px 14px;
  font-size: 13px;
  border-bottom: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink);
}
.print-preview-body {
  flex: 1 1 auto;
  overflow: auto;
  padding: 18px;
  background: #f6f6f4;
}
.print-preview-body svg { display: block; width: 100%; height: auto; }
.print-preview-foot {
  display: flex; gap: 8px; justify-content: flex-end;
  padding: 10px 14px;
  border-top: 1px solid var(--line);
  background: var(--surface);
}

/* Brush preview cursor — the actual selected duration glyph at exact pitch.
   Positioned so the glyph anchor sits at the snap Y line of the staff. */
.brush-preview {
  position: absolute;
  pointer-events: none;
  z-index: 8;
  display: flex; align-items: center; gap: 6px;
  user-select: none;
  transform: translate(-7px, -14px);
}
.brush-preview .preview-glyph {
  font-family: 'Bravura Text', var(--font-music), var(--font-serif);
  font-size: 22px;
  line-height: 1;
  color: var(--accent);
  /* Low-opacity "ghost" so it reads as a preview of what a click will place,
     not an already-placed note. */
  opacity: 0.5;
  filter: drop-shadow(0 1px 1px rgba(0,0,0,0.12));
}
.brush-preview .preview-pitch {
  font-family: var(--font-mono);
  font-size: 10px;
  background: var(--ink);
  color: var(--bg);
  padding: 2px 5px;
  border-radius: 3px;
  letter-spacing: 0.02em;
  white-space: nowrap;
  margin-top: 12px;
}
/* Stack-mode (chord-add) preview is green */
.brush-preview[data-mode="stack"] .preview-glyph { color: #1f8a5b; }
.brush-preview[data-mode="stack"] .preview-pitch { background: #1f8a5b; }

/* Snap guide — thin horizontal line at the exact pitch position */
.snap-guide {
  position: absolute;
  height: 1px;
  background: linear-gradient(to right,
    transparent 0%,
    var(--accent) 6%,
    var(--accent) 94%,
    transparent 100%);
  opacity: 0.4;
  pointer-events: none;
  z-index: 7;
  transform: translateY(-0.5px);
}
.drop-hint {
  transform: translate(-50%, -50%);
}
.drop-hint-dot {
  width: 12px; height: 12px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 0 4px rgba(180, 54, 28, 0.18), 0 0 0 2px var(--surface);
  animation: dropPulse 0.8s ease-in-out infinite;
}
@keyframes dropPulse {
  0%, 100% { box-shadow: 0 0 0 4px rgba(180, 54, 28, 0.18), 0 0 0 2px var(--surface); }
  50%      { box-shadow: 0 0 0 8px rgba(180, 54, 28, 0.10), 0 0 0 2px var(--surface); }
}
.drop-hint-label {
  position: absolute;
  left: 16px; top: -8px;
  background: var(--ink);
  color: var(--bg);
  font: 500 11px/1 var(--font-mono);
  padding: 4px 8px;
  border-radius: 4px;
  white-space: nowrap;
  letter-spacing: 0.02em;
}
.verovio-host[data-drop-active="true"] {
  outline: 2px dashed var(--accent);
  outline-offset: -4px;
  border-radius: 8px;
  background: rgba(180, 54, 28, 0.03);
}

.k-sig, .t-sig {
  font-family: var(--font-serif);
  font-size: 16px;
  font-style: italic;
}

.palette-disclose {
  margin-left: auto;
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 11.5px;
  color: var(--ink-3);
  cursor: pointer;
  user-select: none;
}
.palette-disclose svg { transition: transform .15s; }
.palette[data-collapsed="true"] .palette-disclose svg { transform: rotate(-90deg); }

/* ───────────── Left panel (parts) ─────────────────────────────────────── */

.leftpanel {
  grid-area: left;
  background: var(--surface);
  border-right: 1px solid var(--line);
  display: flex; flex-direction: column;
  overflow: hidden;
}
.panel-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 12px 14px 8px;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--ink-3);
  font-weight: 500;
}
.panel-head .add {
  width: 20px; height: 20px;
  display: grid; place-items: center;
  border-radius: 4px; cursor: pointer; color: var(--ink-3);
  background: transparent; border: 0;
}
.panel-head .add:hover { background: var(--bg-tint); color: var(--ink); }

.parts-list { padding: 0 8px 8px; display: flex; flex-direction: column; gap: 2px; }
.part-item {
  display: grid;
  /* clef · name/meta · +staff · eye · remove — one row. minmax(0,1fr) lets the
     text column shrink (a plain 1fr's auto minimum pushed the trailing buttons
     past the drawer edge, clipping +staff and wrapping eye/remove to a second
     implicit row). */
  grid-template-columns: 22px minmax(0, 1fr) auto auto auto;
  align-items: center;
  padding: 7px 8px;
  border-radius: var(--r-sm);
  cursor: pointer;
  font-size: 13px;
  gap: 6px;
}
.part-item .name,
.part-item .meta { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.part-item:hover { background: var(--bg-tint); }
.part-item[aria-selected="true"] {
  background: var(--accent-soft);
  color: var(--accent);
}
.part-item .ic { color: var(--ink-3); }
.part-item[aria-selected="true"] .ic { color: var(--accent); }
.part-item .name { font-weight: 500; }
.part-item .meta { font-size: 11px; color: var(--ink-3); }
.part-item[aria-selected="true"] .meta { color: var(--accent); opacity: .7; }
.part-item .vis {
  width: 18px; height: 18px;
  border-radius: 4px; display: grid; place-items: center;
  color: var(--ink-3);
}
/* The grand-staff toggle carries a text label ("+staff"/"G+F") — the fixed
   18px .vis width squashed it and the text spilled over the eye/remove
   buttons and past the drawer edge. */
.part-item .staff-toggle { width: auto; height: auto; }

.leftpanel .panel-section {
  border-top: 1px solid var(--line);
  margin-top: 8px;
  padding: 12px 14px 14px;
}
.field-row { display: flex; flex-direction: column; gap: 4px; margin-bottom: 10px; }
.field-row label {
  font-size: 11px;
  color: var(--ink-3);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-weight: 500;
}
.field-row .control {
  display: flex; align-items: center;
  background: var(--bg-tint);
  border-radius: var(--r-sm);
  padding: 0 8px;
  height: var(--btn);
  font-size: 13px;
}
.field-row .control input {
  flex: 1; min-width: 0;
  background: transparent; border: 0; outline: none;
  padding: 0;
}
.field-row .control .unit { color: var(--ink-3); font-size: 11px; }

/* ───────────── Canvas ─────────────────────────────────────────────────── */

.canvas-wrap {
  grid-area: canvas;
  overflow: auto;
  background:
    radial-gradient(1200px 600px at 50% -10%, var(--surface) 0%, rgba(255,255,255,0) 70%),
    var(--bg);
  position: relative;
}
html[data-aesthetic="studio"] .canvas-wrap {
  background: radial-gradient(1200px 600px at 50% -10%, var(--surface-2) 0%, transparent 70%), var(--bg);
}

.score-page {
  margin: 36px auto 60px;
  width: min(840px, calc(100% - 64px));
  background: var(--staff-bg);
  border: 1px solid var(--line);
  border-radius: 4px;
  box-shadow: var(--shadow-card);
  padding: 56px 60px 80px;
  min-height: 600px;
  position: relative;
}
.score-titles {
  text-align: center;
  margin-bottom: 36px;
  font-family: var(--font-serif);
}
.score-titles .title {
  font-size: 30px;
  margin: 0 0 6px;
  font-weight: 400;
  letter-spacing: -0.01em;
}
.score-titles .subtitle {
  font-size: 16px;
  color: var(--ink-2);
  font-style: italic;
  margin: 0 0 14px;
}
.score-titles .byline {
  display: flex; justify-content: space-between;
  font-size: 13px; color: var(--ink-2);
  font-style: italic;
  font-family: var(--font-serif);
}
.score-titles .byline .right { text-align: right; }
.score-titles input {
  background: transparent; border: 0; outline: none;
  font: inherit; color: inherit; text-align: inherit;
  padding: 2px 4px;
  border-radius: 4px;
  width: 100%;
  text-align: center;
}
.score-titles input:focus, .score-titles input:hover {
  background: var(--bg-tint);
}
.score-titles .byline input { width: 220px; text-align: inherit; }

.score-tempo {
  font-family: var(--font-music), var(--font-serif);
  font-size: 16px;
  color: var(--ink-2);
  margin-bottom: 8px;
  padding-left: 10px;
}
.score-tempo .num { font-family: var(--font-sans); margin-left: 6px; font-size: 13px; }

.verovio-host {
  position: relative;
  min-height: 200px;
  /* MS-371 — the score is dragged with our own mouse handlers (pitch drag,
     range select). Without this the browser starts a NATIVE drag of the SVG
     note image on press-drag, which shows the "no-drop" / forbidden cursor and
     fights the real drag. Suppress native image-drag + text selection on the
     score itself (palette→staff drops are unaffected — they start off-host). */
  user-select: none;
  -webkit-user-select: none;
}
.verovio-host svg { display: block; max-width: 100%; height: auto; }
.verovio-host svg,
.verovio-host svg * {
  -webkit-user-drag: none;
  -khtml-user-drag: none;
}
.score-page.is-page-view {
  width: min(1120px, calc(100% - 48px));
  padding: 28px;
  background: color-mix(in srgb, var(--staff-bg) 72%, var(--bg) 28%);
}
.score-page.is-page-view .score-titles,
.score-page.is-page-view .score-tempo {
  display: none;
}
.score-page.is-rtl .score-titles,
.score-page.is-rtl .score-page-meta {
  direction: rtl;
}
.verovio-host--paged {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 24px;
  min-height: 0;
}
.score-paper-page {
  width: min(100%, 840px);
  min-height: 1088px;
  display: flex;
  flex-direction: column;
  background: #fffdf8;
  border: 1px solid color-mix(in srgb, var(--line) 78%, #9c8d78 22%);
  border-radius: 3px;
  box-shadow: 0 20px 44px rgba(18, 16, 12, 0.16);
  padding: 40px 52px 30px;
  page-break-after: always;
}
.verovio-host--paged[data-paper-size="letter"] .score-paper-page {
  min-height: 1060px;
}
.score-page-meta {
  font-family: var(--font-serif);
  color: #15161a;
  margin-bottom: 22px;
}
.score-page-meta-line {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(180px, 2fr) minmax(0, 1fr);
  align-items: end;
  gap: 18px;
}
.score-page-meta-line span {
  min-width: 0;
  font-size: 13px;
  font-style: italic;
  color: #3f4149;
  overflow-wrap: anywhere;
}
.score-page-meta-main strong {
  text-align: center;
  font-size: 28px;
  font-weight: 500;
  line-height: 1.15;
  overflow-wrap: anywhere;
}
.score-page-meta-main span:last-child {
  text-align: end;
}
.score-page-meta-sub {
  grid-template-columns: minmax(0, 1fr) minmax(180px, 2fr) minmax(0, 1fr);
  margin-top: 6px;
}
.score-page-meta-sub span:last-child {
  grid-column: 2;
  text-align: center;
}
.score-paper-svg {
  flex: 1;
}
.score-page-footer {
  margin-top: auto;
  padding-top: 18px;
  text-align: center;
  font: 11px var(--font-sans);
  color: #5b5d66;
}
/* MS-377 — page-view pager: a sticky pill that stays visible while scrolling
   the stacked pages, with Prev/Next + a "Page X / N" indicator. */
.score-pager {
  position: sticky;
  top: 10px;
  z-index: 6;
  align-self: center;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 4px 8px;
  box-shadow: var(--shadow-1);
}
.score-pager-label {
  font: 12px/1 var(--font-sans);
  color: var(--ink-2);
  min-width: 96px;
  text-align: center;
  white-space: nowrap;
}
.score-pager .icon-btn[disabled] { opacity: 0.35; pointer-events: none; }
.verovio-host .v-note { cursor: pointer; }
/* A/B practice loop — a FIXED signal orange (deliberately NOT a theme accent,
   so the loop reads the same in every palette). Endpoints burn brighter than
   the passage. These sit BEFORE the .selected/.playing rules so an actively
   selected or sounding note still takes those colours. */
.verovio-host .ab-loop-note,
.verovio-host .ab-loop-note path,
.verovio-host .ab-loop-note ellipse,
.verovio-host .ab-loop-note use {
  fill: #ff9800 !important;
  stroke: #ff9800 !important;
}
.verovio-host .ab-loop-end,
.verovio-host .ab-loop-end path,
.verovio-host .ab-loop-end ellipse,
.verovio-host .ab-loop-end use {
  fill: #ff6d00 !important;
  stroke: #ff6d00 !important;
}
.verovio-host .ab-loop-end {
  filter: drop-shadow(0 0 6px rgba(255, 109, 0, 0.55));
}
.verovio-host .v-note.selected,
.verovio-host .selected { color: var(--selection) !important; fill: var(--selection) !important; }
.verovio-host .v-note.selected ellipse,
.verovio-host .v-note.selected path,
.verovio-host .selected ellipse,
.verovio-host .selected path,
.verovio-host .selected use {
  fill: var(--selection) !important;
  stroke: var(--selection) !important;
}

/* Currently-playing note: vibrant accent + pulse glow */
.verovio-host .playing-note,
.verovio-host .playing-note path,
.verovio-host .playing-note ellipse,
.verovio-host .playing-note use {
  fill: #1f8a5b !important;
  stroke: #1f8a5b !important;
}
.verovio-host .playing-note {
  filter: drop-shadow(0 0 6px rgba(31, 138, 91, 0.5));
  transform-box: fill-box;
  transform-origin: center;
  animation: playPulse 0.25s ease-out;
}
@keyframes playPulse {
  from { transform: scale(1.18); }
  to   { transform: scale(1); }
}
html[data-aesthetic="studio"] .verovio-host .playing-note,
html[data-aesthetic="studio"] .verovio-host .playing-note path,
html[data-aesthetic="studio"] .verovio-host .playing-note ellipse,
html[data-aesthetic="studio"] .verovio-host .playing-note use {
  fill: #4ade80 !important;
  stroke: #4ade80 !important;
}
html[data-aesthetic="studio"] .verovio-host .playing-note {
  filter: drop-shadow(0 0 8px rgba(74, 222, 128, 0.7));
}
html[data-aesthetic="studio"] .verovio-host svg { filter: invert(0.92) hue-rotate(180deg); }

/* MS-366 — active insertion-staff accent. .staff is an SVG <g>; we tint only
   its direct-child staff-line <path>s a calm blue (notes live deeper in
   .layer, so they keep their colour) to show which staff keyboard / on-screen
   piano / MIDI entry will land on. Deliberately subtle — it must not compete
   with the green note-selection / playing-note highlights. */
.verovio-host .staff.mz-active-staff > path {
  stroke: var(--active-staff-accent, #3b82f6) !important;
  stroke-opacity: 0.7;
  transition: stroke 140ms ease;
}
@media (prefers-reduced-motion: reduce) {
  .verovio-host .staff.mz-active-staff > path { transition: none; }
}
/* Studio (dark) aesthetic inverts the whole SVG, so a brighter blue keeps the
   accent legible after the invert / hue-rotate. */
html[data-aesthetic="studio"] .verovio-host .staff.mz-active-staff > path {
  stroke: #2563eb !important;
  stroke-opacity: 0.85;
}

.canvas-status {
  position: sticky; bottom: 12px; left: 0;
  margin: -40px auto 0;
  display: flex; align-items: center; gap: 12px;
  padding: 6px 12px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 999px;
  box-shadow: var(--shadow-2);
  font-size: 11.5px;
  color: var(--ink-2);
  width: max-content;
  z-index: 2;
}
.canvas-status .dot { width: 6px; height: 6px; border-radius: 50%; background: var(--accent); }

/* ── Save status pill ── */
.save-status { display: inline-flex; align-items: center; gap: 6px; }
.save-status .dot { width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0; }
.save-status--saved     .dot { background: #4ade80; }
.save-status--saving    .dot { background: var(--accent); animation: savePulse 0.9s ease-in-out infinite; }
.save-status--idle      .dot { background: var(--ink-4); }
.save-status--error     .dot { background: #f87171; }
.save-status--reconnecting .dot { background: #fbbf24; animation: savePulse 1.2s ease-in-out infinite; }
.save-status--anon      .dot { background: var(--ink-3); }
@keyframes savePulse { 0%,100% { opacity: 1; } 50% { opacity: 0.35; } }

/* "My scores" toggle in the status bar */
.score-list-toggle {
  background: none; border: none; padding: 0;
  font: inherit; font-size: 11.5px;
  color: var(--accent); cursor: pointer;
  text-decoration: underline dotted;
}
.score-list-toggle:hover { color: var(--ink); }

/* ── Score list panel ── */
.score-list-panel {
  position: absolute;
  bottom: calc(100% + 10px);
  left: 50%; transform: translateX(-50%);
  width: 300px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 10px;
  box-shadow: var(--shadow-3, 0 8px 32px rgba(0,0,0,.35));
  z-index: 20;
  display: flex; flex-direction: column;
  overflow: hidden;
}
.score-list-header {
  display: flex; justify-content: space-between; align-items: center;
  padding: 10px 14px;
  font-size: 12px; font-weight: 600; color: var(--ink);
  border-bottom: 1px solid var(--line);
}
.score-list-body { overflow-y: auto; max-height: 240px; }
.score-list-empty { padding: 18px 14px; font-size: 12px; color: var(--ink-3); text-align: center; }
.score-list-item {
  display: flex; align-items: stretch;
  border-bottom: 1px solid var(--line);
}
.score-list-item:last-child { border-bottom: none; }
.score-list-item.active { background: color-mix(in srgb, var(--accent) 10%, transparent); }
.score-list-title {
  flex: 1; background: none; border: none; padding: 10px 14px;
  cursor: pointer; text-align: left; color: var(--ink);
  display: flex; flex-direction: column; gap: 2px;
}
.score-list-title:hover { background: var(--line); }
.slp-name { font-size: 12.5px; font-weight: 500; }
.slp-meta { font-size: 10.5px; color: var(--ink-3); }
.score-list-del {
  background: none; border: none; border-left: 1px solid var(--line);
  padding: 0 12px; cursor: pointer;
  font-size: 11px; color: var(--ink-3);
}
.score-list-del:hover { color: #f87171; background: rgba(248,113,113,.08); }
.score-list-del.confirm { color: #f87171; font-weight: 700; }
.score-list-footer {
  padding: 8px 14px;
  border-top: 1px solid var(--line);
}
.btn-new-score {
  width: 100%; background: none; border: 1px dashed var(--line);
  border-radius: 6px; padding: 6px 0;
  font-size: 12px; color: var(--ink-2); cursor: pointer;
}
.btn-new-score:hover { border-color: var(--accent); color: var(--accent); }
@media (max-width: 500px) {
  .score-list-panel { width: calc(100vw - 32px); left: 16px; transform: none; }
}

/* zoom controls floating */
.canvas-floats {
  position: absolute; right: 18px; bottom: 18px;
  display: flex; gap: 6px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  padding: 4px;
  box-shadow: var(--shadow-1);
  z-index: 3;
}

/* ───────────── Right inspector ────────────────────────────────────────── */

.inspector {
  grid-area: right;
  background: var(--surface);
  border-left: 1px solid var(--line);
  display: flex; flex-direction: column;
  overflow: hidden;
}
.inspector-tabs {
  display: flex;
  border-bottom: 1px solid var(--line);
  padding: 0 8px;
  font-size: 12.5px;
}
.inspector-tabs button {
  flex: 1;
  padding: 10px 8px;
  background: transparent; border: 0; cursor: pointer;
  color: var(--ink-3);
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}
.inspector-tabs button[aria-selected="true"] {
  color: var(--ink);
  border-bottom-color: var(--ink);
}
.inspector-body {
  flex: 1; overflow: auto;
  padding: 4px 0 24px;
}
.insp-section {
  padding: 12px 14px;
  border-bottom: 1px solid var(--line);
}
.insp-section:last-child { border-bottom: 0; }
.insp-section h4 {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--ink-3);
  font-weight: 500;
  margin: 0 0 10px;
  display: flex; align-items: center; justify-content: space-between;
}
.insp-grid {
  display: grid;
  grid-template-columns: 96px 1fr;
  gap: 6px 12px;
  align-items: center;
  font-size: 12.5px;
}
.insp-grid .label { color: var(--ink-3); font-size: 11.5px; }
.insp-grid .val {
  background: var(--bg-tint);
  border-radius: 5px;
  padding: 5px 8px;
  color: var(--ink);
  display: flex; align-items: center; gap: 6px;
  min-height: 26px;
}
.insp-grid input.val { border: 0; outline: none; }
.insp-grid .val.stepper { padding-right: 2px; }
.insp-grid .stepper-btns { display: flex; flex-direction: column; }
.insp-grid .stepper-btns button {
  width: 16px; height: 12px;
  background: transparent; border: 0; cursor: pointer;
  color: var(--ink-3); padding: 0;
}
.insp-grid .stepper-btns button:hover { color: var(--ink); }

.chip-row { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 6px; }
.chip {
  height: 24px;
  padding: 0 8px;
  display: inline-flex; align-items: center; gap: 4px;
  background: var(--bg-tint);
  border-radius: 999px;
  font-size: 11.5px;
  color: var(--ink-2);
  cursor: pointer;
  border: 0;
}
.chip:hover { background: var(--line); color: var(--ink); }
.chip[aria-pressed="true"] {
  background: var(--ink); color: var(--bg);
}
html[data-aesthetic="studio"] .chip[aria-pressed="true"] {
  background: var(--accent); color: #fff;
}
.chip .ser { font-family: var(--font-serif); font-style: italic; }
.chip .music { font-family: var(--font-music), var(--font-serif); }

.empty-state {
  padding: 28px 18px;
  text-align: center;
  color: var(--ink-3);
  font-size: 12.5px;
  line-height: 1.5;
}
.empty-state .glyph {
  font-family: var(--font-serif);
  font-style: italic;
  font-size: 36px;
  color: var(--ink-4);
  display: block;
  margin-bottom: 8px;
}

/* ───────────── Transport ──────────────────────────────────────────────── */

.transport {
  grid-area: transport;
  background: var(--surface);
  border-top: 1px solid var(--line);
  display: grid;
  /* auto side tracks size to their content; the play cluster centres in the
     leftover middle — the old fixed 240/320 tracks squeezed the centre from
     both sides once the time+bar read-out and jump control filled up. */
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  padding: 0 14px;
  gap: 14px;
}
.tr-center { justify-content: center; }
.tr-right { justify-content: flex-end; }

/* MS-341 - bottom-docked on-screen piano keyboard */
.piano-dock {
  grid-area: piano;
  min-height: 0;
  overflow: hidden;
  display: grid;
  grid-template-columns: 44px minmax(0, 1fr) 44px;
  align-items: stretch;
  background: linear-gradient(180deg, var(--surface), var(--bg-tint));
  border-top: 1px solid var(--line);
  box-shadow: 0 -10px 26px rgba(15, 20, 25, 0.08);
  transition: height 0.18s ease;
}
.piano-dock[data-open="false"] {
  border-top: 0;
  pointer-events: none;
}
.piano-pan {
  appearance: none;
  border: 0;
  background: var(--surface);
  color: var(--ink-2);
  cursor: pointer;
  font-size: 22px;
  font-weight: 700;
  border-inline: 1px solid var(--line);
}
.piano-pan:hover {
  color: var(--ink);
  background: var(--accent-soft);
}
.piano-keys {
  position: relative;
  min-width: 0;
  overflow: hidden;
  padding: 8px 6px 10px;
}
/* The DOCK's keybed is a recessed dark instrument body — the keys sit inside a
   case with a red felt strip along the fallboard, like the landscape overlay's
   frame (scoped to .piano-dock: the landscape keys bring their own frame). */
.piano-dock .piano-keys {
  padding: 14px 10px 12px;
  background: linear-gradient(180deg, #0b0a10 0%, #191622 100%);
  box-shadow: inset 0 2px 10px rgba(0, 0, 0, 0.6), inset 0 -1px 0 rgba(255, 255, 255, 0.04);
}
.piano-dock .piano-keys::before {
  content: "";
  position: absolute;
  left: 10px;
  right: 10px;
  top: 10px;
  height: 4px;
  border-radius: 2px;
  background: linear-gradient(90deg, #6a1e30, #93293f 50%, #6a1e30);
  z-index: 1;                     /* over the white keys, under the blacks */
  pointer-events: none;
}
/* Coordinate frame for the black keys: without this they position against
   .piano-keys' PADDING box while the whites sit in its CONTENT box, so the
   left:% boundary math drifts by the padding across the keyboard. The inset
   mirrors .piano-dock .piano-keys' padding exactly. (The landscape overlay
   needs no frame — its .piano-keys has padding 0, the boxes coincide.) */
.piano-dock .piano-black-row {
  position: absolute;
  inset: 14px 10px 12px;
  pointer-events: none;           /* frame only — the keys re-enable hits */
}
.piano-dock .piano-black-row .piano-key-black {
  top: 0;
  height: 62%;                    /* of the key area — real ~60-63% ratio */
  pointer-events: auto;
}
.piano-white-row {
  display: grid;
  grid-template-columns: repeat(var(--white-count), minmax(0, 1fr));
  height: 100%;
}
.piano-key {
  appearance: none;
  touch-action: manipulation;
  user-select: none;
  border: 0;
  cursor: pointer;
}
.piano-key-white {
  min-width: 0;
  height: 100%;
  margin: 0 1px;      /* seam: the dark keybed shows through between the keys */
  border: 0;
  background: linear-gradient(180deg, #fffef9 0%, #f7f4ec 55%, #eae5d8 92%, #ded8c8 100%);
  color: #3c414c;
  border-radius: 0 0 6px 6px;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  padding: 0 2px 7px;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.85),
    inset 1px 0 0 rgba(255, 255, 255, 0.55),
    inset -1.5px 0 2px -1px rgba(40, 34, 24, 0.35),
    inset 0 -9px 12px -8px rgba(40, 34, 24, 0.45),
    0 2px 3px rgba(0, 0, 0, 0.35);
}
.piano-key-black {
  position: absolute;
  top: 14px;   /* fallback — the dock (.piano-black-row frame) and landscape both override top/height */
  width: max(18px, calc(62% / var(--white-count)));
  min-width: 18px;
  height: calc(64% - 14px);
  transform: translateX(-50%);
  z-index: 2;
  border-radius: 0 0 4px 4px;
  background: linear-gradient(180deg, #33333d 0%, #17171f 16%, #0a0a10 68%, #191920 100%);
  color: #f7f8fa;
  box-shadow:
    inset 1.5px 0 2px -1px rgba(255, 255, 255, 0.3),
    inset -1.5px 0 2px -1px rgba(255, 255, 255, 0.12),
    inset 0 -8px 9px -7px rgba(255, 255, 255, 0.22),
    0 5px 9px rgba(0, 0, 0, 0.5);
}
.piano-key-label {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 10px;
  line-height: 1;
  pointer-events: none;
}
/* Key faces are FIXED ivory/black regardless of theme, so their labels must
   be too. Colour the label spans directly: the .notes-editor-page button
   {color:inherit} reset out-specifies the key buttons' own colour, which made
   labels follow the theme ink — invisible white-on-ivory in dark mode and
   black-on-black in light mode. */
.piano-key-white .piano-key-label { color: #3c414c; }
.piano-key-black .piano-key-label {
  position: absolute;
  bottom: 6px;
  left: 50%;
  transform: translateX(-50%);
  font-size: 9px;
  opacity: 0.82;
  color: #f7f8fa;
}
.piano-key:hover,
.piano-key:focus-visible,
.piano-key.is-playing {
  outline: none;
}
/* Active white keys stay ivory and take an accent WASH (the old flat
   var(--accent-soft) fill went translucent-dark over the keybed). */
.piano-key-white:hover,
.piano-key-white:focus-visible,
.piano-key-white.is-playing {
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--accent) 14%, #fffef9) 0%,
    color-mix(in srgb, var(--accent) 30%, #e7e2d4) 100%);
  color: #3c414c;
}
.piano-key.is-playing {
  box-shadow: 0 0 0 2px var(--accent) inset, 0 0 18px color-mix(in srgb, var(--accent) 40%, transparent);
  animation: pianoFlash 0.22s ease-out;
}
.piano-key-black:hover,
.piano-key-black:focus-visible,
.piano-key-black.is-playing {
  background: linear-gradient(180deg, color-mix(in srgb, var(--accent) 60%, #111) 0%, #101318 100%);
  color: #fff;
}
/* ⚠ Brightness only — NEVER animate transform here: the keyframe's transform
   would replace the black keys' translateX(-50%) centring for the duration of
   the flash, lurching every played black key sideways and back (the desktop
   "black keys shift left/right during playback" bug). */
@keyframes pianoFlash {
  from { filter: brightness(1.45); }
  to { filter: brightness(1); }
}
html[data-aesthetic="paper"] .piano-dock,
html[data-aesthetic="linen"] .piano-dock {
  background: linear-gradient(180deg, var(--surface), var(--paper));
}
html[data-aesthetic="studio"] .piano-key-white {
  background: linear-gradient(180deg, #27323c 0%, #1b222b 100%);
  color: #f4f8fb;
}
html[data-aesthetic="studio"] .piano-key-black {
  background: linear-gradient(180deg, #07090d 0%, #000 100%);
}
.tr-left, .tr-right, .tr-center {
  display: flex; align-items: center; gap: 8px;
}
.tr-center { justify-content: center; }
.tr-right { justify-content: flex-end; }

.tr-time {
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--ink-2);
  background: var(--bg-tint);
  border-radius: var(--r-sm);
  padding: 6px 10px;
  min-width: 84px;
  text-align: center;
}
.tr-time b { color: var(--ink); font-weight: 500; }

.tr-btn {
  width: 34px; height: 34px;
  display: inline-grid; place-items: center;
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--r-sm);
  cursor: pointer;
  color: var(--ink-2);
}
.tr-btn:hover { background: var(--bg-tint); color: var(--ink); }
.tr-btn[aria-pressed="true"] { color: var(--accent); background: var(--accent-soft); }

.tr-play {
  width: 42px; height: 42px;
  background: var(--ink); color: var(--bg);
  border-radius: 50%; border: 0; cursor: pointer;
  display: grid; place-items: center;
  box-shadow: var(--shadow-1);
}
html[data-aesthetic="studio"] .tr-play { background: var(--accent); color: #fff; }
.tr-play:hover { transform: scale(1.04); }
.tr-play:active { transform: scale(0.97); }

.tr-scrub {
  flex: 1;
  height: 6px;
  background: var(--bg-tint);
  border-radius: 999px;
  position: relative;
  cursor: pointer;
  min-width: 120px;
}
.tr-scrub .fill {
  height: 100%;
  background: var(--ink);
  border-radius: inherit;
  position: absolute; left: 0; top: 0;
  width: 22%;
}
html[data-aesthetic="studio"] .tr-scrub .fill { background: var(--accent); }
.tr-scrub .head {
  position: absolute;
  top: 50%; left: 22%;
  width: 12px; height: 12px;
  background: var(--surface);
  border: 2px solid var(--ink);
  border-radius: 50%;
  transform: translate(-50%, -50%);
}
html[data-aesthetic="studio"] .tr-scrub .head { border-color: var(--accent); }

/* Score tempo (BPM) — lives in the top palette (TEMPO group, beside the
   Instrument picker); the transport keeps playback-only controls. */
.palette-bpm {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--bg-tint);
  border-radius: var(--r-sm);
  padding: 0 4px 0 10px;
  height: 28px;
  font-size: 12.5px;
}
.palette-bpm-music { font-family: var(--font-music), var(--font-serif); font-size: 14px; }
.palette-bpm-input {
  width: 44px;
  background: transparent; border: 0; outline: none;
  text-align: right;
  font-family: var(--font-mono);
  font-size: 12.5px;
  /* The nudge arrows are the one and only spinner — hide the browser's
     native inner spin buttons (they doubled the up/down controls). */
  -moz-appearance: textfield;
  appearance: textfield;
}
.palette-bpm-input::-webkit-outer-spin-button,
.palette-bpm-input::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}
.palette-bpm-unit { color: var(--ink-3); font-size: 11px; }
.palette-bpm-nudge { display: flex; flex-direction: column; }
.palette-bpm-nudge button {
  width: 18px; height: 13px;
  background: transparent; border: 0; cursor: pointer;
  color: var(--ink-3); padding: 0; line-height: 1; font-size: 9px;
}
.palette-bpm-nudge button:hover { color: var(--ink); }

/* Jump-to-bar (transport, right of Forward): typable bar number + Go; the ↻
   toggle switches between score bar numbers and played bars incl. repeats. */
.tr-jump {
  display: inline-flex; align-items: center; gap: 4px;
  background: var(--bg-tint);
  border-radius: var(--r-sm);
  height: 28px;
  padding: 0 6px;
  font-size: 11px;
  color: var(--ink-3);
}
.tr-jump input {
  width: 46px; height: 22px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 5px;
  color: var(--ink);
  font-family: var(--font-mono);
  font-size: 12px;
  padding: 0 6px;
  text-align: right;
  outline: none;
  -moz-appearance: textfield;
  appearance: textfield;
}
.tr-jump input::-webkit-outer-spin-button,
.tr-jump input::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}
.tr-jump-reps {
  border: 0; background: transparent;
  color: var(--ink-3); cursor: pointer;
  font-size: 14px; line-height: 1;
  padding: 2px 4px; border-radius: 5px;
}
.tr-jump-reps:hover { color: var(--ink); }
.tr-jump-reps[aria-pressed="true"] { color: var(--accent); background: var(--accent-soft); }
.tr-jump-go {
  border: 0;
  background: var(--accent);
  color: var(--bg);            /* var(--bg), not #fff — survives the Mono palette */
  cursor: pointer;
  font-size: 11px; font-weight: 700;
  padding: 3px 8px;
  border-radius: 5px;
}
.tr-jump-go:hover { filter: brightness(1.08); }
.tr-time-total { color: var(--ink-3); font-weight: 400; font-size: 11.5px; }
/* A/B chip in guided-pick mode: pulse in the loop's signal colour. */
.tr-loop-ab.is-picking {
  color: #ff9800;
  animation: abPickPulse 1s ease-in-out infinite;
}
@keyframes abPickPulse {
  0%   { box-shadow: 0 0 0 0 rgba(255, 152, 0, 0.55); }
  100% { box-shadow: 0 0 0 7px rgba(255, 152, 0, 0); }
}

.tr-vol {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: 11px;
  color: var(--ink-3);
}
.tr-vol input[type="range"] {
  width: 62px;
  accent-color: var(--accent);
  cursor: pointer;
}

/* ───────────── Keyboard helper overlay (decorative) ───────────────────── */

.kbd {
  font-family: var(--font-mono);
  font-size: 10.5px;
  padding: 1px 5px;
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-bottom-width: 2px;
  border-radius: 4px;
  color: var(--ink-2);
}

/* ───────────── Scrollbars ─────────────────────────────────────────────── */
.canvas-wrap::-webkit-scrollbar,
.inspector-body::-webkit-scrollbar,
.parts-list::-webkit-scrollbar { width: 10px; height: 10px; }
.canvas-wrap::-webkit-scrollbar-thumb,
.inspector-body::-webkit-scrollbar-thumb,
.parts-list::-webkit-scrollbar-thumb {
  background: var(--ink-4); border-radius: 999px;
  border: 2px solid transparent; background-clip: padding-box;
}
.canvas-wrap::-webkit-scrollbar-track { background: transparent; }

/* ───────────── Popovers / dropdowns ───────────────────────────────────── */
.popover {
  position: absolute; z-index: 50;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-2);
  padding: 6px;
  font-size: 13px;
  min-width: 180px;
}
.popover .pop-item {
  padding: 6px 10px;
  border-radius: 5px;
  cursor: pointer;
  display: flex; align-items: center; gap: 10px;
  color: var(--ink);
}
.popover .pop-item:hover { background: var(--bg-tint); }
.popover .pop-item .sub { margin-left: auto; color: var(--ink-3); font-size: 11px; }
.popover hr { border: 0; border-top: 1px solid var(--line); margin: 4px 0; }

/* hidden in floating layout when palette is collapsed */
html[data-palette="collapsed"] .palette > .palette-row:not(.always-visible) { display: none; }

/* Loading overlay */
.boot-overlay {
  position: fixed; inset: 0;
  background: var(--bg);
  display: grid; place-items: center;
  z-index: 9999;
  transition: opacity .4s ease;
}
.boot-overlay.gone { opacity: 0; pointer-events: none; }
.boot-overlay .boot-card {
  text-align: center;
  font-family: var(--font-serif);
  color: var(--ink-2);
}
.boot-overlay .boot-card .glyph {
  font-size: 56px;
  color: var(--ink);
  margin-bottom: 8px;
}
.boot-overlay .boot-card .sub {
  font-family: var(--font-sans);
  font-size: 12px;
  color: var(--ink-3);
  text-transform: uppercase;
  letter-spacing: 0.18em;
  margin-top: 14px;
}
.boot-pulse {
  width: 80px; height: 2px;
  background: var(--line);
  margin: 18px auto 0;
  border-radius: 999px;
  overflow: hidden;
  position: relative;
}
.boot-pulse::after {
  content: "";
  position: absolute; inset: 0; width: 40%;
  background: var(--accent);
  border-radius: inherit;
  animation: bootSlide 1.1s ease-in-out infinite;
}
@keyframes bootSlide {
  0%   { left: -40%; }
  100% { left: 100%; }
}

/* =========================================================================
   Mobile-only UI elements — hidden on desktop, shown by the mobile @media
   block below. Keep them top-of-stylesheet so the cascade is predictable.
   ========================================================================= */
.icon-btn.mobile-only,
.palette-sheet-handle,
.palette-mobile-tabs,
.mobile-editor-menu-scrim,
.mobile-scrim {
  display: none;
}

/* Palette sections group each toolbar's chips so the mobile tabs can show
   one at a time; display:contents keeps the desktop flex layout untouched. */
.palette-section { display: contents; }

/* =========================================================================
   TopBar menu dropdowns
   ========================================================================= */

.menus .menu-flyout {
  position: relative;
}
.menus .menu-flyout .menu-trigger {
  font: inherit;
  background: transparent;
  border: 0;
  color: inherit;
  padding: 6px 10px;
  border-radius: var(--r-sm);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 12.5px;
  line-height: 1;
}
.menus .menu-flyout .menu-trigger:hover,
.menus .menu-flyout.open .menu-trigger {
  background: var(--bg-tint);
  color: var(--ink);
}
.menus .menu-flyout .menu-caret {
  font-size: 9px;
  color: var(--ink-3);
  margin-left: 2px;
}
.menus .menu-flyout .menu-dropdown {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  min-width: 220px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-card);
  padding: 6px;
  z-index: 50;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.menus .menu-flyout .menu-item {
  font: inherit;
  background: transparent;
  border: 0;
  color: var(--ink);
  padding: 8px 10px;
  border-radius: var(--r-sm);
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 13px;
  text-align: left;
  width: 100%;
}
.menus .menu-flyout .menu-item:hover,
.menus .menu-flyout .menu-item:focus-visible {
  background: var(--bg-tint);
  outline: none;
}
.menus .menu-flyout .menu-item-ic {
  color: var(--ink-3);
  display: inline-flex;
  width: 20px;
  justify-content: center;
}
.menus .menu-flyout .menu-item-shortcut {
  margin-left: auto;
  color: var(--ink-3);
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1;
}
.menus .menu-flyout .menu-sep {
  height: 1px;
  background: var(--line);
  margin: 4px 2px;
}
.menus .menu-edit .menu-dropdown {
  min-width: 190px;
}
.menus .menu-view .menu-dropdown {
  min-width: 170px;
}
.menus .menu-view .menu-item[aria-checked="true"] .menu-item-ic {
  color: var(--accent);
  font-weight: 700;
}

/* Inline file-import error pill in the topbar */
.topbar .file-error {
  position: absolute;
  top: calc(100% + 4px);
  left: 50%;
  transform: translateX(-50%);
  max-width: 80vw;
  padding: 8px 14px;
  background: #c83333;
  color: #fff;
  font-size: 12.5px;
  border-radius: var(--r-md);
  box-shadow: var(--shadow-2);
  z-index: 60;
}
html[data-aesthetic="mazmazika"] .topbar .file-error {
  background: #b4361c;
}

/* =========================================================================
   MS-322 — Mobile responsive layout (≤1024px)

   The desktop editor uses a CSS grid with two fixed side columns. On phones
   AND tablets we re-arrange to: topbar / canvas / docked palette sheet /
   transport. The Parts panel and Inspector become position:fixed drawers that
   slide in from the edges; the palette docks to the bottom as a collapsible
   sheet. Every rule below is wrapped in @media (max-width: 1024px) so desktop
   (≥1025px) is untouched. NOTE: this 1024px breakpoint is intentionally wider
   than the site-wide mobile breakpoint — the Notes Editor is a dense,
   two-side-column tool that needs the roomier single-column layout on tablets
   too. It is scoped to this page's stylesheets only (notes-editor.css /
   notes-skin.css); do not propagate it to other pages.
   ========================================================================= */

@media (max-width: 1024px) {
  /* Show the mobile-only chrome */
  .icon-btn.mobile-only,
  .palette-sheet-handle {
    display: inline-grid;
    place-items: center;
  }
  .mobile-scrim { display: block; }

  /* Hide desktop-only chrome on mobile. The topbar is a no-wrap flex row, so
     every control left visible competes for the ~412px width — keep only the
     ones you actually need to *edit* on a phone. */
  .topbar .menus,
  .topbar .tab-group,
  .topbar .topbar-tools .icon-btn.hide-md,
  .topbar .topbar-tools .topbar-sep,
  .topbar .avatar { display: none !important; }
  /* Dead "Menu" button (first child, no action) + the export/IO icon cluster
     (upload / download MusicXML / MIDI / WAV / print, all siblings after the
     separator) + the live-MIDI button — reachable on desktop; drop on mobile
     so the bar fits without blowing the layout wide. */
  .topbar > .icon-btn:first-child,
  .topbar .topbar-tools .topbar-sep ~ .icon-btn,
  .topbar .ne-midi-button-wrap,
  .topbar .ne-midi-button { display: none !important; }
  /* Page-view + Score-details + Parts are desktop conveniences; on mobile the
     same actions live in the Menu bottom sheet (View section), so hide the
     pills and keep only the piano-keyboard toggle. */
  .page-view-toggle-pill,
  .score-details-pill,
  .parts-toggle-pill { display: none !important; }
  .topbar .brand > span:nth-child(2) { display: none; }
  .topbar .brand { padding-right: 6px; margin-right: 0; border-right: 0; }
  .topbar .share-btn { display: none; }
  .keyboard-toggle-pill {
    height: 34px;
    min-width: 44px;
    padding: 0 8px;
  }
  .keyboard-toggle-pill span { display: none; }

  /* Tighten the topbar layout for narrow widths. min-width:0 + overflow lets
     the bar shrink inside its grid track instead of forcing the page wider. */
  .topbar { gap: 6px; padding: 0 8px; min-width: 0; overflow: hidden; }
  .topbar .doc-name { font-size: 13px; flex: 1 1 auto; min-width: 0; }

  /* Collapse the app grid into a single column.
     The leftpanel and inspector opt out of the grid via position:fixed below. */
  .app {
    /* minmax(0, …) is critical: a plain 1fr track (= minmax(auto,1fr)) lets a
       wide grid item — here the button-packed topbar — force the column past
       the viewport, blowing the whole page ~250px wide on a phone. Capping the
       track at the viewport keeps the score, palette and piano on-screen. */
    grid-template-columns: minmax(0, 1fr) !important;
    /* topbar / canvas / palette sheet (collapsed: ~92px, expanded: handled by class) / transport */
    grid-template-rows: 48px 1fr auto var(--piano-dock-h, 0px) 60px;
    grid-template-areas:
      "topbar"
      "canvas"
      "palette"
      "piano"
      "transport" !important;
  }
  html[data-layout="floating"] .app {
    grid-template-rows: 48px 1fr auto var(--piano-dock-h, 0px) 60px;
    grid-template-areas:
      "topbar"
      "canvas"
      "palette"
      "piano"
      "transport" !important;
  }

  /* ── Drawer: Parts panel (left) ─────────────────────────────────────── */
  .leftpanel {
    position: fixed;
    top: var(--site-header-h, 60px);
    left: 0;
    bottom: 0;
    width: min(86vw, 320px);
    z-index: 40;
    transform: translateX(-105%);
    transition: transform .26s ease;
    box-shadow: 0 8px 32px -8px rgba(0,0,0,0.32);
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
  }
  .app.drawer-left-open .leftpanel { transform: translateX(0); }

  /* ── Drawer: Inspector (right) ──────────────────────────────────────── */
  .inspector {
    position: fixed;
    top: var(--site-header-h, 60px);
    right: 0;
    bottom: 0;
    width: min(86vw, 340px);
    z-index: 40;
    transform: translateX(105%);
    transition: transform .26s ease;
    box-shadow: -8px 0 32px -8px rgba(0,0,0,0.32);
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
  }
  .app.drawer-right-open .inspector { transform: translateX(0); }

  /* Scrim sits over the canvas; clicking it dismisses any open drawer */
  .mobile-scrim {
    position: fixed;
    inset: var(--site-header-h, 60px) 0 0 0;
    background: rgba(15, 15, 35, 0.5);
    z-index: 35;
    opacity: 0;
    pointer-events: none;
    transition: opacity .2s ease;
  }
  .app.drawer-left-open  .mobile-scrim,
  .app.drawer-right-open .mobile-scrim {
    opacity: 1;
    pointer-events: auto;
  }

  /* ── Canvas: full-width, with bottom padding so the score isn't covered ─ */
  .canvas-wrap {
    padding: 0 8px 8px;
    min-height: 0;
  }
  .score-page {
    width: 100% !important;
    max-width: 100% !important;
    margin: 8px 0 0;
    padding: 18px 14px;
    border-radius: var(--r-md);
  }
  .score-page.is-page-view {
    padding: 10px;
  }
  .score-paper-page {
    width: 100%;
    min-height: 720px;
    padding: 22px 18px 20px;
  }
  .score-page-meta-line {
    grid-template-columns: minmax(0, 1fr);
    gap: 4px;
    text-align: center;
  }
  .score-page-meta-main strong { font-size: 21px; }
  .score-page-meta-main span,
  .score-page-meta-main span:last-child,
  .score-page-meta-sub span:last-child {
    grid-column: auto;
    text-align: center;
  }
  .score-titles .title input  { font-size: 22px !important; }
  .score-titles .subtitle input { font-size: 13px !important; }
  .canvas-floats { bottom: 8px; right: 8px; }
  .canvas-status {
    flex-wrap: wrap;
    font-size: 11px;
    padding: 4px 8px;
    gap: 6px;
    /* Lift clear of the palette expand grip that sits at the canvas/palette seam. */
    bottom: 26px;
  }

  /* ── Palette: docked bottom sheet ───────────────────────────────────── */
  .palette {
    position: relative;     /* stays inside the grid track */
    padding: 6px 8px 4px;
    background: var(--surface);
    border-top: 1px solid var(--line);
    overflow: hidden;       /* hidden rows clip cleanly when collapsed */
    transition: max-height .25s ease;
  }
  /* Tabbed sheet (collapsed default) — the tab strip picks ONE palette SECTION
     (Tools / Measure / Key / Time / Duration / Rest / Rhythm / Instrument /
     Tempo / Pitch / Articulation / Dynamics) and shows just that section's
     chips, scrolling horizontally if needed. The grip above the sheet still
     expands everything at once (wrapped, scrollable) for power users. */
  .palette-mobile-tabs {
    display: flex;
    gap: 4px;
    padding: 0 0 6px;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  .palette-mobile-tabs::-webkit-scrollbar { display: none; }
  .palette-mobile-tab {
    flex: 0 0 auto;
    font: inherit;
    font-size: 11.5px;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--ink-3);
    background: var(--bg-tint);
    border: 1px solid var(--line);
    border-radius: 999px;
    padding: 5px 12px;
    min-height: 30px;
    cursor: pointer;
  }
  .palette-mobile-tab.is-active {
    color: #fff;
    background: var(--accent);
    border-color: var(--accent);
  }
  /* Collapsed tabbed palette: hide every row, then reveal ONLY the row that
     hosts the active section, and within it ONLY the matching cluster. Each
     tab id equals a .palette-cluster[data-section] value (see palette.jsx);
     several sections can share a row, so the row-show list groups tabs by row. */
  .app:not(.palette-sheet-open) .palette > .palette-row,
  .app:not(.palette-sheet-open) .palette > .swing-palette-row { display: none; }

  /* 1 — show the row that contains the active section's cluster */
  .app:not(.palette-sheet-open) .palette[data-mobile-tab="tools"]        > .palette-row--tools,
  .app:not(.palette-sheet-open) .palette[data-mobile-tab="insert"]       > .palette-row--tools,
  .app:not(.palette-sheet-open) .palette[data-mobile-tab="measure"]      > .palette-row--tools,
  .app:not(.palette-sheet-open) .palette[data-mobile-tab="key"]          > .palette-row--tools,
  .app:not(.palette-sheet-open) .palette[data-mobile-tab="time"]         > .palette-row--tools,
  .app:not(.palette-sheet-open) .palette[data-mobile-tab="duration"]     > .palette-row--primary,
  .app:not(.palette-sheet-open) .palette[data-mobile-tab="rest"]         > .palette-row--primary,
  .app:not(.palette-sheet-open) .palette[data-mobile-tab="rhythm"]       > .palette-row--primary,
  .app:not(.palette-sheet-open) .palette[data-mobile-tab="instrument"]   > .palette-row--primary,
  .app:not(.palette-sheet-open) .palette[data-mobile-tab="tempo"]        > .palette-row--primary,
  .app:not(.palette-sheet-open) .palette[data-mobile-tab="staff"]        > .palette-row--primary,
  .app:not(.palette-sheet-open) .palette[data-mobile-tab="pitch"]        > .palette-row--pitch,
  .app:not(.palette-sheet-open) .palette[data-mobile-tab="articulation"] > .palette-row--pitch,
  .app:not(.palette-sheet-open) .palette[data-mobile-tab="ornaments"]    > .palette-row--pitch,
  .app:not(.palette-sheet-open) .palette[data-mobile-tab="note"]         > .palette-row--pitch,
  .app:not(.palette-sheet-open) .palette[data-mobile-tab="lines"]        > .palette-row--lines,
  .app:not(.palette-sheet-open) .palette[data-mobile-tab="dynamics"]     > .palette-row--lines,
  .app:not(.palette-sheet-open) .palette[data-mobile-tab="color"]        > .palette-row--lines,
  .app:not(.palette-sheet-open) .palette[data-mobile-tab="swing"]        > .swing-palette-row,
  .app:not(.palette-sheet-open) .palette[data-mobile-tab="groove"]       > .swing-palette-row {
    display: flex;
    flex-wrap: nowrap;
    align-items: center;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }

  /* 2 — within the shown row, hide every cluster, then reveal only the one
     whose data-section matches the active tab. !important is required: the site
     skin (notes-skin.css, loaded AFTER this file) sets `#app .palette-cluster {
     display: inline-flex }` with ID specificity that a class selector can't beat,
     so both the blanket hide and the single-section show must force it. Among the
     !important rules the show still wins — its extra attribute selector out-
     specifies the blanket hide. */
  .app:not(.palette-sheet-open) .palette[data-mobile-tab] .palette-cluster { display: none !important; }
  .app:not(.palette-sheet-open) .palette[data-mobile-tab="tools"]        .palette-cluster[data-section="tools"],
  .app:not(.palette-sheet-open) .palette[data-mobile-tab="insert"]       .palette-cluster[data-section="insert"],
  .app:not(.palette-sheet-open) .palette[data-mobile-tab="measure"]      .palette-cluster[data-section="measure"],
  .app:not(.palette-sheet-open) .palette[data-mobile-tab="key"]          .palette-cluster[data-section="key"],
  .app:not(.palette-sheet-open) .palette[data-mobile-tab="time"]         .palette-cluster[data-section="time"],
  .app:not(.palette-sheet-open) .palette[data-mobile-tab="duration"]     .palette-cluster[data-section="duration"],
  .app:not(.palette-sheet-open) .palette[data-mobile-tab="rest"]         .palette-cluster[data-section="rest"],
  .app:not(.palette-sheet-open) .palette[data-mobile-tab="rhythm"]       .palette-cluster[data-section="rhythm"],
  .app:not(.palette-sheet-open) .palette[data-mobile-tab="instrument"]   .palette-cluster[data-section="instrument"],
  .app:not(.palette-sheet-open) .palette[data-mobile-tab="tempo"]        .palette-cluster[data-section="tempo"],
  .app:not(.palette-sheet-open) .palette[data-mobile-tab="staff"]        .palette-cluster[data-section="staff"],
  .app:not(.palette-sheet-open) .palette[data-mobile-tab="pitch"]        .palette-cluster[data-section="pitch"],
  .app:not(.palette-sheet-open) .palette[data-mobile-tab="articulation"] .palette-cluster[data-section="articulation"],
  .app:not(.palette-sheet-open) .palette[data-mobile-tab="ornaments"]    .palette-cluster[data-section="ornaments"],
  .app:not(.palette-sheet-open) .palette[data-mobile-tab="note"]         .palette-cluster[data-section="note"],
  .app:not(.palette-sheet-open) .palette[data-mobile-tab="lines"]        .palette-cluster[data-section="lines"],
  .app:not(.palette-sheet-open) .palette[data-mobile-tab="dynamics"]     .palette-cluster[data-section="dynamics"],
  .app:not(.palette-sheet-open) .palette[data-mobile-tab="color"]        .palette-cluster[data-section="color"],
  .app:not(.palette-sheet-open) .palette[data-mobile-tab="swing"]        .palette-cluster[data-section="swing"],
  .app:not(.palette-sheet-open) .palette[data-mobile-tab="groove"]       .palette-cluster[data-section="groove"] {
    display: inline-flex !important;
  }

  .app:not(.palette-sheet-open) .palette > .palette-row .palette-group {
    flex-wrap: nowrap;
    flex: 0 0 auto;
  }
  /* The per-row collapse carets duplicate the tabs on mobile — hide them. */
  .palette .palette-section-toggle { display: none; }

  /* Expanded: reveal every row, group and label. */
  .app.palette-sheet-open .palette > .palette-row {
    display: flex;
  }
  .app.palette-sheet-open .palette {
    max-height: 60vh;
    overflow-y: auto;
  }
  /* Each row: wrap groups so nothing runs off-screen */
  .palette .palette-row {
    flex-wrap: wrap;
    gap: 6px 8px;
    padding: 4px 0;
  }
  .palette .palette-divider { display: none; }
  .palette .palette-disclose { display: none; }
  .palette .palette-label {
    font-size: 9.5px;
    color: var(--ink-3);
    padding: 0;
    white-space: nowrap;
  }
  /* Expanded sheet wraps rows, so labels become full-width section headers;
     in the collapsed scroll-row they stay inline between groups. */
  .app.palette-sheet-open .palette .palette-label { width: 100%; }
  .palette-btn {
    min-width: 38px;
    height: 38px;
  }
  .palette-btn.wide { padding: 0 12px; }

  /* Grip handle that doubles as the expand/collapse control. It sits at the
     canvas/palette seam where the sticky status pill also lives, so give it a
     generous tap target and a z-index above the pill (z-index:2) — otherwise
     taps land on the pill and the sheet never opens. */
  .palette-sheet-handle {
    position: absolute;
    top: -24px;
    left: 50%;
    transform: translateX(-50%);
    width: 110px;
    height: 30px;
    border: 0;
    background: transparent;
    padding: 0;
    cursor: pointer;
    z-index: 7;
  }
  .palette-sheet-grip {
    display: block;
    margin: 13px auto 0;
    width: 44px;
    height: 5px;
    border-radius: 999px;
    background: var(--ink-3);
    opacity: .55;
    transition: opacity .15s ease, background .15s ease;
  }
  .palette-sheet-handle:hover .palette-sheet-grip,
  .palette-sheet-handle[aria-expanded="true"] .palette-sheet-grip {
    background: var(--accent);
    opacity: 1;
  }

  /* ── Transport: touch-friendly, drop the secondary read-outs ─────────── */
  .transport {
    grid-template-columns: 1fr auto 1fr !important;
    padding: 0 8px;
    gap: 6px;
  }
  .transport .tr-time { padding: 4px 6px; min-width: 70px; font-size: 11.5px; }
  .transport .tr-left > div:nth-of-type(2) { display: none; } /* hide "/ total" */
  /* Hide the volume + dB pill in the right region on mobile; the jump-to-bar
     control also needs more room than a phone bar can give. */
  .transport .tr-right .tr-vol,
  .transport .tr-center .tr-jump,
  .transport .tr-right > div:last-child { display: none; }
  .tr-btn {
    width: 44px;
    height: 44px;
    border-radius: var(--r-md);
  }
  .tr-play {
    width: 56px;
    height: 56px;
  }
  .tr-scrub {
    display: none;          /* save horizontal room — scrub is non-essential */
  }
  .piano-dock {
    grid-template-columns: 44px minmax(0, 1fr) 44px;
  }
  .piano-keys {
    overflow: hidden;
    padding: 6px 4px 8px;
  }
  .piano-white-row {
    grid-template-columns: repeat(var(--white-count), minmax(0, 1fr));
  }
  .piano-key-white {
    min-width: 0;
    min-height: 44px;
    border-radius: 0 0 6px 6px;
  }
  .piano-key-black {
    min-width: 22px;
    width: max(22px, calc(68% / var(--white-count)));
    min-height: 44px;
    height: calc(62% - 6px);
    top: 6px;
  }

  /* TopBar's File menu won't open at this width (it lives inside .menus
     which we hid above); the File actions are also exposed as icon buttons
     in topbar-tools, which now stay visible — that's the mobile path. */
  .topbar-tools { gap: 4px; }
  .topbar-tools .icon-btn { width: 38px; height: 38px; }

  /* The inline file-import error pill should not be clipped on phones */
  .topbar .file-error {
    max-width: calc(100vw - 24px);
    white-space: normal;
    line-height: 1.35;
  }

  /* ── Mobile editor menu — File / Edit / View as a bottom sheet ───────── */
  /* Above the fixed site header (z-index ~1000) and the site mobile nav
     (2000) so a tap anywhere outside the sheet dismisses it. */
  .mobile-editor-menu-scrim {
    display: block;
    position: fixed;
    inset: 0;
    background: rgba(15, 15, 35, 0.55);
    z-index: 2100;
  }
  .mobile-editor-menu {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    max-height: 72vh;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    background: var(--surface);
    border-top: 1px solid var(--line);
    border-radius: 14px 14px 0 0;
    padding: 8px 12px calc(12px + env(safe-area-inset-bottom));
    box-shadow: 0 -12px 40px rgba(0, 0, 0, 0.35);
    z-index: 2101;
  }
  .mobile-editor-menu .mem-grip {
    width: 40px;
    height: 4px;
    border-radius: 999px;
    background: var(--ink-3);
    opacity: .5;
    margin: 2px auto 8px;
  }
  .mobile-editor-menu .mem-title {
    font-size: 10.5px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--ink-3);
    padding: 10px 8px 4px;
    border-top: 1px solid var(--line);
    margin-top: 6px;
  }
  .mobile-editor-menu .mem-title:first-of-type {
    border-top: 0;
    margin-top: 0;
  }
  .mobile-editor-menu .mem-item {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    font: inherit;
    font-size: 14px;
    color: var(--ink);
    background: transparent;
    border: 0;
    border-radius: var(--r-sm);
    padding: 11px 8px;
    text-align: left;
    cursor: pointer;
  }
  .mobile-editor-menu .mem-item:active { background: var(--bg-tint); }
  .mobile-editor-menu .mem-item[disabled] { opacity: .4; }
  .mobile-editor-menu .mem-ic {
    display: inline-flex;
    width: 22px;
    justify-content: center;
    color: var(--ink-3);
    font-size: 13px;
  }
}

/* =========================================================================
   Phone-specific tightening (≤480px)
   ========================================================================= */
@media (max-width: 480px) {
  /* Keep all five tracks of the ≤1024px template (incl. the piano-dock var
     row) — a four-track override here pushed the transport into an implicit
     auto row and squeezed the 80px dock into a 56px track, so the dock's
     bottom 24px slid under the transport bar. */
  .app,
  html[data-layout="floating"] .app {
    grid-template-rows: 44px 1fr auto var(--piano-dock-h, 0px) 60px;
  }
  .topbar { padding: 0 6px; gap: 4px; }
  .topbar .doc-name { font-size: 12.5px; padding: 4px 6px; }
  .topbar-tools .icon-btn { width: 34px; height: 34px; }
  .icon-btn.mobile-only { width: 36px; height: 36px; }
  .palette-btn { min-width: 36px; height: 36px; }
  .tr-play { width: 56px; height: 56px; }   /* Apple-recommended minimum */
  .tr-btn  { width: 42px; height: 42px; }
  .score-titles .title input { font-size: 20px !important; }
}

/* =========================================================================
   Shortcuts cheatsheet modal (MS-322 — reachable via ? key or topbar Help)
   ========================================================================= */
.shortcuts-modal {
  position: fixed;
  inset: 0;
  background: rgba(15, 15, 35, 0.55);
  display: grid;
  place-items: center;
  z-index: 80;
  padding: 12px;
}
.shortcuts-modal-card {
  width: min(560px, 100%);
  max-height: min(80vh, 720px);
  background: var(--surface);
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-card);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.shortcuts-modal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 18px;
  border-bottom: 1px solid var(--line);
}
.shortcuts-modal-head h3 {
  margin: 0;
  font-size: 16px;
  font-weight: 600;
  letter-spacing: -0.01em;
}
.shortcuts-table {
  width: 100%;
  border-collapse: collapse;
  margin: 4px 0;
  font-size: 13px;
  overflow-y: auto;
}
.shortcuts-table th,
.shortcuts-table td {
  padding: 10px 18px;
  vertical-align: middle;
  text-align: left;
}
.shortcuts-table th {
  width: 38%;
  font-weight: 500;
  color: var(--ink-2);
}
.shortcuts-table td { color: var(--ink); }
.shortcuts-table tr + tr th,
.shortcuts-table tr + tr td { border-top: 1px solid var(--line); }
.shortcuts-tip {
  margin: 0;
  padding: 12px 18px 16px;
  font-size: 12px;
  color: var(--ink-3);
  border-top: 1px solid var(--line);
  background: var(--bg-tint);
}

/* =========================================================================
   MS-327 commit 3 — Live-tempo badge in the Transport
   ========================================================================= */

.tr-tempo-live {
  display: inline-flex;
  align-items: center;
  margin-left: 8px;
  padding: 2px 8px;
  background: var(--accent-soft);
  color: var(--accent);
  border-radius: 999px;
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: .06em;
  font-weight: 600;
  font-family: var(--font-mono);
}

/* =========================================================================
   MS-325 — Range selection highlight + Inspector actions
   Verovio renders notes as <g class="note" id="…">; we add `.in-range` to
   every notehead group within the active range so the user can see the
   selection at a glance.
   ========================================================================= */

.verovio-host .in-range {
  fill: var(--accent);
}
.verovio-host .in-range * {
  fill: var(--accent);
  stroke: var(--accent);
}
.verovio-host .in-range .notehead,
.verovio-host .in-range ellipse,
.verovio-host .in-range path {
  fill: var(--accent);
  stroke: var(--accent);
  opacity: 0.85;
}

/* Range Inspector — clipboard / edit action rows */
.inspector .range-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.inspector .range-actions button {
  font: inherit;
  font-size: 12.5px;
  padding: 6px 10px;
  background: var(--bg-tint);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  color: var(--ink);
  cursor: pointer;
}
.inspector .range-actions button:hover {
  background: var(--surface);
  border-color: var(--accent);
}
.inspector .range-tip {
  margin: 8px 0 0;
  color: var(--ink-3);
  font-size: 11.5px;
  line-height: 1.4;
}

/* =========================================================================
   MS-324 — Busy spinner inside File-menu items / topbar icons while a WAV
   render runs. Pure CSS rotate animation; no JS frame.
   ========================================================================= */
.menu-item[disabled] { opacity: .65; cursor: not-allowed; }
.menu-item-spin {
  animation: meSpin 0.9s linear infinite;
  transform-origin: 50% 50%;
  color: var(--accent);
}
.icon-btn:has(.menu-item-spin) { color: var(--accent); }
@keyframes meSpin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

/* =========================================================================
   MS-326 — Annotation inline editor (text / tempo / rehearsal / chord)
   Floats over the verovio-host at the click point; commits on Enter / blur,
   cancels on Esc.
   ========================================================================= */

.annotation-editor {
  background: var(--surface);
  border: 1px solid var(--accent);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-2);
  padding: 8px 10px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 180px;
  pointer-events: auto;
}
.annotation-editor-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: .08em;
  color: var(--accent);
  font-weight: 600;
}
.annotation-editor-kind { flex: 1; }
.annotation-editor-del {
  background: transparent;
  border: 0;
  font-size: 14px;
  cursor: pointer;
  color: var(--ink-3);
  padding: 0 2px;
  line-height: 1;
}
.annotation-editor-del:hover { color: #c83333; }

.annotation-editor-cancel,
.annotation-editor-done {
  background: transparent;
  border: 0;
  font-size: 13px;
  line-height: 1;
  cursor: pointer;
  padding: 2px 4px;
  color: var(--ink-3);
}
.annotation-editor-done { color: var(--accent); font-weight: 700; }
.annotation-editor-cancel:hover { color: #c83333; }

/* Scrim behind the editor — desktop keeps the lightweight floating box with
   no scrim; the mobile media block turns it on. */
.annotation-editor-scrim { display: none; }

.annotation-editor input {
  font: inherit;
  font-size: 13px;
  padding: 6px 8px;
  background: var(--bg-tint);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  color: var(--ink);
  outline: none;
  min-width: 0;
}
.annotation-editor input:focus {
  border-color: var(--accent);
  background: var(--surface);
}

.annotation-editor-text  { font-family: var(--font-serif); font-style: italic; }
.annotation-editor-reh   { font-family: var(--font-serif); font-weight: 600; text-align: center; max-width: 70px; }
.annotation-editor-chord { font-family: var(--font-sans); font-weight: 600; letter-spacing: -0.01em; }

.annotation-editor-tempo {
  display: flex;
  align-items: center;
  gap: 6px;
}
.annotation-editor-glyph {
  font-family: var(--font-music), var(--font-serif);
  font-size: 15px;
  color: var(--ink-2);
  white-space: nowrap;
}
.annotation-editor-bpm   { width: 70px; text-align: center; font-family: var(--font-mono); }
.annotation-editor-label { flex: 1; min-width: 0; font-style: italic; }

/* Mobile: a fixed sheet under the topbar instead of a floating box at the
   tap point — stays on-screen above the keyboard, and the scrim stops taps
   from selecting score notes beneath the dialog. 16px inputs prevent the
   iOS focus-zoom that shifted the layout mid-tap. This block must follow
   the base .annotation-editor rules above to win the cascade. */
@media (max-width: 1024px) {
  .annotation-editor-scrim {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 2102;
    background: rgba(15, 15, 35, 0.35);
  }
  .annotation-editor {
    position: fixed !important;
    left: 10px !important;
    right: 10px;
    top: calc(var(--site-header-h, 60px) + 56px) !important;
    z-index: 2103 !important;
    box-shadow: 0 12px 40px rgba(0, 0, 0, 0.4);
  }
  .annotation-editor input { font-size: 16px; }
  .annotation-editor-cancel,
  .annotation-editor-done {
    font-size: 16px;
    padding: 6px 10px;
  }
}

/* Verovio renders <dir>, <tempo>, <reh>, <harm> as SVG groups in the host.
   The page's accent inks them on hover so they read as clickable. */
.verovio-host .dir,
.verovio-host .tempo,
.verovio-host .reh,
.verovio-host .harm {
  cursor: pointer;
  transition: opacity .12s ease;
}
.verovio-host .dir:hover,
.verovio-host .tempo:hover,
.verovio-host .reh:hover,
.verovio-host .harm:hover { opacity: 0.6; }

/* Insert-mode cursor cue — when the user has selected an Insert palette
   button, the staff cursor switches to a crosshair so the next click feels
   like "drop the annotation here." */
.app[data-insert-mode] .verovio-host { cursor: crosshair !important; }

/* =========================================================================
   MS-323 — Share dialog, read-only badge, blocked-edit toast
   ========================================================================= */

.share-modal {
  position: fixed;
  inset: 0;
  background: rgba(15, 15, 35, 0.55);
  display: grid;
  place-items: center;
  z-index: 90;
  padding: 12px;
}
.share-modal-card {
  width: min(620px, 100%);
  max-height: min(85vh, 760px);
  background: var(--surface);
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-card);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.share-modal-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  padding: 16px 20px 14px;
  border-bottom: 1px solid var(--line);
  gap: 10px;
}
.share-modal-head h3 {
  margin: 0;
  font-size: 17px;
  font-weight: 600;
  letter-spacing: -0.01em;
}
.share-modal-sub {
  margin-top: 2px;
  font-size: 12.5px;
  color: var(--ink-3);
  font-family: var(--font-serif);
  font-style: italic;
}

.share-modal-body { padding: 16px 20px; overflow-y: auto; }
.share-modal-empty { padding: 22px 20px; color: var(--ink-3); font-size: 13.5px; line-height: 1.5; }

.share-options { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-bottom: 16px; }
@media (max-width: 480px) { .share-options { grid-template-columns: 1fr; } }
.share-option {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 12px 14px;
  background: var(--bg-tint);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  text-align: left;
  cursor: pointer;
  color: var(--ink);
  font: inherit;
  transition: border-color .12s ease, background .12s ease, transform .06s ease;
}
.share-option:hover:not([disabled]) { border-color: var(--accent); }
.share-option:active:not([disabled]) { transform: translateY(1px); }
.share-option[disabled] { opacity: .55; cursor: not-allowed; }
.share-option-mark {
  width: 28px; height: 28px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--surface);
  border: 1px solid var(--line);
  font-size: 14px;
  flex-shrink: 0;
}
.share-option-edit .share-option-mark { background: var(--accent-soft); border-color: var(--accent); color: var(--accent); }
.share-option-title { font-size: 13.5px; font-weight: 600; margin-bottom: 2px; }
.share-option-desc  { font-size: 12px; color: var(--ink-3); line-height: 1.4; }

.share-list-heading {
  font-size: 11px; text-transform: uppercase; letter-spacing: .08em;
  color: var(--ink-3); margin: 6px 0 8px;
}
.share-list { display: flex; flex-direction: column; gap: 8px; }
.share-list-empty { font-size: 13px; color: var(--ink-3); padding: 12px 0; }
.share-row {
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  padding: 10px 12px;
  background: var(--surface-2);
}
.share-row-meta { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; font-size: 11.5px; }
.share-row-stamp { color: var(--ink-3); font-family: var(--font-mono); font-size: 11px; }
.share-badge {
  display: inline-block; padding: 2px 8px; border-radius: 999px;
  font-size: 10.5px; text-transform: uppercase; letter-spacing: .06em;
  font-weight: 600;
}
.share-badge--view { background: var(--bg-tint); color: var(--ink-2); }
.share-badge--edit { background: var(--accent-soft); color: var(--accent); }

.share-row-link { display: flex; align-items: center; gap: 6px; }
.share-row-link input {
  flex: 1; min-width: 0;
  padding: 6px 8px;
  font: inherit; font-size: 12px; font-family: var(--font-mono);
  background: var(--bg-tint);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  color: var(--ink);
  outline: none;
}
.share-row-copy,
.share-row-revoke {
  font: inherit; font-size: 12px;
  padding: 6px 10px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--ink-2);
  cursor: pointer;
  white-space: nowrap;
}
.share-row-copy:hover { background: var(--bg-tint); color: var(--ink); }
.share-row-revoke:hover { color: #c83333; border-color: #c83333; }
.share-row-revoke.confirm { background: #c83333; color: #fff; border-color: #c83333; }

.share-error {
  margin-bottom: 12px;
  padding: 8px 12px;
  background: rgba(200, 51, 51, 0.08);
  color: #c83333;
  border: 1px solid rgba(200, 51, 51, 0.32);
  border-radius: var(--r-sm);
  font-size: 12.5px;
}

.share-modal-foot {
  border-top: 1px solid var(--line);
  padding: 10px 20px;
  background: var(--bg-tint);
}
.share-modal-tip { margin: 0; color: var(--ink-3); font-size: 11.5px; line-height: 1.5; }

/* MS-342 - Score Details dialog */
.score-details-modal {
  position: fixed;
  inset: 0;
  z-index: 90;
  display: grid;
  place-items: center;
  padding: 22px;
  background: rgba(20, 22, 28, 0.48);
  backdrop-filter: blur(8px);
}
.score-details-card {
  width: min(760px, 100%);
  max-height: min(760px, calc(100dvh - 44px));
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 8px;
  box-shadow: 0 24px 80px rgba(0, 0, 0, 0.28);
  overflow: hidden;
}
.score-details-head {
  display: flex;
  justify-content: space-between;
  gap: 18px;
  padding: 18px 20px;
  border-bottom: 1px solid var(--line);
}
.score-details-head h3 {
  margin: 0;
  font-size: 18px;
  line-height: 1.2;
}
.score-details-head p {
  margin: 4px 0 0;
  color: var(--ink-3);
  font-size: 12.5px;
}
.score-details-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px 16px;
  padding: 18px 20px 20px;
  overflow-y: auto;
}
.score-details-field {
  display: grid;
  gap: 6px;
  min-width: 0;
  color: var(--ink-2);
  font-size: 12px;
  font-weight: 700;
}
.score-details-field--title,
.score-details-field--subtitle,
.score-details-field--copyright,
.score-details-field--dedication {
  grid-column: 1 / -1;
}
.score-details-field input,
.score-details-field textarea {
  width: 100%;
  min-width: 0;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--bg);
  color: var(--ink);
  padding: 9px 10px;
  font-size: 14px;
  font-weight: 500;
  outline: none;
}
.score-details-field textarea {
  resize: vertical;
  line-height: 1.45;
}
.score-details-field input:focus,
.score-details-field textarea:focus {
  border-color: color-mix(in srgb, var(--accent) 55%, var(--line));
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.score-details-foot {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  padding: 14px 20px;
  border-top: 1px solid var(--line);
  background: var(--bg-tint);
}
.score-details-foot .btn {
  min-height: 34px;
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 0 14px;
  cursor: pointer;
  font-weight: 700;
}
.score-details-foot .btn.ghost {
  background: var(--surface);
  color: var(--ink-2);
}
.score-details-foot .btn.primary {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}

/* Top-of-page error banner that surfaces a failed share-load. */
.share-banner-error {
  position: fixed;
  top: calc(var(--site-header-h, 70px) + 10px);
  left: 50%;
  transform: translateX(-50%);
  z-index: 70;
  padding: 10px 16px;
  background: #c83333;
  color: #fff;
  font-size: 13px;
  border-radius: var(--r-md);
  box-shadow: var(--shadow-2);
}

/* One-shot toast shown when a viewer tries to mutate a read-only score */
.ro-toast {
  position: fixed;
  bottom: 80px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 95;
  padding: 10px 16px;
  background: var(--ink);
  color: var(--bg);
  font-size: 13px;
  border-radius: var(--r-md);
  box-shadow: var(--shadow-2);
  max-width: 90vw;
  animation: roToastIn .18s ease-out;
}
@keyframes roToastIn {
  from { opacity: 0; transform: translate(-50%, 6px); }
  to   { opacity: 1; transform: translate(-50%, 0); }
}

/* Save-status pill colour variants for the shared modes */
.save-status--shared-view .dot { background: var(--ink-3); }
.save-status--shared-edit .dot { background: #2a8a4a; }

/* =========================================================================
   Print stylesheet — show only the manuscript paper.
   Brings the score canvas full-width on white paper regardless of aesthetic
   so users can print to paper, or use the browser's "Save as PDF" target.
   ========================================================================= */

@media print {
  /* Force white background and the paper aesthetic regardless of UI choice */
  html, html[data-aesthetic],
  body, body.notes-editor-page {
    background: #ffffff !important;
    color: #15161a !important;
  }

  /* Hide every chrome zone — keep only the score page */
  body > header,
  body > footer,
  body > nav,
  body > .site-menu,
  body > .header,
  .notes-editor-page > main > #app .topbar,
  .notes-editor-page > main > #app .palette,
  .notes-editor-page > main > #app .leftpanel,
  .notes-editor-page > main > #app .inspector,
  .notes-editor-page > main > #app .transport,
  .notes-editor-page > main > #app .canvas-floats,
  .notes-editor-page > main > #app .canvas-status,
  .notes-editor-page > main > #app .score-list-panel,
  .notes-editor-page > main > #app .tweaks-panel,
  .notes-editor-page > main > #app .file-error,
  .notes-editor-page > main > #app .palette-sheet-handle,
  .notes-editor-page > main > #app .mobile-scrim,
  .shortcuts-modal,
  .share-modal,
  .score-details-modal,
  .share-banner-error,
  .piano-dock,
  .ro-toast,
  .boot-overlay,
  .brush-preview,
  .snap-guide,
  .drop-hint {
    display: none !important;
  }

  /* Knock out the global site header offset so the score starts at the top */
  body.notes-editor-page { margin: 0 !important; }
  body.notes-editor-page > main { margin-top: 0 !important; }

  /* Collapse the editor grid so the canvas takes the full page width */
  .notes-editor-page .app,
  .notes-editor-page .canvas-wrap {
    display: block !important;
    position: static !important;
    width: 100% !important;
    max-width: 100% !important;
    height: auto !important;
    background: #ffffff !important;
    padding: 0 !important;
    margin: 0 !important;
    overflow: visible !important;
  }

  /* The actual manuscript paper — full width, no shadow, black-on-white */
  .notes-editor-page .score-page {
    width: 100% !important;
    max-width: 100% !important;
    margin: 0 auto !important;
    padding: 24px 28px !important;
    background: #ffffff !important;
    color: #15161a !important;
    box-shadow: none !important;
    border: 0 !important;
    border-radius: 0 !important;
    page-break-inside: auto;
  }
  .notes-editor-page .score-page.is-page-view {
    padding: 0 !important;
  }
  .notes-editor-page .verovio-host--paged {
    gap: 0 !important;
    display: block !important;
  }
  .notes-editor-page .score-paper-page {
    width: 100% !important;
    min-height: auto !important;
    padding: 12mm 10mm 8mm !important;
    background: #ffffff !important;
    border: 0 !important;
    border-radius: 0 !important;
    box-shadow: none !important;
    page-break-after: always;
    break-after: page;
  }
  .notes-editor-page .score-paper-page:last-of-type {
    page-break-after: auto;
    break-after: auto;
  }
  .notes-editor-page .score-page-meta,
  .notes-editor-page .score-page-footer {
    color: #15161a !important;
  }

  /* Title block — make sure printable text is true black */
  .notes-editor-page .score-page .score-titles,
  .notes-editor-page .score-page .score-titles input {
    color: #15161a !important;
    background: transparent !important;
    border: 0 !important;
  }
  .notes-editor-page .score-page .score-tempo {
    color: #15161a !important;
  }

  /* Verovio SVG: render black ink on white paper */
  .notes-editor-page .verovio-host svg {
    background: #ffffff !important;
  }
  .notes-editor-page .verovio-host svg * {
    fill: #15161a !important;
    stroke: #15161a !important;
  }
  /* Drop UI overlays inside the host */
  .notes-editor-page .verovio-host .selected,
  .notes-editor-page .verovio-host .playing-note {
    fill: #15161a !important;
    stroke: #15161a !important;
  }

  @page {
    margin: 12mm 12mm 14mm 12mm;
  }
}

/* ════════════════════════════════════════════════════════════════════════
   MS-329 — Live MIDI input (top-bar button + popover + Transport Record
   ════════════════════════════════════════════════════════════════════════ */

.ne-midi-button-wrap {
  position: relative;
  display: inline-flex;
  align-items: center;
}
.ne-midi-button {
  position: relative;
  width: auto;
  padding: 0 8px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.ne-midi-glyph {
  font-size: 14px;
  line-height: 1;
}
.ne-midi-status-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--ink-4);
  transition: background 120ms ease, box-shadow 120ms ease;
}
.ne-midi-button-wrap.status-ready    .ne-midi-status-dot { background: #2ecc71; }
.ne-midi-button-wrap.status-leadin   .ne-midi-status-dot { background: #f1c40f; }
.ne-midi-button-wrap.status-recording .ne-midi-status-dot {
  background: #e74c3c;
  animation: ne-midi-pulse 1.1s ease-in-out infinite;
}
.ne-midi-button-wrap.status-no-device .ne-midi-status-dot,
.ne-midi-button-wrap.status-disconnected .ne-midi-status-dot {
  background: var(--ink-4);
}
@keyframes ne-midi-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(231, 76, 60, 0.55); }
  50%      { box-shadow: 0 0 0 6px rgba(231, 76, 60, 0); }
}

.ne-midi-popover {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  z-index: 60;
  width: 280px;
  background: var(--bg);
  color: var(--ink);
  border: 1px solid var(--bg-tint);
  border-radius: 10px;
  padding: 12px;
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.18);
  font-size: 12.5px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.ne-midi-popover-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 13px;
}
.ne-midi-field {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.ne-midi-field > span:first-child {
  font-size: 10.5px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.ne-midi-field select {
  width: 100%;
  padding: 5px 8px;
  background: var(--bg-tint);
  border: 0;
  border-radius: 6px;
  outline: none;
  font: inherit;
  font-size: 12.5px;
  color: var(--ink);
}
.ne-midi-modes {
  display: flex;
  gap: 6px;
}
.ne-midi-modes button {
  flex: 1;
  padding: 6px 8px;
  background: var(--bg-tint);
  border: 0;
  border-radius: 6px;
  font: inherit;
  font-size: 12px;
  color: var(--ink-2);
  cursor: pointer;
  transition: background 120ms ease, color 120ms ease;
}
.ne-midi-modes button[aria-pressed="true"] {
  background: var(--accent-soft);
  color: var(--accent);
}
.ne-midi-overdub {
  flex-direction: row;
  align-items: center;
  gap: 8px;
}
.ne-midi-overdub > span {
  font-size: 12px;
  color: var(--ink-2);
  letter-spacing: 0;
  text-transform: none;
}
.ne-midi-hint {
  margin: 0;
  font-size: 11.5px;
  color: var(--ink-3);
  line-height: 1.4;
}

/* MS-329 — Transport Record button when active */
.tr-btn.tr-record[aria-disabled="true"] {
  cursor: default;
  opacity: 0.7;
}
.tr-btn.tr-record.is-recording {
  animation: ne-midi-pulse 1.1s ease-in-out infinite;
}

/* Hide the popover on small screens — fold to the right drawer instead so
   it doesn't get clipped by the top-bar overflow. */
@media (max-width: 600px) {
  .ne-midi-popover {
    right: -40px;
    width: 260px;
  }
}

/* ============================================================
   MS-330 — Practice mode + standalone practice tools
   ============================================================
   Visual states (note flash classes) attach to Verovio note <g> elements.
   The host shell respects the existing right-panel grid slot so the
   Practice panel slides into the Inspector position cleanly. */

@keyframes ne-practice-flash-green {
  0%   { fill: #18b06d; stroke: #18b06d; opacity: 1; }
  60%  { fill: #18b06d; stroke: #18b06d; opacity: 0.9; }
  100% { fill: currentColor; stroke: currentColor; opacity: 1; }
}
@keyframes ne-practice-flash-yellow {
  0%   { fill: #d8a300; stroke: #d8a300; opacity: 1; }
  60%  { fill: #d8a300; stroke: #d8a300; opacity: 0.9; }
  100% { fill: currentColor; stroke: currentColor; opacity: 1; }
}
@keyframes ne-practice-flash-red {
  0%   { fill: #d23a3a; stroke: #d23a3a; opacity: 1; }
  60%  { fill: #d23a3a; stroke: #d23a3a; opacity: 0.9; }
  100% { fill: currentColor; stroke: currentColor; opacity: 1; }
}
.verovio-host g.note-state-hit-green path,
.verovio-host g.note-state-hit-green ellipse,
.verovio-host g.note-state-hit-green use {
  animation: ne-practice-flash-green 1.2s ease-out forwards;
}
.verovio-host g.note-state-hit-yellow path,
.verovio-host g.note-state-hit-yellow ellipse,
.verovio-host g.note-state-hit-yellow use {
  animation: ne-practice-flash-yellow 1.2s ease-out forwards;
}
.verovio-host g.note-state-miss-red path,
.verovio-host g.note-state-miss-red ellipse,
.verovio-host g.note-state-miss-red use {
  animation: ne-practice-flash-red 1.2s ease-out forwards;
}

/* Loop region highlight — applied at render time to notes inside the A/B
   range. Reuses the existing .in-range affordance so a single source of
   truth styles both the practice loop and the editor range selection. */
.verovio-host g.in-range {
  outline: 2px dashed rgba(79, 195, 247, 0.55);
}

/* Practice panel — slides into the right-panel grid slot when the Practice
   tab is active. Mobile collapses it into a bottom sheet (below). */
.practice-panel {
  display: flex;
  flex-direction: column;
  gap: 16px;
  padding: 18px 18px 80px;
  overflow-y: auto;
  background: var(--surface);
  border-left: 1px solid var(--line);
  font-size: 12.5px;
  color: var(--ink);
  grid-area: right;
}
.practice-panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.practice-panel-head h3 {
  margin: 0;
  font-size: 14px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-2);
}
.practice-play-btn {
  padding: 6px 12px;
  background: var(--accent);
  color: #fff;
  border: 0;
  border-radius: var(--r-sm);
  font-weight: 500;
  cursor: pointer;
  font-size: 12.5px;
}
.practice-play-btn.is-playing {
  background: #d23a3a;
}
.practice-notice {
  padding: 10px 12px;
  background: var(--bg-tint);
  border-radius: var(--r-sm);
  color: var(--ink-2);
  font-size: 12px;
  line-height: 1.4;
}
.practice-section {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.practice-section h4 {
  margin: 0;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.practice-tol-row {
  display: inline-flex;
  background: var(--bg-tint);
  border-radius: var(--r-sm);
  padding: 2px;
  gap: 2px;
}
.practice-tol-chip {
  flex: 1;
  border: 0;
  background: transparent;
  color: var(--ink-2);
  padding: 6px 8px;
  border-radius: 4px;
  cursor: pointer;
  font-size: 12px;
  text-transform: capitalize;
}
.practice-tol-chip small {
  display: block;
  color: var(--ink-4);
  font-size: 10px;
  margin-top: 2px;
}
.practice-tol-chip.is-active {
  background: var(--surface);
  color: var(--ink);
  box-shadow: var(--shadow-1);
}
.practice-parts-list {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.practice-part-row {
  display: grid;
  grid-template-columns: 18px 1fr auto;
  gap: 10px;
  align-items: center;
  padding: 6px 8px;
  background: var(--bg-tint);
  border-radius: var(--r-sm);
  cursor: pointer;
  font-size: 12.5px;
}
.practice-part-name {
  color: var(--ink);
}
.practice-part-clef {
  font-size: 11px;
  color: var(--ink-3);
}
.practice-hint {
  margin: 0;
  font-size: 11px;
  line-height: 1.4;
  color: var(--ink-3);
}
.practice-loop-row {
  display: flex;
  align-items: center;
  gap: 10px;
}
.practice-loop-badge {
  padding: 3px 8px;
  background: var(--accent-soft);
  color: var(--accent);
  border-radius: 4px;
  font-size: 11px;
  font-weight: 500;
}
.practice-link-btn {
  border: 0;
  background: transparent;
  color: var(--accent);
  cursor: pointer;
  font-size: 11.5px;
  padding: 0;
  text-decoration: underline;
}
.practice-toggle-row {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12.5px;
  color: var(--ink-2);
}
.practice-ramp-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
}
.practice-ramp-grid label {
  display: flex;
  flex-direction: column;
  gap: 3px;
  font-size: 11px;
  color: var(--ink-3);
}
.practice-ramp-grid input {
  padding: 4px 6px;
  background: var(--bg-tint);
  border: 0;
  border-radius: 4px;
  font: inherit;
  font-size: 12px;
  color: var(--ink);
}
.practice-summary {
  padding: 12px;
  background: var(--accent-soft);
  border-radius: var(--r-sm);
}
.practice-summary-grid {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 4px 12px;
  margin: 0;
  font-size: 12px;
}
.practice-summary-grid dt {
  color: var(--ink-3);
  font-weight: 500;
}
.practice-summary-grid dd {
  margin: 0;
  font-family: var(--font-mono);
  color: var(--ink);
}
.practice-weak-bars {
  margin-top: 8px;
  font-size: 11.5px;
  color: var(--ink-2);
  line-height: 1.4;
}

/* Transport — MS-330 standalone tool chips (visible in every tab). */
.tr-speed {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 0 6px;
  background: var(--bg-tint);
  border-radius: var(--r-sm);
  height: 28px;
}
.tr-speed-label {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--ink-3);
  min-width: 36px;
  text-align: right;
}
.tr-speed input[type="range"] {
  width: 80px;
  accent-color: var(--accent);
  cursor: pointer;
}
.tr-countin {
  height: 28px;
  padding: 0 10px;
  background: var(--bg-tint);
  border: 0;
  border-radius: var(--r-sm);
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--ink-2);
  cursor: pointer;
}
.tr-countin.is-active {
  background: var(--accent-soft);
  color: var(--accent);
}
.tr-loop-ab {
  font-family: var(--font-mono);
  font-size: 11px;
  width: 38px;
}
.tr-loop-ab.is-active {
  background: var(--accent-soft);
  color: var(--accent);
}

/* Mobile — Practice panel becomes a bottom sheet (per MS-330 spec);
   transport chips shrink to stay inside the 360 px width. The transport
   itself becomes horizontally scrollable on the narrowest viewports so
   all controls remain reachable without colliding with the speed slider /
   count-in / A/B chip MS-330 added. */
@media (max-width: 1024px) {
  .practice-panel {
    position: fixed;
    left: 0;
    right: 0;
    /* Sit above the transport bar (60 px tall in mobile) with a small
       breathing gap so the sheet's shadow reads. */
    bottom: 64px;
    z-index: 35;
    max-height: 55vh;
    grid-area: auto;
    border-left: 0;
    border-top: 1px solid var(--line);
    border-radius: 14px 14px 0 0;
    padding: 14px 14px 24px;
    box-shadow: 0 -8px 24px -8px rgba(0,0,0,0.32);
    background: var(--surface);
  }
  .tr-speed input[type="range"] { width: 56px; }
  .tr-speed-label { display: none; }
  .tr-countin {
    padding: 0 4px;
    min-width: 26px;
    font-size: 10px;
  }
  .tr-loop-ab { width: 30px; font-size: 10px; }
  .transport { overflow-x: auto; }
  .transport::-webkit-scrollbar { height: 4px; }
  .transport::-webkit-scrollbar-thumb { background: var(--line); border-radius: 2px; }
}

/* ════════════════════════════════════════════════════════════════════════
   MS-332 — Real-time collaboration: peer presence, cursors, comments
   ════════════════════════════════════════════════════════════════════════ */

/* ── Peer list (TopBar avatar chips) ── */
.peer-list {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  padding: 0 4px;
}
.peer-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  border: 2px solid transparent;
  font-size: 10px;
  font-weight: 600;
  color: #fff;
  cursor: default;
  user-select: none;
  text-shadow: 0 1px 2px rgba(0,0,0,.25);
  transition: transform .15s ease;
}
.peer-avatar:hover { transform: scale(1.12); }
.peer-avatar--local {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
.peer-avatar--overflow {
  background: var(--panel-bg);
  color: var(--ink-2);
  border: 1.5px solid var(--line);
  font-size: 9px;
}

/* ── Live / Reconnecting status pill ── */
.collab-status {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: .03em;
  white-space: nowrap;
  user-select: none;
}
.collab-status--live {
  background: rgba(46, 160, 67, .12);
  color: #2ea043;
}
.collab-status--reconnecting {
  background: rgba(210, 153, 34, .13);
  color: #b08000;
}
.collab-status-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  flex-shrink: 0;
}
.collab-status--live        .collab-status-dot { background: #2ea043; }
.collab-status--reconnecting .collab-status-dot {
  background: #e3a008;
  animation: collab-blink 1.2s ease-in-out infinite;
}
@keyframes collab-blink {
  0%, 100% { opacity: 1; }
  50%       { opacity: .3; }
}

/* ── Multi-cursor overlay ── */
.cursor-overlay {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 6;
  overflow: hidden;
}
.cursor-line {
  position: absolute;
  width: 2px;
  border-left: 2px solid;
  pointer-events: none;
  border-radius: 1px;
}
.cursor-label {
  position: absolute;
  top: -18px;
  left: 0;
  padding: 1px 5px;
  border-radius: 3px 3px 3px 0;
  font-size: 9px;
  font-weight: 600;
  color: #fff;
  white-space: nowrap;
  line-height: 16px;
  pointer-events: none;
}

/* ── Comment thread bubbles ── */
.comment-bubble {
  position: absolute;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  border: 2px solid var(--canvas-bg, #fff);
  cursor: pointer;
  z-index: 7;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 8px;
  color: #fff;
  font-weight: 700;
  box-shadow: 0 1px 4px rgba(0,0,0,.18);
  transition: transform .12s ease;
}
.comment-bubble:hover { transform: scale(1.2); }
.comment-bubble--resolved { opacity: .45; }

/* ── Comment thread panel (Inspector tab / popover) ── */
.comment-thread {
  padding: 8px 0;
}
.comment-thread-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 12px 4px;
  font-size: 11px;
  font-weight: 600;
  color: var(--ink-2);
  text-transform: uppercase;
  letter-spacing: .05em;
}
.comment-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 4px 12px;
  max-height: 240px;
  overflow-y: auto;
}
.comment-item {
  background: var(--panel-bg);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 6px 8px;
  font-size: 12px;
  line-height: 1.45;
}
.comment-item--resolved {
  opacity: .5;
  text-decoration: line-through;
}
.comment-author {
  font-weight: 600;
  font-size: 11px;
  color: var(--ink-2);
  margin-bottom: 2px;
}
.comment-body { color: var(--ink-1); }
.comment-actions {
  display: flex;
  gap: 6px;
  margin-top: 4px;
}
.comment-action-btn {
  font-size: 10px;
  padding: 1px 6px;
  border-radius: 3px;
  border: 1px solid var(--line);
  background: none;
  color: var(--ink-2);
  cursor: pointer;
}
.comment-action-btn:hover { background: var(--hover); color: var(--ink-1); }
.comment-add-row {
  display: flex;
  gap: 6px;
  padding: 6px 12px 4px;
}
.comment-add-input {
  flex: 1;
  padding: 5px 8px;
  border-radius: 5px;
  border: 1px solid var(--line);
  background: var(--input-bg, var(--canvas-bg));
  color: var(--ink-1);
  font-size: 12px;
  font-family: inherit;
  resize: none;
  min-height: 32px;
  max-height: 80px;
}
.comment-add-input:focus {
  outline: none;
  border-color: var(--accent);
}
.comment-add-btn {
  padding: 5px 10px;
  border-radius: 5px;
  border: none;
  background: var(--accent);
  color: #fff;
  font-size: 11px;
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
  align-self: flex-end;
}
.comment-add-btn:hover { filter: brightness(1.1); }
.comment-add-btn:disabled { opacity: .4; cursor: not-allowed; }
.comment-empty {
  padding: 8px 12px;
  font-size: 12px;
  color: var(--ink-3);
  font-style: italic;
}

/* ── Comment indicator dot on selected note in Inspector ── */
.insp-comment-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--accent);
  margin-left: 4px;
  vertical-align: middle;
}

/* Hide peer-list and collab-status on very small screens (keep the score legible) */
@media (max-width: 480px) {
  .peer-list { display: none; }
  .collab-status-label { display: none; }
}

/* ──────────────────────────────────────────────────────────────────────
   MS-349 — Key Signature dialog (Western / Maqam tabs)
   Mirrors .score-details-modal for visual consistency. RTL flips applied
   via [dir="rtl"] for MS-350 Arabic-mode.
   ────────────────────────────────────────────────────────────────────── */
.key-sig-modal {
  position: fixed; inset: 0;
  background: rgba(15, 20, 30, 0.55);
  display: flex; align-items: center; justify-content: center;
  z-index: 1000;
  padding: 16px;
}
.key-sig-card {
  background: var(--card-bg, #fff);
  color: var(--text, #15161a);
  border-radius: 12px;
  box-shadow: 0 16px 48px rgba(0, 0, 0, 0.25);
  width: min(100%, 680px);
  max-height: calc(100vh - 32px);
  overflow-y: auto;
  display: flex; flex-direction: column;
  gap: 14px;
  padding: 20px 22px;
}
.key-sig-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px;
}
.key-sig-head h3 {
  margin: 0;
  font: 600 18px/1.2 'Inter', system-ui, sans-serif;
}
.key-sig-tabs {
  display: flex; gap: 6px;
  border-bottom: 1px solid var(--border, #e5e7eb);
}
.key-sig-tab {
  background: transparent;
  border: 0;
  padding: 8px 16px;
  font: 500 14px/1 inherit;
  color: var(--text-muted, #5b6373);
  cursor: pointer;
  border-radius: 6px 6px 0 0;
  border-bottom: 2px solid transparent;
}
.key-sig-tab.is-active {
  color: var(--text, #15161a);
  border-bottom-color: var(--accent, #4fc3f7);
}
.key-sig-tab:hover { background: rgba(0, 0, 0, 0.04); }

.key-sig-pane { display: flex; flex-direction: column; gap: 12px; }

.key-sig-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  gap: 8px;
}
.key-sig-chip {
  background: var(--bg-tint, #f3f4f6);
  border: 1px solid transparent;
  border-radius: 8px;
  padding: 10px 12px;
  font: 500 13px/1.2 inherit;
  color: var(--text, #15161a);
  cursor: pointer;
  text-align: left;
  transition: background 0.12s, border-color 0.12s;
}
.key-sig-chip:hover { background: rgba(0, 0, 0, 0.06); }
.key-sig-chip.is-active {
  background: var(--accent-tint, rgba(79, 195, 247, 0.18));
  border-color: var(--accent, #4fc3f7);
}
.key-sig-chip--maqam {
  display: flex; flex-direction: column; gap: 2px;
}
.maqam-name-primary {
  font: 600 14px/1.2 inherit;
}
.maqam-name-secondary {
  font: 400 12px/1.2 inherit;
  color: var(--text-muted, #5b6373);
}

.key-sig-tonic-row {
  display: flex; align-items: center; gap: 10px;
}
.key-sig-tonic-row label {
  font: 500 13px/1 inherit;
  color: var(--text-muted, #5b6373);
}
.key-sig-tonic-row select {
  flex: 0 0 auto;
  background: var(--bg-tint, #f3f4f6);
  border: 1px solid var(--border, #e5e7eb);
  border-radius: 6px;
  padding: 6px 10px;
  font: inherit;
}

.key-sig-preview {
  background: var(--bg-tint, #f3f4f6);
  border-radius: 8px;
  padding: 10px 12px;
  font: 500 13px/1.2 inherit;
  display: flex; gap: 8px; align-items: baseline;
}
.key-sig-preview-label { color: var(--text-muted, #5b6373); }
.key-sig-preview-value { color: var(--text, #15161a); font-weight: 600; }

.key-sig-foot {
  display: flex; justify-content: flex-end; gap: 8px;
}
.key-sig-foot .btn {
  padding: 8px 16px;
  border-radius: 8px;
  font: 500 14px/1 inherit;
  border: 0;
  cursor: pointer;
}
.key-sig-foot .btn.ghost {
  background: transparent;
  color: var(--text-muted, #5b6373);
}
.key-sig-foot .btn.primary {
  background: var(--accent, #4fc3f7);
  color: #fff;
}

/* MS-349 — Inspector "Choose key…" button replaces the old <select>. */
.keysig-open-btn {
  background: transparent;
  border: 0;
  padding: 4px 6px;
  font: inherit;
  color: inherit;
  cursor: pointer;
  text-align: left;
  border-radius: 5px;
  width: 100%;
}
.keysig-open-btn:hover { background: var(--bg-tint, rgba(0, 0, 0, 0.04)); }

/* MS-350 — RTL flip when the score language is Arabic. The dialog content
   already lays out left→right naturally; we just mirror padding nuances
   and re-orient the tonic-row label alignment. */
.key-sig-modal[dir="rtl"] .key-sig-tabs { flex-direction: row-reverse; }
.key-sig-modal[dir="rtl"] .key-sig-foot { flex-direction: row-reverse; }
.key-sig-modal[dir="rtl"] .key-sig-tonic-row { flex-direction: row-reverse; }
.key-sig-modal[dir="rtl"] .key-sig-preview { flex-direction: row-reverse; }

@media (max-width: 600px) {
  .key-sig-card { padding: 16px; }
  .key-sig-list { grid-template-columns: 1fr 1fr; }
  .key-sig-tab { padding: 8px 12px; }
}
@media (max-width: 400px) {
  .key-sig-list { grid-template-columns: 1fr; }
}

/* ──────────────────────────────────────────────────────────────────────
   MS-350 — Arabic-script lyric blocks render right-to-left automatically.
   The `lyric-rtl` class is added at MEI emit time when the lyric starts
   with an Arabic-range code point, and lands on the rendered Verovio
   `<g class="syl">` so the inner `<text>` flows in the correct direction.
   `unicode-bidi: plaintext` lets mixed Arabic + Latin lyrics still resolve
   per-segment.

   Arabic-font fallback stack so missing glyphs land on a real Naskh face
   rather than the browser's default fallback (which often draws Arabic
   in a thin sans face that doesn't pair with notation).
   ────────────────────────────────────────────────────────────────────── */
svg g.syl.lyric-rtl text {
  direction: rtl;
  unicode-bidi: plaintext;
}
svg g.syl.lyric-rtl text,
[lang="ar"] .lyric,
[dir="rtl"] .key-sig-card .maqam-name-primary {
  font-family: 'Noto Naskh Arabic', 'Amiri', 'Arabic Typesetting',
               'Geeza Pro', 'Traditional Arabic', serif;
}

/* ──────────────────────────────────────────────────────────────────────
   MS-346 — Inspector "Explain" panel
   Deterministic music-theory analysis surface: scale degree, chord
   detection, interval list, voice-leading warnings. AI narrative tab
   is hidden behind the MS-331 feature flag in v1.
   ────────────────────────────────────────────────────────────────────── */
.explain-panel { display: flex; flex-direction: column; gap: 4px; }
.explain-empty {
  color: var(--text-muted, #5b6373);
  font: 400 13px/1.4 inherit;
  margin: 0;
}
.explain-key {
  font: 600 14px/1.2 inherit;
  color: var(--text, #15161a);
}
.explain-degree {
  display: flex; align-items: baseline; gap: 8px;
}
.explain-degree .degree-number {
  font: 700 28px/1 inherit;
  color: var(--accent, #4fc3f7);
}
.explain-degree .degree-name {
  font: 500 14px/1.2 inherit;
  color: var(--text, #15161a);
  text-transform: capitalize;
}
.explain-chord {
  display: flex; align-items: baseline; gap: 10px;
  margin-bottom: 6px;
}
.explain-chord .chord-label {
  font: 700 18px/1.2 inherit;
  color: var(--text, #15161a);
}
.explain-chord .chord-roman {
  font: 500 16px/1.2 inherit;
  color: var(--accent, #4fc3f7);
}
.explain-tip {
  color: var(--text-muted, #5b6373);
  font: 400 12px/1.4 inherit;
  margin: 4px 0 0;
}
.explain-intervals {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex; flex-direction: column; gap: 4px;
}
.explain-intervals li {
  display: flex; justify-content: space-between; gap: 8px;
  padding: 4px 8px;
  background: var(--bg-tint, rgba(0, 0, 0, 0.04));
  border-radius: 5px;
  font: 500 12px/1.2 inherit;
}
.explain-intervals .iv-pair { color: var(--text, #15161a); }
.explain-intervals .iv-label { color: var(--text-muted, #5b6373); }
.explain-flag {
  padding: 8px 10px;
  border-radius: 6px;
  font: 500 12px/1.4 inherit;
}
.explain-flag--warn {
  background: rgba(220, 100, 70, 0.10);
  border: 1px solid rgba(220, 100, 70, 0.35);
  color: var(--text, #15161a);
}
.explain-flag .flag-kind {
  font-weight: 700;
  color: rgb(180, 54, 28);
  margin-right: 4px;
}

/* ──────────────────────────────────────────────────────────────────────
   MS-335 — Engraving font select + "Suggest system breaks" action.
   Matches the existing twk-row / twk-lbl visual rhythm in the Tweaks
   panel.
   ────────────────────────────────────────────────────────────────────── */
.twk-row .twk-select {
  background: var(--bg-tint, rgba(0, 0, 0, 0.04));
  border: 1px solid var(--border, rgba(0, 0, 0, 0.10));
  border-radius: 5px;
  padding: 4px 8px;
  font: inherit;
  font-size: 12px;
  color: inherit;
  min-width: 130px;
}
.twk-action-btn {
  width: 100%;
  background: var(--bg-tint, rgba(0, 0, 0, 0.04));
  border: 1px solid var(--border, rgba(0, 0, 0, 0.10));
  border-radius: 6px;
  padding: 6px 10px;
  font: 500 12px/1.2 inherit;
  color: var(--text, #15161a);
  cursor: pointer;
  text-align: left;
}
.twk-action-btn:hover {
  background: var(--accent-tint, rgba(79, 195, 247, 0.10));
  border-color: var(--accent, #4fc3f7);
}
