/* Application chrome: everything that is not the chart itself. */

:root {
  --ink: #14161a;
  --ink-soft: #5c626d;
  --ink-faint: #9aa0ab;
  --line: #d9dce2;
  --line-soft: #eceef2;
  --chrome: #f6f7f9;
  --paper: #ffffff;
  --accent: #1f5fd0;
  --accent-soft: #e8f0ff;
  --danger: #b3261e;
  --warn: #a15c00;
  --radius: 7px;
  --tap: 34px;
}

* { box-sizing: border-box; }

html { height: 100%; }

body {
  margin: 0;
  height: 100%;
  display: flex;
  flex-direction: column;
  color: var(--ink);
  background: var(--chrome);
  font: 14px/1.45 -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
  -webkit-text-size-adjust: 100%;
}

#app { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }

.muted { color: var(--ink-soft); }
.small { font-size: 12px; }
.spacer { flex: 1; }

/* --- toolbar -------------------------------------------------------- */

.toolbar {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  padding-top: max(8px, env(safe-area-inset-top));
  background: var(--paper);
  border-bottom: 1px solid var(--line);
  flex: 0 0 auto;
}

.size-nudge { display: inline-flex; align-items: center; gap: 4px; }
.fit-badge {
  font-size: 12px;
  border-radius: 20px;
  padding: 4px 10px;
  white-space: nowrap;
  border: 1px solid transparent;
}
.fit-badge.ok { background: #e7f5ec; color: #1f7a4d; border-color: #bfe3cd; }
.fit-badge.tight { background: #fdf3e0; color: #8a5d10; border-color: #f0dcb4; }
.fit-badge.over { background: #fdeceb; color: #b3261e; border-color: #f2c9c6; }
@media (max-width: 560px) { .fit-badge { display: none; } }
.size-value { min-width: 34px; text-align: center; font-variant-numeric: tabular-nums; }

.app-title { font-size: 17px; margin: 0; font-weight: 600; letter-spacing: -0.01em; }

.btn {
  font: inherit;
  color: var(--ink);
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 6px 11px;
  min-height: var(--tap);
  cursor: pointer;
  white-space: nowrap;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.btn:hover { background: var(--line-soft); }
.btn:active { transform: translateY(1px); }
.btn:disabled { opacity: 0.4; cursor: default; }
.btn.primary { background: var(--accent); border-color: var(--accent); color: #fff; }
.btn.primary:hover { filter: brightness(1.08); }
.btn.danger { color: var(--danger); }
.btn.small { padding: 4px 9px; min-height: 30px; font-size: 13px; }
.btn.tiny { padding: 3px 8px; min-height: 27px; font-size: 12px; }
.btn.ghost { border-style: dashed; color: var(--ink-soft); }
.icon-btn { padding: 4px 8px; min-width: 30px; min-height: 30px; font-size: 14px; line-height: 1; }

/* --- split layout --------------------------------------------------- */

.split { flex: 1 1 auto; display: flex; min-height: 0; }

/* The whole screen is rebuilt on every edit (see app.js), which the browser's
   own scroll anchoring reads as content having shifted around above the
   fold — it "corrects" for that by moving the scroll position on its own,
   fighting the deliberate restore app.js already does. Disabled, so the one
   thing actually allowed to move this pane's scroll is the person reading
   it. */
.pane { overflow: auto; overflow-anchor: none; -webkit-overflow-scrolling: touch; min-height: 0; }

.editor-pane {
  flex: 1 1 46%;
  padding: 12px 12px 40vh;
  border-right: 1px solid var(--line);
  background: var(--chrome);
}

.editor-pane-empty {
  margin: 20% 12px 0;
  text-align: center;
  font-size: 13px;
}

.chart-pane {
  flex: 1 1 54%;
  padding: 16px;
  background: #eceef1;
}

/* --- Score: Layout and Read ------------------------------------------ */
/* Two screens with one page between them. Layout shows the page as an
   object on a desk, with room for the controls that finish it; Read shows
   the same page and nothing else. Neither shows the editor or the toolbar. */

body.layout-view .editor-pane,
body.layout-view .toolbar,
body.reading .editor-pane,
body.reading .toolbar { display: none; }

body.layout-view .split,
body.reading .split { display: block; height: 100%; }

body.layout-view .chart-pane,
body.reading .chart-pane {
  flex: 1 1 100%;
  height: 100%;
  /* The page is centred in whatever is left of the window. */
  display: flex;
  align-items: center;
  justify-content: center;
  overscroll-behavior: contain;
}

/* Layout: the page sits on a desk, so you can see it *as* a page — where its
   edges are, how much of it is still empty. That reading depends entirely on
   there being a surface behind it that is not the page. */
body.layout-view .chart-pane {
  background: #d9dbe0;
  padding: 28px max(20px, env(safe-area-inset-right))
           calc(28px + 56px) max(20px, env(safe-area-inset-left));
}

/* Read: the page is the screen. Nothing behind it, nothing around it. */
body.reading .chart-pane {
  background: #fff;
  padding: max(6px, env(safe-area-inset-top)) max(6px, env(safe-area-inset-right))
           max(6px, env(safe-area-inset-bottom)) max(6px, env(safe-area-inset-left));
}

/* The frame is taken out of flow by its own transform, so the stage stands in
   for the size it is actually drawn at — see applyFit, which sets both. */
.frame-stage { position: relative; flex: 0 0 auto; }

body.layout-view .chart-frame,
body.reading .chart-frame {
  position: absolute;
  top: 0;
  left: 0;
  overflow: hidden;
  background: #fff;
}

body.layout-view .chart-frame {
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2), 0 12px 34px rgba(0, 0, 0, 0.16);
  border-radius: 2px;
}

body.layout-view .chart,
body.reading .chart {
  box-shadow: none;
  border-radius: 0;
  min-height: 100%;
}

/* --- the Layout panel ------------------------------------------------ */
/* The one place in the app that can afford a proper control surface. It is
   never on screen while a chart is being played from — Read shows the same
   page with none of this — so the one-screen rule that keeps every other
   panel small does not apply to it. */

body { --panel-w: 268px; }

.layout-panel {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  width: var(--panel-w);
  z-index: 45;
  display: flex;
  flex-direction: column;
  overflow-y: auto;
  overscroll-behavior: contain;
  /* Sized to fit an iPad's height without scrolling: scrolling a panel to find
     the one control you want, while the page it changes sits still beside it,
     is what this panel used to ask. The action strip sits beside the panel,
     not under it, so the bottom needs no room kept for it. */
  padding: 10px 14px calc(12px + env(safe-area-inset-bottom));
  padding-top: max(12px, env(safe-area-inset-top));
  background: var(--paper);
  border-left: 1px solid var(--line);
  box-shadow: -2px 0 14px rgba(0, 0, 0, 0.07);
}

/* The page keeps the room the panel is not using, so it stays centred in
   what is left rather than sliding behind the controls. */
body.panel-open.layout-view .chart-pane { padding-right: calc(var(--panel-w) + 20px); }
body.panel-open.layout-view .reading-controls { right: var(--panel-w); }

.lp-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--line);
  margin-bottom: 4px;
}
.lp-heading { font-size: 15px; margin: 0; font-weight: 600; letter-spacing: -0.01em; }

.lp-group { padding: 6px 0; border-bottom: 1px solid var(--line-soft); }
.lp-group:last-of-type { border-bottom: 0; }
.lp-title {
  font-size: 11px;
  margin: 0 0 3px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--ink-faint);
}

.lp-row {
  display: grid;
  grid-template-columns: 74px minmax(0, 1fr) 40px;
  align-items: center;
  gap: 8px;
  padding: 2px 0;
}
.lp-name { font-size: 12px; color: var(--ink-soft); }
.lp-value { text-align: right; font-variant-numeric: tabular-nums; }
.lp-slider { width: 100%; min-width: 0; accent-color: var(--accent); }

/* A choice row has no readout to line up with, so it takes the width back. */
.lp-choices { grid-column: 2 / -1; display: flex; flex-wrap: wrap; gap: 4px; }
.lp-choices .btn { flex: 1 1 auto; min-width: 34px; padding: 3px 6px; }

.lp-toggles { display: grid; grid-template-columns: 1fr 1fr; gap: 0 4px; }
.lp-toggle {
  font: inherit;
  font-size: 12px;
  color: var(--ink);
  background: none;
  border: 0;
  border-radius: 5px;
  padding: 4px;
  min-height: 32px;
  display: flex;
  align-items: center;
  gap: 6px;
  text-align: left;
  cursor: pointer;
}
.lp-toggle:hover { background: var(--line-soft); }
.lp-tick {
  flex: 0 0 auto;
  width: 17px;
  height: 17px;
  border: 1px solid var(--line);
  border-radius: 4px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  line-height: 1;
  color: #fff;
  background: var(--paper);
}
.lp-toggle.on .lp-tick { background: var(--accent); border-color: var(--accent); }

.lp-wide { width: 100%; margin-top: 6px; }
.lp-reset { margin-top: 8px; color: var(--ink-soft); }

/* A narrow window has no room for a page and a panel side by side, so the
   panel takes the bottom of the screen instead and the page keeps the top. */
@media (max-width: 760px) {
  .layout-panel {
    top: auto;
    left: 0;
    width: auto;
    max-height: 52vh;
    border-left: 0;
    border-top: 1px solid var(--line);
    box-shadow: 0 -2px 14px rgba(0, 0, 0, 0.09);
    padding-bottom: calc(12px + env(safe-area-inset-bottom));
  }
  /* The action strip moves to the top on a narrow window, so the page has to
     get out from under it — it was sitting behind the buttons. */
  body.panel-open.layout-view .chart-pane {
    padding-right: 20px;
    padding-top: calc(max(10px, env(safe-area-inset-top)) + 56px);
    padding-bottom: 54vh;
  }
  body.panel-open.layout-view .reading-controls {
    right: max(10px, env(safe-area-inset-right));
    left: auto;
    bottom: auto;
    top: max(10px, env(safe-area-inset-top));
    justify-content: flex-end;
  }
}

.reading-controls {
  position: fixed;
  right: max(10px, env(safe-area-inset-right));
  bottom: max(10px, env(safe-area-inset-bottom));
  display: flex;
  align-items: center;
  gap: 6px;
  z-index: 40;
  opacity: 0.45;
  transition: opacity 0.15s;
}
.reading-controls:hover,
.reading-controls:focus-within { opacity: 1; }

/* Layout's cluster is not in the way of anything — there is a desk around
   the page to put it on — so it is fully lit and centred under the page,
   rather than faded into a corner the way Read's single ✕ is. A control you
   have to go looking for is a control that costs you time you meant to
   spend on the chart. */
body.layout-view .reading-controls {
  left: 0;
  right: 0;
  bottom: max(12px, env(safe-area-inset-bottom));
  justify-content: center;
  flex-wrap: wrap;
  opacity: 1;
  pointer-events: none;
}
body.layout-view .reading-controls > * { pointer-events: auto; }

.reading-zoom { display: inline-flex; gap: 6px; }

.btn.round {
  border-radius: 999px;
  min-width: 44px;
  min-height: 44px;
  padding: 0 12px;
  background: rgba(255, 255, 255, 0.94);
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.18);
  backdrop-filter: blur(6px);
  font-size: 15px;
}
.btn.round.wide-btn { padding: 0 16px; }
/* .btn.primary is defined further up this file and carries exactly the same
   specificity as .btn.round, so the pale fill above was winning the tie on
   source order alone — which left every "on" control in this cluster (the
   PDF button, the click, "Repeats: collapsed") drawing white text on white.
   The accent fill and the hover feedback are both restated here so a round
   button reads the same as any other button does. */
