diff --git a/public/css/assistant.css b/public/css/assistant.css
index 4cdedce9..002b33c0 100644
--- a/public/css/assistant.css
+++ b/public/css/assistant.css
@@ -12,7 +12,7 @@
.assistant-history { display:grid; gap:10px; align-content:start; position:sticky; top:0; }
.assistant-new-chat { display:flex; align-items:center; justify-content:center; gap:8px; width:100%; border:1px solid var(--blue-light); background:var(--blue-light); color:var(--blue); border-radius:10px; padding:10px 12px; font-size:13px; font-weight:700; cursor:pointer; }
.assistant-new-chat:hover { border-color:var(--blue); background:var(--blue-light); }
-.assistant-main { display:flex; flex-direction:column; min-height:calc(100vh - 200px); min-width:0; }
+.assistant-main { display:flex; flex-direction:column; min-height:0; min-width:0; }
#assistant-chat-view { display:grid; grid-template-rows:minmax(0,1fr) auto; min-height:0; min-width:0; }
.assistant-messages { padding:16px; max-height:none; overflow-y:auto; overflow-x:hidden; background:transparent; min-width:0; }
.assistant-empty { max-width:680px; margin:50px auto; text-align:center; color:var(--g500); }
@@ -278,12 +278,12 @@
@keyframes assistant-pulse { 0%,100% { box-shadow: 0 0 0 0 rgba(220,38,38,.45); } 50% { box-shadow: 0 0 0 14px rgba(220,38,38,0); } }
/* Full-screen Open WebUI workspace: the assistant replaces the app chrome */
-/* 52px is the slim app header, which the assistant shares (see styles.css). */
-body.assistant-workspace .assistant-layout { height: calc(100vh - 52px); min-height: 0; grid-template-rows: minmax(0, 1fr); overflow: hidden; }
+/* No header bar anywhere now, so the layout owns the whole viewport. */
+body.assistant-workspace .assistant-layout { height: 100vh; min-height: 0; grid-template-rows: minmax(0, 1fr); overflow: hidden; }
/* Phones: workspace mode hides .app-header, so there is no 64px to subtract and
the mobile flex layout must survive the more specific workspace selectors. */
@media (max-width: 640px) {
- body.assistant-workspace .assistant-layout { height:calc(100dvh - 52px); display:flex; flex-direction:column; grid-template-rows:none; overflow:hidden; }
+ body.assistant-workspace .assistant-layout { height:100dvh; display:flex; flex-direction:column; grid-template-rows:none; overflow:hidden; }
}
/* Desktop: the saved-chats rail collapses like ChatGPT's sidebar */
@@ -490,7 +490,8 @@ body.assistant-mode-workspace .assistant-rail-workspace { display:flex; }
content and nothing else. */
.assistant-main.card {
background-image:linear-gradient(var(--g100) 1px, transparent 1px), linear-gradient(90deg, var(--g100) 1px, transparent 1px);
- background-size:28px 28px; background-position:-1px -1px; background-color:white; }
+ background-size:28px 28px; background-position:-1px -1px; background-color:white;
+ border:1px solid var(--g200); border-radius:14px; box-shadow:var(--shadow); overflow:hidden; }
/* The composer is a card floating on that ground, with room around it rather
than pinned to the panel edge. */
diff --git a/public/css/styles.css b/public/css/styles.css
index 34338663..713a7ecd 100644
--- a/public/css/styles.css
+++ b/public/css/styles.css
@@ -45,31 +45,25 @@ body{font-family:'Inter',system-ui,sans-serif;background:var(--g50);color:var(--
/* HEADER */
-/* A slim, quiet top bar. The tall blue gradient dominated every screen and, by
- being the app's loudest element, made any view without it look like a
- different product. Content is what should carry the colour. */
-.app-header{background:white;color:var(--g800);padding:0 16px;border-bottom:1px solid var(--g200);height:52px;display:flex;align-items:center;}
-.header-content{width:100%;margin:0;}
-.header-top{display:flex;justify-content:space-between;align-items:center;gap:12px;}
-.logo{display:flex;align-items:center;gap:9px;}
-.logo i{font-size:18px;color:var(--blue);}
-.logo h1{font-size:15px;font-weight:700;color:var(--g900);white-space:nowrap;}
-.tagline{display:none;}
-.header-right{display:flex;align-items:center;gap:8px;}
-.model-selector{display:flex;align-items:center;gap:6px;background:var(--g50);border:1px solid var(--g200);padding:4px 8px;border-radius:8px;}
-.model-selector label{font-size:11px;color:var(--g500);}
-.model-selector select{padding:3px 6px;border:1px solid var(--g200);border-radius:6px;background:white;color:var(--g700);font-size:12px;font-family:inherit;max-width:200px;}
-.model-selector select option{background:white;color:var(--g800);}
-.cost-badge{font-size:10px;padding:2px 8px;background:#ecfdf5;border:1px solid #a7f3d0;border-radius:10px;color:#047857;font-weight:600;white-space:nowrap;}
-.header-buttons{display:flex;gap:4px;}
-.btn-header{background:none;border:1px solid transparent;color:var(--g500);width:32px;height:32px;border-radius:8px;cursor:pointer;font-size:13px;transition:all 0.15s;}
-.btn-header:hover{background:var(--g100);color:var(--g800);}
+/* No header bar at all. The brand heads the menu, Settings and Log out sit in
+ the account card at its foot, and the content gets the full height. */
+.menu-head { display:flex; align-items:center; gap:4px; padding:10px 8px 8px 12px; }
+.menu-brand { display:flex; align-items:center; gap:8px; flex:1 1 auto; min-width:0; }
+.menu-brand i { font-size:16px; color:var(--blue); flex:0 0 auto; }
+.menu-brand h1 { font-size:13.5px; font-weight:700; color:var(--g900); line-height:1.2; margin:0; overflow:hidden; text-overflow:ellipsis; }
+.menu-icon-btn { flex:0 0 auto; display:inline-flex; align-items:center; justify-content:center; width:28px; height:28px; border:none; border-radius:8px; background:none; color:var(--g500); font-size:13px; cursor:pointer; }
+.menu-icon-btn:hover { background:var(--g100); color:var(--g800); }
+.assistant-history .menu-head { padding:0 0 8px; }
+.btn-menu-toggle { display:none; }
+@media(max-width:768px){
+ .btn-menu-toggle { display:inline-flex; align-items:center; justify-content:center; position:fixed; top:10px; left:10px; z-index:150; width:38px; height:38px; border:1px solid var(--g200); border-radius:10px; background:white; color:var(--g700); font-size:15px; box-shadow:var(--shadow); }
+}
/* APP BODY LAYOUT */
-.app-body{display:flex;min-height:calc(100vh - 52px);}
+.app-body{display:flex;min-height:100vh;}
/* SIDEBAR */
-.sidebar{width:210px;flex-shrink:0;background:white;border-right:1.5px solid var(--g200);display:flex;flex-direction:column;position:sticky;top:0;height:calc(100vh - 52px);overflow-y:auto;z-index:100;transition:width 0.22s ease;}
+.sidebar{width:210px;flex-shrink:0;background:white;border-right:1.5px solid var(--g200);display:flex;flex-direction:column;position:sticky;top:0;height:100vh;overflow-y:auto;z-index:100;transition:width 0.22s ease;}
.sidebar.collapsed{width:0;border:none;overflow:hidden;}
.sidebar-header{display:none;justify-content:space-between;align-items:center;padding:12px 16px;border-bottom:1px solid var(--g200);}
.sidebar-title{font-size:13px;font-weight:700;color:var(--g700);}
@@ -85,7 +79,22 @@ body{font-family:'Inter',system-ui,sans-serif;background:var(--g50);color:var(--
/* Sidebar collapse/expand buttons (desktop only) */
/* MAIN */
-.main-content{flex:1;min-width:0;padding:20px 20px;}
+/* One shell for every view. Each tab used to be a plain white page while the
+ assistant and the workspace launcher sat on a tiled card, so opening any menu
+ item changed the whole face of the app. The tiled ground and the card edge
+ belong to the shell, so only the contents differ. */
+.main-content{flex:1;min-width:0;min-height:0;padding:14px;display:flex;flex-direction:column;
+ background-image:linear-gradient(var(--g100) 1px, transparent 1px), linear-gradient(90deg, var(--g100) 1px, transparent 1px);
+ background-size:28px 28px;background-position:-1px -1px;background-color:var(--g50);}
+.main-content > .tab-content.active{flex:1 1 auto;min-height:0;background:white;border:1px solid var(--g200);border-radius:14px;box-shadow:var(--shadow);padding:20px;overflow:auto;}
+/* The assistant brings its own full-bleed layout, so it takes the shell's place
+ rather than nesting a second card inside it. */
+.main-content > #assistant-tab.active{padding:0;border:none;box-shadow:none;background:transparent;overflow:visible;}
+@media(max-width:768px){
+ .main-content{padding:8px;}
+ .main-content > .tab-content.active{padding:12px;border-radius:12px;}
+ .main-content > #assistant-tab.active{padding:0;}
+}
.tab-content{display:none;}
.tab-content.active{display:block;animation:fadeIn 0.25s ease;}
@keyframes fadeIn{from{opacity:0;transform:translateY(8px);}to{opacity:1;transform:translateY(0);}}
@@ -335,10 +344,21 @@ textarea.full-input{resize:vertical;}
.sidebar.open{left:0;box-shadow:4px 0 20px rgba(0,0,0,0.18);}
.sidebar.open~.sidebar-overlay{display:block;}
.sidebar-header{display:flex;}
- /* Hide desktop collapse controls on mobile */
- .sidebar-pin-btn{display:none;}
- .sidebar-expand-btn{display:none !important;}
- .main-content{padding:12px;}
+ /* The sidebar slides in as a whole on mobile, so a collapse control inside it
+ has nothing to collapse — the overlay close is the way out. */
+ .assistant-menu-toggle{display:none !important;}
+ /* Give the drawer room to breathe and keep the account card reachable at the
+ foot of a scrolling menu. */
+ .sidebar{display:flex;flex-direction:column;overflow-y:auto;}
+ .sidebar-nav{flex:1 1 auto;min-height:0;}
+ .menu-head{padding:12px 10px 8px;}
+ .menu-brand h1{font-size:13px;}
+ .account-card{position:sticky;bottom:0;background:white;}
+ .account-menu{left:8px;right:8px;}
+ /* The palette is full-bleed on a phone, where a centred dialog wastes space. */
+ .menu-search{padding:0;align-items:stretch;}
+ .menu-search-panel{width:100%;max-height:100%;border:none;border-radius:0;}
+ .main-content{padding:8px;}
.demographics-bar{flex-direction:column;}
.demo-field input,.demo-field select{min-width:100%;}
.note-meta{flex-direction:column;}
@@ -1210,7 +1230,7 @@ textarea.full-input{resize:vertical;}
because the assistant rail takes its place. */
body.assistant-workspace .sidebar,
body.assistant-workspace .announcement-banner { display:none; }
-body.assistant-workspace .app-body { min-height:calc(100vh - 52px); }
+body.assistant-workspace .app-body { min-height:100vh; }
body.assistant-workspace #assistant-tab.active { width:100%; }
/* iOS: taps on controls must not trigger double-tap zoom */
button, a, .btn-sm, .btn-generate, .btn-send, .tab-btn, input, textarea, select, label { touch-action: manipulation; }
@@ -1246,8 +1266,7 @@ body.menu-hidden .sidebar > *:not(.sidebar-nav) { display:none; }
body.menu-hidden .sidebar-nav > *:not(.assistant-menu-toggle) { display:none; }
body.menu-hidden .assistant-menu-toggle,
body.assistant-workspace.menu-hidden .assistant-history .assistant-menu-toggle {
- position:fixed; top:76px; left:10px; z-index:120; margin:0; background:white; box-shadow:var(--shadow); }
-body.assistant-workspace.menu-hidden .assistant-menu-toggle { top:10px; }
+ position:fixed; top:10px; left:10px; z-index:120; margin:0; width:34px; height:34px; border:1px solid var(--g200); background:white; box-shadow:var(--shadow); }
body.assistant-workspace.menu-hidden .assistant-layout { grid-template-columns:0 minmax(0,1fr) 330px; }
body.assistant-workspace.menu-hidden.assistant-no-citations .assistant-layout { grid-template-columns:0 minmax(0,1fr); }
body.assistant-workspace.menu-hidden .assistant-history > *:not(.assistant-menu-toggle) { display:none; }
@@ -1287,3 +1306,25 @@ body.assistant-preview .assistant-preview-note { display:flex; }
body.menu-hidden .account-card, body.assistant-workspace.menu-hidden .account-card { display:none; }
/* A preview visitor has no account to show. */
body.assistant-preview .account-card { display:none; }
+
+/* ── Search palette ──────────────────────────────────────────────────────────
+ One component in both views; the view decides what it searches. */
+
+.menu-search { position:fixed; inset:0; z-index:200; background:rgba(15,23,42,.45); display:flex; align-items:flex-start; justify-content:center; padding:12vh 16px 16px; }
+.menu-search[hidden] { display:none; }
+.menu-search-panel { width:min(640px,100%); max-height:70vh; display:flex; flex-direction:column; background:white; border:1px solid var(--g200); border-radius:14px; box-shadow:0 24px 60px rgba(15,23,42,.28); overflow:hidden; }
+.menu-search-head { display:flex; align-items:center; gap:10px; padding:12px 14px; border-bottom:1px solid var(--g100); }
+.menu-search-head i { color:var(--g400); font-size:13px; }
+.menu-search-head input { flex:1 1 auto; min-width:0; border:none; outline:none; background:none; font-family:inherit; font-size:15px; color:var(--g900); }
+.menu-search-head button { border:none; background:none; color:var(--g400); font-size:14px; cursor:pointer; padding:4px; }
+.menu-search-head button:hover { color:var(--g700); }
+.menu-search-results { flex:1 1 auto; min-height:0; overflow-y:auto; padding:6px; display:flex; flex-direction:column; gap:2px; }
+.menu-search-item { display:flex; align-items:center; gap:10px; width:100%; border:none; border-radius:9px; padding:9px 10px; background:none; color:var(--g800); font-family:inherit; font-size:13px; text-align:left; cursor:pointer; }
+.menu-search-item i { width:16px; text-align:center; color:var(--g400); font-size:12px; flex:0 0 auto; }
+.menu-search-item span { flex:1 1 auto; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
+.menu-search-item em { flex:0 0 auto; font-style:normal; font-size:11px; color:var(--g400); }
+.menu-search-item:hover, .menu-search-item.is-active { background:var(--blue-light); color:var(--blue); }
+.menu-search-item:hover i, .menu-search-item.is-active i { color:var(--blue); }
+.menu-search-empty { margin:0; padding:18px 12px; text-align:center; font-size:13px; color:var(--g400); }
+/* Collapsed: only the toggle survives, so there is a way back. */
+body.menu-hidden .menu-brand, body.menu-hidden [data-menu-search] { display:none; }
diff --git a/public/index.html b/public/index.html
index 7790fbc4..bf053704 100644
--- a/public/index.html
+++ b/public/index.html
@@ -149,35 +149,14 @@
-
-
+
+
+
+
@@ -197,7 +176,16 @@
+
+
+
diff --git a/public/js/app.js b/public/js/app.js
index 8d3de73c..0a90a877 100644
--- a/public/js/app.js
+++ b/public/js/app.js
@@ -264,6 +264,122 @@ document.addEventListener('DOMContentLoaded', function() {
document.querySelectorAll('.account-card-btn').forEach(function(b) { b.setAttribute('aria-expanded', 'false'); });
});
+ // ── Search ──────────────────────────────────────────────────────────────────
+ // One palette; the view decides what it searches. In the workspace that is the
+ // app menu, in the assistant it is the saved chats. Both sources are already
+ // in memory, so this needs no new endpoint.
+ var searchModal = document.getElementById('menu-search');
+ var searchInput = document.getElementById('menu-search-input');
+ var searchResults = document.getElementById('menu-search-results');
+
+ function searchSources() {
+ // The assistant publishes its chats; anything else searches the menu.
+ if (window.location.pathname === '/assistant' && typeof window.assistantSearchableChats === 'function') {
+ return { kind: 'chats', items: window.assistantSearchableChats() };
+ }
+ return { kind: 'tabs', items: Array.prototype.map.call(document.querySelectorAll('.tab-btn'), function(tab) {
+ var label = tab.querySelector('span');
+ var icon = tab.querySelector('i');
+ return {
+ id: tab.getAttribute('data-tab'),
+ title: label ? label.textContent : tab.getAttribute('data-tab'),
+ icon: icon ? icon.className : 'fas fa-circle',
+ hidden: tab.classList.contains('hidden')
+ };
+ }).filter(function(t) { return t.id && !t.hidden; }) };
+ }
+
+ function renderSearch(term) {
+ if (!searchResults) return;
+ var source = searchSources();
+ var needle = String(term || '').trim().toLowerCase();
+ var matches = source.items.filter(function(item) {
+ return !needle || String(item.title || '').toLowerCase().indexOf(needle) !== -1;
+ }).slice(0, 40);
+ searchResults.innerHTML = '';
+ if (!matches.length) {
+ var empty = document.createElement('p');
+ empty.className = 'menu-search-empty';
+ empty.textContent = needle
+ ? 'Nothing matches “' + term + '”.'
+ : (source.kind === 'chats' ? 'No saved chats yet.' : 'Nothing to search.');
+ searchResults.appendChild(empty);
+ return;
+ }
+ matches.forEach(function(item, index) {
+ var row = document.createElement('button');
+ row.type = 'button';
+ row.className = 'menu-search-item' + (index === 0 ? ' is-active' : '');
+ row.setAttribute('role', 'option');
+ row.setAttribute('data-search-kind', source.kind);
+ row.setAttribute('data-search-id', item.id);
+ row.innerHTML = '' +
+ (item.meta ? '' : '');
+ row.querySelector('span').textContent = item.title || '';
+ if (item.meta) row.querySelector('em').textContent = item.meta;
+ searchResults.appendChild(row);
+ });
+ }
+
+ function openSearch() {
+ if (!searchModal) return;
+ searchModal.hidden = false;
+ if (searchInput) {
+ searchInput.value = '';
+ searchInput.placeholder = searchSources().kind === 'chats' ? 'Search chats...' : 'Search the workspace...';
+ searchInput.focus();
+ }
+ renderSearch('');
+ }
+ function closeSearch() { if (searchModal) searchModal.hidden = true; }
+
+ function runSearchItem(row) {
+ if (!row) return;
+ var kind = row.getAttribute('data-search-kind');
+ var id = row.getAttribute('data-search-id');
+ closeSearch();
+ if (kind === 'chats') {
+ if (typeof window.assistantOpenChat === 'function') window.assistantOpenChat(id);
+ return;
+ }
+ // A workspace result lives in the app, so reaching one from the assistant
+ // leaves it — the same rule the account menu follows.
+ if (window.location.pathname === '/assistant') {
+ try { localStorage.setItem('ped_last_tab', id); } catch (e) {}
+ window.location.href = '/';
+ return;
+ }
+ activateTab(id);
+ }
+
+ document.addEventListener('click', function(event) {
+ if (event.target.closest && event.target.closest('[data-menu-search]')) { openSearch(); return; }
+ if (event.target.closest && event.target.closest('#menu-search-close')) { closeSearch(); return; }
+ var row = event.target.closest && event.target.closest('.menu-search-item');
+ if (row) { runSearchItem(row); return; }
+ if (searchModal && !searchModal.hidden && event.target === searchModal) closeSearch();
+ });
+ if (searchInput) searchInput.addEventListener('input', function() { renderSearch(searchInput.value); });
+ document.addEventListener('keydown', function(event) {
+ var key = String(event.key || '').toLowerCase();
+ if ((event.metaKey || event.ctrlKey) && key === 'k') { event.preventDefault(); openSearch(); return; }
+ if (!searchModal || searchModal.hidden) return;
+ if (event.key === 'Escape') { closeSearch(); return; }
+ var rows = Array.prototype.slice.call(searchResults ? searchResults.querySelectorAll('.menu-search-item') : []);
+ if (!rows.length) return;
+ var at = rows.findIndex(function(r) { return r.classList.contains('is-active'); });
+ if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {
+ event.preventDefault();
+ var next = event.key === 'ArrowDown' ? Math.min(at + 1, rows.length - 1) : Math.max(at - 1, 0);
+ rows.forEach(function(r) { r.classList.remove('is-active'); });
+ rows[next].classList.add('is-active');
+ rows[next].scrollIntoView({ block: 'nearest' });
+ } else if (event.key === 'Enter') {
+ event.preventDefault();
+ runSearchItem(rows[at === -1 ? 0 : at]);
+ }
+ });
+
// Expose activateTab globally so auth.js can call it after login
window.activateTab = activateTab;
diff --git a/public/js/clinicalAssistant.js b/public/js/clinicalAssistant.js
index 1fd93436..97c196d0 100644
--- a/public/js/clinicalAssistant.js
+++ b/public/js/clinicalAssistant.js
@@ -2177,6 +2177,20 @@ import {
return groups.sort(function (a, b) { return a.order - b.order; });
}
+ // Published for the shared search palette: the assistant owns its chats, so it
+ // exposes them rather than having the palette reach into its internals.
+ if (typeof window !== 'undefined') window.assistantSearchableChats = function() {
+ return (savedChatCache || []).map(function(chat) {
+ return {
+ id: chat.id,
+ title: chat.title || 'Saved chat',
+ icon: isChatPinned(chat.id) ? 'fas fa-thumbtack' : 'fas fa-message',
+ meta: formatSavedDate(chat.updated_at || chat.created_at)
+ };
+ });
+ };
+ if (typeof window !== 'undefined') window.assistantOpenChat = function(id) { loadSavedChat(id); };
+
function renderSavedChats(chats) {
savedChatCache = chats || [];
var wrap = document.getElementById('assistant-saved-chats');
diff --git a/test/assistant-workspace-layout.test.js b/test/assistant-workspace-layout.test.js
index 9c256443..0b22148b 100644
--- a/test/assistant-workspace-layout.test.js
+++ b/test/assistant-workspace-layout.test.js
@@ -175,12 +175,16 @@ test('the menu toggle uses an icon that reads as a menu', () => {
const markup = read(file);
const button = markup.split('\n').find(l => l.includes('data-menu-toggle'));
assert.ok(button, file + ' has the toggle');
- // fa-table-columns draws a split-pane glyph, which does not say "menu".
- assert.doesNotMatch(button, /fa-table-columns/, file + ' uses a menu icon');
- assert.match(button, /fa-bars/, file);
+ // fa-table-columns draws a split-pane glyph that says nothing about what the
+ // click does. Angles point the way the panel moves.
+ assert.doesNotMatch(button, /fa-table-columns/, file + ' avoids the split-pane glyph');
+ assert.match(button, /fa-angles-left/, file);
}
assert.match(read('public/css/assistant.css'), /\.assistant-menu-toggle\.is-collapsed i \{ transform:rotate\(180deg\); \}/,
'and it turns to show the direction it will act in');
+ // Collapsed, the toggle is the only control left, so it must stay reachable.
+ assert.match(read('public/css/styles.css'), /body\.menu-hidden \.menu-brand, body\.menu-hidden \[data-menu-search\] \{ display:none; \}/,
+ 'brand and search go, the toggle stays');
});
test('workspace mode does not override the mobile layout with a desktop header offset', () => {
@@ -191,8 +195,8 @@ test('workspace mode does not override the mobile layout with a desktop header o
// specific than the .assistant-layout rule inside @media (max-width:640px), so
// the mobile rule needs a matching-specificity override to win at all.
// Both now subtract the app header, which the assistant keeps rather than hides.
- const override = css.indexOf('body.assistant-workspace .assistant-layout { height:calc(100dvh - 52px);');
- const desktop = css.indexOf('body.assistant-workspace .assistant-layout { height: calc(100vh - 52px)');
+ const override = css.indexOf('body.assistant-workspace .assistant-layout { height:100dvh;');
+ const desktop = css.indexOf('body.assistant-workspace .assistant-layout { height: 100vh');
assert.ok(desktop > 0, 'the desktop workspace rule exists');
assert.ok(override > desktop, 'the mobile override comes after it, so it wins');
const rule = css.slice(override, css.indexOf('}', override));
@@ -386,14 +390,50 @@ test('one menu, ending the same way in both views', () => {
'a preview visitor has no account to show');
});
-test('the top bar is slim and quiet, not a coloured band', () => {
+test('there is no header bar; the brand heads the menu instead', () => {
+ const index = read('public/index.html');
const css = read('public/css/styles.css');
- const header = css.split('\n').find(l => l.startsWith('.app-header{'));
- // A tall gradient made the header the loudest thing on screen, so any view
- // without it read as a different product.
- assert.doesNotMatch(header, /linear-gradient/, 'no colour band');
- assert.match(header, /height:52px/, 'and it is slim');
- // Everything measured against the header must follow it down.
- assert.doesNotMatch(css, /calc\(100vh - 66px\)/, 'no stale 66px offsets');
- assert.doesNotMatch(read('public/css/assistant.css'), /calc\(100vh - 66px\)/);
+ // Settings and Log out moved to the account card, so a whole band of chrome
+ // had nothing left to hold and became content.
+ assert.doesNotMatch(index, /