char-slop/chordpad.vibed.software
git clone https://git.t4t.associates/char-slop/chordpad.vibed.software
040fec5
main
1: root { 2color-scheme : dark; 3font-family : "Inter Variable" , Inter, system-ui, sans-serif; 4font-size : 13 px ; 5 6/* cool greys, against which the warm accents stand out; lines neutral */ 7--bg : oklch ( 19.9 % 0.014 285.1 ); 8--panel : oklch ( 23.1 % 0.017 285 ); 9--panel-2 : oklch ( 27 % 0.022 284.8 ); 10--border : oklch ( 34.7 % 0 0 ); 11/* for the few lines that divide more than the rest */ 12--border-strong : oklch ( 46 % 0 0 ); 13/* around the track being edited */ 14--border-active : oklch ( 64 % 0 0 ); 15--text : oklch ( 95.4 % 0.008 332.1 ); 16--muted : oklch ( 63.9 % 0.023 333.1 ); 17--accent : oklch ( 82.4 % 0.159 330.6 ); 18--accent-mute : oklch ( 63.8 % 0.13 331.4 ); 19/* the accent turned halfway round the hue wheel, for melodies */ 20--accent-melody : oklch ( 82.4 % 0.142 150.6 ); 21/* the accent turned towards purple, and a touch more vivid: chord notes outside the key */ 22--accent-outside : oklch ( 82.4 % 0.16 295.6 ); 23/* the other keys on the key's axis: a minor third up, down, and a tritone away */ 24--accent-sharp : oklch ( 82.4 % 0.127 40.6 ); 25--accent-flat : oklch ( 82.4 % 0.127 210.6 ); 26--accent-inverse : oklch ( 82.4 % 0.127 270.6 ); 27/* the parallel modes: quieter than the axis, and running from the brightest mode (light and 28warm) to the darkest (dim and cool), with the minor scales' variants off to the side in red */ 29--mode-lydian : oklch ( 84 % 0.075 95 ); 30--mode-ionian : oklch ( 80 % 0.075 125 ); 31--mode-mixolydian : oklch ( 76 % 0.075 155 ); 32--mode-dorian : oklch ( 72 % 0.075 185 ); 33--mode-aeolian : oklch ( 68 % 0.075 215 ); 34--mode-phrygian : oklch ( 64 % 0.075 245 ); 35--mode-locrian : oklch ( 60 % 0.075 275 ); 36--mode-harmonicMinor : oklch ( 70 % 0.085 20 ); 37--mode-melodicMinor : oklch ( 75 % 0.085 45 ); 38 39--row-off : oklch ( 20.8 % 0.014 285.1 ); 40--row-scale : oklch ( 24.4 % 0.019 284.9 ); 41--row-tonic : oklch ( 27.3 % 0.036 301 ); 42--line-row : oklch ( 0 % 0 0 / 0.165 ); 43--line-bar : oklch ( 100 % 0 0 / 0.2 ); 44--line-beat : oklch ( 100 % 0 0 / 0.09 ); 45 46--c : var ( --muted ); 47} 48 49/* in the key: nothing to point out */ 50. on-home { 51--c : var ( --text ); 52} 53/* from none of the key, its axis, or its parallel modes */ 54. chromatic { 55--c : var ( --accent ); 56} 57. on-sharp { 58--c : var ( --accent-sharp ); 59} 60. on-flat { 61--c : var ( --accent-flat ); 62} 63. on-inverse { 64--c : var ( --accent-inverse ); 65} 66. from-lydian { 67--c : var ( --mode-lydian ); 68} 69. from-ionian { 70--c : var ( --mode-ionian ); 71} 72. from-mixolydian { 73--c : var ( --mode-mixolydian ); 74} 75. from-dorian { 76--c : var ( --mode-dorian ); 77} 78. from-aeolian { 79--c : var ( --mode-aeolian ); 80} 81. from-phrygian { 82--c : var ( --mode-phrygian ); 83} 84. from-locrian { 85--c : var ( --mode-locrian ); 86} 87. from-harmonicMinor { 88--c : var ( --mode-harmonicMinor ); 89} 90. from-melodicMinor { 91--c : var ( --mode-melodicMinor ); 92} 93 94* { 95box-sizing : border-box; 96} 97 98[hidden ]{ 99display : none!important ; 100} 101 102body { 103margin : 0 ; 104background : var ( --bg ); 105color : var ( --text ); 106} 107 108button , 109input , 110select { 111font : inherit; 112color : inherit; 113background : var ( --panel-2 ); 114border : 1 px solidvar ( --border ); 115padding : 3 px 8 px ; 116} 117button { 118cursor : pointer; 119} 120button : hover : not (: disabled ) { 121border-color : var ( --accent-mute ); 122} 123button : disabled { 124opacity : 0.4 ; 125cursor : default; 126} 127input [type = "checkbox" ]{ 128padding : 0 ; 129accent-color : var ( --accent ); 130} 131 132kbd , 133code { 134font-family : inherit; 135font-size : 11 px ; 136background : var ( --panel-2 ); 137border : 1 px solidvar ( --border ); 138padding : 0 4 px ; 139} 140 141. app { 142display : grid; 143grid-template-rows : auto1 fr auto auto auto; 144height : 100 vh ; 145} 146 147/* the project on the left, the transport in the very middle, settings on the right */ 148. toolbar { 149display : grid; 150grid-template-columns : 1 fr auto1 fr ; 151gap : 8 px 20 px ; 152align-items : center; 153padding : 8 px 12 px ; 154background : var ( --panel ); 155border-bottom : 1 px solidvar ( --border ); 156 157. tb-section { 158display : flex; 159flex-wrap : wrap; 160gap : 8 px 20 px ; 161align-items : center; 162} 163. tb-right { 164justify-content : end; 165} 166 167. tb-group { 168display : flex; 169gap : 6 px ; 170align-items : center; 171} 172label { 173display : flex; 174gap : 6 px ; 175align-items : center; 176color : var ( --muted ); 177} 178. tb-projects { 179max-width : 160 px ; 180} 181. tb-bpm { 182width : 58 px ; 183} 184. tb-play { 185min-width : 70 px ; 186border-color : var ( --accent ); 187} 188} 189 190/* no room for three columns: let it wrap */ 191@media ( max-width : 1080 px ) { 192. toolbar { 193display : flex; 194flex-wrap : wrap; 195} 196} 197 198. timeline { 199overflow : auto; 200user-select : none; 201-webkit-user-select : none; 202background : var ( --bg ); 203} 204 205. tl-content { 206position : relative; 207min-height : 100 % ; 208} 209. tl-rows { 210display : grid; 211} 212 213. tl-corner , 214. ruler { 215position : sticky; 216top : 0 ; 217height : 22 px ; 218background-color : var ( --panel ); 219border-bottom : 1 px solidvar ( --border ); 220z-index : 3 ; 221} 222. tl-corner { 223left : 0 ; 224z-index : 4 ; 225border-right : 1 px solidvar ( --border ); 226} 227. ruler { 228cursor : text; 229 230. loop-region { 231position : absolute; 232top : 0 ; 233bottom : 0 ; 234background : color-mix ( in oklab, var ( --accent ) 22 % , transparent); 235border-inline : 2 px solidvar ( --accent ); 236cursor : default; 237} 238. loop-region . off { 239background : color-mix ( in oklab, var ( --muted ) 12 % , transparent); 240border-color : var ( --muted ); 241} 242/* straddling the region's edges, to grab them by */ 243. loop-edge { 244position : absolute; 245top : 0 ; 246bottom : 0 ; 247width : 9 px ; 248cursor : ew-resize; 249} 250. loop-edge . start { 251left : -6 px ; 252} 253. loop-edge . end { 254right : -6 px ; 255} 256span { 257position : absolute; 258top : 4 px ; 259font-size : 11 px ; 260color : var ( --muted ); 261pointer-events : none; 262} 263} 264 265. track-head { 266position : sticky; 267left : 0 ; 268scroll-margin-top : 22 px ; 269z-index : 2 ; 270background : var ( --panel ); 271border-right : 1 px solidvar ( --border ); 272border-bottom : 1 px solidvar ( --border ); 273padding : 6 px 40 px 6 px 8 px ; 274/* dragged by, to move the track */ 275cursor : grab; 276 277& . active { 278background : var ( --panel-2 ); 279} 280& . active . th-name { 281font-weight : 650 ; 282} 283. th-top { 284display : flex; 285gap : 4 px ; 286} 287. th-name { 288flex : 1 ; 289min-width : 0 ; 290background : transparent; 291border-color : transparent; 292padding : 2 px 4 px ; 293} 294. th-name : hover , 295. th-name : focus { 296border-color : var ( --border ); 297} 298. th-btn { 299padding : 0 6 px ; 300font-size : 11 px ; 301} 302. th-btn . on { 303background : var ( --accent ); 304color : var ( --bg ); 305} 306. th-bass { 307display : flex; 308align-items : center; 309gap : 6 px ; 310padding : 4 px 4 px 0 ; 311color : var ( --muted ); 312font-size : 11 px ; 313input { 314margin : 0 ; 315} 316} 317. th-gain { 318display : flex; 319align-items : center; 320gap : 6 px ; 321padding : 4 px 4 px 0 ; 322color : var ( --muted ); 323font-size : 11 px ; 324font-variant-numeric : tabular-nums; 325input { 326flex : 1 ; 327min-width : 0 ; 328margin : 0 ; 329accent-color : var ( --muted ); 330} 331span { 332width : 44 px ; 333text-align : right; 334} 335} 336} 337 338. keys { 339position : absolute; 340right : 0 ; 341bottom : 0 ; 342width : 34 px ; 343overflow : hidden; 344cursor : ns-resize; 345 346. keys-inner { 347display : flex; 348flex-direction : column; 349will-change : translate; 350} 351 352. key { 353flex : 0 0 10 px ; 354background : oklch ( 88.5 % 0.014 286.1 ); 355border-bottom : 1 px solidoklch ( 0 % 0 0 / 0.2 ); 356font-size : 8 px ; 357line-height : 9 px ; 358color : oklch ( 32.1 % 0 0 ); 359text-align : right; 360padding-right : 2 px ; 361} 362. key . black { 363background : oklch ( 28.9 % 0.018 285.2 ); 364margin-right : 12 px ; 365} 366. key . tonic { 367box-shadow : inset3 px 0 var ( --accent ); 368} 369} 370 371. lane { 372position : relative; 373border-bottom : 1 px solidvar ( --border ); 374} 375 376/* over the borders it shares with the tracks either side, rather than beside them */ 377: is (. track-head , . lane ). active :: after { 378content : "" ; 379position : absolute; 380inset : -1 px 0 ; 381z-index : 1 ; 382border-block : 1 px solidvar ( --border-active ); 383pointer-events : none; 384} 385 386. track-resize { 387position : absolute; 388left : 0 ; 389right : 0 ; 390bottom : 0 ; 391height : 5 px ; 392cursor : row-resize; 393 394& : hover { 395background : color-mix ( in oklab, var ( --accent ) 50 % , transparent); 396} 397} 398/* keep the resize cursor while dragging over other things */ 399body . resizing-track , 400body . resizing-track * { 401cursor : row-resize!important ; 402} 403body . resizing-loop , 404body . resizing-loop * { 405cursor : ew-resize!important ; 406} 407body . panning , 408body . panning * , 409body . reordering , 410body . reordering * { 411cursor : grabbing!important ; 412} 413. reorder-line { 414position : fixed; 415z-index : 10 ; 416height : 2 px ; 417background : var ( --accent ); 418pointer-events : none; 419} 420 421. roll { 422position : relative; 423overflow : hidden; 424cursor : crosshair; 425} 426. roll-inner { 427position : relative; 428/* moved through by transform, so its own layer: moving it then needn't paint it again */ 429will-change : translate; 430} 431 432. lane . notes { 433--note : var ( --accent-melody ); 434} 435 436. note { 437position : absolute; 438overflow : hidden; 439padding-left : 2 px ; 440font-size : 9 px ; 441font-weight : 600 ; 442line-height : 9 px ; 443white-space : nowrap; 444color : oklch ( 0 % 0 0 / 0.7 ); 445background : var ( --note , var ( --accent )); 446box-shadow : inset0 0 0 1 px oklch ( 0 % 0 0 / 0.267 ); 447 448& . selected { 449background : oklch ( 100 % 0 0 ); 450} 451& . outside { 452--note : var ( --accent-outside ); 453} 454& . auto { 455background : color-mix ( in oklab, var ( --note , var ( --accent )) 45 % , var ( --bg )); 456color : oklch ( 100 % 0 0 / 0.75 ); 457} 458/* written but not played: a bass left to another track */ 459& . silent { 460background : none; 461box-shadow : inset0 0 0 1 px color-mix ( in oklab, var ( --note , var ( --accent )) 70 % , transparent); 462color : var ( --muted ); 463} 464& . ghost { 465background : color-mix ( in oklab, var ( --accent-melody ) 30 % , transparent); 466box-shadow : none; 467pointer-events : none; 468} 469} 470. roll > . note : not (. auto ) { 471cursor : grab; 472} 473 474. chord-col { 475position : absolute; 476top : 0 ; 477bottom : 0 ; 478 479/* chords take turns being shaded rather than getting lines: they always start on a grid line, 480and a line of their own would only brighten it */ 481& . alt { 482background : oklch ( 100 % 0 0 / 0.02 ); 483} 484& . current { 485background : oklch ( 100 % 0 0 / 0.039 ); 486} 487} 488 489. strip { 490position : relative; 491background : var ( --panel ); 492border-bottom : 1 px solidvar ( --border ); 493cursor : text; 494} 495 496. chord { 497position : absolute; 498top : 4 px ; 499bottom : 4 px ; 500padding : 3 px 6 px ; 501overflow : hidden; 502white-space : nowrap; 503cursor : grab; 504background : color-mix ( in oklab, var ( --c ) 16 % , var ( --panel-2 )); 505border : 1 px solidcolor-mix ( in oklab, var ( --c ) 40 % , transparent); 506border-left : 2 px solidvar ( --c ); 507 508& . current { 509outline : 2 px solidvar ( --text ); 510outline-offset : -1 px ; 511} 512& . selected { 513background : color-mix ( in oklab, var ( --c ) 34 % , var ( --panel-2 )); 514border-color : var ( --c ); 515} 516& . unknown { 517--c : oklch ( 51 % 0 0 ); 518} 519& . pinned :: after { 520content : "" ; 521position : absolute; 522top : 4 px ; 523right : 8 px ; 524width : 5 px ; 525height : 5 px ; 526border-radius : 50 % ; 527background : var ( --text ); 528} 529 530. chord-name { 531font-weight : 600 ; 532font-size : 14 px ; 533} 534. chord-roman { 535font-size : 11 px ; 536color : var ( --muted ); 537} 538. chord-tag { 539margin-left : 6 px ; 540color : var ( --c ); 541} 542. chord-handle { 543position : absolute; 544top : 0 ; 545right : 0 ; 546bottom : 0 ; 547width : 6 px ; 548cursor : ew-resize; 549} 550} 551 552. tl-line { 553position : absolute; 554top : 0 ; 555bottom : 0 ; 556left : 0 ; 557width : 2 px ; 558margin-left : -1 px ; 559pointer-events : none; 560z-index : 1 ; 561} 562. tl-cursor { 563background : color-mix ( in oklab, var ( --accent ) 60 % , transparent); 564} 565. tl-playhead { 566background : var ( --text ); 567} 568 569. tl-add { 570position : sticky; 571left : 0 ; 572display : flex; 573gap : 6 px ; 574padding : 8 px ; 575z-index : 2 ; 576} 577 578. chord-editor { 579position : absolute; 580z-index : 5 ; 581display : flex; 582gap : 6 px ; 583align-items : center; 584padding : 6 px 4 px ; 585pointer-events : none; 586 587input { 588pointer-events : auto; 589width : 110 px ; 590font-weight : 600 ; 591font-size : 14 px ; 592border-color : var ( --accent ); 593background : var ( --bg ); 594} 595input . invalid { 596border-color : oklch ( 68.8 % 0.201 24.1 ); 597color : oklch ( 79 % 0.121 20.1 ); 598} 599. chord-hint { 600color : var ( --muted ); 601background : var ( --bg ); 602padding : 2 px 6 px ; 603} 604. chord-hint : empty { 605display : none; 606} 607} 608 609. palette { 610background : var ( --panel ); 611border-top : 1 px solidvar ( --border ); 612padding : 6 px 12 px 8 px ; 613 614& [data-open = "false" ]{ 615padding-bottom : 6 px ; 616header { 617margin-bottom : 0 ; 618} 619. palette-body , 620. help , 621label { 622display : none; 623} 624} 625max-height : 34 vh ; 626overflow : auto; 627 628header { 629display : flex; 630gap : 16 px ; 631align-items : center; 632color : var ( --muted ); 633margin-bottom : 6 px ; 634label { 635display : flex; 636gap : 4 px ; 637align-items : center; 638} 639} 640} 641 642. palette-body { 643display : flex; 644gap : 32 px ; 645align-items : start; 646} 647 648. circle { 649flex : none; 650width : 260 px ; 651height : 260 px ; 652 653. circle-chord { 654cursor : pointer; 655path { 656fill : transparent; 657stroke : color-mix ( in oklab, var ( --border ) 70 % , transparent); 658} 659& : hover path { 660fill : var ( --panel-2 ); 661} 662& . here path { 663fill : color-mix ( in oklab, var ( --c ) 18 % , var ( --panel )); 664stroke : var ( --c ); 665} 666text { 667text-anchor : middle; 668pointer-events : none; 669} 670. name { 671fill : var ( --c ); 672font-size : 12 px ; 673font-weight : 600 ; 674} 675. roman { 676fill : var ( --muted ); 677font-size : 8.5 px ; 678} 679/* less room on the inner ring */ 680& . minor . name { 681font-size : 10.5 px ; 682} 683} 684} 685 686. palette-row { 687display : grid; 688grid-template-columns : 110 px repeat ( 7 , 104 px ); 689border-top : 1 px solidcolor-mix ( in oklab, var ( --border ) 60 % , transparent); 690 691/* the key and its axis, then the modes */ 692& . on-inverse + . palette-row { 693border-top-color : var ( --border-strong ); 694} 695 696. palette-mode { 697display : grid; 698align-content : center; 699color : var ( --c ); 700small { 701color : var ( --muted ); 702font-size : 10 px ; 703} 704} 705& . on-home . palette-mode { 706font-weight : 650 ; 707} 708} 709 710. chip { 711display : flex; 712gap : 6 px ; 713align-items : baseline; 714padding : 4 px 6 px ; 715background : none; 716border : none; 717 718b { 719color : var ( --c ); 720font-weight : 600 ; 721} 722span { 723color : var ( --muted ); 724font-size : 11 px ; 725} 726& : hover { 727background : var ( --panel-2 ); 728} 729& . same { 730opacity : 0.35 ; 731} 732} 733 734. hints { 735display : flex; 736gap : 16 px ; 737padding : 6 px 12 px ; 738color : var ( --muted ); 739font-size : 11 px ; 740border-top : 1 px solidvar ( --border ); 741background : var ( --panel ); 742 743. hint kbd + kbd { 744margin-left : 2 px ; 745} 746} 747 748. dialog { 749background : var ( --panel ); 750color : var ( --text ); 751border : 1 px solidvar ( --border ); 752padding : 16 px ; 753width : min ( 560 px , 90 vw ); 754 755& :: backdrop { 756background : oklch ( 0 % 0 0 / 0.5 ); 757} 758h2 { 759margin : 0 0 12 px ; 760font-size : 15 px ; 761} 762} 763 764. dialog-actions { 765display : flex; 766justify-content : flex-end; 767gap : 6 px ; 768margin-top : 12 px ; 769} 770 771. tt-dialog { 772. tt-options { 773display : grid; 774gap : 6 px ; 775max-height : 60 vh ; 776overflow : auto; 777} 778. tt-option { 779display : grid; 780grid-template-columns : 1 fr auto; 781gap : 2 px 12 px ; 782text-align : left; 783padding : 8 px 10 px ; 784} 785. tt-option : focus-visible { 786outline : 2 px solidvar ( --accent ); 787outline-offset : -2 px ; 788} 789. tt-detail { 790color : var ( --muted ); 791} 792. tt-preview { 793grid-column : 1 / -1 ; 794color : var ( --muted ); 795font-size : 11 px ; 796white-space : nowrap; 797overflow : hidden; 798text-overflow : ellipsis; 799} 800. tt-preview : empty { 801display : none; 802} 803} 804 805. midi-dialog { 806. midi-parts { 807display : grid; 808grid-template-columns : auto1 fr auto; 809gap : 6 px 12 px ; 810align-items : baseline; 811max-height : 60 vh ; 812overflow : auto; 813} 814. midi-part { 815display : contents; 816} 817. midi-detail { 818color : var ( --muted ); 819} 820} 821 822. disclosure { 823background : none; 824border : none; 825padding : 0 ; 826font-size : 11 px ; 827white-space : nowrap; 828 829/* a chevron, as on git.t4t.associates */ 830& :: before { 831content : "" ; 832display : inline-block; 833position : relative; 834top : -0.17 em ; 835width : 0.4 em ; 836height : 0.4 em ; 837margin-right : 0.6 em ; 838border-right : 1.5 px solid currentColor; 839border-bottom : 1.5 px solid currentColor; 840transform : rotate ( 45 deg ); 841} 842& [aria-expanded = "false" ]:: before { 843top : -0.05 em ; 844transform : rotate ( -45 deg ); 845} 846} 847 848. help { 849display : inline-grid; 850place-items : center; 851width : 14 px ; 852height : 14 px ; 853border : 1 px solid currentColor; 854border-radius : 50 % ; 855color : var ( --muted ); 856font-size : 9 px ; 857font-weight : 650 ; 858cursor : help; 859 860& : hover { 861color : var ( --accent ); 862} 863} 864. disclosure : hover : not (: disabled ) { 865color : var ( --accent ); 866} 867 868. chord-panel { 869display : flex; 870gap : 16 px ; 871align-items : center; 872padding : 6 px 12 px ; 873background : var ( --panel ); 874border-top : 1 px solidvar ( --border ); 875 876& [data-open = "true" ]. chord-panel-body { 877min-height : 42 px ; 878} 879. chord-panel-body { 880display : flex; 881flex-wrap : wrap; 882gap : 8 px 20 px ; 883/* the buttons in a line, under their labels */ 884align-items : end; 885} 886 887. chord-panel-empty { 888align-self : center; 889color : var ( --muted ); 890} 891. chord-panel-name { 892display : grid; 893min-width : 72 px ; 894& : empty { 895display : none; 896} 897b { 898font-size : 16 px ; 899} 900span { 901color : var ( --muted ); 902font-size : 11 px ; 903} 904} 905. chord-panel-group { 906display : grid; 907gap : 3 px ; 908} 909. chord-panel-label { 910color : var ( --muted ); 911font-size : 11 px ; 912} 913. chord-panel-buttons { 914display : flex; 915gap : 4 px ; 916} 917. chord-panel-action { 918display : flex; 919gap : 6 px ; 920align-items : baseline; 921padding : 3 px 8 px ; 922b { 923font-weight : 650 ; 924} 925} 926} 927 928. select-box { 929position : fixed; 930z-index : 10 ; 931pointer-events : none; 932border : 1 px solidvar ( --accent-melody ); 933background : color-mix ( in oklab, var ( --accent-melody ) 15 % , transparent); 934} 935 936. menu { 937/* undo the centring popovers get by default, so it can sit under its button */ 938inset : auto; 939margin : 0 ; 940padding : 4 px ; 941min-width : 170 px ; 942color : var ( --text ); 943background : var ( --panel-2 ); 944border : 1 px solidvar ( --border ); 945box-shadow : 0 8 px 24 px oklch ( 0 % 0 0 / 0.4 ); 946 947button { 948display : block; 949width : 100 % ; 950text-align : left; 951background : none; 952border : none; 953padding : 5 px 10 px ; 954} 955button : hover { 956background : color-mix ( in oklab, var ( --accent ) 18 % , transparent); 957} 958hr { 959border : none; 960border-top : 1 px solidvar ( --border ); 961margin : 4 px 2 px ; 962} 963}