diff --git a/public/css/assistant.css b/public/css/assistant.css index 1356c679..3cbae761 100644 --- a/public/css/assistant.css +++ b/public/css/assistant.css @@ -563,17 +563,17 @@ body.assistant-mode-workspace .assistant-rail-workspace { display:flex; } body.assistant-sources-open .assistant-sources-fab { background:var(--blue-light); border-color:var(--blue-light); } } -/* Desktop: the rail is the same white sidebar the workspace uses, flush to the - window edge. It used to sit inside the content area's 14px padding, on the - tiled ground — so the menu changed background between the two views, the - name card sat 6px lower and further in, and the page was 28px taller than - the window. The 14px now belongs to the panels beside the rail. */ +/* Desktop: the rail is laid out as the workspace sidebar is, flush to the + window edge and flat on the page's tiled ground. It used to sit inside the + content area's 14px padding, so its name card sat 6px lower and further in + and the page was 28px taller than the window. The 14px now belongs to the + panels beside the rail. */ @media (min-width:961px) { body.assistant-workspace .main-content { padding:0; } body.assistant-workspace .assistant-layout { padding-right:14px; } body.assistant-workspace .assistant-main, body.assistant-workspace .assistant-side { margin-block:14px; height:auto; } - body.assistant-workspace .assistant-history { padding:0; gap:0; background:white; border-right:1.5px solid var(--g200); } + body.assistant-workspace .assistant-history { padding:0; gap:0; } body.assistant-workspace .assistant-rail-actions { padding:0 8px; } body.assistant-workspace .assistant-history .card { padding:0 8px; } /* Workspace links: the app's .tab-btn, full-bleed with the same inset. */ diff --git a/public/css/styles.css b/public/css/styles.css index 4055ea77..15b02d97 100644 --- a/public/css/styles.css +++ b/public/css/styles.css @@ -66,11 +66,20 @@ body{font-family:'Inter',system-ui,sans-serif;background:var(--g50);color:var(-- } /* APP BODY LAYOUT */ -.app-body{display:flex;min-height:100vh;} +/* The tiled ground covers the whole page — menu and content alike — from one + origin, so switching between the assistant and a workspace page never moves + the grid or changes what the menu sits on. */ +.app-body{display:flex;min-height:100vh; + 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);} /* 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:100vh;overflow:hidden;z-index:100;transition:width 0.22s ease;} .sidebar.collapsed{width:0;border:none;overflow:hidden;} +/* Desktop: the menu is flat on the tiled ground, as the assistant's rail is — + a white boxed sidebar here made every workspace page look like another app. + A phone keeps the white sheet, because there it slides over the page. */ +@media(min-width:769px){ .sidebar{ background:transparent; border-right:none; } } .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);} /* Head pinned, list scrolls, account card pinned. */ @@ -89,12 +98,14 @@ body{font-family:'Inter',system-ui,sans-serif;background:var(--g50);color:var(-- /* MAIN */ /* 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; + item changed the whole face of the app. The card edge belongs to the shell + and the tiled ground to .app-body, so only the contents differ. */ +.main-content{flex:1;min-width:0;min-height:0;padding:14px;display:flex;flex-direction:column;} +/* The page card carries the same tiled-white fill as the assistant's chat panel + (.assistant-main.card), so entering a workspace page keeps the surface. */ +.main-content > .tab-content.active{flex:1 1 auto;min-height:0;background-color:white; 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;} + background-size:28px 28px;background-position:-1px -1px;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;} diff --git a/test/assistant-workspace-layout.test.js b/test/assistant-workspace-layout.test.js index 1b8360e0..517a87ee 100644 --- a/test/assistant-workspace-layout.test.js +++ b/test/assistant-workspace-layout.test.js @@ -423,10 +423,24 @@ test('every view sits in the same shell, so opening a menu item is not a new app const css = read('public/css/styles.css'); // Each tab used to be a plain white page while the assistant and the workspace // launcher sat on a tiled card, so any menu click changed the whole face. - assert.match(css, /\.main-content\{[^}]*background-image:linear-gradient/, - 'the tiled ground belongs to the shell'); + // The ground covers the whole page, menu included, from one origin: a second + // tile on .main-content would start 210px in and seam against the menu's. + assert.match(css, /\.app-body\{[^}]*background-image:linear-gradient/, + 'the tiled ground belongs to the page'); + assert.doesNotMatch(css, /\.main-content\{[^}]*background-image/, 'and only to the page'); + // Flat menu on desktop, in both views; the phone sheet stays white. + assert.match(css, /@media\(min-width:769px\)\{ \.sidebar\{ background:transparent; border-right:none; \} \}/); assert.match(css, /\.main-content > \.tab-content\.active\{[^}]*border:1px solid var\(--g200\);border-radius:14px/, 'and every tab gets the same card edge'); + // ...and the same tiled-white surface as the assistant's chat panel, so a + // workspace page does not turn plain white on entry. + const tile = 'linear-gradient(var(--g100) 1px, transparent 1px), linear-gradient(90deg, var(--g100) 1px, transparent 1px)'; + const card = css.slice(css.indexOf('.main-content > .tab-content.active{'), css.indexOf('}', css.indexOf('.main-content > .tab-content.active{'))); + assert.ok(card.includes('background-color:white') && card.includes(tile) && card.includes('background-size:28px 28px'), 'page card is tiled white'); + const panel = read('public/css/assistant.css'); + // The top-level rule, not the phone override that also names .assistant-main.card. + const chat = (panel.match(/^\.assistant-main\.card \{[^}]*\}/m) || [''])[0]; + assert.ok(chat.includes('background-color:white') && chat.includes(tile) && chat.includes('background-size:28px 28px'), 'the same fill as the chat panel'); // The assistant brings a full-bleed layout, so it replaces the shell card // rather than nesting a second one inside it. assert.match(css, /\.main-content > #assistant-tab\.active\{padding:0;border:none/); @@ -535,14 +549,15 @@ test('the menu head reads toggle, mark, search — and account tabs are not list } }); -test('desktop: the assistant rail is the app sidebar, flush and white', () => { +test('desktop: the assistant rail is the app sidebar, flush and flat', () => { const css = read('public/css/assistant.css'); const styles = read('public/css/styles.css'); // Inside the content area's 14px padding the rail sat on the tiled ground, its // name card 6px lower and further in, and the page 28px taller than the window. const desk = css.slice(css.lastIndexOf('@media (min-width:961px) {')); assert.match(desk, /body\.assistant-workspace \.main-content \{ padding:0; \}/); - assert.match(desk, /body\.assistant-workspace \.assistant-history \{ padding:0; gap:0; background:white; border-right:1\.5px solid var\(--g200\); \}/); + assert.match(desk, /body\.assistant-workspace \.assistant-history \{ padding:0; gap:0; \}/, + 'flush, and flat on the tiled ground like the workspace sidebar'); assert.match(desk, /body\.assistant-workspace \.assistant-side \{ margin-block:14px; height:auto; \}/, 'the panels carry the 14px'); // Same insets as the sidebar: .menu-head, .assistant-mode-switch, .account-card. const rail = styles.slice(styles.lastIndexOf('@media (min-width:961px) {'));