diff --git a/src/pygui/ISC/HomePage.qml b/src/pygui/ISC/HomePage.qml
index cede73d..c109de6 100644
--- a/src/pygui/ISC/HomePage.qml
+++ b/src/pygui/ISC/HomePage.qml
@@ -404,7 +404,7 @@ Rectangle {
id: badgeLabel
anchors.centerIn: parent
text: deviceController.connectionStatus || "Disconnected"
- color: "#111111"
+ color: Theme.statusBadgeText
font.pixelSize: Theme.font2xs
font.bold: true
}
diff --git a/src/pygui/ISC/Tabs/DataTab.qml b/src/pygui/ISC/Tabs/DataTab.qml
index 2dd862e..38e58ae 100644
--- a/src/pygui/ISC/Tabs/DataTab.qml
+++ b/src/pygui/ISC/Tabs/DataTab.qml
@@ -1,5 +1,6 @@
import QtQuick
import QtQuick.Controls
+import QtQuick.Controls.impl
import QtQuick.Layouts
import ISC
import ISC.Wafer
@@ -124,7 +125,7 @@ Item {
Layout.fillWidth: true
implicitHeight: 38
radius: 4
- color: Qt.rgba(1, 1, 1, 0.02)
+ color: Theme.cardWash
border.color: Theme.cardBorder
border.width: 1
@@ -232,7 +233,7 @@ Item {
Label {
text: slotBox.filePath !== ""
? root.shortName(slotBox.filePath)
- : (root.activeBox === slotBox.boxIndex ? "← Select file from left panel…" : "Click to select")
+ : (root.activeBox === slotBox.boxIndex ? "<- Select file from left panel..." : "Click to select")
font.pixelSize: Theme.fontXs
color: slotBox.filePath !== "" ? Theme.headingColor : Theme.bodyColor
opacity: slotBox.filePath !== "" ? 1.0 : 0.6
@@ -248,14 +249,15 @@ Item {
onClicked: slotBox.cleared()
background: Rectangle {
radius: Theme.radiusSm
- color: parent.hovered ? Qt.rgba(1, 1, 1, 0.08) : "transparent"
+ color: parent.hovered ? Theme.flatButtonHover : "transparent"
}
- contentItem: Label {
- text: "✕"
+ contentItem: IconImage {
+ source: "icons/x.svg"
+ width: 14; height: 14
+ sourceSize.width: 14
+ sourceSize.height: 14
color: Theme.bodyColor
- font.pixelSize: Theme.fontSm
- horizontalAlignment: Text.AlignHCenter
- verticalAlignment: Text.AlignVCenter
+ anchors.centerIn: parent
}
}
}
@@ -291,44 +293,54 @@ Item {
background: Rectangle {
radius: Theme.radiusSm
- color: resetBtn.hovered ? Qt.rgba(1, 1, 1, 0.08) : "transparent"
+ color: resetBtn.hovered ? Theme.flatButtonHover : "transparent"
}
- contentItem: Label {
- text: "↺"
- font.pixelSize: Theme.fontLg
+ contentItem: IconImage {
+ source: "icons/rotate-ccw.svg"
+ width: 18; height: 18
+ sourceSize.width: 18
+ sourceSize.height: 18
color: Theme.bodyColor
- horizontalAlignment: Text.AlignHCenter
- verticalAlignment: Text.AlignVCenter
+ anchors.centerIn: parent
}
ToolTip.visible: resetBtn.hovered
ToolTip.text: "Reset comparison"
}
-
- Label {
- text: "Dynamic Time Warping Profile Matching"
- font.pixelSize: Theme.fontSm
- color: Theme.bodyColor
- }
}
// ── Error Banner ───────────────────────────────────────────
Rectangle {
Layout.fillWidth: true
- Layout.preferredHeight: errorLabel.implicitHeight + 16
+ Layout.preferredHeight: errorRow.implicitHeight + 16
visible: root.errorMessage !== ""
- color: Qt.rgba(0.93, 0.27, 0.27, 0.15)
- border.color: "#ef4444"
+ color: Theme.errorSurface
+ border.color: Theme.statusErrorColor
border.width: 1
radius: Theme.radiusSm
- Label {
- id: errorLabel
+ RowLayout {
+ id: errorRow
anchors.fill: parent
anchors.margins: 8
- text: "⚠ " + root.errorMessage
- color: "#fca5a5"
- font.pixelSize: Theme.fontSm
- wrapMode: Text.WordWrap
+ spacing: 8
+
+ IconImage {
+ source: "icons/triangle-alert.svg"
+ width: 16; height: 16
+ sourceSize.width: 16
+ sourceSize.height: 16
+ color: Theme.errorTextSoft
+ Layout.alignment: Qt.AlignTop
+ }
+
+ Label {
+ id: errorLabel
+ text: root.errorMessage
+ color: Theme.errorTextSoft
+ font.pixelSize: Theme.fontSm
+ wrapMode: Text.WordWrap
+ Layout.fillWidth: true
+ }
}
}
@@ -402,9 +414,9 @@ Item {
var plotH = height - padTop - padBottom
var range = (maxV - minV) || 1
- ctx.strokeStyle = Qt.rgba(1, 1, 1, 0.08)
+ ctx.strokeStyle = Theme.chartGridLine
ctx.lineWidth = 1
- ctx.fillStyle = Qt.rgba(1, 1, 1, 0.35)
+ ctx.fillStyle = Theme.chartAxisText
ctx.font = "10px sans-serif"
ctx.textAlign = "right"
@@ -507,10 +519,14 @@ Item {
visible: !root.hasSeries
spacing: 8
- Label {
+ IconImage {
Layout.alignment: Qt.AlignHCenter
- text: root.comparing ? "" : "📊"
- font.pixelSize: 32
+ visible: !root.comparing
+ source: "icons/bar-chart.svg"
+ width: 32; height: 32
+ sourceSize.width: 32
+ sourceSize.height: 32
+ color: Theme.sideMutedText
}
Label {
Layout.alignment: Qt.AlignHCenter
@@ -655,10 +671,13 @@ Item {
anchors.centerIn: parent
visible: root.compareSensorLayout.length === 0 || !enableOverlapCheck.checked
spacing: 4
- Label {
+ IconImage {
Layout.alignment: Qt.AlignHCenter
- text: "🗺"
- font.pixelSize: 24
+ source: "icons/map.svg"
+ width: 24; height: 24
+ sourceSize.width: 24
+ sourceSize.height: 24
+ color: Theme.sideMutedText
}
Label {
Layout.alignment: Qt.AlignHCenter
@@ -864,7 +883,7 @@ Item {
label: "DTW ALIGNMENT DISTANCE"
value: root.warpingDistance >= 0 ? root.warpingDistance.toFixed(2) : "--"
valueColor: root.warpingDistance >= 0
- ? (root.warpingDistance < 50 ? "#6ee7b7" : root.warpingDistance < 100 ? "#fde047" : "#ef4444")
+ ? (root.warpingDistance < 50 ? Theme.metricGood : root.warpingDistance < 100 ? Theme.metricWarn : Theme.metricBad)
: Theme.sideMutedText
}
ReadoutCard {
@@ -878,7 +897,7 @@ Item {
label: "MAX SENSOR DEVIATION"
value: root.maxSensorDeviation >= 0 ? root.maxSensorDeviation.toFixed(2) + "°C" : "--"
valueColor: root.maxSensorDeviation >= 0
- ? (root.maxSensorDeviation < 1.0 ? "#6ee7b7" : root.maxSensorDeviation < 3.0 ? "#fde047" : "#ef4444")
+ ? (root.maxSensorDeviation < 1.0 ? Theme.metricGood : root.maxSensorDeviation < 3.0 ? Theme.metricWarn : Theme.metricBad)
: Theme.sideMutedText
}
}
diff --git a/src/pygui/ISC/Tabs/SelectFileDialog.qml b/src/pygui/ISC/Tabs/SelectFileDialog.qml
index 7a2c2b8..4928be5 100644
--- a/src/pygui/ISC/Tabs/SelectFileDialog.qml
+++ b/src/pygui/ISC/Tabs/SelectFileDialog.qml
@@ -1,5 +1,6 @@
import QtQuick
import QtQuick.Controls
+import QtQuick.Controls.impl
import QtQuick.Layouts
import Qt.labs.qmlmodels
import ISC
@@ -181,10 +182,17 @@ Dialog {
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: 12
- text: "✕"
implicitWidth: 32
implicitHeight: 32
onClicked: root.close()
+ contentItem: IconImage {
+ source: "icons/x.svg"
+ width: 14; height: 14
+ sourceSize.width: 14
+ sourceSize.height: 14
+ color: Theme.buttonNeutralText
+ anchors.centerIn: parent
+ }
}
}
diff --git a/src/pygui/ISC/Tabs/SettingsTab.qml b/src/pygui/ISC/Tabs/SettingsTab.qml
index b16d3fe..0ad7858 100644
--- a/src/pygui/ISC/Tabs/SettingsTab.qml
+++ b/src/pygui/ISC/Tabs/SettingsTab.qml
@@ -1,5 +1,6 @@
import QtQuick
import QtQuick.Controls
+import QtQuick.Controls.impl
import QtQuick.Layouts
import QtQuick.Dialogs
import ISC
@@ -123,19 +124,17 @@ Item {
ColorAnimation { duration: Theme.durationFast }
}
- Text {
+ IconImage {
anchors.centerIn: parent
- text: "✓"
- font.pixelSize: Theme.fontMd
- font.bold: true
+ source: "icons/check.svg"
+ width: 12; height: 12
+ sourceSize.width: 12
+ sourceSize.height: 12
color: Theme.panelBackground
opacity: toggle.checked ? 1.0 : 0.0
Behavior on opacity {
NumberAnimation { duration: Theme.durationFast }
}
- // Small nudge to center the checkmark perfectly
- verticalAlignment: Text.AlignVCenter
- horizontalAlignment: Text.AlignHCenter
}
}
@@ -366,7 +365,7 @@ Item {
width: 22
height: 22
radius: height / 2
- color: "white"
+ color: Theme.toggleThumb
anchors.verticalCenter: parent.verticalCenter
x: Theme.isDarkMode ? parent.width - width - 3 : 3
@@ -452,12 +451,9 @@ Item {
}
}
- Label {
+ Row {
anchors.centerIn: parent
- text: "↓ Scroll for more"
- font.pixelSize: Theme.fontSm
- font.bold: true
- color: Theme.bodyColor
+ spacing: 4
opacity: (settingsScroll.ScrollBar.vertical.position <= 0 && settingsScroll.contentHeight > settingsScroll.height) ? (scrollHintTimer.running ? 1 : 0) : 0
Behavior on opacity {
@@ -465,6 +461,22 @@ Item {
duration: 400
}
}
+
+ IconImage {
+ anchors.verticalCenter: parent.verticalCenter
+ source: "icons/chevron-down.svg"
+ width: 14; height: 14
+ sourceSize.width: 14
+ sourceSize.height: 14
+ color: Theme.bodyColor
+ }
+ Label {
+ anchors.verticalCenter: parent.verticalCenter
+ text: "Scroll for more"
+ font.pixelSize: Theme.fontSm
+ font.bold: true
+ color: Theme.bodyColor
+ }
}
}
}
diff --git a/src/pygui/ISC/Tabs/StatusTab.qml b/src/pygui/ISC/Tabs/StatusTab.qml
index 24ff99e..98fb309 100644
--- a/src/pygui/ISC/Tabs/StatusTab.qml
+++ b/src/pygui/ISC/Tabs/StatusTab.qml
@@ -1,6 +1,7 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
+import QtQuick.Controls.impl
import QtQuick.Dialogs
import ISC
@@ -211,7 +212,7 @@ ColumnLayout {
id: statusPillText
anchors.centerIn: parent
text: root.isConnected ? "ACTIVE" : (root.isBusy ? deviceController.connectionStatus.replace("...", "").toUpperCase() : "INACTIVE")
- color: "#111111"
+ color: Theme.statusBadgeText
font.pixelSize: Theme.fontXs
font.weight: Font.Bold
font.family: Theme.uiFontFamily
@@ -483,9 +484,12 @@ ColumnLayout {
anchors.rightMargin: Theme.panelPadding
spacing: 8
- Text {
- text: "📄"
- font.pixelSize: Theme.fontSm
+ IconImage {
+ source: "icons/file-text.svg"
+ width: 14; height: 14
+ sourceSize.width: 14
+ sourceSize.height: 14
+ color: Theme.bodyColor
visible: root.csvPath !== ""
Layout.alignment: Qt.AlignVCenter
}
diff --git a/src/pygui/ISC/Tabs/components/ReadoutPanel.qml b/src/pygui/ISC/Tabs/components/ReadoutPanel.qml
index 962b671..39d139b 100644
--- a/src/pygui/ISC/Tabs/components/ReadoutPanel.qml
+++ b/src/pygui/ISC/Tabs/components/ReadoutPanel.qml
@@ -1,5 +1,6 @@
import QtQuick
import QtQuick.Controls
+import QtQuick.Controls.impl
import QtQuick.Layouts
import ISC
@@ -32,18 +33,17 @@ ColumnLayout {
ColorAnimation { duration: Theme.durationFast }
}
- Text {
+ IconImage {
anchors.centerIn: parent
- text: "✓"
- font.pixelSize: Theme.fontSm
- font.bold: true
+ source: "../icons/check.svg"
+ width: 12; height: 12
+ sourceSize.width: 12
+ sourceSize.height: 12
color: Theme.panelBackground
opacity: toggle.checked ? 1.0 : 0.0
Behavior on opacity {
NumberAnimation { duration: Theme.durationFast }
}
- verticalAlignment: Text.AlignVCenter
- horizontalAlignment: Text.AlignHCenter
}
}
@@ -205,7 +205,7 @@ ColumnLayout {
Item { Layout.fillWidth: true }
Label {
text: s.diff !== undefined ? s.diff : "—"
- color: Theme.isDarkMode ? "#A78BFA" : "#8B5CF6"
+ color: Theme.diffAccent
font.family: Theme.codeFontFamily
font.pixelSize: Theme.fontMd
font.bold: true
diff --git a/src/pygui/ISC/Tabs/components/ReplaceSensorDialog.qml b/src/pygui/ISC/Tabs/components/ReplaceSensorDialog.qml
index 5c1ea37..7e3de1e 100644
--- a/src/pygui/ISC/Tabs/components/ReplaceSensorDialog.qml
+++ b/src/pygui/ISC/Tabs/components/ReplaceSensorDialog.qml
@@ -64,7 +64,7 @@ Dialog {
id: overrideTag
anchors.centerIn: parent
text: "OVERRIDE"
- color: "white"
+ color: Theme.statusBadgeText
font.pixelSize: Theme.fontXs
font.bold: true
font.letterSpacing: 1
diff --git a/src/pygui/ISC/Tabs/components/StreamStatsDialog.qml b/src/pygui/ISC/Tabs/components/StreamStatsDialog.qml
index bd1cc6a..0eb47d6 100644
--- a/src/pygui/ISC/Tabs/components/StreamStatsDialog.qml
+++ b/src/pygui/ISC/Tabs/components/StreamStatsDialog.qml
@@ -1,6 +1,7 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
+import QtQuick.Controls.impl
import ISC
// ===== Stream Stats Dialog =====
@@ -72,7 +73,6 @@ Popup {
}
Button {
- text: "✕"
flat: true
Layout.preferredWidth: 32
Layout.preferredHeight: 32
@@ -82,11 +82,13 @@ Popup {
radius: Theme.radiusXs
color: parent.hovered ? Theme.buttonNeutralHover : "transparent"
}
- contentItem: Label {
- text: parent.text
+ contentItem: IconImage {
+ source: "../icons/x.svg"
+ width: 14; height: 14
+ sourceSize.width: 14
+ sourceSize.height: 14
color: Theme.bodyColor
- horizontalAlignment: Text.AlignHCenter
- verticalAlignment: Text.AlignVCenter
+ anchors.centerIn: parent
}
}
}
diff --git a/src/pygui/ISC/Tabs/icons/bar-chart.svg b/src/pygui/ISC/Tabs/icons/bar-chart.svg
new file mode 100644
index 0000000..f5445d1
--- /dev/null
+++ b/src/pygui/ISC/Tabs/icons/bar-chart.svg
@@ -0,0 +1,15 @@
+
diff --git a/src/pygui/ISC/Tabs/icons/check.svg b/src/pygui/ISC/Tabs/icons/check.svg
new file mode 100644
index 0000000..5abe152
--- /dev/null
+++ b/src/pygui/ISC/Tabs/icons/check.svg
@@ -0,0 +1,13 @@
+
diff --git a/src/pygui/ISC/Tabs/icons/chevron-down.svg b/src/pygui/ISC/Tabs/icons/chevron-down.svg
new file mode 100644
index 0000000..e70d30b
--- /dev/null
+++ b/src/pygui/ISC/Tabs/icons/chevron-down.svg
@@ -0,0 +1,13 @@
+
diff --git a/src/pygui/ISC/Tabs/icons/file-text.svg b/src/pygui/ISC/Tabs/icons/file-text.svg
new file mode 100644
index 0000000..5227939
--- /dev/null
+++ b/src/pygui/ISC/Tabs/icons/file-text.svg
@@ -0,0 +1,17 @@
+
diff --git a/src/pygui/ISC/Tabs/icons/folder.svg b/src/pygui/ISC/Tabs/icons/folder.svg
new file mode 100644
index 0000000..ef69b34
--- /dev/null
+++ b/src/pygui/ISC/Tabs/icons/folder.svg
@@ -0,0 +1,13 @@
+
diff --git a/src/pygui/ISC/Tabs/icons/rotate-ccw.svg b/src/pygui/ISC/Tabs/icons/rotate-ccw.svg
new file mode 100644
index 0000000..eb0fe34
--- /dev/null
+++ b/src/pygui/ISC/Tabs/icons/rotate-ccw.svg
@@ -0,0 +1,14 @@
+
diff --git a/src/pygui/ISC/Tabs/icons/triangle-alert.svg b/src/pygui/ISC/Tabs/icons/triangle-alert.svg
new file mode 100644
index 0000000..4739ae8
--- /dev/null
+++ b/src/pygui/ISC/Tabs/icons/triangle-alert.svg
@@ -0,0 +1,15 @@
+
diff --git a/src/pygui/ISC/Tabs/icons/x.svg b/src/pygui/ISC/Tabs/icons/x.svg
new file mode 100644
index 0000000..e317943
--- /dev/null
+++ b/src/pygui/ISC/Tabs/icons/x.svg
@@ -0,0 +1,14 @@
+
diff --git a/src/pygui/ISC/Theme.qml b/src/pygui/ISC/Theme.qml
index a82cb68..c9a9c8f 100644
--- a/src/pygui/ISC/Theme.qml
+++ b/src/pygui/ISC/Theme.qml
@@ -7,18 +7,23 @@ import QtQuick
// =============================================================================
// Sections:
// 1. Mode flag
-// 2. Typography
+// 2. Typography (families, pixel sizes, weights)
// 3. Motion
-// 4. Tone palette (raw tones; everything else derives from these)
-// 5. Surfaces (page / card / panel / workspace backgrounds)
+// 4. Tone palette (raw tones; everything else derives from these)
+// 5. Surfaces (page / card / panel / workspace backgrounds)
// 6. Borders
-// 7. Text (headings, body, panel titles)
-// 8. Controls (fields, buttons, checkbox)
-// 9. Tracks (pill toggle + scrollbar)
-// 10. Tabs (footer tab bar)
-// 11. Side rail
-// 12. Status (success / warning / error)
-// 13. Geometry (radius / border width / spacing / sizing)
+// 7. Text (headings, body, panel titles)
+// 8. Controls (fields, buttons, checkbox, toggle)
+// 9. Interaction overlays (hover / active washes — mode-aware)
+// 10. Tracks (pill toggle + scrollbar)
+// 11. Tabs (mode toggle pills)
+// 12. Side rail
+// 13. Transport / toolbar
+// 14. Status & badges (success / warning / error, badge text)
+// 15. Sensor bands (wafer map dots)
+// 16. Wafer family badges (source list avatars + accent bars)
+// 17. Comparison & charts (metric grading, diff accent, canvas grid)
+// 18. Geometry (radius / border width / spacing / sizing)
// =============================================================================
// Based on Codex themes:
// Dark (oscurange): surface #0B0B0F, ink #E6E6E6
@@ -29,7 +34,10 @@ QtObject {
// ── 1. Mode ──────────────────────────────────────────────────────────────
property bool isDarkMode: true
- // ── 2. Typography ──────────────────────────────────────────────────────
+ // ── 2. Typography ────────────────────────────────────────────────────────
+ readonly property string uiFontFamily: "Geist, Inter, system-ui, -apple-system, BlinkMacSystemFont, sans-serif"
+ readonly property string codeFontFamily: "\"Geist Mono\", ui-monospace, \"SFMono-Regular\", monospace"
+
// pixelSize scale — map to closest token, tune globally
readonly property int font2xs: 9 // tiny metadata
readonly property int fontXs: 11 // captions, micro labels
@@ -44,22 +52,20 @@ QtObject {
readonly property int fontWeightMedium: 500
readonly property int fontWeightBold: 700
- // ── 3. Motion ──────────────────────────────────────────────────────────
+ // ── 3. Motion ────────────────────────────────────────────────────────────
readonly property int durationFast: 120 // micro-interactions (focus ring, hover flash)
readonly property int durationBase: 180 // standard transitions (pill switch, row select)
readonly property int durationSlow: 260 // larger transitions (panel open/close)
readonly property var easeStandard: Easing.OutCubic
- // ── 4. Tone palette (Codex theme v1 inspired) ───────────────────────────
- readonly property string uiFontFamily: "Geist, Inter, system-ui, -apple-system, BlinkMacSystemFont, sans-serif"
- readonly property string codeFontFamily: "\"Geist Mono\", ui-monospace, \"SFMono-Regular\", monospace"
-
+ // ── 4. Tone palette (Codex theme v1 inspired) ────────────────────────────
readonly property color themeSurface: isDarkMode ? "#0B0B0F" : "#F9F9F7"
readonly property color themeInk: isDarkMode ? "#E6E6E6" : "#2D2D2B"
readonly property color themeAccent: isDarkMode ? "#F9B98C" : "#B87333"
readonly property color themeSkill: isDarkMode ? "#479FFA" : "#3B82F6" // blue family both modes
readonly property color themeAdded: isDarkMode ? "#40C977" : "#00C853"
readonly property color themeRemoved: isDarkMode ? "#FA423E" : "#FF5F38"
+ readonly property color themeViolet: isDarkMode ? "#A78BFA" : "#8B5CF6"
readonly property color tone100: themeSurface
readonly property color tone150: isDarkMode ? "#101014" : "#F3F3F1"
@@ -71,7 +77,7 @@ QtObject {
readonly property color toneMute: isDarkMode ? "#A8A8A1" : "#85857E"
readonly property color toneBorder: isDarkMode ? "#2D2D34" : "#D2D2CE"
- // ── 3. Surfaces ──────────────────────────────────────────────────────────
+ // ── 5. Surfaces ──────────────────────────────────────────────────────────
readonly property color pageBackground: tone100
readonly property color cardBackground: tone150
readonly property color panelBackground: tone150
@@ -79,7 +85,7 @@ QtObject {
readonly property color responseBackground: tone150
readonly property color subtleSectionBackground: tone250
- // ── 4. Borders ───────────────────────────────────────────────────────────
+ // ── 6. Borders ───────────────────────────────────────────────────────────
readonly property color cardBorder: toneBorder
readonly property color cardSurfaceBorder: isDarkMode ? "#3A3A42" : "#C7C7C2"
readonly property color responseBorder: toneBorder
@@ -88,14 +94,14 @@ QtObject {
readonly property color outerFrameBorder: isDarkMode ? "#3A3A42" : "#C7C7C2"
readonly property color softBorder: isDarkMode ? "#24242A" : "#E4E4E1"
- // ── 5. Text ──────────────────────────────────────────────────────────────
+ // ── 7. Text ──────────────────────────────────────────────────────────────
readonly property color headingColor: toneText
readonly property color bodyColor: toneMute
readonly property color subheadingColor: toneMute
readonly property color panelTitleText: toneMute
readonly property color disabledText: toneMute
- // ── 6. Controls ──────────────────────────────────────────────────────────
+ // ── 8. Controls ──────────────────────────────────────────────────────────
// Fields
readonly property color fieldBackground: isDarkMode ? "#101014" : "#FFFFFF"
readonly property color fieldText: toneText
@@ -111,32 +117,48 @@ QtObject {
readonly property color primaryAccent: themeAccent
// Checkbox
readonly property color checkboxText: toneText
+ // Toggle switch thumb (white knob reads on both track colors)
+ readonly property color toggleThumb: "#FFFFFF"
- // ── 7. Tracks (pill toggle, scrollbar thumb) ─────────────────────────────
+ // ── 9. Interaction overlays ──────────────────────────────────────────────
+ // Mode-aware washes. Never use raw Qt.rgba(1,1,1,x) in views: a white
+ // overlay is invisible on light-mode surfaces.
+ readonly property color listHoverBackground: isDarkMode ? Qt.rgba(1, 1, 1, 0.04) : Qt.rgba(0, 0, 0, 0.03)
+ readonly property color listActiveBackground: isDarkMode ? Qt.rgba(1, 1, 1, 0.06) : Qt.rgba(0, 0, 0, 0.05)
+ readonly property color flatButtonHover: isDarkMode ? Qt.rgba(1, 1, 1, 0.08) : Qt.rgba(0, 0, 0, 0.06)
+ readonly property color cardWash: isDarkMode ? Qt.rgba(1, 1, 1, 0.02) : Qt.rgba(0, 0, 0, 0.02)
+
+ // ── 10. Tracks (pill toggle, scrollbar thumb) ────────────────────────────
readonly property color trackBackground: isDarkMode ? "#25252B" : "#E2E2DE"
- // ── 8. Tabs (mode toggle pills) ──────────────────────────────────────────
+ // ── 11. Tabs (mode toggle pills) ─────────────────────────────────────────
readonly property color tabActiveBackground: isDarkMode ? "#25252B" : "#FFFFFF"
- // ── 9. Side rail ─────────────────────────────────────────────────────────
+ // ── 12. Side rail ────────────────────────────────────────────────────────
readonly property color sideRailBackground: tone150
readonly property color sidePanelBackground: isDarkMode ? "#151518" : "#F3F3F1"
readonly property color sideActiveBackground: isDarkMode ? "#25252B" : "#FFFFFF"
readonly property color sideBorder: toneBorder
readonly property color sideMutedText: toneMute
- // ── 10a. Transport / toolbar surfaces ────────────────────────────────────
+ // ── 13. Transport / toolbar surfaces ─────────────────────────────────────
readonly property color transportButtonBg: tone250
readonly property color transportButtonHover: tone300
readonly property color liveColor: themeAdded
readonly property color recordColor: themeRemoved
- // ── 10. Status ───────────────────────────────────────────────────────────
+ // ── 14. Status & badges ──────────────────────────────────────────────────
readonly property color statusSuccessColor: themeAdded
readonly property color statusWarningColor: isDarkMode ? "#E8A817" : "#B8860B" // amber/yellow, separate from accent
readonly property color statusErrorColor: themeRemoved
+ // Text placed ON a filled status pill / saturated chip:
+ readonly property color statusBadgeText: "#111111" // dark ink on bright status fills, both modes
+ readonly property color textOnColor: "#FFFFFF" // white text on deep saturated fills (avatars etc.)
+ // Error banner (soft red surface + readable red text)
+ readonly property color errorSurface: Qt.alpha(statusErrorColor, 0.15)
+ readonly property color errorTextSoft: isDarkMode ? "#FCA5A5" : "#B91C1C"
- // -- 10b. Sensor bands (wafer map dots)
+ // ── 15. Sensor bands (wafer map dots) ────────────────────────────────────
readonly property color sensorInRange: statusSuccessColor
// ponytail: high-temp shares error red — semantically correct (dangerous value),
// re-hue if colorblind testing demands a different channel.
@@ -145,7 +167,31 @@ QtObject {
readonly property color waferRingColor: toneBorder
readonly property color waferAxisColor: softBorder
- // ── 11. Geometry ─────────────────────────────────────────────────────────
+ // ── 16. Wafer family badges (SourcePanel list) ───────────────────────────
+ // Accent = left bar / outline shade; Fill = avatar circle behind textOnColor.
+ // Family grouping mirrors FileBrowser's waferType first-letter convention.
+ readonly property color familyBlueAccent: "#3B82F6" // A / E / P
+ readonly property color familyBlueFill: "#1D4ED8"
+ readonly property color familyGreenAccent: "#10B981" // B / C / D
+ readonly property color familyGreenFill: "#065F46"
+ readonly property color familyVioletAccent: "#8B5CF6" // Z
+ readonly property color familyVioletFill: "#7C3AED"
+ readonly property color familyNeutralFill: "#374151" // unknown family
+
+ // ── 17. Comparison & charts ──────────────────────────────────────────────
+ // Metric grading for DTW readout cards (good → caution → bad).
+ // Dark values are pastel (readable on tone150); light values are deepened
+ // so they still pass on near-white cards.
+ readonly property color metricGood: isDarkMode ? "#6EE7B7" : "#059669"
+ readonly property color metricWarn: isDarkMode ? "#FDE047" : "#B45309"
+ readonly property color metricBad: isDarkMode ? "#EF4444" : "#DC2626"
+ // DIFF column accent in ReadoutPanel
+ readonly property color diffAccent: themeViolet
+ // Canvas chart primitives (DTW plot grid + axis labels)
+ readonly property color chartGridLine: isDarkMode ? Qt.rgba(1, 1, 1, 0.08) : Qt.rgba(0, 0, 0, 0.10)
+ readonly property color chartAxisText: isDarkMode ? Qt.rgba(1, 1, 1, 0.35) : Qt.rgba(0, 0, 0, 0.45)
+
+ // ── 18. Geometry ─────────────────────────────────────────────────────────
// Radius
readonly property int radiusXs: 6 // fields, tight elements
readonly property int radiusSm: 8 // buttons