moontide-mcp 2.0.1 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -6
- package/dist/ask.js +30 -8
- package/dist/mcp.js +60 -14
- package/dist/protocol.js +89 -2
- package/dist/reference.js +22 -0
- package/dist/session.js +53 -0
- package/package.json +1 -1
- package/page/ask-view.js +21 -7
- package/page/ask.js +292 -34
- package/page/change-timing.js +25 -4
- package/page/harmony.js +13 -0
- package/page/index.html +4 -3
- package/page/jam-model.js +11 -2
- package/page/jam-view.js +17 -0
- package/page/lights.js +278 -0
- package/page/main.js +1723 -140
- package/page/midi-clock.js +1 -1
- package/page/midi-out.js +12 -0
- package/page/mixer-groups.js +114 -0
- package/page/mixer-model.js +172 -29
- package/page/mixer-rewrite.js +30 -1
- package/page/mixer-view.js +282 -13
- package/page/note-edit.js +267 -0
- package/page/note-locate.js +346 -0
- package/page/note-panel.js +381 -0
- package/page/note-tag.js +126 -0
- package/page/page-rewrite.js +184 -0
- package/page/song-edit.js +230 -0
- package/page/song-fit.js +250 -0
- package/page/song-grid-model.js +491 -0
- package/page/song-grid-view.js +710 -0
- package/page/song-prefs.js +100 -0
- package/page/structure-check.js +216 -0
- package/page/structure-view.js +38 -0
- package/page/structure.js +760 -0
- package/page/style.css +879 -84
- package/page/takeover.js +20 -5
- package/page/timeline-edit-view.js +1956 -0
- package/page/timeline-gesture.js +279 -0
- package/page/timeline.js +196 -3
- package/page/tracks.js +37 -8
- package/page/ui-state.js +10 -5
- package/page/views.js +25 -8
- package/reference/functions.md +1 -0
- package/reference/midi.md +2 -0
- package/reference/structure.md +131 -0
package/page/style.css
CHANGED
|
@@ -365,10 +365,11 @@ body {
|
|
|
365
365
|
|
|
366
366
|
/* A segmented group: a 1px frame on the dominant fill, no padding and no gap, so it is 1.75rem tall plus its frame and
|
|
367
367
|
fits the slim bar. The buttons inside are the hit targets (at least 1.75rem square). The Edits timing group of the
|
|
368
|
-
Settings card
|
|
368
|
+
Settings card and the launch group of the Song grid's toolbar share every rule below; they only set their own text size. */
|
|
369
369
|
#view-buttons,
|
|
370
370
|
#layout-buttons,
|
|
371
|
-
#change-timing
|
|
371
|
+
#change-timing,
|
|
372
|
+
#song-launch {
|
|
372
373
|
display: inline-flex;
|
|
373
374
|
flex: none;
|
|
374
375
|
align-items: stretch;
|
|
@@ -383,7 +384,8 @@ body {
|
|
|
383
384
|
|
|
384
385
|
#view-buttons button,
|
|
385
386
|
#layout-buttons button,
|
|
386
|
-
#change-timing button
|
|
387
|
+
#change-timing button,
|
|
388
|
+
#song-launch button {
|
|
387
389
|
display: inline-flex;
|
|
388
390
|
align-items: center;
|
|
389
391
|
justify-content: center;
|
|
@@ -411,7 +413,8 @@ body {
|
|
|
411
413
|
|
|
412
414
|
#view-buttons button:hover,
|
|
413
415
|
#layout-buttons button:hover,
|
|
414
|
-
#change-timing button:hover
|
|
416
|
+
#change-timing button:hover,
|
|
417
|
+
#song-launch button:hover {
|
|
415
418
|
background: var(--surface-2);
|
|
416
419
|
color: var(--text);
|
|
417
420
|
}
|
|
@@ -420,7 +423,8 @@ body {
|
|
|
420
423
|
changes width when the selection moves. Muted text never sits on this fill. */
|
|
421
424
|
#view-buttons button[aria-pressed="true"],
|
|
422
425
|
#layout-buttons button[aria-pressed="true"],
|
|
423
|
-
#change-timing button[aria-pressed="true"]
|
|
426
|
+
#change-timing button[aria-pressed="true"],
|
|
427
|
+
#song-launch button[aria-pressed="true"] {
|
|
424
428
|
background: var(--surface-2);
|
|
425
429
|
color: var(--text);
|
|
426
430
|
box-shadow: inset 0 0 0 1px var(--border);
|
|
@@ -428,7 +432,8 @@ body {
|
|
|
428
432
|
|
|
429
433
|
#view-buttons button:focus-visible,
|
|
430
434
|
#layout-buttons button:focus-visible,
|
|
431
|
-
#change-timing button:focus-visible
|
|
435
|
+
#change-timing button:focus-visible,
|
|
436
|
+
#song-launch button:focus-visible {
|
|
432
437
|
outline: 1px solid var(--text-muted);
|
|
433
438
|
outline-offset: -1px;
|
|
434
439
|
}
|
|
@@ -440,7 +445,8 @@ body {
|
|
|
440
445
|
max-width: 100%;
|
|
441
446
|
}
|
|
442
447
|
|
|
443
|
-
#change-timing button
|
|
448
|
+
#change-timing button,
|
|
449
|
+
#song-launch button {
|
|
444
450
|
font-size: 0.8125rem;
|
|
445
451
|
}
|
|
446
452
|
|
|
@@ -1645,7 +1651,9 @@ body {
|
|
|
1645
1651
|
grid-row: 1;
|
|
1646
1652
|
}
|
|
1647
1653
|
|
|
1648
|
-
|
|
1654
|
+
/* A lane's event area fills the lane's whole cell, so the rings, ghosts and washes drawn over it (the mark layer fills the same
|
|
1655
|
+
cell) sit on the notes whatever height the lane's name column gives the lane. */
|
|
1656
|
+
.lane-events {
|
|
1649
1657
|
align-self: stretch;
|
|
1650
1658
|
width: 100%;
|
|
1651
1659
|
height: 100%;
|
|
@@ -1692,6 +1700,234 @@ body {
|
|
|
1692
1700
|
.lane[data-drum-rows="7"] { min-height: 8.75rem; }
|
|
1693
1701
|
.lane[data-drum-rows="8"] { min-height: 10rem; }
|
|
1694
1702
|
|
|
1703
|
+
/* The editable Timeline: the panel under the lanes, and the marks on a lane. The panel is a quiet strip that is always the
|
|
1704
|
+
same height, so the lanes do not move under the pointer when a note is picked; its two text lines keep their room even
|
|
1705
|
+
when empty. A selected note gets a solid ring, a preview a dashed one, the other places of the same token a dotted one
|
|
1706
|
+
and a range of cycles a wash with two edges: outlines and words only, never the accent colors, which keep their uses
|
|
1707
|
+
(the playhead is the only accent on the Timeline). The marks sit on top of a lane in its own grid cell, never take the
|
|
1708
|
+
pointer and are hidden from screen readers. Nothing here moves, fades or animates. */
|
|
1709
|
+
#timeline-note {
|
|
1710
|
+
flex: 0 0 auto;
|
|
1711
|
+
box-sizing: border-box;
|
|
1712
|
+
display: flex;
|
|
1713
|
+
flex-wrap: wrap;
|
|
1714
|
+
align-items: center;
|
|
1715
|
+
gap: 0.25rem 1rem;
|
|
1716
|
+
padding: 0.5rem 1rem;
|
|
1717
|
+
background: var(--secondary);
|
|
1718
|
+
border-top: 1px solid var(--border);
|
|
1719
|
+
font-size: 0.8125rem;
|
|
1720
|
+
font-weight: 400;
|
|
1721
|
+
line-height: 1.5;
|
|
1722
|
+
}
|
|
1723
|
+
|
|
1724
|
+
#timeline-note[hidden] {
|
|
1725
|
+
display: none;
|
|
1726
|
+
}
|
|
1727
|
+
|
|
1728
|
+
.tl-note-where {
|
|
1729
|
+
min-width: 0;
|
|
1730
|
+
min-height: 2rem;
|
|
1731
|
+
display: flex;
|
|
1732
|
+
align-items: center;
|
|
1733
|
+
color: var(--text-muted);
|
|
1734
|
+
overflow-wrap: anywhere;
|
|
1735
|
+
}
|
|
1736
|
+
|
|
1737
|
+
/* The spaces at the start of the position text are kept when the lane name and the position sit side by side. */
|
|
1738
|
+
.tl-note-where > span {
|
|
1739
|
+
white-space: pre-wrap;
|
|
1740
|
+
}
|
|
1741
|
+
|
|
1742
|
+
.tl-lane-name {
|
|
1743
|
+
font-weight: 600;
|
|
1744
|
+
color: var(--text);
|
|
1745
|
+
}
|
|
1746
|
+
|
|
1747
|
+
.tl-note-state {
|
|
1748
|
+
color: var(--text-muted);
|
|
1749
|
+
}
|
|
1750
|
+
|
|
1751
|
+
.tl-note-controls {
|
|
1752
|
+
display: flex;
|
|
1753
|
+
flex-wrap: wrap;
|
|
1754
|
+
align-items: center;
|
|
1755
|
+
gap: 0.5rem 1rem;
|
|
1756
|
+
}
|
|
1757
|
+
|
|
1758
|
+
.tl-note-controls[hidden] {
|
|
1759
|
+
display: none;
|
|
1760
|
+
}
|
|
1761
|
+
|
|
1762
|
+
.tl-group {
|
|
1763
|
+
display: flex;
|
|
1764
|
+
align-items: center;
|
|
1765
|
+
gap: 0.25rem;
|
|
1766
|
+
}
|
|
1767
|
+
|
|
1768
|
+
/* A range offers only Ask Claude: the groups and the Make a rest button are hidden, and their display must not undo that. */
|
|
1769
|
+
.tl-group[hidden],
|
|
1770
|
+
.tl-btn[hidden] {
|
|
1771
|
+
display: none;
|
|
1772
|
+
}
|
|
1773
|
+
|
|
1774
|
+
.tl-label {
|
|
1775
|
+
color: var(--text-muted);
|
|
1776
|
+
margin-right: 0.25rem;
|
|
1777
|
+
}
|
|
1778
|
+
|
|
1779
|
+
.tl-value {
|
|
1780
|
+
font-family: var(--font-mono);
|
|
1781
|
+
color: var(--text);
|
|
1782
|
+
margin-right: 0.25rem;
|
|
1783
|
+
}
|
|
1784
|
+
|
|
1785
|
+
.tl-fixed {
|
|
1786
|
+
color: var(--text-muted);
|
|
1787
|
+
margin-right: 0.25rem;
|
|
1788
|
+
}
|
|
1789
|
+
|
|
1790
|
+
.tl-btn {
|
|
1791
|
+
box-sizing: border-box;
|
|
1792
|
+
min-width: 2rem;
|
|
1793
|
+
height: 2rem;
|
|
1794
|
+
padding: 0 0.5rem;
|
|
1795
|
+
background: var(--surface-2);
|
|
1796
|
+
border: 1px solid var(--border);
|
|
1797
|
+
color: var(--text);
|
|
1798
|
+
font-family: inherit;
|
|
1799
|
+
font-size: 0.8125rem;
|
|
1800
|
+
font-weight: 400;
|
|
1801
|
+
line-height: 1.5;
|
|
1802
|
+
cursor: pointer;
|
|
1803
|
+
}
|
|
1804
|
+
|
|
1805
|
+
.tl-btn:hover:not([aria-disabled="true"]) {
|
|
1806
|
+
border-color: var(--text-muted);
|
|
1807
|
+
}
|
|
1808
|
+
|
|
1809
|
+
.tl-btn[aria-disabled="true"] {
|
|
1810
|
+
border-style: dashed;
|
|
1811
|
+
cursor: default;
|
|
1812
|
+
}
|
|
1813
|
+
|
|
1814
|
+
.tl-btn:focus-visible {
|
|
1815
|
+
outline: 1px solid var(--text-muted);
|
|
1816
|
+
outline-offset: 1px;
|
|
1817
|
+
}
|
|
1818
|
+
|
|
1819
|
+
#timeline-note-line,
|
|
1820
|
+
.tl-note-hint {
|
|
1821
|
+
flex: 1 0 100%;
|
|
1822
|
+
margin: 0;
|
|
1823
|
+
min-height: 1.5rem;
|
|
1824
|
+
color: var(--text-muted);
|
|
1825
|
+
overflow-wrap: anywhere;
|
|
1826
|
+
}
|
|
1827
|
+
|
|
1828
|
+
#timeline-note-line[data-kind="refused"],
|
|
1829
|
+
#timeline-note-line[data-kind="result"],
|
|
1830
|
+
#timeline-note-line[data-kind="notice"],
|
|
1831
|
+
#timeline-note-line[data-kind="preview"] {
|
|
1832
|
+
color: var(--text);
|
|
1833
|
+
}
|
|
1834
|
+
|
|
1835
|
+
#workspace[data-layout="b"] #timeline-note-line,
|
|
1836
|
+
#workspace[data-layout="b"] .tl-note-hint {
|
|
1837
|
+
min-height: 4rem;
|
|
1838
|
+
}
|
|
1839
|
+
|
|
1840
|
+
/* In the side panel the buttons wrap into rows when a note is selected; the panel reserves their room, so it keeps one height
|
|
1841
|
+
whether nothing, a note or a drag is shown and the lanes do not move when a note is picked. */
|
|
1842
|
+
#workspace[data-layout="b"] #timeline-note {
|
|
1843
|
+
min-height: 19rem;
|
|
1844
|
+
}
|
|
1845
|
+
|
|
1846
|
+
#timeline-lanes:focus-visible {
|
|
1847
|
+
outline: 1px solid var(--text-muted);
|
|
1848
|
+
outline-offset: -1px;
|
|
1849
|
+
}
|
|
1850
|
+
|
|
1851
|
+
#timeline-lanes[data-dragging] {
|
|
1852
|
+
user-select: none;
|
|
1853
|
+
}
|
|
1854
|
+
|
|
1855
|
+
/* The pointer only confirms what the words say: a cross over empty lane area, a hand over a note, up-and-down arrows while an
|
|
1856
|
+
editable note is dragged, the plain arrow while a note the page cannot edit is dragged, a cross for a drag across the lanes.
|
|
1857
|
+
The lanes hold the pointer during a drag, so they carry the cursor themselves while one lasts. */
|
|
1858
|
+
#timeline-lanes .lane-events {
|
|
1859
|
+
cursor: crosshair;
|
|
1860
|
+
}
|
|
1861
|
+
|
|
1862
|
+
#timeline-lanes[data-hover="note"] .lane-events {
|
|
1863
|
+
cursor: pointer;
|
|
1864
|
+
}
|
|
1865
|
+
|
|
1866
|
+
#timeline-lanes[data-dragging="pitch"],
|
|
1867
|
+
#timeline-lanes[data-dragging="pitch"] .lane-events {
|
|
1868
|
+
cursor: ns-resize;
|
|
1869
|
+
}
|
|
1870
|
+
|
|
1871
|
+
#timeline-lanes[data-dragging="refused"],
|
|
1872
|
+
#timeline-lanes[data-dragging="refused"] .lane-events {
|
|
1873
|
+
cursor: default;
|
|
1874
|
+
}
|
|
1875
|
+
|
|
1876
|
+
#timeline-lanes[data-dragging="range"],
|
|
1877
|
+
#timeline-lanes[data-dragging="range"] .lane-events {
|
|
1878
|
+
cursor: crosshair;
|
|
1879
|
+
}
|
|
1880
|
+
|
|
1881
|
+
.lane-marks {
|
|
1882
|
+
grid-column: 2;
|
|
1883
|
+
grid-row: 1;
|
|
1884
|
+
position: relative;
|
|
1885
|
+
pointer-events: none;
|
|
1886
|
+
min-width: 0;
|
|
1887
|
+
}
|
|
1888
|
+
|
|
1889
|
+
.tl-ring,
|
|
1890
|
+
.tl-ghost,
|
|
1891
|
+
.tl-same {
|
|
1892
|
+
position: absolute;
|
|
1893
|
+
box-sizing: border-box;
|
|
1894
|
+
min-width: 0.5rem;
|
|
1895
|
+
outline-offset: 0.25rem;
|
|
1896
|
+
}
|
|
1897
|
+
|
|
1898
|
+
.tl-ring {
|
|
1899
|
+
outline: 1px solid var(--text);
|
|
1900
|
+
}
|
|
1901
|
+
|
|
1902
|
+
.tl-ghost {
|
|
1903
|
+
outline: 1px dashed var(--text);
|
|
1904
|
+
}
|
|
1905
|
+
|
|
1906
|
+
.tl-same {
|
|
1907
|
+
outline: 1px dotted var(--text-muted);
|
|
1908
|
+
}
|
|
1909
|
+
|
|
1910
|
+
/* The element the lanes name with aria-activedescendant: it carries the name of the active note or lane for screen readers and
|
|
1911
|
+
paints nothing. It is not hidden from them, so it is clipped to nothing instead of taking display: none. */
|
|
1912
|
+
.tl-active {
|
|
1913
|
+
position: absolute;
|
|
1914
|
+
width: 1px;
|
|
1915
|
+
height: 1px;
|
|
1916
|
+
overflow: hidden;
|
|
1917
|
+
clip-path: inset(50%);
|
|
1918
|
+
pointer-events: none;
|
|
1919
|
+
}
|
|
1920
|
+
|
|
1921
|
+
.tl-range {
|
|
1922
|
+
position: absolute;
|
|
1923
|
+
top: 0;
|
|
1924
|
+
bottom: 0;
|
|
1925
|
+
box-sizing: border-box;
|
|
1926
|
+
background: color-mix(in srgb, var(--text) 14%, transparent);
|
|
1927
|
+
border-left: 1px solid var(--text-muted);
|
|
1928
|
+
border-right: 1px solid var(--text-muted);
|
|
1929
|
+
}
|
|
1930
|
+
|
|
1695
1931
|
/* The arrange() sections above the lanes — same grid columns as .lane, so
|
|
1696
1932
|
a section span lines up with the ruler/lane track column beneath it. No accent is used here
|
|
1697
1933
|
(accent stays reserved for "live now"/"structural" states, never a static
|
|
@@ -2289,6 +2525,7 @@ body {
|
|
|
2289
2525
|
#parts-view {
|
|
2290
2526
|
flex: 1;
|
|
2291
2527
|
min-height: 0;
|
|
2528
|
+
min-width: 0;
|
|
2292
2529
|
display: flex;
|
|
2293
2530
|
flex-direction: column;
|
|
2294
2531
|
padding: 1rem;
|
|
@@ -2439,132 +2676,487 @@ body {
|
|
|
2439
2676
|
background: var(--accent);
|
|
2440
2677
|
}
|
|
2441
2678
|
|
|
2442
|
-
/*
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
height too: CodeMirror scrolls only inside a .cm-editor of bounded height; without it the
|
|
2446
|
-
editor grew to its content and #editor-area cut off every line past its bottom. */
|
|
2447
|
-
#editor-area > strudel-editor + div,
|
|
2448
|
-
#editor-area > strudel-editor + div > .cm-editor {
|
|
2449
|
-
height: 100%;
|
|
2450
|
-
}
|
|
2451
|
-
|
|
2452
|
-
#audio-unlock-overlay {
|
|
2453
|
-
position: fixed;
|
|
2454
|
-
inset: 0;
|
|
2455
|
-
margin: 0;
|
|
2456
|
-
padding: 1rem;
|
|
2457
|
-
border: none;
|
|
2458
|
-
background: rgba(11, 13, 16, 0.85);
|
|
2679
|
+
/* The lines above the Song grid in the Parts view. #song-notes sits between the message and the grid so its lines do not
|
|
2680
|
+
scroll away with a long grid. No accent, no motion. */
|
|
2681
|
+
#song-notes {
|
|
2459
2682
|
display: flex;
|
|
2460
2683
|
flex-direction: column;
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
font-family: inherit;
|
|
2465
|
-
/* Stays above the Ask Claude box (z-index 1000). */
|
|
2466
|
-
z-index: 2000;
|
|
2684
|
+
gap: 0.5rem;
|
|
2685
|
+
padding-bottom: 0.5rem;
|
|
2686
|
+
border-bottom: 1px solid var(--border);
|
|
2467
2687
|
}
|
|
2468
2688
|
|
|
2469
|
-
|
|
2470
|
-
#audio-unlock-overlay[hidden] {
|
|
2689
|
+
#song-notes[hidden] {
|
|
2471
2690
|
display: none;
|
|
2472
2691
|
}
|
|
2473
2692
|
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
its own accent rule to render in teal. */
|
|
2477
|
-
#audio-unlock-overlay [data-accent="true"] {
|
|
2478
|
-
color: var(--accent);
|
|
2479
|
-
}
|
|
2480
|
-
|
|
2481
|
-
#audio-unlock-cta {
|
|
2482
|
-
font-size: 1.5rem;
|
|
2483
|
-
font-weight: 600;
|
|
2484
|
-
line-height: 1.2;
|
|
2485
|
-
}
|
|
2486
|
-
|
|
2487
|
-
#audio-error {
|
|
2488
|
-
margin-top: 2rem;
|
|
2693
|
+
.song-note {
|
|
2694
|
+
margin: 0;
|
|
2489
2695
|
font-size: 1rem;
|
|
2490
2696
|
font-weight: 400;
|
|
2491
2697
|
line-height: 1.5;
|
|
2492
2698
|
color: var(--text);
|
|
2699
|
+
overflow-wrap: anywhere;
|
|
2493
2700
|
}
|
|
2494
2701
|
|
|
2495
|
-
|
|
2496
|
-
|
|
2702
|
+
.song-note[data-kind="check-failed"] {
|
|
2703
|
+
color: var(--text-muted);
|
|
2497
2704
|
}
|
|
2498
2705
|
|
|
2499
|
-
/* The
|
|
2500
|
-
|
|
2501
|
-
#
|
|
2502
|
-
flex: 1;
|
|
2503
|
-
min-height: 0;
|
|
2504
|
-
overflow: hidden;
|
|
2706
|
+
/* The toolbar above the Song grid: what a launched section waits for, and where the music is. #song-launch shares the
|
|
2707
|
+
segmented group look of the top bar (the selector lists near #view-buttons). No accent, no motion. */
|
|
2708
|
+
#song-bar {
|
|
2505
2709
|
display: flex;
|
|
2506
|
-
flex-
|
|
2710
|
+
flex-wrap: wrap;
|
|
2711
|
+
align-items: center;
|
|
2712
|
+
column-gap: 1rem;
|
|
2713
|
+
row-gap: 0.5rem;
|
|
2507
2714
|
}
|
|
2508
2715
|
|
|
2509
|
-
#
|
|
2716
|
+
#song-bar[hidden] {
|
|
2510
2717
|
display: none;
|
|
2511
2718
|
}
|
|
2512
2719
|
|
|
2513
|
-
|
|
2514
|
-
#
|
|
2720
|
+
#song-launch-label,
|
|
2721
|
+
#song-now {
|
|
2722
|
+
margin: 0;
|
|
2515
2723
|
font-size: 0.8125rem;
|
|
2516
2724
|
font-weight: 400;
|
|
2517
2725
|
line-height: 1.5;
|
|
2518
2726
|
color: var(--text-muted);
|
|
2519
|
-
margin: 0;
|
|
2520
|
-
padding: 0.5rem 1rem;
|
|
2521
|
-
border-bottom: 1px solid var(--border);
|
|
2522
2727
|
}
|
|
2523
2728
|
|
|
2524
|
-
#
|
|
2729
|
+
#song-now[hidden] {
|
|
2525
2730
|
display: none;
|
|
2526
2731
|
}
|
|
2527
2732
|
|
|
2528
|
-
|
|
2733
|
+
/* The one sentence under the toolbar: why the grid is off, what waits, or why a gesture changed nothing. It is the only
|
|
2734
|
+
live region of the view and changes only on a gesture or a state change. A queued launch and one that needs no code
|
|
2735
|
+
change are information, so they are muted; the rest read in the plain text color. No accent, no motion. */
|
|
2736
|
+
#song-line {
|
|
2737
|
+
margin: 0;
|
|
2529
2738
|
font-size: 1rem;
|
|
2530
2739
|
font-weight: 400;
|
|
2531
2740
|
line-height: 1.5;
|
|
2741
|
+
color: var(--text);
|
|
2742
|
+
overflow-wrap: anywhere;
|
|
2743
|
+
}
|
|
2744
|
+
|
|
2745
|
+
#song-line[data-kind="queued"],
|
|
2746
|
+
#song-line[data-kind="already"] {
|
|
2532
2747
|
color: var(--text-muted);
|
|
2533
|
-
margin: 0;
|
|
2534
|
-
padding: 1rem;
|
|
2535
2748
|
}
|
|
2536
2749
|
|
|
2537
|
-
#
|
|
2750
|
+
#song-line[hidden] {
|
|
2538
2751
|
display: none;
|
|
2539
2752
|
}
|
|
2540
2753
|
|
|
2541
|
-
|
|
2542
|
-
|
|
2754
|
+
/* The Song grid: sections as columns, groups and tracks as rows. Only .song-grid-scroll scrolls, in both directions; the
|
|
2755
|
+
name column and the header row stay in place (sticky) and are opaque so scrolled cells slide under them. The section
|
|
2756
|
+
header is the Parts card (.part-card), so the playing and queued colors come from the rules above. Nothing here uses an
|
|
2757
|
+
accent, a destructive or a Jam color, and nothing moves: no transition and no animation. */
|
|
2758
|
+
#parts-rows[data-view="song"] {
|
|
2543
2759
|
flex: 1;
|
|
2544
2760
|
min-height: 0;
|
|
2761
|
+
min-width: 0;
|
|
2762
|
+
overflow: hidden;
|
|
2545
2763
|
}
|
|
2546
2764
|
|
|
2547
|
-
|
|
2548
|
-
|
|
2765
|
+
.song-grid-scroll {
|
|
2766
|
+
flex: 1;
|
|
2767
|
+
min-width: 0;
|
|
2768
|
+
min-height: 0;
|
|
2769
|
+
overflow: auto;
|
|
2770
|
+
scroll-padding-left: 10rem;
|
|
2771
|
+
scroll-padding-top: 7rem;
|
|
2549
2772
|
}
|
|
2550
2773
|
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
padding: 0.5rem 1rem;
|
|
2559
|
-
border-top: 1px solid var(--border);
|
|
2774
|
+
.song-grid {
|
|
2775
|
+
border-collapse: separate;
|
|
2776
|
+
border-spacing: 0;
|
|
2777
|
+
table-layout: fixed;
|
|
2778
|
+
width: 100%;
|
|
2779
|
+
min-width: calc(10rem + var(--song-columns) * 10rem);
|
|
2780
|
+
background: var(--dominant);
|
|
2560
2781
|
}
|
|
2561
2782
|
|
|
2562
|
-
|
|
2783
|
+
.song-col-name {
|
|
2784
|
+
width: 10rem;
|
|
2785
|
+
}
|
|
2786
|
+
|
|
2787
|
+
.song-grid col[data-playing="true"] {
|
|
2788
|
+
background: var(--secondary);
|
|
2789
|
+
}
|
|
2790
|
+
|
|
2791
|
+
.song-grid tr[hidden] {
|
|
2563
2792
|
display: none;
|
|
2564
2793
|
}
|
|
2565
2794
|
|
|
2566
|
-
|
|
2567
|
-
|
|
2795
|
+
.song-grid th,
|
|
2796
|
+
.song-grid td {
|
|
2797
|
+
padding: 0;
|
|
2798
|
+
min-width: 0;
|
|
2799
|
+
text-align: left;
|
|
2800
|
+
vertical-align: top;
|
|
2801
|
+
font-size: 0.8125rem;
|
|
2802
|
+
font-weight: 400;
|
|
2803
|
+
line-height: 1.5;
|
|
2804
|
+
color: var(--text);
|
|
2805
|
+
border-right: 1px solid var(--border);
|
|
2806
|
+
border-bottom: 1px solid var(--border);
|
|
2807
|
+
}
|
|
2808
|
+
|
|
2809
|
+
.song-grid thead th {
|
|
2810
|
+
position: sticky;
|
|
2811
|
+
top: 0;
|
|
2812
|
+
z-index: 2;
|
|
2813
|
+
background: var(--dominant);
|
|
2814
|
+
}
|
|
2815
|
+
|
|
2816
|
+
.song-grid .song-colhead {
|
|
2817
|
+
padding: 0.25rem;
|
|
2818
|
+
}
|
|
2819
|
+
|
|
2820
|
+
.song-grid .song-corner {
|
|
2821
|
+
position: sticky;
|
|
2822
|
+
left: 0;
|
|
2823
|
+
z-index: 3;
|
|
2824
|
+
padding: 0.5rem;
|
|
2825
|
+
color: var(--text-muted);
|
|
2826
|
+
}
|
|
2827
|
+
|
|
2828
|
+
.song-grid .song-rowhead {
|
|
2829
|
+
position: sticky;
|
|
2830
|
+
left: 0;
|
|
2831
|
+
z-index: 1;
|
|
2832
|
+
background: var(--dominant);
|
|
2833
|
+
padding: 0.25rem 0.5rem;
|
|
2834
|
+
padding-inline-start: calc(0.5rem + var(--depth, 0) * 1rem);
|
|
2835
|
+
overflow-wrap: anywhere;
|
|
2836
|
+
vertical-align: middle;
|
|
2837
|
+
}
|
|
2838
|
+
|
|
2839
|
+
.song-grid .song-rowhead[data-deep="true"] {
|
|
2840
|
+
padding-inline-start: 4.5rem;
|
|
2841
|
+
}
|
|
2842
|
+
|
|
2843
|
+
.song-group-row .song-rowhead,
|
|
2844
|
+
.song-group-row td {
|
|
2845
|
+
background: var(--secondary);
|
|
2846
|
+
}
|
|
2847
|
+
|
|
2848
|
+
.song-head {
|
|
2849
|
+
width: 100%;
|
|
2850
|
+
box-sizing: border-box;
|
|
2851
|
+
margin: 0;
|
|
2852
|
+
}
|
|
2853
|
+
|
|
2854
|
+
.song-head .part-name {
|
|
2855
|
+
font-weight: 600;
|
|
2856
|
+
}
|
|
2857
|
+
|
|
2858
|
+
.song-head-line {
|
|
2859
|
+
display: flex;
|
|
2860
|
+
flex-wrap: wrap;
|
|
2861
|
+
align-items: baseline;
|
|
2862
|
+
column-gap: 0.5rem;
|
|
2863
|
+
}
|
|
2864
|
+
|
|
2865
|
+
.song-head .song-head-action,
|
|
2866
|
+
.song-head .song-used {
|
|
2867
|
+
font-family: inherit;
|
|
2868
|
+
font-size: 0.8125rem;
|
|
2869
|
+
font-weight: 400;
|
|
2870
|
+
line-height: 1.5;
|
|
2871
|
+
color: var(--text-muted);
|
|
2872
|
+
}
|
|
2873
|
+
|
|
2874
|
+
.song-head .song-harmony {
|
|
2875
|
+
max-height: 3em;
|
|
2876
|
+
overflow: hidden;
|
|
2877
|
+
overflow-wrap: anywhere;
|
|
2878
|
+
font-size: 0.8125rem;
|
|
2879
|
+
font-weight: 400;
|
|
2880
|
+
line-height: 1.5;
|
|
2881
|
+
color: var(--text-muted);
|
|
2882
|
+
}
|
|
2883
|
+
|
|
2884
|
+
.song-fold {
|
|
2885
|
+
display: inline-flex;
|
|
2886
|
+
align-items: baseline;
|
|
2887
|
+
gap: 0.5rem;
|
|
2888
|
+
max-width: 100%;
|
|
2889
|
+
margin: 0;
|
|
2890
|
+
padding: 0;
|
|
2891
|
+
background: transparent;
|
|
2892
|
+
border: none;
|
|
2893
|
+
color: var(--text);
|
|
2894
|
+
font-family: inherit;
|
|
2895
|
+
font-size: 0.8125rem;
|
|
2896
|
+
font-weight: 600;
|
|
2897
|
+
line-height: 1.5;
|
|
2898
|
+
text-align: left;
|
|
2899
|
+
cursor: pointer;
|
|
2900
|
+
overflow-wrap: anywhere;
|
|
2901
|
+
}
|
|
2902
|
+
|
|
2903
|
+
.song-fold:focus-visible {
|
|
2904
|
+
outline: 1px solid var(--text-muted);
|
|
2905
|
+
outline-offset: 0.25rem;
|
|
2906
|
+
}
|
|
2907
|
+
|
|
2908
|
+
.song-fold-name {
|
|
2909
|
+
min-width: 0;
|
|
2910
|
+
}
|
|
2911
|
+
|
|
2912
|
+
.song-count {
|
|
2913
|
+
font-weight: 400;
|
|
2914
|
+
color: var(--text-muted);
|
|
2915
|
+
}
|
|
2916
|
+
|
|
2917
|
+
.song-cell {
|
|
2918
|
+
display: flex;
|
|
2919
|
+
flex-direction: column;
|
|
2920
|
+
justify-content: center;
|
|
2921
|
+
width: 100%;
|
|
2922
|
+
min-height: 3rem;
|
|
2923
|
+
box-sizing: border-box;
|
|
2924
|
+
margin: 0;
|
|
2925
|
+
padding: 0.25rem 0.5rem;
|
|
2926
|
+
background: transparent;
|
|
2927
|
+
border: 1px solid transparent;
|
|
2928
|
+
color: var(--text);
|
|
2929
|
+
font-family: inherit;
|
|
2930
|
+
font-size: 0.8125rem;
|
|
2931
|
+
font-weight: 400;
|
|
2932
|
+
line-height: 1.5;
|
|
2933
|
+
text-align: left;
|
|
2934
|
+
cursor: pointer;
|
|
2935
|
+
}
|
|
2936
|
+
|
|
2937
|
+
.song-cell:hover:not([aria-disabled="true"]) {
|
|
2938
|
+
border-color: var(--text-muted);
|
|
2939
|
+
}
|
|
2940
|
+
|
|
2941
|
+
.song-cell:focus-visible {
|
|
2942
|
+
outline: 1px solid var(--text-muted);
|
|
2943
|
+
outline-offset: -1px;
|
|
2944
|
+
}
|
|
2945
|
+
|
|
2946
|
+
/* A control the line switched off stays focusable and keeps its text; only the pointer says it does nothing. */
|
|
2947
|
+
.song-cell[aria-disabled="true"],
|
|
2948
|
+
.song-head[aria-disabled="true"] {
|
|
2949
|
+
cursor: default;
|
|
2950
|
+
}
|
|
2951
|
+
|
|
2952
|
+
.song-variation {
|
|
2953
|
+
white-space: nowrap;
|
|
2954
|
+
overflow: hidden;
|
|
2955
|
+
text-overflow: ellipsis;
|
|
2956
|
+
}
|
|
2957
|
+
|
|
2958
|
+
.song-cell[data-kind="rest"] .song-variation,
|
|
2959
|
+
.song-wait,
|
|
2960
|
+
.song-fit {
|
|
2961
|
+
color: var(--text-muted);
|
|
2962
|
+
}
|
|
2963
|
+
|
|
2964
|
+
/* The second line of a cell: whether a fixed variation fits its section's harmony, or that the cell's change waits for its
|
|
2965
|
+
line. Words in the muted colour, two lines at most; the whole text is in the cell's title. */
|
|
2966
|
+
.song-wait,
|
|
2967
|
+
.song-fit {
|
|
2968
|
+
max-height: 3em;
|
|
2969
|
+
overflow: hidden;
|
|
2970
|
+
overflow-wrap: anywhere;
|
|
2971
|
+
}
|
|
2972
|
+
|
|
2973
|
+
.song-cell[aria-expanded="true"] {
|
|
2974
|
+
border-color: var(--text-muted);
|
|
2975
|
+
}
|
|
2976
|
+
|
|
2977
|
+
/* The list that opens on a cell. It is fixed to the window and lives outside the grid's scroller, so the scroller never
|
|
2978
|
+
clips it; the page puts it below the cell or above it and keeps it inside the window. */
|
|
2979
|
+
#song-cell-list {
|
|
2980
|
+
position: fixed;
|
|
2981
|
+
z-index: 5;
|
|
2982
|
+
box-sizing: border-box;
|
|
2983
|
+
min-width: 10rem;
|
|
2984
|
+
max-width: 20rem;
|
|
2985
|
+
max-height: 16rem;
|
|
2986
|
+
overflow-y: auto;
|
|
2987
|
+
margin: 0;
|
|
2988
|
+
padding: 0.25rem;
|
|
2989
|
+
background: var(--secondary);
|
|
2990
|
+
border: 1px solid var(--text-muted);
|
|
2991
|
+
}
|
|
2992
|
+
|
|
2993
|
+
#song-cell-list[hidden] {
|
|
2994
|
+
display: none;
|
|
2995
|
+
}
|
|
2996
|
+
|
|
2997
|
+
.song-option {
|
|
2998
|
+
display: flex;
|
|
2999
|
+
flex-wrap: wrap;
|
|
3000
|
+
align-items: baseline;
|
|
3001
|
+
column-gap: 0.5rem;
|
|
3002
|
+
padding: 0.25rem 0.5rem;
|
|
3003
|
+
font-size: 0.8125rem;
|
|
3004
|
+
line-height: 1.5;
|
|
3005
|
+
color: var(--text);
|
|
3006
|
+
cursor: pointer;
|
|
3007
|
+
overflow-wrap: anywhere;
|
|
3008
|
+
}
|
|
3009
|
+
|
|
3010
|
+
.song-option[data-active="true"] {
|
|
3011
|
+
box-shadow: inset 0 0 0 1px var(--text-muted);
|
|
3012
|
+
}
|
|
3013
|
+
|
|
3014
|
+
.song-option-note {
|
|
3015
|
+
color: var(--text-muted);
|
|
3016
|
+
}
|
|
3017
|
+
|
|
3018
|
+
.song-list-note {
|
|
3019
|
+
padding: 0.25rem 0.5rem;
|
|
3020
|
+
font-size: 0.8125rem;
|
|
3021
|
+
line-height: 1.5;
|
|
3022
|
+
overflow-wrap: anywhere;
|
|
3023
|
+
}
|
|
3024
|
+
|
|
3025
|
+
.song-option-rest {
|
|
3026
|
+
border-top: 1px solid var(--border);
|
|
3027
|
+
}
|
|
3028
|
+
|
|
3029
|
+
.song-grid .song-outside-note {
|
|
3030
|
+
padding: 0.25rem 0.5rem;
|
|
3031
|
+
color: var(--text-muted);
|
|
3032
|
+
}
|
|
3033
|
+
|
|
3034
|
+
/* Strudel inserts the CodeMirror container as the NEXT SIBLING of <strudel-editor>,
|
|
3035
|
+
not inside it. Fill the available height and let CodeMirror handle its own native
|
|
3036
|
+
scrolling/wrapping — no text/font restyling here. The editor itself (.cm-editor) needs the
|
|
3037
|
+
height too: CodeMirror scrolls only inside a .cm-editor of bounded height; without it the
|
|
3038
|
+
editor grew to its content and #editor-area cut off every line past its bottom. */
|
|
3039
|
+
#editor-area > strudel-editor + div,
|
|
3040
|
+
#editor-area > strudel-editor + div > .cm-editor {
|
|
3041
|
+
height: 100%;
|
|
3042
|
+
}
|
|
3043
|
+
|
|
3044
|
+
#audio-unlock-overlay {
|
|
3045
|
+
position: fixed;
|
|
3046
|
+
inset: 0;
|
|
3047
|
+
margin: 0;
|
|
3048
|
+
padding: 1rem;
|
|
3049
|
+
border: none;
|
|
3050
|
+
background: rgba(11, 13, 16, 0.85);
|
|
3051
|
+
display: flex;
|
|
3052
|
+
flex-direction: column;
|
|
3053
|
+
align-items: center;
|
|
3054
|
+
justify-content: center;
|
|
3055
|
+
cursor: pointer;
|
|
3056
|
+
font-family: inherit;
|
|
3057
|
+
/* Stays above the Ask Claude box (z-index 1000). */
|
|
3058
|
+
z-index: 2000;
|
|
3059
|
+
}
|
|
3060
|
+
|
|
3061
|
+
/* The display rule above beats the browser's [hidden] default, so hiding needs its own rule. */
|
|
3062
|
+
#audio-unlock-overlay[hidden] {
|
|
3063
|
+
display: none;
|
|
3064
|
+
}
|
|
3065
|
+
|
|
3066
|
+
/* Overlay counterpart of the top-bar accent rule (#top-bar [data-accent="true"]):
|
|
3067
|
+
the overlay is a button with its own browser text color, so the CTA span needs
|
|
3068
|
+
its own accent rule to render in teal. */
|
|
3069
|
+
#audio-unlock-overlay [data-accent="true"] {
|
|
3070
|
+
color: var(--accent);
|
|
3071
|
+
}
|
|
3072
|
+
|
|
3073
|
+
#audio-unlock-cta {
|
|
3074
|
+
font-size: 1.5rem;
|
|
3075
|
+
font-weight: 600;
|
|
3076
|
+
line-height: 1.2;
|
|
3077
|
+
}
|
|
3078
|
+
|
|
3079
|
+
#audio-error {
|
|
3080
|
+
margin-top: 2rem;
|
|
3081
|
+
font-size: 1rem;
|
|
3082
|
+
font-weight: 400;
|
|
3083
|
+
line-height: 1.5;
|
|
3084
|
+
color: var(--text);
|
|
3085
|
+
}
|
|
3086
|
+
|
|
3087
|
+
#audio-error[hidden] {
|
|
3088
|
+
display: none;
|
|
3089
|
+
}
|
|
3090
|
+
|
|
3091
|
+
/* The Mixer view. #mixer-view fills the panel like #timeline-view; #mixer-strips is its
|
|
3092
|
+
only scroll container (both axes). Strips never wrap and never shrink below 11rem. */
|
|
3093
|
+
#mixer-view {
|
|
3094
|
+
flex: 1;
|
|
3095
|
+
min-height: 0;
|
|
3096
|
+
overflow: hidden;
|
|
3097
|
+
display: flex;
|
|
3098
|
+
flex-direction: column;
|
|
3099
|
+
}
|
|
3100
|
+
|
|
3101
|
+
#mixer-view[hidden] {
|
|
3102
|
+
display: none;
|
|
3103
|
+
}
|
|
3104
|
+
|
|
3105
|
+
/* The one notice line above the strips: disconnected, or a hand edit that was not evaluated. */
|
|
3106
|
+
#mixer-notice {
|
|
3107
|
+
font-size: 0.8125rem;
|
|
3108
|
+
font-weight: 400;
|
|
3109
|
+
line-height: 1.5;
|
|
3110
|
+
color: var(--text-muted);
|
|
3111
|
+
margin: 0;
|
|
3112
|
+
padding: 0.5rem 1rem;
|
|
3113
|
+
border-bottom: 1px solid var(--border);
|
|
3114
|
+
}
|
|
3115
|
+
|
|
3116
|
+
#mixer-notice[hidden] {
|
|
3117
|
+
display: none;
|
|
3118
|
+
}
|
|
3119
|
+
|
|
3120
|
+
#mixer-message {
|
|
3121
|
+
font-size: 1rem;
|
|
3122
|
+
font-weight: 400;
|
|
3123
|
+
line-height: 1.5;
|
|
3124
|
+
color: var(--text-muted);
|
|
3125
|
+
margin: 0;
|
|
3126
|
+
padding: 1rem;
|
|
3127
|
+
}
|
|
3128
|
+
|
|
3129
|
+
#mixer-message[hidden] {
|
|
3130
|
+
display: none;
|
|
3131
|
+
}
|
|
3132
|
+
|
|
3133
|
+
#mixer-body {
|
|
3134
|
+
display: flex;
|
|
3135
|
+
flex: 1;
|
|
3136
|
+
min-height: 0;
|
|
3137
|
+
}
|
|
3138
|
+
|
|
3139
|
+
#mixer-body[hidden] {
|
|
3140
|
+
display: none;
|
|
3141
|
+
}
|
|
3142
|
+
|
|
3143
|
+
/* The MIDI tracks that play no notes, in one quiet line under the strips. */
|
|
3144
|
+
#mixer-nonotes {
|
|
3145
|
+
font-size: 0.8125rem;
|
|
3146
|
+
font-weight: 400;
|
|
3147
|
+
line-height: 1.5;
|
|
3148
|
+
color: var(--text-muted);
|
|
3149
|
+
margin: 0;
|
|
3150
|
+
padding: 0.5rem 1rem;
|
|
3151
|
+
border-top: 1px solid var(--border);
|
|
3152
|
+
}
|
|
3153
|
+
|
|
3154
|
+
#mixer-nonotes[hidden] {
|
|
3155
|
+
display: none;
|
|
3156
|
+
}
|
|
3157
|
+
|
|
3158
|
+
#mixer-strips {
|
|
3159
|
+
flex: 1;
|
|
2568
3160
|
min-width: 0;
|
|
2569
3161
|
min-height: 0;
|
|
2570
3162
|
overflow: auto;
|
|
@@ -2603,6 +3195,196 @@ body {
|
|
|
2603
3195
|
.mx-strip[data-color="7"] { --strip-color: var(--track-7); }
|
|
2604
3196
|
.mx-strip[data-color="8"] { --strip-color: var(--track-8); }
|
|
2605
3197
|
|
|
3198
|
+
/* A group of the song is a frame around the strips of its tracks (and of its sub-groups). The head names the group and
|
|
3199
|
+
stays at the left of the strips area while a wide group scrolls; from the fifth level the frame drops its padding, so a
|
|
3200
|
+
deep tree keeps room for names. A folded group shows its head only. */
|
|
3201
|
+
.mx-group {
|
|
3202
|
+
flex: 0 0 auto;
|
|
3203
|
+
align-self: flex-start;
|
|
3204
|
+
min-height: 100%;
|
|
3205
|
+
min-width: 0;
|
|
3206
|
+
box-sizing: border-box;
|
|
3207
|
+
display: flex;
|
|
3208
|
+
flex-direction: column;
|
|
3209
|
+
gap: 0.5rem;
|
|
3210
|
+
padding: 0.5rem;
|
|
3211
|
+
border: 1px solid var(--border);
|
|
3212
|
+
border-top: 0.25rem solid var(--border);
|
|
3213
|
+
}
|
|
3214
|
+
|
|
3215
|
+
.mx-group[data-deep="true"] {
|
|
3216
|
+
padding: 0;
|
|
3217
|
+
gap: 0;
|
|
3218
|
+
}
|
|
3219
|
+
|
|
3220
|
+
.mx-group-head {
|
|
3221
|
+
position: sticky;
|
|
3222
|
+
left: 1rem;
|
|
3223
|
+
align-self: flex-start;
|
|
3224
|
+
box-sizing: border-box;
|
|
3225
|
+
width: 11rem;
|
|
3226
|
+
display: flex;
|
|
3227
|
+
flex-direction: column;
|
|
3228
|
+
gap: 0.25rem;
|
|
3229
|
+
background: var(--secondary);
|
|
3230
|
+
}
|
|
3231
|
+
|
|
3232
|
+
.mx-group-title {
|
|
3233
|
+
display: flex;
|
|
3234
|
+
align-items: center;
|
|
3235
|
+
gap: 0.5rem;
|
|
3236
|
+
min-width: 0;
|
|
3237
|
+
min-height: 1.5rem;
|
|
3238
|
+
}
|
|
3239
|
+
|
|
3240
|
+
.mx-fold {
|
|
3241
|
+
flex: 1 1 auto;
|
|
3242
|
+
min-width: 0;
|
|
3243
|
+
display: flex;
|
|
3244
|
+
align-items: baseline;
|
|
3245
|
+
gap: 0.5rem;
|
|
3246
|
+
min-height: 1.5rem;
|
|
3247
|
+
margin: 0;
|
|
3248
|
+
padding: 0;
|
|
3249
|
+
background: none;
|
|
3250
|
+
border: 0;
|
|
3251
|
+
color: var(--text);
|
|
3252
|
+
font-family: inherit;
|
|
3253
|
+
font-size: 0.8125rem;
|
|
3254
|
+
font-weight: 600;
|
|
3255
|
+
line-height: 1.25;
|
|
3256
|
+
text-align: left;
|
|
3257
|
+
cursor: pointer;
|
|
3258
|
+
}
|
|
3259
|
+
|
|
3260
|
+
.mx-fold-chevron {
|
|
3261
|
+
flex: 0 0 auto;
|
|
3262
|
+
font-weight: 400;
|
|
3263
|
+
color: var(--text-muted);
|
|
3264
|
+
}
|
|
3265
|
+
|
|
3266
|
+
.mx-fold:hover .mx-fold-chevron {
|
|
3267
|
+
color: var(--text);
|
|
3268
|
+
}
|
|
3269
|
+
|
|
3270
|
+
.mx-fold-name {
|
|
3271
|
+
min-width: 0;
|
|
3272
|
+
overflow: hidden;
|
|
3273
|
+
text-overflow: ellipsis;
|
|
3274
|
+
white-space: nowrap;
|
|
3275
|
+
}
|
|
3276
|
+
|
|
3277
|
+
.mx-fold:focus-visible {
|
|
3278
|
+
outline: 1px solid var(--text-muted);
|
|
3279
|
+
outline-offset: -1px;
|
|
3280
|
+
}
|
|
3281
|
+
|
|
3282
|
+
.mx-group-line {
|
|
3283
|
+
display: flex;
|
|
3284
|
+
align-items: center;
|
|
3285
|
+
gap: 0.25rem;
|
|
3286
|
+
}
|
|
3287
|
+
|
|
3288
|
+
.mx-group-count {
|
|
3289
|
+
flex: 1 1 auto;
|
|
3290
|
+
min-width: 0;
|
|
3291
|
+
overflow: hidden;
|
|
3292
|
+
text-overflow: ellipsis;
|
|
3293
|
+
white-space: nowrap;
|
|
3294
|
+
font-size: 0.8125rem;
|
|
3295
|
+
font-weight: 400;
|
|
3296
|
+
line-height: 1.25;
|
|
3297
|
+
color: var(--text-muted);
|
|
3298
|
+
}
|
|
3299
|
+
|
|
3300
|
+
/* Some of the group's tracks are muted or soloed: a dashed outline in the text colour (the count line says how many). */
|
|
3301
|
+
.mx-group-head .mx-mute[aria-pressed="mixed"],
|
|
3302
|
+
.mx-group-head .mx-solo[aria-pressed="mixed"] {
|
|
3303
|
+
border-style: dashed;
|
|
3304
|
+
border-color: var(--text);
|
|
3305
|
+
color: var(--text);
|
|
3306
|
+
}
|
|
3307
|
+
|
|
3308
|
+
.mx-group-head [data-writes="true"]:disabled {
|
|
3309
|
+
cursor: default;
|
|
3310
|
+
}
|
|
3311
|
+
|
|
3312
|
+
.mx-group-note {
|
|
3313
|
+
margin: 0;
|
|
3314
|
+
font-size: 0.8125rem;
|
|
3315
|
+
font-weight: 400;
|
|
3316
|
+
line-height: 1.25;
|
|
3317
|
+
color: var(--text-muted);
|
|
3318
|
+
overflow-wrap: anywhere;
|
|
3319
|
+
}
|
|
3320
|
+
|
|
3321
|
+
.mx-group-note[hidden] {
|
|
3322
|
+
display: none;
|
|
3323
|
+
}
|
|
3324
|
+
|
|
3325
|
+
.mx-group-body {
|
|
3326
|
+
flex: 1 1 auto;
|
|
3327
|
+
min-width: 0;
|
|
3328
|
+
display: flex;
|
|
3329
|
+
align-items: stretch;
|
|
3330
|
+
gap: 0.5rem;
|
|
3331
|
+
padding-top: 0.5rem;
|
|
3332
|
+
border-top: 1px solid var(--border);
|
|
3333
|
+
}
|
|
3334
|
+
|
|
3335
|
+
.mx-group-body[hidden] {
|
|
3336
|
+
display: none;
|
|
3337
|
+
}
|
|
3338
|
+
|
|
3339
|
+
.mx-group-body > .mx-strip,
|
|
3340
|
+
.mx-group-body > .mx-group {
|
|
3341
|
+
align-self: stretch;
|
|
3342
|
+
min-height: 0;
|
|
3343
|
+
}
|
|
3344
|
+
|
|
3345
|
+
/* A track strip's name row: the light, then the name button. The light's box never changes size, so a blink moves nothing.
|
|
3346
|
+
The loop in the page writes the fade as the fill's opacity; nothing here animates. */
|
|
3347
|
+
.mx-name-row {
|
|
3348
|
+
display: flex;
|
|
3349
|
+
align-items: center;
|
|
3350
|
+
gap: 0.5rem;
|
|
3351
|
+
min-height: 1.5rem;
|
|
3352
|
+
min-width: 0;
|
|
3353
|
+
}
|
|
3354
|
+
|
|
3355
|
+
.mx-name-row > button.mx-name {
|
|
3356
|
+
flex: 1 1 auto;
|
|
3357
|
+
width: auto;
|
|
3358
|
+
min-width: 0;
|
|
3359
|
+
}
|
|
3360
|
+
|
|
3361
|
+
.mx-light {
|
|
3362
|
+
flex: 0 0 auto;
|
|
3363
|
+
position: relative;
|
|
3364
|
+
box-sizing: border-box;
|
|
3365
|
+
width: 0.75rem;
|
|
3366
|
+
height: 0.75rem;
|
|
3367
|
+
border: 1px solid var(--text-muted);
|
|
3368
|
+
border-radius: 50%;
|
|
3369
|
+
}
|
|
3370
|
+
|
|
3371
|
+
.mx-light[hidden] {
|
|
3372
|
+
display: none;
|
|
3373
|
+
}
|
|
3374
|
+
|
|
3375
|
+
.mx-light-fill {
|
|
3376
|
+
position: absolute;
|
|
3377
|
+
inset: 0;
|
|
3378
|
+
border-radius: 50%;
|
|
3379
|
+
background: var(--text);
|
|
3380
|
+
opacity: 0;
|
|
3381
|
+
}
|
|
3382
|
+
|
|
3383
|
+
/* The steady state of motion off only: lit while the track played within the last cycle. */
|
|
3384
|
+
.mx-light[data-lit="true"] .mx-light-fill {
|
|
3385
|
+
opacity: 1;
|
|
3386
|
+
}
|
|
3387
|
+
|
|
2606
3388
|
.mx-name {
|
|
2607
3389
|
font-size: 0.8125rem;
|
|
2608
3390
|
font-weight: 600;
|
|
@@ -3794,6 +4576,19 @@ button.mx-name:focus-visible {
|
|
|
3794
4576
|
color: var(--text-muted);
|
|
3795
4577
|
}
|
|
3796
4578
|
|
|
4579
|
+
/* The section whose harmony the line shows, after the value: shown only for a piece with sections. */
|
|
4580
|
+
#jam-declared-section {
|
|
4581
|
+
flex: none;
|
|
4582
|
+
font-size: 0.8125rem;
|
|
4583
|
+
font-weight: 400;
|
|
4584
|
+
line-height: 1.5;
|
|
4585
|
+
color: var(--text-muted);
|
|
4586
|
+
}
|
|
4587
|
+
|
|
4588
|
+
#jam-declared-section[hidden] {
|
|
4589
|
+
display: none;
|
|
4590
|
+
}
|
|
4591
|
+
|
|
3797
4592
|
#jam-degrees {
|
|
3798
4593
|
display: flex;
|
|
3799
4594
|
flex-direction: row;
|