From 17610f12f35751f51f70e8d8f02b2b6391361055 Mon Sep 17 00:00:00 2001
From: Xiaohan-Tian <157918347+Xiaohan-Tian@users.noreply.github.com>
Date: Thu, 9 Apr 2026 17:31:49 -0700
Subject: [PATCH] refactor: split monolithic App.css into feature-based
co-located CSS files
---
src/App.css | 2029 ---------------------
src/App.tsx | 1 +
src/components/ChatBox.css | 313 ++++
src/components/ChatBox.tsx | 1 +
src/components/InstrumentSelection.css | 123 ++
src/components/InstrumentSelection.tsx | 1 +
src/components/MainContent.css | 105 ++
src/components/MainContent.tsx | 1 +
src/components/StatusBar.css | 16 +
src/components/StatusBar.tsx | 1 +
src/components/Toolbar.css | 155 ++
src/components/Toolbar.tsx | 1 +
src/components/common/FileImportModal.css | 161 ++
src/components/common/FileImportModal.tsx | 1 +
src/components/common/LoadingOverlay.css | 36 +
src/components/common/LoadingOverlay.tsx | 1 +
src/components/piano-roll/PianoRoll.css | 265 +++
src/components/piano-roll/PianoRoll.tsx | 1 +
src/components/settings/Settings.css | 389 ++++
src/components/settings/SettingsPanel.tsx | 1 +
src/components/track/Region.css | 110 ++
src/components/track/RegionItem.tsx | 1 +
src/components/track/Track.css | 207 +++
src/components/track/TrackInfoPanel.tsx | 1 +
src/index.css | 6 +
src/main.tsx | 1 +
src/styles/shared.css | 125 ++
src/styles/variables.css | 11 +
28 files changed, 2035 insertions(+), 2029 deletions(-)
create mode 100644 src/components/ChatBox.css
create mode 100644 src/components/InstrumentSelection.css
create mode 100644 src/components/MainContent.css
create mode 100644 src/components/StatusBar.css
create mode 100644 src/components/Toolbar.css
create mode 100644 src/components/common/FileImportModal.css
create mode 100644 src/components/common/LoadingOverlay.css
create mode 100644 src/components/piano-roll/PianoRoll.css
create mode 100644 src/components/settings/Settings.css
create mode 100644 src/components/track/Region.css
create mode 100644 src/components/track/Track.css
create mode 100644 src/styles/shared.css
create mode 100644 src/styles/variables.css
diff --git a/src/App.css b/src/App.css
index c0d216c..0c36aff 100644
--- a/src/App.css
+++ b/src/App.css
@@ -1,15 +1,3 @@
-:root {
- --time-signature-numerator: 4;
- --max-number-of-bars: 32;
- --track-grid-bar-width: 40px;
- --region-piano-key-width: 60px;
- --region-piano-key-height: 20px;
- --region-grid-beat-width: 40px;
- --region-grid-bar-width: calc(var(--region-grid-beat-width) * var(--time-signature-numerator));
- --chat-box-width: 350px;
- --instrument-selection-width: 300px;
-}
-
/* Reset default styles */
* {
margin: 0;
@@ -50,994 +38,6 @@ body {
overflow: hidden;
}
-/* Toolbar */
-.toolbar {
- display: flex;
- justify-content: space-between;
- align-items: center;
- background-color: #2d2d2d;
- height: 50px;
- padding: 0 10px;
- border-bottom: 1px solid #3a3a3a;
-}
-
-.toolbar-left, .toolbar-center, .toolbar-right {
- display: flex;
- align-items: center;
-}
-
-.toolbar-left {
- display: flex;
- align-items: center;
-}
-
-.logo-container {
- margin-right: 10px;
- display: flex;
- align-items: center;
-}
-
-.logo {
- height: 30px;
- width: auto;
-}
-
-.project-name {
- font-size: 14px;
- color: #e0e0e0;
- margin-right: 20px;
- display: flex;
- align-items: center;
- pointer-events: auto;
-}
-
-.toolbar button {
- background: transparent;
- border: none;
- color: #e0e0e0;
- margin: 0 5px;
- padding: 5px;
- cursor: pointer;
- display: flex;
- align-items: center;
- justify-content: center;
- border-radius: 3px;
- font-size: 14px;
- pointer-events: auto;
-}
-
-.toolbar button:hover {
- background-color: #3a3a3a;
-}
-
-.toolbar button:disabled {
- color: #666;
- cursor: not-allowed;
-}
-
-.record-btn {
- color: #ff4444;
-}
-
-.toolbar-separator {
- width: 1px;
- height: 20px;
- background-color: #555;
- margin: 0 10px;
-}
-
-.transport-control {
- display: flex;
- align-items: center;
- margin: 0 10px;
- pointer-events: auto;
-}
-
-.transport-item {
- margin: 0 5px;
- padding: 2px 2px;
- background-color: #3a3a3a;
- border-radius: 3px;
- font-size: 12px;
-}
-
-/* Fixed-width font for time display to prevent layout shifts */
-.current-time {
- font-family: 'Courier New', 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
- font-weight: normal;
- letter-spacing: 0.5px;
- padding: 2px 4px;
-}
-
-/* Clickable BPM styling */
-.current-bpm {
- font-family: 'Courier New', 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
- font-weight: normal;
- letter-spacing: 0.5px;
- cursor: pointer;
- transition: background-color 0.2s ease;
- padding: 2px 4px;
- border-radius: 2px;
-}
-
-.current-bpm:hover {
- background-color: #4a4a4a;
- color: #fff;
-}
-
-/* Clickable time signature styling */
-.current-time-signature {
- font-family: 'Courier New', 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
- font-weight: normal;
- letter-spacing: 0.5px;
- cursor: pointer;
- transition: background-color 0.2s ease;
- padding: 2px 4px;
- border-radius: 2px;
-}
-
-.current-time-signature:hover {
- background-color: #4a4a4a;
- color: #fff;
-}
-
-.current-key-signature {
- font-family: 'Courier New', 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
- font-weight: normal;
- letter-spacing: 0.5px;
- cursor: pointer;
- transition: background-color 0.2s ease;
- padding: 2px 4px;
- border-radius: 2px;
-}
-
-.current-key-signature:hover {
- background-color: #4a4a4a;
- color: #fff;
-}
-
-.export-dropdown .quant-dropdown {
- width: 250px;
- left: 0;
-}
-
-/* Main content */
-.main-content {
- display: flex;
- flex-direction: column;
- flex: 1;
- overflow: auto; /* Main scrollable container */
- position: relative;
-}
-
-.main-content-wrapper {
- display: flex;
- flex-direction: column;
- min-width: calc(200px + var(--max-number-of-bars) * var(--track-grid-bar-width)); /* info width + grid width */
- min-height: fit-content;
- position: relative;
-}
-
-.top-left-spacer {
- position: fixed;
- top: 50px;
- left: 0;
- width: 200px;
- height: 20px;
- background-color: #2d2d2d;
- border-bottom: 1px solid #3a3a3a;
- border-right: 1px solid #3a3a3a;
- z-index: 1002; /* Higher than other elements to ensure it's always visible */
-}
-
-/* Offset spacer when instrument selection panel is visible on the left */
-.main-content.has-left-instrument .top-left-spacer {
- left: 300px;
-}
-
-.bar-numbers {
- position: sticky;
- top: 0;
- height: 20px;
- display: flex;
- border-bottom: 1px solid #3a3a3a;
- background-color: #2d2d2d;
- z-index: 20;
- margin-left: 200px; /* Offset for info-container */
- width: calc(var(--max-number-of-bars) * var(--track-grid-bar-width)); /* Exact width for 32 bars */
- cursor: pointer; /* Show pointer cursor on hover to indicate interactivity */
-}
-
-.bar-numbers:hover {
- cursor: url("data:image/svg+xml,%3csvg width='16' height='16' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M4 6h8l-4 4-4-4z' fill='%23e0e0e0'/%3e%3c/svg%3e") 8 8, pointer;
-}
-
-.bar-number-cell {
- min-width: var(--track-grid-bar-width);
- width: var(--track-grid-bar-width);
- flex-shrink: 0;
- flex-grow: 0;
- height: 20px;
- text-align: center;
- font-size: 12px;
- border-right: 1px solid #3a3a3a;
- color: #999;
- display: flex;
- align-items: center;
- justify-content: center;
- box-sizing: border-box;
-}
-
-.bar-number-cell.looped {
- background-color: #e1ae01;
- color: #1e1e1e;
-}
-
-.main-content-body {
- display: flex;
- min-height: fit-content;
-}
-
-.info-container {
- position: sticky;
- left: 0;
- width: 200px;
- z-index: 1002;
- background-color: #2d2d2d;
- align-self: flex-start;
-}
-
-/* Shift the bar numbers and info panel when instrument selection is present */
-/* No need to shift bar numbers or info container; they live inside main content.
- Only shift the fixed spacer when the left panel is present. */
-
-.track-top-spacer {
- height: 20px;
- border-bottom: 1px solid #3a3a3a;
- background-color: #2d2d2d;
- position: sticky;
- top: 0;
- z-index: 15;
-}
-
-.grid-container {
- margin-left: 0; /* No need for margin since we're using flex */
- min-width: calc(var(--max-number-of-bars) * var(--track-grid-bar-width)); /* Ensure minimum width */
- min-height: fit-content;
- position: relative; /* Required for absolute positioned playhead */
-}
-
-.track-grid {
- display: block;
- height: 120px;
- min-width: calc(var(--max-number-of-bars) * var(--track-grid-bar-width)); /* 32 bars * --track-grid-bar-width */
- background-size: var(--track-grid-bar-width) 120px;
- background-image:
- /* Vertical lines for bars */
- linear-gradient(to right,
- transparent calc(var(--track-grid-bar-width) - 1px), #3a3a3a calc(var(--track-grid-bar-width) - 1px), #3a3a3a var(--track-grid-bar-width)
- );
- position: relative;
- border-bottom: 1px solid #3a3a3a;
-}
-
-.track-grid.pencil-cursor {
- cursor: crosshair;
-}
-
-.add-track-btn {
- background: transparent;
- border: none;
- outline: none;
- color: #999;
- cursor: pointer;
- font-size: 12px;
- padding: 0;
- height: 100%;
- width: 100%;
- display: flex;
- align-items: center;
- justify-content: center;
-}
-
-.add-track-btn:focus,
-.add-track-btn:focus-visible {
- outline: none;
-}
-
-.add-track-btn:hover {
- color: #e0e0e0;
-}
-
-.track {
- display: flex;
- height: 120px;
- position: relative;
- border-bottom: none;
-}
-
-.track-info {
- width: 200px;
- height: 120px;
- padding: 15px;
- background-color: #2d2d2d;
- display: flex;
- flex-direction: column;
- border-right: 1px solid #3a3a3a;
- border-bottom: 1px solid #3a3a3a;
- flex-shrink: 0;
- box-sizing: border-box;
- cursor: grab;
- position: relative;
-}
-
-.track-info:active {
- cursor: grabbing;
-}
-
-.track-info.selected {
- background-color: #363636;
-}
-
-/* Drag and drop styles */
-.track-info.drag-over {
- border-top: 2px solid #7b68ee;
-}
-
-.track-grid.drag-over {
- border-top: 2px solid #7b68ee;
-}
-
-/* Dragging state */
-.track-info.dragging {
- opacity: 0.5;
- background-color: #444;
-}
-
-.track-grid.dragging {
- opacity: 0.5;
- background-color: #333;
-}
-
-/* Remove drag indicator since hover cursor is sufficient */
-
-.track-name {
- font-size: 12px;
- cursor: pointer;
- position: relative;
-}
-
-.track-name:hover {
- color: #7b68ee;
-}
-
-.track-name:hover::before {
- content: "✎";
- position: absolute;
- right: 0px;
- font-size: 16px;
- opacity: 1;
-}
-
-.track-controls {
- display: flex;
- flex-direction: column;
- width: 100%;
- height: 100%;
-}
-
-.track-name-and-volume {
- display: flex;
- flex-direction: row;
- flex: 1;
- align-items: flex-start;
- gap: 8px;
-}
-
-.instrument-image {
- flex-shrink: 0;
- margin-top: -10px;
- margin-left: -10px;
-}
-
-.instrument-image img {
- display: block;
- border-radius: 4px;
-}
-
-.track-name-and-controls {
- display: flex;
- flex-direction: column;
- flex: 1;
- min-width: 0;
-}
-
-.volume-slider {
- margin-bottom: 15px;
- width: 100%;
- display: flex;
- align-items: center;
- gap: 6px;
-}
-
-.volume-slider input[type="range"] {
- flex: 1;
- min-width: 0;
- height: 6px;
-}
-
-.volume-slider .reset-volume {
- flex-shrink: 0;
- width: 16px;
- height: 16px;
- border-radius: 8px;
- background: #3a3a3a;
- color: #e0e0e0;
- /* border: 1px solid #444; */
- display: inline-flex;
- align-items: center;
- justify-content: center;
- cursor: pointer;
- font-size: 10px;
-}
-
-.volume-slider .reset-volume:hover {
- background: #4a4a4a;
-}
-
-.pan-controls {
- display: flex;
-}
-
-.pan-controls button {
- background: #3a3a3a;
- border: none;
- color: #e0e0e0;
- margin-right: 5px;
- width: 24px;
- height: 24px;
- font-size: 12px;
- border-radius: 2px;
- cursor: pointer;
- display: flex;
- align-items: center;
- justify-content: center;
-}
-
-.pan-controls button.solo.active {
- background: #c8a400; /* yellow */
- color: #101010;
-}
-
-.pan-controls button.mute.active {
- background: #d32f2f; /* red */
- color: #ffffff;
-}
-
-/* Status bar */
-.status-bar {
- display: flex;
- justify-content: space-between;
- align-items: center;
- background-color: #2d2d2d;
- padding: 5px 10px;
- font-size: 12px;
- color: #999;
- border-top: 1px solid #3a3a3a;
- height: 30px;
-}
-
-.status-right span {
- margin-left: 15px;
-}
-
-/* For the piano roll (to be implemented later) */
-.piano-roll {
- background-color: #7b68ee;
- height: 100%;
-}
-
-/* Piano Roll Panel */
-.piano-roll-panel {
- position: fixed;
- background-color: #2d2d2d;
- border: 1px solid #3a3a3a;
- box-shadow: 0 0 20px rgba(0, 0, 0, 0.5);
- display: flex;
- flex-direction: column;
- overflow: hidden;
-}
-
-/* Piano notes */
-.piano-note {
- position: absolute;
- background-color: #ff5555; /* Red color */
- border: 1px solid #999;
- border-radius: 2px;
- z-index: 10;
- cursor: pointer;
- user-select: none;
- box-sizing: border-box;
-}
-
-.piano-note:hover {
- filter: brightness(1.1);
- box-shadow: 0 0 5px rgba(255, 85, 85, 0.5);
-}
-
-.piano-note.dragging {
- opacity: 0.8;
- box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
- z-index: 100;
- cursor: grabbing;
-}
-
-.piano-note.resizing {
- opacity: 0.8;
- box-shadow: 0 0 10px rgba(255, 85, 85, 0.7);
- z-index: 100;
-}
-
-.piano-note.selected {
- border: 2px solid white;
- z-index: 50;
-}
-
-.piano-roll-header {
- height: 30px;
- background-color: #1e1e1e;
- border-bottom: 1px solid #3a3a3a;
- display: flex;
- align-items: center;
- padding: 0 10px;
- cursor: move;
- user-select: none;
-}
-
-/* Piano roll toolbar */
-.piano-roll-toolbar {
- height: 30px;
- background-color: #252525;
- border-bottom: 1px solid #3a3a3a;
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 0 10px;
- user-select: none;
- position: relative;
- z-index: 100; /* Ensure toolbar and its dropdowns appear above piano roll content */
-}
-
-/* Override pointer-events for piano roll toolbar sections */
-.piano-roll-toolbar .toolbar-left,
-.piano-roll-toolbar .toolbar-right {
- pointer-events: auto;
-}
-
-.piano-roll-toolbar .quant-button {
- font-size: 10px;
-}
-
-.piano-roll-toolbar .toolbar-left .quant-button {
- margin-left: 0px;
- margin-right: 5px;
-}
-
-.piano-roll-toolbar .toolbar-left .quant-dropdown {
- left: 0;
-}
-
-/* Generic button blink effect */
-.quant-button.button-blink {
- animation: buttonBlink 0.2s ease-in-out;
-}
-
-@keyframes buttonBlink {
- 0% { background-color: #333; }
- 50% { background-color: #555; }
- 100% { background-color: #333; }
-}
-
-.toolbar-left, .toolbar-right {
- display: flex;
- align-items: center;
- z-index: 1;
- pointer-events: none;
-}
-
-.toolbar-left {
- width: 20%;
- justify-content: flex-start;
-}
-
-.toolbar-right {
- width: 33%;
- justify-content: flex-end;
- z-index: 1500;
-}
-
-.toolbar-center {
- position: absolute;
- left: 50%;
- transform: translateX(-50%);
- display: flex;
- align-items: center;
- justify-content: center;
- z-index: 1005;
- margin-left: -50px;
-}
-
-.tool-button {
- width: 30px;
- height: 30px;
- background-color: transparent;
- border: none;
- border-radius: 3px;
- color: #999;
- font-size: 14px;
- display: flex;
- align-items: center;
- justify-content: center;
- cursor: pointer;
- margin: 0 2px;
-}
-
-.tool-button:hover {
- background-color: #3a3a3a;
- color: #e0e0e0;
-}
-
-.tool-button.active {
- background-color: #4a4a4a;
- color: #e0e0e0;
-}
-
-.chatbox-export-dropdown .quant-dropdown {
- width: 250px;
- left: -200px;
-}
-
-.key-signature-dropdown .quant-dropdown {
- width: 100px;
- left: 0;
-}
-
-.quant-button {
- background-color: #333;
- border: 1px solid #444;
- border-radius: 3px;
- color: #e0e0e0;
- font-size: 12px;
- padding: 3px 8px;
- margin-left: 5px;
- cursor: pointer;
- display: flex;
- align-items: center;
- gap: 5px;
-}
-
-.quant-button:hover {
- background-color: #444;
-}
-
-.quant-dropdown-container {
- position: relative;
- display: inline-block;
- z-index: 1500;
-}
-
-.quant-dropdown {
- position: absolute;
- top: 100%;
- right: 0;
- background-color: #2d2d2d;
- border: 1px solid #444;
- border-radius: 3px;
- width: 100px;
- z-index: 1500;
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
- margin-top: 2px;
- max-height: 200px;
- overflow-y: auto;
-}
-
-.quant-option {
- padding: 6px 10px;
- font-size: 12px;
- color: #e0e0e0;
- cursor: pointer;
- transition: background-color 0.2s;
-}
-
-.quant-option:hover {
- background-color: #444;
-}
-
-.quant-option.active {
- background-color: #4a6b8a;
-}
-
-.piano-roll-title {
- flex: 1;
- text-align: center;
- font-size: 14px;
- color: #e0e0e0;
- text-transform: uppercase;
- cursor: pointer;
- padding: 5px;
- border-radius: 3px;
-}
-
-.close-button {
- background: transparent;
- border: none;
- color: #e0e0e0;
- cursor: pointer;
- font-size: 14px;
- padding: 5px;
-}
-
-.close-button:hover {
- color: #ff4444;
-}
-
-.piano-roll-content {
- display: flex;
- flex-direction: column;
- flex: 1;
- overflow: auto;
-}
-
-.piano-grid-header {
- display: grid;
- grid-template-columns: repeat(var(--max-number-of-bars), var(--region-grid-bar-width));
- width: calc(var(--max-number-of-bars) * var(--region-grid-bar-width) + var(--region-piano-key-width) - 1px);
- min-width: 100%;
- height: 20px;
- border-bottom: 1px solid #3a3a3a;
- background-color: #1e1e1e;
- padding-left: calc(var(--region-piano-key-width) - 1px);
- box-sizing: border-box;
- position: sticky;
- top: 0;
- z-index: 20;
- cursor: pointer; /* Show pointer cursor on hover to indicate interactivity */
-}
-
-.piano-grid-header:hover {
- cursor: url("data:image/svg+xml,%3csvg width='16' height='16' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M4 6h8l-4 4-4-4z' fill='%23e0e0e0'/%3e%3c/svg%3e") 8 8, pointer;
-}
-
-.piano-bar-number {
- border-left: 1px solid #3a3a3a;
- padding-left: 10px;
- font-size: 10px;
-}
-
-.piano-roll-body {
- display: flex;
- min-height: calc(8 * 12 * var(--region-piano-key-height)); /* 8 octaves * 12 notes * piano key height */
- width: calc(var(--max-number-of-bars) * var(--region-grid-bar-width) + var(--region-piano-key-width)); /* 32 bars * 160px width + piano keys width */
-}
-
-.piano-keys-container {
- width: var(--region-piano-key-width);
- flex-shrink: 0;
- overflow: hidden;
- border-right: 1px solid #3a3a3a;
- background-color: #252525;
- position: sticky;
- left: 0;
- z-index: 10;
-}
-
-.piano-grid-container {
- flex: 1;
- min-width: calc(var(--max-number-of-bars) * var(--region-grid-bar-width));
- min-height: calc(8 * 12 * var(--region-piano-key-height));
- z-index: 5;
-}
-
-.piano-octave {
- display: flex;
- flex-direction: column;
-}
-
-.piano-key {
- width: var(--region-piano-key-width);
- height: var(--region-piano-key-height);
- box-sizing: border-box;
- display: flex;
- align-items: center;
- border-bottom: 1px solid #3a3a3a;
-}
-
-.piano-key.natural {
- background-color: #e0e0e0;
- color: #222;
-}
-
-.piano-key.sharp {
- background-color: #222;
- color: #e0e0e0;
-}
-
-.key-label {
- font-size: 10px;
- padding-left: 5px;
-}
-
-.piano-grid {
- width: 100%;
- height: 100%;
- position: relative;
- background-size: var(--region-grid-beat-width) var(--region-piano-key-height), 100% 100%;
- /* background-image is now set dynamically via React inline styles in PianoGrid component */
-}
-
-.piano-grid.pencil-cursor {
- cursor: crosshair;
-}
-
-/* Piano Grid Cursor Highlights */
-.piano-grid-pitch-highlight {
- position: absolute;
- left: 0;
- right: 0;
- background-color: rgba(123, 104, 238, 0.15);
- border-top: 1px solid rgba(123, 104, 238, 0.3);
- border-bottom: 1px solid rgba(123, 104, 238, 0.3);
- pointer-events: none;
- z-index: 1;
- transition: opacity 0.1s ease;
-}
-
-.piano-grid-beat-highlight {
- position: absolute;
- top: 0;
- bottom: 0;
- background-color: rgba(123, 104, 238, 0.1);
- border-left: 1px solid rgba(123, 104, 238, 0.25);
- border-right: 1px solid rgba(123, 104, 238, 0.25);
- pointer-events: none;
- z-index: 1;
- transition: opacity 0.1s ease;
-}
-
-.piano-grid-chord-highlight {
- position: absolute;
- background-color: rgba(255, 77, 77, 0.25);
- border: 1px solid rgba(255, 77, 77, 0.8);
- pointer-events: none;
- z-index: 2;
- transition: opacity 0.1s ease;
-}
-
-.resize-handle {
- position: absolute;
- right: 5px;
- bottom: 5px;
- width: 20px;
- height: 20px;
- cursor: nwse-resize;
- color: #999;
- display: flex;
- align-items: center;
- justify-content: center;
- z-index: 100;
-}
-
-/* Track Region Styles */
-.track-region {
- position: absolute;
- background-color: #4a6b8a;
- border: 2px solid #5a7b9a;
- border-radius: 3px;
- height: calc(100%);
- margin: 0px;
- overflow: hidden;
- display: flex;
- flex-direction: column;
- cursor: pointer;
- user-select: none;
- transition: box-shadow 0.1s ease;
- will-change: transform;
-}
-
-.track-region:hover {
- box-shadow: 0 0 0 1px #7a9bba;
-}
-
-.track-region.selected {
- /* box-shadow: 0 0 0 2px #ffffff, 0 0 8px rgba(255, 255, 255, 0.3); */ /* let's only apply a border */
- border-color: #ffffff;
-}
-
-.track-region.dragging {
- opacity: 0.8;
- box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
- z-index: 100;
- pointer-events: none;
- transform-origin: center center;
- animation: pulse 1.5s infinite;
- cursor: grabbing;
- transition: none; /* Remove transition during drag for immediate response */
-}
-
-@keyframes pulse {
- 0% {
- box-shadow: 0 0 0 0 rgba(122, 155, 186, 0.7);
- }
- 70% {
- box-shadow: 0 0 0 5px rgba(122, 155, 186, 0);
- }
- 100% {
- box-shadow: 0 0 0 0 rgba(122, 155, 186, 0);
- }
-}
-
-.region-header {
- background-color: #5a7b9a;
- color: #fff;
- padding: 2px 6px;
- font-size: 11px;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- cursor: move;
- height: 18px;
- user-select: none;
-}
-
-.track-region:hover .region-header {
- background-color: #6a8baa;
-}
-
-.region-content {
- height: calc(100% - 18px);
- background-color: #87CEFA; /* Light blue */
- width: 100%;
- position: relative; /* Allow overlayed controls */
-}
-
-/* Region pencil trigger inside content */
-.region-pencil-btn {
- position: absolute;
- top: 4px;
- left: 4px;
- background: rgba(0, 0, 0, 0.25);
- color: #fff;
- border: 1px solid rgba(255, 255, 255, 0.2);
- border-radius: 3px;
- padding: 2px;
- margin: 0;
- cursor: pointer;
- z-index: 2;
- display: inline-flex;
- align-items: center;
- justify-content: center;
-}
-
-.region-pencil-btn:hover {
- background: rgba(0, 0, 0, 0.35);
-}
-
-/* Instrument dropdown specific styles */
-.instrument-dropdown .quant-dropdown {
- min-width: 80px;
- width: auto;
- right: auto;
- left: 0;
-}
-
-/* Settings dropdown specific styles */
-.settings-dropdown .quant-dropdown {
- min-width: 100px;
- width: auto;
- right: auto;
- left: 0;
-}
-
/* Update structure in JSX to match this pattern:
@@ -1049,1032 +49,3 @@ body {
*/
-
-/* ChatBox */
-.chatbox {
- display: flex;
- flex-direction: column;
- width: var(--chat-box-width);
- background-color: #2d2d2d;
- border-left: 1px solid #3a3a3a;
- flex-shrink: 0;
-}
-
-.chatbox.is-hidden {
- display: none;
-}
-
-/* Instrument Selection Panel */
-.instrument-selection {
- display: flex;
- flex-direction: column;
- width: var(--instrument-selection-width);
- background-color: #2d2d2d;
- border-right: 1px solid #3a3a3a;
- flex-shrink: 0;
- position: relative;
-}
-
-.instrument-selection-header {
- display: flex;
- align-items: center;
- justify-content: space-between;
- height: 40px;
- padding: 0 12px;
- background-color: transparent;
- border: none;
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- z-index: 2;
-}
-
-.instrument-selection-header h3 {
- color: #e0e0e0;
- font-size: 12px;
- font-weight: bold;
-}
-
-.instrument-selection-close-btn {
- background: transparent;
- border: none;
- color: #e0e0e0;
- cursor: pointer;
- padding: 4px;
- border-radius: 3px;
-}
-
-.instrument-selection-close-btn:hover {
- background-color: #4a4a4a;
-}
-
-.instrument-selection-top {
- height: 300px;
- position: relative;
- border-bottom: 1px solid #3a3a3a;
- overflow: hidden;
- background-image:
- linear-gradient(rgba(0,0,0,0.35), rgba(0,0,0,0.35)),
- url('/resources/instrument_bg.png');
- background-size: cover; /* fill while keeping aspect ratio */
- background-position: center;
-}
-
-.instrument-preview {
- position: absolute;
- inset: 0;
- display: flex;
- align-items: center;
- justify-content: center;
-}
-
-.instrument-preview img {
- width: 256px;
- height: 256px;
- object-fit: contain;
- border-radius: 6px;
- opacity: 1;
-}
-
-.instrument-name-overlay {
- position: absolute;
- bottom: 16px;
- left: 0;
- right: 0;
- text-align: center;
- font-size: 12px;
- color: #e0e0e0;
- text-shadow: 0 1px 2px rgba(0,0,0,0.6);
- z-index: 1;
- font-size: 16px;
- font-weight: bold;
-}
-
-.instrument-selection-bottom {
- flex: 1;
- display: grid;
- grid-template-columns: 1fr 1fr;
- min-height: 0; /* allow children to scroll */
-}
-
-.instrument-groups, .instrument-list {
- overflow: hidden;
-}
-
-/* vertical divider between groups and instruments */
-.instrument-groups {
- border-right: 1px solid #3a3a3a;
-}
-
-.instrument-groups-list, .instrument-instruments-list {
- height: 100%;
- overflow-y: auto;
-}
-
-.instrument-group-item, .instrument-instrument-item {
- padding: 8px 12px;
- /* remove per-item separators */
- border-bottom: none;
- cursor: pointer;
- font-size: 12px;
- color: #e0e0e0;
-}
-
-.instrument-group-item:hover, .instrument-instrument-item:hover {
- background-color: #3a3a3a;
-}
-
-.instrument-group-item.active, .instrument-instrument-item.active {
- background-color: #4a4a4a;
-}
-
-.chatbox-header {
- display: flex;
- align-items: center;
- justify-content: space-between; /* left title, right actions */
- background-color: #3a3a3a;
- height: 40px;
- border-bottom: 1px solid #4a4a4a;
- padding: 0 15px;
-}
-
-.chatbox-actions {
- display: flex;
- gap: 8px;
- align-items: center;
-}
-
-.chatbox-action-btn {
- background: transparent;
- border: none;
- cursor: pointer;
- padding: 4px;
- display: inline-flex;
- align-items: center;
- justify-content: center;
- color: #e0e0e0;
- font-size: 14px;
-}
-
-.chatbox-action-btn:hover {
- background-color: #4a4a4a;
- border-radius: 3px;
-}
-
-/* ChatBox export button wrapper and dropdown positioning */
-.chatbox-export-wrapper {
- position: relative;
- display: inline-block;
-}
-
-.chatbox-export-btn {
- display: flex;
- align-items: center;
- gap: 4px;
-}
-
-.chatbox-export-dropdown-anchor {
- position: absolute;
- top: 100%;
- left: 0;
- z-index: 10000;
-}
-
-.chatbox-header h3 {
- color: #e0e0e0;
- font-size: 12px;
- font-weight: bold;
- margin: 0;
-}
-
-.chatbox-content {
- flex: 1;
- padding: 15px;
- color: #e0e0e0;
- font-size: 12px;
- overflow-y: auto;
-}
-
-/* Chat Messages */
-.chatbox-messages {
- flex: 1;
- padding: 10px;
- overflow-y: auto;
- display: flex;
- flex-direction: column;
- gap: 12px;
-}
-
-.message-container {
- width: 100%;
- word-wrap: break-word;
-}
-
-.message-user {
- width: 100%;
-}
-
-.message-assistant {
- width: 100%;
-}
-
-.message-content {
- padding: 8px 12px;
- border-radius: 8px;
- font-size: 12px;
- line-height: 1.4;
-}
-
-/* User message styling - lighter background like input */
-.message-user .message-content {
- background-color: #3a3a3a;
- color: #e0e0e0;
- border: 1px solid #4a4a4a;
-}
-
-/* Assistant message styling - transparent */
-.message-assistant .message-content {
- background-color: transparent;
- color: #e0e0e0;
- border: 1px solid #2a2a2a;
-}
-
-/* Input Area */
-.chatbox-input-area {
- padding: 10px;
-}
-
-.chatbox-input {
- width: 100%;
- padding: 8px 12px;
- background-color: #4a4a4a;
- border: 1px solid #5a5a5a;
- border-radius: 6px;
- color: #e0e0e0;
- font-size: 12px;
- outline: none;
- resize: none;
- min-height: 36px;
- max-height: 120px;
-}
-
-.chatbox-input:focus {
- border-color: #6a6a6a;
- background-color: #4a4a4a;
-}
-
-.chatbox-input::placeholder {
- color: #999;
-}
-
-
-/* Markdown styling in messages */
-.message-content h1,
-.message-content h2,
-.message-content h3 {
- margin: 8px 0 4px 0;
- color: #e0e0e0;
-}
-
-.message-content h3 {
- font-size: 14px;
-}
-
-.message-content p {
- margin: 4px 0;
-}
-
-.message-content ul,
-.message-content ol {
- margin: 4px 0;
- padding-left: 16px;
-}
-
-.message-content li {
- margin: 2px 0;
-}
-
-.message-content code {
- background-color: #2a2a2a;
- padding: 2px 4px;
- border-radius: 3px;
- font-family: 'Courier New', Courier, monospace;
- font-size: 11px;
-}
-
-.message-content pre {
- background-color: #1a1a1a;
- padding: 8px;
- border-radius: 6px;
- overflow-x: auto;
- margin: 8px 0;
-}
-
-.message-content blockquote {
- border-left: 3px solid #5a5a5a;
- padding-left: 12px;
- margin: 8px 0;
- color: #ccc;
-}
-
-.message-content table {
- border-collapse: collapse;
- width: 100%;
- margin: 8px 0;
- font-size: 11px;
-}
-
-.message-content th,
-.message-content td {
- border: 1px solid #4a4a4a;
- padding: 4px 8px;
- text-align: left;
-}
-
-.message-content th {
- background-color: #3a3a3a;
- font-weight: bold;
-}
-
-textarea {
- font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
- font-size: 12px;
- line-height: 1.4;
-}
-
-/* Abort link styling */
-.abort-link {
- background: none !important;
- border: none !important;
- color: #7b68ee !important;
- text-decoration: underline !important;
- cursor: pointer !important;
- padding: 0 !important;
- font: inherit !important;
- font-size: 12px !important;
-}
-
-.abort-link:hover {
- color: #9b88ff !important;
- text-decoration: none !important;
-}
-
-/* Tool XML Expander */
-.tool-xml-expander {
- margin-bottom: 8px;
-}
-
-.tool-xml-expander-header {
- color: #e0e0e0;
- cursor: pointer;
- user-select: none;
- padding: 4px 8px;
- /* background-color: #f5f5f5; */
- border: 1px solid #2a2a2a;
- border-radius: 4px;
- display: flex;
- align-items: center;
- gap: 8px;
-}
-
-.tool-xml-expander-arrow {
- font-size: 12px;
- color: #666;
-}
-
-.tool-xml-expander-title {
- /* font-family: 'Courier New', Monaco, 'Menlo', 'Ubuntu Mono', monospace; */
- font-size: 12px;
- font-weight: bold;
- color: #e0e0e0;
-}
-
-.tool-xml-expander-content {
- margin-top: 4px;
- padding: 8px;
- background-color: #f9f9f9;
- border: 1px solid #ddd;
- border-radius: 4px;
- font-family: 'Courier New', Monaco, 'Menlo', 'Ubuntu Mono', monospace;
- font-size: 12px;
- white-space: pre-wrap;
- overflow: auto;
- max-height: 200px;
- color: #333;
-}
-
-/* Settings Panel Styles */
-.settings-panel {
- width: 100%;
- height: 100%;
- background-color: #1e1e1e;
- display: flex;
- flex-direction: column;
-}
-
-.settings-container {
- display: flex;
- height: 100%;
- overflow: hidden;
-}
-
-/* Settings Sidebar */
-.settings-sidebar {
- width: 250px;
- background-color: #2d2d2d;
- border-right: 1px solid #3a3a3a;
- display: flex;
- flex-direction: column;
-}
-
-.settings-sidebar-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: 20px;
- border-bottom: 1px solid #3a3a3a;
-}
-
-.settings-sidebar-header h2 {
- color: #e0e0e0;
- font-size: 18px;
- font-weight: 600;
- margin: 0;
-}
-
-.settings-close-btn {
- background: transparent;
- border: none;
- color: #e0e0e0;
- cursor: pointer;
- padding: 5px;
- border-radius: 3px;
- display: flex;
- align-items: center;
- justify-content: center;
- font-size: 16px;
-}
-
-.settings-close-btn:hover {
- background-color: #3a3a3a;
- color: #fff;
-}
-
-.settings-nav {
- display: flex;
- flex-direction: column;
- padding: 10px;
-}
-
-.settings-nav-item {
- background: transparent;
- border: none;
- color: #b0b0b0;
- padding: 12px 16px;
- text-align: left;
- cursor: pointer;
- border-radius: 4px;
- margin-bottom: 2px;
- font-size: 14px;
- font-weight: 500;
- transition: all 0.2s ease;
-}
-
-.settings-nav-item:hover {
- background-color: #3a3a3a;
- color: #e0e0e0;
-}
-
-.settings-nav-item.active {
- background-color: #4a4a4a;
- color: #fff;
-}
-
-/* Settings Content */
-.settings-content {
- flex: 1;
- overflow-y: auto;
- background-color: #1e1e1e;
- display: flex;
- justify-content: center;
-}
-
-.settings-section {
- padding: 30px;
- width: 800px;
-}
-
-.settings-section-header {
- margin-bottom: 30px;
- border-bottom: 1px solid #3a3a3a;
- padding-bottom: 15px;
-}
-
-.settings-section-header h3 {
- color: #fff;
- font-size: 24px;
- font-weight: 600;
- margin: 0;
-}
-
-.settings-section-content {
- display: flex;
- flex-direction: column;
- gap: 30px;
- padding-bottom: 30px;
-}
-
-.settings-group {
- background-color: #2d2d2d;
- border-radius: 8px;
- padding: 20px;
- border: 1px solid #3a3a3a;
-}
-
-.settings-group h4 {
- color: #fff;
- font-size: 16px;
- font-weight: 600;
- margin: 0 0 15px 0;
-}
-
-.settings-group-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 15px;
-}
-
-.settings-group-header h4 {
- margin: 0;
-}
-
-.settings-description {
- color: #b0b0b0;
- font-size: 14px;
- line-height: 1.5;
- margin-bottom: 15px;
-}
-
-.settings-item {
- margin-bottom: 15px;
-}
-
-.settings-item:last-child {
- margin-bottom: 0;
-}
-
-.settings-label {
- display: block;
- color: #e0e0e0;
- font-size: 14px;
- font-weight: 500;
- margin-bottom: 5px;
-}
-
-.settings-input, .settings-select, .settings-textarea {
- width: 100%;
- /* max-width: 300px; */
- padding: 8px 12px;
- background-color: #3a3a3a;
- border: 1px solid #555;
- border-radius: 4px;
- color: #e0e0e0;
- font-size: 14px;
- transition: border-color 0.2s ease;
- font-family: inherit;
-}
-
-.settings-input:focus, .settings-select:focus, .settings-textarea:focus {
- outline: none;
- border-color: #5a9fd4;
- box-shadow: 0 0 0 2px rgba(90, 159, 212, 0.2);
-}
-
-.settings-textarea {
- max-width: 600px;
- resize: vertical;
- min-height: 120px;
-}
-
-.settings-input[type="number"] {
- max-width: 100px;
-}
-
-/* Custom Checkbox */
-.settings-checkbox-container {
- display: flex;
- align-items: center;
- cursor: pointer;
- color: #e0e0e0;
- font-size: 14px;
- user-select: none;
-}
-
-.settings-checkbox-container input[type="checkbox"] {
- display: none;
-}
-
-.settings-checkmark {
- width: 18px;
- height: 18px;
- background-color: #3a3a3a;
- border: 1px solid #555;
- border-radius: 3px;
- margin-right: 10px;
- position: relative;
- transition: all 0.2s ease;
-}
-
-.settings-checkbox-container input[type="checkbox"]:checked + .settings-checkmark {
- background-color: #5a9fd4;
- border-color: #5a9fd4;
-}
-
-.settings-checkbox-container input[type="checkbox"]:checked + .settings-checkmark::after {
- content: '';
- position: absolute;
- left: 5px;
- top: 2px;
- width: 6px;
- height: 10px;
- border: solid white;
- border-width: 0 2px 2px 0;
- transform: rotate(45deg);
-}
-
-/* Settings Buttons */
-.settings-btn {
- background-color: #3a3a3a;
- border: 1px solid #555;
- color: #e0e0e0;
- padding: 8px 16px;
- border-radius: 4px;
- cursor: pointer;
- font-size: 14px;
- font-weight: 500;
- transition: all 0.2s ease;
- display: inline-flex;
- align-items: center;
- gap: 6px;
-}
-
-.settings-btn:hover {
- background-color: #4a4a4a;
- border-color: #666;
-}
-
-.settings-btn-primary {
- background-color: #5a9fd4;
- border-color: #5a9fd4;
- color: #fff;
-}
-
-.settings-btn-primary:hover {
- background-color: #4a8fc4;
- border-color: #4a8fc4;
-}
-
-.settings-btn-danger {
- background-color: #d45a5a;
- border-color: #d45a5a;
- color: #fff;
-}
-
-.settings-btn-danger:hover {
- background-color: #c44a4a;
- border-color: #c44a4a;
-}
-
-.settings-btn-danger:disabled {
- background-color: #555;
- border-color: #555;
- color: #888;
- cursor: not-allowed;
-}
-
-.settings-btn-small {
- padding: 6px 10px;
- font-size: 12px;
-}
-
-/* Settings Help Links */
-.settings-help-links {
- display: flex;
- gap: 16px;
- margin-bottom: 8px;
-}
-
-button.settings-help {
- color: #5a9fd4;
- text-decoration: underline;
- cursor: pointer;
- font-size: 14px;
- background: none;
- border: none;
- padding: 0;
- font-family: inherit;
-}
-
-button.settings-help:hover {
- color: #7bbfef;
-}
-
-/* Settings Validation Errors */
-.settings-validation-errors {
- margin-top: 8px;
- padding: 8px;
- background-color: rgba(211, 90, 90, 0.1);
- border: 1px solid #d35a5a;
- border-radius: 4px;
- max-height: 200px;
- overflow-y: auto;
-}
-
-.settings-validation-error {
- color: #ff6b6b;
- font-size: 12px;
- line-height: 1.4;
- margin-bottom: 4px;
-}
-
-.settings-validation-error:last-child {
- margin-bottom: 0;
-}
-
-/* Templates List */
-.templates-list {
- display: flex;
- flex-direction: column;
- gap: 10px;
- margin-top: 15px;
-}
-
-.template-item {
- background-color: #3a3a3a;
- border: 1px solid #555;
- border-radius: 6px;
- padding: 15px;
- display: flex;
- justify-content: space-between;
- align-items: center;
- transition: border-color 0.2s ease;
-}
-
-.template-item:hover {
- border-color: #666;
-}
-
-.template-info {
- flex: 1;
-}
-
-.template-name {
- color: #fff;
- font-size: 16px;
- font-weight: 600;
- margin: 0 0 5px 0;
-}
-
-.template-description {
- color: #b0b0b0;
- font-size: 14px;
- margin: 0 0 5px 0;
-}
-
-.template-tracks {
- color: #888;
- font-size: 12px;
- font-weight: 500;
-}
-
-.template-actions {
- display: flex;
- gap: 8px;
-}
-
-/* File Import Modal */
-.file-import-overlay {
- position: fixed;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- background-color: rgba(0, 0, 0, 0.7);
- display: flex;
- align-items: center;
- justify-content: center;
- z-index: 10001;
- backdrop-filter: blur(2px);
-}
-
-.file-import-modal {
- background-color: #2d2d2d;
- border: 1px solid #3a3a3a;
- border-radius: 8px;
- box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
- width: 90%;
- max-width: 500px;
- max-height: 80vh;
- overflow: hidden;
- animation: fileImportFadeIn 0.2s ease-out;
-}
-
-@keyframes fileImportFadeIn {
- from {
- opacity: 0;
- transform: scale(0.95) translateY(-10px);
- }
- to {
- opacity: 1;
- transform: scale(1) translateY(0);
- }
-}
-
-.file-import-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: 20px;
- border-bottom: 1px solid #3a3a3a;
- background-color: #252525;
-}
-
-.file-import-title {
- color: #e0e0e0;
- font-size: 18px;
- font-weight: 600;
- margin: 0;
-}
-
-.file-import-close-btn {
- background: transparent;
- border: none;
- color: #b0b0b0;
- cursor: pointer;
- padding: 8px;
- border-radius: 4px;
- display: flex;
- align-items: center;
- justify-content: center;
- font-size: 16px;
- transition: all 0.2s ease;
-}
-
-.file-import-close-btn:hover {
- background-color: #3a3a3a;
- color: #e0e0e0;
-}
-
-.file-import-drop-zone {
- padding: 40px 20px;
- margin: 20px;
- border: 2px dashed #555;
- border-radius: 8px;
- background-color: #1e1e1e;
- transition: all 0.3s ease;
- cursor: pointer;
-}
-
-.file-import-drop-zone:hover {
- border-color: #7b68ee;
- background-color: rgba(123, 104, 238, 0.05);
-}
-
-.file-import-drop-zone.drag-over {
- border-color: #7b68ee;
- background-color: rgba(123, 104, 238, 0.1);
- transform: scale(1.02);
-}
-
-.file-import-drop-content {
- text-align: center;
- color: #e0e0e0;
-}
-
-.file-import-icon {
- font-size: 48px;
- margin-bottom: 16px;
- opacity: 0.7;
-}
-
-.file-import-description {
- font-size: 18px;
- font-weight: 500;
- margin: 0 0 8px 0;
- color: #e0e0e0;
-}
-
-.file-import-formats {
- font-size: 14px;
- color: #b0b0b0;
- margin: 0 0 24px 0;
-}
-
-.file-import-divider {
- position: relative;
- margin: 24px 0;
- text-align: center;
-}
-
-.file-import-divider::before {
- content: '';
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- height: 1px;
- background-color: #3a3a3a;
-}
-
-.file-import-divider span {
- background-color: #1e1e1e;
- padding: 0 12px;
- color: #888;
- font-size: 12px;
- text-transform: uppercase;
- letter-spacing: 0.5px;
-}
-
-.file-import-browse-btn {
- display: inline-block;
- background-color: #5a9fd4;
- color: #fff;
- padding: 12px 24px;
- border-radius: 6px;
- font-size: 14px;
- font-weight: 500;
- cursor: pointer;
- transition: all 0.2s ease;
- border: none;
-}
-
-.file-import-browse-btn:hover {
- background-color: #4a8fc4;
- transform: translateY(-1px);
- box-shadow: 0 4px 12px rgba(90, 159, 212, 0.3);
-}
-
-/* Global Loading Overlay */
-.global-loading-overlay {
- position: fixed;
- inset: 0;
- background-color: rgba(0, 0, 0, 0.4);
- z-index: 20000;
- display: flex;
- align-items: center;
- justify-content: center;
- pointer-events: all; /* block interactions */
-}
-
-.global-loading-content {
- display: flex;
- flex-direction: column;
- align-items: center;
- gap: 10px;
-}
-
-.global-loading-spinner {
- width: 40px;
- height: 40px;
- border: 4px solid rgba(255, 255, 255, 0.25);
- border-top-color: #ffffff;
- border-radius: 50%;
- animation: globalSpinner 1s linear infinite;
-}
-
-.global-loading-text {
- color: #e0e0e0;
- font-size: 14px;
-}
-
-@keyframes globalSpinner {
- to { transform: rotate(360deg); }
-}
-
-/* Processing wave animation */
-.processing-wave {
- background: linear-gradient(
- 90deg,
- rgba(135, 206, 250, 0.5) 0%,
- rgba(135, 206, 250, 0.8) 25%,
- rgb(171, 218, 250) 50%,
- rgba(135, 206, 250, 0.8) 75%,
- rgba(135, 206, 250, 0.5) 100%
- );
- background-size: 200% 100%;
- background-clip: text;
- -webkit-background-clip: text;
- -webkit-text-fill-color: transparent;
- animation: wave 2s linear infinite;
-}
-
-@keyframes wave {
- 0% {
- background-position: 200% 0%;
- }
- 100% {
- background-position: -200% 0%;
- }
-}
diff --git a/src/App.tsx b/src/App.tsx
index f219f79..fc635c3 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,5 +1,6 @@
import { useEffect } from 'react';
import './App.css';
+import './styles/shared.css';
import { useProjectStore } from './stores/projectStore';
import { useGlobalKeyboardHandler } from './hooks/useGlobalKeyboardHandler';
import Toolbar from './components/Toolbar';
diff --git a/src/components/ChatBox.css b/src/components/ChatBox.css
new file mode 100644
index 0000000..6018761
--- /dev/null
+++ b/src/components/ChatBox.css
@@ -0,0 +1,313 @@
+/* ChatBox */
+.chatbox {
+ display: flex;
+ flex-direction: column;
+ width: var(--chat-box-width);
+ background-color: #2d2d2d;
+ border-left: 1px solid #3a3a3a;
+ flex-shrink: 0;
+}
+
+.chatbox.is-hidden {
+ display: none;
+}
+
+.chatbox-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between; /* left title, right actions */
+ background-color: #3a3a3a;
+ height: 40px;
+ border-bottom: 1px solid #4a4a4a;
+ padding: 0 15px;
+}
+
+.chatbox-actions {
+ display: flex;
+ gap: 8px;
+ align-items: center;
+}
+
+.chatbox-action-btn {
+ background: transparent;
+ border: none;
+ cursor: pointer;
+ padding: 4px;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ color: #e0e0e0;
+ font-size: 14px;
+}
+
+.chatbox-action-btn:hover {
+ background-color: #4a4a4a;
+ border-radius: 3px;
+}
+
+/* ChatBox export button wrapper and dropdown positioning */
+.chatbox-export-wrapper {
+ position: relative;
+ display: inline-block;
+}
+
+.chatbox-export-btn {
+ display: flex;
+ align-items: center;
+ gap: 4px;
+}
+
+.chatbox-export-dropdown-anchor {
+ position: absolute;
+ top: 100%;
+ left: 0;
+ z-index: 10000;
+}
+
+.chatbox-export-dropdown .quant-dropdown {
+ width: 250px;
+ left: -200px;
+}
+
+.chatbox-header h3 {
+ color: #e0e0e0;
+ font-size: 12px;
+ font-weight: bold;
+ margin: 0;
+}
+
+.chatbox-content {
+ flex: 1;
+ padding: 15px;
+ color: #e0e0e0;
+ font-size: 12px;
+ overflow-y: auto;
+}
+
+/* Chat Messages */
+.chatbox-messages {
+ flex: 1;
+ padding: 10px;
+ overflow-y: auto;
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+}
+
+.message-container {
+ width: 100%;
+ word-wrap: break-word;
+}
+
+.message-user {
+ width: 100%;
+}
+
+.message-assistant {
+ width: 100%;
+}
+
+.message-content {
+ padding: 8px 12px;
+ border-radius: 8px;
+ font-size: 12px;
+ line-height: 1.4;
+}
+
+/* User message styling - lighter background like input */
+.message-user .message-content {
+ background-color: #3a3a3a;
+ color: #e0e0e0;
+ border: 1px solid #4a4a4a;
+}
+
+/* Assistant message styling - transparent */
+.message-assistant .message-content {
+ background-color: transparent;
+ color: #e0e0e0;
+ border: 1px solid #2a2a2a;
+}
+
+/* Input Area */
+.chatbox-input-area {
+ padding: 10px;
+}
+
+.chatbox-input {
+ width: 100%;
+ padding: 8px 12px;
+ background-color: #4a4a4a;
+ border: 1px solid #5a5a5a;
+ border-radius: 6px;
+ color: #e0e0e0;
+ font-size: 12px;
+ outline: none;
+ resize: none;
+ min-height: 36px;
+ max-height: 120px;
+}
+
+.chatbox-input:focus {
+ border-color: #6a6a6a;
+ background-color: #4a4a4a;
+}
+
+.chatbox-input::placeholder {
+ color: #999;
+}
+
+
+/* Markdown styling in messages */
+.message-content h1,
+.message-content h2,
+.message-content h3 {
+ margin: 8px 0 4px 0;
+ color: #e0e0e0;
+}
+
+.message-content h3 {
+ font-size: 14px;
+}
+
+.message-content p {
+ margin: 4px 0;
+}
+
+.message-content ul,
+.message-content ol {
+ margin: 4px 0;
+ padding-left: 16px;
+}
+
+.message-content li {
+ margin: 2px 0;
+}
+
+.message-content code {
+ background-color: #2a2a2a;
+ padding: 2px 4px;
+ border-radius: 3px;
+ font-family: 'Courier New', Courier, monospace;
+ font-size: 11px;
+}
+
+.message-content pre {
+ background-color: #1a1a1a;
+ padding: 8px;
+ border-radius: 6px;
+ overflow-x: auto;
+ margin: 8px 0;
+}
+
+.message-content blockquote {
+ border-left: 3px solid #5a5a5a;
+ padding-left: 12px;
+ margin: 8px 0;
+ color: #ccc;
+}
+
+.message-content table {
+ border-collapse: collapse;
+ width: 100%;
+ margin: 8px 0;
+ font-size: 11px;
+}
+
+.message-content th,
+.message-content td {
+ border: 1px solid #4a4a4a;
+ padding: 4px 8px;
+ text-align: left;
+}
+
+.message-content th {
+ background-color: #3a3a3a;
+ font-weight: bold;
+}
+
+/* Abort link styling */
+.abort-link {
+ background: none !important;
+ border: none !important;
+ color: #7b68ee !important;
+ text-decoration: underline !important;
+ cursor: pointer !important;
+ padding: 0 !important;
+ font: inherit !important;
+ font-size: 12px !important;
+}
+
+.abort-link:hover {
+ color: #9b88ff !important;
+ text-decoration: none !important;
+}
+
+/* Tool XML Expander */
+.tool-xml-expander {
+ margin-bottom: 8px;
+}
+
+.tool-xml-expander-header {
+ color: #e0e0e0;
+ cursor: pointer;
+ user-select: none;
+ padding: 4px 8px;
+ /* background-color: #f5f5f5; */
+ border: 1px solid #2a2a2a;
+ border-radius: 4px;
+ display: flex;
+ align-items: center;
+ gap: 8px;
+}
+
+.tool-xml-expander-arrow {
+ font-size: 12px;
+ color: #666;
+}
+
+.tool-xml-expander-title {
+ /* font-family: 'Courier New', Monaco, 'Menlo', 'Ubuntu Mono', monospace; */
+ font-size: 12px;
+ font-weight: bold;
+ color: #e0e0e0;
+}
+
+.tool-xml-expander-content {
+ margin-top: 4px;
+ padding: 8px;
+ background-color: #f9f9f9;
+ border: 1px solid #ddd;
+ border-radius: 4px;
+ font-family: 'Courier New', Monaco, 'Menlo', 'Ubuntu Mono', monospace;
+ font-size: 12px;
+ white-space: pre-wrap;
+ overflow: auto;
+ max-height: 200px;
+ color: #333;
+}
+
+/* Processing wave animation */
+.processing-wave {
+ background: linear-gradient(
+ 90deg,
+ rgba(135, 206, 250, 0.5) 0%,
+ rgba(135, 206, 250, 0.8) 25%,
+ rgb(171, 218, 250) 50%,
+ rgba(135, 206, 250, 0.8) 75%,
+ rgba(135, 206, 250, 0.5) 100%
+ );
+ background-size: 200% 100%;
+ background-clip: text;
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ animation: wave 2s linear infinite;
+}
+
+@keyframes wave {
+ 0% {
+ background-position: 200% 0%;
+ }
+ 100% {
+ background-position: -200% 0%;
+ }
+}
diff --git a/src/components/ChatBox.tsx b/src/components/ChatBox.tsx
index 7852145..6fe7a06 100644
--- a/src/components/ChatBox.tsx
+++ b/src/components/ChatBox.tsx
@@ -1,4 +1,5 @@
import React, { useState, useRef, useEffect, memo, useCallback } from 'react';
+import './ChatBox.css';
import { FaPlus, FaBan, FaDownload } from 'react-icons/fa';
import { UserMessage, AssistantMessage } from './chat';
import { AgentCore } from '../agent/core/AgentCore';
diff --git a/src/components/InstrumentSelection.css b/src/components/InstrumentSelection.css
new file mode 100644
index 0000000..0805958
--- /dev/null
+++ b/src/components/InstrumentSelection.css
@@ -0,0 +1,123 @@
+/* Instrument Selection Panel */
+.instrument-selection {
+ display: flex;
+ flex-direction: column;
+ width: var(--instrument-selection-width);
+ background-color: #2d2d2d;
+ border-right: 1px solid #3a3a3a;
+ flex-shrink: 0;
+ position: relative;
+}
+
+.instrument-selection-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ height: 40px;
+ padding: 0 12px;
+ background-color: transparent;
+ border: none;
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ z-index: 2;
+}
+
+.instrument-selection-header h3 {
+ color: #e0e0e0;
+ font-size: 12px;
+ font-weight: bold;
+}
+
+.instrument-selection-close-btn {
+ background: transparent;
+ border: none;
+ color: #e0e0e0;
+ cursor: pointer;
+ padding: 4px;
+ border-radius: 3px;
+}
+
+.instrument-selection-close-btn:hover {
+ background-color: #4a4a4a;
+}
+
+.instrument-selection-top {
+ height: 300px;
+ position: relative;
+ border-bottom: 1px solid #3a3a3a;
+ overflow: hidden;
+ background-image:
+ linear-gradient(rgba(0,0,0,0.35), rgba(0,0,0,0.35)),
+ url('/resources/instrument_bg.png');
+ background-size: cover; /* fill while keeping aspect ratio */
+ background-position: center;
+}
+
+.instrument-preview {
+ position: absolute;
+ inset: 0;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.instrument-preview img {
+ width: 256px;
+ height: 256px;
+ object-fit: contain;
+ border-radius: 6px;
+ opacity: 1;
+}
+
+.instrument-name-overlay {
+ position: absolute;
+ bottom: 16px;
+ left: 0;
+ right: 0;
+ text-align: center;
+ font-size: 16px;
+ color: #e0e0e0;
+ text-shadow: 0 1px 2px rgba(0,0,0,0.6);
+ z-index: 1;
+ font-weight: bold;
+}
+
+.instrument-selection-bottom {
+ flex: 1;
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ min-height: 0; /* allow children to scroll */
+}
+
+.instrument-groups, .instrument-list {
+ overflow: hidden;
+}
+
+/* vertical divider between groups and instruments */
+.instrument-groups {
+ border-right: 1px solid #3a3a3a;
+}
+
+.instrument-groups-list, .instrument-instruments-list {
+ height: 100%;
+ overflow-y: auto;
+}
+
+.instrument-group-item, .instrument-instrument-item {
+ padding: 8px 12px;
+ /* remove per-item separators */
+ border-bottom: none;
+ cursor: pointer;
+ font-size: 12px;
+ color: #e0e0e0;
+}
+
+.instrument-group-item:hover, .instrument-instrument-item:hover {
+ background-color: #3a3a3a;
+}
+
+.instrument-group-item.active, .instrument-instrument-item.active {
+ background-color: #4a4a4a;
+}
diff --git a/src/components/InstrumentSelection.tsx b/src/components/InstrumentSelection.tsx
index 454a60c..b923e5e 100644
--- a/src/components/InstrumentSelection.tsx
+++ b/src/components/InstrumentSelection.tsx
@@ -1,4 +1,5 @@
import React, { useMemo, useState, useEffect } from 'react';
+import './InstrumentSelection.css';
import { useProjectStore } from '../stores/projectStore';
import { INSTRUMENT_GROUPS, FLUIDR3_INSTRUMENT_MAP } from '../constants/generalMidiConstants';
import { KGMidiTrack, type InstrumentType } from '../core/track/KGMidiTrack';
diff --git a/src/components/MainContent.css b/src/components/MainContent.css
new file mode 100644
index 0000000..9dec725
--- /dev/null
+++ b/src/components/MainContent.css
@@ -0,0 +1,105 @@
+/* Main content */
+.main-content {
+ display: flex;
+ flex-direction: column;
+ flex: 1;
+ overflow: auto; /* Main scrollable container */
+ position: relative;
+}
+
+.main-content-wrapper {
+ display: flex;
+ flex-direction: column;
+ min-width: calc(200px + var(--max-number-of-bars) * var(--track-grid-bar-width)); /* info width + grid width */
+ min-height: fit-content;
+ position: relative;
+}
+
+.top-left-spacer {
+ position: fixed;
+ top: 50px;
+ left: 0;
+ width: 200px;
+ height: 20px;
+ background-color: #2d2d2d;
+ border-bottom: 1px solid #3a3a3a;
+ border-right: 1px solid #3a3a3a;
+ z-index: 1002; /* Higher than other elements to ensure it's always visible */
+}
+
+/* Offset spacer when instrument selection panel is visible on the left */
+.main-content.has-left-instrument .top-left-spacer {
+ left: 300px;
+}
+
+.bar-numbers {
+ position: sticky;
+ top: 0;
+ height: 20px;
+ display: flex;
+ border-bottom: 1px solid #3a3a3a;
+ background-color: #2d2d2d;
+ z-index: 20;
+ margin-left: 200px; /* Offset for info-container */
+ width: calc(var(--max-number-of-bars) * var(--track-grid-bar-width)); /* Exact width for 32 bars */
+ cursor: pointer; /* Show pointer cursor on hover to indicate interactivity */
+}
+
+.bar-numbers:hover {
+ cursor: url("data:image/svg+xml,%3csvg width='16' height='16' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M4 6h8l-4 4-4-4z' fill='%23e0e0e0'/%3e%3c/svg%3e") 8 8, pointer;
+}
+
+.bar-number-cell {
+ min-width: var(--track-grid-bar-width);
+ width: var(--track-grid-bar-width);
+ flex-shrink: 0;
+ flex-grow: 0;
+ height: 20px;
+ text-align: center;
+ font-size: 12px;
+ border-right: 1px solid #3a3a3a;
+ color: #999;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ box-sizing: border-box;
+}
+
+.bar-number-cell.looped {
+ background-color: #e1ae01;
+ color: #1e1e1e;
+}
+
+.main-content-body {
+ display: flex;
+ min-height: fit-content;
+}
+
+.info-container {
+ position: sticky;
+ left: 0;
+ width: 200px;
+ z-index: 1002;
+ background-color: #2d2d2d;
+ align-self: flex-start;
+}
+
+/* Shift the bar numbers and info panel when instrument selection is present */
+/* No need to shift bar numbers or info container; they live inside main content.
+ Only shift the fixed spacer when the left panel is present. */
+
+.track-top-spacer {
+ height: 20px;
+ border-bottom: 1px solid #3a3a3a;
+ background-color: #2d2d2d;
+ position: sticky;
+ top: 0;
+ z-index: 15;
+}
+
+.grid-container {
+ margin-left: 0; /* No need for margin since we're using flex */
+ min-width: calc(var(--max-number-of-bars) * var(--track-grid-bar-width)); /* Ensure minimum width */
+ min-height: fit-content;
+ position: relative; /* Required for absolute positioned playhead */
+}
diff --git a/src/components/MainContent.tsx b/src/components/MainContent.tsx
index d8fb397..f09f55f 100644
--- a/src/components/MainContent.tsx
+++ b/src/components/MainContent.tsx
@@ -1,4 +1,5 @@
import React, { useState, useEffect, useRef, useCallback } from 'react';
+import './MainContent.css';
import { createPortal } from 'react-dom';
import { useProjectStore } from '../stores/projectStore';
import { KGCore } from '../core/KGCore';
diff --git a/src/components/StatusBar.css b/src/components/StatusBar.css
new file mode 100644
index 0000000..e4c4feb
--- /dev/null
+++ b/src/components/StatusBar.css
@@ -0,0 +1,16 @@
+/* Status bar */
+.status-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ background-color: #2d2d2d;
+ padding: 5px 10px;
+ font-size: 12px;
+ color: #999;
+ border-top: 1px solid #3a3a3a;
+ height: 30px;
+}
+
+.status-right span {
+ margin-left: 15px;
+}
diff --git a/src/components/StatusBar.tsx b/src/components/StatusBar.tsx
index e52e4a4..17f23a5 100644
--- a/src/components/StatusBar.tsx
+++ b/src/components/StatusBar.tsx
@@ -1,4 +1,5 @@
import React from 'react';
+import './StatusBar.css';
import { useProjectStore } from '../stores/projectStore';
const StatusBar: React.FC = () => {
diff --git a/src/components/Toolbar.css b/src/components/Toolbar.css
new file mode 100644
index 0000000..6e7441c
--- /dev/null
+++ b/src/components/Toolbar.css
@@ -0,0 +1,155 @@
+/* Toolbar */
+.toolbar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ background-color: #2d2d2d;
+ height: 50px;
+ padding: 0 10px;
+ border-bottom: 1px solid #3a3a3a;
+}
+
+.toolbar-left, .toolbar-center, .toolbar-right {
+ display: flex;
+ align-items: center;
+}
+
+.toolbar-left {
+ display: flex;
+ align-items: center;
+}
+
+.logo-container {
+ margin-right: 10px;
+ display: flex;
+ align-items: center;
+}
+
+.logo {
+ height: 30px;
+ width: auto;
+}
+
+.project-name {
+ font-size: 14px;
+ color: #e0e0e0;
+ margin-right: 20px;
+ display: flex;
+ align-items: center;
+ pointer-events: auto;
+}
+
+.toolbar button {
+ background: transparent;
+ border: none;
+ color: #e0e0e0;
+ margin: 0 5px;
+ padding: 5px;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ border-radius: 3px;
+ font-size: 14px;
+ pointer-events: auto;
+}
+
+.toolbar button:hover {
+ background-color: #3a3a3a;
+}
+
+.toolbar button:disabled {
+ color: #666;
+ cursor: not-allowed;
+}
+
+.record-btn {
+ color: #ff4444;
+}
+
+.toolbar-separator {
+ width: 1px;
+ height: 20px;
+ background-color: #555;
+ margin: 0 10px;
+}
+
+.transport-control {
+ display: flex;
+ align-items: center;
+ margin: 0 10px;
+ pointer-events: auto;
+}
+
+.transport-item {
+ margin: 0 5px;
+ padding: 2px 2px;
+ background-color: #3a3a3a;
+ border-radius: 3px;
+ font-size: 12px;
+}
+
+/* Fixed-width font for time display to prevent layout shifts */
+.current-time {
+ font-family: 'Courier New', 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
+ font-weight: normal;
+ letter-spacing: 0.5px;
+ padding: 2px 4px;
+}
+
+/* Clickable BPM styling */
+.current-bpm {
+ font-family: 'Courier New', 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
+ font-weight: normal;
+ letter-spacing: 0.5px;
+ cursor: pointer;
+ transition: background-color 0.2s ease;
+ padding: 2px 4px;
+ border-radius: 2px;
+}
+
+.current-bpm:hover {
+ background-color: #4a4a4a;
+ color: #fff;
+}
+
+/* Clickable time signature styling */
+.current-time-signature {
+ font-family: 'Courier New', 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
+ font-weight: normal;
+ letter-spacing: 0.5px;
+ cursor: pointer;
+ transition: background-color 0.2s ease;
+ padding: 2px 4px;
+ border-radius: 2px;
+}
+
+.current-time-signature:hover {
+ background-color: #4a4a4a;
+ color: #fff;
+}
+
+.current-key-signature {
+ font-family: 'Courier New', 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
+ font-weight: normal;
+ letter-spacing: 0.5px;
+ cursor: pointer;
+ transition: background-color 0.2s ease;
+ padding: 2px 4px;
+ border-radius: 2px;
+}
+
+.current-key-signature:hover {
+ background-color: #4a4a4a;
+ color: #fff;
+}
+
+.export-dropdown .quant-dropdown {
+ width: 250px;
+ left: 0;
+}
+
+.key-signature-dropdown .quant-dropdown {
+ width: 100px;
+ left: 0;
+}
diff --git a/src/components/Toolbar.tsx b/src/components/Toolbar.tsx
index 8ebef89..01d81b9 100644
--- a/src/components/Toolbar.tsx
+++ b/src/components/Toolbar.tsx
@@ -1,4 +1,5 @@
import React from 'react';
+import './Toolbar.css';
import { saveProject } from '../util/saveUtil';
import { KGStorage } from '../core/io/KGStorage';
import { DB_CONSTANTS } from '../constants/coreConstants';
diff --git a/src/components/common/FileImportModal.css b/src/components/common/FileImportModal.css
new file mode 100644
index 0000000..5ce3f6f
--- /dev/null
+++ b/src/components/common/FileImportModal.css
@@ -0,0 +1,161 @@
+/* File Import Modal */
+.file-import-overlay {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background-color: rgba(0, 0, 0, 0.7);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ z-index: 10001;
+ backdrop-filter: blur(2px);
+}
+
+.file-import-modal {
+ background-color: #2d2d2d;
+ border: 1px solid #3a3a3a;
+ border-radius: 8px;
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
+ width: 90%;
+ max-width: 500px;
+ max-height: 80vh;
+ overflow: hidden;
+ animation: fileImportFadeIn 0.2s ease-out;
+}
+
+@keyframes fileImportFadeIn {
+ from {
+ opacity: 0;
+ transform: scale(0.95) translateY(-10px);
+ }
+ to {
+ opacity: 1;
+ transform: scale(1) translateY(0);
+ }
+}
+
+.file-import-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 20px;
+ border-bottom: 1px solid #3a3a3a;
+ background-color: #252525;
+}
+
+.file-import-title {
+ color: #e0e0e0;
+ font-size: 18px;
+ font-weight: 600;
+ margin: 0;
+}
+
+.file-import-close-btn {
+ background: transparent;
+ border: none;
+ color: #b0b0b0;
+ cursor: pointer;
+ padding: 8px;
+ border-radius: 4px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 16px;
+ transition: all 0.2s ease;
+}
+
+.file-import-close-btn:hover {
+ background-color: #3a3a3a;
+ color: #e0e0e0;
+}
+
+.file-import-drop-zone {
+ padding: 40px 20px;
+ margin: 20px;
+ border: 2px dashed #555;
+ border-radius: 8px;
+ background-color: #1e1e1e;
+ transition: all 0.3s ease;
+ cursor: pointer;
+}
+
+.file-import-drop-zone:hover {
+ border-color: #7b68ee;
+ background-color: rgba(123, 104, 238, 0.05);
+}
+
+.file-import-drop-zone.drag-over {
+ border-color: #7b68ee;
+ background-color: rgba(123, 104, 238, 0.1);
+ transform: scale(1.02);
+}
+
+.file-import-drop-content {
+ text-align: center;
+ color: #e0e0e0;
+}
+
+.file-import-icon {
+ font-size: 48px;
+ margin-bottom: 16px;
+ opacity: 0.7;
+}
+
+.file-import-description {
+ font-size: 18px;
+ font-weight: 500;
+ margin: 0 0 8px 0;
+ color: #e0e0e0;
+}
+
+.file-import-formats {
+ font-size: 14px;
+ color: #b0b0b0;
+ margin: 0 0 24px 0;
+}
+
+.file-import-divider {
+ position: relative;
+ margin: 24px 0;
+ text-align: center;
+}
+
+.file-import-divider::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ height: 1px;
+ background-color: #3a3a3a;
+}
+
+.file-import-divider span {
+ background-color: #1e1e1e;
+ padding: 0 12px;
+ color: #888;
+ font-size: 12px;
+ text-transform: uppercase;
+ letter-spacing: 0.5px;
+}
+
+.file-import-browse-btn {
+ display: inline-block;
+ background-color: #5a9fd4;
+ color: #fff;
+ padding: 12px 24px;
+ border-radius: 6px;
+ font-size: 14px;
+ font-weight: 500;
+ cursor: pointer;
+ transition: all 0.2s ease;
+ border: none;
+}
+
+.file-import-browse-btn:hover {
+ background-color: #4a8fc4;
+ transform: translateY(-1px);
+ box-shadow: 0 4px 12px rgba(90, 159, 212, 0.3);
+}
diff --git a/src/components/common/FileImportModal.tsx b/src/components/common/FileImportModal.tsx
index cd0e675..b57b90b 100644
--- a/src/components/common/FileImportModal.tsx
+++ b/src/components/common/FileImportModal.tsx
@@ -1,4 +1,5 @@
import React, { useCallback, useState } from 'react';
+import './FileImportModal.css';
import { FaTimes } from 'react-icons/fa';
interface FileImportModalProps {
diff --git a/src/components/common/LoadingOverlay.css b/src/components/common/LoadingOverlay.css
new file mode 100644
index 0000000..56de905
--- /dev/null
+++ b/src/components/common/LoadingOverlay.css
@@ -0,0 +1,36 @@
+/* Global Loading Overlay */
+.global-loading-overlay {
+ position: fixed;
+ inset: 0;
+ background-color: rgba(0, 0, 0, 0.4);
+ z-index: 20000;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ pointer-events: all; /* block interactions */
+}
+
+.global-loading-content {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 10px;
+}
+
+.global-loading-spinner {
+ width: 40px;
+ height: 40px;
+ border: 4px solid rgba(255, 255, 255, 0.25);
+ border-top-color: #ffffff;
+ border-radius: 50%;
+ animation: globalSpinner 1s linear infinite;
+}
+
+.global-loading-text {
+ color: #e0e0e0;
+ font-size: 14px;
+}
+
+@keyframes globalSpinner {
+ to { transform: rotate(360deg); }
+}
diff --git a/src/components/common/LoadingOverlay.tsx b/src/components/common/LoadingOverlay.tsx
index 6b8259e..c6c1c6d 100644
--- a/src/components/common/LoadingOverlay.tsx
+++ b/src/components/common/LoadingOverlay.tsx
@@ -1,4 +1,5 @@
import React from 'react';
+import './LoadingOverlay.css';
interface LoadingOverlayProps {
visible: boolean;
diff --git a/src/components/piano-roll/PianoRoll.css b/src/components/piano-roll/PianoRoll.css
new file mode 100644
index 0000000..386b265
--- /dev/null
+++ b/src/components/piano-roll/PianoRoll.css
@@ -0,0 +1,265 @@
+/* For the piano roll (to be implemented later) */
+.piano-roll {
+ background-color: #7b68ee;
+ height: 100%;
+}
+
+/* Piano Roll Panel */
+.piano-roll-panel {
+ position: fixed;
+ background-color: #2d2d2d;
+ border: 1px solid #3a3a3a;
+ box-shadow: 0 0 20px rgba(0, 0, 0, 0.5);
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+}
+
+/* Piano notes */
+.piano-note {
+ position: absolute;
+ background-color: #ff5555; /* Red color */
+ border: 1px solid #999;
+ border-radius: 2px;
+ z-index: 10;
+ cursor: pointer;
+ user-select: none;
+ box-sizing: border-box;
+}
+
+.piano-note:hover {
+ filter: brightness(1.1);
+ box-shadow: 0 0 5px rgba(255, 85, 85, 0.5);
+}
+
+.piano-note.dragging {
+ opacity: 0.8;
+ box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
+ z-index: 100;
+ cursor: grabbing;
+}
+
+.piano-note.resizing {
+ opacity: 0.8;
+ box-shadow: 0 0 10px rgba(255, 85, 85, 0.7);
+ z-index: 100;
+}
+
+.piano-note.selected {
+ border: 2px solid white;
+ z-index: 50;
+}
+
+.piano-roll-header {
+ height: 30px;
+ background-color: #1e1e1e;
+ border-bottom: 1px solid #3a3a3a;
+ display: flex;
+ align-items: center;
+ padding: 0 10px;
+ cursor: move;
+ user-select: none;
+}
+
+/* Piano roll toolbar */
+.piano-roll-toolbar {
+ height: 30px;
+ background-color: #252525;
+ border-bottom: 1px solid #3a3a3a;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 0 10px;
+ user-select: none;
+ position: relative;
+ z-index: 100; /* Ensure toolbar and its dropdowns appear above piano roll content */
+}
+
+/* Override pointer-events for piano roll toolbar sections */
+.piano-roll-toolbar .toolbar-left,
+.piano-roll-toolbar .toolbar-right {
+ pointer-events: auto;
+}
+
+.piano-roll-toolbar .quant-button {
+ font-size: 10px;
+}
+
+.piano-roll-toolbar .toolbar-left .quant-button {
+ margin-left: 0px;
+ margin-right: 5px;
+}
+
+.piano-roll-toolbar .toolbar-left .quant-dropdown {
+ left: 0;
+}
+
+.piano-roll-title {
+ flex: 1;
+ text-align: center;
+ font-size: 14px;
+ color: #e0e0e0;
+ text-transform: uppercase;
+ cursor: pointer;
+ padding: 5px;
+ border-radius: 3px;
+}
+
+.close-button {
+ background: transparent;
+ border: none;
+ color: #e0e0e0;
+ cursor: pointer;
+ font-size: 14px;
+ padding: 5px;
+}
+
+.close-button:hover {
+ color: #ff4444;
+}
+
+.piano-roll-content {
+ display: flex;
+ flex-direction: column;
+ flex: 1;
+ overflow: auto;
+}
+
+.piano-grid-header {
+ display: grid;
+ grid-template-columns: repeat(var(--max-number-of-bars), var(--region-grid-bar-width));
+ width: calc(var(--max-number-of-bars) * var(--region-grid-bar-width) + var(--region-piano-key-width) - 1px);
+ min-width: 100%;
+ height: 20px;
+ border-bottom: 1px solid #3a3a3a;
+ background-color: #1e1e1e;
+ padding-left: calc(var(--region-piano-key-width) - 1px);
+ box-sizing: border-box;
+ position: sticky;
+ top: 0;
+ z-index: 20;
+ cursor: pointer; /* Show pointer cursor on hover to indicate interactivity */
+}
+
+.piano-grid-header:hover {
+ cursor: url("data:image/svg+xml,%3csvg width='16' height='16' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M4 6h8l-4 4-4-4z' fill='%23e0e0e0'/%3e%3c/svg%3e") 8 8, pointer;
+}
+
+.piano-bar-number {
+ border-left: 1px solid #3a3a3a;
+ padding-left: 10px;
+ font-size: 10px;
+}
+
+.piano-roll-body {
+ display: flex;
+ min-height: calc(8 * 12 * var(--region-piano-key-height)); /* 8 octaves * 12 notes * piano key height */
+ width: calc(var(--max-number-of-bars) * var(--region-grid-bar-width) + var(--region-piano-key-width)); /* 32 bars * 160px width + piano keys width */
+}
+
+.piano-keys-container {
+ width: var(--region-piano-key-width);
+ flex-shrink: 0;
+ overflow: hidden;
+ border-right: 1px solid #3a3a3a;
+ background-color: #252525;
+ position: sticky;
+ left: 0;
+ z-index: 10;
+}
+
+.piano-grid-container {
+ flex: 1;
+ min-width: calc(var(--max-number-of-bars) * var(--region-grid-bar-width));
+ min-height: calc(8 * 12 * var(--region-piano-key-height));
+ z-index: 5;
+}
+
+.piano-octave {
+ display: flex;
+ flex-direction: column;
+}
+
+.piano-key {
+ width: var(--region-piano-key-width);
+ height: var(--region-piano-key-height);
+ box-sizing: border-box;
+ display: flex;
+ align-items: center;
+ border-bottom: 1px solid #3a3a3a;
+}
+
+.piano-key.natural {
+ background-color: #e0e0e0;
+ color: #222;
+}
+
+.piano-key.sharp {
+ background-color: #222;
+ color: #e0e0e0;
+}
+
+.key-label {
+ font-size: 10px;
+ padding-left: 5px;
+}
+
+.piano-grid {
+ width: 100%;
+ height: 100%;
+ position: relative;
+ background-size: var(--region-grid-beat-width) var(--region-piano-key-height), 100% 100%;
+ /* background-image is now set dynamically via React inline styles in PianoGrid component */
+}
+
+.piano-grid.pencil-cursor {
+ cursor: crosshair;
+}
+
+/* Piano Grid Cursor Highlights */
+.piano-grid-pitch-highlight {
+ position: absolute;
+ left: 0;
+ right: 0;
+ background-color: rgba(123, 104, 238, 0.15);
+ border-top: 1px solid rgba(123, 104, 238, 0.3);
+ border-bottom: 1px solid rgba(123, 104, 238, 0.3);
+ pointer-events: none;
+ z-index: 1;
+ transition: opacity 0.1s ease;
+}
+
+.piano-grid-beat-highlight {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ background-color: rgba(123, 104, 238, 0.1);
+ border-left: 1px solid rgba(123, 104, 238, 0.25);
+ border-right: 1px solid rgba(123, 104, 238, 0.25);
+ pointer-events: none;
+ z-index: 1;
+ transition: opacity 0.1s ease;
+}
+
+.piano-grid-chord-highlight {
+ position: absolute;
+ background-color: rgba(255, 77, 77, 0.25);
+ border: 1px solid rgba(255, 77, 77, 0.8);
+ pointer-events: none;
+ z-index: 2;
+ transition: opacity 0.1s ease;
+}
+
+.resize-handle {
+ position: absolute;
+ right: 5px;
+ bottom: 5px;
+ width: 20px;
+ height: 20px;
+ cursor: nwse-resize;
+ color: #999;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ z-index: 100;
+}
diff --git a/src/components/piano-roll/PianoRoll.tsx b/src/components/piano-roll/PianoRoll.tsx
index 53a71b4..b60ee28 100644
--- a/src/components/piano-roll/PianoRoll.tsx
+++ b/src/components/piano-roll/PianoRoll.tsx
@@ -1,4 +1,5 @@
import React, { useRef, useEffect, useState, useCallback } from 'react';
+import './PianoRoll.css';
import type { MouseEvent } from 'react';
import { useProjectStore } from '../../stores/projectStore';
import { FaGripLines } from 'react-icons/fa';
diff --git a/src/components/settings/Settings.css b/src/components/settings/Settings.css
new file mode 100644
index 0000000..d916da9
--- /dev/null
+++ b/src/components/settings/Settings.css
@@ -0,0 +1,389 @@
+/* Settings Panel Styles */
+.settings-panel {
+ width: 100%;
+ height: 100%;
+ background-color: #1e1e1e;
+ display: flex;
+ flex-direction: column;
+}
+
+.settings-container {
+ display: flex;
+ height: 100%;
+ overflow: hidden;
+}
+
+/* Settings Sidebar */
+.settings-sidebar {
+ width: 250px;
+ background-color: #2d2d2d;
+ border-right: 1px solid #3a3a3a;
+ display: flex;
+ flex-direction: column;
+}
+
+.settings-sidebar-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 20px;
+ border-bottom: 1px solid #3a3a3a;
+}
+
+.settings-sidebar-header h2 {
+ color: #e0e0e0;
+ font-size: 18px;
+ font-weight: 600;
+ margin: 0;
+}
+
+.settings-close-btn {
+ background: transparent;
+ border: none;
+ color: #e0e0e0;
+ cursor: pointer;
+ padding: 5px;
+ border-radius: 3px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 16px;
+}
+
+.settings-close-btn:hover {
+ background-color: #3a3a3a;
+ color: #fff;
+}
+
+.settings-nav {
+ display: flex;
+ flex-direction: column;
+ padding: 10px;
+}
+
+.settings-nav-item {
+ background: transparent;
+ border: none;
+ color: #b0b0b0;
+ padding: 12px 16px;
+ text-align: left;
+ cursor: pointer;
+ border-radius: 4px;
+ margin-bottom: 2px;
+ font-size: 14px;
+ font-weight: 500;
+ transition: all 0.2s ease;
+}
+
+.settings-nav-item:hover {
+ background-color: #3a3a3a;
+ color: #e0e0e0;
+}
+
+.settings-nav-item.active {
+ background-color: #4a4a4a;
+ color: #fff;
+}
+
+/* Settings Content */
+.settings-content {
+ flex: 1;
+ overflow-y: auto;
+ background-color: #1e1e1e;
+ display: flex;
+ justify-content: center;
+}
+
+.settings-section {
+ padding: 30px;
+ width: 800px;
+}
+
+.settings-section-header {
+ margin-bottom: 30px;
+ border-bottom: 1px solid #3a3a3a;
+ padding-bottom: 15px;
+}
+
+.settings-section-header h3 {
+ color: #fff;
+ font-size: 24px;
+ font-weight: 600;
+ margin: 0;
+}
+
+.settings-section-content {
+ display: flex;
+ flex-direction: column;
+ gap: 30px;
+ padding-bottom: 30px;
+}
+
+.settings-group {
+ background-color: #2d2d2d;
+ border-radius: 8px;
+ padding: 20px;
+ border: 1px solid #3a3a3a;
+}
+
+.settings-group h4 {
+ color: #fff;
+ font-size: 16px;
+ font-weight: 600;
+ margin: 0 0 15px 0;
+}
+
+.settings-group-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 15px;
+}
+
+.settings-group-header h4 {
+ margin: 0;
+}
+
+.settings-description {
+ color: #b0b0b0;
+ font-size: 14px;
+ line-height: 1.5;
+ margin-bottom: 15px;
+}
+
+.settings-item {
+ margin-bottom: 15px;
+}
+
+.settings-item:last-child {
+ margin-bottom: 0;
+}
+
+.settings-label {
+ display: block;
+ color: #e0e0e0;
+ font-size: 14px;
+ font-weight: 500;
+ margin-bottom: 5px;
+}
+
+.settings-input, .settings-select, .settings-textarea {
+ width: 100%;
+ /* max-width: 300px; */
+ padding: 8px 12px;
+ background-color: #3a3a3a;
+ border: 1px solid #555;
+ border-radius: 4px;
+ color: #e0e0e0;
+ font-size: 14px;
+ transition: border-color 0.2s ease;
+ font-family: inherit;
+}
+
+.settings-input:focus, .settings-select:focus, .settings-textarea:focus {
+ outline: none;
+ border-color: #5a9fd4;
+ box-shadow: 0 0 0 2px rgba(90, 159, 212, 0.2);
+}
+
+.settings-textarea {
+ max-width: 600px;
+ resize: vertical;
+ min-height: 120px;
+}
+
+.settings-input[type="number"] {
+ max-width: 100px;
+}
+
+/* Custom Checkbox */
+.settings-checkbox-container {
+ display: flex;
+ align-items: center;
+ cursor: pointer;
+ color: #e0e0e0;
+ font-size: 14px;
+ user-select: none;
+}
+
+.settings-checkbox-container input[type="checkbox"] {
+ display: none;
+}
+
+.settings-checkmark {
+ width: 18px;
+ height: 18px;
+ background-color: #3a3a3a;
+ border: 1px solid #555;
+ border-radius: 3px;
+ margin-right: 10px;
+ position: relative;
+ transition: all 0.2s ease;
+}
+
+.settings-checkbox-container input[type="checkbox"]:checked + .settings-checkmark {
+ background-color: #5a9fd4;
+ border-color: #5a9fd4;
+}
+
+.settings-checkbox-container input[type="checkbox"]:checked + .settings-checkmark::after {
+ content: '';
+ position: absolute;
+ left: 5px;
+ top: 2px;
+ width: 6px;
+ height: 10px;
+ border: solid white;
+ border-width: 0 2px 2px 0;
+ transform: rotate(45deg);
+}
+
+/* Settings Buttons */
+.settings-btn {
+ background-color: #3a3a3a;
+ border: 1px solid #555;
+ color: #e0e0e0;
+ padding: 8px 16px;
+ border-radius: 4px;
+ cursor: pointer;
+ font-size: 14px;
+ font-weight: 500;
+ transition: all 0.2s ease;
+ display: inline-flex;
+ align-items: center;
+ gap: 6px;
+}
+
+.settings-btn:hover {
+ background-color: #4a4a4a;
+ border-color: #666;
+}
+
+.settings-btn-primary {
+ background-color: #5a9fd4;
+ border-color: #5a9fd4;
+ color: #fff;
+}
+
+.settings-btn-primary:hover {
+ background-color: #4a8fc4;
+ border-color: #4a8fc4;
+}
+
+.settings-btn-danger {
+ background-color: #d45a5a;
+ border-color: #d45a5a;
+ color: #fff;
+}
+
+.settings-btn-danger:hover {
+ background-color: #c44a4a;
+ border-color: #c44a4a;
+}
+
+.settings-btn-danger:disabled {
+ background-color: #555;
+ border-color: #555;
+ color: #888;
+ cursor: not-allowed;
+}
+
+.settings-btn-small {
+ padding: 6px 10px;
+ font-size: 12px;
+}
+
+/* Settings Help Links */
+.settings-help-links {
+ display: flex;
+ gap: 16px;
+ margin-bottom: 8px;
+}
+
+button.settings-help {
+ color: #5a9fd4;
+ text-decoration: underline;
+ cursor: pointer;
+ font-size: 14px;
+ background: none;
+ border: none;
+ padding: 0;
+ font-family: inherit;
+}
+
+button.settings-help:hover {
+ color: #7bbfef;
+}
+
+/* Settings Validation Errors */
+.settings-validation-errors {
+ margin-top: 8px;
+ padding: 8px;
+ background-color: rgba(211, 90, 90, 0.1);
+ border: 1px solid #d35a5a;
+ border-radius: 4px;
+ max-height: 200px;
+ overflow-y: auto;
+}
+
+.settings-validation-error {
+ color: #ff6b6b;
+ font-size: 12px;
+ line-height: 1.4;
+ margin-bottom: 4px;
+}
+
+.settings-validation-error:last-child {
+ margin-bottom: 0;
+}
+
+/* Templates List */
+.templates-list {
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+ margin-top: 15px;
+}
+
+.template-item {
+ background-color: #3a3a3a;
+ border: 1px solid #555;
+ border-radius: 6px;
+ padding: 15px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ transition: border-color 0.2s ease;
+}
+
+.template-item:hover {
+ border-color: #666;
+}
+
+.template-info {
+ flex: 1;
+}
+
+.template-name {
+ color: #fff;
+ font-size: 16px;
+ font-weight: 600;
+ margin: 0 0 5px 0;
+}
+
+.template-description {
+ color: #b0b0b0;
+ font-size: 14px;
+ margin: 0 0 5px 0;
+}
+
+.template-tracks {
+ color: #888;
+ font-size: 12px;
+ font-weight: 500;
+}
+
+.template-actions {
+ display: flex;
+ gap: 8px;
+}
diff --git a/src/components/settings/SettingsPanel.tsx b/src/components/settings/SettingsPanel.tsx
index 599a1ba..b4e6c5a 100644
--- a/src/components/settings/SettingsPanel.tsx
+++ b/src/components/settings/SettingsPanel.tsx
@@ -1,4 +1,5 @@
import React, { useState } from 'react';
+import './Settings.css';
import SettingsSidebar from './SettingsSidebar';
import GeneralSettings from './sections/GeneralSettings';
import BehaviorSettings from './sections/BehaviorSettings';
diff --git a/src/components/track/Region.css b/src/components/track/Region.css
new file mode 100644
index 0000000..c1c17d5
--- /dev/null
+++ b/src/components/track/Region.css
@@ -0,0 +1,110 @@
+/* Track Region Styles */
+.track-region {
+ position: absolute;
+ background-color: #4a6b8a;
+ border: 2px solid #5a7b9a;
+ border-radius: 3px;
+ height: calc(100%);
+ margin: 0px;
+ overflow: hidden;
+ display: flex;
+ flex-direction: column;
+ cursor: pointer;
+ user-select: none;
+ transition: box-shadow 0.1s ease;
+ will-change: transform;
+}
+
+.track-region:hover {
+ box-shadow: 0 0 0 1px #7a9bba;
+}
+
+.track-region.selected {
+ /* box-shadow: 0 0 0 2px #ffffff, 0 0 8px rgba(255, 255, 255, 0.3); */ /* let's only apply a border */
+ border-color: #ffffff;
+}
+
+.track-region.dragging {
+ opacity: 0.8;
+ box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
+ z-index: 100;
+ pointer-events: none;
+ transform-origin: center center;
+ animation: pulse 1.5s infinite;
+ cursor: grabbing;
+ transition: none; /* Remove transition during drag for immediate response */
+}
+
+@keyframes pulse {
+ 0% {
+ box-shadow: 0 0 0 0 rgba(122, 155, 186, 0.7);
+ }
+ 70% {
+ box-shadow: 0 0 0 5px rgba(122, 155, 186, 0);
+ }
+ 100% {
+ box-shadow: 0 0 0 0 rgba(122, 155, 186, 0);
+ }
+}
+
+.region-header {
+ background-color: #5a7b9a;
+ color: #fff;
+ padding: 2px 6px;
+ font-size: 11px;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ cursor: move;
+ height: 18px;
+ user-select: none;
+}
+
+.track-region:hover .region-header {
+ background-color: #6a8baa;
+}
+
+.region-content {
+ height: calc(100% - 18px);
+ background-color: #87CEFA; /* Light blue */
+ width: 100%;
+ position: relative; /* Allow overlayed controls */
+}
+
+/* Region pencil trigger inside content */
+.region-pencil-btn {
+ position: absolute;
+ top: 4px;
+ left: 4px;
+ background: rgba(0, 0, 0, 0.25);
+ color: #fff;
+ border: 1px solid rgba(255, 255, 255, 0.2);
+ border-radius: 3px;
+ padding: 2px;
+ margin: 0;
+ cursor: pointer;
+ z-index: 2;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.region-pencil-btn:hover {
+ background: rgba(0, 0, 0, 0.35);
+}
+
+/* Instrument dropdown specific styles */
+.instrument-dropdown .quant-dropdown {
+ min-width: 80px;
+ width: auto;
+ right: auto;
+ left: 0;
+}
+
+/* Settings dropdown specific styles */
+.settings-dropdown .quant-dropdown {
+ min-width: 100px;
+ width: auto;
+ right: auto;
+ left: 0;
+}
diff --git a/src/components/track/RegionItem.tsx b/src/components/track/RegionItem.tsx
index c54ba1d..084e021 100644
--- a/src/components/track/RegionItem.tsx
+++ b/src/components/track/RegionItem.tsx
@@ -1,4 +1,5 @@
import React, { useState, useRef, useEffect } from 'react';
+import './Region.css';
import { FaPencilAlt } from 'react-icons/fa';
import type { ResizeAction } from '../interfaces';
import { REGION_CONSTANTS, DEBUG_MODE } from '../../constants';
diff --git a/src/components/track/Track.css b/src/components/track/Track.css
new file mode 100644
index 0000000..67143bc
--- /dev/null
+++ b/src/components/track/Track.css
@@ -0,0 +1,207 @@
+/* Track grid */
+.track-grid {
+ display: block;
+ height: 120px;
+ min-width: calc(var(--max-number-of-bars) * var(--track-grid-bar-width)); /* 32 bars * --track-grid-bar-width */
+ background-size: var(--track-grid-bar-width) 120px;
+ background-image:
+ /* Vertical lines for bars */
+ linear-gradient(to right,
+ transparent calc(var(--track-grid-bar-width) - 1px), #3a3a3a calc(var(--track-grid-bar-width) - 1px), #3a3a3a var(--track-grid-bar-width)
+ );
+ position: relative;
+ border-bottom: 1px solid #3a3a3a;
+}
+
+.track-grid.pencil-cursor {
+ cursor: crosshair;
+}
+
+.add-track-btn {
+ background: transparent;
+ border: none;
+ outline: none;
+ color: #999;
+ cursor: pointer;
+ font-size: 12px;
+ padding: 0;
+ height: 100%;
+ width: 100%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.add-track-btn:focus,
+.add-track-btn:focus-visible {
+ outline: none;
+}
+
+.add-track-btn:hover {
+ color: #e0e0e0;
+}
+
+.track {
+ display: flex;
+ height: 120px;
+ position: relative;
+ border-bottom: none;
+}
+
+.track-info {
+ width: 200px;
+ height: 120px;
+ padding: 15px;
+ background-color: #2d2d2d;
+ display: flex;
+ flex-direction: column;
+ border-right: 1px solid #3a3a3a;
+ border-bottom: 1px solid #3a3a3a;
+ flex-shrink: 0;
+ box-sizing: border-box;
+ cursor: grab;
+ position: relative;
+}
+
+.track-info:active {
+ cursor: grabbing;
+}
+
+.track-info.selected {
+ background-color: #363636;
+}
+
+/* Drag and drop styles */
+.track-info.drag-over {
+ border-top: 2px solid #7b68ee;
+}
+
+.track-grid.drag-over {
+ border-top: 2px solid #7b68ee;
+}
+
+/* Dragging state */
+.track-info.dragging {
+ opacity: 0.5;
+ background-color: #444;
+}
+
+.track-grid.dragging {
+ opacity: 0.5;
+ background-color: #333;
+}
+
+/* Remove drag indicator since hover cursor is sufficient */
+
+.track-name {
+ font-size: 12px;
+ cursor: pointer;
+ position: relative;
+}
+
+.track-name:hover {
+ color: #7b68ee;
+}
+
+.track-name:hover::before {
+ content: "\270E";
+ position: absolute;
+ right: 0px;
+ font-size: 16px;
+ opacity: 1;
+}
+
+.track-controls {
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+ height: 100%;
+}
+
+.track-name-and-volume {
+ display: flex;
+ flex-direction: row;
+ flex: 1;
+ align-items: flex-start;
+ gap: 8px;
+}
+
+.instrument-image {
+ flex-shrink: 0;
+ margin-top: -10px;
+ margin-left: -10px;
+}
+
+.instrument-image img {
+ display: block;
+ border-radius: 4px;
+}
+
+.track-name-and-controls {
+ display: flex;
+ flex-direction: column;
+ flex: 1;
+ min-width: 0;
+}
+
+.volume-slider {
+ margin-bottom: 15px;
+ width: 100%;
+ display: flex;
+ align-items: center;
+ gap: 6px;
+}
+
+.volume-slider input[type="range"] {
+ flex: 1;
+ min-width: 0;
+ height: 6px;
+}
+
+.volume-slider .reset-volume {
+ flex-shrink: 0;
+ width: 16px;
+ height: 16px;
+ border-radius: 8px;
+ background: #3a3a3a;
+ color: #e0e0e0;
+ /* border: 1px solid #444; */
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ cursor: pointer;
+ font-size: 10px;
+}
+
+.volume-slider .reset-volume:hover {
+ background: #4a4a4a;
+}
+
+.pan-controls {
+ display: flex;
+}
+
+.pan-controls button {
+ background: #3a3a3a;
+ border: none;
+ color: #e0e0e0;
+ margin-right: 5px;
+ width: 24px;
+ height: 24px;
+ font-size: 12px;
+ border-radius: 2px;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.pan-controls button.solo.active {
+ background: #c8a400; /* yellow */
+ color: #101010;
+}
+
+.pan-controls button.mute.active {
+ background: #d32f2f; /* red */
+ color: #ffffff;
+}
diff --git a/src/components/track/TrackInfoPanel.tsx b/src/components/track/TrackInfoPanel.tsx
index 70090b9..6f00c64 100644
--- a/src/components/track/TrackInfoPanel.tsx
+++ b/src/components/track/TrackInfoPanel.tsx
@@ -1,4 +1,5 @@
import React, { useState } from 'react';
+import './Track.css';
import { KGTrack } from '../../core/track/KGTrack';
import { useProjectStore } from '../../stores/projectStore';
import TrackInfoItem from './TrackInfoItem';
diff --git a/src/index.css b/src/index.css
index a60a5a5..26e4e0a 100644
--- a/src/index.css
+++ b/src/index.css
@@ -58,6 +58,12 @@ button:focus-visible {
outline: 2px auto rgba(100, 108, 255, 0.5);
}
+textarea {
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
+ font-size: 12px;
+ line-height: 1.4;
+}
+
input[type="range"] {
-webkit-appearance: none;
appearance: none;
diff --git a/src/main.tsx b/src/main.tsx
index 65b9909..13b6272 100644
--- a/src/main.tsx
+++ b/src/main.tsx
@@ -1,6 +1,7 @@
import 'reflect-metadata';
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
+import './styles/variables.css';
import './index.css';
import App from './App.tsx';
import { KGCore } from './core/KGCore';
diff --git a/src/styles/shared.css b/src/styles/shared.css
new file mode 100644
index 0000000..2f1253e
--- /dev/null
+++ b/src/styles/shared.css
@@ -0,0 +1,125 @@
+/* Shared toolbar layout classes (used by Toolbar and PianoRollToolbar) */
+
+.toolbar-left, .toolbar-right {
+ display: flex;
+ align-items: center;
+ z-index: 1;
+ pointer-events: none;
+}
+
+.toolbar-left {
+ width: 20%;
+ justify-content: flex-start;
+}
+
+.toolbar-right {
+ width: 33%;
+ justify-content: flex-end;
+ z-index: 1500;
+}
+
+.toolbar-center {
+ position: absolute;
+ left: 50%;
+ transform: translateX(-50%);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ z-index: 1005;
+ margin-left: -50px;
+}
+
+/* Tool buttons (used by Toolbar and PianoRollToolbar) */
+
+.tool-button {
+ width: 30px;
+ height: 30px;
+ background-color: transparent;
+ border: none;
+ border-radius: 3px;
+ color: #999;
+ font-size: 14px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ cursor: pointer;
+ margin: 0 2px;
+}
+
+.tool-button:hover {
+ background-color: #3a3a3a;
+ color: #e0e0e0;
+}
+
+.tool-button.active {
+ background-color: #4a4a4a;
+ color: #e0e0e0;
+}
+
+/* Quantization dropdown system (used by KGDropdown) */
+
+.quant-button {
+ background-color: #333;
+ border: 1px solid #444;
+ border-radius: 3px;
+ color: #e0e0e0;
+ font-size: 12px;
+ padding: 3px 8px;
+ margin-left: 5px;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ gap: 5px;
+}
+
+.quant-button:hover {
+ background-color: #444;
+}
+
+.quant-dropdown-container {
+ position: relative;
+ display: inline-block;
+ z-index: 1500;
+}
+
+.quant-dropdown {
+ position: absolute;
+ top: 100%;
+ right: 0;
+ background-color: #2d2d2d;
+ border: 1px solid #444;
+ border-radius: 3px;
+ width: 100px;
+ z-index: 1500;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
+ margin-top: 2px;
+ max-height: 200px;
+ overflow-y: auto;
+}
+
+.quant-option {
+ padding: 6px 10px;
+ font-size: 12px;
+ color: #e0e0e0;
+ cursor: pointer;
+ transition: background-color 0.2s;
+}
+
+.quant-option:hover {
+ background-color: #444;
+}
+
+.quant-option.active {
+ background-color: #4a6b8a;
+}
+
+/* Generic button blink effect */
+.quant-button.button-blink {
+ animation: buttonBlink 0.2s ease-in-out;
+}
+
+@keyframes buttonBlink {
+ 0% { background-color: #333; }
+ 50% { background-color: #555; }
+ 100% { background-color: #333; }
+}
diff --git a/src/styles/variables.css b/src/styles/variables.css
new file mode 100644
index 0000000..a08337e
--- /dev/null
+++ b/src/styles/variables.css
@@ -0,0 +1,11 @@
+:root {
+ --time-signature-numerator: 4;
+ --max-number-of-bars: 32;
+ --track-grid-bar-width: 40px;
+ --region-piano-key-width: 60px;
+ --region-piano-key-height: 20px;
+ --region-grid-beat-width: 40px;
+ --region-grid-bar-width: calc(var(--region-grid-beat-width) * var(--time-signature-numerator));
+ --chat-box-width: 350px;
+ --instrument-selection-width: 300px;
+}