/**
 * chart-v2.css — styles for Chart Editor v2 (parallel to Collections).
 * Companion to assets/js/chart-v2.js and assets/css/smufl.css.
 *
 * Naming: every class is `.suite-*` so this file can never collide with
 * Collections (.coll-*) or the legacy chart-editor (.chart-editor-*).
 */

/* ── Tab → Chart generator button (suite Tab panel) ──────────────────── */
.suite-tab-gen { display: flex; justify-content: flex-end; gap: 8px; margin: 0 0 8px; }
.suite-tab-gen-btn {
  padding: 8px 14px;
  border-radius: 8px;
  border: 1px solid var(--accent, #c85a1a);
  background: var(--accent, #c85a1a);
  color: #fff;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
}
.suite-tab-gen-btn:hover { filter: brightness(1.05); }
.suite-tab-gen-btn--ghost {
  background: var(--surface, #fff);
  color: var(--accent, #c85a1a);
}

/* ── Page shell ──────────────────────────────────────────────────────── */
#route-chart-v2 { padding: 20px 24px 64px; }
.suite-root { width: 100%; margin: 0 auto; color: var(--text); }
/* When chart-v2 is the active route, lift the global page-wrap 1600 px
   cap so the chart can use the full viewport width.  Editor + browser
   modes both benefit; user explicitly asked for max width on the chart
   page (2026-04-29). */
.page-wrap:has(#route-chart-v2.active) {
  max-width: none;
  padding-left: var(--sp-3);
  padding-right: var(--sp-3);
}
.suite-root--read .suite-toolbar,
.suite-root--read .suite-bar-gear,
.suite-root--read .suite-hint { display: none !important; }
/* Section header stays visible in read mode (the name + tempo are
   PUBLISHED chart content), but all editing chrome inside it is HIDDEN:
   the right-side tools cluster (+ Bar, ×N, ↑, ↓, ×, ⚙), the time-sig
   select, and the editing borders/backgrounds on the name input. */
.suite-root--read .suite-section-head .suite-btn,
.suite-root--read .suite-section-head-tools,
.suite-root--read .suite-section-head .suite-section-ts {
  display: none;
}
/* Section name stays readable but loses its editable affordance. */
.suite-root--read .suite-section-name {
  pointer-events: none; background: transparent; border-color: transparent;
}
/* Hide empty-diagram '+' placeholders so read-mode reads as a clean printed
   chart, not an editor.  Also drop any active-edit orange outline. */
.suite-root--read .suite-beat-diagram-empty { visibility: hidden; }
.suite-root--read .suite-beat-rhythm.is-editing { box-shadow: none; background: transparent; }
/* No interactive affordances in read mode — kill the cursor: pointer and
   the hover card (cream background "popover" effect) on every clickable
   cell so the chart reads as a static printed score. */
.suite-root--read .suite-beat-diagram,
.suite-root--read .suite-beat-rhythm,
.suite-root--read .suite-beat-chord,
.suite-root--read .suite-rhy-glyph { cursor: default; }
.suite-root--read .suite-beat-diagram:hover,
.suite-root--read .suite-beat-rhythm:hover {
  background: transparent;
  box-shadow: none;
}
/* Push the Read/Edit toggle to the right edge of the chart-picker bar
   so it's the obvious "exit read mode" action. */
.suite-chartbar-mode { margin-left: auto; }

/* Undo / Redo buttons — icon-only, square, sit just left of the
   Read/Edit toggle (auto-margin pushes Mode all the way right).
   Sizing matches Fretly's legacy undo/redo (site.css `.btn--sm`):
   16 px glyph, tight 3/6 px padding. */
.suite-chartbar-undo,
.suite-chartbar-redo {
  min-width: 32px;
  padding: 3px 6px;
  font-size: 16px;
  line-height: 1;
}
.suite-chartbar-undo { margin-left: auto; }   /* gap before pair */
.suite-chartbar-redo { margin-right: 4px; }
.suite-chartbar-mode { margin-left: 0; }       /* override earlier auto */
.suite-chartbar-undo.is-disabled,
.suite-chartbar-redo.is-disabled,
.suite-chartbar-undo:disabled,
.suite-chartbar-redo:disabled {
  opacity: 0.32;
  cursor: not-allowed;
  pointer-events: none;
}

/* ── Export stage ────────────────────────────────────────────────────── */
/* Off-screen host for _snapshot's chart export: a fresh read-mode chart
   is rendered here at canonical width and captured, so the LIVE view
   never changes during export (owner 2026-07-08).  Positioned off-screen
   (not display:none — the layout cascade must run). */
.suite-export-stage {
  position: absolute;
  left: -20000px;
  top: 0;
  width: 1600px;
  background: var(--surface, #fff);
}

/* ── Chart-picker bar (top) ──────────────────────────────────────────── */
.suite-chartbar {
  display: flex; gap: 8px; align-items: center;
  /* Half-width windows (owner 2026-07-08): controls used to overflow the
     bar and get clipped — wrap to a second row instead. */
  flex-wrap: wrap;
  row-gap: 6px;
  padding: 10px 14px;
  background: var(--surface, #fff);
  border: 1px solid var(--border, #e1ddd2);
  /* Match the content-card look (.coll-block) so the chartbar and the
     Collection / Diagram-Sheet section blocks below it form a single
     visual family — same radius, same elevation, same border. */
  border-radius: var(--r-lg, 14px);
  box-shadow: var(--shadow);
  margin-bottom: 12px;
}
.suite-chart-select {
  flex: 1 1 240px; min-width: 200px; max-width: 360px;
  padding: 8px 10px; border-radius: 8px; border: 1px solid var(--border, #d8d4c8);
  background: var(--surface, #fff); color: var(--text); font-size: 14px;
}
/* Active-chart name button — replaces the old <select>.  Click opens
   the FretlyOrganizer overlay (chart manager). */
.suite-chartbar-current {
  flex: 0 1 auto; min-width: 140px; max-width: 360px;
  padding: 8px 12px;
  border-radius: 8px;
  border: 1px solid var(--border, #d8d4c8);
  background: var(--surface, #fff);
  color: var(--text);
  font-size: 14px; font-weight: 600;
  cursor: pointer;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.suite-chartbar-current:hover { border-color: var(--accent, #c85a1a); }
.suite-chartbar-manage {
  padding: 8px 12px;
  border-radius: 8px;
  border: 1px solid var(--border, #d8d4c8);
  background: var(--surface, #fff);
  color: var(--text);
  font-size: 13px;
  cursor: pointer;
}
.suite-chartbar-manage:hover {
  border-color: var(--accent, #c85a1a);
  color: var(--accent, #c85a1a);
}
/* Back-to-navigator button — always visible in editor mode so the user
   can step out of an open chart and return to the folder browser.
   Inherits .suite-btn dimensions (6 px × 12 px padding, 6 px radius,
   13 px font) so it matches the rest of the chartbar (Export, Edit)
   visually.  Only overrides colour to read as a quieter navigation
   affordance vs the action buttons. */
.suite-chartbar-back {
  color: var(--text-2, #555);
  white-space: nowrap;
}
.suite-chartbar-back:hover {
  border-color: var(--accent, #c85a1a);
  color: var(--accent, #c85a1a);
}

/* Origin back-pill — visible only when the chart was opened from a
   music page (chord, scale, …) that stamped `?from=…&fromLabel=…`.
   Visually the user's path home: tinted background, accent border so
   it stands apart from the generic "← Charts" navigator button. */
.suite-chartbar-origin {
  padding: 8px 12px;
  border-radius: 8px;
  border: 1px solid var(--accent, #c85a1a);
  background: rgba(232, 135, 74, 0.08);
  color: var(--accent, #c85a1a);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
}
.suite-chartbar-origin:hover {
  background: var(--accent, #c85a1a);
  color: #fff;
}

/* Picker-view origin bar — same pill, hosted in its own band above
   the FretlyOrganizer grid so the user always has a path home. */
.suite-picker-originbar {
  display: flex;
  align-items: center;
  padding: 12px 16px 0;
}

/* Suites banner — courtesy nudge at the top of the chart-v2
   file-explorer view pointing to ?route=suites (the canonical
   home).  Discreet styling, single-line, dismissible.  See
   chart/editor.js _renderBrowser for the mount logic. */
.suite-suites-banner {
  display: flex;
  align-items: center;
  gap: var(--space-md, 12px);
  margin: 12px 16px 0;
  padding: var(--space-sm, 10px) var(--space-md, 14px);
  background: var(--accent-bg, rgba(232,135,74,.08));
  border: 1px solid var(--accent-border, rgba(232,135,74,.25));
  border-radius: var(--radius-md, 8px);
  color: var(--text, #2a2a2a);
  font-size: var(--font-sm, 13px);
}
.suite-suites-banner-msg {
  flex: 1 1 auto;
  min-width: 0;
}
.suite-suites-banner-msg strong { font-weight: var(--weight-bold, 600); }
.suite-suites-banner-go {
  flex-shrink: 0;
  text-decoration: none;
  white-space: nowrap;
}
.suite-suites-banner-dismiss {
  flex-shrink: 0;
  width: 24px; height: 24px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 0;
  border-radius: var(--radius-sm, 4px);
  color: var(--text-2, #777);
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  transition: background var(--t-fast, .12s), color var(--t-fast, .12s);
}
.suite-suites-banner-dismiss:hover {
  background: var(--surface-2, #f8f5ef);
  color: var(--text, #2a2a2a);
}

/* ── Read-mode chart title ───────────────────────────────────────────
   The chart-picker bar in read mode hosts a styled heading instead of
   the editable selector + management buttons.  Serif typography with
   generous size + weight reads as a published page title.  Undo/Redo
   stay (see chart-v2.css default rule); the Read/Edit toggle is kept
   so users can flip back. */
.suite-chartbar--read {
  background: transparent;
  border: none;
  padding: 8px 0 0;
  margin-bottom: 8px;
}
.suite-chart-title-read {
  flex: 1 1 auto;
  margin: 0;
  padding: 4px 0;
  font-family: 'Source Serif Pro', 'Palatino Linotype', Georgia, serif;
  font-size: 32px;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--text);
  line-height: 1.15;
  text-align: center;
}
/* Standalone variant — rendered without the surrounding chartbar
   (chord-page suite drill-in uses this).  Gives the title some
   breathing room since there's no chartbar padding above. */
.suite-chart-title-read--standalone {
  padding: var(--space-md, 12px) 0 var(--space-sm, 8px);
}

/* §13 title-on-paper (owner 2026-06-12): the chart title is part of
   the printed sheet — same engraved typography as the old read-mode
   h1, rendered at the top of .suite-paper in BOTH modes and draggable
   with the Move tool (display.titleOffset). */
.suite-chart-title-paper {
  margin: 0 0 var(--space-sm, 8px);
  padding: var(--space-xs, 4px) 0;
  font-family: 'Source Serif Pro', 'Palatino Linotype', Georgia, serif;
  font-size: 32px;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--text);
  line-height: 1.15;
  text-align: center;
}
.suite-move-armed .suite-chart-title-paper { cursor: move; }
.suite-move-armed .suite-chart-title-paper:hover {
  outline: 1px dashed var(--accent, #c85a1a);
  outline-offset: 2px;
}

/* ── Toolbar ─────────────────────────────────────────────────────────── */
/* Override the routes-v2 grid layout with FLEX so each control is sized
   to its content (not forced into 160px grid tracks).  Keeps the
   labelled-column look from `.form-group` for the controls that need it
   (Key, Mode, Tempo, Bars/line, sliders), while letting the small toggle
   cluster and action button sit at their natural width. */
.suite-toolbar.toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 14px;
  align-items: end;
  margin-bottom: 16px;
}
/* Title row sits ABOVE the control bar so the chart's name reads as a
   page heading rather than another toolbar control. */
.suite-toolbar-wrap { display: flex; flex-direction: column; gap: 8px; margin-top: 8px; margin-bottom: 16px; }
.suite-title-row { padding: 0 4px; }
.suite-title {
  width: 100%;
  padding: 4px 6px;
  border: 1px solid transparent; background: transparent;
  font-size: 26px; font-weight: 700; color: var(--text);
  border-radius: 6px;
  font-family: 'Georgia', 'Times New Roman', serif;
  box-sizing: border-box;
}
/* Smaller chart-title on narrow viewports so it doesn't dominate the
   row or wrap awkwardly. */
@media (max-width: 720px) { .suite-title { font-size: 20px; } }
@media (max-width: 480px) { .suite-title { font-size: 17px; } }
.suite-title:focus { outline: none; border-color: var(--accent, #c85a1a); background: var(--surface, #fff); }
/* Toolbar wrapper above already supplies bottom margin; clear the
   control-bar's own margin so they don't double up. */
.suite-toolbar.toolbar { margin-bottom: 0; }
.suite-toolbar-action { align-self: end; }

/* Compact toggle cluster — Display / Rhythm / Diagrams / Resize.
   Buttons carry their own label inline (no .form-group wrapper) and sit
   tightly together.  Aligns to the bottom so they line up with the
   labelled-column controls' inputs. */
.suite-toolbar-toggles {
  display: inline-flex;
  gap: 4px;
  align-self: end;
  padding-bottom: 2px;
}
.suite-toolbar-toggles .suite-btn--toggle {
  height: 30px;
  padding: 0 10px;
  font-size: 12px;
  line-height: 1;
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.suite-toolbar-toggles .suite-btn--toggle .suite-smufl { font-size: 16px; }

/* Tie-direction glyph in the Ties toolbar button.  Anchors to the TOP
   of the button when ties render ABOVE noteheads (concave-down arc),
   and to the BOTTOM when ties render BELOW (concave-up arc).  Visually
   mirrors the actual tie position so the button reads at a glance. */
.suite-tie-glyph {
  display: inline-block;
  line-height: 1;
  font-size: 18px;
}
.suite-toolbar-toggles .suite-btn--toggle .suite-tie-glyph--above { align-self: flex-start; }
.suite-toolbar-toggles .suite-btn--toggle .suite-tie-glyph--below { align-self: flex-end;   }

/* Narrow-column override for fields that only need a small input. */
.suite-toolbar .suite-tf--narrow { min-width: 70px; max-width: 90px; }
.suite-toolbar .suite-tf--narrow select { width: 100%; }
.suite-key, .suite-mode, .suite-bpl, .suite-tempo {
  padding: 5px 8px; border-radius: 6px; border: 1px solid var(--border, #d8d4c8);
  background: var(--surface, #fff); color: var(--text); font-size: 13px;
}
.suite-tempo { width: 60px; }
.suite-fontsize { width: 100px; }

/* Size steppers — replaces sliders for the four size controls.
   [−] [number] [+] [↺] cluster — precise typing, ±1 nudge, one-click
   reset.  Buttons + input share a 28-px height for a tidy strip. */
.suite-size-stepper {
  display: inline-flex; align-items: center; gap: 2px;
}
.suite-size-stepper-btn {
  width: 24px; height: 28px;
  padding: 0;
  border: 1px solid var(--border, #d8d4c8);
  background: var(--surface, #fff); color: var(--text);
  font-size: 16px; line-height: 1;
  border-radius: 4px;
  cursor: pointer;
}
.suite-size-stepper-btn:hover { background: var(--surface-2, #f1ede4); }
.suite-size-stepper-num {
  width: 44px; height: 28px;
  padding: 0 4px;
  text-align: center;
  border: 1px solid var(--border, #d8d4c8);
  background: var(--surface, #fff); color: var(--text);
  font-size: 13px;
  border-radius: 4px;
  /* Hide native spinners — our +/- buttons replace them. */
  -moz-appearance: textfield;
}
.suite-size-stepper-num::-webkit-outer-spin-button,
.suite-size-stepper-num::-webkit-inner-spin-button {
  -webkit-appearance: none; margin: 0;
}
.suite-size-stepper-reset {
  width: 24px; height: 28px;
  padding: 0;
  margin-left: 2px;
  border: 1px solid transparent;
  background: transparent; color: var(--text-2, #666);
  font-size: 14px; line-height: 1;
  border-radius: 4px;
  cursor: pointer;
}
.suite-size-stepper-reset:hover {
  background: var(--surface-2, #f1ede4);
  color: var(--accent, #c85a1a);
  border-color: var(--border, #d8d4c8);
}

/* ── Generic button ──────────────────────────────────────────────────── */
.suite-btn {
  padding: 6px 12px; border-radius: 6px;
  background: var(--surface, #fff);
  border: 1px solid var(--border, #d8d4c8);
  color: var(--text); font-size: 13px; cursor: pointer;
  transition: background 0.12s, border-color 0.12s;
  line-height: 1.2; font-family: inherit;
}
.suite-btn:hover { background: var(--surface-2, #f1ede4); border-color: var(--border-strong, #c4bfb0); }
.suite-btn--toggle.is-on {
  background: var(--accent-bg, #fff3e6);
  border-color: var(--accent, #c85a1a);
  color: var(--accent, #c85a1a);
}
.suite-btn--accent {
  background: var(--accent, #c85a1a); color: #fff;
  border-color: var(--accent, #c85a1a);
}
.suite-btn--accent:hover { background: var(--accent-hover, #b04a14); }

/* ── Paper area (sections live here) ─────────────────────────────────── */
.suite-paper {
  background: var(--surface, #fffef9);
  border: 1px solid var(--border, #e1ddd2);
  border-radius: 12px;
  padding: 18px 22px;
  font-family: 'Georgia', 'Times New Roman', serif;
  /* Container for narrow-paper queries (half-width window / side panels
     open squeeze the paper while the VIEWPORT stays wide, so media
     queries can't see it — owner 2026-07-08). */
  container-type: inline-size;
  container-name: suite-paper;
}
/* Narrow paper: shrink the engraved sheet title so it doesn't wrap into
   a two-line monolith (the 32px default assumes a full-width sheet). */
@container suite-paper (max-width: 560px) {
  .suite-chart-title-paper { font-size: 22px; }
}
@container suite-paper (max-width: 380px) {
  .suite-chart-title-paper { font-size: 18px; }
}

/* ── Section ─────────────────────────────────────────────────────────── */
/* No extra left padding — paper's symmetric 22px horizontal padding is
   the only horizontal inset. */
/* Per-section vertical margin — chart-level default OR per-section
   override (set via openSectionSettings).  Written as CSS variables
   on the .suite-section element by _applyDisplaySettings.  Defaults
   come from chart.display (top=0, bottom=20) so existing charts
   render unchanged.  Sliders set the actual margin values; user can
   reduce bottom to 0 for flush sections or increase to add space. */
.suite-section {
  margin-top:    var(--suite-section-margin-top,    0);
  margin-bottom: var(--suite-section-margin-bottom, 36px);
}
.suite-section-head {
  display: flex; align-items: center; gap: 8px;
  /* nowrap — keep info + tools on a single line as long as possible.
     The info side shrinks via `flex: 1 1 0; min-width: 0` so the
     section name + override marker can compress before anything
     wraps; the tools side has `flex-shrink: 0` so its buttons keep
     their natural width.  Only when the viewport is so narrow that
     even the tools don't fit does the user need a wider window — and
     even then the header just clips, it doesn't reflow. */
  flex-wrap: nowrap;
  margin-bottom: 26px;
  padding: 6px 8px;
  background: var(--surface-2, #f0ede5);
  border-radius: 6px;
}
/* Two-column header — INFO on the left, TOOLS pushed to the right via
   margin-left: auto.  Info shrinks first when space is tight; tools
   never shrink. */
.suite-section-head-info {
  display: flex; align-items: center; gap: 8px;
  flex: 1 1 0; min-width: 0;
  overflow: hidden;
}
.suite-section-head-tools {
  display: flex; align-items: center; gap: 6px;
  margin-left: auto;
  flex-shrink: 0;
}
.suite-section-name {
  flex: 0 0 80px; padding: 4px 8px;
  border: 1px solid transparent; background: transparent;
  font-size: 14px; font-weight: 700; color: var(--text);
  border-radius: 4px;
}
.suite-section-name:focus { outline: none; border-color: var(--accent, #c85a1a); background: var(--surface, #fff); }
.suite-section-ts {
  padding: 4px 6px; border-radius: 5px; border: 1px solid var(--border, #d8d4c8);
  font-size: 12px; background: var(--surface, #fff); color: var(--text);
}

/* ── Tempo cluster (engraved "♩ = N") ────────────────────────────────
   Shared between chart-level meta strip, section header, and per-bar
   marker.  Layout: SMuFL note glyph (Bravura Text) + italic " = " +
   italic BPM digits, all sitting on the SAME baseline.  Bravura's
   stemmed-note glyphs hang DOWN from the baseline by default; we use
   `vertical-align: baseline` and a slightly larger glyph font-size so
   the stem-tip rises above the digit cap height — matches engraving
   convention (note above, digits to the right).  No flex — pure
   inline-baseline alignment, which is the only way to get rock-solid
   vertical alignment of a SMuFL glyph next to plain text digits. */
/* Inline-flex with align-items: baseline.  Bravura draws the notehead
   ON the font baseline, with the stem extending UP — so aligning text
   baselines puts the notehead bottom at the digits' baseline.
   `flex-end` aligns line-box BOTTOMS, which doesn't match because the
   note has a 1.6em line box vs the text's 1em — the note ends up
   floating above. `baseline` is the right invariant.
   Note: the SMuFL quarter-note glyph is offset slightly below the
   font baseline, so a small downward `top` nudge plants the notehead
   exactly at the digit baseline. */
.suite-tempo-cluster {
  display: inline-flex;
  align-items: baseline;
  font-family: 'Source Serif Pro', 'Palatino Linotype', Georgia, serif;
  font-size: 16px;
  font-style: italic;
  font-weight: 600;
  color: var(--text);
  white-space: nowrap;
  line-height: 1;
  user-select: none;
}
.suite-tempo-cluster .suite-tempo-note {
  /* MUST match the font name registered in smufl.css ('BravuraText'). */
  font-family: 'BravuraText', 'Bravura', serif;
  font-style: normal;
  font-weight: normal;
  font-size: 1.6em;       /* larger so stem rises above digits */
  line-height: 1;
  display: inline-block;
  margin-right: 0.18em;
  position: relative;
  top: 0.32em;            /* Bravura's quarter-note glyph carries a fair
                              bit of empty descender space below the
                              notehead — push the whole glyph down so
                              the visible notehead bottom sits FLUSH on
                              the digit baseline. */
}
.suite-tempo-cluster .suite-tempo-dot {
  font-family: 'BravuraText', 'Bravura', serif;
  font-size: 1em;
  margin-left: 0.05em;
}
.suite-tempo-cluster .suite-tempo-eq  { margin-right: 0.18em; }
.suite-tempo-cluster .suite-tempo-bpm { }

/* Feel / interpretation marker (italic phrase, e.g. "Swing"). */
.suite-feel-marker {
  font-family: 'Source Serif Pro', 'Palatino Linotype', Georgia, serif;
  font-style: italic;
  font-weight: 600;
  font-size: 16px;
  color: var(--text);
  user-select: none;
}

/* Chart-level meta strip — sits above the first section, below the
   chart title.  Houses the chart's tempo cluster + feel marker.  When a
   section overrides either, the section's own marker takes over inside
   that section's header. */
.suite-chart-meta {
  display: flex; align-items: baseline;
  padding: 4px 8px 14px;
  cursor: default;
}
/* Tight click target — only as wide as the tempo/feel content */
.suite-chart-meta-btn {
  display: inline-flex; align-items: baseline; gap: 18px;
  cursor: pointer; border-radius: 4px;
  padding: 2px 6px; margin: -2px -6px;
}
.suite-chart-meta-btn:hover { color: var(--accent, #c85a1a); }
.suite-chart-meta--empty .suite-chart-meta-btn {
  opacity: 0.55; font-style: italic; color: var(--text-2, #666);
  font-size: 13px;
}
.suite-root--read .suite-chart-meta-btn { cursor: default; pointer-events: none; }
.suite-root--read .suite-chart-meta--empty { display: none; }

/* Section header — tempo + feel cluster (the inline editable input
   form is removed; the cluster is now click-to-edit via the meta
   popover). */
.suite-section-meta {
  display: inline-flex; align-items: baseline; gap: 12px; cursor: pointer;
  padding: 2px 6px; border-radius: 4px;
}
.suite-section-meta:hover { background: var(--surface, #fff); }
.suite-section-meta-empty {
  font-size: 12px; opacity: 0.6; font-style: italic;
}
.suite-root--read .suite-section-meta { cursor: default; }
.suite-root--read .suite-section-meta:hover { background: transparent; }
.suite-root--read .suite-section-meta-empty { display: none; }
/* (Section colour swatches removed — feature unused.) */

/* ── Bars row ────────────────────────────────────────────────────────── */
/* Each bar carries its OWN four-sided enclosure (heavier 2px top/bottom,
   1px left/right).  Adjacent bars in the same row overlap their inner
   left/right edges via margin-left:-1px so internal barlines stay 1px.
   .suite-bars adds padding-left:1px to absorb the leading bar's negative
   margin so the leftmost barline lines up with the container edge.
   row-gap separates wrapped rows so the second row reads as its own row. */
.suite-bars {
  display: flex;
  flex-wrap: wrap;
  gap: 0;
  /* Generous vertical gap between wrapped lines of bars so the bar
     numbers (sitting -16px above each bar) read clearly as belonging
     to the bar BELOW them, not crowding the chord text of the line
     above. */
  row-gap: 28px;
  padding-left: 1px;
  /* Allow chord-text spillover to extend past a bar's right edge into the
     gutter without being clipped at the .suite-bars boundary. */
  overflow: visible;
}
/* Forces the next .suite-bar onto a new visual row (used when bar.breakBefore = true). */
.suite-bar-break {
  flex-basis: 100%;
  width: 100%;
  height: 0;
  overflow: hidden;
}

/* "Add bar" placeholder — dashed-outline empty bar at the end of the
   bars grid.  Clickable to append a new bar.  Sized in the same flex
   slot pattern as a real bar so it lines up nicely; styled lighter
   than a real bar so it doesn't compete visually for attention.
   Hidden in read mode (chrome layer). */
.suite-bar-add {
  flex: 0 0 auto;
  align-self: stretch;
  margin-left: -1px;          /* mirror .suite-bar's overlap so the dashed
                                 left border meets the previous bar's right */
  min-width: 80px;
  min-height: 96px;
  border: 2px dashed var(--border, #d8d4c8);
  border-radius: 6px;
  background: transparent;
  color: var(--text-3, #b8b3a3);
  font-size: 28px;
  font-weight: 300;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background 0.12s, color 0.12s, border-color 0.12s;
}
.suite-bar-add:hover {
  background: var(--surface-2, #f1ede4);
  color: var(--accent, #c85a1a);
  border-color: var(--accent, #c85a1a);
}
.suite-root--read .suite-bar-add { display: none; }

/* Display Settings drivers — section-border visibility, border style,
   barline style, bar-number / section-header visibility.  All these are
   set as classes / CSS variables on the chart root or the bars grid by
   the Display Settings popover, so they apply WITHOUT a rerender. */
/* Barline overlay — single SVG drawn AFTER layout, sized + positioned
   to cover the visual extent of .suite-bars.  Sits OUTSIDE the
   transformed subtree so its strokes render at native device pixels
   regardless of any ancestor `transform: scale`.  See
   Editor.prototype._drawBarlineOverlay for the geometry pass. */
.suite-barline-overlay {
  position: absolute;
  pointer-events: none;
  overflow: visible;
  color: var(--text);
  z-index: 1;
}
/* Section is the positioning context for the overlay. */
.suite-section { position: relative; }
.suite-root.no-bar-numbers   .suite-bar-num     { display: none; }
.suite-root.no-section-header .suite-section-head { display: none; }

/* Row separators — thin horizontal lines between the diagram, rhythm and
   chord rows inside every bar.  Hidden by default; enabled by adding
   .row-seps to .suite-root.  Style + colour are CSS-variable driven so
   Display Settings can tweak them.  These divs are flex siblings with
   intermediate `order` values (1, 3) so they always sit between rows
   regardless of the user's row-order choice.  flex-shrink:0 keeps them
   visible when adjacent rows grow with content (e.g. a tall diagram
   row).  margin: 6px 0 keeps a tidy gap so diagrams never touch the
   line. */
.suite-bar-row-sep {
  display: none;
  height: 0;
  flex: 0 0 auto;
  /* Bar has asymmetric horizontal padding (2 px left, 8 px right) so
     diagrams + time-sig hug the leading barline.  The separator's left
     edge would land 2 px from the leading barline and 8 px from the
     trailing one — visually unbalanced.  Margin-left:6 evens it out so
     the dashed line has the SAME 8 px inset from both barlines. */
  margin: 6px 0 6px 6px;
  border-top-width: 1px;
  border-top-style: var(--suite-rowsep-style, dashed);
  border-top-color: var(--suite-rowsep-color, #888);
}
.suite-root.row-seps .suite-bar-row-sep { display: block; }

.suite-bar {
  position: relative;
  display: flex; flex-direction: column;
  /* Vertical gap between rows (diagram / rhythm / chord / scales).
     Driven per-section by the --suite-row-gap variable set on .suite-bars
     in `_applyDisplaySettings`.  Default 0. */
  gap: var(--suite-row-gap, 0);
  /* No CSS border — barlines are drawn by the .suite-bar-edges SVG
     overlay using vector-effect: non-scaling-stroke (see chart-v2.js
     BarView.render).  CSS borders scale with `transform: scale(N)`
     and turn into sub-pixel smears at small window sizes; SVG
     non-scaling strokes rasterise at the device pixel and stay crisp. */
  border: 0;
  /* Adjacent bars no longer overlap their borders (no CSS border to
     overlap).  Their SVG edges are at the cell edges; left/right
     barlines meet exactly. */
  margin-left: 0;
  /* Bar padding stays tight to the leading barline so diagrams and the
     time-signature column sit close to the bar's left edge (engraving
     convention).  Chord-text safe-zone is applied to the FIRST chord
     cell of each bar instead — see the
     `.suite-bar-row--chord > .suite-beat-slot:first-child` rule below. */
  padding: 6px 8px 8px 2px;
  /* No hardcoded bar min-height — each visible row has its own
     min-height (diagram 64, rhythm 48, chord 36, scales 28).  When
     auxiliary rows are toggled off the bar collapses to its remaining
     content; a 96 px floor was making chord-only charts artificially
     tall. */
  min-width: 0;     /* let bar shrink below content size in grid layout */
  /* `overflow: visible` so wide chord names rendered in the chord row
     can spill past the bar's right edge.  Without this they get clipped
     at the bar boundary even though the cell itself allows overflow. */
  overflow: visible;
}

/* Each row spans the bar; each beat-slot gets proportional flex. */
.suite-bar-row { display: flex; gap: 0; }
.suite-beat-slot {
  display: flex;
  align-items: center;
  justify-content: stretch;
  min-width: 0;
  position: relative;
  /* Stretch the slot vertically to fill the row's cross-axis so its
     children (cells with `height: 100%`) actually have a sized parent
     to fill.  Without this, a row with `align-items: flex-end` keeps
     slots at their content height, and `height: 100%` on cells then
     resolves to that smaller content height — defeating the empty-cell
     "+" placeholder's uniform-Y centring. */
  align-self: stretch;
}
/* Beat slots in the rhythm row inherit bottom-alignment so sub-beats sit on
   the same baseline as the parent slot's siblings. */
.suite-beat-slot--rhythm {
  padding-top: 8px;       /* room for tuplet bracket */
  align-items: flex-end;
}

/* Sub-cells inside a beat-slot share the slot equally. */
.suite-beat-slot > .suite-beat-diagram,
.suite-beat-slot > .suite-beat-rhythm,
.suite-beat-slot > .suite-beat-chord  { flex: 1 1 0; min-width: 0; }

/* (Beat-1 anchor is enforced by JS in `BarView.renderTo` — pins the
   first SUB-CELL of the first slot to flex: 0 0 80px so beat 1's first
   audible note lands at a consistent X regardless of bar width or
   subdivision.  Doing it in JS is necessary because per-slot flex is
   set inline via `s.style.flex = widthUnits + ' 1 0'` in `_slot()`,
   which would beat any external CSS.) */

/* (No divider between sub-beats — the rhythm glyphs and chord text already
    communicate the grouping; a faint line just adds visual noise.) */

/* Tuplet bracket number above a tuplet beat-slot. */
.suite-tuplet-bracket {
  position: absolute;
  top: -2px; left: 50%; transform: translateX(-50%);
  font-size: 10px; font-weight: 700; color: var(--accent, #c85a1a);
  font-family: 'Georgia', serif; font-style: italic;
  background: var(--surface, #fffef9);
  padding: 0 4px;
  z-index: 1;
}
.suite-tuplet-num {
  font-size: 10px; color: var(--accent, #c85a1a); margin-left: 2px;
  font-style: italic; font-weight: 700;
}

/* Every row carries `position: relative` so the absolute tsig overlay
   (`.suite-bar-tsig`) anchors against the row it's mounted in.  The rhythm
   row additionally hosts the absolute SVG tie layer. */
.suite-bar-row--diagram,
.suite-bar-row--rhythm,
.suite-bar-row--chord,
.suite-bar-row--scales { position: relative; }
.suite-tie-layer { color: var(--text); }

/* RHYTHM-ROW-HIDDEN MODE — by design, the tsig falls back into the chord
   (or diagram) row.  We do NOT pad the bar, do NOT shift the diagram, do
   NOT move barlines or row separators.  Each visual concern is its own
   layer with its own positioning.

   The ONLY in-bar adjustment for an active tsig is on beat 1's chord cell
   itself: its content (the chord display + editable input) shifts right
   by `--tsig-width` so the chord text clears the digits.  Bars without
   `.has-tsig` are unaffected; bars with `.has-tsig` shift only their
   chord cell — diagram cells, scales chips, bar number, barlines, and
   the row-separator dashes all stay at the same X.  Beat-1 stacked-column
   alignment between tsig-bearing and tsig-less bars survives because the
   bar's geometric edges and beat positions don't move; only the chord
   text inside one cell does. */
.suite-bars--rhythm-hidden .suite-bar.has-tsig
  .suite-bar-row--chord > .suite-beat-slot:first-child .suite-beat-chord:first-of-type {
  /* Tsig column (22px) + a gap that survives transform-scale(0.5) — the
     read-mode "copy at natural width, scale to fit" pattern means CSS px
     visually halve at 1/2 viewport.  24px natural ⇒ ~12px at half-scale,
     comfortable; 10px would feel cramped. */
  padding-left: calc(24px + var(--tsig-width, 22px));
}

/* DIAGRAM-ROW TSIG — tsig falls here when both rhythm AND chord rows are
   hidden.  Shift the first beat's diagram cell right so the fretboard
   doesn't overlap the time-signature digits. */
.suite-bars--rhythm-hidden.suite-bars--chord-hidden .suite-bar.has-tsig
  .suite-bar-row--diagram > .suite-beat-slot:first-child .suite-beat-diagram:first-of-type {
  padding-left: calc(24px + var(--tsig-width, 22px));
}

/* SCALES-ROW TSIG — tsig falls here when rhythm, chord, AND diagram rows
   are all hidden (scales-only section).  Shift the first scale chip right. */
.suite-bars--rhythm-hidden.suite-bars--chord-hidden.suite-bars--diagram-hidden .suite-bar.has-tsig
  .suite-bar-row--scales > .suite-beat-slot:first-child .suite-beat-scales:first-of-type {
  padding-left: calc(24px + var(--tsig-width, 22px));
}

/* Hidden silent target of an auto-spilled tied note (dotted overflow). */
.suite-rhy-hidden { display: inline-block; min-width: 4px; opacity: 0; }

/* Pickup-bar spacer pushes beats to the right of the bar. */
.suite-pickup-spacer { display: inline-block; }

/* Free-time bar indicator — dashed right barline so the user sees the meter
   isn't strict. */
.suite-bar[data-bar-id]:has(.suite-bar-tsig:contains('𝄎')) { border-right-style: dashed; }
/* (Some browsers don't support :has(...:contains()); we also tag bars below.) */
.suite-bar.is-free { border-right-style: dashed; border-right-color: var(--text-2, #888); }
.suite-bar.is-pickup { border-left-style: dashed; }
/* (Right barline variants removed — barline styling is now driven
    entirely by the SVG barline overlay (_drawVerticalBarline), which
    reads bar.barlineEnd ('single' | 'double' | 'heavy' | 'final') and
    paints the appropriate stroke pattern.  The old CSS borders +
    box-shadow stack stacked ON TOP of the overlay strokes, producing
    the multi-line / extra-bottom-line artifact.) */

/* Repeat-mark layer — sits inside the bar's edge */
.suite-bar-line {
  position: absolute; top: 0; bottom: 0; width: 14px;
  display: flex; align-items: center; justify-content: center;
  pointer-events: none;
}
.suite-bar-line--left  { left: 0; }
.suite-bar-line--right { right: 0; }
.suite-bar-line .suite-mark { font-size: 36px; line-height: 1; color: var(--text); }
.suite-bar--rep-start { padding-left: 16px; }
.suite-bar--rep-end   { padding-right: 16px; }

/* ── Bar rows ────────────────────────────────────────────────────────── */
.suite-bar-row {
  display: flex; align-items: center; justify-content: space-around;
  gap: 4px; min-height: 22px;
}
/* Diagram row sits at the TOP of the bar.  Its BOTTOM has a fixed
   minimum gap above the rhythm row (= above the tsig overlay) so taller
   diagrams (6+ frets) never crowd or touch the time signature.  The row
   grows UPWARD when a diagram exceeds the default min-height — the bar
   itself is `flex-direction: column`, so a taller diagram pushes the
   bar's overall top up, while the diagram-to-rhythm gap stays constant.
   align-items: flex-end keeps shorter diagrams bottom-aligned (so all
   diagrams in a row share a baseline regardless of fret count).
   padding-top reserves room ABOVE the diagram for open-string dots ("o")
   and any other above-staff markers — without it, the diagram's top can
   sit flush against the bar's top barline. */
/* Diagram row.  Default min-height covers a typical 5-fret voicing.
   `_alignDiagramRows` runs post-paint, measures the tallest diagram
   on each LINE of bars, and writes that height to every diagram row
   in the line via inline `style.height`.  That keeps all bars on a
   line the SAME height — barlines extend the full height — and
   guarantees diagrams stay INSIDE the bar (no content escapes upward
   over the bar number).  Cells `align-items: flex-end` so smaller
   diagrams in the same line sit at the bottom. */
.suite-bar-row--diagram {
  min-height: 64px;
  padding-top: 4px;
  padding-bottom: 8px;
  align-items: flex-end;
  overflow: visible;
}
/* Rhythm row is a FIXED height so the chord row below always lands at the
   same vertical position across bars regardless of whether a bar contains
   tall note glyphs (stems + flags) or compact slashes.  Glyphs are aligned
   to the bottom of the row so noteheads / slash bottoms share one baseline. */
/* Rhythm-row height scales with the rhythm-size variable so larger
   glyphs (and their stems + beams) stay inside the row instead of
   bleeding into the diagram row above.  Default 48 px when unset. */
.suite-bar-row--rhythm  { height: var(--suite-rhythm-row-h, 48px); align-items: flex-end; opacity: 0.85; }
.suite-bar-row--chord   { min-height: 36px; padding-top: 2px; }
/* Scales row — vertical list of clickable scale chips per beat. */
.suite-bar-row--scales  { min-height: 28px; padding-top: 4px; align-items: flex-start; }

/* ── Scale cell ──────────────────────────────────────────────────── */
.suite-beat-scales {
  flex: 1 1 0; min-width: 0;
  /* Scale chips align to the LEFT of every cell — matches how chord
     text sits in the row above (left-anchored within each beat).
     Was `center`; that left mid-bar chips floating in the middle of
     the cell, visually disconnected from their chord. */
  display: flex; flex-direction: column; align-items: flex-start;
  gap: 2px; padding: 2px;
}
.suite-scale-chip {
  display: inline-block;
  font-family: 'Source Serif Pro', 'Palatino Linotype', Georgia, serif;
  font-style: italic;
  /* Chip text size driven by --suite-scale-size CSS variable (set by the
     Scale-size toolbar slider).  Default 13 px when unset. */
  font-size: var(--suite-scale-size, 13px);
  color: var(--accent, #c85a1a);
  text-decoration: none;
  padding: 1px 4px;
  border-radius: 3px;
  white-space: nowrap;
  position: relative;
  /* Re-enable hits on the chip itself (the slot container disables
     pointer events so the overflowed chip tail stays clickable —
     see the .suite-bar-row--scales rule below). */
  pointer-events: auto;
}
/* Long scale chips routinely overflow their beat-slot box (e.g. "Gb
   Melodic Minor" in a 60 px slot).  The chip element's bounding box
   extends to fit the text, but the NEXT sibling slot paints later in
   DOM order and visually overlays the overflowed tail — eating clicks
   on the second half of the chip name.  Fix: scales-row slot boxes
   become pointer-transparent so clicks fall through to whichever
   chip's hit area sits under the cursor.  Chips + the "+ add" button
   re-enable pointer events explicitly. */
.suite-bar-row--scales > .suite-beat-slot,
.suite-bar-row--scales > .suite-beat-slot > .suite-beat-scales {
  pointer-events: none;
}
.suite-scale-add { pointer-events: auto; }
.suite-scale-chip:hover { background: var(--surface-2, #f1ede4); text-decoration: underline; }
.suite-scale-chip-x {
  display: none;
  font-size: 12px; color: var(--text-3, #b8b3a3);
  margin-left: 4px; cursor: pointer;
}
.suite-scale-chip:hover .suite-scale-chip-x { display: inline; }
.suite-scale-chip-x:hover { color: var(--text); }
.suite-scale-add {
  font-size: 11px; color: var(--text-3, #b8b3a3);
  background: transparent; border: 1px dashed var(--border, #d8d4c8);
  border-radius: 3px; padding: 1px 6px;
  cursor: pointer; font-style: italic;
}
.suite-scale-add:hover { color: var(--accent, #c85a1a); border-color: var(--accent, #c85a1a); }
.suite-root--read .suite-scale-add { display: none; }
.suite-root--read .suite-scale-chip-x { display: none !important; }

/* ── Scale picker popover (two-column: keys | scales) ──────────────── */
.suite-popover--scale-picker { width: 460px; }
.suite-scale-picker-body {
  display: grid;
  grid-template-columns: 140px 1fr;
  gap: 12px;
  margin-top: 6px;
}
.suite-scale-picker-keys {
  display: flex; flex-direction: column; gap: 2px;
  max-height: 320px; overflow-y: auto;
  border-right: 1px solid var(--border, #e1ddd2);
  padding-right: 8px;
}
.suite-scale-picker-scales {
  display: flex; flex-direction: column; gap: 4px;
  min-width: 0;
}
.suite-scale-search {
  width: 100%; padding: 6px 8px;
  border: 1px solid var(--border, #d8d4c8);
  border-radius: 4px;
  font-size: 13px;
}
.suite-scale-list {
  display: flex; flex-direction: column; gap: 2px;
  max-height: 280px; overflow-y: auto;
}
.suite-scale-group-label {
  font-size: 11px; font-weight: 700; text-transform: uppercase;
  color: var(--text-2, #666); margin: 8px 0 2px; letter-spacing: 0.06em;
}
.suite-scale-key {
  text-align: left; padding: 4px 8px;
  border: 1px solid transparent; border-radius: 4px;
  background: transparent; color: var(--text);
  font-size: 13px; cursor: pointer;
}
.suite-scale-key:hover { background: var(--surface-2, #f1ede4); }
.suite-scale-key.is-on {
  background: var(--accent, #c85a1a); color: #fff;
  font-weight: 600;
}
.suite-scale-pick {
  text-align: left; padding: 4px 8px;
  border: 1px solid transparent; border-radius: 4px;
  background: transparent; color: var(--text);
  font-size: 13px; cursor: pointer;
}
.suite-scale-pick:hover { background: var(--surface-2, #f1ede4); }
.suite-scale-pick.is-on { background: var(--accent, #c85a1a); color: #fff; }
.suite-scale-pick.is-on:hover { background: var(--accent, #c85a1a); }

/* ── Scale chip hover menu ─────────────────────────────────────────── */
.suite-scale-chip-menu {
  position: absolute;
  z-index: 1000;
  display: flex; flex-direction: column;
  background: var(--surface, #fff);
  border: 1px solid var(--border, #d8d4c8);
  border-radius: 6px;
  box-shadow: 0 4px 14px rgba(0,0,0,0.12);
  padding: 4px;
  min-width: 140px;
}
.suite-scale-chip-menu-btn {
  text-align: left; padding: 6px 10px;
  border: 0; background: transparent;
  font-size: 13px; color: var(--text);
  cursor: pointer; border-radius: 4px;
}
.suite-scale-chip-menu-btn:hover {
  background: var(--surface-2, #f1ede4);
  color: var(--accent, #c85a1a);
}

/* (Inspect overlay styles moved to assets/css/fretly-inspector.css —
   the inspector is now an app-wide module, not chart-v2-specific.) */

/* (Chord display rule lives further down at line ~1130 alongside the
   other .suite-chord-input-wrap CSS — keep them together.  No additional
   .suite-chord-display block here to avoid an override-collision: the
   later rule would silently win and break pointer-events.) */

/* ── Chord cell click menu (read mode) ─────────────────────────────── */
/* Same styling family as `.suite-scale-chip-menu` so the two affordances
   feel like one system.  Anchored above the chord display, centered on
   its midline (positioned in JS via `transform: translate(-50%, -100%)`). */
.suite-chord-cell-menu {
  position: absolute;
  z-index: 1000;
  display: flex; flex-direction: column;
  background: var(--surface, #fff);
  border: 1px solid var(--border, #d8d4c8);
  border-radius: 6px;
  box-shadow: 0 4px 14px rgba(0,0,0,0.12);
  padding: 4px;
  min-width: 160px;
}
.suite-chord-cell-menu-btn {
  text-align: left; padding: 6px 10px;
  border: 0; background: transparent;
  font-size: 13px; color: var(--text);
  cursor: pointer; border-radius: 4px;
}
.suite-chord-cell-menu-btn:hover {
  background: var(--surface-2, #f1ede4);
  color: var(--accent, #c85a1a);
}

/* ── Beat — diagram cell (top row) ───────────────────────────────────── */
/* `height: auto` so the cell grows with its SVG (taller frets / fingering).
   `min-height: 60px` keeps an empty cell tall enough to read as a slot.
   `align-items: flex-end` pins the SVG to the BOTTOM of the cell so all
   diagrams share a baseline above the rhythm row regardless of natural
   height — engraving convention. */
.suite-beat-diagram {
  flex: 1 1 0; min-width: 0;
  display: flex; align-items: flex-end; justify-content: center;
  /* `align-self: stretch` overrides the parent row's `align-items:
     flex-end` for THIS item, forcing the cell to fill the row's full
     cross-axis (vertical) height.  Without this, `align-items: flex-end`
     on the row keeps cells at their content height — different cells
     end up different heights, and the "+" placeholder's absolute-50%
     centring lands at a different Y per cell.  With stretch + 100%, all
     cells share row height → all "+" placements share Y.  The cell's
     OWN `align-items: flex-end` keeps SVG diagrams pinned to the cell
     bottom (engraving convention). */
  align-self: stretch;
  height: 100%; min-height: 60px; padding: 2px;
  position: relative;          /* anchor for absolute children (the "+" placeholder) */
  border-radius: 4px; cursor: pointer;
  transition: background 0.12s;
}
/* Ensure the SVG never escapes its cell vertically — `overflow: visible`
   on the SVG tag is needed for engraving conventions (×/○ above the nut)
   but the cell itself clips so the row separator below stays clean. */
.suite-beat-diagram > svg.suite-mini-diag { display: block; }
/* First diagram cell of a bar: extra LEFT padding to keep the fret-
   position label (e.g. "11" for an 11th-fret voicing) clear of the
   barline.  Increased from 10 → 18 so the gap survives uniform
   transform-scale at narrow viewports — at 50 % scale, 18 px reads as
   9 px visually, still a comfortable margin; at 100 % the diagram
   sits with a generous left buffer.  Lower values look tight at scale. */
/* First diagram cell gets extra left padding to clear the SVG's fret-
   position label, which renders to the LEFT of the grid (and `overflow:
   visible` lets it spill past the SVG's box).  At higher positions the
   label is two digits ("10", "11", "12"…), needing more headroom — 28 px
   keeps even those clear of the leading barline at any scale. */
.suite-bar-row--diagram > .suite-beat-slot:first-of-type > .suite-beat-diagram {
  padding-left: 28px;
}
.suite-beat-diagram:hover { background: var(--surface-2, #f1ede4); }
.suite-beat-diagram.has-voicing { background: transparent; }
/* Drop-target visual states for diagram drag-and-drop.  Set on every
   cell that's a valid landing spot when a drag starts (cells whose
   rhythm cell holds an audible note); removed on dragend.  The dragged
   diagram cell itself gets `is-drag-source` so we can dim it. */
.suite-beat-diagram.is-drop-target {
  background: var(--accent-bg, #fff3e6);
  outline: 2px dashed var(--accent, #c85a1a);
  outline-offset: -2px;
  border-radius: 6px;
  cursor: copy;
  transition: background 0.1s, outline-color 0.1s;
}
/* Stronger highlight when the dragged diagram is currently HOVERED over
   a valid target — shows EXACTLY where the diagram will land on drop. */
.suite-beat-diagram.is-drop-target.is-drop-hover {
  background: var(--accent, #c85a1a);
  outline-color: var(--accent, #c85a1a);
}
.suite-beat-diagram.is-drop-target.is-drop-hover .suite-beat-diagram-empty {
  color: #fff;
  font-weight: 700;
}
.suite-beat-diagram.is-drag-source { opacity: 0.4; }
.suite-beat-diagram-empty {
  font-size: 22px; color: var(--text-3, #b8b3a3); font-weight: 300;
  /* Centered vertically in the row — uniform "middle-ish" Y across
     every empty diagram cell, no matter how tall the row is for the
     line.  Achieved by absolute positioning anchored to the cell's
     vertical center (cells are `position: relative` already).  This is
     immune to cell-height variation: as long as the cell fills the
     row's full height (which it does — `align-items: flex-end` on the
     row pins the cell bottom; row height is uniform per line via
     _alignDiagramRows), the placeholder lands at the same Y. */
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  pointer-events: none;
}
/* Secondary affordance on an EMPTY diagram cell: small ✎ button (top-
   right) that opens the diagram editor.  The PRIMARY click on the empty
   cell is chord-NAME entry, so the pencil is intentionally discreet —
   revealed on cell hover, but with a real hit target (min 22 px). */
.suite-beat-diagram-editbtn {
  position: absolute;
  top: var(--space-2xs, 2px);
  right: var(--space-2xs, 2px);
  min-width: 22px; min-height: 22px;
  padding: 0 var(--space-2xs, 2px);
  border: var(--border-w, 1px) solid transparent;
  border-radius: var(--radius-sm, 4px);
  background: transparent;
  color: var(--text-3, #b8b3a3);
  font-size: var(--font-sm, 13px);
  line-height: 1;
  cursor: pointer;
  opacity: 0;
  transition: opacity 0.12s, background 0.12s, color 0.12s;
}
.suite-beat-diagram:hover .suite-beat-diagram-editbtn,
.suite-beat-diagram-editbtn:focus-visible {
  opacity: 1;
}
.suite-beat-diagram-editbtn:hover {
  background: var(--surface, #fff);
  border-color: var(--border, #e1ddd2);
  color: var(--accent, #c85a1a);
}
.suite-root--read .suite-beat-diagram-editbtn { display: none; }
.suite-mini-diag-fallback { font-size: 32px; color: var(--text-3, #b8b3a3); }

/* ── Beat — rhythm cell (middle row) ─────────────────────────────────── */
/* Glyph CENTERED in the cell by default (slash-style chord comping).  Beam
   math in chart-v2.js measures the actual notehead bbox now, so changing
   this alignment doesn't break beam landing. */
.suite-beat-rhythm {
  flex: 1 1 0; min-width: 0;
  display: flex; align-items: flex-end; justify-content: center;
  /* Glyph size driven by --suite-rhythm-size CSS variable (set by the
     Rhythm-size toolbar slider).  Default 28 px when unset. */
  font-size: var(--suite-rhythm-size, 28px);
  line-height: 1; color: var(--text);
  cursor: pointer; border-radius: 4px;
  transition: background 0.12s, box-shadow 0.12s;
  /* Reserve enough vertical room for the tallest glyph (stem + flag).
     Inner glyph spans hang at the bottom of this box so baselines match. */
  height: 100%;
  padding-bottom: 2px;
  box-sizing: border-box;
}
/* (Removed: first-cell flex-start rules.  See CENTERING PRINCIPLE below.)
   The diagram, notehead, and chord text in each cell are now uniformly
   CENTERED.  Engraving convention here is "vertical alignment of all
   three rows on the beat's centre", not "anchor to the barline".  When
   a chord name is wider than its cell, it spills to BOTH sides equally
   so the visual midpoint stays under the note. */
.suite-beat-rhythm:hover {
  background: var(--surface-2, #f1ede4);
  box-shadow: inset 0 0 0 1px var(--border, #d8d4c8);
}
/* Whole-bar rhythm cell — when a bar contains a SINGLE rhythm
   cell (one slash / one note covering the entire bar), left-align
   the glyph to the bar's leading edge instead of centring it.
   Same offset as the chord text below.  Per user 2026-05-13.
   `.suite-bar.is-whole-bar` is set in bar-view.js when the bar
   has exactly one beat and no sub-beats — independent of the
   beat's `noteValue` field, so it covers whole / dot-half + rest /
   etc.  Also accepts the legacy `.suite-beat-rhythm.is-whole-bar`
   class set by cell-renderers.js for noteValue='whole'. */
.suite-bar.is-whole-bar .suite-beat-rhythm,
.suite-beat-rhythm.is-whole-bar {
  justify-content: flex-start;
  padding-left: var(--suite-leading-inset, 6px);
}
/* Transient highlight: ONLY while the rhythm-editor popover is open on this cell. */
.suite-beat-rhythm.is-editing {
  background: var(--accent-bg, #fff3e6);
  box-shadow: inset 0 0 0 1px var(--accent, #c85a1a);
}
.suite-beat-rhythm .suite-slash { font-size: 32px; }
/* Augmentation dot uses the parent's font-size — at the same size as the
   note, SMuFL's own glyph metrics place it correctly relative to the
   notehead.  A small left margin keeps it from kissing the notehead. */
.suite-aug-dot { margin-left: 2px; }
/* PHASE 1 LAYERS: beamed-cell glyphs are now rendered as SVG <text> inside
   the beam-layer SVG, so HTML font glyphs in beamed cells are hidden via
   `visibility: hidden` (which preserves layout — the cell still has the
   right intrinsic width — but suppresses the HTML rendering so we don't
   get a doubled glyph).  Non-beamed cells keep their HTML font glyph. */
.suite-beat-rhythm.is-beamed .suite-smufl-wrap { visibility: hidden; }
/* Inline-block wrapper for note (+ optional dot) so the two glyphs share
   one line box with the SMuFL font's natural baseline.  Without this they
   become separate flex items and bottom-align by line-box, dropping the
   dot below the notehead. */
.suite-smufl-wrap {
  display: inline-block;
  line-height: 1;
  white-space: nowrap;
}

/* ── Beat — chord cell (bottom row) ──────────────────────────────────── */
/* CENTERED to match the notehead above and the chord-diagram in the row
   above that — the user's "centering principle" (see top of file).  When
   the chord name is wider than its cell it spills equally to BOTH sides
   so the visual midpoint stays directly under the note.
   Combined with `field-sizing: content` on .suite-chord-input below, the
   chord text overflows the cell and the bar without being clipped.
   Future: a per-chart toggle for clip-vs-spill. */
.suite-beat-chord {
  flex: 1 1 0; min-width: 0;
  position: relative;
  display: flex; align-items: center; justify-content: center;
  overflow: visible;
  white-space: nowrap;
  /* Internal horizontal breathing room.  Generic 4 px helps middle
     cells too; the FIRST and LAST chord cells of each bar get extra
     padding (rules below) to absorb spillover from wide chord names
     and keep that text from crashing into the barlines. */
  padding: 0 4px;
}
/* Safe zones at the first / last chord cell of every bar — only the
   chord ROW gets extra padding so diagrams + rhythm + time-sig stay
   tight to the leading barline. */
.suite-bar-row--chord > .suite-beat-slot:first-child .suite-beat-chord:first-of-type,
.suite-bar-row--scales > .suite-beat-slot:first-child .suite-beat-scales:first-of-type {
  padding-left: 10px;
}
.suite-bar-row--chord > .suite-beat-slot:last-child .suite-beat-chord:last-of-type,
.suite-bar-row--scales > .suite-beat-slot:last-child .suite-beat-scales:last-of-type {
  padding-right: 10px;
}
/* Scale chips have their own 4 px horizontal padding (so the hover
   background reads as a chip).  In the first cell of a bar that
   padding pushes the chip TEXT inward, misaligning it with the chord
   text in the cell above (which has no chip-padding equivalent).
   Cancel with a small negative left-margin on the very first chip in
   the leading cell, so its visible text starts at the same X as the
   chord name above.  All OTHER cells use the cell's natural left
   padding (no negative margin) so chips sit at the cell's left edge. */
.suite-bar-row--scales > .suite-beat-slot:first-child .suite-beat-scales:first-of-type > .suite-scale-chip:first-child {
  margin-left: -6px;
}
.suite-beat-overlay {
  position: absolute; top: -14px; left: 0; right: 0;
  text-align: center;
  font-size: 16px; line-height: 1; color: var(--text-2, #555);
  pointer-events: none;
}
.suite-mark-diamond { color: #2266aa; }
.suite-mark-ghost   { color: #999; font-family: 'Georgia', serif; }
.suite-mark-push    { color: #cc6600; font-weight: 700; }

/* ── Chord input (Option 3 — display span + editable input) ─────────── */
/* The wrap holds two stacked elements:
     • `.suite-chord-display` — a non-interactive label, centered on the
       cell's centerline via `position: absolute; left: 50%;
       transform: translateX(-50%)`.  Free to overflow both directions
       (including under the time-sig spacer) — pointer-events: none, so
       it never steals clicks from the input below.
     • `.suite-chord-input` — the editable surface, kept at full cell
       width for click target.  Its TEXT is rendered transparent when
       the wrap doesn't have `.is-editing`, so the span and input never
       visually compete; on focus the wrap toggles `.is-editing` and
       the input becomes opaque while the span hides.
   Failsafe: if the display span fails to render, the input still
   shows the chord (just clipped at cell edges as before). */
.suite-chord-input-wrap {
  flex: 1 1 0; min-width: 0;
  position: relative;
  overflow: visible;
  /* Reserve at least the input's height so the absolute-positioned span
     doesn't collapse the wrap to 0 and break vertical centering. */
  min-height: 1.6em;
  display: flex;
  align-items: center;
}
.suite-chord-display {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  white-space: nowrap;
  /* `pointer-events: auto` so the JS-attached hover-menu / click handlers
     fire on the chord text.  Click routing (read → Inspect, edit → focus
     input) is done in JS — see _attachChordDisplayMenu in chart-v2.js. */
  pointer-events: auto;
  cursor: pointer;
  font-family: 'Georgia', 'Times New Roman', serif;
  font-weight: 700;
  color: var(--text);
  z-index: 2;
  /* font-size set inline by JS to match input — keeps both at the
     same metric so there's no visual jump on focus/blur. */
}
/* (chord-text-under-tsig leftward shift was attempted here; reverted —
   needs a different design pass.  See CLAUDE.md TODO.) */
/* While editing: span hides, input shows its own text. */
.suite-chord-input-wrap.is-editing .suite-chord-display { visibility: hidden; }
/* While NOT editing: input text is transparent (caret too) so the user
   sees only the display span.  The input still receives focus + clicks. */
.suite-chord-input-wrap:not(.is-editing) .suite-chord-input {
  color: transparent;
  caret-color: transparent;
}
/* Read mode: hide the editable input entirely; only the display span
   renders.  Existing chrome-hiding rules already disable the input's
   focus path indirectly, this just removes the empty box. */
.suite-root--read .suite-chord-input { visibility: hidden; }
.suite-chord-input {
  /* `field-sizing: content` makes the input grow to fit its value (so
     "Csus4add2" no longer scrolls inside a fixed-width box).  min-width
     keeps the input at least as wide as the cell so short names still
     fill the slot.  Browsers without field-sizing fall back to width:100%
     and the old clipping behaviour — graceful degradation. */
  width: 100%;
  min-width: 100%;
  field-sizing: content;
  box-sizing: border-box;
  padding: 4px 2px;
  border: none; border-bottom: 1px solid transparent;
  background: transparent; outline: none;
  font-family: 'Georgia', 'Times New Roman', serif;
  font-weight: 700;
  color: var(--text);
  text-align: center;
  transition: border-color 0.12s, background 0.12s;
}
.suite-chord-input:focus {
  border-bottom-color: var(--accent, #c85a1a);
  background: var(--accent-bg, #fff3e6);
}
.suite-chord-input.suite-chord-invalid { color: #c0392b; }

/* ── Autocomplete popup ──────────────────────────────────────────────── */
.suite-chord-popup {
  position: absolute;
  background: var(--surface, #fff);
  border: 1px solid var(--border, #d8d4c8);
  border-radius: 6px;
  max-height: 240px; overflow-y: auto;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
  z-index: 9999;
  min-width: 200px;
}
.suite-chord-suggest {
  display: flex; justify-content: space-between; align-items: center;
  padding: 8px 12px;
  font-family: 'Georgia', serif;
  cursor: pointer;
  border-bottom: 1px solid var(--border, #ebe7da);
}
.suite-chord-suggest:last-child { border-bottom: none; }
.suite-chord-suggest:hover, .suite-chord-suggest.is-active {
  background: var(--accent-bg, #fff3e6);
}
.suite-chord-suggest-name { font-size: 16px; font-weight: 700; color: var(--text); }
.suite-chord-suggest-label { font-size: 11px; color: var(--text-2, #888); margin-left: 12px; }

/* ── Bar number (chart-wide index, centred above the leading barline) ─ */
.suite-bar-num {
  position: absolute;
  top: -16px;
  left: 0;
  transform: translateX(-50%);
  padding: 0 4px;
  font-size: 11px;
  line-height: 1;
  color: var(--text-3, #a8a39a);
  font-family: 'Georgia', serif;
  font-style: italic;
  user-select: none;
  white-space: nowrap;
}
/* (Previously: the leftmost bar's number was inset a few px to keep the
    digits "inside the row".  Removed — engraving convention puts the
    number directly above its leading barline, and `.suite-bars` /
    `.suite-section` have overflow:visible so a digit extending a few px
    into the gutter is fine.) */

/* ── Bar selection (Phase C2, FEATURE_BAR_SELECTION — plan §7) ─────── */
/* The handle strip is the bar-number zone above each bar: the selection
   hit area.  z-index 1 keeps the gear / line-break / number (z 2)
   clickable on top of it.  Hover pre-outlines the whole bar (CSS :has —
   no JS).  Read mode never shows it. */
.suite-bar-handle {
  position: absolute;
  top: -16px; left: 0; right: 0;
  height: 16px;
  z-index: 1;
  cursor: pointer;
  border-radius: 3px;
}
.suite-bar-handle:hover { background: rgba(200, 90, 26, 0.12); }
.suite-bar:has(> .suite-bar-handle:hover) {
  outline: 1px dashed var(--accent, #c85a1a);
  outline-offset: 2px;
  border-radius: 2px;
}
.suite-bar.is-selected {
  outline: 2px solid var(--accent, #c85a1a);
  outline-offset: 2px;
  border-radius: 2px;
  background: rgba(200, 90, 26, 0.06);
}
.suite-root--read .suite-bar-handle { display: none; }

/* Chart-tab view pills (toolbar controls re-homed) */
.suite-sidepanel-viewpill { font-size: 11px; padding: 4px 9px; min-width: 0; }

/* Export menu — flat, no native chrome */
.suite-export-menu { display: flex; flex-direction: column; gap: 2px;
  padding: 6px; min-width: 220px; }
.suite-export-item { border: none; background: transparent; text-align: left;
  font-size: 13px; padding: 7px 10px; border-radius: var(--radius-sm, 6px);
  cursor: pointer; color: var(--text, #333); }
.suite-export-item:hover { background: var(--surface-2, #f4f1ea); }

/* Zoom menu (chartbar) — reuses the export-menu chrome */
.suite-zoom-menu { min-width: 160px; max-height: 70vh; overflow-y: auto; }
.suite-export-item.is-current { font-weight: 600; }

/* Fixed zoom > 100% is the ONLY state where horizontal overflow of the
   sheet is legitimate — scroll instead of clipping. */
.suite-zoom-overflow .suite-paper,
.suite-zoom-overflow .suite-root { overflow-x: auto; }

/* ── Repeat structure (§11.2) — engraved bar chrome ─────────────────
   Rendered in BOTH edit and read modes (it's notation, not edit UI).
   Sits above the bar-number strip so handles stay clickable. */
.suite-repeat-count {
  position: absolute;
  right: 2px; top: -16px;
  font-family: 'Georgia', serif;
  font-style: italic;
  font-weight: 700;
  font-size: 12px;
  color: var(--text, #333);
  white-space: nowrap;
  z-index: 2;
  pointer-events: none;
}
.suite-volta {
  position: absolute;
  left: 0; right: 35%; top: -32px;
  height: 14px;
  border-top: 1.5px solid var(--text, #333);
  border-left: 1.5px solid var(--text, #333);
  font-family: 'Georgia', serif;
  font-size: 11px;
  font-weight: 700;
  padding: 0 0 0 5px;
  line-height: 14px;
  z-index: 2;
  pointer-events: none;
}
.suite-navmark {
  position: absolute;
  right: 0; top: -32px;
  font-family: 'Georgia', serif;
  font-style: italic;
  font-weight: 700;
  font-size: 12px;
  white-space: nowrap;
  z-index: 2;
  pointer-events: none;
}
.suite-navmark .suite-smufl { font-size: 18px; font-style: normal; }

/* Flat number input (sidebar) — no native spinner chrome */
.suite-sidepanel-ctl input[type="number"],
.suite-sidepanel-num {
  border: 1px solid var(--border, #e3e3e3);
  background: var(--surface, #fff);
  border-radius: var(--radius-sm, 6px);
  font-size: var(--font-xs, 11px);
  padding: 4px 8px;
  width: 64px;
  color: var(--text, #333);
  -moz-appearance: textfield;
  appearance: textfield;
}
.suite-sidepanel-ctl input[type="number"]::-webkit-outer-spin-button,
.suite-sidepanel-ctl input[type="number"]::-webkit-inner-spin-button {
  -webkit-appearance: none; margin: 0;
}
.suite-sidepanel-ctl input[type="number"]:focus,
.suite-sidepanel-pickbtn:focus {
  outline: none;
  border-color: var(--accent, #c85a1a);
}

/* NNS marks (1Chart study) — push above the chord, walk arrows after */
.suite-mark-push .suite-smufl { font-size: 0.75em; }
.suite-mark-push { color: var(--accent, #c85a1a); margin-left: 2px; }
.suite-mark-walk { font-weight: 700; margin-left: 2px; }

/* NNS inspector tab */
.suite-nns-row { display: flex; flex-direction: column; gap: 4px;
  padding: 6px 0; border-bottom: 1px solid var(--border, #eee); }
.suite-nns-chord { font-size: var(--font-xs, 11px); font-weight: 600;
  font-variant-numeric: tabular-nums; }
.suite-nns-pill { min-width: 34px; padding: 3px 8px; font-size: 13px; }

/* Rhythm caret (FEATURE_RHYTHM_CARET) — the active edit position */
.suite-beat-rhythm.is-caret {
  outline: 2px solid var(--accent, #c85a1a);
  outline-offset: 1px;
  border-radius: 3px;
  background: rgba(200, 90, 26, 0.10);
}

/* Vector note fallback (Phase F, FEATURE_VECTOR_FLAGS) — em-scaled so
   it sits on the same baseline + stem height (1.107em ratio) the LOCKED
   beam formula expects. */
.suite-vector-note {
  height: 1.30em;
  width: auto;
  vertical-align: -0.18em;
  display: inline-block;
}
.suite-smufl-wrap--vector { line-height: 1; }

/* Tool palette (Phase E) — armed tool paints rhythm cells.
   Optical centering (owner 2026-06-11): SMuFL note ink rises ABOVE the
   baseline, so flex-centering the line box leaves stemmed glyphs
   looking high-left.  Fixed button box + a downward shift on stemmed
   glyphs centres the INK, not the line box. */
.suite-tool-btn {
  width: 40px; height: 44px; min-width: 40px;
  display: inline-flex; align-items: center; justify-content: center;
  padding: 0;
}
/* UNIFORM baseline shift (owner 2026-06-11: whole note must align with
   the other notes) — every glyph shares one notehead baseline, GP-style,
   instead of per-button centering. */
.suite-tool-btn .suite-smufl,
.suite-pos-btn .suite-smufl { font-size: 20px; line-height: 1; display: block;
  transform: translateY(0.34em); }
/* `.is-current` = the CARET's state mirrored on the palette (subtle
   fill); `.is-on` (stronger, existing) = the ARMED tool. */
.suite-tool-btn.is-current {
  border-color: var(--accent, #c85a1a);
  background: rgba(200, 90, 26, 0.08);
}
.suite-tool-armed .suite-beat-rhythm { cursor: crosshair; }
.suite-tool-armed .suite-beat-rhythm:hover {
  outline: 1px dashed var(--accent, #c85a1a);
  outline-offset: 1px;
}

/* §13 DP-A — Move tool armed: movable objects get a move cursor + faint
   outline so the drag affordance is discoverable (spec: "hovering a
   movable object shows a move cursor + faint outline"). */
.suite-move-armed .suite-beat-rhythm,
.suite-move-armed .suite-rhy-glyph { cursor: move; }
.suite-move-armed .suite-chord-input-wrap { cursor: move; }
.suite-move-armed .suite-beat-diagram.has-voicing,
.suite-move-armed .suite-beat-scales[data-beat] { cursor: move; }
.suite-move-armed .suite-bar-tsig,
.suite-move-armed .suite-bar-num,
.suite-move-armed .suite-section-head { cursor: move; }
.suite-move-armed .suite-rhy-glyph:hover,
.suite-move-armed .suite-chord-input-wrap:hover,
.suite-move-armed .suite-beat-diagram.has-voicing:hover,
.suite-move-armed .suite-beat-scales[data-beat]:hover,
.suite-move-armed .suite-bar-tsig:hover,
.suite-move-armed .suite-bar-num:hover,
.suite-move-armed .suite-section-head:hover {
  outline: 1px dashed var(--accent, #c85a1a);
  outline-offset: 2px;
}
/* While Move is armed, the chord input must not look text-editable. */
.suite-move-armed .suite-chord-input { pointer-events: none; }

/* Selection-tab sub-tabs (Bar | Rhythm) + embedded rhythm editor */
.suite-sidepanel-tabs--sub { margin-top: var(--space-xs, 6px); border-bottom: none;
  padding-bottom: 0; }
.suite-sidepanel-subbody { display: flex; flex-direction: column;
  gap: var(--space-sm, 10px); }
.suite-sidepanel-stepgrp { display: flex; align-items: center; gap: 4px; }
.suite-sidepanel-stepval { font-size: var(--font-xs, 11px); min-width: 44px;
  text-align: center; font-variant-numeric: tabular-nums; }
.suite-sidepanel-ctl--stack { flex-direction: column; align-items: stretch;
  gap: 4px; }
.suite-sidepanel-rhybody { display: flex; flex-direction: column;
  gap: var(--space-sm, 10px); }
.suite-sidepanel-rhybody .suite-popover-head { margin: 0; }
.suite-sidepanel-rhybody .suite-rhy-grid { flex-wrap: wrap; }

/* Selection-tab chrome (Inspector right panel) */
.suite-sidepanel-selcount { font-size: 11px; font-weight: 700;
  color: var(--accent, #c85a1a); margin-bottom: var(--space-xs, 6px); }
.suite-sidepanel-ctl select { max-width: 130px; }

/* Popover pill picker (replaces native dropdowns — owner 2026-06-11) */
.suite-sidepanel-pickbtn {
  border: 1px solid var(--border, #e3e3e3);
  background: var(--surface, #fff);
  border-radius: var(--radius-sm, 6px);
  font-size: var(--font-xs, 11px);
  padding: 4px 10px;
  cursor: pointer;
  max-width: 140px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--text, #333);
}
.suite-sidepanel-pickbtn:hover {
  background: var(--surface-2, #f4f1ea);
  border-color: var(--border-strong, #c4bfb0);
}
.suite-optpop {
  max-width: 340px;
  padding: 10px 12px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.suite-optpop-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.suite-optpop-btn {
  min-width: 44px;
  padding: 5px 10px;
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  border-radius: var(--radius-sm, 6px);
}
.suite-sidepanel-actions { display: flex; flex-wrap: wrap; gap: 6px;
  margin-top: var(--space-sm, 10px); }
.suite-sidepanel-actions .suite-sidepanel-action { width: auto; margin-top: 0;
  padding: 3px 10px; }
.suite-sidepanel-action--danger { color: var(--danger, #b3261e); }

/* ── Per-bar tempo marking ("♩ = N") on the bar-number row ─────────── */
/* Sits to the RIGHT of .suite-bar-num, on the same horizontal strip.  Same
   colour as the bar number so the cluster reads as one piece of meta. */
.suite-bar-tempo {
  position: absolute;
  top: -18px;
  left: 14px;
  display: inline-flex; align-items: baseline; gap: 2px;
  font-size: 12px; line-height: 1;
  color: var(--text, #1a1a18);
  font-family: 'Georgia', serif;
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
  user-select: none;
}
.suite-bar-tempo .suite-bar-tempo-glyph { font-size: 16px; line-height: 1; }
.suite-bar-tempo:hover { color: var(--accent, #c85a1a); }
.suite-root--read .suite-bar-tempo { cursor: default; color: var(--text); }
.suite-root--read .suite-bar-tempo:hover { color: var(--text); }

/* ── Drag handle on right edge ──────────────────────────────────────── */
.suite-bar-resize {
  position: absolute;
  top: 0; right: -3px; bottom: 0;
  width: 6px;
  cursor: col-resize;
  z-index: 5;
  transition: background 0.12s;
}
.suite-bar-resize:hover { background: var(--accent, #c85a1a); opacity: 0.4; }
/* Read mode: bar numbers stay visible (the user reads bar refs in
   performance), but the editing chrome — drag handles, side rail,
   line-break / stretch toggles — is hidden. */
.suite-root--read .suite-bar-resize { display: none; }

/* ── Per-row stretch side-rail ───────────────────────────────────────── */
/* Vertical menu attached to the LEFT of each `.suite-bars` (in the
   section's gutter).  One small button per row, positioned absolutely
   at the row's mid-height by `_placeRowSideControls`. */
.suite-row-rail {
  position: absolute;
  top: 0; bottom: 0;
  left: -28px;        /* default: in the grey gutter outside .suite-root */
  width: 24px;
  pointer-events: none;
}
/* Narrow viewports: .suite-root has no left margin, so left:-28px would
   push the rail off-screen.  Tuck it inside the chart's left padding
   instead — still visible, just adjacent to the bars rather than in
   the page gutter. */
@media (max-width: 1320px) {
  .suite-row-rail { left: 0; }
}
.suite-row-stretch {
  position: absolute;
  left: 0;
  width: 22px; height: 22px;
  padding: 0;
  border: 1px solid var(--border, #d8d4c8);
  background: var(--surface, #fff);
  color: var(--text);
  border-radius: 4px;
  cursor: pointer;
  pointer-events: auto;
  font-size: 13px; line-height: 1;
  display: flex; align-items: center; justify-content: center;
}
.suite-row-stretch:hover { background: var(--surface-2, #f1ede4); }
.suite-row-stretch.is-on {
  background: var(--accent-bg, #fff3e6);
  color: var(--accent, #c85a1a);
  border-color: var(--accent, #c85a1a);
}
/* Read-only chart (standalone or embedded in Collections) — strip every
   edit-only chrome.  Hide both the row-stretch rail and the individual
   buttons in case any code path attaches buttons outside a rail wrapper. */
.suite-root--read .suite-row-rail,
.suite-root--read .suite-row-stretch,
.suite-root--read .suite-bar-linebreak { display: none !important; }

/* ── Per-glyph horizontal nudge (resize-mode only) ───────────────────── */
/* Each rhythm cell wraps its glyph in `.suite-rhy-glyph`.  In resize mode the
   user can grab the glyph and drag horizontally to nudge that single note
   within its cell, leaving every other note's position untouched.  The
   offset is stored as `target.glyphOffset` (px) in the chart data and
   re-applied as a CSS translateX on every render. */
.suite-rhy-glyph {
  display: inline-block;
  line-height: 1;
  white-space: nowrap;
}
body.suite-resize-mode .suite-rhy-glyph {
  cursor: ew-resize;
}
body.suite-resize-mode .suite-rhy-glyph:hover {
  background: rgba(200, 90, 26, 0.12);
  border-radius: 3px;
}
.suite-root--read .suite-rhy-glyph { cursor: inherit; }

/* (Deprecated cell-width resize handles removed.  Resize mode now uses
    per-glyph drag — see `.suite-rhy-glyph` rules above.) */
.suite-rhy-cell { position: relative; }

/* ── Bar gear button (settings popover trigger) ─────────────────────── */
.suite-bar-gear {
  /* Sits just below the top barline.  See .suite-bar-linebreak comment
     above for the geometry (bar padding-top: 6 + 2 px breathing
     strip = top: 8). */
  position: absolute; top: 8px; right: 2px;
  width: 26px; height: 26px;
  padding: 0; border: none;
  background: transparent;
  font-size: 16px; line-height: 1; opacity: 0.3;
  cursor: pointer; color: var(--text);
}
.suite-bar:hover .suite-bar-gear { opacity: 0.7; }
.suite-bar-gear:hover { opacity: 1; }

/* ── Bar line-break toggle ──────────────────────────────────────────── */
/* Top-left corner button — click to start a new line at this bar.
   Faded by default; brightens on hover; ACCENT color when active so the
   forced break is visible at a glance even when not hovering. */
.suite-bar-linebreak {
  /* Sits just below the top barline.  The bar has padding-top: 6px
     (see .suite-bar) and no CSS border; the barline overlay paints
     at row.top = bar.top + 6.  `top: 8px` puts the linebreak icon
     2 px below the barline so its full 18 px footprint reads as
     INSIDE the bar (user feedback 2026-05-12). */
  position: absolute; top: 8px; left: 2px;
  width: 18px; height: 18px;
  padding: 0; border: none;
  background: transparent;
  font-size: 13px; line-height: 1; opacity: 0.25;
  cursor: pointer; color: var(--text);
  border-radius: 3px;
}
.suite-bar:hover .suite-bar-linebreak { opacity: 0.7; }
.suite-bar-linebreak:hover { opacity: 1; background: var(--surface-2, #f1ede4); }
.suite-bar-linebreak.is-on {
  opacity: 1;
  color: var(--accent, #c85a1a);
  background: var(--accent-bg, #fff3e6);
}
.suite-root--read .suite-bar-linebreak { display: none; }

/* ── Bar context popover ─────────────────────────────────────────────── */
.suite-popover {
  position: absolute; z-index: 9998;
  background: var(--surface, #fff);
  border: 1px solid var(--border, #d8d4c8);
  border-radius: 8px;
  padding: 10px 12px;
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.18);
  display: flex; flex-direction: column; gap: 8px;
  min-width: 200px;
}
.suite-popover-chk { font-size: 13px; display: flex; align-items: center; gap: 6px; cursor: pointer; }

/* Bar-settings popover: wide, short, draggable.  Two-column grid keeps
   the form compact horizontally while the drag-handle header lets the
   user move it out of the way.  The base .suite-popover provides the
   surface (background, border, shadow); we override layout only. */
.suite-popover--bar {
  min-width: 540px;
  max-width: 640px;
  padding: 12px 14px 14px;
  display: grid;
  grid-template-columns: 1fr 1fr;
  column-gap: 20px;
  row-gap: 10px;
}
/* Drag handle spans both columns at the top of the grid. */
.suite-popover--bar .suite-popover-drag {
  grid-column: 1 / -1;
  margin: -8px -10px 6px;
  padding: 6px 10px;
  font-size: 11px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-3, #888);
  background: var(--surface-2, #f5f1e6);
  border-bottom: 1px solid var(--border, #d8d4c8);
  border-top-left-radius: 8px;
  border-top-right-radius: 8px;
  cursor: grab;
  user-select: none;
}
.suite-popover--bar .suite-popover-drag:active { cursor: grabbing; }
/* Bottom action buttons in a 3-col sub-grid (Duplicate / Insert / Repair /
   Clear / Delete).  The wrapper spans both main columns; buttons fill evenly. */
.suite-popover--bar > button { grid-column: 1 / -1; }   /* fallback for lone buttons */
.suite-bar-action-row {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 6px;
}
.suite-bar-action-row button { width: 100%; }

/* Rhythm-editor popover (richer layout than the bar-settings popover).
   Wider, shorter — sections flow into a 2-column grid so DISPLAY+SUBDIVIDE
   share row 1, TUPLET+NOTE-VALUE share row 2, etc.  Head + foot span the
   full grid via grid-column: 1 / -1.  Switching this from `display: flex
   column` (inherited from .suite-popover) to `display: grid` is the only
   override needed — section markup is unchanged. */
.suite-popover--rhythm {
  min-width: 580px;
  max-width: 720px;
  padding: 14px 16px;
  display: grid;
  grid-template-columns: 1fr 1fr;
  column-gap: 24px;
  row-gap: 12px;
}
.suite-popover--rhythm .suite-popover-head,
.suite-popover--rhythm .suite-popover-foot,
.suite-popover--rhythm .suite-popover-drag { grid-column: 1 / -1; }
/* Rhythm popover drag bar mirrors the bar-popover drag bar. */
.suite-popover--rhythm .suite-popover-drag {
  margin: -10px -12px 4px;
  padding: 6px 10px;
  font-size: 11px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-3, #888);
  background: var(--surface-2, #f5f1e6);
  border-bottom: 1px solid var(--border, #d8d4c8);
  border-top-left-radius: 8px;
  border-top-right-radius: 8px;
  cursor: grab;
  user-select: none;
}
.suite-popover--rhythm .suite-popover-drag:active { cursor: grabbing; }
/* Compact time-sig picker — opened by clicking the time-sig digits. */
.suite-popover--tsig { min-width: 180px; padding: 12px 14px; gap: 10px; }
.suite-tsig-select { width: 100%; padding: 6px 8px; font-size: 14px; }
.suite-rhy-btn--sub {
  min-width: 56px; padding: 4px 10px;
  display: inline-flex; align-items: center; gap: 2px;
  flex-direction: column;            /* count on top, ratio badge below */
  line-height: 1.05;
}
.suite-rhy-btn--sub .suite-smufl { font-size: 18px; }
.suite-rhy-count { font-size: 15px; font-weight: 600; }
/* Italic ratio under the count for tuplet presets ("3:2", "5:4", etc.).
   Mirrors traditional engraving's tuplet labels. */
.suite-rhy-tuplet-badge {
  font-size: 9px;
  font-style: italic;
  color: var(--text-2, #777);
  letter-spacing: 0.02em;
  margin-top: 1px;
}
.suite-rhy-btn--sub.is-tuplet.is-on .suite-rhy-tuplet-badge { color: var(--accent, #c85a1a); }
.suite-popover-head {
  display: flex; justify-content: space-between; align-items: center;
  border-bottom: 1px solid var(--border, #ebe7da); padding-bottom: 8px;
}
.suite-popover-title { font-size: 13px; font-weight: 700; color: var(--text); text-transform: uppercase; letter-spacing: 0.04em; }
.suite-popover-preview { font-size: 28px; line-height: 1; color: var(--text); }
.suite-popover-section { display: flex; flex-direction: column; gap: 4px; }
.suite-popover-section-label {
  font-size: 11px; font-weight: 600; color: var(--text-3, #888);
  text-transform: uppercase; letter-spacing: 0.06em;
}

/* ── Section layout-mode picker (segmented buttons) ─────────────────
   Used by openSectionSettings → "Layout" group.  Each button toggles
   sec.layoutMode (even / fit / engraved / manual).  Visual properties
   exposed as `--suite-layout-mode-*` design tokens for theme + CMS
   overrides — no hard-coded colours, no inline styling. */
.suite-layout-modes {
  display: inline-flex;
  align-self: flex-start;   /* don't stretch as flex/grid child */
  width: max-content;       /* size to button content, not parent */
  gap:     0;
  border:        1px solid var(--suite-layout-mode-border, var(--border, #d8d4c8));
  border-radius: var(--suite-layout-mode-radius, 6px);
  overflow: hidden;
}
.suite-layout-mode {
  appearance: none;
  -webkit-appearance: none;
  background:    var(--suite-layout-mode-bg, transparent);
  color:         var(--suite-layout-mode-fg, var(--text-2, #555));
  border:        none;
  border-right:  1px solid var(--suite-layout-mode-border, var(--border, #d8d4c8));
  padding:       6px 12px;
  font-family:   inherit;
  font-size:     12px;
  font-weight:   500;
  cursor:        pointer;
  transition:    background 0.12s, color 0.12s;
}
.suite-layout-mode:last-child { border-right: none; }
.suite-layout-mode:hover {
  background: var(--suite-layout-mode-hover-bg, var(--surface-2, #f5f1e6));
  color:      var(--suite-layout-mode-hover-fg, var(--text, #2a2a2a));
}
.suite-layout-mode.is-active {
  background: var(--suite-layout-mode-active-bg, var(--accent, #c85a1a));
  color:      var(--suite-layout-mode-active-fg, #fff);
  font-weight: 600;
}
.suite-rhy-grid {
  display: flex; flex-wrap: wrap; gap: 4px;
}
.suite-rhy-btn {
  min-width: 38px; height: 38px;
  padding: 4px 8px;
  border: 1px solid var(--border, #d8d4c8);
  border-radius: 6px;
  background: var(--surface, #fff);
  color: var(--text);
  font-size: 14px; font-family: inherit; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  transition: background 0.1s, border-color 0.1s;
}
.suite-rhy-btn .suite-smufl { font-size: 22px; line-height: 1; }
.suite-rhy-btn:hover { background: var(--surface-2, #f1ede4); border-color: var(--border-strong, #c4bfb0); }
.suite-rhy-btn.is-on {
  background: var(--accent-bg, #fff3e6);
  border-color: var(--accent, #c85a1a);
  color: var(--accent, #c85a1a);
}
/* Disabled — note-value/subdivision/dotted that would overflow the bar
   or beat slot.  Greyed-out with no hover; click is also blocked in JS. */
.suite-rhy-btn.is-disabled,
.suite-rhy-btn:disabled {
  opacity: 0.32;
  cursor: not-allowed;
  pointer-events: none;
}
/* Section-settings + Display popover: tabbed dialog.
   Section settings tabs: Music / Rows / Style.
   Display tabs:           Style / Rows / Scales.
   Width 560 px — tabs replace the prior 3-column grid layout. */
.suite-popover--section-settings,
.suite-popover--display {
  width: 560px;
  max-width: calc(100vw - 32px);
  padding: 0 16px 14px;
  display: flex;
  flex-direction: column;
  align-items: stretch;
}

/* ── Tab nav ─────────────────────────────────────────────────────
   Horizontal pill-style tabs.  Active tab gets accent underline +
   text colour; inactive tabs are muted.  Whole bar sits flush
   below the dialog header, with a thin border-bottom that the
   active tab's underline interrupts. */
.suite-popover-tabs {
  display: flex;
  gap: 0;
  margin: 4px -16px 0;
  padding: 0 16px;
  border-bottom: 1px solid var(--border, #d8d4c8);
}
.suite-popover-tab-btn {
  appearance: none;
  background: transparent;
  border: 0;
  padding: 10px 18px 9px;
  margin: 0;
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  color: var(--text-3, #999);
  cursor: pointer;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px; /* overlap the nav's border-bottom */
  transition: color 120ms ease, border-color 120ms ease;
}
.suite-popover-tab-btn:hover {
  color: var(--text-2, #555);
}
.suite-popover-tab-btn[data-active="true"] {
  color: var(--accent, #c97f3b);
  border-bottom-color: var(--accent, #c97f3b);
}

/* ── Tab panels ──────────────────────────────────────────────────
   Only the active panel is shown.  Each panel uses a 2-column grid
   so dense fields (e.g. rows toggles + separators) read cleanly
   without requiring a wide dialog.  Column 1 + 2 wrap when narrow. */
.suite-popover-panels {
  display: block;
  padding: 14px 0 6px;
  min-height: 280px;
}
.suite-popover-tab {
  display: none;
  grid-template-columns: 1fr 1fr;
  column-gap: 22px;
  row-gap: 14px;
  align-items: start;
}
.suite-popover-tab[data-active="true"] {
  display: grid;
}
/* Music tab is the only single-column tab (tempo / feel / layout
   sit naturally in one stack so the dialog stays compact). */
.suite-popover-tab[data-tab="music"] {
  grid-template-columns: 1fr;
  max-width: 400px;
}
/* Each `_section()` block inside a panel — vertical stack with
   consistent gap.  Replaces the prior `.suite-popover-col` rule. */
.suite-popover-tab > .suite-popover-section {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
/* Drag handle + head + footer span the full dialog width regardless
   of which tab is active. */
.suite-popover--section-settings .suite-popover-drag,
.suite-popover--section-settings .suite-popover-head,
.suite-popover--section-settings .suite-popover-foot,
.suite-popover--display .suite-popover-drag,
.suite-popover--display .suite-popover-head,
.suite-popover--display .suite-popover-foot {
  flex: 0 0 auto;
}
/* Shared drag-bar style for section-settings and display (mirrors --bar) */
.suite-popover--section-settings .suite-popover-drag,
.suite-popover--display .suite-popover-drag {
  margin: 0 -14px 0;
  padding: 6px 14px;
  font-size: 11px; letter-spacing: 0.04em; text-transform: uppercase;
  color: var(--text-3, #888);
  background: var(--surface-2, #f5f1e6);
  border-bottom: 1px solid var(--border, #d8d4c8);
  border-top-left-radius: 8px; border-top-right-radius: 8px;
  cursor: grab; user-select: none;
}
.suite-popover--section-settings .suite-popover-drag:active,
.suite-popover--display .suite-popover-drag:active { cursor: grabbing; }
.suite-popover--section-settings .suite-popover-head,
.suite-popover--display .suite-popover-head {
  padding: 10px 0 6px; margin-bottom: 0;
}

.suite-popover-foot {
  display: flex; justify-content: flex-end; gap: 6px;
  border-top: 1px solid var(--border, #ebe7da); padding-top: 10px;
}

/* ── Time signature (engraving-style stacked digits) ─────────────────── */
/* TIME SIGNATURE — its own absolute layer, mounted INSIDE its host row
   (rhythm > chord > diagram fallback in JS).  This is one of the chart's
   independent visual layers — barlines, row separators, content rows
   and the tsig each own their own positioning and never push the others
   around.  No bar padding is applied for the tsig column; the tsig
   simply overlays the leading area of its host row, exactly as it does
   in the rhythm-visible case.  Chord text in beat 1 is allowed to fall
   under the digits — same trade-off as when the tsig sits in the rhythm
   row above the chord row.

   Two render layers stacked at the same position:
     .suite-bar-tsig-smufl  — Bravura PUA digits (U+E080–E089), proper
                            engraved style.  Visible only once
                            <body.suite-fonts-ready> is set by chart-v2.js
                            after measure-verifying Bravura is loaded.
     .suite-bar-tsig-ascii  — Plain bold serif digits.  Visible by default;
                            hidden once Bravura is verified.  Guarantees
                            users ALWAYS see a time signature.

   Default position values can be overridden by CMS / FretlyDisplayConfig
   via the CSS custom properties below. */
.suite-bar-tsig {
  --tsig-width: 22px;        /* visual width of the tsig overlay */
  --tsig-size-smufl: 38px;   /* Bravura PUA digits render large */
  --tsig-size-ascii: 20px;   /* serif fallback (smaller numerals) */
  /* `--tsig-vshift` empirically aligns the divider line with the host row's
     OPTICAL centre.  CSS centres by box geometry; the SMUFL glyphs render
     with line-height 0.78 which puts their *visual* centre 3–4 px above the
     box centre.  The base value compensates so the divider lines up with
     a serif-text optical middle (chord text uses Georgia/Times).  The
     rhythm-row override below resets it to 0 because the rhythm row has
     no chord text to align against — the divider sits cleanly on the
     row's beat-line as engraving expects. */
  --tsig-vshift: 4px;
  position: absolute;
  left: 0;
  top: 50%;
  transform: translateY(calc(-50% + var(--tsig-vshift)));
  width: var(--tsig-width);
  display: flex;
  justify-content: center;
  color: var(--text);
  pointer-events: none;
  line-height: 0.9;
  z-index: 4;                /* above beat cells, below interactive chrome */
}
/* Rhythm-row case: divider sits on the staff midline as in standard
   engraving — no nudge needed because there's no body-text optical centre
   to match against. */
.suite-bar-row--rhythm > .suite-bar-tsig { --tsig-vshift: 0px; }

/* When the tsig host falls back to chord / scales / diagram (because
   the rhythm row is hidden), the SMuFL glyph size must shrink to fit
   the host row's height — otherwise the 38 px Bravura digits overflow
   the chord row (~24 px tall) and visually spill into the separator
   and scales-row area below.  Match the chord row's font scale so the
   tsig fraction is roughly the same height as the chord text.  Same
   logic for scales / diagram fallbacks (smaller glyphs to fit). */
/* Tsig keeps its default 38 px SMuFL size in EVERY host row
   (user-stated 2026-05-04: "I don't want the timesig to be smaller.
   Just make the chord text row bigger and keep tsig the same size as
   default in the whole sheet").  Host rows that need to fit the 38 px
   glyph grow their min-height via the `.has-tsig` rule on the row
   itself. */

/* Toggle animation — added by the row-stretch click handler for ~220 ms
   while the cascade runs, then removed.  Smooths the bar-width change so
   the diagrams + chord text reposition cleanly instead of snapping.

   Note: we DON'T transition `.suite-bars` transform.  `_fitChartToWidth`
   resets transform briefly during its measure/reapply cycle; tweening
   that reset would make the entire chart visually scale (and so diagram
   strokes / dot sizes) for ~180 ms — looking like a momentary preset
   change.  Bar-width transitions are enough to perceive the change as
   smooth without scaling artefacts. */
.suite-root.suite-toggle-anim .suite-bar {
  transition: flex-grow 180ms ease, flex-basis 180ms ease, max-width 180ms ease;
}
/* Edit-mode click target — re-enable pointer events and show pointer cursor. */
.suite-bar-tsig.is-clickable {
  pointer-events: auto;
  cursor: pointer;
  border-radius: 4px;
  transition: background 0.12s;
}
.suite-bar-tsig.is-clickable:hover {
  background: var(--accent-bg, #fff3e6);
}
/* Read mode strips interactivity. */
.suite-root--read .suite-bar-tsig.is-clickable { cursor: inherit; pointer-events: none; }
.suite-root--read .suite-bar-tsig.is-clickable:hover { background: transparent; }
/* Both render layers occupy the SAME stacking position; one is hidden. */
.suite-bar-tsig-smufl,
.suite-bar-tsig-ascii {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}
/* Default: ASCII fallback visible, SMuFL hidden. */
.suite-bar-tsig-smufl { display: none; }
.suite-bar-tsig-smufl { font-size: var(--tsig-size-smufl); line-height: 0.78; }
.suite-bar-tsig-ascii {
  font-family: 'Times New Roman', 'Times', Georgia, serif;
  font-size: var(--tsig-size-ascii);
  font-weight: 700;
  line-height: 0.95;
}
/* Bravura verified — flip the layers. */
body.suite-fonts-ready .suite-bar-tsig-smufl { display: flex; }
body.suite-fonts-ready .suite-bar-tsig-ascii { display: none; }

.suite-bar-tsig-num,
.suite-bar-tsig-den {
  display: block;
  text-align: center;
  font-feature-settings: "lnum" 1;
}
/* Horizontal divider between numerator and denominator.  Drawn on the
   numerator's bottom edge with a small horizontal pad so it doesn't span
   the full column width.  Both render layers (SMuFL + ASCII fallback)
   get the rule so it's visible regardless of which is active. */
.suite-bar-tsig-smufl .suite-bar-tsig-num,
.suite-bar-tsig-ascii .suite-bar-tsig-num {
  border-bottom: 1px solid currentColor;
  padding: 0 1px 1px;
  margin-bottom: 1px;
}
/* Free-time / asymmetric labels stay inline but smaller and one-line. */
.suite-bar-tsig--text {
  flex-direction: row;
  font-family: inherit;
  font-size: 12px;
  color: var(--accent, #c85a1a);
  font-weight: 700;
  line-height: 1;
}
/* (Legacy `.suite-bar-tsig-spacer` removed — tsig is now an absolute
   layer, so diag + chord rows no longer need a flex spacer to match
   the rhythm row's column.) */

/* ── Footer hint ─────────────────────────────────────────────────────── */
.suite-hint {
  margin: 14px 4px 0;
  font-size: 12px; color: var(--text-3, #888);
  font-family: -apple-system, sans-serif; line-height: 1.5;
}

/* ── SMuFL helper class (local — independent of smufl.css base) ──────── */
.suite-smufl {
  font-family: 'BravuraText', 'Bravura', serif;
  font-style: normal; font-weight: normal;
  line-height: 1;
}

/* ── Read mode: hide editing chrome ONLY, leave proportions identical
   to edit mode.  Earlier overrides bumped chord-input font-size and
   paper padding, which inflated the bar heights — now removed.  All
   sizing decisions come from `display.fontSize` and `display.diagramSize`
   via the toolbar so edit and read render exactly the same. */
.suite-root--read .suite-bar-gear { display: none; }

/* ── Dark-mode tweaks (Fretly auto-applies via CSS vars) ─────────────── */
[data-theme="dark"] .suite-paper { background: var(--surface, #1f1d18); }

/* ═══════════════════════════════════════════════════════════════════════
   Chart Suite — tab bar + panels
   ═══════════════════════════════════════════════════════════════════════ */

/* Tab bar */
.suite-suite-tabs {
  display: flex;
  gap: 2px;
  padding: 6px 12px 0;
  border-bottom: 2px solid var(--border, #e0ddd6);
  background: var(--surface-2, #f7f5f0);
  /* Half-width windows (owner 2026-07-08): keep the strip on ONE line and
     scroll horizontally — wrapping pushed tabs onto a second row. */
  flex-wrap: nowrap;
  overflow-x: auto;
  scrollbar-width: thin;
}
.suite-suite-tab { white-space: nowrap; flex: 0 0 auto; }
.suite-suite-tab {
  padding: 6px 14px;
  font-size: 13px;
  font-weight: 500;
  border: none;
  background: none;
  color: var(--text-2, #777);
  cursor: pointer;
  border-radius: 4px 4px 0 0;
  border-bottom: 2px solid transparent;
  margin-bottom: -2px;
  transition: color 0.12s, border-color 0.12s;
  /* Rendered as <a> (open-in-new-tab support) — neutralise anchor defaults. */
  display: inline-block;
  text-decoration: none;
}
.suite-suite-tab:hover { color: var(--text, #2a2820); }
.suite-suite-tab--active {
  color: var(--accent, #c8862a);
  border-bottom-color: var(--accent, #c8862a);
  background: var(--surface, #fff);
}

/* Panel common */
.suite-suite-panel {
  margin-top: 8px;
  padding: 16px 16px 32px;
}
/* Collection panel: sections (coll-block / coll-subgroup) span
   edge-to-edge to match the chartbar width. The blocks carry their own
   border-radius, border and shadow; no horizontal inset is needed.
   .coll-subgroup provides margin-top so the default 16px top is dropped.
   32px bottom padding preserves breathing room before page end. */
/* Optional tab block at the top of the Collection total view */
.suite-collview-tab { margin: 0 0 18px; border: 1px solid var(--border, #e1ddd2); border-radius: 12px; background: var(--surface, #fff); overflow: hidden; }
.suite-collview-tab-head { display: flex; align-items: center; justify-content: space-between; padding: 8px 12px; border-bottom: 1px solid var(--border, #e1ddd2); }
/* Read-only Collection block header controls: collapse chevron + Columns
   stepper (view-only, public-safe). Owner 2026-07-13 points 2 & 3. */
.suite-collview-tab-head { gap: 10px; }
.suite-collview-tab-head .suite-collview-tab-title { flex: 1 1 auto; }
.suite-collview-chevron { display: inline-flex; align-items: center; transition: transform .15s ease; color: var(--text-muted, #888); }
.suite-collview-chevron svg { width: 14px; height: 14px; }
.suite-collview-cols { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; color: var(--text-muted, #777); }
.suite-collview-cols-label { font-weight: 600; }
.suite-collview-cols-val { min-width: 12px; text-align: center; font-weight: 700; color: var(--text); }
.suite-collview-cols .coll-btn-icon { width: 22px; height: 22px; line-height: 1; font-size: 15px; }
.suite-collview-tab-title { font-weight: 700; font-size: 14px; color: var(--text); }
/* Public read-only Collection aux sections (arpeggios / scales) reuse the
   logged-in renderers but strip content-EDITING chrome only. Collapse chevrons
   and view controls (cols) STAY -- they never change content (owner 2026-07-13,
   "all controls that don't change content are available to public"). */
.suite-collview-ro-aux .coll-add-wrap { display: none !important; }
.suite-collview-ro-aux .coll-btn-danger,
.suite-collview-ro-aux .coll-btn-icon[title="Edit"] { display: none !important; }
.suite-collview-tab-toggle { font-size: 12px; padding: 4px 10px; border-radius: 7px; border: 1px solid var(--border, #d8d4c8); background: var(--surface, #fff); color: var(--text); cursor: pointer; }
.suite-collview-tab-toggle:hover { border-color: var(--accent, #c85a1a); }
.suite-collview-tab-body { padding: 10px 12px; overflow-x: auto; }
.suite-collview-tab-body.is-hidden { display: none; }
.suite-collview-tab-body svg { max-width: 100%; height: auto; }

.suite-suite-panel--collection {
  padding: 0 0 32px;
}
.suite-suite-panel-header {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 16px;
  flex-wrap: wrap;
}
.suite-suite-panel-title {
  font-size: 15px;
  font-weight: 600;
  color: var(--text, #2a2820);
}
.suite-suite-panel-open {
  font-size: 12px;
  color: var(--accent, #c8862a);
  text-decoration: none;
  padding: 4px 10px;
  border: 1px solid var(--accent, #c8862a);
  border-radius: 4px;
}
.suite-suite-panel-open:hover { background: var(--accent-light, #fdf3e3); }
.suite-suite-empty {
  color: var(--text-3, #999);
  font-size: 13px;
  padding: 24px 0;
}
.suite-suite-warn {
  color: #7a5b00;
  background: #fff8e6;
  border: 1px solid #f0d992;
  border-radius: 6px;
  padding: 10px 12px;
}

/* Diagram panel inline toolbar */
.suite-diag-toolbar {
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
  padding: 10px 0 14px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 16px;
}
.suite-diag-ctrl-group {
  display: inline-flex; align-items: center; gap: 5px; flex-wrap: wrap;
}
.suite-diag-ctrl-label {
  font-size: 12px; font-weight: 500; color: var(--text-2, #888);
  white-space: nowrap;
}
.suite-diag-preset-btn {
  padding: 4px 10px; border-radius: 6px;
  font-size: 12px; font-weight: 500; font-family: inherit;
  border: 1px solid var(--border); background: var(--surface, #fff);
  color: var(--text); cursor: pointer;
  transition: background .12s, border-color .12s, color .12s;
}
.suite-diag-preset-btn:hover   { background: var(--surface-2, #f5f3ee); }
.suite-diag-preset-btn--active { background: var(--accent); border-color: var(--accent); color: #fff; }
.suite-diag-spin-btn {
  width: 26px; height: 26px; border-radius: 5px;
  font-size: 14px; line-height: 1;
  border: 1px solid var(--border); background: var(--surface, #fff);
  color: var(--text); cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
}
.suite-diag-spin-btn:hover { background: var(--accent); border-color: var(--accent); color: #fff; }
.suite-diag-spin-val {
  min-width: 22px; text-align: center;
  font-size: 13px; font-weight: 600; color: var(--text);
}

/* Collection chord-text grid */
.suite-coll-chord-grid {
  display: flex; flex-direction: column; gap: 10px;
}
.suite-coll-chord-section {
  display: flex; flex-wrap: wrap; align-items: flex-start; gap: 6px;
}
.suite-coll-chord-badge {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 22px; height: 22px; padding: 0 6px;
  background: var(--accent, #c8862a); color: #fff;
  border-radius: 5px; font-size: 11px; font-weight: 700;
  flex-shrink: 0; margin-top: 2px;
}
.suite-coll-chord-bar {
  display: inline-flex; gap: 4px;
  padding: 4px 6px;
  border: 1px solid var(--border); border-radius: 6px;
  background: var(--surface, #fff);
}
.suite-coll-chord-bar--rpt-start { border-left: 3px solid var(--accent, #c8862a); }
.suite-coll-chord-bar--rpt-end   { border-right: 3px solid var(--accent, #c8862a); }
.suite-coll-chord-cell {
  font-size: 13px; font-weight: 500; color: var(--text);
  min-width: 28px; text-align: center;
  white-space: nowrap;
}
.suite-coll-chord-cell--empty { color: var(--text-3, #bbb); }

/* Diagram grid */
.suite-suite-diagram-grid {
  display: grid;
  gap: 12px;
  margin-top: 8px;
}
.suite-suite-diagram-grid--compact { gap: 8px; }
.suite-suite-diagram-cell {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
}
.suite-suite-diagram-cell svg { display: block; }
.suite-suite-diagram-empty {
  background: var(--surface-2, #f0ede6);
  border: 1px dashed var(--border, #ccc);
  border-radius: 4px;
}
.suite-suite-diagram-label {
  font-size: 11px;
  color: var(--text-2, #666);
  text-align: center;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Collection panel sections */
.suite-suite-coll-section {
  margin-bottom: 28px;
}
.suite-suite-coll-label {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-3, #999);
  margin-bottom: 10px;
}
/* Chart preview inside collection panel — read-only, contained */
.suite-suite-chart-preview {
  border: 1px solid var(--border, #e0ddd6);
  border-radius: 6px;
  overflow: hidden;
  max-height: 480px;
  overflow-y: auto;
}
.suite-suite-chart-preview .suite-paper {
  padding: 12px;
}

/* Scale list */
.suite-suite-scale-list {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.suite-suite-scale-chip {
  font-size: 12px;
  padding: 3px 10px;
  background: var(--surface-2, #f0ede6);
  border: 1px solid var(--border, #ddd);
  border-radius: 12px;
  color: var(--text-2, #555);
}

/* Dark mode */
[data-theme="dark"] .suite-suite-tabs {
  background: var(--surface-2, #2a2820);
  border-bottom-color: var(--border, #3a3830);
}
[data-theme="dark"] .suite-suite-tab--active {
  background: var(--surface, #1f1d18);
}
[data-theme="dark"] .suite-suite-chart-preview {
  border-color: var(--border, #3a3830);
}


/* ── Side panels — Phase B shell (CHART-UI-V2-PLAN.md, 2026-06-10) ──────────
   Flag-gated (FEATURE_SIDE_PANELS).  Panels are siblings of .suite-root;
   bar layout is untouched. */
.suite-shell { display: flex; align-items: stretch; gap: 0; min-width: 0; }
.suite-shell > .suite-root { flex: 1 1 auto; min-width: 0; }

/* FULL-BLEED shell (owner 2026-06-11: "we don't need grey space next
   to the sidebars") — when the panel shell is present, the route +
   page-wrap give up their gutters so the panels sit flush against the
   viewport edges; the middle column re-applies the original page
   padding internally.  :has() selectors match (and outrank, being
   later with equal id-weight) the `.page-wrap:has(#route-chart-v2.active)`
   width-lift rule above. */
.page-wrap:has(#route-chart-v2.active .suite-shell),
.page-wrap:has(#route-suite.active .suite-shell) {
  padding-left: 0;
  padding-right: 0;
  padding-top: 0;
}
#route-chart-v2:has(.suite-shell),
#route-suite:has(.suite-shell) { padding: 0; }
.suite-shell > .suite-root { padding: 20px 24px 64px; }

.suite-sidepanel {
  flex: 0 0 auto;
  width: 240px;
  display: flex;
  flex-direction: column;
  background: var(--surface, #fff);
  transition: width .18s ease;
  overflow: hidden;
  /* Sit above the chart layer (chart content is z-index ≤ 5; popovers are
     ≥ 1000 and stay above this).  While the panel animates open the chart
     hasn't re-fit yet, so its still-wide engraving briefly overlaps the
     panel's column — being opaque + above the chart, the panel occludes
     that transient spill instead of the chart painting on top of it.
     (owner 2026-06-16) */
  position: relative;
  z-index: 6;
}
.suite-sidepanel--left  { border-right: 1px solid var(--border, #e3e3e3); }
.suite-sidepanel--right { border-left:  1px solid var(--border, #e3e3e3); width: 264px; }
/* Collapsed = ZERO width (owner 2026-06-11) — reopen via the chartbar
   Tools / Inspector buttons or keys 1 / 2. */
.suite-sidepanel.is-collapsed { width: 0; border: none; overflow: hidden; }
.suite-sidepanel.is-collapsed > * { display: none; }

.suite-sidepanel-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: var(--space-xs, 6px) var(--space-sm, 10px);
  border-bottom: 1px solid var(--border, #e3e3e3);
  min-height: 34px;
}
.suite-sidepanel.is-collapsed .suite-sidepanel-head { border-bottom: none; justify-content: center; padding: 6px 2px; }
.suite-sidepanel-title {
  font-size: var(--font-xs, 11px); font-weight: 700;
  text-transform: uppercase; letter-spacing: .06em;
  color: var(--text-2, #777);
}
.suite-sidepanel-toggle {
  border: none; background: none; cursor: pointer;
  font-size: 15px; line-height: 1; padding: 2px 6px;
  color: var(--text-2, #777); border-radius: var(--radius-sm, 4px);
}
.suite-sidepanel-toggle:hover { background: var(--surface-2, #f2f2f2); color: var(--text, #222); }

.suite-sidepanel-body { flex: 1; overflow-y: auto; padding: var(--space-sm, 10px); }

.suite-sidepanel-group { margin-bottom: var(--space-md, 14px); }
.suite-sidepanel-group-title {
  font-size: var(--font-xs, 11px); font-weight: 600; color: var(--text, #333);
  margin-bottom: 2px;
}
.suite-sidepanel-group-hint { font-size: 11px; color: var(--text-3, #aaa); font-style: italic; }

.suite-sidepanel-tabs {
  display: flex; gap: 2px; margin-bottom: var(--space-sm, 10px);
  border-bottom: 1px solid var(--border, #e3e3e3); padding-bottom: 6px;
}
.suite-sidepanel-tab {
  border: 1px solid var(--border, #e3e3e3); background: var(--surface, #fff);
  font-size: var(--font-xs, 11px); padding: 3px 8px; cursor: pointer;
  border-radius: var(--radius-sm, 4px); color: var(--text-2, #777);
}
.suite-sidepanel-tab.is-active {
  background: var(--accent, #2f6fed); border-color: var(--accent, #2f6fed); color: #fff;
}
.suite-sidepanel-tabbody { font-size: 12px; color: var(--text-2, #777); line-height: 1.5; }

/* Vector tsig (Phase A): inherit the tsig column's color/positioning. */
.suite-bar-tsig--vector svg { display: block; margin: 0 auto; }

@media (max-width: 1100px) { /* small screens: panels start collapsed-friendly */
  .suite-sidepanel { width: 200px; }
  .suite-sidepanel--right { width: 220px; }
}

/* Phase C slice 1 — Inspector Chart-tab controls */
.suite-sidepanel-ctl { display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-xs, 6px); margin-bottom: var(--space-sm, 10px); }
.suite-sidepanel-ctl-label { font-size: var(--font-xs, 11px); font-weight: 600;
  color: var(--text-2, #777); white-space: nowrap; }
.suite-sidepanel-action { width: 100%; margin-top: var(--space-sm, 10px);
  padding: 6px 10px; font-size: var(--font-xs, 12px); cursor: pointer;
  border: 1px solid var(--border, #e3e3e3); border-radius: var(--radius-sm, 5px);
  background: var(--surface, #fff); color: var(--text, #333); }
.suite-sidepanel-action:hover { background: var(--surface-2, #f4f4f4); }

.suite-sidepanel-seclink { flex: 1; text-align: left; border: none; background: none;
  cursor: pointer; font-size: 12px; color: var(--text, #333); padding: 4px 2px;
  border-radius: var(--radius-sm, 4px); }
.suite-sidepanel-seclink:hover { background: var(--surface-2, #f4f4f4); }
.suite-sidepanel-action--inline { width: auto; margin-top: 0; padding: 3px 8px; }

/* Chartbar panel-toggle buttons */
.suite-paneltoggle { font-size: var(--font-xs, 12px); }
.suite-paneltoggle.is-on { background: var(--surface-2, #f0f0f0); box-shadow: inset 0 0 0 1px var(--border, #ddd); }
.suite-paneltoggle--left { margin-right: var(--space-sm, 10px); }
.suite-paneltoggle--right { margin-left: var(--space-sm, 10px); }

/* Context-aware Inspector (owner 2026-06-16): the Inspector is a CHART
   tool — its controls don't touch the Diagram Sheet / Collection / Tab
   views (each is a self-contained embed with its own toolbar).  Hide the
   inspector panel AND its chartbar toggle off the Chart tab so those
   views aren't cluttered with controls that do nothing there. */
.suite-shell:not([data-suite-tab="chart"]) .suite-sidepanel--right,
.suite-shell:not([data-suite-tab="chart"]) .suite-paneltoggle--right {
  display: none !important;
}
/* Same reasoning for the LEFT tool palette: it arms CHART beat tools (note
   values, beams, tuplets, articulations) that don't apply to the Diagram
   Sheet / Collection / Tab embeds (each carries its own tools).  Hide it —
   and its toggle — off the Chart tab so there's only ONE Tools palette in
   view on the Tab tab (owner 2026-06-18). */
.suite-shell:not([data-suite-tab="chart"]) .suite-sidepanel--left,
.suite-shell:not([data-suite-tab="chart"]) .suite-paneltoggle--left {
  display: none !important;
}