.btn.round.primary { background: var(--accent); border-color: var(--accent); color: #fff; }
.btn.round:hover { background: #fff; }
.btn.round.primary:hover { background: var(--accent); }

/* One shape for "press this to make sound happen," wherever it appears —
   the dock, the Build toolbar, and Map's transport all use it, so the eye
   doesn't have to relearn what play looks like on every screen. */
.btn.transport {
  border-radius: 999px;
  min-width: 40px;
  min-height: 40px;
  padding: 0;
  font-size: 15px;
}
.btn.transport.big { min-width: 48px; min-height: 48px; font-size: 18px; }

/* Score is a viewer for the chart itself, not for the recording — the dock
   belongs to Build, where you are tapping timestamps against it. */
body.reading #audio-dock,
body.layout-view #audio-dock { display: none; }

@media (max-width: 900px) {
  .split { flex-direction: column; }
  .editor-pane { flex: none; border-right: 0; border-bottom: 1px solid var(--line); padding-bottom: 16px; }
  .chart-pane { flex: none; padding: 10px; }
  /* The constant panel is a desktop fix for the chart jumping sideways —
     stacked on top of the chart instead of beside it, an empty one is just
     the chart pushed down for nothing, so here it goes back to only
     appearing once there is something to show in it. */
  .editor-pane:has(.editor-pane-empty) { display: none; }
}

/* Phones: bigger targets, and the toolbar has to survive a 390px screen. */
@media (max-width: 560px) {
  :root { --tap: 40px; }
  .toolbar { flex-wrap: wrap; gap: 6px; padding: 6px 8px; }
  .toolbar .btn { padding: 6px 9px; }
  .app-title { font-size: 16px; }
  .size-nudge { order: 3; }
  .editor-pane { padding: 8px 8px 30vh; }
  .chart-pane { padding: 8px; }
  .pep-head { flex-wrap: wrap; }
  .pc-summary { flex: 1 0 100%; order: 5; white-space: normal; }
  .ph-side .icon-btn, .sec-head .icon-btn { min-width: 36px; min-height: 36px; }
  .phrase-add-menu .btn.tiny { min-height: 34px; padding: 5px 9px; }
  .field { font-size: 13px; }
  input, select { min-height: 36px; font-size: 16px; } /* 16px stops iOS zooming on focus */
}

/* --- song notes ------------------------------------------------------ */
/* Title, artist, tempo and so on are edited in the chart's own header now
   (see chart.css) — this card is just the song's notes and lyrics. */

.song-notes {
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 10px 12px;
  margin-bottom: 12px;
}

.row { display: flex; align-items: center; gap: 8px; }
.row.wrap { flex-wrap: wrap; }

.field { display: inline-flex; align-items: center; gap: 5px; font-size: 12px; color: var(--ink-soft); }
.field-label { white-space: nowrap; }

input, select, textarea {
  font: inherit;
  color: var(--ink);
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 5px;
  padding: 5px 7px;
  min-height: 30px;
  max-width: 100%;
}
input:focus, select:focus { outline: 2px solid var(--accent-soft); border-color: var(--accent); }
input.narrow { width: 62px; }
input.wide { width: 100%; }
input[type="number"] { width: 68px; }

/* --- the phrase editor panel ------------------------------------------ */
/* The left pane's only content now: whichever phrase is open. The section
   and phrase list itself lives in the chart pane (see chart.css) — this is
   just the detail behind it. */

.phrase-editor-panel { display: flex; flex-direction: column; gap: 8px; }

.pep-head { display: flex; align-items: center; gap: 8px; min-height: var(--tap); }

.pc-type {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--ink-soft);
  background: var(--line-soft);
  border-radius: 4px;
  padding: 2px 6px;
  white-space: nowrap;
  flex: 0 0 auto;
}
.pc-summary { flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--ink-soft); }

