diff --git a/eslint-plugin-rill/index.js b/eslint-plugin-rill/index.js
new file mode 100644
index 000000000000..2185896e5140
--- /dev/null
+++ b/eslint-plugin-rill/index.js
@@ -0,0 +1,7 @@
+import noDisallowedTailwindTextColors from "./no-disallowed-tailwind-colors.js";
+
+export default {
+ rules: {
+ "no-disallowed-tailwind-text-colors": noDisallowedTailwindTextColors,
+ },
+};
diff --git a/eslint-plugin-rill/no-disallowed-tailwind-colors.js b/eslint-plugin-rill/no-disallowed-tailwind-colors.js
new file mode 100644
index 000000000000..5de8386262ed
--- /dev/null
+++ b/eslint-plugin-rill/no-disallowed-tailwind-colors.js
@@ -0,0 +1,91 @@
+/**
+ * ESLint rule to disallow certain Tailwind text color classes.
+ * Disallows: text-gray-*, text-neutral-*, text-slate-*, text-stone-*, text-zinc-*
+ */
+
+const DISALLOWED_TEXT_PATTERN =
+ /\btext-(gray|neutral|slate|stone|zinc)-\d{1,3}\b/g;
+const TEXT_ERROR_MESSAGE =
+ 'Disallowed Tailwind text color class: "{{ className }}". Use semantic color classes instead.';
+
+const DISALLOWED_BACKGROUND_PATTERN =
+ /\bbg-(gray|neutral|slate|stone|zinc)-\d{1,3}\b/g;
+const DISALLOWED_BACKGROUND_CLASSES = /\bbg-(white|black)\b/g;
+const BACKGROUND_ERROR_MESSAGE =
+ 'Disallowed Tailwind background color class: "{{ className }}". Use semantic color classes instead.';
+
+const DISALLOWED_CLASSES_PATTERNS = [
+ [DISALLOWED_TEXT_PATTERN, TEXT_ERROR_MESSAGE],
+
+ [DISALLOWED_BACKGROUND_PATTERN, BACKGROUND_ERROR_MESSAGE],
+ [DISALLOWED_BACKGROUND_CLASSES, BACKGROUND_ERROR_MESSAGE],
+];
+
+function reportAllMatches(value, context, node) {
+ if (typeof value !== "string") return;
+
+ for (const [pattern, errorMessage] of DISALLOWED_CLASSES_PATTERNS) {
+ for (const match of value.matchAll(pattern)) {
+ context.report({
+ node,
+ message: errorMessage,
+ data: { className: match[0] },
+ });
+ }
+ }
+}
+
+export default {
+ meta: {
+ type: "problem",
+ docs: {
+ description:
+ "Disallow non-semantic Tailwind text/background color classes (gray, neutral, slate, stone, zinc)",
+ },
+ schema: [],
+ },
+ create(context) {
+ const sourceCode = context.sourceCode ?? context.getSourceCode();
+
+ return {
+ // Check Svelte HTML attributes (class="..." and className="...")
+ SvelteAttribute(node) {
+ if (node.key?.name === "class" || node.key?.name === "className") {
+ for (const valueNode of node.value) {
+ if (valueNode.type === "SvelteLiteral") {
+ reportAllMatches(valueNode.value, context, valueNode);
+ }
+ }
+ }
+ },
+ // Check Svelte shorthand class directives (class:text-gray-500)
+ SvelteDirective(node) {
+ if (node.kind === "Class" && node.key?.name) {
+ const className = node.key.name.name || node.key.name;
+ reportAllMatches(className, context, node);
+ }
+ },
+ // Check Svelte
diff --git a/web-common/src/features/alerts/PreviewEmpty.svelte b/web-common/src/features/alerts/PreviewEmpty.svelte
index 62aeda311de2..44383411e797 100644
--- a/web-common/src/features/alerts/PreviewEmpty.svelte
+++ b/web-common/src/features/alerts/PreviewEmpty.svelte
@@ -6,7 +6,7 @@
-
+
{topLine}
diff --git a/web-common/src/features/alerts/data-tab/NoFiltersSelected.svelte b/web-common/src/features/alerts/data-tab/NoFiltersSelected.svelte
index c10266bafa40..78750bd6c968 100644
--- a/web-common/src/features/alerts/data-tab/NoFiltersSelected.svelte
+++ b/web-common/src/features/alerts/data-tab/NoFiltersSelected.svelte
@@ -6,7 +6,7 @@
-
+
{m.alert_no_filters_heading()}
diff --git a/web-common/src/features/canvas/components/charts/custom-chart/AgenticChartPrompt.svelte b/web-common/src/features/canvas/components/charts/custom-chart/AgenticChartPrompt.svelte
index 642e1ccfa3e6..60b4f5bf269a 100644
--- a/web-common/src/features/canvas/components/charts/custom-chart/AgenticChartPrompt.svelte
+++ b/web-common/src/features/canvas/components/charts/custom-chart/AgenticChartPrompt.svelte
@@ -41,7 +41,7 @@
{#if icon}
-
+
{:else}
diff --git a/web-common/src/features/dashboards/errors/InlineErrorIndicator.svelte b/web-common/src/features/dashboards/errors/InlineErrorIndicator.svelte
index 96cb44eb6ce2..3691d8f3f829 100644
--- a/web-common/src/features/dashboards/errors/InlineErrorIndicator.svelte
+++ b/web-common/src/features/dashboards/errors/InlineErrorIndicator.svelte
@@ -35,7 +35,7 @@
{#if message}