Files
openclaw/ui/src/styles/layout.css
T
Val Alexander f76a3c5225 feat(ui): dashboard-v2 views refactor (slice 3/3 of dashboard-v2) (#41503)
* feat(ui): add chat infrastructure modules (slice 1 of dashboard-v2)

New self-contained chat modules extracted from dashboard-v2-structure:

- chat/slash-commands.ts: slash command definitions and completions
- chat/slash-command-executor.ts: execute slash commands via gateway RPC
- chat/slash-command-executor.node.test.ts: test coverage
- chat/speech.ts: speech-to-text (STT) support
- chat/input-history.ts: per-session input history navigation
- chat/pinned-messages.ts: pinned message management
- chat/deleted-messages.ts: deleted message tracking
- chat/export.ts: shared exportChatMarkdown helper
- chat-export.ts: re-export shim for backwards compat

Gateway fix:
- Restore usage/cost stripping in chat.history sanitization
- Add test coverage for sanitization behavior

These modules are additive and tree-shaken — no existing code
imports them yet. They will be wired in subsequent slices.

* feat(ui): add utilities, theming, and i18n updates (slice 2 of dashboard-v2)

UI utilities and theming improvements extracted from dashboard-v2-structure:

Icons & formatting:
- icons.ts: expanded icon set for new dashboard views
- format.ts: date/number formatting helpers
- tool-labels.ts: human-readable tool name mappings

Theming:
- theme.ts: enhanced theme resolution and system theme support
- theme-transition.ts: simplified transition logic
- storage.ts: theme parsing improvements for settings persistence

Navigation & types:
- navigation.ts: extended tab definitions for dashboard-v2
- app-view-state.ts: expanded view state management
- types.ts: new type definitions (HealthSummary, ModelCatalogEntry, etc.)

Components:
- components/dashboard-header.ts: reusable header component

i18n:
- Updated en, pt-BR, zh-CN, zh-TW locales with new dashboard strings

All changes are additive or backwards-compatible. Build passes.
Part of #36853.

* feat(ui): dashboard-v2 views refactor (slice 3 of dashboard-v2)

Complete views refactor from dashboard-v2-structure, building on
slice 1 (chat infra, #41497) and slice 2 (utilities/theming, #41500).

Core app wiring:
- app.ts: updated host component with new state properties
- app-render.ts: refactored render pipeline for new dashboard layout
- app-render.helpers.ts: extracted render helpers
- app-settings.ts: theme listener lifecycle fix, cron runs on tab load
- app-gateway.ts: refactored chat event handling
- app-chat.ts: slash command integration

New views:
- views/command-palette.ts: command palette (Cmd+K)
- views/login-gate.ts: authentication gate
- views/bottom-tabs.ts: mobile tab navigation
- views/overview-*.ts: modular overview dashboard (cards, attention,
  event log, hints, log tail, quick actions)
- views/agents-panels-overview.ts: agent overview panel

Refactored views:
- views/chat.ts: major refactor with STT, slash commands, search,
  export, pinned messages, input history
- views/config.ts: restructured config management
- views/agents.ts: streamlined agent management
- views/overview.ts: modular composition from sub-views
- views/sessions.ts: enhanced session management

Controllers:
- controllers/health.ts: new health check controller
- controllers/models.ts: new model catalog controller
- controllers/agents.ts: tools catalog improvements
- controllers/config.ts: config form enhancements

Tests & infrastructure:
- Updated test helpers, browser tests, node tests
- vite.config.ts: build configuration updates
- markdown.ts: rendering improvements

Build passes  | 44 files | +6,626/-1,499
Part of #36853. Depends on #41497 and #41500.

* UI: fix chat review follow-ups

* fix(ui): repair chat clear and attachment regressions

* fix(ui): address remaining chat review comments

* fix(ui): address review follow-ups

* fix(ui): replay queued local slash commands

* fix(ui): repair control-ui type drift

* fix(ui): restore control UI styling

* feat(ui): enhance layout and styling for config and topbar components

- Updated grid layout for the config layout to allow full-width usage.
- Introduced new styles for top tabs and search components to improve usability.
- Added theme mode toggle styling for better visual integration.
- Implemented tests for layout and theme mode components to ensure proper rendering and functionality.

* feat(ui): add config file opening functionality and enhance styles

- Implemented a new handler to open the configuration file using the default application based on the operating system.
- Updated various CSS styles across components for improved visual consistency and usability, including adjustments to padding, margins, and font sizes.
- Introduced new styles for the data table and sidebar components to enhance layout and interaction.
- Added tests for the collapsed navigation rail to ensure proper functionality in different states.

* refactor(ui): update CSS styles for improved layout and consistency

- Simplified font-body declaration in base.css for cleaner code.
- Adjusted transition properties in components.css for better readability.
- Added new .workspace-link class in components.css for enhanced link styling.
- Changed config layout from grid to flex in config.css for better responsiveness.
- Updated related tests to reflect layout changes in config-layout.browser.test.ts.

* feat(ui): enhance theme handling and loading states in chat interface

- Updated CSS to support new theme mode attributes for better styling consistency across light and dark themes.
- Introduced loading skeletons in the chat view to improve user experience during data fetching.
- Refactored command palette to manage focus more effectively, enhancing accessibility.
- Added tests for the appearance theme picker and loading states to ensure proper rendering and functionality.

* refactor(ui): streamline ephemeral state management in chat and config views

- Introduced interfaces for ephemeral state in chat and config views to encapsulate related variables.
- Refactored state management to utilize a single object for better organization and maintainability.
- Removed legacy state variables and updated related functions to reference the new state structure.
- Enhanced readability and consistency across the codebase by standardizing state handling.

* chore: remove test files to reduce PR scope

* fix(ui): resolve type errors in debug props and chat search

* refactor(ui): remove stream mode functionality across various components

- Eliminated stream mode related translations and CSS styles to streamline the user interface.
- Updated multiple components to remove references to stream mode, enhancing code clarity and maintainability.
- Adjusted rendering logic in views to ensure consistent behavior without stream mode.
- Improved overall readability by cleaning up unused variables and props.

* fix(ui): add msg-meta CSS and fix rebase type errors

* fix(ui): add CSS for chat footer action buttons (TTS, delete) and msg-meta

* feat(ui): add delete confirmation with remember-decision checkbox

* fix(ui): delete confirmation with remember, attention icon sizing

* fix(ui): open delete confirm popover to the left (not clipped)

* fix(ui): show all nav items in collapsed sidebar, remove gap

* fix(ui): address P1/P2 review feedback — session queue clear, kill scope, palette guard, stop button

* fix(ui): address Greptile re-review — kill scope, queue flush, idle handling, parallel fetch

- SECURITY: /kill <target> now enforces session tree scope (not just /kill all)
- /kill reports idle sessions gracefully instead of throwing
- Queue continues draining after local slash commands
- /model fetches sessions.list + models.list in parallel (perf fix)

* fix(ui): style update banner close button — SVG stroke + sizing

* fix(ui): update layout styles for sidebar and content spacing

* UI: restore colon slash command parsing

* UI: restore slash command session queries

* Refactor thinking resolution: Introduce resolveThinkingDefaultForModel function and update model-selection to utilize it. Add tests for new functionality in thinking.test.ts.

* fix(ui): constrain welcome state logo size, add missing CSS for new session view

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-03-12 12:46:19 -05:00

988 lines
18 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* ===========================================
Shell Layout
=========================================== */
.shell {
--shell-pad: 16px;
--shell-gap: 16px;
--shell-nav-width: 220px;
--shell-nav-rail-width: 72px;
--shell-topbar-height: 52px;
--shell-focus-duration: 200ms;
--shell-focus-ease: var(--ease-out);
height: 100vh;
display: grid;
grid-template-columns: var(--shell-nav-width) minmax(0, 1fr);
grid-template-rows: var(--shell-topbar-height) 1fr;
grid-template-areas:
"topbar topbar"
"nav content";
gap: 0;
animation: dashboard-enter 0.3s var(--ease-out);
transition: grid-template-columns var(--shell-focus-duration) var(--shell-focus-ease);
overflow: hidden;
}
@supports (height: 100dvh) {
.shell {
height: 100dvh;
}
}
.shell--chat {
min-height: 100vh;
height: 100vh;
overflow: hidden;
}
@supports (height: 100dvh) {
.shell--chat {
height: 100dvh;
}
}
.shell--nav-collapsed {
grid-template-columns: var(--shell-nav-rail-width) minmax(0, 1fr);
}
.shell--chat-focus {
grid-template-columns: 0px minmax(0, 1fr);
}
.shell--onboarding {
grid-template-rows: 0 1fr;
}
.shell--onboarding .topbar {
display: none;
}
.shell--onboarding .content {
padding-top: 0;
}
.shell--chat-focus .content {
padding-top: 0;
}
.shell--chat-focus .content>*+* {
margin-top: 0;
}
/* ===========================================
Topbar
=========================================== */
.topbar {
grid-area: topbar;
position: sticky;
top: 0;
z-index: 40;
display: flex;
justify-content: space-between;
align-items: center;
gap: 16px;
padding: 0 20px;
height: var(--shell-topbar-height);
border-bottom: 1px solid var(--border);
background: color-mix(in srgb, var(--bg) 85%, transparent);
backdrop-filter: blur(12px) saturate(1.6);
-webkit-backdrop-filter: blur(12px) saturate(1.6);
}
.topbar-left {
display: flex;
align-items: center;
gap: 12px;
}
.topbar .nav-collapse-toggle {
width: 36px;
height: 36px;
margin-bottom: 0;
}
.topbar .nav-collapse-toggle__icon {
width: 20px;
height: 20px;
}
.topbar .nav-collapse-toggle__icon svg {
width: 20px;
height: 20px;
}
/* Brand */
.brand {
display: flex;
align-items: center;
gap: 8px;
}
.brand-logo {
width: 26px;
height: 26px;
flex-shrink: 0;
}
.brand-logo img {
width: 100%;
height: 100%;
object-fit: contain;
}
.brand-text {
display: flex;
flex-direction: column;
gap: 0;
}
.brand-title {
font-size: 15px;
font-weight: 700;
letter-spacing: -0.03em;
line-height: 1.1;
color: var(--text-strong);
}
.brand-sub {
font-size: 9px;
font-weight: 500;
color: var(--muted);
letter-spacing: 0.06em;
text-transform: uppercase;
line-height: 1;
}
/* Topbar status */
.topbar-status {
display: flex;
align-items: center;
gap: 8px;
}
.topbar-status .pill {
padding: 6px 10px;
gap: 6px;
font-size: 12px;
font-weight: 500;
height: 32px;
box-sizing: border-box;
}
.topbar-status .pill .mono {
display: flex;
align-items: center;
line-height: 1;
margin-top: 0px;
}
.topbar-status .statusDot {
width: 6px;
height: 6px;
}
.topbar-status .theme-orb__trigger {
width: 26px;
height: 26px;
font-size: 13px;
}
/* Topbar search trigger */
.topbar-search {
display: inline-flex;
align-items: center;
gap: 12px;
padding: 7px 12px;
border: 1px solid var(--border);
border-radius: var(--radius-md);
background: var(--bg-elevated);
color: var(--muted);
font-size: 13px;
cursor: pointer;
transition:
border-color var(--duration-fast) ease,
background var(--duration-fast) ease,
color var(--duration-fast) ease;
min-width: 180px;
}
.topbar-search:hover {
border-color: var(--border-strong);
background: var(--bg-hover);
color: var(--text);
}
.topbar-search:focus-visible {
outline: none;
box-shadow: var(--focus-ring);
}
.topbar-search__label {
flex: 1;
text-align: left;
}
.topbar-search__kbd {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 2px 6px;
border: 1px solid var(--border);
border-radius: var(--radius-sm);
background: var(--bg);
font-family: var(--mono);
font-size: 11px;
line-height: 1;
color: var(--muted);
}
.topbar-theme-mode {
display: inline-flex;
align-items: center;
gap: 2px;
padding: 3px;
border: 1px solid var(--border);
border-radius: var(--radius-lg);
background: color-mix(in srgb, var(--bg-elevated) 70%, transparent);
}
.topbar-theme-mode__btn {
width: 30px;
height: 30px;
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0;
border: 1px solid transparent;
border-radius: calc(var(--radius-md) - 1px);
background: transparent;
color: var(--muted);
cursor: pointer;
transition:
color var(--duration-fast) ease,
background var(--duration-fast) ease,
border-color var(--duration-fast) ease;
}
.topbar-theme-mode__btn:hover {
color: var(--text);
background: var(--bg-hover);
}
.topbar-theme-mode__btn:focus-visible {
outline: none;
box-shadow: var(--focus-ring);
}
.topbar-theme-mode__btn--active {
color: var(--accent);
background: var(--accent-subtle);
border-color: color-mix(in srgb, var(--accent) 25%, transparent);
}
.topbar-theme-mode__btn svg {
width: 14px;
height: 14px;
stroke: currentColor;
fill: none;
stroke-width: 1.75px;
stroke-linecap: round;
stroke-linejoin: round;
}
/* ===========================================
Navigation Sidebar (shadcn-inspired)
=========================================== */
/* Sidebar wrapper occupies the "nav" grid area */
.shell-nav {
grid-area: nav;
display: flex;
min-height: 0;
overflow: hidden;
transition: width var(--shell-focus-duration) var(--shell-focus-ease);
}
/* The sidebar panel itself */
.sidebar {
display: flex;
flex-direction: column;
flex: 1;
min-height: 0;
min-width: 0;
overflow: hidden;
background: var(--bg);
}
:root[data-theme-mode="light"] .sidebar {
background: var(--panel);
}
/* Collapsed: icon-only rail */
.sidebar--collapsed {
width: var(--shell-nav-rail-width);
min-width: var(--shell-nav-rail-width);
flex: 0 0 var(--shell-nav-rail-width);
border-right: 1px solid color-mix(in srgb, var(--border-strong) 72%, transparent);
}
/* Header: brand + collapse toggle */
.sidebar-header {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
padding: 14px 14px 6px;
flex-shrink: 0;
}
.sidebar--collapsed .sidebar-header {
justify-content: center;
padding: 12px 10px 6px;
}
/* Brand lockup */
.sidebar-brand {
display: flex;
align-items: center;
gap: 8px;
min-width: 0;
}
.sidebar-brand__logo {
width: 22px;
height: 22px;
flex-shrink: 0;
border-radius: 6px;
}
.sidebar-brand__title {
font-size: 14px;
font-weight: 700;
letter-spacing: -0.025em;
color: var(--text-strong);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
/* Scrollable nav body */
.sidebar-nav {
flex: 1;
overflow-y: auto;
overflow-x: hidden;
padding: 4px 8px;
scrollbar-width: none;
}
.sidebar-nav::-webkit-scrollbar {
display: none;
}
.sidebar--collapsed .sidebar-nav {
padding: 4px 8px;
display: flex;
flex-direction: column;
gap: 24px;
}
/* Collapsed sidebar: centre icons, hide text */
.sidebar--collapsed .nav-group__label {
display: none;
}
.sidebar--collapsed .nav-group {
gap: 4px;
margin-bottom: 0;
}
/* In collapsed sidebar, always show nav items (icon-only) regardless of group collapse state */
.sidebar--collapsed .nav-group--collapsed .nav-group__items {
display: grid;
}
.sidebar--collapsed .nav-item {
justify-content: center;
width: 44px;
height: 42px;
padding: 0;
margin: 0 auto;
border-radius: 16px;
}
.sidebar--collapsed .nav-item__icon {
width: 18px;
height: 18px;
opacity: 0.78;
}
.sidebar--collapsed .nav-item__icon svg {
width: 18px;
height: 18px;
}
.sidebar--collapsed .nav-item__text {
display: none;
}
.sidebar--collapsed .nav-item__external-icon {
display: none;
}
/* Footer: docs link + version */
.sidebar-footer {
flex-shrink: 0;
padding: 8px;
border-top: 1px solid var(--border);
}
.sidebar--collapsed .sidebar-footer {
padding: 12px 8px 10px;
}
.sidebar-footer__docs-block {
display: flex;
flex-direction: column;
align-items: center;
gap: 4px;
}
.sidebar--collapsed .sidebar-footer__docs-block {
align-items: center;
gap: 10px;
}
.sidebar--collapsed .sidebar-footer .nav-item {
justify-content: center;
width: 44px;
height: 44px;
padding: 0;
}
.sidebar-version {
display: flex;
align-items: center;
justify-content: center;
padding: 4px 10px;
}
.sidebar-version__text {
font-size: 11px;
color: var(--muted);
font-weight: 500;
letter-spacing: 0.02em;
}
.sidebar-version__dot {
width: 8px;
height: 8px;
border-radius: var(--radius-full);
background: color-mix(in srgb, var(--accent) 78%, white 22%);
box-shadow: 0 0 0 4px color-mix(in srgb, var(--accent) 14%, transparent);
opacity: 1;
margin: 0 auto;
}
/* Drag-to-resize handle */
.sidebar-resizer {
width: 3px;
cursor: col-resize;
flex-shrink: 0;
background: transparent;
transition: background var(--duration-fast) ease;
position: relative;
}
.sidebar-resizer::after {
content: "";
position: absolute;
top: 0;
bottom: 0;
left: 0;
width: 3px;
background: transparent;
transition: background var(--duration-fast) ease;
}
.sidebar-resizer:hover::after {
background: var(--accent);
opacity: 0.35;
}
.sidebar-resizer:active::after {
background: var(--accent);
opacity: 0.6;
}
/* Shell-level collapsed / focus overrides */
.shell--nav-collapsed .shell-nav {
width: var(--shell-nav-rail-width);
min-width: var(--shell-nav-rail-width);
}
.shell--chat-focus .shell-nav {
width: 0;
min-width: 0;
overflow: hidden;
pointer-events: none;
opacity: 0;
}
/* Nav collapse toggle */
.nav-collapse-toggle {
width: 28px;
height: 28px;
display: flex;
align-items: center;
justify-content: center;
background: transparent;
border: 1px solid transparent;
border-radius: var(--radius-sm);
cursor: pointer;
transition:
background var(--duration-fast) ease,
border-color var(--duration-fast) ease,
color var(--duration-fast) ease;
margin-bottom: 0;
color: var(--muted);
}
.nav-collapse-toggle:hover {
background: var(--bg-hover);
color: var(--text);
}
.nav-collapse-toggle__icon {
display: flex;
align-items: center;
justify-content: center;
width: 16px;
height: 16px;
color: inherit;
}
.nav-collapse-toggle__icon svg {
width: 16px;
height: 16px;
stroke: currentColor;
fill: none;
stroke-width: 1.5px;
stroke-linecap: round;
stroke-linejoin: round;
}
.nav-collapse-toggle:hover .nav-collapse-toggle__icon {
color: inherit;
}
/* Nav groups */
.nav-group {
margin-bottom: 12px;
display: grid;
gap: 1px;
}
.nav-group:last-child {
margin-bottom: 0;
}
.nav-group__items {
display: grid;
gap: 1px;
}
.nav-group--collapsed .nav-group__items {
display: none;
}
.nav-group__label {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
width: 100%;
padding: 5px 10px;
font-size: 10px;
font-weight: 600;
color: var(--muted);
margin-bottom: 2px;
background: transparent;
border: none;
cursor: pointer;
text-align: left;
text-transform: uppercase;
letter-spacing: 0.06em;
border-radius: var(--radius-sm);
transition:
color var(--duration-fast) ease,
background var(--duration-fast) ease;
}
.nav-group__label:hover {
color: var(--text);
background: var(--bg-hover);
}
.nav-group__label--static {
cursor: default;
}
.nav-group__label--static:hover {
color: var(--muted);
background: transparent;
}
.nav-group__label-text {
flex: 1;
}
.nav-group__chevron {
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 10px;
opacity: 0.5;
transition: transform var(--duration-fast) ease;
}
.nav-group__chevron svg {
width: 12px;
height: 12px;
stroke: currentColor;
fill: none;
stroke-width: 1.5px;
stroke-linecap: round;
stroke-linejoin: round;
}
.nav-group--collapsed .nav-group__chevron {
transform: rotate(-90deg);
}
/* Nav items */
.nav-item {
position: relative;
display: flex;
align-items: center;
justify-content: flex-start;
gap: 8px;
padding: 7px 10px;
border-radius: var(--radius-md);
border: 1px solid transparent;
background: transparent;
color: var(--muted);
cursor: pointer;
text-decoration: none;
transition:
border-color var(--duration-fast) ease,
background var(--duration-fast) ease,
color var(--duration-fast) ease;
}
.nav-item__icon {
width: 15px;
height: 15px;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
opacity: 0.6;
transition: opacity var(--duration-fast) ease;
}
.nav-item__icon svg {
width: 15px;
height: 15px;
stroke: currentColor;
fill: none;
stroke-width: 1.5px;
stroke-linecap: round;
stroke-linejoin: round;
}
.nav-item__text {
font-size: 13px;
font-weight: 450;
white-space: nowrap;
}
.nav-item:hover {
color: var(--text);
background: var(--bg-hover);
text-decoration: none;
}
.nav-item:hover .nav-item__icon {
opacity: 0.9;
}
.nav-item.active,
.nav-item--active {
color: var(--text-strong);
background: var(--accent-subtle);
border-color: color-mix(in srgb, var(--accent) 15%, transparent);
}
.nav-item.active .nav-item__icon,
.nav-item--active .nav-item__icon {
opacity: 1;
color: var(--accent);
}
.sidebar--collapsed .nav-item--active::before,
.sidebar--collapsed .nav-item.active::before {
content: "";
position: absolute;
left: 6px;
top: 11px;
bottom: 11px;
width: 2px;
border-radius: 999px;
background: color-mix(in srgb, var(--accent) 78%, transparent);
}
.sidebar--collapsed .nav-item.active,
.sidebar--collapsed .nav-item--active {
background: color-mix(in srgb, var(--accent-subtle) 88%, var(--bg-elevated) 12%);
border-color: color-mix(in srgb, var(--accent) 12%, var(--border) 88%);
box-shadow: inset 0 1px 0 color-mix(in srgb, var(--text) 6%, transparent);
}
.sidebar--collapsed .nav-collapse-toggle {
width: 44px;
height: 34px;
margin-bottom: 0;
border-color: color-mix(in srgb, var(--border-strong) 74%, transparent);
border-radius: var(--radius-full);
background: color-mix(in srgb, var(--bg-elevated) 92%, transparent);
box-shadow:
inset 0 1px 0 color-mix(in srgb, var(--text) 8%, transparent),
0 8px 18px color-mix(in srgb, black 16%, transparent);
}
.sidebar--collapsed .nav-collapse-toggle:hover {
border-color: color-mix(in srgb, var(--border-strong) 72%, transparent);
background: color-mix(in srgb, var(--bg-elevated) 96%, transparent);
}
.nav-item__external-icon {
width: 12px;
height: 12px;
display: inline-flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
margin-left: auto;
opacity: 0;
transition: opacity var(--duration-fast) ease;
}
.nav-item__external-icon svg {
width: 12px;
height: 12px;
stroke: currentColor;
fill: none;
stroke-width: 1.5px;
stroke-linecap: round;
stroke-linejoin: round;
}
.nav-item:hover .nav-item__external-icon {
opacity: 0.5;
}
/* ===========================================
Content Area
=========================================== */
.content {
grid-area: content;
padding: 16px 20px 32px;
display: block;
min-height: 0;
overflow-y: auto;
overflow-x: hidden;
}
.content>*+* {
margin-top: 20px;
}
:root[data-theme-mode="light"] .content {
background: var(--bg-content);
}
.content--chat {
display: flex;
flex-direction: column;
gap: 24px;
overflow: hidden;
padding-bottom: 0;
}
.content--chat>*+* {
margin-top: 0;
}
/* Content header */
.content-header {
display: flex;
align-items: flex-end;
justify-content: space-between;
gap: 16px;
padding: 4px 8px;
overflow: hidden;
transform-origin: top center;
transition:
opacity var(--shell-focus-duration) var(--shell-focus-ease),
transform var(--shell-focus-duration) var(--shell-focus-ease),
max-height var(--shell-focus-duration) var(--shell-focus-ease),
padding var(--shell-focus-duration) var(--shell-focus-ease);
max-height: 80px;
}
.shell--chat-focus .content-header {
opacity: 0;
transform: translateY(-8px);
max-height: 0px;
padding: 0;
pointer-events: none;
}
.page-title {
font-size: 22px;
font-weight: 650;
letter-spacing: -0.03em;
line-height: 1.2;
color: var(--text-strong);
}
.page-sub {
color: var(--muted);
font-size: 13px;
font-weight: 400;
margin-top: 4px;
letter-spacing: -0.005em;
}
.page-meta {
display: flex;
gap: 8px;
}
/* Chat view header adjustments */
.content--chat .content-header {
flex-direction: row;
align-items: center;
justify-content: space-between;
gap: 16px;
}
.content--chat .content-header>div:first-child {
text-align: left;
}
.content--chat .page-meta {
justify-content: flex-start;
}
.content--chat .chat-controls {
flex-shrink: 0;
}
/* ===========================================
Grid Utilities
=========================================== */
.grid {
display: grid;
gap: 20px;
}
.grid-cols-2 {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.grid-cols-3 {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
.stat-grid {
display: grid;
gap: 14px;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
}
.note-grid {
display: grid;
gap: 16px;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
}
.row {
display: flex;
gap: 12px;
align-items: center;
}
.stack {
display: grid;
gap: 12px;
grid-template-columns: minmax(0, 1fr);
}
.filters {
display: flex;
flex-wrap: wrap;
gap: 8px;
align-items: center;
}
/* ===========================================
Responsive - Tablet
=========================================== */
@media (max-width: 1100px) {
.shell {
--shell-pad: 12px;
--shell-gap: 12px;
grid-template-columns: 1fr;
grid-template-rows: auto auto 1fr;
grid-template-areas:
"topbar"
"nav"
"content";
}
.nav-group {
grid-auto-flow: column;
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
margin-bottom: 0;
}
.grid-cols-2,
.grid-cols-3 {
grid-template-columns: 1fr;
}
.topbar {
position: static;
padding: 12px 14px;
gap: 10px;
}
.topbar-status {
flex-wrap: wrap;
}
.table-head,
.table-row {
grid-template-columns: 1fr;
}
.list-item {
grid-template-columns: 1fr;
}
}