diff --git a/content/keyboard.js b/content/keyboard.js
index 04a9f2c..330581a 100644
--- a/content/keyboard.js
+++ b/content/keyboard.js
@@ -1,6 +1,9 @@
// Outlook Relook — Gmail-Style Keyboard Navigation & Multi-Select
// Adds keyboard focus cursor and multi-select to OWA's message list.
// Gated by the keyboardMultiSelect setting.
+//
+// Tracks selections by stable message ID (data attribute or aria-label)
+// rather than DOM element reference, since OWA frequently re-renders rows.
window.OutlookRelook = window.OutlookRelook || {};
@@ -11,26 +14,42 @@ window.OutlookRelook.Keyboard = (function () {
var currentSettings = {};
var cleanupFns = [];
- // State
- var focusedIndex = -1; // Index of the focused message in the list
- var selectedSet = new Set(); // Set of selected message DOM elements
- var countBadge = null; // Selection count badge element
+ // State — track by ID strings, not DOM references
+ var focusedId = null; // ID of the focused message
+ var selectedIds = new Set(); // Set of selected message IDs
+ var countBadge = null;
- // --- Helpers ---
+ // --- Message ID extraction ---
+ // OWA messages have various attributes we can use as stable IDs.
+ // Try data-convid, data-itemid, id, or fall back to aria-label.
+
+ function getMessageId(el) {
+ return el.getAttribute('data-convid')
+ || el.getAttribute('data-itemid')
+ || el.getAttribute('data-tid')
+ || el.getAttribute('id')
+ || el.getAttribute('aria-label')
+ || null;
+ }
function getMessageItems() {
- // Get all message items from the message list
var items = document.querySelectorAll(
'[role="listbox"] [role="option"], [role="list"] [role="listitem"]'
);
return Array.from(items);
}
+ function findItemById(items, id) {
+ if (!id) return -1;
+ for (var i = 0; i < items.length; i++) {
+ if (getMessageId(items[i]) === id) return i;
+ }
+ return -1;
+ }
+
function isComposeOrDialogActive() {
var active = document.activeElement;
if (!active) return false;
-
- // Check if focus is in a compose area, search bar, or dialog
var tag = active.tagName.toLowerCase();
if (tag === 'input' || tag === 'textarea') return true;
if (active.getAttribute('contenteditable') === 'true') return true;
@@ -38,53 +57,90 @@ window.OutlookRelook.Keyboard = (function () {
if (active.closest('[role="search"]')) return true;
if (active.closest('[aria-label*="compose" i]')) return true;
if (active.closest('[aria-label*="New message" i]')) return true;
-
return false;
}
- function setFocus(items, index) {
- // Remove old focus
- var oldFocused = document.querySelector('.or-kb-focused');
- if (oldFocused) oldFocused.classList.remove('or-kb-focused');
+ // --- Visual state application ---
+ // Re-applies focus and selection classes to current DOM elements
+ // based on the ID-based state. Called after every key action and
+ // by the MutationObserver when OWA re-renders.
- if (index < 0 || index >= items.length) return;
+ function applyVisualState(items) {
+ // Clear all visual markers first
+ var oldFocused = document.querySelectorAll('.or-kb-focused');
+ for (var f = 0; f < oldFocused.length; f++) oldFocused[f].classList.remove('or-kb-focused');
+ var oldSelected = document.querySelectorAll('.or-kb-selected');
+ for (var s = 0; s < oldSelected.length; s++) oldSelected[s].classList.remove('or-kb-selected');
- focusedIndex = index;
- var item = items[index];
- item.classList.add('or-kb-focused');
+ if (!items) items = getMessageItems();
- // Scroll into view if needed
- item.scrollIntoView({ block: 'nearest', behavior: 'smooth' });
- }
-
- function toggleSelect(item) {
- if (selectedSet.has(item)) {
- selectedSet.delete(item);
- item.classList.remove('or-kb-selected');
- } else {
- selectedSet.add(item);
- item.classList.add('or-kb-selected');
+ // Apply focus
+ if (focusedId) {
+ var focusIdx = findItemById(items, focusedId);
+ if (focusIdx >= 0) {
+ items[focusIdx].classList.add('or-kb-focused');
+ }
}
+
+ // Apply selections
+ selectedIds.forEach(function (id) {
+ var idx = findItemById(items, id);
+ if (idx >= 0) {
+ items[idx].classList.add('or-kb-selected');
+ }
+ });
+
updateCountBadge();
}
+ // --- Focus management ---
+
+ function getFocusedIndex(items) {
+ if (!focusedId) return -1;
+ return findItemById(items, focusedId);
+ }
+
+ function setFocus(items, index) {
+ if (index < 0 || index >= items.length) return;
+ focusedId = getMessageId(items[index]);
+ applyVisualState(items);
+ items[index].scrollIntoView({ block: 'nearest', behavior: 'smooth' });
+ }
+
+ // --- Selection management ---
+
+ function toggleSelect(items, index) {
+ if (index < 0 || index >= items.length) return;
+ var id = getMessageId(items[index]);
+ if (!id) return;
+
+ if (selectedIds.has(id)) {
+ selectedIds.delete(id);
+ } else {
+ selectedIds.add(id);
+ }
+ applyVisualState(items);
+ }
+
function clearSelection() {
- selectedSet.forEach(function (item) {
- item.classList.remove('or-kb-selected');
- });
- selectedSet.clear();
+ selectedIds.clear();
+ var oldSelected = document.querySelectorAll('.or-kb-selected');
+ for (var i = 0; i < oldSelected.length; i++) oldSelected[i].classList.remove('or-kb-selected');
updateCountBadge();
}
function getActionTargets(items) {
- // If messages are selected, return those. Otherwise return the focused message.
- if (selectedSet.size > 0) {
- return Array.from(selectedSet);
+ var targets = [];
+ if (selectedIds.size > 0) {
+ selectedIds.forEach(function (id) {
+ var idx = findItemById(items, id);
+ if (idx >= 0) targets.push(items[idx]);
+ });
+ } else {
+ var fi = getFocusedIndex(items);
+ if (fi >= 0) targets.push(items[fi]);
}
- if (focusedIndex >= 0 && focusedIndex < items.length) {
- return [items[focusedIndex]];
- }
- return [];
+ return targets;
}
// --- Selection count badge ---
@@ -101,7 +157,7 @@ window.OutlookRelook.Keyboard = (function () {
function updateCountBadge() {
if (!countBadge) countBadge = createCountBadge();
if (!countBadge) return;
- var count = selectedSet.size;
+ var count = selectedIds.size;
if (count === 0) {
countBadge.style.opacity = '0';
} else {
@@ -111,30 +167,20 @@ window.OutlookRelook.Keyboard = (function () {
}
// --- Actions ---
- // Each action simulates what a user would do in OWA to perform the operation.
- // We click the message to select it in OWA, then trigger the toolbar action.
function performAction(targets, actionFn) {
if (targets.length === 0) return;
-
- // Process targets one at a time with a small delay between each
var i = 0;
function processNext() {
if (i >= targets.length) {
- // After all targets processed, clear selection
clearSelection();
return;
}
var target = targets[i];
i++;
-
- // Click the message to make it OWA-selected
target.click();
-
- // Small delay to let OWA register the selection, then perform action
setTimeout(function () {
actionFn(target);
- // Delay before next target
setTimeout(processNext, 150);
}, 100);
}
@@ -143,19 +189,14 @@ window.OutlookRelook.Keyboard = (function () {
function actionDelete(targets) {
performAction(targets, function () {
- // Find and click the delete button in the toolbar
var deleteBtn = document.querySelector(
'[aria-label*="Delete" i][role="button"], [aria-label*="delete" i][role="menuitem"]'
);
if (deleteBtn) {
deleteBtn.click();
} else {
- // Fallback: try dispatching Delete key
var deleteEvent = new KeyboardEvent('keydown', {
- key: 'Delete',
- code: 'Delete',
- bubbles: true,
- cancelable: true
+ key: 'Delete', code: 'Delete', bubbles: true, cancelable: true
});
document.activeElement.dispatchEvent(deleteEvent);
}
@@ -183,7 +224,6 @@ window.OutlookRelook.Keyboard = (function () {
if (readBtn) {
readBtn.click();
} else {
- // Try context menu approach
triggerContextMenuAction(/mark as read/i);
}
});
@@ -203,11 +243,8 @@ window.OutlookRelook.Keyboard = (function () {
}
function actionMove(targets) {
- // For move, we just need to trigger OWA's move dialog on the current selection
if (targets.length > 0) {
- // Click the first target to ensure something is selected
targets[0].click();
-
setTimeout(function () {
var moveBtn = document.querySelector(
'[aria-label*="Move to" i][role="button"], [aria-label*="Move" i][role="menuitem"]'
@@ -222,19 +259,14 @@ window.OutlookRelook.Keyboard = (function () {
}
function triggerContextMenuAction(pattern) {
- // Open context menu on the focused/selected element
var focused = document.querySelector('.or-kb-focused');
if (!focused) return;
-
var rect = focused.getBoundingClientRect();
var contextEvent = new MouseEvent('contextmenu', {
- bubbles: true,
- cancelable: true,
- clientX: rect.x + 10,
- clientY: rect.y + 10,
+ bubbles: true, cancelable: true,
+ clientX: rect.x + 10, clientY: rect.y + 10,
});
focused.dispatchEvent(contextEvent);
-
setTimeout(function () {
var menuItems = document.querySelectorAll('[role="menuitem"]');
for (var j = 0; j < menuItems.length; j++) {
@@ -243,7 +275,6 @@ window.OutlookRelook.Keyboard = (function () {
return;
}
}
- // Close context menu if not found
document.body.click();
}, 300);
}
@@ -251,7 +282,6 @@ window.OutlookRelook.Keyboard = (function () {
// --- Key handler ---
function handleKeydown(e) {
- // Skip if keyboard mode is off or compose/dialog is active
if (!currentSettings.keyboardMultiSelect) return;
if (isComposeOrDialogActive()) return;
@@ -262,15 +292,21 @@ window.OutlookRelook.Keyboard = (function () {
var shift = e.shiftKey;
// Initialize focus if not set
- if (focusedIndex < 0 || focusedIndex >= items.length) {
- // Find the currently OWA-selected item, or start at 0
+ var currentIdx = getFocusedIndex(items);
+ if (currentIdx < 0) {
for (var f = 0; f < items.length; f++) {
- if (items[f].getAttribute('aria-selected') === 'true') {
- focusedIndex = f;
+ if (items[f].getAttribute('aria-selected') === 'true' ||
+ items[f].classList.contains('is-selected')) {
+ currentIdx = f;
+ focusedId = getMessageId(items[f]);
break;
}
}
- if (focusedIndex < 0) focusedIndex = 0;
+ if (currentIdx < 0) {
+ currentIdx = 0;
+ focusedId = getMessageId(items[0]);
+ }
+ applyVisualState(items);
}
var handled = true;
@@ -280,19 +316,14 @@ window.OutlookRelook.Keyboard = (function () {
case 'j':
case 'ArrowDown':
if (shift) {
- // Select current and move down
- if (focusedIndex >= 0 && focusedIndex < items.length) {
- if (!selectedSet.has(items[focusedIndex])) {
- toggleSelect(items[focusedIndex]);
- }
- }
- if (focusedIndex < items.length - 1) {
- setFocus(items, focusedIndex + 1);
- toggleSelect(items[focusedIndex]);
+ toggleSelect(items, currentIdx);
+ if (currentIdx < items.length - 1) {
+ setFocus(items, currentIdx + 1);
+ toggleSelect(items, currentIdx + 1);
}
} else {
- if (focusedIndex < items.length - 1) {
- setFocus(items, focusedIndex + 1);
+ if (currentIdx < items.length - 1) {
+ setFocus(items, currentIdx + 1);
}
}
break;
@@ -300,46 +331,35 @@ window.OutlookRelook.Keyboard = (function () {
case 'k':
case 'ArrowUp':
if (shift) {
- // Select current and move up
- if (focusedIndex >= 0 && focusedIndex < items.length) {
- if (!selectedSet.has(items[focusedIndex])) {
- toggleSelect(items[focusedIndex]);
- }
- }
- if (focusedIndex > 0) {
- setFocus(items, focusedIndex - 1);
- toggleSelect(items[focusedIndex]);
+ toggleSelect(items, currentIdx);
+ if (currentIdx > 0) {
+ setFocus(items, currentIdx - 1);
+ toggleSelect(items, currentIdx - 1);
}
} else {
- if (focusedIndex > 0) {
- setFocus(items, focusedIndex - 1);
+ if (currentIdx > 0) {
+ setFocus(items, currentIdx - 1);
}
}
break;
case 'x':
case ' ':
- // Toggle select on focused message
- e.preventDefault(); // Prevent page scroll on Space
- if (focusedIndex >= 0 && focusedIndex < items.length) {
- toggleSelect(items[focusedIndex]);
- }
+ e.preventDefault();
+ toggleSelect(items, currentIdx);
break;
case '#':
- // Delete selected/focused messages
targets = getActionTargets(items);
actionDelete(targets);
break;
case 'e':
- // Archive selected/focused messages
targets = getActionTargets(items);
actionArchive(targets);
break;
case 'I':
- // Shift+i — Mark as read
if (shift) {
targets = getActionTargets(items);
actionMarkRead(targets);
@@ -349,7 +369,6 @@ window.OutlookRelook.Keyboard = (function () {
break;
case 'U':
- // Shift+u — Mark as unread
if (shift) {
targets = getActionTargets(items);
actionMarkUnread(targets);
@@ -359,21 +378,18 @@ window.OutlookRelook.Keyboard = (function () {
break;
case 'v':
- // Move selected messages
targets = getActionTargets(items);
actionMove(targets);
break;
case 'Escape':
- // Deselect all
clearSelection();
break;
case 'Enter':
case 'o':
- // Open focused message in reading pane
- if (focusedIndex >= 0 && focusedIndex < items.length) {
- items[focusedIndex].click();
+ if (currentIdx >= 0 && currentIdx < items.length) {
+ items[currentIdx].click();
}
break;
@@ -383,33 +399,32 @@ window.OutlookRelook.Keyboard = (function () {
if (handled) {
e.stopPropagation();
- // Only preventDefault for keys we handle (except Enter which OWA should also process)
if (key !== 'Enter' && key !== 'o') {
e.preventDefault();
}
}
}
- // --- Cleanup stale selections when message list re-renders ---
+ // --- Re-apply visual state when OWA re-renders the message list ---
function setupListObserver() {
var listObserver = new MutationObserver(function () {
- // Remove stale entries from selectedSet (elements no longer in DOM)
- selectedSet.forEach(function (item) {
- if (!document.contains(item)) {
- selectedSet.delete(item);
- }
- });
- updateCountBadge();
-
- // Reset focusedIndex if the focused item is gone
- var focusedEl = document.querySelector('.or-kb-focused');
- if (!focusedEl || !document.contains(focusedEl)) {
- focusedIndex = -1;
+ // Prune IDs that no longer exist in DOM
+ var items = getMessageItems();
+ var currentIds = new Set();
+ for (var i = 0; i < items.length; i++) {
+ var id = getMessageId(items[i]);
+ if (id) currentIds.add(id);
}
+ selectedIds.forEach(function (id) {
+ if (!currentIds.has(id)) selectedIds.delete(id);
+ });
+ if (focusedId && !currentIds.has(focusedId)) focusedId = null;
+
+ // Re-apply classes to new DOM elements
+ applyVisualState(items);
});
- // Watch the message list container for child changes
var checkInterval = setInterval(function () {
var list = document.querySelector('[role="listbox"], [role="list"]');
if (list) {
@@ -444,7 +459,6 @@ window.OutlookRelook.Keyboard = (function () {
var isEnabled = settings.keyboardMultiSelect;
currentSettings = settings;
- // Only tear down and restart if the keyboard setting itself changed
if (wasEnabled !== isEnabled) {
stop();
start(settings);
@@ -457,11 +471,10 @@ window.OutlookRelook.Keyboard = (function () {
}
cleanupFns = [];
- // Clean up DOM state
clearSelection();
var focused = document.querySelector('.or-kb-focused');
if (focused) focused.classList.remove('or-kb-focused');
- focusedIndex = -1;
+ focusedId = null;
if (countBadge) {
countBadge.remove();
diff --git a/popup/popup.html b/popup/popup.html
index ec8cf44..eaf0bf5 100644
--- a/popup/popup.html
+++ b/popup/popup.html
@@ -20,6 +20,7 @@
diff --git a/themes/brutalist.css b/themes/brutalist.css
new file mode 100644
index 0000000..86e1ee7
--- /dev/null
+++ b/themes/brutalist.css
@@ -0,0 +1,253 @@
+/*
+ * Outlook Relook — Brutalist Theme
+ * Stark minimalism. Monospace. Borders only, almost no fills.
+ * High contrast. Maximum information density. No comfort.
+ * Inspired by terminal UIs, tax forms, and concrete architecture.
+ */
+
+/* ============================================================
+ LIGHT VARIANT
+ ============================================================ */
+html[data-outlook-relook-scheme="light"] {
+ --or-bg-primary: #ffffff;
+ --or-bg-secondary: #ffffff;
+ --or-bg-tertiary: #ffffff;
+ --or-bg-hover: transparent;
+ --or-bg-selected: transparent;
+ --or-text-primary: #000000;
+ --or-text-secondary: #000000;
+ --or-text-tertiary: #555555;
+ --or-text-disabled: #999999;
+ --or-border: #000000;
+ --or-border-light: #000000;
+ --or-accent: var(--or-accent-override, #000000);
+ --or-accent-hover: var(--or-accent-override, #333333);
+ --or-shadow: none;
+}
+
+/* ============================================================
+ DARK VARIANT
+ ============================================================ */
+html[data-outlook-relook-scheme="dark"] {
+ --or-bg-primary: #000000;
+ --or-bg-secondary: #000000;
+ --or-bg-tertiary: #000000;
+ --or-bg-hover: transparent;
+ --or-bg-selected: transparent;
+ --or-text-primary: #ffffff;
+ --or-text-secondary: #ffffff;
+ --or-text-tertiary: #aaaaaa;
+ --or-text-disabled: #555555;
+ --or-border: #ffffff;
+ --or-border-light: #ffffff;
+ --or-accent: var(--or-accent-override, #ffffff);
+ --or-accent-hover: var(--or-accent-override, #cccccc);
+ --or-shadow: none;
+}
+
+/* ============================================================
+ TYPOGRAPHY — Monospace, tight, utilitarian
+ ============================================================ */
+html[data-outlook-relook-scheme] *,
+html[data-outlook-relook-scheme] *::before,
+html[data-outlook-relook-scheme] *::after {
+ font-family: 'SF Mono', 'Menlo', 'Monaco', 'Consolas', 'Liberation Mono', monospace !important;
+ letter-spacing: -0.03em !important;
+ -webkit-font-smoothing: none !important;
+ font-smooth: never !important;
+}
+
+html[data-outlook-relook-scheme] body {
+ font-size: 12px !important;
+}
+
+/* ============================================================
+ STRIP EVERYTHING — more aggressive than Swiss
+ ============================================================ */
+html[data-outlook-relook-scheme] * {
+ border-radius: 0 !important;
+ text-shadow: none !important;
+ box-shadow: none !important;
+ background-image: none !important;
+ transition: none !important;
+ animation: none !important;
+}
+
+/* ============================================================
+ SURFACES — pure white/black, no distinction between panes
+ ============================================================ */
+html[data-outlook-relook-scheme] body {
+ background-color: var(--or-bg-primary) !important;
+ color: var(--or-text-primary) !important;
+}
+
+/* Top bar — just a bottom border */
+html[data-outlook-relook-scheme] [role="banner"],
+html[data-outlook-relook-scheme] header {
+ background-color: var(--or-bg-primary) !important;
+ border-bottom: 2px solid var(--or-border) !important;
+}
+
+/* Folder pane — border only, no background change */
+html[data-outlook-relook-scheme] [role="navigation"],
+html[data-outlook-relook-scheme] [role="complementary"] {
+ background-color: var(--or-bg-primary) !important;
+ border-right: 2px solid var(--or-border) !important;
+}
+
+/* Message list — no background */
+html[data-outlook-relook-scheme] [role="listbox"],
+html[data-outlook-relook-scheme] [role="list"] {
+ background-color: var(--or-bg-primary) !important;
+}
+
+/* Message list items — borders only, no fills */
+html[data-outlook-relook-scheme] [role="option"],
+html[data-outlook-relook-scheme] [role="listitem"] {
+ background-color: transparent !important;
+ border-bottom: 1px solid var(--or-border) !important;
+ color: var(--or-text-primary) !important;
+ padding: 3px 8px !important;
+}
+
+/* Hover: invert colors instead of fill */
+html[data-outlook-relook-scheme="light"] [role="option"]:hover,
+html[data-outlook-relook-scheme="light"] [role="listitem"]:hover {
+ background-color: #000000 !important;
+ color: #ffffff !important;
+}
+
+html[data-outlook-relook-scheme="dark"] [role="option"]:hover,
+html[data-outlook-relook-scheme="dark"] [role="listitem"]:hover {
+ background-color: #ffffff !important;
+ color: #000000 !important;
+}
+
+/* Selected: invert */
+html[data-outlook-relook-scheme="light"] [role="option"][aria-selected="true"],
+html[data-outlook-relook-scheme="light"] [role="listitem"][aria-selected="true"] {
+ background-color: #000000 !important;
+ color: #ffffff !important;
+}
+
+html[data-outlook-relook-scheme="dark"] [role="option"][aria-selected="true"],
+html[data-outlook-relook-scheme="dark"] [role="listitem"][aria-selected="true"] {
+ background-color: #ffffff !important;
+ color: #000000 !important;
+}
+
+/* Reading pane */
+html[data-outlook-relook-scheme] [role="main"] {
+ background-color: var(--or-bg-primary) !important;
+}
+
+/* ============================================================
+ TOOLBAR — stark, no visual weight
+ ============================================================ */
+html[data-outlook-relook-scheme] [role="toolbar"] {
+ background-color: var(--or-bg-primary) !important;
+ border-bottom: 1px solid var(--or-border) !important;
+}
+
+html[data-outlook-relook-scheme] [role="toolbar"] button,
+html[data-outlook-relook-scheme] [role="toolbar"] [role="button"] {
+ background-color: transparent !important;
+ border: 1px solid transparent !important;
+ color: var(--or-text-primary) !important;
+ text-transform: uppercase !important;
+ font-size: 10px !important;
+ letter-spacing: 0.05em !important;
+}
+
+html[data-outlook-relook-scheme] [role="toolbar"] button:hover,
+html[data-outlook-relook-scheme] [role="toolbar"] [role="button"]:hover {
+ border-color: var(--or-border) !important;
+ background-color: transparent !important;
+}
+
+/* ============================================================
+ BUTTONS — outlined only, never filled
+ ============================================================ */
+html[data-outlook-relook-scheme] button,
+html[data-outlook-relook-scheme] [role="button"] {
+ background-color: transparent !important;
+ color: var(--or-text-primary) !important;
+ border: 1px solid transparent !important;
+}
+
+html[data-outlook-relook-scheme] button:hover,
+html[data-outlook-relook-scheme] [role="button"]:hover {
+ border-color: var(--or-border) !important;
+}
+
+/* Links: same color as text, underlined */
+html[data-outlook-relook-scheme] a {
+ color: var(--or-text-primary) !important;
+ text-decoration: underline !important;
+}
+
+html[data-outlook-relook-scheme] a:hover {
+ text-decoration: none !important;
+}
+
+/* ============================================================
+ FOLDER PANE — all caps, no fills
+ ============================================================ */
+html[data-outlook-relook-scheme] [role="treeitem"] {
+ color: var(--or-text-primary) !important;
+ background-color: transparent !important;
+ text-transform: uppercase !important;
+ font-size: 10px !important;
+ letter-spacing: 0.06em !important;
+ border-bottom: 1px solid var(--or-border-light) !important;
+}
+
+html[data-outlook-relook-scheme] [role="treeitem"]:hover {
+ text-decoration: underline !important;
+ background-color: transparent !important;
+}
+
+html[data-outlook-relook-scheme] [role="treeitem"][aria-selected="true"] {
+ font-weight: 900 !important;
+ background-color: transparent !important;
+}
+
+/* ============================================================
+ SECONDARY TEXT
+ ============================================================ */
+html[data-outlook-relook-scheme] [role="option"] span,
+html[data-outlook-relook-scheme] [role="listitem"] span {
+ color: var(--or-text-tertiary) !important;
+ font-size: 11px !important;
+}
+
+html[data-outlook-relook-scheme] time {
+ color: var(--or-text-tertiary) !important;
+ font-size: 10px !important;
+ text-transform: uppercase !important;
+}
+
+/* ============================================================
+ DIALOGS — bordered box, no fill
+ ============================================================ */
+html[data-outlook-relook-scheme] [role="dialog"],
+html[data-outlook-relook-scheme] [role="alertdialog"] {
+ background-color: var(--or-bg-primary) !important;
+ border: 2px solid var(--or-border) !important;
+}
+
+/* ============================================================
+ SCROLLBARS — hairline
+ ============================================================ */
+html[data-outlook-relook-scheme] ::-webkit-scrollbar {
+ width: 2px !important;
+ height: 2px !important;
+}
+
+html[data-outlook-relook-scheme] ::-webkit-scrollbar-track {
+ background: transparent !important;
+}
+
+html[data-outlook-relook-scheme] ::-webkit-scrollbar-thumb {
+ background: var(--or-text-primary) !important;
+}
diff --git a/themes/swiss.css b/themes/swiss.css
index 71b58ea..a2fe681 100644
--- a/themes/swiss.css
+++ b/themes/swiss.css
@@ -1,6 +1,8 @@
/*
* Outlook Relook — Swiss / Helvetica Theme
- * Monochrome, tight grid, no decoration. Content density is king.
+ * Ruthlessly minimal. Black, white, grey, accent. Nothing else.
+ * Helvetica Neue everywhere. Zero decoration. Grid discipline.
+ * If an element doesn't serve the content, it should be invisible.
*/
/* ============================================================
@@ -8,18 +10,18 @@
============================================================ */
html[data-outlook-relook-scheme="light"] {
--or-bg-primary: #ffffff;
- --or-bg-secondary: #fafafa;
- --or-bg-tertiary: #f0f0f0;
- --or-bg-hover: #e8e8e8;
- --or-bg-selected: #e0e0e0;
+ --or-bg-secondary: #ffffff;
+ --or-bg-tertiary: #f7f7f7;
+ --or-bg-hover: #f0f0f0;
+ --or-bg-selected: #f0f0f0;
--or-text-primary: #000000;
- --or-text-secondary: #333333;
- --or-text-tertiary: #666666;
- --or-text-disabled: #999999;
- --or-border: #d0d0d0;
- --or-border-light: #e5e5e5;
- --or-accent: var(--or-accent-override, #000000);
- --or-accent-hover: var(--or-accent-override, #333333);
+ --or-text-secondary: #555555;
+ --or-text-tertiary: #888888;
+ --or-text-disabled: #bbbbbb;
+ --or-border: #000000;
+ --or-border-light: #e0e0e0;
+ --or-accent: var(--or-accent-override, #ff0000);
+ --or-accent-hover: var(--or-accent-override, #cc0000);
--or-shadow: none;
}
@@ -27,71 +29,86 @@ html[data-outlook-relook-scheme="light"] {
DARK VARIANT
============================================================ */
html[data-outlook-relook-scheme="dark"] {
- --or-bg-primary: #1a1a1a;
- --or-bg-secondary: #222222;
- --or-bg-tertiary: #2a2a2a;
- --or-bg-hover: #333333;
- --or-bg-selected: #3a3a3a;
- --or-text-primary: #e8e8e8;
- --or-text-secondary: #cccccc;
- --or-text-tertiary: #999999;
- --or-text-disabled: #666666;
- --or-border: #3a3a3a;
- --or-border-light: #2f2f2f;
- --or-accent: var(--or-accent-override, #e8e8e8);
- --or-accent-hover: var(--or-accent-override, #ffffff);
+ --or-bg-primary: #0a0a0a;
+ --or-bg-secondary: #0a0a0a;
+ --or-bg-tertiary: #141414;
+ --or-bg-hover: #1a1a1a;
+ --or-bg-selected: #1a1a1a;
+ --or-text-primary: #ffffff;
+ --or-text-secondary: #aaaaaa;
+ --or-text-tertiary: #666666;
+ --or-text-disabled: #444444;
+ --or-border: #ffffff;
+ --or-border-light: #222222;
+ --or-accent: var(--or-accent-override, #ff3333);
+ --or-accent-hover: var(--or-accent-override, #ff6666);
--or-shadow: none;
}
/* ============================================================
- TYPOGRAPHY
+ TYPOGRAPHY — Helvetica Neue, aggressively applied
============================================================ */
-html[data-outlook-relook-scheme] body,
-html[data-outlook-relook-scheme] [role="main"],
-html[data-outlook-relook-scheme] [role="navigation"],
-html[data-outlook-relook-scheme] [role="complementary"],
-html[data-outlook-relook-scheme] [role="banner"],
-html[data-outlook-relook-scheme] input,
-html[data-outlook-relook-scheme] button,
-html[data-outlook-relook-scheme] select,
-html[data-outlook-relook-scheme] textarea {
+html[data-outlook-relook-scheme] *,
+html[data-outlook-relook-scheme] *::before,
+html[data-outlook-relook-scheme] *::after {
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif !important;
- letter-spacing: -0.01em !important;
+ letter-spacing: -0.02em !important;
+ -webkit-font-smoothing: antialiased !important;
+ -moz-osx-font-smoothing: grayscale !important;
}
/* ============================================================
- SURFACES & BACKGROUNDS
+ STRIP ALL DECORATION — the core Swiss principle
+ ============================================================ */
+html[data-outlook-relook-scheme] * {
+ border-radius: 0 !important;
+ text-shadow: none !important;
+ box-shadow: none !important;
+ background-image: none !important;
+ text-decoration-color: var(--or-text-primary) !important;
+ outline-color: var(--or-accent) !important;
+}
+
+/* Remove ALL gradients, transitions, and transforms from non-essential elements */
+html[data-outlook-relook-scheme] button,
+html[data-outlook-relook-scheme] [role="button"],
+html[data-outlook-relook-scheme] [role="tab"],
+html[data-outlook-relook-scheme] [role="menuitem"],
+html[data-outlook-relook-scheme] [role="option"],
+html[data-outlook-relook-scheme] [role="listitem"],
+html[data-outlook-relook-scheme] [role="treeitem"] {
+ transition: none !important;
+ animation: none !important;
+}
+
+/* ============================================================
+ SURFACES — flatten everything to white (or black in dark)
============================================================ */
html[data-outlook-relook-scheme] body {
background-color: var(--or-bg-primary) !important;
color: var(--or-text-primary) !important;
}
-/* Top bar */
html[data-outlook-relook-scheme] [role="banner"],
html[data-outlook-relook-scheme] header {
background-color: var(--or-bg-primary) !important;
border-bottom: 1px solid var(--or-border) !important;
- box-shadow: var(--or-shadow) !important;
}
-/* Folder pane */
html[data-outlook-relook-scheme] [role="navigation"],
html[data-outlook-relook-scheme] [role="complementary"] {
- background-color: var(--or-bg-secondary) !important;
+ background-color: var(--or-bg-primary) !important;
border-right: 1px solid var(--or-border-light) !important;
}
-/* Message list */
html[data-outlook-relook-scheme] [role="listbox"],
html[data-outlook-relook-scheme] [role="list"] {
background-color: var(--or-bg-primary) !important;
}
-/* Message list items */
html[data-outlook-relook-scheme] [role="option"],
html[data-outlook-relook-scheme] [role="listitem"] {
- background-color: var(--or-bg-primary) !important;
+ background-color: transparent !important;
border-bottom: 1px solid var(--or-border-light) !important;
color: var(--or-text-primary) !important;
}
@@ -104,74 +121,81 @@ html[data-outlook-relook-scheme] [role="listitem"]:hover {
html[data-outlook-relook-scheme] [role="option"][aria-selected="true"],
html[data-outlook-relook-scheme] [role="listitem"][aria-selected="true"] {
background-color: var(--or-bg-selected) !important;
+ border-left: 3px solid var(--or-accent) !important;
}
-/* Reading pane */
html[data-outlook-relook-scheme] [role="main"] {
background-color: var(--or-bg-primary) !important;
}
/* ============================================================
- DECORATIVE REMOVAL
+ TOOLBAR — minimal, no background distinction
============================================================ */
-html[data-outlook-relook-scheme] * {
- border-radius: 0 !important;
- text-shadow: none !important;
+html[data-outlook-relook-scheme] [role="toolbar"] {
+ background-color: var(--or-bg-primary) !important;
+ border-bottom: 1px solid var(--or-border-light) !important;
}
-html[data-outlook-relook-scheme] button,
-html[data-outlook-relook-scheme] [role="button"],
-html[data-outlook-relook-scheme] [role="tab"],
-html[data-outlook-relook-scheme] [role="menuitem"] {
- box-shadow: none !important;
- background-image: none !important;
+/* Toolbar buttons: text only, no background */
+html[data-outlook-relook-scheme] [role="toolbar"] button,
+html[data-outlook-relook-scheme] [role="toolbar"] [role="button"] {
+ background-color: transparent !important;
+ border: none !important;
+ color: var(--or-text-primary) !important;
+}
+
+html[data-outlook-relook-scheme] [role="toolbar"] button:hover,
+html[data-outlook-relook-scheme] [role="toolbar"] [role="button"]:hover {
+ background-color: var(--or-bg-hover) !important;
}
/* ============================================================
- BUTTONS & INTERACTIVE
+ BUTTONS — understate everything
============================================================ */
+html[data-outlook-relook-scheme] button,
+html[data-outlook-relook-scheme] [role="button"] {
+ background-color: transparent !important;
+ color: var(--or-text-primary) !important;
+}
+
html[data-outlook-relook-scheme] button:hover,
html[data-outlook-relook-scheme] [role="button"]:hover {
background-color: var(--or-bg-hover) !important;
}
+/* Links: accent color, no underline by default */
html[data-outlook-relook-scheme] a {
color: var(--or-accent) !important;
+ text-decoration: none !important;
}
html[data-outlook-relook-scheme] a:hover {
+ text-decoration: underline !important;
color: var(--or-accent-hover) !important;
}
/* ============================================================
- TOOLBAR / COMMAND BAR
- ============================================================ */
-html[data-outlook-relook-scheme] [role="toolbar"] {
- background-color: var(--or-bg-primary) !important;
- border-bottom: 1px solid var(--or-border-light) !important;
- box-shadow: none !important;
-}
-
-/* ============================================================
- FOLDER PANE TREE ITEMS
+ FOLDER PANE — text hierarchy only, no visual chrome
============================================================ */
html[data-outlook-relook-scheme] [role="treeitem"] {
color: var(--or-text-secondary) !important;
+ background-color: transparent !important;
}
html[data-outlook-relook-scheme] [role="treeitem"]:hover {
- background-color: var(--or-bg-hover) !important;
color: var(--or-text-primary) !important;
+ background-color: transparent !important;
+ text-decoration: underline !important;
}
html[data-outlook-relook-scheme] [role="treeitem"][aria-selected="true"] {
- background-color: var(--or-bg-selected) !important;
color: var(--or-text-primary) !important;
- font-weight: 600 !important;
+ font-weight: 700 !important;
+ background-color: transparent !important;
}
/* ============================================================
- SECONDARY TEXT
+ SECONDARY TEXT — clear hierarchy
============================================================ */
html[data-outlook-relook-scheme] [role="option"] span,
html[data-outlook-relook-scheme] [role="listitem"] span {
@@ -180,4 +204,32 @@ html[data-outlook-relook-scheme] [role="listitem"] span {
html[data-outlook-relook-scheme] time {
color: var(--or-text-tertiary) !important;
+ font-size: 11px !important;
+ text-transform: uppercase !important;
+ letter-spacing: 0.03em !important;
+}
+
+/* ============================================================
+ DIALOGS & OVERLAYS
+ ============================================================ */
+html[data-outlook-relook-scheme] [role="dialog"],
+html[data-outlook-relook-scheme] [role="alertdialog"] {
+ background-color: var(--or-bg-primary) !important;
+ border: 1px solid var(--or-border) !important;
+}
+
+/* ============================================================
+ SCROLLBARS — thin, monochrome
+ ============================================================ */
+html[data-outlook-relook-scheme] ::-webkit-scrollbar {
+ width: 4px !important;
+ height: 4px !important;
+}
+
+html[data-outlook-relook-scheme] ::-webkit-scrollbar-track {
+ background: transparent !important;
+}
+
+html[data-outlook-relook-scheme] ::-webkit-scrollbar-thumb {
+ background: var(--or-text-tertiary) !important;
}