/* =============================================================================
   renderer.css — the CANONICAL Songbook renderer styles (2026-08-17)
   -----------------------------------------------------------------------------
   This file is the visual half of the canonical renderer that lives in this
   repo (assets/mac/songbook.js + guitar.js). The Mac app loads it from here;
   the WEBSITE receives a byte-identical published copy at
   assets/css/songbook-app.css via scripts/publish-site.sh — the site is the
   viewing surface, this repo is the authoring surface, and the styles flow
   one way: app -> site. Never edit the site's copy directly.

   Everything in here styles what the renderer DRAWS — the chart, the degree
   system, word timing, the edit workspace, the quick switcher, the reference
   overlay, the wave band. Mac window chrome (toolbar integration, the notes
   disclosure, key-window desaturation) stays in mac.css, which is app-only.
============================================================================= */

/* ------------------------------------------------- chart density and rows */
/* The staff at ~2/3 height (MUST match ROW/NAME_H/FOOT_H in layout.js —
   the base sheet's 11/22/16 originals are overridden here). */
.sb {
  --row: 7.5px;
  --name-h: 20px;
  --foot-h: 13px;
  --staff-h: 37.5px;
}
.sb { gap: 6px; }
.sb.compact { gap: 4px; }
.sb-head { padding-bottom: 6px; }
.sb.compact .sb-head { padding-bottom: 4px; }
.sb.compact .sb-act { gap: 5px; }

/* The shapes and practice rows are strips of small type with generous air above
   and below them. In a window that trades every spare pixel for another system,
   they give some back without losing a line. */
.sb-shapes { padding: 0; gap: 12px; }
.sb-setup { padding: 0; }

/* ------------------------------------------- 2. rows: definition, then density */
/* A hairline between systems, and the 13px of blank closes to 9. The rule sits
   ABOVE each system — between the previous row's lyrics and this row's staff,
   which is the boundary the eye was having to infer from whitespace alone — and
   it is centred in what is left rather than run flush against the lyrics it is
   separating from, which would read as an underline on the words instead of a
   boundary between rows.

   9% and not more: the staff's own six lines are 26% and --line is 15%, so this
   stays the faintest rule on the page. It is a boundary, not notation. */
.sb-system {
  margin-top: 2px;
  padding-top: 3px;
  border-top: 1px solid color-mix(in srgb, var(--fg) 9%, transparent);
}
.sb-system:first-child { margin-top: 0; padding-top: 1px; border-top: 0; }
.sb-secs { height: 16px; }
/* The section's colour: a bar at the foot of the label band, touching the
   staff it governs, under the label that names it. */
