mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-10-06 23:12:22 +02:00
style-part-01..08 were arbitrary 6,000-line cuts, so the names said nothing and a reader had no way to guess which file held a rule. The original stylesheet turns out to be roughly area-grouped already, so cutting where the content changes rather than every 6,000 lines produces boundaries worth naming. Classifying every top-level rule by selector prefix and smoothing over a 40-rule window gives 17 stable runs: agent-chat, compare, memory, documents, admin-settings, skills, gallery, cookbook, tasks, image-editor, email, notes, calendar, research. The numeric prefix stays because load order is load-bearing, and it also disambiguates the areas that appear twice: the original interleaves, and merging non-adjacent blocks of the same area would reorder the cascade. The names describe where a file sits, not a claim that it holds every rule for that area or only rules for it. The header in each file says so, because that is the misreading this naming invites. Reconstruction was checked against lab's style.css before rewriting: identical after whitespace normalisation, all 47,528 lines accounted for. The computed style baseline still reproduces exactly.
1284 lines
46 KiB
CSS
1284 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: 0 !important;
|
||
left: 0 !important;
|
||
top: 0 !important;
|
||
width: 100vw !important;
|
||
max-width: 100vw !important;
|
||
height: 100vh !important;
|
||
max-height: 100vh !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: 0 !important;
|
||
left: calc(var(--icon-rail-w, 48px) + var(--sidebar-w, 0px)) !important;
|
||
right: 0 !important;
|
||
bottom: 0 !important;
|
||
width: auto !important;
|
||
max-width: none !important;
|
||
height: 100vh !important;
|
||
max-height: 100vh !important;
|
||
border-radius: 0 !important;
|
||
transform: none !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 {
|
||
left: 0 !important;
|
||
right: 0 !important;
|
||
width: 100vw !important;
|
||
max-width: 100vw !important;
|
||
height: 100dvh !important;
|
||
max-height: 100dvh !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;
|
||
}
|