.phrase-editor { display: flex; flex-direction: column; gap: 8px; }
.groove-url { flex: 1 1 auto; min-width: 120px; }

.btn.add { border-style: dashed; color: var(--ink-soft); }
.btn.add:hover { color: var(--ink); border-style: solid; }

.add-section { width: 100%; margin-top: 10px; border-style: dashed; }

/* Drag-to-reorder: the handle is grabbed, the card it belongs to tracks the
   pointer with no transition of its own, and its siblings slide over with one
   so the reorder reads as a single continuous motion. */
.drag-handle { cursor: grab; color: var(--ink-faint); touch-action: none; }

/* --- annotations ---------------------------------------------------- */

.annotations { display: flex; flex-direction: column; gap: 4px; align-items: flex-start; margin-top: 6px; }
.annotation { display: flex; gap: 4px; width: 100%; }
.annotation input { flex: 1 1 auto; font-size: 13px; font-style: italic; }

/* --- grid editor ---------------------------------------------------- */

.grid-editor { border: 1px solid var(--line); border-radius: 5px; padding: 8px; background: var(--paper); }
.grid-controls { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; margin-bottom: 8px; }
.grid-controls label { display: inline-flex; gap: 5px; align-items: center; font-size: 12px; color: var(--ink-soft); }

.grid-view.editable .gcell.editable {
  cursor: pointer;
  background: transparent;
  border: 0;
  padding: 0;
  min-height: 24px;
}
.grid-view.editable .gcell.editable:hover { background: var(--accent-soft); }
.grid-view.editable .glabel.wide { width: 118px; flex: 0 0 118px; }
.grid-view.editable .glabel.wide select { width: 100%; font-size: 11px; min-height: 24px; padding: 2px 4px; }
.brush-static { font-size: 11px; color: var(--ink-soft); }

/* --- library -------------------------------------------------------- */

.lib-search { flex: 1 1 160px; max-width: 320px; font-size: 14px; }
.library { flex: 1 1 auto; min-height: 0; overflow: hidden; padding: 14px; display: flex; flex-direction: column; }
.song-table {
  max-width: 780px;
  width: 100%;
  margin: 0 auto;
  background: var(--paper);
  border: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  min-height: 0;
}
.song-row {
  display: grid;
  grid-template-columns: 1fr 150px 90px 96px;
  align-items: center;
  column-gap: 8px;
}
.song-table-head { flex: 0 0 auto; background: var(--chrome); border-bottom: 1px solid var(--line); }
/* The header stays put outside this box; only the rows themselves scroll,
   so a long library never pushes the header (or the toolbar above it) off
   screen — see drum-chart-standing-constraints in memory: a chart reader
   never needs to scroll to see the whole picture, and neither should this. */
.song-table-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; }
.song-table-body > .song-row + .song-row { border-top: 1px solid var(--line-soft); }
.song-table-body > .song-row:hover { background: var(--line-soft); }
.col-artist, .col-updated { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.col-title { min-width: 0; }
.song-table-head > * { overflow: hidden; }
.col-sort {
  display: flex;
  align-items: center;
  gap: 4px;
  width: 100%;
  background: none;
  border: 0;
  font: inherit;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--ink-faint);
  cursor: pointer;
  padding: 7px 10px;
}
.col-sort:hover { color: var(--ink-soft); }
.col-sort.active { color: var(--ink-soft); }
.sort-arrow { font-size: 8px; }
.song-table-body .col-artist,
.song-table-body .col-updated { padding: 3px 10px; font-size: 13px; }
.song-open {
  width: 100%;
  text-align: left;
  background: none;
  border: 0;
  padding: 5px 10px;
  cursor: pointer;
  font: inherit;
  font-size: 14px;
  font-weight: 600;
}
.song-meta-mobile { display: none; padding: 0 10px 5px; }
.song-tools { display: inline-flex; gap: 3px; padding: 3px 10px; }
.col-tools { display: flex; justify-content: flex-end; }
.empty { text-align: center; color: var(--ink); margin-top: 18vh; }

/* Below 560px there's nowhere to put an artist column; fold it into a second
   line under the title instead, and drop to three grid tracks. */
@media (max-width: 560px) {
  .song-row { grid-template-columns: 1fr 92px 100px; }
  .col-artist { display: none; }
  .song-meta-mobile { display: block; font-size: 11px; }
}

/* "+ New song" asks how you are starting (library.js). */
.new-song { position: relative; display: inline-flex; }
.new-song-menu {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  z-index: 40;
  display: flex;
  flex-direction: column;
  gap: 4px;
  width: 290px;
  padding: 6px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.14);
}
.new-song-choice {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
  min-height: 52px;
  padding: 8px 12px;
  font: inherit;
  text-align: left;
  color: inherit;
  background: none;
  border: none;
  border-radius: 5px;
  cursor: pointer;
}
.new-song-choice:hover, .new-song-choice:focus { outline: none; background: var(--accent-soft); }
.new-song-choice strong { font-size: 14px; font-weight: 600; }

/* --- status --------------------------------------------------------- */

/* The message lives in the toolbar of whatever screen is showing (see
   statusline.js), in space the toolbar already had, so it never covers a
   control. It takes whatever width is spare and gives it up first. */
.status-slot {
  flex: 1 1 0;
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  text-align: center;
  font-size: 12px;
  color: var(--ink-soft);
  opacity: 0;
}
.status-slot.visible { opacity: 1; }

/* Only for a screen with no toolbar to put it in — reading full screen — and
   at the top there, clear of the controls along the bottom. */
.status {
  position: fixed;
  left: 50%;
  top: max(10px, env(safe-area-inset-top));
  transform: translateX(-50%) translateY(-12px);
  background: #14161a;
  color: #fff;
  padding: 8px 14px;
  border-radius: 20px;
  font-size: 13px;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.15s, transform 0.15s;
  /* Above the full-screen Map (z-index 60). Below it, every message the Map
     sets — which beat tracker ran, what the drum check did, where bar 1 went —
     was drawn behind the Map and never seen. */
  z-index: 70;
}
.status.visible { opacity: 1; transform: translateX(-50%) translateY(0); }

/* --- audio dock ----------------------------------------------------- */

#audio-dock {
  flex: 0 0 auto;
  border-top: 1px solid var(--line);
  background: var(--paper);
  padding: 6px 12px;
  padding-bottom: max(6px, env(safe-area-inset-bottom));
}
#audio-dock[hidden] { display: none; }

.audio-bar { display: flex; align-items: center; gap: 8px; }
.au-clock { font-variant-numeric: tabular-nums; white-space: nowrap; min-width: 84px; }
.au-wave {
  flex: 1 1 auto;
  height: 40px;
  min-width: 80px;
  cursor: pointer;
  border-radius: 4px;
  background: #fafbfc;
  border: 1px solid var(--line-soft);
}