.sb-secbar {
  position: absolute; bottom: 0; height: 2.5px; border-radius: 99px;
  background: color-mix(in srgb, var(--fg) 18%, transparent);
}
.sb-secbar[data-kind="verse"]      { background: color-mix(in srgb, var(--c-cyan-1, #0891b2) 55%, transparent); }
.sb-secbar[data-kind="pre-chorus"] { background: color-mix(in srgb, var(--c-violet-1, #7c3aed) 55%, transparent); }
.sb-secbar[data-kind="chorus"]     { background: color-mix(in srgb, var(--c-amber-1, #d97706) 55%, transparent); }
.sb-secbar[data-kind="bridge"]     { background: color-mix(in srgb, var(--c-mint-1, #059669) 55%, transparent); }
.sb-secbar[data-kind="solo"]       { background: color-mix(in srgb, var(--c-rose-1, #e11d48) 55%, transparent); }
.sb-seclab { z-index: 2; }

/* Lyrics ride closer to the staff they belong to than to the rule below them:
   the block is nearer its own notation than the next system's, which is the
   other half of making a tighter row still read as one row. */
.sb-lyr { margin-top: 1px; }

/* The staff scroller keeps its own overscroll — flicking to the end of a long
   song should not rubber-band the window behind it. Horizontal geometry
   untouched: padding-right stays the site's 4px. */
.sb-systems { overscroll-behavior: contain; }


/* =============================================================================
   5. THE RENDERER EVOLUTION (2026-08-17) — styles for the forked renderer
   (assets/mac/songbook.js + guitar.js). Everything below belongs to features
   the site's stack does not have; nothing below overrides a copied file's
   rule by accident — it styles markup only the fork emits, plus the stated
   type upgrades.
============================================================================= */

/* ------------------------------------------------------ 5.1 the degree ramp */
/* One hue system for the whole app: scale degree N wears capo-N's hue from
   guitar.css (.tag-capo). I = blue, ii = teal, iii = green, IV = amber,
   V = ember, vi = red, vii = pink. The L values mirror the capo tags' own
   measured contrast fixes (168/140 drop to 20%). Degree 0 = a root the key
   cannot place (or no key) — neutral, never a wrong colour. */
[data-deg] { --deg-h: 200; --deg-l: 27%; }
[data-deg="2"] { --deg-h: 168; --deg-l: 20%; }
[data-deg="3"] { --deg-h: 140; --deg-l: 20%; }
[data-deg="4"] { --deg-h: 38; }
[data-deg="5"] { --deg-h: 20; }
[data-deg="6"] { --deg-h: 355; }
[data-deg="7"] { --deg-h: 330; }

/* The chord ON the staff: a rounded chip in its degree's colour, opaque so it
   knocks out the staff lines the way the bare name used to. */
.sb-cn[data-deg] {
  top: -3px;
  font-size: 11px; line-height: 1.3; padding: 1px 5px 2px;
  border-radius: 5px;
  background: color-mix(in srgb, hsl(var(--deg-h) 70% 48%) 10%, var(--bg));
  border: 1px solid color-mix(in srgb, hsl(var(--deg-h) 70% 48%) 26%, var(--bg));
  color: hsl(var(--deg-h) 72% var(--deg-l));
}
.sb-cn[data-deg="0"] {
  background: color-mix(in srgb, var(--fg) 7%, var(--bg));
  border-color: color-mix(in srgb, var(--fg) 24%, var(--bg));
  color: var(--fg);
}
/* Still held from the row above: the chip goes hollow — an echo, not a hit. */
.sb-cn.carry[data-deg] {
  background: var(--bg);
  border-style: dashed;
  color: color-mix(in srgb, hsl(var(--deg-h) 72% var(--deg-l)) 72%, var(--fg-mute));
}
/* The provenance dot keeps its meaning on top of the chip. */
.sb-ch.own .sb-cn::after { font-size: 9px; }

/* The same chip, inline — the inspector names the selected chord with it. */
.sb-degchip {
  display: inline-block; font-size: 11.5px; font-weight: 700; line-height: 1.3;
  padding: 1px 6px 2px; border-radius: 5px;
  background: color-mix(in srgb, hsl(var(--deg-h) 70% 48%) 10%, var(--bg));
  border: 1px solid color-mix(in srgb, hsl(var(--deg-h) 70% 48%) 26%, var(--bg));
  color: hsl(var(--deg-h) 72% var(--deg-l));
}

/* The shapes strip and the picker speak the same colour. A picked (on)
   chord fills with its degree at a depth white text survives on. */
.sb-shape[data-deg] b { color: hsl(var(--deg-h) 72% var(--deg-l)); }
.sb-pk[data-deg]:not([data-deg="0"]) {
  background: color-mix(in srgb, hsl(var(--deg-h) 82% 48%) 12%, transparent);
  color: hsl(var(--deg-h) 72% var(--deg-l));
}
.sb-pk[data-deg]:not([data-deg="0"]):hover {
  background: color-mix(in srgb, hsl(var(--deg-h) 82% 48%) 22%, transparent);
}
.sb-pk.on[data-deg]:not([data-deg="0"]) {
  background: hsl(var(--deg-h) 70% 34%);
  color: #fff;
}

/* --------------------------------------- 5.1b the chord ON the staff itself */
/* Take two (Ryder): the colour was landing on the NAME while the notation —
   the digit stack, the duration — stayed white boxes and mono. Now the whole
   chord is one designed object in its degree's colour:
     · a PLATE behind the fret digits, spanning the six lines at the onset —
       the plate does the knockout, so the digits stop being six separate
       white rectangles;
     · the digits themselves in the text face, semibold, in the degree's ink;
     · the DURATION as a colour capsule running from the chip to the release.
   The name chip sits flush over the plate: chip, plate, capsule — one shape. */
.sb-ch[data-deg] {
  --degc: hsl(var(--deg-h) 58% 46%);
  --degink: hsl(var(--deg-h) 72% var(--deg-l));
}
.sb-ch[data-deg="0"] {
  --degc: color-mix(in srgb, var(--fg) 42%, transparent);
  --degink: var(--fg);
}
.sb-plate {
  position: absolute; left: -3px; width: 18px;
  top: calc(var(--name-h) - 3px);
  height: calc(var(--staff-h) + 6px);
  border-radius: 4px; pointer-events: none;
  background: color-mix(in srgb, var(--degc) 7%, var(--bg));
  border: 1px solid color-mix(in srgb, var(--degc) 18%, var(--bg));
  box-shadow: inset 2px 0 0 color-mix(in srgb, var(--degc) 30%, transparent);
}
/* Digits live ON the plate: text face, degree ink, no boxes of their own. */
.sb-ch[data-deg] .sb-frets i {
  font: 700 7px/1 var(--sans, inherit);
  background: none; padding: 0;
  left: -3px; min-width: 18px; text-align: center;
  color: var(--degink);
}
.sb-ch[data-deg] .sb-frets i.x {
  color: color-mix(in srgb, var(--degink) 45%, transparent);
  font-weight: 500; opacity: 1;
}
/* HITS, redrawn for the slim staff (the old white per-glyph boxes smeared
   at the 7.5px pitch): one slim NEUTRAL plate, ×s in the text face on the
   struck strings, and a neutral × chip on top. A strike is a point in time,
   marked the traditional way. */
.sb-plate.hitplate {
  left: -2px; width: 12px;
  top: calc(var(--name-h) - 3px);
  height: calc(var(--staff-h) + 6px);
  background: color-mix(in srgb, var(--fg) 5%, var(--bg));
  border: 1px solid color-mix(in srgb, var(--fg) 15%, var(--bg));
  box-shadow: none;
}
.sb-ch.hit .sb-frets i,
.sb-ch.hit .sb-frets i.x {
  font: 600 7px/1 var(--sans, inherit);
  background: none; padding: 0;
  left: -2px; min-width: 12px; text-align: center;
  color: color-mix(in srgb, var(--fg) 70%, transparent);
  opacity: 1; font-weight: 600;
}
.sb-cn.hitmark {
  top: -3px; left: -2px;
  font: 700 10px/1.3 var(--sans, inherit);
  padding: 1px 4px 2px; border-radius: 5px;
  background: color-mix(in srgb, var(--fg) 7%, var(--bg));
  border: 1px solid color-mix(in srgb, var(--fg) 22%, var(--bg));
  color: var(--fg-dim);
}
/* The editor's grey slab behind a selected/armed hit is gone too. */
.sb.editing .sb-ch.hit { background: none; box-shadow: none; }
.sb.editing .sb-ch.hit.sel .sb-plate.hitplate {
  border-color: var(--accent);
  box-shadow: inset 2px 0 0 var(--accent);
}
/* NO duration bar (Ryder, 2026-08-17): "a chord is just a chord hit in
   space/time. this isn't a DAW, it's a songbook." The chip and plate mark
   the strike; the length still lives in the editor (Length row, alt-arrows,
   the end-grab) — it is simply not drawn as a held ribbon. This also kills
   the base sheet's grey gradient rule. */
.sb-dur { display: none; }
/* The chip aligns with its plate's left edge. */
.sb-cn[data-deg]:not(.flip):not(.carry) { left: -4px; }
/* Selection reads on the plate, not as six rings around six digits. */
.sb-ch.sel .sb-frets i { box-shadow: none; }
.sb-ch.sel .sb-plate {
  border-color: var(--accent);
  box-shadow: inset 2px 0 0 var(--accent),
              0 0 0 1px color-mix(in srgb, var(--accent) 40%, transparent);
}
/* Tab digits and melody notes join the text face — the mono was the
   "computer-science" look; a chart is read, not compiled. */
.sb-tn, .sb-mn { font: 650 9px/1 var(--sans, inherit); border-radius: 2px; padding: 0.5px 2px; }

/* --------------------------------------------------------- 5.2 lyric type */
/* The reading surface earns real type: a half-point up in size, medium
   weight, full ink. LYR_PX in assets/mac/songbook.js MUST match --lyr here —
   placement measures text in exactly this face. */
.sb { --lyr: 12.5px; }
.sb-lyric {
  line-height: 1.3; font-weight: 500; letter-spacing: .004em;
  color: var(--fg);
  font-variant-ligatures: contextual;
}

/* The melisma extender: a word held past its letters draws its rule out to
   the beat it releases on, with a small tick at the release. */
.sb-lyric.melisma { display: flex; align-items: baseline; white-space: nowrap; overflow: hidden; }
.sb-lyric.melisma > .sb-ext {
  flex: 1 1 auto; min-width: 0; height: 4px;
  align-self: flex-end; margin: 0 3px 4px 5px;
  border-bottom: 1.5px solid color-mix(in srgb, var(--fg) 38%, transparent);
}
/* A tail that is pure held time (no words carried) is rule from edge to
   release — the en-dash on its head already says the word continues. */
.sb-lyric.tail.melisma { min-height: 12px; }
/* The words ride in .sb-lt so the melisma flex row has exactly two items:
   the text, then the rule. */
.sb-lt { min-width: 0; }
.sb-lyric.melisma > .sb-lt { flex: 0 0 auto; }

/* ------------------------------------------------ 5.2b word-level timing */
/* Every word is its own object while editing: drag it to its beat, hold it
   to its release. Timed words carry a spine; held words carry their rule. */
.sb-w { text-decoration: none; }
/* METRIC-NEUTRAL, by law: edit mode only ADDS — indicators paint with
   box-shadow/background and never with padding or borders that would shift
   a single glyph off its play-mode position. */
.sb.editing .sb-w { border-radius: 2px; cursor: grab; }
.sb.editing .sb-w:hover { background: color-mix(in srgb, var(--accent) 18%, transparent); }
.sb.editing .sb-w:active { cursor: grabbing; }
.sb-w.timed { box-shadow: inset 0 -2px 0 color-mix(in srgb, var(--accent) 75%, transparent); }
.sb-w.held { box-shadow: inset 0 -2px 0 color-mix(in srgb, var(--fg) 40%, transparent); }
.sb-w.timed.held {
  box-shadow: inset 0 -2px 0 color-mix(in srgb, var(--accent) 75%, transparent),
              inset 0 -4px 0 color-mix(in srgb, var(--fg) 30%, transparent);
}
.sb-w.on { background: var(--accent); color: var(--accent-fg); box-shadow: none; }
.sb-w.dragging { opacity: .35; }
/* A word-timed segment marks its own start while editing. */
.sb.editing .sb-lyric.seg {
  box-shadow: inset 2px 0 0 color-mix(in srgb, var(--accent) 45%, transparent);
}
/* The ghost, wearing a dragged word: it rides at the foot of the stage,
   where the lyric will actually land. */
.sb-ghost.word {
  top: auto; bottom: -4px;
  font: 600 12px/1.2 var(--sans, inherit);
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 10%, var(--bg));
  padding: 1px 4px 2px; border-radius: 3px;
}

/* The panel's word chips and steppers. */
.sb-words { display: flex; flex-wrap: wrap; gap: 3px; min-width: 0; }
.sb-wchip {
  font: 500 11.5px/1.3 var(--sans, inherit);
  padding: 2px 7px 3px; border-radius: 4px;
  border: 1px solid var(--line); background: var(--bg);
  color: var(--fg-dim); cursor: pointer;
  transition: background 120ms ease, border-color 120ms ease;
}
.sb-wchip:hover { background: var(--chip); color: var(--fg); }
.sb-wchip.timed {
  border-color: color-mix(in srgb, var(--accent) 55%, transparent);
  box-shadow: inset 2px 0 0 var(--accent);
  color: var(--fg);
}
.sb-wchip.held { border-bottom: 2px solid color-mix(in srgb, var(--fg) 45%, transparent); }
.sb-wchip.on { background: var(--accent); border-color: var(--accent); color: var(--accent-fg); }
.sb-wctl { align-items: center; }
.sb-wval {
  font: 500 10.5px var(--mono);
  color: var(--fg); font-variant-numeric: tabular-nums;
  min-width: 86px; text-align: center;
}

/* ------------------------------------------------- 5.3 the edit workspace */
/* The staff and the docked panel share the working row; only the staff
   scrolls. songbook.css gave `.sb > .sb-systems` the flexible slot — the
   fork wraps both in .sb-work, which takes that slot instead. */
.sb > .sb-work { flex: 1 1 0; display: flex; min-height: 0; position: relative; }
.sb-work > .sb-systems { flex: 1 1 auto; min-width: 0; }

/* The panel FLOATS (absolute) — entering edit mode must not move one pixel
   of the chart. Translucent + blurred so the staff's edge stays legible
   under it; the tab collapses it entirely. */
.sb-editpanel {
  position: absolute; top: 0; right: 0; bottom: 0; width: 262px; z-index: 60;
  min-height: 0; overflow-y: auto;
  display: flex; flex-direction: column; gap: 7px;
  padding: 7px;
  background: color-mix(in srgb, var(--bg-elev) 90%, transparent);
  -webkit-backdrop-filter: blur(9px) saturate(1.05);
  backdrop-filter: blur(9px) saturate(1.05);
  border: 1px solid var(--line);
  border-radius: 6px;
  box-shadow: 0 10px 34px color-mix(in srgb, #000 14%, transparent);
  animation: sb-ep-in 220ms cubic-bezier(.32, .72, 0, 1);
}
.sb-ep-collapse {
  position: absolute; top: 5px; right: 7px; z-index: 5;
  font: 700 12px/1 var(--sans, inherit);
  width: 20px; height: 20px; border: 0; border-radius: 4px;
  background: color-mix(in srgb, var(--fg) 6%, transparent);
  color: var(--fg-mute); cursor: pointer;
}
.sb-ep-collapse:hover { background: color-mix(in srgb, var(--fg) 12%, transparent); color: var(--fg); }
.sb-ep-tab {
  position: absolute; top: 6px; right: 0; z-index: 60;
  font: 600 10.5px/1 var(--sans, inherit); letter-spacing: .03em;
  padding: 7px 8px 7px 9px; border: 1px solid var(--line); border-right: 0;
  border-radius: 6px 0 0 6px;
  background: color-mix(in srgb, var(--bg-elev) 92%, transparent);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  color: var(--fg-dim); cursor: pointer;
}
.sb-ep-tab:hover { color: var(--fg); background: var(--bg-elev); }
/* Position only, never opacity: a frozen first frame (occluded windows
   suspend CSS animations) must still be a VISIBLE panel. */
@keyframes sb-ep-in {
  from { transform: translateX(14px); }
}
.sb-ep-sec {
  display: flex; flex-direction: column; align-items: flex-start; gap: 7px;
  padding: 8px 9px 10px;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 5px;
}
/* Selection holds its place while the selection changes — a fixed floor keeps
   Bars from jumping when a chord is picked or dropped. */
.sb-ep-selsec { min-height: 108px; }
.sb-ep-head {
  font-size: 9.5px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase;
  color: var(--fg-mute);
}
.sb-ep-head b { color: var(--fg); font-variant-numeric: tabular-nums; letter-spacing: 0; }
.sb-ep-row { display: flex; gap: 5px; flex-wrap: wrap; }
.sb-ep-hint { font-size: 10.5px; color: var(--fg-mute); line-height: 1.5; }

/* Units stack in the panel; the site laid them out in a row with dividers. */
.sb-editpanel .sb-unit,
.sb-editpanel .sb-unit + .sb-unit {
  display: flex; flex-wrap: wrap; align-items: center;
  border-left: 0; padding-left: 0; padding-right: 0;
}
.sb-editpanel .sb-pick { display: flex; flex-wrap: wrap; }
/* songbook.css scoped its disabled-dim to the old rows; the panel needs it too. */
.sb-editpanel .sb-tw[disabled] { opacity: .34; pointer-events: none; }
.sb-editpanel .sb-where { margin-left: 0; }
.sb-editpanel .sb-in { min-width: 0; }
.sb-editpanel .sb-unit.grow { flex: 0 0 auto; min-width: 0; width: 100%; }
.sb-editpanel .sb-cgrid { max-height: 220px; overflow-y: auto; width: 100%; }
.sb-editpanel .sb-seg { flex-wrap: wrap; }

/* ------------------------------------------- 5.4 sidebar visibility filter */
.sidebar-vis { display: flex; gap: 2px; padding: 0 10px 8px; }
.sidebar-vis button {
  flex: 1; font: 600 10px var(--sans, inherit); letter-spacing: .05em;
  padding: 3.5px 0 4.5px; border: 0; border-radius: 4px;
  background: none; color: var(--fg-mute); cursor: pointer;
  transition: background 130ms ease, color 130ms ease;
}
.sidebar-vis button:hover { background: color-mix(in srgb, var(--fg) 7%, transparent); color: var(--fg); }
.sidebar-vis button.active {
  background: color-mix(in srgb, var(--fg) 9%, transparent); color: var(--fg);
}

/* --------------------------------------------------- 5.5 the quick switcher */
.qswitch-backdrop {
  position: fixed; inset: 0; z-index: 200;
  background: color-mix(in srgb, #000 24%, transparent);
  -webkit-backdrop-filter: blur(7px) saturate(1.1); backdrop-filter: blur(7px) saturate(1.1);
  display: flex; justify-content: center; align-items: flex-start;
  padding-top: 11vh;
  animation: qs-fade 130ms ease;
}
@keyframes qs-fade { from { opacity: 0; } }
.qswitch {
  width: min(540px, 90vw);
  background: var(--bg-elev);
  border: 1px solid color-mix(in srgb, var(--fg) 18%, transparent);
  border-radius: 12px;
  box-shadow: 0 28px 80px color-mix(in srgb, #000 32%, transparent),
              0 2px 10px color-mix(in srgb, #000 18%, transparent);
  overflow: hidden;
  animation: qs-pop 190ms cubic-bezier(.32, .72, 0, 1);
}
@keyframes qs-pop { from { opacity: 0; transform: translateY(-10px) scale(.985); } }
.qswitch-in {
  width: 100%; box-sizing: border-box;
  font: 500 16px var(--sans, inherit); padding: 14px 17px;
  border: 0; outline: 0; background: none; color: var(--fg);
  border-bottom: 1px solid color-mix(in srgb, var(--fg) 10%, transparent);
}
.qswitch-in::placeholder { color: var(--fg-mute); }
.qswitch-list { max-height: 46vh; overflow-y: auto; padding: 6px; }
.qswitch-row {
  display: flex; align-items: baseline; gap: 9px;
  padding: 8px 11px; border-radius: 7px; cursor: pointer;
}
.qswitch-row .t { font-weight: 650; font-size: 13.5px; white-space: nowrap; }
.qswitch-row .a {
  flex: 1; color: var(--fg-mute); font-size: 11.5px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.qswitch-row .tags { display: inline-flex; gap: 4px; }
.qswitch-row:hover { background: color-mix(in srgb, var(--fg) 6%, transparent); }
.qswitch-row.active { background: color-mix(in srgb, var(--accent) 15%, transparent); }
.qswitch-row.here .t::before {
  content: "▸"; margin-right: 5px; font-size: 10px; color: var(--accent);
}
.qswitch-empty { padding: 18px; color: var(--fg-mute); font-size: 12.5px; }

/* -------------------------------------------------- 5.6 reference overlay */
/* Reference drops over the song as a sheet: the chart stays mounted under
   it, Esc puts you back. Motion says where it came from — down from the
   toolbar's control, back up on close. */
.ref-overlay {
  position: fixed; inset: 0; z-index: 190;
  background: color-mix(in srgb, #000 28%, transparent);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  opacity: 0; transition: opacity 170ms ease;
}
.ref-overlay.open { opacity: 1; }
.ref-sheet {
  position: absolute; top: 3vh; left: 50%;
  transform: translateX(-50%) translateY(-14px);
  width: min(1080px, 94vw); height: 92vh;
  background: var(--bg);
  border: 1px solid color-mix(in srgb, var(--fg) 16%, transparent);
  border-radius: 13px;
  box-shadow: 0 34px 90px color-mix(in srgb, #000 36%, transparent);
  display: flex; flex-direction: column; overflow: hidden;
  transition: transform 230ms cubic-bezier(.32, .72, 0, 1);
}
.ref-overlay.open .ref-sheet { transform: translateX(-50%) translateY(0); }
.ref-close {
  position: absolute; top: 10px; right: 12px; z-index: 5;
  font: 600 15px/1 var(--sans, inherit);
  width: 26px; height: 26px; border: 0; border-radius: 50%;
  background: color-mix(in srgb, var(--fg) 8%, transparent);
  color: var(--fg-dim); cursor: pointer;
}
.ref-close:hover { background: color-mix(in srgb, var(--fg) 14%, transparent); color: var(--fg); }
.ref-sheet-body { flex: 1; min-height: 0; overflow-y: auto; padding: 16px 22px 24px; }
.ref-sheet-body .page-reference { min-height: 0; }

/* ------------------------------------------------------- 5.7 the wave band */
/* THE FULL SCREEN (Ryder, take two): the welcome view opens as the wave —
   ribbons edge to edge over the whole window, one per song, hover names it,
   click opens it (assets/mac/guitar.js). The stats and the picker grid live
   below the fold; the band is not a framed hero any more, it IS the page. */
.page-welcome .dashboard { padding: 0 0 28px; gap: 22px; }
.page-welcome .stats-grid, .page-welcome .picker { padding: 0 22px; }
.gen-band {
  height: 100vh;
  margin: 0;
  border: 0; border-radius: 0;
  background: transparent;
}
.gen-band .gen-overlay { padding: 22px 26px; }
.gen-band .gen-overlay {
  background: linear-gradient(180deg, transparent 45%,
    color-mix(in srgb, var(--bg) 62%, transparent) 100%);
}
.gen-tip {
  position: absolute; z-index: 3; pointer-events: none;
  display: flex; flex-direction: column; gap: 1px;
  max-width: 240px; padding: 5px 10px 6px;
  background: color-mix(in srgb, var(--bg-elev) 88%, transparent);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  border: 1px solid color-mix(in srgb, var(--fg) 14%, transparent);
  border-left: 3px solid var(--tipc, var(--accent));
  border-radius: 7px;
  box-shadow: 0 6px 18px color-mix(in srgb, #000 16%, transparent);
}
.gen-tip b { font-size: 12.5px; color: var(--fg); white-space: nowrap; }
.gen-tip span { font-size: 10.5px; color: var(--fg-mute); white-space: nowrap; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
  .mac-notes { transition: none !important; }
}

/* ============================================================ v2 additions */
/* The substrate canvas: the staff, rules, ticks and tints, painted by the
   layout core (one composited draw per system instead of a thousand
   elements). It sits under the bar cells and the marks. */
.sb-sub { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }

/* The Times ruler: the time map's mm:ss projection under the four-bar
   marks, on the same baseline as the number it belongs to. */
.sb-timelab {
  position: absolute; bottom: -2px; margin-left: 30px; padding-left: 4px;
  font: 500 8.5px var(--mono); color: var(--fg-mute); opacity: .8;
  font-variant-numeric: tabular-nums; white-space: nowrap; pointer-events: none;
}

/* History: every save and snapshot, restorable. */
.sb-histpop { min-width: 320px; max-height: 46vh; overflow-y: auto; }
.sb-histrow {
  display: flex; align-items: center; gap: 7px; flex-wrap: wrap;
  padding: 5px 2px; border-top: 1px solid var(--line);
}
.sb-histrow:first-of-type { border-top: 0; }
.sb-histrow b {
  font-size: 11.5px; max-width: 120px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.sb-histrow > span { flex: 1; font-size: 10px; color: var(--fg-mute); }
.sb-histdiff {
  flex-basis: 100%; font-style: normal; font-size: 10.5px;
  color: var(--fg-dim); line-height: 1.45;
}

/* Timing anchors in the panel: one anchor, one line. */
.sb-tmrow { align-items: center; flex-wrap: nowrap; gap: 4px; }
.sb-tmrow .sb-wval { min-width: 0; }
.sb-tmrow .sb-wval:first-child { min-width: 44px; text-align: left; }
