openvibers/openvibe.live Commits
Chat names and the AI label readable on light themes (#521)
Changes
@@@ -6,7 +6,8 @@.cf-wrap {--cf-gap: 16px;--cf-radius: 14px;-- --cf-ai: #a78bfa; /* AI text on dark surfaces */++ /* AI text: the violet mixed with the theme's text, so it holds on light themes too (it read 2.5:1 on Daylight). */++ --cf-ai: color-mix(in srgb, #a78bfa 62%, var(--text-primary, #e6edf7));--cf-ai-2: #22d3ee;--cf-ai-fill: linear-gradient(135deg, #6d28d9, #0e7490); /* behind white text: 4.5:1 or better */max-width: 1240px;@@@ -1138,7 +1138,7 @@ function queueFullscreenChatEntry(entry) {function buildFullscreenChatEntry(msg) {const badge = chatSettings.showBadges ? getBadgeHTML(msg.role) : '';let nameColor = relayColorFor(msg) || msg.color || msg.profile_color || getRoleColor(msg.role);-- if (chatSettings.readableColors) nameColor = ensureReadableColor(nameColor);++ if (chatSettings.readableColors || _chatLightTheme()) nameColor = ensureReadableColor(nameColor);const displayName = esc(msg.username || msg.displayName || `anon${msg.anonId || ''}`);const _relayPlatform = (msg.source_platform || parseRelayUsername(msg.username || msg.displayName || '').platform || '').toLowerCase();const _relayBadge = relayBadgeHTML(_relayPlatform);@@@ -2586,7 +2586,7 @@ function buildChatMessageEl(msg, opts = {}) {const badge = chatSettings.showBadges ? getBadgeHTML(msg.role) : '';let nameColor = relayColorFor(msg) || msg.color || msg.profile_color || getRoleColor(msg.role);// Readable colors — ensure minimum contrast against dark backgrounds-- if (chatSettings.readableColors) nameColor = ensureReadableColor(nameColor);++ if (chatSettings.readableColors || _chatLightTheme()) nameColor = ensureReadableColor(nameColor);const displayName = esc(msg.username || msg.displayName || `anon${msg.anonId || ''}`);const coreUsername = esc(msg.core_username || '');@@@ -2906,7 +2906,7 @@ function addSystemMessage(text, isError = false) {*/function getChatAvatarHTML(msg) {let nameColor = relayColorFor(msg) || msg.color || msg.profile_color || getRoleColor(msg.role);-- if (chatSettings.readableColors) nameColor = ensureReadableColor(nameColor);++ if (chatSettings.readableColors || _chatLightTheme()) nameColor = ensureReadableColor(nameColor);// Strip any "[Twitch]/[Kick]/[RS]" relay prefix so the initial is the real letter.const raw = (msg.username || msg.displayName || `anon${msg.anonId || ''}`).replace(/^\[[^\]]+\]\s*/, '');const initial = esc((raw.charAt(0) || '?').toUpperCase());@@@ -2927,7 +2927,7 @@ function addGottiMessage(msg) {const avatarHtml = getChatAvatarHTML(msg);const hatHtml = msg.hatFX?.emoji ? `<span class="chat-hat" aria-hidden="true">${esc(msg.hatFX.emoji)}</span>` : '';let nameColor = relayColorFor(msg) || msg.color || msg.profile_color || getRoleColor(msg.role);-- if (chatSettings.readableColors) nameColor = ensureReadableColor(nameColor);++ if (chatSettings.readableColors || _chatLightTheme()) nameColor = ensureReadableColor(nameColor);const displayName = esc(msg.username || msg.displayName || `anon${msg.anonId || ''}`);const coreUsername = esc(msg.core_username || '');@@@ -5203,7 +5203,7 @@ function _buildCrossfeedEl(msg) {}const badge = chatSettings.showBadges ? getBadgeHTML(msg.role) : '';let nameColor = relayColorFor(msg) || msg.color || msg.profile_color || getRoleColor(msg.role);-- if (chatSettings.readableColors) nameColor = ensureReadableColor(nameColor);++ if (chatSettings.readableColors || _chatLightTheme()) nameColor = ensureReadableColor(nameColor);const displayName = esc(msg.username || msg.displayName || `anon${msg.anonId || ''}`);const _relayPlatform = (msg.source_platform || parseRelayUsername(msg.username || msg.displayName || '').platform || '').toLowerCase();const _relayBadge = relayBadgeHTML(_relayPlatform);@@@ -5961,8 +5961,13 @@ function playMentionSound() {} catch { }}++// A light theme (theme-loader sets data-theme-mode): pale name colours there vanish on white, so names are always made++// readable, darkened rather than brightened (contrast probe, 2026-11-01: 1.56:1 for a pale name on Daylight).++function _chatLightTheme() {++ try { return document.documentElement.getAttribute('data-theme-mode') === 'light'; } catch { return false; }++}function ensureReadableColor(hex) {-- // Ensure minimum luminance for dark backgrounds (target: 0.4 relative luminance)++ // Dark themes: a minimum brightness (0.4). Light themes: a maximum (0.45), about 4.5:1 on white.try {let r, g, b;if (hex.startsWith('#')) {@@@ -5974,6 +5979,12 @@ function ensureReadableColor(hex) {return hex;}const lum = (0.299 * r + 0.587 * g + 0.114 * b) / 255;++ if (_chatLightTheme()) {++ if (lum <= 0.45) return hex;++ const k = 0.45 / lum;++ r = Math.round(r * k); g = Math.round(g * k); b = Math.round(b * k);++ return `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}`;++ }if (lum < 0.4) {// Brighten the color while keeping the hueconst boost = 0.4 / Math.max(lum, 0.01);@@@ -22,7 +22,7 @@ const BUDGETS = {htmlRawKB: 128, // 119.3 with the icons drawn on the server (2026-11-01, plan L54 K4: the OpenVibe glyphs in the HTML, 20.8 KB brotli); measured 94.9 beforehtmlBrotliKB: 30,jsFiles: 26, // measured 23 (incl. route scripts for "/")-- jsRawKB: 1250, // 1247.7 openvibe-shared 4.70.0 (2026-11-01: the app bar, busy(), skeletons, view transitions); 1244.3 with openvibe-shared 4.66.0: the mark with depth and motion, ov-fx loaded on request (2026-10-31); 1243.5 with openvibe-shared 4.64.0: the look travels between sites, the Look panel in the menu (2026-10-31); 1242.7 with openvibe-shared 4.59.0: the Pair mark beside the name, set in the brand face, and the ring on page moves (2026-10-31); 1238.8 with the home's featured stream once and the intro closed on phones (2026-10-31); 1237.4 with the home's two more tab blocks on phones (2026-10-30); 1233.9 with the home's Catch up tabs on phones (2026-10-30); 1230.8 with openvibe-shared 4.53.0: the footer's columns fold on phones (2026-10-30); 1227.8 with openvibe-shared 4.52.0: the Dock's loader and its Chats tab (2026-10-30); 1223.5 with openvibe-shared 4.48.0 (the site switcher on the mark, the menu's Start tab and quick tools; Kit's touch hit areas and the phone navbar fix, 4.44-4.47.3); 1215.4 with openvibe-shared 4.43.0 (room.css carries the kit tokens, 4.39.1; the kit's 4.39.0 rules); measured 1203.9 (2026-10-28: openvibe-shared 4.30.0, the bell center: tabs with counts, the Unread filter, thumbnails, swipe, the phone sheet; 4.31.0's ✦ adds about 3 KB); 1187.2 (2026-10-28: openvibe-shared 4.27.0, Notifications 2.0: opaque themed toasts held while a menu is open, grouping, priority, System cards and the rich bell panel); 1158.8 (2026-10-28: openvibe-shared 4.25.0, the menu's orb, messages, the phone sheet and auto-hide in the navbar; the messenger opens from the bar)++ jsRawKB: 1251, // 1250.2 (2026-11-01: topics live now, readable chat names on light themes); 1247.7 openvibe-shared 4.70.0 (2026-11-01: the app bar, busy(), skeletons, view transitions); 1244.3 with openvibe-shared 4.66.0: the mark with depth and motion, ov-fx loaded on request (2026-10-31); 1243.5 with openvibe-shared 4.64.0: the look travels between sites, the Look panel in the menu (2026-10-31); 1242.7 with openvibe-shared 4.59.0: the Pair mark beside the name, set in the brand face, and the ring on page moves (2026-10-31); 1238.8 with the home's featured stream once and the intro closed on phones (2026-10-31); 1237.4 with the home's two more tab blocks on phones (2026-10-30); 1233.9 with the home's Catch up tabs on phones (2026-10-30); 1230.8 with openvibe-shared 4.53.0: the footer's columns fold on phones (2026-10-30); 1227.8 with openvibe-shared 4.52.0: the Dock's loader and its Chats tab (2026-10-30); 1223.5 with openvibe-shared 4.48.0 (the site switcher on the mark, the menu's Start tab and quick tools; Kit's touch hit areas and the phone navbar fix, 4.44-4.47.3); 1215.4 with openvibe-shared 4.43.0 (room.css carries the kit tokens, 4.39.1; the kit's 4.39.0 rules); measured 1203.9 (2026-10-28: openvibe-shared 4.30.0, the bell center: tabs with counts, the Unread filter, thumbnails, swipe, the phone sheet; 4.31.0's ✦ adds about 3 KB); 1187.2 (2026-10-28: openvibe-shared 4.27.0, Notifications 2.0: opaque themed toasts held while a menu is open, grouping, priority, System cards and the rich bell panel); 1158.8 (2026-10-28: openvibe-shared 4.25.0, the menu's orb, messages, the phone sheet and auto-hide in the navbar; the messenger opens from the bar)jsBrotliKB: 293.3, // 292.6 openvibe-shared 4.70.0 (2026-11-01: the app bar, busy(), skeletons, view transitions); 291.1 with openvibe-shared 4.57.1 (the Dock's async token and scope-aware controls, 4.57.0; the tool frame's facts, 4.56.0) (2026-10-31); 290.6 with the home's two more tab blocks on phones (2026-10-30); 289.8 with the home's Catch up tabs on phones (2026-10-30); 288.2 with openvibe-shared 4.52.0: the Dock's loader and its Chats tab (2026-10-30); 287.4 with openvibe-shared 4.48.0 (the site switcher on the mark, the menu's Start tab and quick tools; Kit's touch hit areas and the phone navbar fix, 4.44-4.47.3); measured 283.2 (2026-10-28: openvibe-shared 4.30.0, the bell center as above); 279.6 (2026-10-28: openvibe-shared 4.27.0, Notifications 2.0 as above); 273.1 (2026-10-28: openvibe-shared 4.25.0 as above); 270.5 (2026-10-28: openvibe-shared 4.22.0, the navbar's search magnifier with / and Ctrl+K and the More menu; search.js and loading.js load only when used); 269.6 (2026-10-28: openvibe-shared 4.19.0, the account menu's gear and people-group icons inline; 268 on 2026-10-27: openvibe-shared 4.16.0, the folded balance chip, Across OpenVibe with site marks and the icon preload in the navbar); 265.3 (2026-10-27: openvibe-shared 4.15.0, the compact footer opens into the whole one, and the pulse line); 263.3 on 10-23 (openvibe-shared 4.9.0, status text twins in every theme); 262.5 on 10-17 (openvibe-shared 4.4.0, every site in the launcher)cssRawKB: 270, // measured ~243 since the first-paint subset (style.core.css) replaced style.css (~717 before)cssBrotliKB: 55, // measured ~47.5 (was ~130)
@@ -6,7 +6,8 @@
@@ -6,7 +6,8 @@
.cf-wrap {
.cf-wrap {
--cf-gap: 16px;
--cf-gap: 16px;
--cf-radius: 14px;
--cf-radius: 14px;
- --cf-ai: #a78bfa; /* AI text on dark surfaces */
+ /* AI text: the violet mixed with the theme's text, so it holds on light themes too (it read 2.5:1 on Daylight). */
+ --cf-ai: color-mix(in srgb, #a78bfa 62%, var(--text-primary, #e6edf7));
--cf-ai-2: #22d3ee;
--cf-ai-2: #22d3ee;
--cf-ai-fill: linear-gradient(135deg, #6d28d9, #0e7490); /* behind white text: 4.5:1 or better */
--cf-ai-fill: linear-gradient(135deg, #6d28d9, #0e7490); /* behind white text: 4.5:1 or better */
max-width: 1240px;
max-width: 1240px;
@@ -1138,7 +1138,7 @@ function queueFullscreenChatEntry(entry) {
@@ -1138,7 +1138,7 @@ function queueFullscreenChatEntry(entry) {
function buildFullscreenChatEntry(msg) {
function buildFullscreenChatEntry(msg) {
const badge = chatSettings.showBadges ? getBadgeHTML(msg.role) : '';
const badge = chatSettings.showBadges ? getBadgeHTML(msg.role) : '';
let nameColor = relayColorFor(msg) || msg.color || msg.profile_color || getRoleColor(msg.role);
let nameColor = relayColorFor(msg) || msg.color || msg.profile_color || getRoleColor(msg.role);
- if (chatSettings.readableColors) nameColor = ensureReadableColor(nameColor);
+ if (chatSettings.readableColors || _chatLightTheme()) nameColor = ensureReadableColor(nameColor);
const displayName = esc(msg.username || msg.displayName || `anon${msg.anonId || ''}`);
const displayName = esc(msg.username || msg.displayName || `anon${msg.anonId || ''}`);
const _relayPlatform = (msg.source_platform || parseRelayUsername(msg.username || msg.displayName || '').platform || '').toLowerCase();
const _relayPlatform = (msg.source_platform || parseRelayUsername(msg.username || msg.displayName || '').platform || '').toLowerCase();
const _relayBadge = relayBadgeHTML(_relayPlatform);
const _relayBadge = relayBadgeHTML(_relayPlatform);
@@ -2586,7 +2586,7 @@ function buildChatMessageEl(msg, opts = {}) {
@@ -2586,7 +2586,7 @@ function buildChatMessageEl(msg, opts = {}) {
const badge = chatSettings.showBadges ? getBadgeHTML(msg.role) : '';
const badge = chatSettings.showBadges ? getBadgeHTML(msg.role) : '';
let nameColor = relayColorFor(msg) || msg.color || msg.profile_color || getRoleColor(msg.role);
let nameColor = relayColorFor(msg) || msg.color || msg.profile_color || getRoleColor(msg.role);
// Readable colors — ensure minimum contrast against dark backgrounds
// Readable colors — ensure minimum contrast against dark backgrounds
- if (chatSettings.readableColors) nameColor = ensureReadableColor(nameColor);
+ if (chatSettings.readableColors || _chatLightTheme()) nameColor = ensureReadableColor(nameColor);
const displayName = esc(msg.username || msg.displayName || `anon${msg.anonId || ''}`);
const displayName = esc(msg.username || msg.displayName || `anon${msg.anonId || ''}`);
const coreUsername = esc(msg.core_username || '');
const coreUsername = esc(msg.core_username || '');
@@ -2906,7 +2906,7 @@ function addSystemMessage(text, isError = false) {
@@ -2906,7 +2906,7 @@ function addSystemMessage(text, isError = false) {
*/
*/
function getChatAvatarHTML(msg) {
function getChatAvatarHTML(msg) {
let nameColor = relayColorFor(msg) || msg.color || msg.profile_color || getRoleColor(msg.role);
let nameColor = relayColorFor(msg) || msg.color || msg.profile_color || getRoleColor(msg.role);
- if (chatSettings.readableColors) nameColor = ensureReadableColor(nameColor);
+ if (chatSettings.readableColors || _chatLightTheme()) nameColor = ensureReadableColor(nameColor);
// Strip any "[Twitch]/[Kick]/[RS]" relay prefix so the initial is the real letter.
// Strip any "[Twitch]/[Kick]/[RS]" relay prefix so the initial is the real letter.
const raw = (msg.username || msg.displayName || `anon${msg.anonId || ''}`).replace(/^\[[^\]]+\]\s*/, '');
const raw = (msg.username || msg.displayName || `anon${msg.anonId || ''}`).replace(/^\[[^\]]+\]\s*/, '');
const initial = esc((raw.charAt(0) || '?').toUpperCase());
const initial = esc((raw.charAt(0) || '?').toUpperCase());
@@ -2927,7 +2927,7 @@ function addGottiMessage(msg) {
@@ -2927,7 +2927,7 @@ function addGottiMessage(msg) {
const avatarHtml = getChatAvatarHTML(msg);
const avatarHtml = getChatAvatarHTML(msg);
const hatHtml = msg.hatFX?.emoji ? `<span class="chat-hat" aria-hidden="true">${esc(msg.hatFX.emoji)}</span>` : '';
const hatHtml = msg.hatFX?.emoji ? `<span class="chat-hat" aria-hidden="true">${esc(msg.hatFX.emoji)}</span>` : '';
let nameColor = relayColorFor(msg) || msg.color || msg.profile_color || getRoleColor(msg.role);
let nameColor = relayColorFor(msg) || msg.color || msg.profile_color || getRoleColor(msg.role);
- if (chatSettings.readableColors) nameColor = ensureReadableColor(nameColor);
+ if (chatSettings.readableColors || _chatLightTheme()) nameColor = ensureReadableColor(nameColor);
const displayName = esc(msg.username || msg.displayName || `anon${msg.anonId || ''}`);
const displayName = esc(msg.username || msg.displayName || `anon${msg.anonId || ''}`);
const coreUsername = esc(msg.core_username || '');
const coreUsername = esc(msg.core_username || '');
@@ -5203,7 +5203,7 @@ function _buildCrossfeedEl(msg) {
@@ -5203,7 +5203,7 @@ function _buildCrossfeedEl(msg) {
}
}
const badge = chatSettings.showBadges ? getBadgeHTML(msg.role) : '';
const badge = chatSettings.showBadges ? getBadgeHTML(msg.role) : '';
let nameColor = relayColorFor(msg) || msg.color || msg.profile_color || getRoleColor(msg.role);
let nameColor = relayColorFor(msg) || msg.color || msg.profile_color || getRoleColor(msg.role);
- if (chatSettings.readableColors) nameColor = ensureReadableColor(nameColor);
+ if (chatSettings.readableColors || _chatLightTheme()) nameColor = ensureReadableColor(nameColor);
const displayName = esc(msg.username || msg.displayName || `anon${msg.anonId || ''}`);
const displayName = esc(msg.username || msg.displayName || `anon${msg.anonId || ''}`);
const _relayPlatform = (msg.source_platform || parseRelayUsername(msg.username || msg.displayName || '').platform || '').toLowerCase();
const _relayPlatform = (msg.source_platform || parseRelayUsername(msg.username || msg.displayName || '').platform || '').toLowerCase();
const _relayBadge = relayBadgeHTML(_relayPlatform);
const _relayBadge = relayBadgeHTML(_relayPlatform);
@@ -5961,8 +5961,13 @@ function playMentionSound() {
@@ -5961,8 +5961,13 @@ function playMentionSound() {
} catch { }
} catch { }
}
}
+// A light theme (theme-loader sets data-theme-mode): pale name colours there vanish on white, so names are always made
+// readable, darkened rather than brightened (contrast probe, 2026-11-01: 1.56:1 for a pale name on Daylight).
+function _chatLightTheme() {
+ try { return document.documentElement.getAttribute('data-theme-mode') === 'light'; } catch { return false; }
+}
function ensureReadableColor(hex) {
function ensureReadableColor(hex) {
- // Ensure minimum luminance for dark backgrounds (target: 0.4 relative luminance)
+ // Dark themes: a minimum brightness (0.4). Light themes: a maximum (0.45), about 4.5:1 on white.
try {
try {
let r, g, b;
let r, g, b;
if (hex.startsWith('#')) {
if (hex.startsWith('#')) {
@@ -5974,6 +5979,12 @@ function ensureReadableColor(hex) {
@@ -5974,6 +5979,12 @@ function ensureReadableColor(hex) {
return hex;
return hex;
}
}
const lum = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
const lum = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
+ if (_chatLightTheme()) {
+ if (lum <= 0.45) return hex;
+ const k = 0.45 / lum;
+ r = Math.round(r * k); g = Math.round(g * k); b = Math.round(b * k);
+ return `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}`;
+ }
if (lum < 0.4) {
if (lum < 0.4) {
// Brighten the color while keeping the hue
// Brighten the color while keeping the hue
const boost = 0.4 / Math.max(lum, 0.01);
const boost = 0.4 / Math.max(lum, 0.01);
@@ -22,7 +22,7 @@ const BUDGETS = {
@@ -22,7 +22,7 @@ const BUDGETS = {
htmlRawKB: 128, // 119.3 with the icons drawn on the server (2026-11-01, plan L54 K4: the OpenVibe glyphs in the HTML, 20.8 KB brotli); measured 94.9 before
htmlRawKB: 128, // 119.3 with the icons drawn on the server (2026-11-01, plan L54 K4: the OpenVibe glyphs in the HTML, 20.8 KB brotli); measured 94.9 before
htmlBrotliKB: 30,
htmlBrotliKB: 30,
jsFiles: 26, // measured 23 (incl. route scripts for "/")
jsFiles: 26, // measured 23 (incl. route scripts for "/")
- jsRawKB: 1250, // 1247.7 openvibe-shared 4.70.0 (2026-11-01: the app bar, busy(), skeletons, view transitions); 1244.3 with openvibe-shared 4.66.0: the mark with depth and motion, ov-fx loaded on request (2026-10-31); 1243.5 with openvibe-shared 4.64.0: the look travels between sites, the Look panel in the menu (2026-10-31); 1242.7 with openvibe-shared 4.59.0: the Pair mark beside the name, set in the brand face, and the ring on page moves (2026-10-31); 1238.8 with the home's featured stream once and the intro closed on phones (2026-10-31); 1237.4 with the home's two more tab blocks on phones (2026-10-30); 1233.9 with the home's Catch up tabs on phones (2026-10-30); 1230.8 with openvibe-shared 4.53.0: the footer's columns fold on phones (2026-10-30); 1227.8 with openvibe-shared 4.52.0: the Dock's loader and its Chats tab (2026-10-30); 1223.5 with openvibe-shared 4.48.0 (the site switcher on the mark, the menu's Start tab and quick tools; Kit's touch hit areas and the phone navbar fix, 4.44-4.47.3); 1215.4 with openvibe-shared 4.43.0 (room.css carries the kit tokens, 4.39.1; the kit's 4.39.0 rules); measured 1203.9 (2026-10-28: openvibe-shared 4.30.0, the bell center: tabs with counts, the Unread filter, thumbnails, swipe, the phone sheet; 4.31.0's ✦ adds about 3 KB); 1187.2 (2026-10-28: openvibe-shared 4.27.0, Notifications 2.0: opaque themed toasts held while a menu is open, grouping, priority, System cards and the rich bell panel); 1158.8 (2026-10-28: openvibe-shared 4.25.0, the menu's orb, messages, the phone sheet and auto-hide in the navbar; the messenger opens from the bar)
+ jsRawKB: 1251, // 1250.2 (2026-11-01: topics live now, readable chat names on light themes); 1247.7 openvibe-shared 4.70.0 (2026-11-01: the app bar, busy(), skeletons, view transitions); 1244.3 with openvibe-shared 4.66.0: the mark with depth and motion, ov-fx loaded on request (2026-10-31); 1243.5 with openvibe-shared 4.64.0: the look travels between sites, the Look panel in the menu (2026-10-31); 1242.7 with openvibe-shared 4.59.0: the Pair mark beside the name, set in the brand face, and the ring on page moves (2026-10-31); 1238.8 with the home's featured stream once and the intro closed on phones (2026-10-31); 1237.4 with the home's two more tab blocks on phones (2026-10-30); 1233.9 with the home's Catch up tabs on phones (2026-10-30); 1230.8 with openvibe-shared 4.53.0: the footer's columns fold on phones (2026-10-30); 1227.8 with openvibe-shared 4.52.0: the Dock's loader and its Chats tab (2026-10-30); 1223.5 with openvibe-shared 4.48.0 (the site switcher on the mark, the menu's Start tab and quick tools; Kit's touch hit areas and the phone navbar fix, 4.44-4.47.3); 1215.4 with openvibe-shared 4.43.0 (room.css carries the kit tokens, 4.39.1; the kit's 4.39.0 rules); measured 1203.9 (2026-10-28: openvibe-shared 4.30.0, the bell center: tabs with counts, the Unread filter, thumbnails, swipe, the phone sheet; 4.31.0's ✦ adds about 3 KB); 1187.2 (2026-10-28: openvibe-shared 4.27.0, Notifications 2.0: opaque themed toasts held while a menu is open, grouping, priority, System cards and the rich bell panel); 1158.8 (2026-10-28: openvibe-shared 4.25.0, the menu's orb, messages, the phone sheet and auto-hide in the navbar; the messenger opens from the bar)
jsBrotliKB: 293.3, // 292.6 openvibe-shared 4.70.0 (2026-11-01: the app bar, busy(), skeletons, view transitions); 291.1 with openvibe-shared 4.57.1 (the Dock's async token and scope-aware controls, 4.57.0; the tool frame's facts, 4.56.0) (2026-10-31); 290.6 with the home's two more tab blocks on phones (2026-10-30); 289.8 with the home's Catch up tabs on phones (2026-10-30); 288.2 with openvibe-shared 4.52.0: the Dock's loader and its Chats tab (2026-10-30); 287.4 with openvibe-shared 4.48.0 (the site switcher on the mark, the menu's Start tab and quick tools; Kit's touch hit areas and the phone navbar fix, 4.44-4.47.3); measured 283.2 (2026-10-28: openvibe-shared 4.30.0, the bell center as above); 279.6 (2026-10-28: openvibe-shared 4.27.0, Notifications 2.0 as above); 273.1 (2026-10-28: openvibe-shared 4.25.0 as above); 270.5 (2026-10-28: openvibe-shared 4.22.0, the navbar's search magnifier with / and Ctrl+K and the More menu; search.js and loading.js load only when used); 269.6 (2026-10-28: openvibe-shared 4.19.0, the account menu's gear and people-group icons inline; 268 on 2026-10-27: openvibe-shared 4.16.0, the folded balance chip, Across OpenVibe with site marks and the icon preload in the navbar); 265.3 (2026-10-27: openvibe-shared 4.15.0, the compact footer opens into the whole one, and the pulse line); 263.3 on 10-23 (openvibe-shared 4.9.0, status text twins in every theme); 262.5 on 10-17 (openvibe-shared 4.4.0, every site in the launcher)
jsBrotliKB: 293.3, // 292.6 openvibe-shared 4.70.0 (2026-11-01: the app bar, busy(), skeletons, view transitions); 291.1 with openvibe-shared 4.57.1 (the Dock's async token and scope-aware controls, 4.57.0; the tool frame's facts, 4.56.0) (2026-10-31); 290.6 with the home's two more tab blocks on phones (2026-10-30); 289.8 with the home's Catch up tabs on phones (2026-10-30); 288.2 with openvibe-shared 4.52.0: the Dock's loader and its Chats tab (2026-10-30); 287.4 with openvibe-shared 4.48.0 (the site switcher on the mark, the menu's Start tab and quick tools; Kit's touch hit areas and the phone navbar fix, 4.44-4.47.3); measured 283.2 (2026-10-28: openvibe-shared 4.30.0, the bell center as above); 279.6 (2026-10-28: openvibe-shared 4.27.0, Notifications 2.0 as above); 273.1 (2026-10-28: openvibe-shared 4.25.0 as above); 270.5 (2026-10-28: openvibe-shared 4.22.0, the navbar's search magnifier with / and Ctrl+K and the More menu; search.js and loading.js load only when used); 269.6 (2026-10-28: openvibe-shared 4.19.0, the account menu's gear and people-group icons inline; 268 on 2026-10-27: openvibe-shared 4.16.0, the folded balance chip, Across OpenVibe with site marks and the icon preload in the navbar); 265.3 (2026-10-27: openvibe-shared 4.15.0, the compact footer opens into the whole one, and the pulse line); 263.3 on 10-23 (openvibe-shared 4.9.0, status text twins in every theme); 262.5 on 10-17 (openvibe-shared 4.4.0, every site in the launcher)
cssRawKB: 270, // measured ~243 since the first-paint subset (style.core.css) replaced style.css (~717 before)
cssRawKB: 270, // measured ~243 since the first-paint subset (style.core.css) replaced style.css (~717 before)
cssBrotliKB: 55, // measured ~47.5 (was ~130)
cssBrotliKB: 55, // measured ~47.5 (was ~130)