.audio-panel { margin-top: 8px; display: flex; flex-direction: column; gap: 6px; }
.marker-list { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 6px; }
.marker-list li {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  border: 1px solid var(--line);
  border-radius: 20px;
  padding: 2px 4px 2px 2px;
}
.marker-name { font-size: 12px; padding-right: 4px; }

/* the section the recording is currently in */
.chart-section.playing { background: #fff6de; box-shadow: inset 3px 0 0 #d08a1f; }
.phrase.playing { outline: 2px solid #d08a1f; outline-offset: 1px; }

/* --- groove editor --------------------------------------------------- */

.groove-editor {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--paper);
  padding: 8px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.ge-preview {
  display: flex;
  justify-content: center;
  padding: 4px 2px 6px;
  border-bottom: 1px dashed var(--line);
  overflow-x: auto;
}
.ge-preview-empty { padding: 8px; }

.ge-controls { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.ge-zoom { display: inline-flex; align-items: center; gap: 4px; }
.ge-controls label { display: inline-flex; align-items: center; gap: 5px; font-size: 12px; color: var(--ink-soft); }
.ge-controls select, .ge-controls input { min-height: 30px; font-size: 13px; }
.ge-controls input[type="number"] { width: 58px; }
.ge-controls .ge-swing.disabled { opacity: 0.45; }

/* A wider-than-one-bar groove (or a high zoom level, see .ge-zoom) can need
   more width than the panel has — this is what lets it scroll rather than
   crush every cell to fit. All rows share one scrolling box, so they stay
   aligned with each other as it scrolls; the label column is pinned to the
   left edge of it (position: sticky) so it never scrolls out of view along
   with the cells it names. */
.ge-grid {
  display: flex; flex-direction: column; gap: 3px; overflow-x: auto;
  /* Column widths are measured against this box (see cellColumns in
     grooveeditor.js); --ge-label-room is what the row name, the gap after it
     and the two edge lines take out of it. */
  container-type: inline-size;
  --ge-label-room: 90px;
}
.ge-row { display: flex; align-items: stretch; gap: 6px; position: relative; }

.ge-label {
  position: sticky;
  left: 0;
  z-index: 2;
  flex: 0 0 78px;
  width: 78px;
  font: 600 11px/1.1 inherit;
  text-align: left;
  color: var(--ink-soft);
  background: var(--paper);
  border: 1px solid transparent;
  border-radius: 4px;
  padding: 2px 4px;
  cursor: pointer;
}
.ge-label:hover { background: var(--line-soft); border-color: var(--line); }
.ge-label.static { cursor: default; }
.ge-label.static:hover { background: none; border-color: transparent; }

.ge-cells {
  display: grid;
  flex: 0 0 auto;
  border-left: 2px solid var(--ink);
  border-right: 2px solid var(--ink);
  min-width: 0;
  position: relative;
}

.ge-cell {
  position: relative;
  min-width: 0;
  height: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 0;
  border-right: 1px solid var(--line-soft);
  background: transparent;
  cursor: pointer;
  padding: 0;
  font-size: 14px;
  line-height: 1;
  color: var(--ink);
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}
.ge-cell:last-child { border-right: 0; }
.ge-cell.beat { border-left: 1px solid var(--line); background: #fbfbfd; }
.ge-cell.barline { border-left: 2px solid var(--ink); }
.ge-cell:hover { background: var(--accent-soft); }
.ge-cell.on { color: #000; }
.ge-cell.w-ghost .glyph { font-size: 10px; opacity: 0.55; }
.ge-cell.w-accent .glyph { font-weight: 800; }
.ge-cell.menu-open { background: var(--accent-soft); }

.ge-row.counts .ge-cell,
.ge-count {
  height: 14px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 9px;
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
}
.ge-count.beat { color: var(--ink-soft); font-weight: 700; }
.ge-row.counts .ge-cells { border-color: transparent; }

/* the long-press / right-click menu, placed on the screen by placeGrooveMenu */
.ge-menu {
  position: fixed;
  z-index: 50;
  top: 0;
  left: 0;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 6px;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.16);
  padding: 3px;
  display: flex;
  flex-direction: column;
  min-width: 132px;
  text-align: left;
}
.ge-menu-item {
  display: flex;
  align-items: center;
  gap: 7px;
  font: inherit;
  font-size: 12px;
  text-align: left;
  background: none;
  border: 0;
  border-radius: 4px;
  padding: 6px 8px;
  cursor: pointer;
  white-space: nowrap;
  color: var(--ink);
}
.ge-menu-item:hover { background: var(--accent-soft); }
.ge-menu-item.danger { color: var(--danger); }
.ge-menu-glyph { width: 14px; text-align: center; }

.groove-import { margin-top: 2px; }
.groove-import summary {
  font-size: 12px;
  color: var(--ink-soft);
  cursor: pointer;
  padding: 4px 0;
}
.groove-import[open] summary { margin-bottom: 6px; }

@media (max-width: 560px) {
  .ge-label { flex-basis: 58px; width: 58px; font-size: 10px; }
  .ge-grid { --ge-label-room: 70px; }
  .ge-cell { height: 34px; }
}

/* play-time slashes */
.ge-row.slashes { margin-bottom: 2px; }
.ge-row.slashes .ge-cells { border-color: var(--line); }
.ge-cell.slash { height: 22px; font-size: 15px; color: var(--ink-faint); }
.ge-cell.slash.on { color: #000; background: #eef3fb; }
.ge-cell.under-slash { opacity: 0.32; }

/* --- the recording workspace ----------------------------------------- */

body.audio-view-open { overflow: hidden; }

.audio-view {
  position: fixed;
  inset: 0;
  z-index: 60;
  background: var(--chrome);
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: max(10px, env(safe-area-inset-top)) max(12px, env(safe-area-inset-right))
           max(10px, env(safe-area-inset-bottom)) max(12px, env(safe-area-inset-left));
}

.av-head { display: flex; align-items: baseline; gap: 10px; flex: 0 0 auto; }
.av-head h2 { margin: 0; font-size: 17px; }

.av-transport {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  flex: 0 0 auto;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 7px 10px;
}
.av-clock { font-variant-numeric: tabular-nums; font-size: 13px; color: var(--ink-soft); min-width: 96px; }

.av-speed, .av-zoom, .av-loop {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  color: var(--ink-soft);
}
.av-speed input[type="range"] { width: 130px; }
.av-speed-value, .av-zoom-value { font-variant-numeric: tabular-nums; min-width: 34px; text-align: center; color: var(--ink); }
.btn.small.set { border-color: var(--accent); color: var(--accent); }

.av-body {
  flex: 1 1 auto;
  display: flex;
  gap: 8px;
  min-height: 0;
}
.av-wave-col {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.av-sections {
  flex: 0 0 180px;
  width: 180px;
  overflow-y: auto;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 4px;
}
.av-sections-empty { margin: 8px 6px; }
.av-section-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.av-section-row {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 4px 6px;
  border-radius: 5px;
  cursor: pointer;
  font-size: 12px;
}
.av-section-row:hover { background: rgba(31, 95, 208, 0.07); }
.av-section-name {
  flex: 1 1 auto;
  min-width: 0;
  border: none;
  background: none;
  font: inherit;
  font-weight: 600;
  color: inherit;
  padding: 2px 3px;
  border-radius: 3px;
  text-overflow: ellipsis;
}
.av-section-name:hover, .av-section-name:focus { outline: none; background: rgba(31, 95, 208, 0.08); }
.av-section-row .name-field { flex: 1 1 auto; min-width: 0; display: flex; align-items: center; }

/* The section name field's ▾ and the menu of names it opens (sectionlabel.js). */
.name-field-toggle {
  flex: 0 0 auto;
  width: 22px;
  height: 22px;
  padding: 0;
  border: none;
  border-radius: 4px;
  background: none;
  color: var(--ink-soft);
  font-size: 12px;
  line-height: 1;
  cursor: pointer;
  opacity: 0.45;
}
.name-field:hover .name-field-toggle,
.name-field:focus-within .name-field-toggle,
.name-field-toggle:focus-visible { opacity: 1; }
.name-field-toggle:hover { background: rgba(31, 95, 208, 0.1); color: var(--accent); }
@media (hover: none) { .name-field-toggle { opacity: 0.8; width: 28px; height: 28px; } }
.name-menu {
  position: fixed;
  z-index: 80;
  display: flex;
  flex-direction: column;
  min-width: 140px;
  max-height: calc(100vh - 16px);
  overflow-y: auto;
  padding: 4px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.14);
  text-transform: none;
  letter-spacing: normal;
}
.name-menu-item {
  text-align: left;
  font: inherit;
  font-size: 13px;
  padding: 6px 10px;
  border: none;
  border-radius: 4px;
  background: none;
  color: inherit;
  cursor: pointer;
}
.name-menu-item:hover, .name-menu-item:focus { outline: none; background: var(--accent-soft); }
.name-menu-item.current { font-weight: 600; color: var(--accent); }
.av-section-count {
  flex: 0 0 auto;
  min-width: 1.6em;
  text-align: right;
  font-variant-numeric: tabular-nums;
  font-size: 11px;
  color: var(--ink-soft);
}
.av-section-time {
  flex: 0 0 auto;
  width: 3em;
  text-align: right;
  font-variant-numeric: tabular-nums;
  font-size: 11px;
  color: var(--ink-soft);
}

.av-overview-wrap {
  position: relative;
  flex: 0 0 54px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  cursor: pointer;
  touch-action: none;
}
.av-overview { display: block; width: 100%; height: 100%; }
.av-viewport {
  position: absolute;
  top: 0;
  bottom: 0;
  border: 2px solid var(--accent);
  background: rgba(31, 95, 208, 0.08);
  pointer-events: none;
  border-radius: 3px;
}

.av-stage {
  position: relative;
  flex: 1 1 auto;
  min-height: 160px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  cursor: crosshair;
  touch-action: none;
}
.av-wave { display: block; width: 100%; height: 100%; }

.av-flags { position: absolute; inset: 0; pointer-events: none; z-index: 2; }
.av-flag {
  position: absolute;
  top: 6px;
  /* set per flag by positionFlags, which deals overlapping ones into rows */
  transform: translateX(-2px);
  display: flex;
  align-items: center;
  gap: 5px;
  background: #14161a;
  color: #fff;
  border-radius: 4px;
  padding: 3px 6px;
  font-size: 11px;
  white-space: nowrap;
  pointer-events: auto;
  cursor: grab;
  touch-action: none;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.25);
}
.av-flag:active { cursor: grabbing; }
.av-flag-name { font-weight: 600; }
.av-flag-time { opacity: 0.65; font-variant-numeric: tabular-nums; }
.av-flag-x {
  background: none;
  border: 0;
  color: #fff;
  opacity: 0.6;
  cursor: pointer;
  font-size: 13px;
  line-height: 1;
  padding: 0 1px;
}
.av-flag-x:hover { opacity: 1; }

/* A manual meter change — not draggable (see meterMarkFlagFor), so no grab
   cursor, and a distinct color (the palette's --warn) from a section's. */
.av-flag-meter { background: var(--warn); cursor: default; }

/* Above section flags (z-index 2) — in Edit beats mode a beat under a flag
   should still be the thing a click lands on, not the flag sitting near it. */
.av-beat-handles { position: absolute; inset: 0; pointer-events: none; z-index: 3; }
.av-beat-handle {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 10px;
  transform: translateX(-5px);
  cursor: grab;
  touch-action: none;
  pointer-events: auto;
}
.av-beat-handle::before {
  content: '';
  position: absolute;
  left: 4px;
  top: 0;
  bottom: 0;
  width: 2px;
  background: #1f5fd0;
  opacity: 0.5;
}
.av-beat-handle::after {
  content: '';
  position: absolute;
  left: 1px;
  top: 2px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #1f5fd0;
}
.av-beat-handle:hover::before { opacity: 0.9; }
.av-beat-handle:active { cursor: grabbing; }
.av-beat-handle:active::before { opacity: 1; }

/* Downbeats warp the grid instead of moving one beat, so they get their own
   colour and a bigger grip — the thing worth reaching for first. */
.av-beat-handle.downbeat { z-index: 1; width: 14px; transform: translateX(-7px); }
.av-beat-handle.downbeat::before { left: 6px; width: 2.5px; background: #b3641e; opacity: 0.7; }
.av-beat-handle.downbeat::after { left: 2px; width: 11px; height: 11px; background: #b3641e; }
.av-beat-handle.downbeat:hover::before, .av-beat-handle.downbeat:active::before { opacity: 1; }

/* A frozen downbeat can't be dragged — click it to unfreeze rather than a
   separate control, so solid and dark (not faded) is what "click again to
   undo this" looks like here, matching the flags' own dark, definite fill,
   rather than reading as disabled or faded out. */
.av-beat-handle.downbeat.frozen { cursor: pointer; }
.av-beat-handle.downbeat.frozen::before { background: #14161a; opacity: 0.85; }
.av-beat-handle.downbeat.frozen::after {
  background: #14161a;
  opacity: 1;
  box-shadow: 0 0 0 3px rgba(20, 22, 26, 0.22);
}

/* The playhead's own grip, separate from the beat grid's (above) — a drag
   here always moves the playhead, whatever a plain drag on the stage itself
   currently means (pan on a touch, scrub for a mouse). Above the beat
   handles (z-index 4 vs 3) since it is the one you reach for most and a beat
   sitting right at the playhead should never steal the touch. The triangle
   flag at the top is the grabbable part; the hairline continues the red the
   canvas already draws the playhead in, so the two read as one mark. */
.av-playhead-handle {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 22px;
  transform: translateX(-11px);
  cursor: grab;
  touch-action: none;
  pointer-events: auto;
  z-index: 4;
}
.av-playhead-handle::before {
  content: '';
  position: absolute;
  left: 10px;
  top: 0;
  bottom: 0;
  width: 2px;
  background: #b3261e;
  opacity: 0;
}
.av-playhead-handle::after {
  content: '';
  position: absolute;
  left: 3px;
  top: 0;
  width: 16px;
  height: 12px;
  background: #b3261e;
  clip-path: polygon(0 0, 100% 0, 50% 100%);
}
.av-playhead-handle:hover::before,
.av-playhead-handle:active::before { opacity: 0.6; }
.av-playhead-handle:active { cursor: grabbing; }

.av-markbar {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  flex: 0 0 auto;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 8px 10px;
}
.btn.big-mark { font-size: 15px; padding: 10px 16px; min-height: 44px; }
.av-queue { display: inline-flex; gap: 5px; flex-wrap: wrap; }
.av-queue-item {
  font-size: 11px;
  background: var(--line-soft);
  color: var(--ink-soft);
  border-radius: 20px;
  padding: 3px 9px;
}
.av-queue-item.more { background: transparent; }
.av-follow { display: inline-flex; align-items: center; gap: 5px; font-size: 12px; color: var(--ink-soft); }

@media (max-width: 700px) {
  .av-transport { gap: 7px; padding: 6px 8px; }
  .av-speed input[type="range"] { width: 92px; }
  .av-head h2 { font-size: 15px; }
}

/* the marker palette */
.av-mark-label { font-size: 12px; color: var(--ink-soft); white-space: nowrap; }
.av-palette { display: flex; gap: 5px; flex-wrap: wrap; flex: 1 1 auto; }
.btn.mark-kind { font-size: 12px; padding: 6px 11px; min-height: 36px; }
.btn.mark-kind.custom { border-style: dashed; }
.av-hint { white-space: nowrap; }

/* the dock can be dragged taller */
/* The dock is a column so the bar — and the waveform inside it — grow when the
   dock is dragged taller. */
#audio-dock { display: flex; flex-direction: column; min-height: 0; }
#audio-dock .audio-bar { flex: 1 1 auto; align-items: stretch; min-height: 0; }
#audio-dock .audio-bar > .btn,
#audio-dock .audio-bar > .au-clock { align-self: center; }
#audio-dock .audio-panel { flex: 0 0 auto; }
.au-grip {
  flex: 0 0 auto;
  height: 9px;
  margin: -2px 0 2px;
  cursor: ns-resize;
  position: relative;
  touch-action: none;
}
.au-grip::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 3px;
  transform: translateX(-50%);
  width: 42px;
  height: 3px;
  border-radius: 3px;
  background: var(--line);
}
.au-grip:hover::before { background: var(--ink-faint); }
/* The waveform takes whatever height the dock has been dragged to. Note the
   bar must be allowed to grow — an earlier rule pinning it to flex:0 0 auto is
   what stopped the waveform following the drag. */
#audio-dock .au-wave { flex: 1 1 auto; height: auto; min-height: 40px; }

.av-markbar.naming { outline: 2px solid var(--accent); outline-offset: -2px; }
.btn.mark-kind.danger { color: var(--danger); border-color: #f2c9c6; }

/* cued hits — the figure the band plays */
.ge-row.cues { margin-bottom: 1px; }
.ge-row.cues .ge-cells { border-color: var(--line); }
.ge-cell.cue { height: 20px; font-size: 11px; color: var(--ink-faint); }
.ge-cell.cue.on { color: #000; background: #fdf3e0; }

/* the column that is sounding while a groove loops */
.ge-cell.sounding { box-shadow: inset 0 0 0 2px var(--accent); }

/* a written hit, briefly lit because a MIDI kit just struck that voice */
.ge-cell.midi-hit { background: var(--accent-soft); transition: background 0.18s ease-out; }
.ge-controls label input[type="number"] { width: 62px; }

/* the beat grid controls */
.av-beat { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; color: var(--ink-soft); }
.av-bpm { font-variant-numeric: tabular-nums; font-weight: 600; color: var(--ink); }
/* Map's notehead picker — the shared one out of chart.js, which keeps the
   engraved glyph out of the native option list (see .note-pick there). The
   hover lives on the wrapper now, since the control itself is invisible. */
.av-beat .note-pick { border-radius: 3px; padding: 1px 4px; margin: -1px -2px; }
.av-beat .note-pick:hover,
.av-beat .note-pick:focus-within { background: rgba(31, 95, 208, 0.08); }
.av-beat .note-pick-face { font-weight: 600; color: var(--ink); }
.av-timesig-select {
  border: 1px solid var(--line); background: var(--paper); font: inherit; color: inherit;
  padding: 3px 5px; border-radius: 5px; cursor: pointer; font-size: 12px;
}

/* In the Mark here row. Only as wide as its closed label, "Trim…" — the
   options are longer, but only show once it is open. */
.av-trim-select {
  width: 6em; min-height: 36px;
  border: 1px dashed var(--line); background: var(--paper); font: inherit; color: inherit;
  padding: 3px 8px; border-radius: var(--radius); cursor: pointer; font-size: 12px;
}

.av-click-controls { display: inline-flex; align-items: center; gap: 5px; }
.av-click-volume { width: 96px; }
.av-click-level { min-width: 30px; font-variant-numeric: tabular-nums; }
.av-nudge { display: inline-flex; align-items: center; gap: 3px; }
.av-nudge-value { min-width: 44px; text-align: center; font-variant-numeric: tabular-nums; }
.av-bpm-range { font-weight: 400; color: var(--ink-soft); }
.av-bpm-fix { margin-left: 5px; padding: 1px 6px; min-height: 20px; font-size: 11px; font-weight: 600; vertical-align: 1px; }

/* the overview box is a handle when zoomed in */
.av-viewport { pointer-events: auto; cursor: grab; }
.av-viewport:active { cursor: grabbing; background: rgba(31, 95, 208, 0.16); }

/* the bar sounding while a chart plays */
.sounding-bar { box-shadow: inset 0 0 0 2px var(--accent); border-radius: 4px; }

/* what is playing, and how far through it is */
.play-progress { display: inline-flex; align-items: center; gap: 6px; }
.play-progress-track {
  width: 110px;
  height: 5px;
  border-radius: 3px;
  background: var(--line);
  overflow: hidden;
}
.play-progress-fill {
  display: block;
  height: 100%;
  width: 0;
  background: var(--accent);
  transition: width 0.12s linear;
}
.play-progress-label { white-space: nowrap; font-variant-numeric: tabular-nums; }

.av-adjust { display: inline-flex; align-items: center; gap: 3px; }

/* where the selection falls in the recording */
.btn.locate { font-variant-numeric: tabular-nums; }

/* what "play" means: the kit alone, the record alone, or both together */
.play-mode { display: inline-flex; gap: 2px; }
.play-mode .btn { border-radius: 0; }
.play-mode .btn:first-child { border-radius: 4px 0 0 4px; }
.play-mode .btn:last-child { border-radius: 0 4px 4px 0; }
.play-mode .btn[disabled] { opacity: 0.4; cursor: not-allowed; }

/* importing an isolated drum track to settle the beat grid */
.av-drums { display: inline-flex; }

/* the metronome toggle, shared by the Build toolbar and the reading controls */
.click-toggle { display: inline-flex; align-items: center; gap: 6px; }

/* --- the mixer -------------------------------------------------------- */

.mix { position: relative; display: inline-flex; }
.mixer-panel {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  z-index: 40;
  min-width: 210px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 9px 10px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.18);
}
.mix-row { display: flex; align-items: center; gap: 8px; }
.mix-row .mix-fader { flex: 1 1 auto; }
.mix-fader { display: flex; align-items: center; gap: 7px; font-size: 12px; color: var(--ink-soft); }
.mix-name { flex: 0 0 52px; }
.mix-fader input[type="range"] { flex: 1 1 auto; min-width: 70px; }
.mix-value { flex: 0 0 34px; text-align: right; font-variant-numeric: tabular-nums; }
.mix-choices { display: inline-flex; gap: 4px; }

/* A lyric note in Build reads as the words it is, so the two panes agree. */
.annotation.style-lyric input {
  font-family: Georgia, "Iowan Old Style", "Times New Roman", serif;
  font-style: italic;
  color: #7a3d8f;
}
