mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-10-20 22:02:20 +02:00
1290 lines
46 KiB
CSS
1290 lines
46 KiB
CSS
/* 07-documents - part of the former static/style.css.
|
||
*
|
||
* The stylesheet is split by area, but the split is mechanical: rules were
|
||
* moved verbatim and NOT regrouped. The numeric prefix is the load order, and
|
||
* that order is what preserves the cascade. A rule sits in the file its
|
||
* original position fell into, so an area's rules are not all in its file and
|
||
* a file is not only that area's rules.
|
||
*
|
||
* Do not reorder the <link> tags in static/index.html, and do not move a rule
|
||
* between files: with 1,151 redeclarations and 1,886 !important in this
|
||
* cascade, either can change which declaration wins.
|
||
*
|
||
* static/index.html and the PRECACHE list in static/sw.js must agree on this
|
||
* order. tests/test_static_stylesheet_manifest.py and
|
||
* tests/test_css_computed_style_snapshot.py fail if that drifts.
|
||
*/
|
||
.modal.modal-left-docked {
|
||
align-items: stretch;
|
||
justify-content: flex-start;
|
||
}
|
||
.modal.modal-left-docked .modal-content {
|
||
border-right: 1px solid var(--border);
|
||
box-shadow: 4px 0 14px rgba(0, 0, 0, 0.18);
|
||
border-radius: 0;
|
||
/* Pin transitions OFF on the dock's positioning properties. The wide
|
||
sidebar collapse/expand changes --sidebar-w instantly, which means
|
||
the docked modal's `left: calc(...)` jumps by ~240px. Any CSS
|
||
transition on `left` (inherited or otherwise) would animate that
|
||
jump as a fly-across. Same defense for right-docked / fullscreen
|
||
panels in case future themes add a generic transition. */
|
||
transition: none !important;
|
||
}
|
||
.modal.modal-right-docked .modal-content,
|
||
#email-lib-modal.email-lib-fullscreen .modal-content,
|
||
#doclib-modal.doclib-fullscreen .doclib-modal-content {
|
||
transition: none !important;
|
||
}
|
||
.modal.modal-right-docked .email-reader-header,
|
||
.modal.modal-left-docked .email-reader-header {
|
||
flex-direction: column;
|
||
/* Stretch the meta to the full header width so the absolute
|
||
action cluster's right:0 lands at the right edge (was sizing
|
||
meta to chip content width and centering it). */
|
||
align-items: stretch;
|
||
gap: 6px;
|
||
}
|
||
/* Docked panes: 4px between From→To and 4px between To→Cc.
|
||
Meta has its own 2px gap (From→details) so an extra 2px on
|
||
details margin-top gives a 4px From→To distance, and gap:4 on
|
||
the details flex column gives 4px between To and Cc. */
|
||
.modal.modal-right-docked .email-reader-meta-details,
|
||
.modal.modal-left-docked .email-reader-meta-details {
|
||
margin-top: 2px;
|
||
gap: 4px;
|
||
}
|
||
/* Docked: always show To/Cc — there's vertical room reserved for
|
||
the action cluster already and the chevron toggle just adds
|
||
friction. Force the hidden attribute open and hide the chevron. */
|
||
.modal.modal-right-docked .email-reader-meta-details[hidden],
|
||
.modal.modal-left-docked .email-reader-meta-details[hidden] {
|
||
display: flex !important;
|
||
}
|
||
.modal.modal-right-docked .email-reader-meta-toggle,
|
||
.modal.modal-left-docked .email-reader-meta-toggle {
|
||
display: none;
|
||
}
|
||
.modal.modal-right-docked .email-reader-header > .email-reader-actions,
|
||
.modal.modal-left-docked .email-reader-header > .email-reader-actions {
|
||
position: static;
|
||
align-self: flex-end;
|
||
background: none;
|
||
padding-left: 0;
|
||
}
|
||
/* Docked modal: keep all meta rows as flex so From / To / Cc
|
||
labels align at the same x. Chips already overflow-scroll
|
||
inside each row when there are too many. No per-row margin-top
|
||
here — the spacing between rows comes entirely from
|
||
.email-reader-meta-details gap so From→To and To→Cc match. */
|
||
.modal.modal-right-docked .email-reader-meta-row:not(.email-reader-meta-from),
|
||
.modal.modal-left-docked .email-reader-meta-row:not(.email-reader-meta-from) {
|
||
padding-right: 0;
|
||
}
|
||
.modal.modal-right-docked .email-reader-meta-row strong,
|
||
.modal.modal-left-docked .email-reader-meta-row strong {
|
||
min-width: 0;
|
||
}
|
||
.modal.modal-right-docked .recipient-chip,
|
||
.modal.modal-left-docked .recipient-chip {
|
||
max-width: 100%;
|
||
}
|
||
.archive-list {
|
||
margin-top: 8px;
|
||
border-top: 1px solid var(--border);
|
||
padding-top: 8px;
|
||
}
|
||
#archive-modal .memory-sort-select,
|
||
#archive-modal .memory-toolbar-btn {
|
||
height: 32px;
|
||
}
|
||
.archive-menu-btn {
|
||
position: relative;
|
||
top: 2px;
|
||
}
|
||
#archive-chips .doclib-chip {
|
||
height: 22px;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
font-size: 10px;
|
||
padding: 0 8px;
|
||
}
|
||
/* Library tab panels — Chats / Archive / Research / Documents share the
|
||
same toolbar dimensions so the sort dropdown + Select button line up
|
||
identically across tabs. */
|
||
#doclib-panel-chats .memory-sort-select,
|
||
#doclib-panel-archive .memory-sort-select,
|
||
#doclib-panel-research .memory-sort-select,
|
||
[data-doclib-panel="documents"] .memory-sort-select {
|
||
height: 24px;
|
||
font-size: 11px;
|
||
width: 86px;
|
||
}
|
||
#doclib-panel-chats .memory-toolbar-btn,
|
||
#doclib-panel-archive .memory-toolbar-btn,
|
||
#doclib-panel-research .memory-toolbar-btn,
|
||
[data-doclib-panel="documents"] .memory-toolbar-btn {
|
||
height: 24px;
|
||
font-size: 11px;
|
||
position: relative;
|
||
top: -3px;
|
||
}
|
||
/* Research's Recent (sort) + Select sat 1px lower than the other tabs — nudge up. */
|
||
#doclib-panel-research .memory-sort-select { position: relative; top: 1.5px; }
|
||
#doclib-panel-research .memory-toolbar-btn { top: -4.5px; }
|
||
.library-sort-picker {
|
||
width: 108px;
|
||
flex: 0 0 108px;
|
||
top: 1px;
|
||
}
|
||
.library-sort-picker .library-sort-btn {
|
||
top: 0;
|
||
width: 100%;
|
||
}
|
||
.library-sort-picker .library-sort-menu {
|
||
top: calc(100% + 4px);
|
||
width: max(100%, 154px);
|
||
}
|
||
.library-sort-picker .library-sort-item[aria-selected="true"] {
|
||
background: color-mix(in srgb, var(--accent, var(--red)) 13%, transparent);
|
||
}
|
||
#doclib-panel-chats #doclib-chats-tidy-btn,
|
||
#doclib-panel-chats #doclib-chats-select-btn,
|
||
#doclib-panel-archive #doclib-arc-select-btn {
|
||
top: 1px;
|
||
}
|
||
#doclib-panel-chats .doclib-chip-scroll-arrow {
|
||
top: calc(50% - 9px) !important;
|
||
}
|
||
[data-doclib-panel="documents"] .doclib-chip-scroll-arrow {
|
||
top: calc(50% - 9px) !important;
|
||
}
|
||
#doclib-modal .doclib-chip-scroll-arrow {
|
||
top: calc(50% - 19px) !important;
|
||
}
|
||
[data-doclib-panel="documents"] #doclib-tidy-btn,
|
||
[data-doclib-panel="documents"] #doclib-select-btn {
|
||
top: 1px;
|
||
}
|
||
#doclib-panel-research #doclib-research-tidy-btn,
|
||
#doclib-panel-research #doclib-research-select-btn {
|
||
top: -0.5px;
|
||
}
|
||
#doclib-panel-research .library-sort-picker { top: -0.5px; }
|
||
[data-doclib-panel] { padding-top: 6px !important; }
|
||
#doclib-panel-chats, #doclib-panel-archive { padding-top: 14px !important; }
|
||
#doclib-panel-chats .memory-desc, #doclib-panel-archive .memory-desc, #doclib-panel-research .memory-desc { margin-top: 7px; }
|
||
#doclib-panel-chats .memory-search-input,
|
||
#doclib-panel-archive .memory-search-input {
|
||
height: 30px !important;
|
||
min-height: 30px !important;
|
||
flex-shrink: 0;
|
||
font-size: 11px;
|
||
}
|
||
/* Unified search bar across Library tabs + Memory modal — same height,
|
||
same magnifying-glass icon at the start, consistent padding. */
|
||
#doclib-panel-chats .memory-search-input,
|
||
#doclib-panel-archive .memory-search-input,
|
||
#doclib-panel-research .memory-search-input,
|
||
[data-doclib-panel="documents"] .memory-search-input,
|
||
#memory-modal .memory-search-input,
|
||
#tasks-modal .memory-search-input {
|
||
height: 30px;
|
||
min-height: 30px;
|
||
font-size: 11px;
|
||
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23e06c75' stroke-opacity='0.85' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><circle cx='11' cy='11' r='8'/><line x1='21' y1='21' x2='16.65' y2='16.65'/></svg>");
|
||
background-repeat: no-repeat;
|
||
background-position: 9px center;
|
||
padding-left: 28px;
|
||
}
|
||
#doclib-panel-chats .doclib-chip {
|
||
height: 28px;
|
||
}
|
||
#doclib-panel-archive .doclib-chip {
|
||
height: 28px;
|
||
}
|
||
#doclib-panel-chats .doclib-chip,
|
||
#doclib-panel-archive .doclib-chip {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
font-size: 9px;
|
||
padding: 0 8px;
|
||
border-radius: 10px;
|
||
}
|
||
.doclib-grid:has(.doclib-card-expanded) > .doclib-card:not(.doclib-card-expanded) {
|
||
display: none;
|
||
}
|
||
/* Hide everything except the grid when a card is expanded */
|
||
.admin-card:has(.doclib-card-expanded) > *:not(.doclib-grid):not(.hwfit-cached-list) {
|
||
opacity: 0;
|
||
max-height: 0;
|
||
overflow: hidden;
|
||
pointer-events: none;
|
||
margin: 0 !important;
|
||
padding: 0 !important;
|
||
transition: opacity 0.12s ease, max-height 0.2s ease;
|
||
}
|
||
.admin-card:has(.doclib-card-expanded) > .memory-bulk-bar {
|
||
display: none;
|
||
}
|
||
.admin-card:has(.doclib-card-expanded) > .doclib-grid,
|
||
.admin-card:has(.doclib-card-expanded) > .hwfit-cached-list {
|
||
max-height: none !important;
|
||
min-height: 0 !important;
|
||
overflow: visible !important;
|
||
}
|
||
/* Firefox-mobile (no :has()) fallback: when reading an email, fully remove the
|
||
list-mode chrome (accounts row, toolbar, bulk bar, desc) — display:none so no
|
||
residual flex-gap leaves an empty strip above the reader — and zero the
|
||
admin-card gap so the grid/reader starts flush at the top. */
|
||
#email-lib-modal.email-reading .admin-card > *:not(.doclib-grid):not(.hwfit-cached-list) {
|
||
display: none !important;
|
||
}
|
||
#email-lib-modal .admin-card:has(.doclib-card-expanded),
|
||
#email-lib-modal.email-reading .admin-card {
|
||
gap: 0 !important;
|
||
padding: 0 !important;
|
||
margin-bottom: 0 !important;
|
||
border: 0 !important;
|
||
border-radius: 0 !important;
|
||
background: transparent !important;
|
||
}
|
||
/* Override for chat-rows + research-rows: those expand inline with a
|
||
bounded preview (max-height: 60vh), so the grid must stay clipped
|
||
and scrollable. Without this scoping the overflow:visible above lets
|
||
the expanded chat preview escape the grid and overlap whatever's
|
||
underneath/beside the modal (e.g., a docked sibling panel) — what
|
||
the user calls "merging with other windows". */
|
||
.admin-card:has(.doclib-chat-row.doclib-card-expanded) > .doclib-grid {
|
||
overflow: hidden auto !important;
|
||
}
|
||
/* Email modal needs the grid to STAY a constrained flex container when
|
||
expanded — overflow:visible (set above for cookbook) lets content escape
|
||
instead of letting the expanded reader fill via flex:1. We keep the same
|
||
max-height:none + min-height:0 but flip overflow back so the reader
|
||
actually fills the modal. */
|
||
#email-lib-modal .admin-card:has(.doclib-card-expanded) > .doclib-grid,
|
||
#email-lib-modal.email-reading .admin-card > .doclib-grid {
|
||
overflow: hidden !important;
|
||
display: flex !important;
|
||
flex: 1 1 auto !important;
|
||
}
|
||
#email-lib-modal.email-reading #email-lib-grid > .date-section-header {
|
||
display: none !important;
|
||
}
|
||
#email-lib-modal.email-reading .doclib-modal-content {
|
||
min-height: var(--email-reading-modal-min-h, auto);
|
||
}
|
||
#email-lib-modal .doclib-card.doclib-card-expanded {
|
||
flex: 1 1 auto !important;
|
||
height: 100% !important;
|
||
/* Neutral frame on the active email — the accent border + glow felt
|
||
overbearing on desktop; the size jump alone is enough signal. */
|
||
border: 1px solid var(--border) !important;
|
||
box-shadow: 0 6px 18px rgba(0,0,0,0.12) !important;
|
||
animation: none !important;
|
||
}
|
||
/* Desktop-only, ONLY on the currently-expanded email card. Nudges the title
|
||
row down 6px / right 2px, bolds the subject, hides the timestamp from the
|
||
meta line (the reader header carries its own date), and pulls the prev/next
|
||
nav arrows in 4px. */
|
||
@media (min-width: 769px) {
|
||
#email-lib-modal .doclib-card-expanded .email-card-titlerow,
|
||
#email-lib-modal .doclib-card-expanded .email-card-titlerow > * {
|
||
position: relative;
|
||
top: 6px;
|
||
left: 2px;
|
||
}
|
||
/* Smaller subject — the reader header below already carries weight. */
|
||
#email-lib-modal .doclib-card-expanded .email-card-titlerow .memory-item-title {
|
||
font-weight: 700;
|
||
font-size: 12px;
|
||
}
|
||
/* A bit more breathing room around the title row so the smaller bold text
|
||
doesn't crowd the meta line below. (Timestamp kept — user changed mind.) */
|
||
#email-lib-modal .doclib-card-expanded .email-card-titlerow {
|
||
padding: 4px 0 6px;
|
||
line-height: 1.35;
|
||
}
|
||
/* Nudge the date down/left in the meta row, and give the meta line +4px of
|
||
extra bottom space so the shifted date isn't clipped. */
|
||
#email-lib-modal .doclib-card-expanded .email-meta-date {
|
||
position: relative;
|
||
top: 4px;
|
||
left: 0;
|
||
}
|
||
#email-lib-modal .doclib-card-expanded .memory-item-meta {
|
||
padding-bottom: 4px;
|
||
}
|
||
#email-lib-modal .doclib-card-expanded .email-card-nav-arrows {
|
||
position: relative;
|
||
left: -4px;
|
||
}
|
||
}
|
||
/* Skills modal: same mechanism as email above. The default expanded-grid
|
||
rule (overflow:visible, no flex) lets the card expand inline to ~content
|
||
height instead of filling — which is why the skill preview stopped at
|
||
partial height. Flip the grid back to a constrained flex container and
|
||
let the expanded card fill it, exactly like the email reader. */
|
||
#memory-modal .admin-card:has(.doclib-card-expanded) > .doclib-grid {
|
||
overflow: hidden !important;
|
||
display: flex !important;
|
||
flex-direction: column !important;
|
||
flex: 1 1 auto !important;
|
||
}
|
||
#memory-modal .doclib-card.doclib-card-expanded {
|
||
flex: 1 1 auto !important;
|
||
height: 100% !important;
|
||
}
|
||
#email-lib-modal .modal-content {
|
||
transition: width 0.22s ease-out, height 0.22s ease-out;
|
||
}
|
||
@media (min-width: 769px) {
|
||
body:not(.email-doc-split-active) #email-lib-modal:not(.email-lib-fullscreen):not(.modal-left-docked):not(.modal-right-docked) .modal-content:not([style*="height"]) {
|
||
min-height: min(560px, 85vh);
|
||
}
|
||
}
|
||
|
||
/* Serve panel specifically: the admin-card inline style is
|
||
`overflow:hidden` (so the toolbar/header don't drift), and the list
|
||
inside has overflow:visible. On short windows that combination
|
||
clipped the cards off the bottom with no scrollbar. Make the list
|
||
itself the scroll surface so the rest of the card stays put. */
|
||
.cookbook-group[data-backend-group="Serve"] > .admin-card {
|
||
min-height: 0;
|
||
}
|
||
.cookbook-group[data-backend-group="Serve"] > .admin-card > #hwfit-cached-list,
|
||
.cookbook-group[data-backend-group="Serve"] > .admin-card > .hwfit-cached-list {
|
||
flex: 1 1 0;
|
||
min-height: 0;
|
||
overflow-y: auto !important;
|
||
overscroll-behavior: contain;
|
||
}
|
||
.cookbook-group[data-backend-group="Serve"] > .admin-card > .hwfit-cached-list .doclib-card.doclib-card-expanded {
|
||
flex: 0 0 auto !important;
|
||
overflow: visible !important;
|
||
}
|
||
/* Launch model cards use the same domino entrance as the other library lists
|
||
when a cached-model scan finishes. The class is removed after the one-shot
|
||
entrance, so filtering and sorting stay instantaneous. */
|
||
#cookbook-modal .hwfit-cached-list.cookbook-serve-models-just-loaded > .doclib-card {
|
||
animation: section-domino-in 0.36s cubic-bezier(0.22, 1.61, 0.36, 1) backwards;
|
||
}
|
||
#cookbook-modal .hwfit-cached-list.cookbook-serve-models-just-loaded > .doclib-card:nth-child(1) { animation-delay: 0.04s; }
|
||
#cookbook-modal .hwfit-cached-list.cookbook-serve-models-just-loaded > .doclib-card:nth-child(2) { animation-delay: 0.08s; }
|
||
#cookbook-modal .hwfit-cached-list.cookbook-serve-models-just-loaded > .doclib-card:nth-child(3) { animation-delay: 0.12s; }
|
||
#cookbook-modal .hwfit-cached-list.cookbook-serve-models-just-loaded > .doclib-card:nth-child(4) { animation-delay: 0.16s; }
|
||
#cookbook-modal .hwfit-cached-list.cookbook-serve-models-just-loaded > .doclib-card:nth-child(5) { animation-delay: 0.20s; }
|
||
#cookbook-modal .hwfit-cached-list.cookbook-serve-models-just-loaded > .doclib-card:nth-child(6) { animation-delay: 0.24s; }
|
||
#cookbook-modal .hwfit-cached-list.cookbook-serve-models-just-loaded > .doclib-card:nth-child(7) { animation-delay: 0.28s; }
|
||
#cookbook-modal .hwfit-cached-list.cookbook-serve-models-just-loaded > .doclib-card:nth-child(8) { animation-delay: 0.32s; }
|
||
#cookbook-modal .hwfit-cached-list.cookbook-serve-models-just-loaded > .doclib-card:nth-child(9) { animation-delay: 0.36s; }
|
||
#cookbook-modal .hwfit-cached-list.cookbook-serve-models-just-loaded > .doclib-card:nth-child(10) { animation-delay: 0.40s; }
|
||
#cookbook-modal .hwfit-cached-list.cookbook-serve-models-just-loaded > .doclib-card:nth-child(11) { animation-delay: 0.44s; }
|
||
#cookbook-modal .hwfit-cached-list.cookbook-serve-models-just-loaded > .doclib-card:nth-child(12) { animation-delay: 0.48s; }
|
||
#cookbook-modal .hwfit-cached-list.cookbook-serve-models-just-loaded > .doclib-card:nth-child(n+13) { animation-delay: 0.48s; }
|
||
@media (prefers-reduced-motion: reduce) {
|
||
#cookbook-modal .hwfit-cached-list.cookbook-serve-models-just-loaded > .doclib-card {
|
||
animation: none;
|
||
}
|
||
}
|
||
/* Drag-and-drop visual hint for the email compose pane. Subtle accent
|
||
outline + tinted overlay so it's obvious files will attach if dropped. */
|
||
.doc-editor-pane.email-dragover {
|
||
outline: 2px dashed var(--accent, #2563eb);
|
||
outline-offset: -8px;
|
||
background: color-mix(in srgb, var(--accent, #2563eb) 6%, transparent);
|
||
}
|
||
.doc-editor-pane.email-dragover::after {
|
||
content: 'Drop to attach';
|
||
position: absolute;
|
||
top: 50%;
|
||
left: 50%;
|
||
transform: translate(-50%, -50%);
|
||
background: var(--accent, #2563eb);
|
||
color: #fff;
|
||
padding: 8px 16px;
|
||
border-radius: 6px;
|
||
font-size: 12px;
|
||
pointer-events: none;
|
||
z-index: 1000;
|
||
}
|
||
|
||
/* Email reader window — make the body always fill the available vertical
|
||
space regardless of how the window is positioned/resized. The user can
|
||
drag the bottom-right corner to resize; the body re-flexes automatically. */
|
||
.email-window-modal .modal-content {
|
||
display: flex !important;
|
||
flex-direction: column !important;
|
||
resize: both;
|
||
overflow: hidden;
|
||
min-width: 320px;
|
||
min-height: 240px;
|
||
/* When user resizes/drags so the window covers a side, force the inner
|
||
body to fill all the way to the bottom. The default max-height: 85vh
|
||
(set inline by _makeDraggable's exitFullscreen) and 80vh from the
|
||
opener both cap at the *viewport* — if the browser window then changes
|
||
size (e.g. OS aero-snap), the modal stays at the old height and
|
||
truncates rows. Drop the cap whenever an explicit width OR height has
|
||
been written inline by the resize handle / drag handler. */
|
||
}
|
||
.email-window-modal .modal-content[style*="width"],
|
||
.email-window-modal .modal-content[style*="height"] {
|
||
max-height: calc(100vh - 16px) !important;
|
||
}
|
||
.email-window-modal .email-window-body {
|
||
flex: 1 1 auto !important;
|
||
min-height: 0 !important;
|
||
/* Explicit basis of 0 makes the body grow to fill remaining space rather
|
||
than its content's intrinsic height (which was capping the thread). */
|
||
flex-basis: 0 !important;
|
||
max-height: none !important;
|
||
overflow: auto !important;
|
||
overscroll-behavior: contain;
|
||
}
|
||
|
||
/* Individual email reader window — fullscreen mode (drag-to-top snap or
|
||
double-click header). Same recipe as the library modal: pin to viewport
|
||
edges and let the inner body absorb the remaining height. */
|
||
body:not(.email-doc-split-active) .email-window-modal.email-window-fullscreen .modal-content {
|
||
position: fixed !important;
|
||
inset: var(--safe-top) var(--safe-right) var(--safe-bottom) var(--safe-left) !important;
|
||
width: auto !important;
|
||
max-width: none !important;
|
||
height: auto !important;
|
||
max-height: none !important;
|
||
border-radius: 0 !important;
|
||
transform: none !important;
|
||
display: flex !important;
|
||
flex-direction: column !important;
|
||
}
|
||
body:not(.email-doc-split-active) .email-window-modal.email-window-fullscreen .email-window-body {
|
||
flex: 1 1 auto !important;
|
||
min-height: 0 !important;
|
||
max-height: none !important;
|
||
}
|
||
|
||
/* Email library modal: fullscreen mode + larger mobile sheet (mirrors the
|
||
cookbook treatment so the toolbar and bulk actions stay reachable).
|
||
Leaves whichever navigation strip is currently visible on the left
|
||
(the wide sidebar OR the icon rail — they're mutually exclusive, so
|
||
one of the two CSS vars is 0 at any given time, set by init.js). */
|
||
body:not(.email-doc-split-active) #email-lib-modal.email-lib-fullscreen:not(.modal-right-docked) .modal-content {
|
||
position: fixed !important;
|
||
top: var(--safe-top) !important;
|
||
left: calc(var(--safe-left) + var(--icon-rail-w, 48px) + var(--sidebar-w, 0px)) !important;
|
||
right: var(--safe-right) !important;
|
||
bottom: var(--safe-bottom) !important;
|
||
width: auto !important;
|
||
max-width: none !important;
|
||
height: auto !important;
|
||
max-height: none !important;
|
||
border-radius: 0 !important;
|
||
transform: none !important;
|
||
}
|
||
@media (min-width: 769px) {
|
||
body.hamburger-right:not(.email-doc-split-active) #email-lib-modal.email-lib-fullscreen:not(.modal-right-docked) .modal-content {
|
||
left: var(--safe-left) !important;
|
||
right: calc(var(--safe-right) + var(--icon-rail-w, 48px) + var(--sidebar-w, 0px)) !important;
|
||
}
|
||
}
|
||
/* Mobile: the /email route adds .email-lib-fullscreen, but the desktop full-
|
||
bleed rule above squares off the corners and offsets the email by the icon
|
||
rail. On phones the email should be the normal bottom-sheet — full width,
|
||
rounded top corners. Same specificity as the rule above + later in source,
|
||
so it wins on mobile. */
|
||
@media (max-width: 768px) {
|
||
body:not(.email-doc-split-active) #email-lib-modal.email-lib-fullscreen:not(.modal-right-docked) .modal-content {
|
||
top: var(--sheet-top) !important;
|
||
left: var(--safe-left) !important;
|
||
right: var(--safe-right) !important;
|
||
bottom: 0 !important;
|
||
width: auto !important;
|
||
max-width: none !important;
|
||
height: auto !important;
|
||
max-height: none !important;
|
||
border-radius: 14px 14px 0 0 !important;
|
||
border-top: 1px solid var(--border) !important;
|
||
}
|
||
}
|
||
/* Make the inner panes actually grow to fill the fullscreen container
|
||
instead of staying at their natural size. The body owns the remaining
|
||
height below the header; the admin-card + grid then expand into it. */
|
||
#email-lib-modal.email-lib-fullscreen .modal-body {
|
||
flex: 1 1 auto !important;
|
||
min-height: 0 !important;
|
||
overflow: hidden !important;
|
||
}
|
||
#email-lib-modal.email-lib-fullscreen .modal-body > .admin-card {
|
||
flex: 1 1 auto !important;
|
||
min-height: 0 !important;
|
||
}
|
||
#email-lib-modal.email-lib-fullscreen .doclib-grid {
|
||
flex: 1 1 auto !important;
|
||
min-height: 0 !important;
|
||
max-height: none !important;
|
||
overflow: auto !important;
|
||
}
|
||
@media (max-width: 768px) {
|
||
/* Mobile email modal sizing — keep in sync with the rule earlier in the
|
||
file. 75dvh tall always so flex children (the expanded email reader)
|
||
have a real height to grow into. */
|
||
#email-lib-modal .modal-content {
|
||
max-height: 90dvh !important;
|
||
max-height: 90vh !important;
|
||
height: 90dvh !important;
|
||
height: 90vh !important;
|
||
}
|
||
/* Inner panes grow to fill the modal-content — without flex:1 on the
|
||
body, the expanded email reader sits in a tiny box because there's
|
||
nothing pushing it to take the remaining height. overflow:hidden +
|
||
min-height:0 lets each layer pass its constraints down. */
|
||
#email-lib-modal .modal-body,
|
||
#email-lib-modal .admin-card {
|
||
flex: 1 1 auto !important;
|
||
min-height: 0 !important;
|
||
overflow: hidden !important;
|
||
max-height: none !important;
|
||
}
|
||
#email-lib-modal .doclib-grid {
|
||
flex: 1 1 auto !important;
|
||
min-height: 0 !important;
|
||
max-height: none !important;
|
||
overflow-y: auto !important;
|
||
}
|
||
/* modal-content keeps its scroll OFF here — the inner flex children
|
||
(doclib-grid for the list view, email-reader-body for the expanded
|
||
reader) own the scroll surfaces. Without this, double-scroll layouts
|
||
trap touches and the reader can't claim full height. */
|
||
#email-lib-modal .modal-content {
|
||
overflow: hidden !important;
|
||
-webkit-overflow-scrolling: touch;
|
||
overscroll-behavior: contain;
|
||
touch-action: pan-y;
|
||
}
|
||
/* Attachment row on phones: cap to ~2 rows so it never dominates the
|
||
reader. If more chips exist, the row scrolls vertically. Smaller chip
|
||
padding + max-width keeps each chip compact so two rows usually fit
|
||
everything anyway. */
|
||
#email-lib-modal .email-reader-atts {
|
||
padding: 4px 10px !important;
|
||
gap: 3px !important;
|
||
max-height: calc(2 * 22px + 12px); /* 2 rows × chip height + padding */
|
||
overflow-y: auto;
|
||
align-content: flex-start;
|
||
}
|
||
#email-lib-modal .email-attachment-chip {
|
||
padding: 1px 6px !important;
|
||
font-size: 10px !important;
|
||
max-width: min(240px, calc(100vw - 44px)) !important;
|
||
line-height: 18px !important;
|
||
}
|
||
}
|
||
|
||
|
||
/* Mobile: only ONE scroll surface inside the cookbook modal. The
|
||
modal-content is the scroller. Everything inside (cookbook-body,
|
||
cookbook-group, all the inner lists/panels) gets overflow: visible
|
||
so touch-pan never gets trapped in a nested scroller.
|
||
Without this, three levels of overflow:auto + max-height combinations
|
||
produce dead-zone areas where swipes do nothing. */
|
||
@media (max-width: 768px) {
|
||
#cookbook-modal .modal-content {
|
||
overflow-y: auto !important;
|
||
-webkit-overflow-scrolling: touch;
|
||
overscroll-behavior: contain;
|
||
touch-action: pan-y;
|
||
}
|
||
#cookbook-modal .cookbook-body,
|
||
#cookbook-modal .cookbook-group,
|
||
#cookbook-modal .cookbook-section-body,
|
||
#cookbook-modal .hwfit-cached-list,
|
||
#cookbook-modal .doclib-grid,
|
||
#cookbook-modal .hwfit-list,
|
||
#cookbook-modal .hwfit-panel-cmd {
|
||
overflow: visible !important;
|
||
max-height: none !important;
|
||
min-height: 0 !important;
|
||
}
|
||
/* Running tmux output: cap how tall an expanded card gets (a long-lived job
|
||
can leave thousands of lines) so it doesn't balloon, but keep its own
|
||
scroll so you can read it. Outputs default collapsed on mobile now, so
|
||
you're usually looking at one expanded card at a time — no wall of nested
|
||
scrollers, and you collapse it to move past. */
|
||
#cookbook-modal .cookbook-output-pre,
|
||
#cookbook-modal .cookbook-task .cookbook-output-pre {
|
||
max-height: 45vh !important;
|
||
min-height: 0 !important;
|
||
overflow-y: auto !important;
|
||
overflow-x: hidden !important;
|
||
overscroll-behavior: auto; /* chain to the modal at the scroll boundary */
|
||
}
|
||
/* cookbook-body's flex:1 was needed when it owned scrolling — drop it
|
||
so the inner content drives modal-content's scroll height. */
|
||
#cookbook-modal .cookbook-body {
|
||
flex: 0 0 auto !important;
|
||
height: auto !important;
|
||
}
|
||
/* Launch tab's cached-list normally has `flex: 1 1 0; min-height: 0`
|
||
(so it fills the modal on desktop). On mobile the parent now has
|
||
`height: auto`, which collapses `flex: 1 1 0` to ZERO PX —
|
||
models render but the list area is invisible because the flex
|
||
basis is 0 and there's no free space to grow into. Switch to
|
||
content-sized flex so the list grows with its children. */
|
||
#cookbook-modal .cookbook-group[data-backend-group="Serve"] > .admin-card > .hwfit-cached-list,
|
||
#cookbook-modal .cookbook-group[data-backend-group="Serve"] > .admin-card > #hwfit-cached-list {
|
||
flex: 0 0 auto !important;
|
||
overflow: visible !important;
|
||
}
|
||
}
|
||
#cookbook-modal .hwfit-cached-list {
|
||
flex-shrink: 0;
|
||
}
|
||
.memory-toolbar {
|
||
transition: opacity 0.12s ease, max-height 0.2s ease;
|
||
max-height: 120px;
|
||
}
|
||
.doclib-card {
|
||
background: color-mix(in srgb, var(--fg) 3%, transparent);
|
||
border: 1px solid var(--border);
|
||
border-radius: 8px;
|
||
cursor: pointer;
|
||
transition: all 0.15s, opacity 0.3s, max-height 0.3s ease;
|
||
position: relative;
|
||
}
|
||
.doclib-card.doclib-card-deleting {
|
||
opacity: 0;
|
||
max-height: 0 !important;
|
||
overflow: hidden;
|
||
margin: 0;
|
||
padding: 0;
|
||
border-color: transparent;
|
||
}
|
||
.doclib-card.selected,
|
||
/* Universal selection highlight: any card-shaped row (documents, chats,
|
||
archive, research, skills, memories, tasks) gets the same accent outline
|
||
when its checkbox is checked. Done via :has() so the highlight follows
|
||
selection without per-renderer JS changes. The canonical checkbox class
|
||
is .memory-select-cb across every list. */
|
||
.memory-item:has(.memory-select-cb:checked),
|
||
.doclib-card:has(.memory-select-cb:checked),
|
||
.doclib-chat-row:has(.memory-select-cb:checked) {
|
||
border-color: color-mix(in srgb, var(--red) 40%, transparent);
|
||
background: color-mix(in srgb, var(--red) 4%, transparent);
|
||
/* 2px accent outline overlaid on the 1px border — reads as a thicker
|
||
selected border without shifting layout (every card would otherwise
|
||
need a 2px transparent border to keep the same width). */
|
||
outline: 2px solid var(--accent-primary, var(--red));
|
||
outline-offset: -1px;
|
||
}
|
||
.doclib-card-header {
|
||
display: flex;
|
||
align-items: center;
|
||
padding: 7px 8px;
|
||
gap: 6px;
|
||
min-width: 0;
|
||
}
|
||
/* Mobile only: push the unexpanded email card's title-row text down 4px so
|
||
it sits visually centered with the surrounding card padding. Targets the
|
||
actual title-row class (.email-card-titlerow) — the earlier attempt used
|
||
.doclib-card-header which the email card builds differently. */
|
||
@media (max-width: 768px) {
|
||
#email-lib-modal .doclib-card:not(.doclib-card-expanded) .email-card-titlerow {
|
||
margin-top: 4px;
|
||
}
|
||
}
|
||
.doclib-card-title {
|
||
font-size: 11px;
|
||
font-weight: 600;
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
min-width: 0;
|
||
flex: 1;
|
||
}
|
||
.doclib-card-ver {
|
||
padding: 1px 6px;
|
||
border-radius: 8px;
|
||
background: color-mix(in srgb, var(--accent, var(--red)) 15%, transparent);
|
||
color: var(--accent, var(--red));
|
||
font-size: 9px;
|
||
flex-shrink: 0;
|
||
font-weight: 600;
|
||
letter-spacing: 0.3px;
|
||
min-width: 24px;
|
||
text-align: left;
|
||
box-sizing: border-box;
|
||
}
|
||
.doclib-card-ver-muted {
|
||
background: color-mix(in srgb, var(--fg) 6%, transparent);
|
||
color: color-mix(in srgb, var(--fg) 35%, transparent);
|
||
}
|
||
.doclib-card-lang {
|
||
padding: 1px 6px;
|
||
border-radius: 8px;
|
||
background: color-mix(in srgb, var(--accent) 10%, transparent);
|
||
color: var(--accent);
|
||
font-size: 9px;
|
||
text-align: left;
|
||
flex-shrink: 0;
|
||
min-width: 52px;
|
||
box-sizing: border-box;
|
||
}
|
||
.doclib-card-session {
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
min-width: 60px;
|
||
width: 100px;
|
||
max-width: 100px;
|
||
font-size: 9px;
|
||
color: var(--fg-muted);
|
||
flex-shrink: 0;
|
||
text-align: left;
|
||
}
|
||
.doclib-card-time {
|
||
flex-shrink: 0;
|
||
opacity: 0.5;
|
||
font-size: 9px;
|
||
color: var(--fg-muted);
|
||
min-width: 50px;
|
||
text-align: left;
|
||
}
|
||
/* Footer — used by archive cards */
|
||
.doclib-card-footer {
|
||
display: contents;
|
||
}
|
||
/* Preview — hidden by default, shown on expand */
|
||
.doclib-card-preview {
|
||
display: none;
|
||
position: relative;
|
||
padding: 8px 12px;
|
||
font-family: 'Berkeley Mono', 'SF Mono', 'Fira Code', monospace;
|
||
font-size: 9.5px;
|
||
line-height: 1.5;
|
||
color: var(--code-fg, var(--hl-fg, var(--fg)));
|
||
border-top: 1px solid color-mix(in srgb, var(--border) 30%, transparent);
|
||
margin: 0;
|
||
}
|
||
.doclib-card-preview pre {
|
||
margin: 0;
|
||
white-space: pre-wrap;
|
||
word-break: break-all;
|
||
}
|
||
.doclib-card-expanded .doclib-card-preview pre {
|
||
flex: 1 1 0;
|
||
overflow-y: auto;
|
||
min-height: 0;
|
||
}
|
||
.doclib-card-preview code.hljs {
|
||
background: none;
|
||
padding: 0;
|
||
}
|
||
/* Expanded-only action bar — inside preview. Buttons shifted up 4px by
|
||
trimming the row's top margin so they sit closer to the preview text. */
|
||
.doclib-card-expanded-actions {
|
||
display: none;
|
||
align-items: flex-start;
|
||
gap: 6px;
|
||
padding: 8px 0 2px;
|
||
border-top: 1px solid color-mix(in srgb, var(--border) 30%, transparent);
|
||
margin-top: 4px;
|
||
}
|
||
.doclib-card-expanded-actions > .doclib-card-action-btn,
|
||
.doclib-card-expanded-actions .doclib-action-btn-row > .doclib-card-action-btn {
|
||
position: relative;
|
||
top: -4px;
|
||
}
|
||
.doclib-action-group {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 3px;
|
||
}
|
||
.doclib-action-btn-row {
|
||
display: flex;
|
||
gap: 6px;
|
||
}
|
||
.doclib-action-hint-row {
|
||
display: flex;
|
||
gap: 6px;
|
||
}
|
||
/* Match the chat/research footer buttons exactly: flat, bordered,
|
||
app font, accent on hover. */
|
||
.doclib-card-action-btn {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 4px;
|
||
box-sizing: border-box;
|
||
font-size: 10px;
|
||
padding: 3px 8px;
|
||
border-radius: 4px;
|
||
background: none;
|
||
border: 1px solid var(--border);
|
||
color: var(--fg-muted);
|
||
cursor: pointer;
|
||
/* These buttons live inside .doclib-card-preview, which forces a
|
||
monospace font. The chat/research footer buttons instead inherit the
|
||
modal font, which is the app font (Fira Code) on mobile and Inter on
|
||
desktop (.modal-content's Inter rule is inside @media min-width:769px).
|
||
Mirror that here so all three footers match in both contexts. */
|
||
font-family: var(--font-family, 'Fira Code', monospace);
|
||
transition: border-color 0.15s, color 0.15s;
|
||
}
|
||
@media (min-width: 769px) {
|
||
.doclib-card-action-btn {
|
||
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||
letter-spacing: -0.015em;
|
||
}
|
||
}
|
||
.doclib-card-action-btn:hover {
|
||
border-color: var(--accent, var(--red));
|
||
color: var(--accent, var(--red));
|
||
}
|
||
.doclib-card-text-btn-danger {
|
||
color: var(--color-danger, #e06c75);
|
||
border-color: var(--color-danger, #e06c75);
|
||
}
|
||
.doclib-card-text-btn-danger:hover {
|
||
color: #ff4d4d;
|
||
border-color: #ff4d4d;
|
||
}
|
||
.doclib-card-expanded-actions > .doclib-card-action-btn {
|
||
font-size: 10px;
|
||
padding: 3px 8px;
|
||
}
|
||
/* Push the Open/Clone group to the right edge of the action bar — Delete
|
||
anchors the left, primary actions sit opposite. */
|
||
.doclib-card-expanded-actions > .doclib-action-group {
|
||
margin-left: auto;
|
||
}
|
||
.doclib-card-expanded-actions > .doclib-expanded-delete-btn,
|
||
.doclib-card-expanded-actions > .doclib-expanded-archive-btn {
|
||
left: 0 !important;
|
||
}
|
||
.doclib-expanded-mobile-more { display: none; }
|
||
.doclib-btn-hint {
|
||
font-weight: normal;
|
||
opacity: 0.35;
|
||
font-size: 8px;
|
||
min-width: 58px;
|
||
padding: 0 8px;
|
||
box-sizing: border-box;
|
||
}
|
||
@media (max-width: 768px) {
|
||
.doclib-btn-hint { display: none !important; }
|
||
}
|
||
|
||
/* Chat row expand preview — matches the documents-tab expand style. */
|
||
.doclib-card-chevron {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
align-self: center;
|
||
flex-shrink: 0;
|
||
width: 14px;
|
||
height: 14px;
|
||
line-height: 0;
|
||
opacity: 0.3;
|
||
transform: rotate(0deg);
|
||
transition: transform 0.2s ease, opacity 0.15s;
|
||
}
|
||
.doclib-card-chevron svg { display: block; }
|
||
.doclib-card-expanded .doclib-card-chevron,
|
||
.task-card.expanded .doclib-card-chevron {
|
||
opacity: 0.8;
|
||
transform: rotate(180deg);
|
||
}
|
||
.doclib-card > .memory-item-actions { order: 1; }
|
||
.doclib-card > .doclib-card-chevron { order: 2; }
|
||
.doclib-chat-header .memory-item-actions,
|
||
.task-card .memory-item-actions { order: 2; }
|
||
.doclib-chat-header .doclib-card-chevron,
|
||
.task-card .doclib-card-chevron { order: 3; }
|
||
.hwfit-cached-list > .doclib-card > .memory-item-actions { order: 2; }
|
||
.hwfit-cached-list > .doclib-card > .doclib-card-chevron { order: 3; }
|
||
#email-lib-modal .doclib-card > .memory-item-actions { order: 1; align-self: center; }
|
||
#email-lib-modal .doclib-card > .doclib-card-chevron { display: none; }
|
||
.doclib-chat-row { flex-direction: column; align-items: stretch; }
|
||
.doclib-chat-row .doclib-card-chevron {
|
||
display: inline-flex;
|
||
opacity: 0.55;
|
||
transition: transform 0.2s ease, opacity 0.15s;
|
||
flex-shrink: 0;
|
||
}
|
||
.doclib-chat-row:not(.doclib-card-expanded) .doclib-card-chevron {
|
||
transform: rotate(0deg);
|
||
}
|
||
.doclib-chat-row.doclib-card-expanded .doclib-card-chevron {
|
||
opacity: 0.8;
|
||
transform: rotate(180deg);
|
||
}
|
||
/* Release .memory-item's base max-height: 200px when a chat row is
|
||
expanded. Without this, the row clips at 200px on desktop and the
|
||
preview's messages/actions visually spill past the row's box —
|
||
"colliding" with the next chat in the column. The mobile takeover
|
||
below already handles this via the same override; this rule is the
|
||
desktop-or-any-viewport equivalent. */
|
||
.doclib-chat-row.doclib-card-expanded {
|
||
max-height: none;
|
||
overflow: visible;
|
||
}
|
||
/* When a chat row is expanded, take over the grid the same way documents
|
||
do: hide siblings, hide the admin-card toolbar, and let this row plus
|
||
its preview claim the full available height. .memory-item's default
|
||
max-height: 200px must be overridden or the preview will be tiny. */
|
||
/* Mobile-only "card takeover" for an expanded chat — hides siblings,
|
||
hides the admin-card toolbar, and lets this row + its preview claim
|
||
the full available height. On desktop the expanded preview just
|
||
renders inline below the row with its messages constrained by
|
||
max-height + overflow:auto so the user gets a normal scroll. */
|
||
@media (max-width: 820px) {
|
||
.doclib-grid:has(.doclib-chat-row.doclib-card-expanded) > .doclib-chat-row:not(.doclib-card-expanded) {
|
||
display: none;
|
||
}
|
||
.admin-card:has(.doclib-chat-row.doclib-card-expanded) > *:not(.doclib-grid) {
|
||
display: none;
|
||
}
|
||
.admin-card:has(.doclib-chat-row.doclib-card-expanded) > .doclib-grid {
|
||
flex: 1 1 auto !important;
|
||
max-height: none !important;
|
||
overflow-y: auto !important;
|
||
}
|
||
.doclib-chat-row.doclib-card-expanded {
|
||
flex: 1 1 auto !important;
|
||
max-height: none !important;
|
||
min-height: 0 !important;
|
||
overflow: hidden !important;
|
||
display: flex !important;
|
||
flex-direction: column !important;
|
||
align-items: stretch !important;
|
||
}
|
||
.doclib-chat-row.doclib-card-expanded .doclib-chat-header {
|
||
flex: 0 0 auto !important;
|
||
}
|
||
.doclib-chat-row.doclib-card-expanded .doclib-chat-preview {
|
||
flex: 1 1 auto !important;
|
||
min-height: 0 !important;
|
||
overflow: hidden !important;
|
||
display: flex !important;
|
||
flex-direction: column !important;
|
||
padding-bottom: 4px !important;
|
||
}
|
||
.doclib-chat-row.doclib-card-expanded .doclib-chat-preview-messages {
|
||
-webkit-overflow-scrolling: touch;
|
||
max-height: none !important;
|
||
flex: 1 1 auto !important;
|
||
min-height: 0 !important;
|
||
}
|
||
}
|
||
.doclib-chat-preview {
|
||
font-size: 11px;
|
||
padding: 0 4px 6px;
|
||
}
|
||
.doclib-chat-preview .doclib-chat-open-btn {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 4px;
|
||
font-size: 10px;
|
||
padding: 3px 8px;
|
||
border-radius: 4px;
|
||
color: var(--fg-muted);
|
||
border: 1px solid var(--border);
|
||
background: none;
|
||
cursor: pointer;
|
||
font-family: inherit;
|
||
transition: border-color 0.15s, color 0.15s;
|
||
}
|
||
.doclib-chat-preview .task-completed-report-btn {
|
||
color: var(--accent, var(--red));
|
||
border-color: color-mix(in srgb, var(--accent, var(--red)) 55%, var(--border));
|
||
}
|
||
.doclib-chat-preview .doclib-chat-open-btn:hover {
|
||
border-color: var(--accent, var(--red));
|
||
color: var(--accent, var(--red));
|
||
}
|
||
.doclib-chat-preview-messages {
|
||
margin-top: 6px;
|
||
max-height: 320px;
|
||
overflow-y: auto;
|
||
-webkit-overflow-scrolling: touch;
|
||
padding-right: 4px;
|
||
}
|
||
/* Desktop expanded state — match the documents-tab behavior: hide
|
||
sibling chats, hide the admin-card toolbar/header, and let the
|
||
expanded row + its messages preview claim the full modal height.
|
||
Chat rows use `memory-item doclib-chat-row` (no `doclib-card` class)
|
||
so the document-tab's global rules at line 12284-12304 skip them —
|
||
these mirror those rules scoped to chat rows. The mobile media query
|
||
above (820px) keeps the same takeover behavior for phones. */
|
||
@media (min-width: 821px) {
|
||
.doclib-grid:has(.doclib-chat-row.doclib-card-expanded) > .doclib-chat-row:not(.doclib-card-expanded) {
|
||
display: none;
|
||
}
|
||
.admin-card:has(.doclib-chat-row.doclib-card-expanded) > *:not(.doclib-grid) {
|
||
display: none;
|
||
}
|
||
.admin-card:has(.doclib-chat-row.doclib-card-expanded) > .doclib-grid {
|
||
flex: 1 1 auto !important;
|
||
max-height: none !important;
|
||
overflow: hidden auto !important;
|
||
}
|
||
.doclib-chat-row.doclib-card-expanded {
|
||
flex: 1 1 auto !important;
|
||
max-height: none !important;
|
||
min-height: 0 !important;
|
||
display: flex !important;
|
||
flex-direction: column !important;
|
||
}
|
||
.doclib-chat-row.doclib-card-expanded .doclib-chat-preview {
|
||
flex: 1 1 auto !important;
|
||
min-height: 0 !important;
|
||
display: flex !important;
|
||
flex-direction: column !important;
|
||
}
|
||
.doclib-chat-row.doclib-card-expanded .doclib-chat-preview-messages {
|
||
flex: 1 1 auto !important;
|
||
min-height: 0 !important;
|
||
max-height: none !important;
|
||
overflow-y: auto !important;
|
||
}
|
||
}
|
||
.doclib-chat-preview-actions {
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
align-items: center;
|
||
gap: 8px;
|
||
padding: 2px 0 2px;
|
||
border-top: 1px solid color-mix(in srgb, var(--border) 30%, transparent);
|
||
margin-top: 2px;
|
||
flex-shrink: 0;
|
||
/* Whole action footer nudged down 5px. */
|
||
position: relative;
|
||
top: 5px;
|
||
}
|
||
.doclib-chat-delete-btn,
|
||
.doclib-chat-archive-btn,
|
||
.doclib-chat-restore-btn,
|
||
.doclib-chat-discuss-btn,
|
||
.doclib-chat-copy-btn {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 4px;
|
||
font-size: 10px;
|
||
padding: 3px 8px;
|
||
border-radius: 4px;
|
||
background: none;
|
||
cursor: pointer;
|
||
font-family: inherit;
|
||
transition: border-color 0.15s, color 0.15s;
|
||
}
|
||
.doclib-chat-archive-btn,
|
||
.doclib-chat-restore-btn,
|
||
.doclib-chat-discuss-btn,
|
||
.doclib-chat-copy-btn {
|
||
color: var(--fg-muted);
|
||
border: 1px solid var(--border);
|
||
}
|
||
.doclib-chat-restore-btn:hover {
|
||
color: var(--accent, var(--red));
|
||
border-color: var(--accent, var(--red));
|
||
}
|
||
.doclib-chat-archive-btn:hover,
|
||
.doclib-chat-discuss-btn:hover,
|
||
.doclib-chat-copy-btn:hover {
|
||
color: var(--accent, var(--red));
|
||
border-color: var(--accent, var(--red));
|
||
}
|
||
.doclib-chat-delete-btn {
|
||
color: var(--color-danger, #e06c75);
|
||
border: 1px solid var(--color-danger, #e06c75);
|
||
}
|
||
.doclib-chat-delete-btn:hover {
|
||
color: #ff4d4d;
|
||
border-color: #ff4d4d;
|
||
}
|
||
/* When a chat is archived there's no Archive button, so Delete becomes
|
||
the only left-side action and needs the auto margin to push Open right. */
|
||
.doclib-chat-preview-actions:not(:has(.doclib-chat-archive-btn)) > .doclib-chat-delete-btn {
|
||
margin-right: auto;
|
||
}
|
||
/* Hide the "..." menu while the chat card is expanded — archive +
|
||
delete live in the preview footer instead. */
|
||
.doclib-chat-row.doclib-card-expanded ._chat-menu { display: none; }
|
||
.doclib-chat-preview-actions.doclib-chat-preview-actions-top {
|
||
border-top: none;
|
||
border-bottom: 1px solid color-mix(in srgb, var(--border) 30%, transparent);
|
||
margin-top: 4px;
|
||
margin-bottom: 6px;
|
||
padding: 0 0 6px;
|
||
justify-content: flex-start;
|
||
}
|
||
.doclib-chat-preview-messages .doclib-chat-msg {
|
||
margin: 4px 0 10px;
|
||
padding-left: 8px;
|
||
border-left: 2px solid color-mix(in srgb, var(--border) 70%, transparent);
|
||
}
|
||
.doclib-chat-preview-messages .doclib-chat-msg.user {
|
||
border-left-color: color-mix(in srgb, var(--accent, var(--red)) 60%, transparent);
|
||
}
|
||
.doclib-chat-preview-messages .doclib-chat-msg-role {
|
||
font-size: 9px;
|
||
font-weight: 600;
|
||
letter-spacing: 0.06em;
|
||
text-transform: uppercase;
|
||
opacity: 0.55;
|
||
margin-bottom: 2px;
|
||
}
|
||
.doclib-chat-preview-messages .doclib-chat-msg.user .doclib-chat-msg-role {
|
||
color: var(--accent, var(--red));
|
||
opacity: 0.85;
|
||
}
|
||
.doclib-chat-preview-messages .doclib-chat-msg-body {
|
||
white-space: pre-wrap;
|
||
word-break: break-word;
|
||
opacity: 0.85;
|
||
line-height: 1.45;
|
||
}
|
||
/* Chat-bubble preview — mirrors the real chat layout. User bubbles hug
|
||
right with an accent tint; assistant bubbles hug left with a neutral
|
||
panel tint and a small model tag at the top. */
|
||
.doclib-chat-bubble-row {
|
||
display: flex;
|
||
margin: 6px 0;
|
||
}
|
||
.doclib-chat-bubble-row.user { justify-content: flex-end; }
|
||
.doclib-chat-bubble-row.assistant { justify-content: flex-start; }
|
||
.doclib-chat-bubble {
|
||
max-width: 85%;
|
||
padding: 6px 10px 8px;
|
||
border-radius: 14px;
|
||
font-size: 11px;
|
||
line-height: 1.45;
|
||
border: 1px solid var(--border);
|
||
background: color-mix(in srgb, var(--fg) 4%, transparent);
|
||
}
|
||
.doclib-chat-bubble-row.user .doclib-chat-bubble {
|
||
background: color-mix(in srgb, var(--accent, var(--red)) 14%, transparent);
|
||
border-color: color-mix(in srgb, var(--accent, var(--red)) 30%, transparent);
|
||
border-bottom-right-radius: 4px;
|
||
}
|
||
.doclib-chat-bubble-row.assistant .doclib-chat-bubble {
|
||
border-bottom-left-radius: 4px;
|
||
}
|
||
.doclib-chat-msg-model {
|
||
display: inline-block;
|
||
font-size: 8px;
|
||
font-weight: 600;
|
||
letter-spacing: 0.04em;
|
||
text-transform: uppercase;
|
||
opacity: 0.55;
|
||
margin-bottom: 3px;
|
||
padding: 1px 6px;
|
||
border-radius: 6px;
|
||
background: color-mix(in srgb, var(--fg) 8%, transparent);
|
||
color: var(--fg-muted, var(--fg));
|
||
}
|
||
.doclib-chat-bubble-body { word-break: break-word; }
|
||
.doclib-chat-bubble-body p { margin: 4px 0; }
|
||
.doclib-chat-bubble-body p:first-child { margin-top: 0; }
|
||
.doclib-chat-bubble-body p:last-child { margin-bottom: 0; }
|
||
.doclib-chat-bubble-body pre {
|
||
font-size: 10px;
|
||
margin: 4px 0;
|
||
padding: 6px 8px;
|
||
background: color-mix(in srgb, var(--bg) 60%, transparent);
|
||
border-radius: 6px;
|
||
overflow-x: auto;
|
||
}
|
||
.doclib-chat-bubble-body code {
|
||
font-size: 10px;
|
||
padding: 1px 4px;
|
||
border-radius: 3px;
|
||
background: color-mix(in srgb, var(--fg) 8%, transparent);
|
||
}
|
||
.doclib-chat-bubble-body pre code { background: none; padding: 0; }
|
||
.doclib-chat-bubble-body ul,
|
||
.doclib-chat-bubble-body ol {
|
||
margin: 4px 0;
|
||
padding-left: 18px;
|
||
}
|
||
.doclib-card-collapse-chevron {
|
||
display: none;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 24px;
|
||
height: 22px;
|
||
padding: 0;
|
||
border: 1px solid transparent;
|
||
border-radius: 6px;
|
||
background: transparent;
|
||
color: var(--color-muted, var(--fg));
|
||
font: inherit;
|
||
opacity: 0.3;
|
||
cursor: pointer;
|
||
flex-shrink: 0;
|
||
margin: 0 0 0 4px;
|
||
transition: opacity 0.15s, background 0.15s, border-color 0.15s;
|
||
}
|
||
.doclib-card-collapse-chevron:hover {
|
||
opacity: 1;
|
||
background: color-mix(in srgb, var(--fg) 8%, transparent);
|
||
border-color: color-mix(in srgb, var(--fg) 24%, transparent);
|
||
}
|
||
.cookbook-serve-title {
|
||
display: flex;
|
||
align-items: center;
|
||
min-width: 0;
|
||
}
|
||
.cookbook-serve-title .doclib-card-collapse-chevron {
|
||
display: inline-flex;
|
||
margin-left: auto;
|
||
margin-top: 0;
|
||
}
|
||
.doclib-card-expanded .doclib-card-collapse-chevron {
|
||
display: inline-flex;
|
||
}
|
||
/* Expanded card — fills the whole grid */
|
||
.doclib-card.doclib-card-expanded {
|
||
flex: 1;
|
||
min-height: 0;
|
||
background: color-mix(in srgb, var(--fg) 3%, transparent);
|
||
border: 1px solid var(--border);
|
||
border-radius: 8px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
overflow: hidden;
|
||
animation: doclib-expand 0.2s ease-out;
|
||
}
|
||
.doclib-card.doclib-card-expanded {
|
||
flex-direction: column !important;
|
||
align-items: stretch !important;
|
||
max-height: none !important;
|
||
gap: 4px !important;
|
||
}
|
||
.doclib-card.doclib-card-expanded > .memory-item-actions { display: none; }
|
||
/* Non-preview children of an expanded doc card carry an inline flex:1 from
|
||
the row layout. With the card now flex-column those children would steal
|
||
half the height and shrink the preview — pin them at auto height. */
|
||
.doclib-card.doclib-card-expanded > div:not(.doclib-card-preview):not(.doclib-card-header):not(.memory-item-actions):not(.email-card-reader) {
|
||
flex: 0 0 auto !important;
|
||
}
|
||
/* The email reader IS the scroll container — keep its flex:1 so its
|
||
internal body can claim the rest of the card's height and scroll. */
|
||
.doclib-card.doclib-card-expanded > .email-card-reader {
|
||
flex: 1 1 auto !important;
|
||
min-height: 0 !important;
|
||
}
|
||
.doclib-card.doclib-card-expanded .doclib-card-preview {
|
||
display: flex;
|
||
flex-direction: column;
|
||
flex: 1 1 auto !important;
|
||
/* The preview matches chat rows: document content scrolls, while the
|
||
footer stays in the card rather than becoming the last scroll item. */
|
||
overflow: hidden;
|
||
min-height: 0;
|
||
}
|
||
.doclib-card.doclib-card-expanded .doclib-card-expanded-actions {
|
||
display: flex;
|
||
flex-shrink: 0;
|
||
}
|