diff --git a/DESIGN.md b/DESIGN.md index e65e270..c3ad67a 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -8,7 +8,7 @@ colors: paper-raised: "#f8f9fa" paper-sunk: "#e9ecef" ink: "#212529" - ink-muted: "#6c757d" + ink-muted: "#5f666d" rule: "#dee2e6" night: "#1a1a1a" night-raised: "#2d2d2d" @@ -19,6 +19,15 @@ colors: lamp-green: "#198754" lamp-red: "#dc3545" lamp-amber: "#ffc107" + status-text-success: "#146c43" + status-text-warning: "#7a5d02" + status-text-danger: "#b02a37" + status-text-info: "#0a6c80" + night-status-text-success: "#75b798" + night-status-text-warning: "#ffda6a" + night-status-text-danger: "#f1aeb5" + night-status-text-info: "#6edff6" + night-signal-blue-text: "#6ea8fe" route-direct: "#20c997" scope-black: "#0d1117" scope-rule: "#30363d" @@ -162,12 +171,15 @@ A neutral Bootstrap-gray desk with one blue signal and a set of lamp colors that - **Lamp Amber** (`lamp-amber`): warning and degraded states, and the packet-entry rule in the activity log. - **Lamp Red** (`lamp-red`): disconnected, error, negative deltas, destructive actions. +### Status text +The lamp hues are fill tones. As text they fail contrast (amber on white is 1.6:1), so text that carries state uses a separate per-theme set, exposed in `base.html` as `--text-success`, `--text-warning`, `--text-danger`, `--text-info`, `--text-primary`, `--link-color` and `--code-color`. Bootstrap's `.text-*` utilities, `.text-muted`, `.form-text`, and the outline buttons all resolve through these, so a page gets the right tone in both themes by using the utility. Light values pass 4.5:1 on paper, paper-raised and paper-sunk; dark values pass on night, night-raised and night-sunk. Solid `bg-info` and `bg-warning` badges carry dark text. + ### Neutral - **Paper** (`paper`) / **Night** (`night`): page background in light and dark. - **Paper Raised** (`paper-raised`) / **Night Raised** (`night-raised`): card headers, footer, log-entry blocks in light; cards themselves in dark. - **Paper Sunk** (`paper-sunk`) / **Night Sunk** (`night-sunk`): meter tracks, empty chip fills, connection-info panels, striped and hovered table rows in dark. - **Ink** (`ink`) / **Night Ink** (`night-ink`): body text. -- **Ink Muted** (`ink-muted`) / **Night Ink Muted** (`night-ink-muted`): labels, secondary values, empty states, inactive icons. +- **Ink Muted** (`ink-muted`) / **Night Ink Muted** (`night-ink-muted`): labels, secondary values, empty states, inactive icons. Ink Muted is a step darker than Bootstrap's `#6c757d` so it holds 4.5:1 on paper-sunk too. On the console-black rail and table headers, muted text uses the night tone in either theme. - **Rule** (`rule`) / **Night Rule** (`night-rule`): 1px borders, dividers, the hairline after section titles. - **Console Black** (`console-black`): the navbar rail in both themes. - **Scope Black**, **Scope Rule**, **Scope Ink** (`scope-black`, `scope-rule`, `scope-ink`): the log console's own dark surface, border, and default line color, borrowed from a terminal rather than from the page theme. @@ -178,6 +190,8 @@ Charts use their own validated palettes in `static/js/dashboard.js`, not the lam ### Named Rules **The Lamp Rule.** Green, amber, and red mean connected, degraded, and failed. They never decorate a heading, an icon, or a button that isn't about state. +**The Fill-Is-Not-Text Rule.** A lamp or accent hue used as text goes through its status-text token, never the raw fill hex. Tinted surfaces (message bubbles, delta chips) are a low-alpha wash of the hue over the card, so body text and the status-text tokens keep their contrast on them. + **The Twin Token Rule.** A color that is hard-coded for one theme ships with its `[data-theme="dark"]` (or light) counterpart in the same change. Bootstrap 5.1.3 has no dark theme of its own here; nothing inherits one for free. **The Legend Rule.** Several chart hues sit under 3:1 against their card, so a series is always identified by a legend or a label as well as by color. diff --git a/modules/web_viewer/templates/base.html b/modules/web_viewer/templates/base.html index 00bc92b..2a16ffd 100644 --- a/modules/web_viewer/templates/base.html +++ b/modules/web_viewer/templates/base.html @@ -33,7 +33,7 @@ --bg-secondary: #f8f9fa; --bg-tertiary: #e9ecef; --text-color: #212529; - --text-muted: #6c757d; + --text-muted: #5f666d; --border-color: #dee2e6; --card-bg: #ffffff; --card-header-bg: #f8f9fa; @@ -41,6 +41,16 @@ --log-entry-bg: #f8f9fa; --connection-info-bg: #e9ecef; --shadow-color: rgba(0, 0, 0, 0.1); + /* Status and accent colors used as text. Bootstrap's own text-* + colors are background tones and fail contrast as text; these + pass 4.5:1 on paper, paper-raised and paper-sunk. */ + --text-success: #146c43; + --text-warning: #7a5d02; + --text-danger: #b02a37; + --text-info: #0a6c80; + --text-primary: #0d6efd; + --link-color: #0d6efd; + --code-color: #ab296a; } /* CSS Variables for Dark Mode */ @@ -57,6 +67,14 @@ --log-entry-bg: #2d2d2d; --connection-info-bg: #3d3d3d; --shadow-color: rgba(0, 0, 0, 0.3); + /* Pass 4.5:1 on night, night-raised and night-sunk. */ + --text-success: #75b798; + --text-warning: #ffda6a; + --text-danger: #f1aeb5; + --text-info: #6edff6; + --text-primary: #6ea8fe; + --link-color: #6ea8fe; + --code-color: #e685b5; } /* Apply theme variables */ @@ -255,11 +273,74 @@ color: var(--text-muted); } - /* Dark mode text muted */ - [data-theme="dark"] .text-muted { + /* Muted and status text follow the theme in both themes */ + .text-muted, + .form-text { color: var(--text-muted) !important; } + /* On the console-black table headers and navbar, muted text uses the + night tone in either theme. */ + .table-dark .text-muted, + .navbar-dark .text-muted { + color: #adb5bd !important; + } + + .alert code { color: inherit; } + + .text-success { color: var(--text-success) !important; } + .text-warning { color: var(--text-warning) !important; } + .text-danger { color: var(--text-danger) !important; } + .text-info { color: var(--text-info) !important; } + .text-primary { color: var(--text-primary) !important; } + code { color: var(--code-color); } + + /* Solid info and warning fills are light, so they carry dark text + (Bootstrap 5.1 gives every badge white text). */ + .badge.bg-info, + .badge.bg-warning { + color: #212529 !important; + } + + [data-theme="dark"] a:not(.btn):not(.nav-link):not(.navbar-brand):not(.dropdown-item) { + color: var(--link-color); + } + + /* Outline buttons: Bootstrap's outline text colors are its fill tones, + which fail as text on raised surfaces and on the dark theme. */ + .btn-outline-secondary { + color: var(--text-muted); + } + .btn-outline-secondary:hover, + .btn-outline-secondary.active { + color: #fff; + background-color: #6c757d; + } + .btn-outline-danger { + color: var(--text-danger); + } + .btn-outline-danger:hover, + .btn-outline-danger.active { + color: #fff; + } + [data-theme="dark"] .btn-outline-primary { + color: var(--text-primary); + } + [data-theme="dark"] .btn-outline-primary:hover, + [data-theme="dark"] .btn-outline-primary.active { + color: #fff; + } + .btn-outline-warning { + color: var(--text-warning); + } + .btn-outline-warning:hover, + .btn-outline-warning.active { + color: #212529; + } + [data-theme="dark"] .btn-link { + color: var(--link-color); + } + /* Dark mode borders. The directional utilities need naming too — the all-sides rule does not cover them, so a .border-start divider drew Bootstrap's light #dee2e6 straight onto a dark card. */ diff --git a/modules/web_viewer/templates/contacts.html b/modules/web_viewer/templates/contacts.html index f474925..e15ea88 100644 --- a/modules/web_viewer/templates/contacts.html +++ b/modules/web_viewer/templates/contacts.html @@ -2777,9 +2777,9 @@ document.addEventListener('DOMContentLoaded', () => { color: var(--text-color); } -/* Ensure all text in table cells is light in dark mode */ -[data-theme="dark"] .table td, -[data-theme="dark"] .table td * { +/* Table cells take the light text color in dark mode; children with their + own color (badges, buttons, status text) keep it. */ +[data-theme="dark"] .table td { color: var(--text-color) !important; } diff --git a/modules/web_viewer/templates/feeds.html b/modules/web_viewer/templates/feeds.html index 3ead05b..52c22d8 100644 --- a/modules/web_viewer/templates/feeds.html +++ b/modules/web_viewer/templates/feeds.html @@ -1216,9 +1216,9 @@ document.addEventListener('DOMContentLoaded', () => { color: var(--text-color); } -/* Ensure all text in table cells is light in dark mode */ -[data-theme="dark"] .table td, -[data-theme="dark"] .table td * { +/* Table cells take the light text color in dark mode; children with their + own color (badges, buttons, status text) keep it. */ +[data-theme="dark"] .table td { color: var(--text-color) !important; } diff --git a/modules/web_viewer/templates/greeter.html b/modules/web_viewer/templates/greeter.html index b7a73b0..d592440 100644 --- a/modules/web_viewer/templates/greeter.html +++ b/modules/web_viewer/templates/greeter.html @@ -574,9 +574,9 @@ document.addEventListener('DOMContentLoaded', () => { color: var(--text-color); } -/* Ensure all text in table cells is light in dark mode */ -[data-theme="dark"] .table td, -[data-theme="dark"] .table td * { +/* Table cells take the light text color in dark mode; children with their + own color (badges, buttons, status text) keep it. */ +[data-theme="dark"] .table td { color: var(--text-color) !important; } diff --git a/modules/web_viewer/templates/logs.html b/modules/web_viewer/templates/logs.html index b0131cb..de8211d 100644 --- a/modules/web_viewer/templates/logs.html +++ b/modules/web_viewer/templates/logs.html @@ -43,10 +43,11 @@ .log-line.level-error { color: #f85149; } .log-line.level-critical{ color: #ff79c6; font-weight: bold; } - [data-theme="light"] .log-line.level-debug { color: #0d9488; } - [data-theme="light"] .log-line.level-info { color: #0d6efd; } - [data-theme="light"] .log-line.level-warning { color: #fd7e14; } - [data-theme="light"] .log-line.level-error { color: #dc3545; } + /* Light set: each passes 4.5:1 on the light log well (#f8f9fa). */ + [data-theme="light"] .log-line.level-debug { color: #0f766e; } + [data-theme="light"] .log-line.level-info { color: #0a58ca; } + [data-theme="light"] .log-line.level-warning { color: #a85300; } + [data-theme="light"] .log-line.level-error { color: #b02a37; } [data-theme="light"] .log-line.level-critical{ color: #6610f2; font-weight: bold; } .log-controls { @@ -97,14 +98,14 @@ .log-level-toggle[data-level="DEBUG"].is-on { background: #2dd4bf; color: #0d1117; border-color: #2dd4bf; } .log-level-toggle[data-level="INFO"].is-on { background: #58a6ff; color: #0d1117; border-color: #58a6ff; } .log-level-toggle[data-level="WARNING"].is-on { background: #d29922; color: #0d1117; border-color: #d29922; } - .log-level-toggle[data-level="ERROR"].is-on { background: #f85149; color: #fff; border-color: #f85149; } + .log-level-toggle[data-level="ERROR"].is-on { background: #f85149; color: #0d1117; border-color: #f85149; } .log-level-toggle[data-level="CRITICAL"].is-on { background: #ff79c6; color: #0d1117; border-color: #ff79c6; } /* Light theme — on */ - [data-theme="light"] .log-level-toggle[data-level="DEBUG"].is-on { background: #0d9488; color: #fff; border-color: #0d9488; } - [data-theme="light"] .log-level-toggle[data-level="INFO"].is-on { background: #0d6efd; color: #fff; border-color: #0d6efd; } + [data-theme="light"] .log-level-toggle[data-level="DEBUG"].is-on { background: #0f766e; color: #fff; border-color: #0f766e; } + [data-theme="light"] .log-level-toggle[data-level="INFO"].is-on { background: #0a58ca; color: #fff; border-color: #0a58ca; } [data-theme="light"] .log-level-toggle[data-level="WARNING"].is-on { background: #fd7e14; color: #212529; border-color: #fd7e14; } - [data-theme="light"] .log-level-toggle[data-level="ERROR"].is-on { background: #dc3545; color: #fff; border-color: #dc3545; } + [data-theme="light"] .log-level-toggle[data-level="ERROR"].is-on { background: #b02a37; color: #fff; border-color: #b02a37; } [data-theme="light"] .log-level-toggle[data-level="CRITICAL"].is-on { background: #6610f2; color: #fff; border-color: #6610f2; } {% endblock %} diff --git a/modules/web_viewer/templates/radio.html b/modules/web_viewer/templates/radio.html index 1c0d0bc..6b85698 100644 --- a/modules/web_viewer/templates/radio.html +++ b/modules/web_viewer/templates/radio.html @@ -1968,9 +1968,9 @@ document.addEventListener('DOMContentLoaded', () => { color: var(--text-color); } -/* Ensure all text in table cells is light in dark mode */ -[data-theme="dark"] .table td, -[data-theme="dark"] .table td * { +/* Table cells take the light text color in dark mode; children with their + own color (badges, buttons, status text) keep it. */ +[data-theme="dark"] .table td { color: var(--text-color) !important; } diff --git a/modules/web_viewer/templates/realtime.html b/modules/web_viewer/templates/realtime.html index 0e411d0..be51a13 100644 --- a/modules/web_viewer/templates/realtime.html +++ b/modules/web_viewer/templates/realtime.html @@ -102,7 +102,6 @@ .live-msg-time { font-size: 0.58rem; line-height: 1.2; - opacity: 0.88; } .stream-entry:hover { @@ -162,10 +161,6 @@ color: #fff; } - .text-warning { - color: #fd7e14 !important; - } - .conversation-entry { border-left: 3px solid #007bff; padding-left: 10px; @@ -179,11 +174,23 @@ color: var(--text-color); } + /* Dark bubbles are light tints of the lamp and signal hues over the + card, like the dashboard delta chips, so body text and the theme's + status text colors keep their contrast inside them. */ [data-theme="dark"] .user-message { - background-color: #1a237e; - border-color: #283593; - color: #e3f2fd; - box-shadow: 0 1px 3px rgba(0, 0, 0, 0.5); + background-color: rgba(13, 110, 253, 0.18); + border-color: rgba(110, 168, 254, 0.35); + color: var(--text-color); + } + + /* Sender names on the light blue bubble need a deeper blue than the + page's link blue. */ + .user-message .text-primary { + color: #0a58ca !important; + } + + [data-theme="dark"] .user-message .text-primary { + color: #8bb9fe !important; } .bot-message-success { @@ -194,10 +201,9 @@ } [data-theme="dark"] .bot-message-success { - background-color: #1b5e20; - border-color: #2e7d32; - color: #c8e6c9; - box-shadow: 0 1px 3px rgba(0, 0, 0, 0.5); + background-color: rgba(25, 135, 84, 0.2); + border-color: rgba(117, 183, 152, 0.35); + color: var(--text-color); } .bot-message-danger { @@ -208,10 +214,9 @@ } [data-theme="dark"] .bot-message-danger { - background-color: #4a148c; - border-color: #6a1b9a; - color: #f8bbd0; - box-shadow: 0 1px 3px rgba(0, 0, 0, 0.5); + background-color: rgba(220, 53, 69, 0.18); + border-color: rgba(234, 134, 143, 0.35); + color: var(--text-color); } .response-text { @@ -529,15 +534,15 @@ Show: