Files
odysseus/static/css/style-part-07.css
T
Léo 03d55dfe3c refactor(css): split style.css into ordered fragments
static/style.css was 47,530 lines. It is now nine files under static/css/:
tokens.css holds the :root custom properties, light theme and density classes,
and style-part-01..08 carry the rest in their original order. Nothing was
rewritten; every line moved verbatim and the <link> order in index.html
reproduces the original file byte for byte.

Cut points are brace-depth zero and outside block comments, so no rule or
comment is split. All 47,531 source lines are accounted for across the
fragments.

The computed-style baseline recorded before the split is reproduced exactly,
which is the evidence that the cascade is unchanged rather than an argument
that it should be.

Three things the split broke and this fixes:

- The harness self-test swapped two conflicting .attach-strip blocks inside
  style.css to prove the digest is order-sensitive. It rewrote one hardcoded
  URL, so with the file gone it silently measured an unmodified page. It now
  searches every stylesheet, rewrites whichever holds the pair, and fails
  loudly if none does.
- Four tests asserted the cache-bust token by matching /static/style.css?v=.
  They check the real invariant now, that every app stylesheet shares one
  token with app.js, through stylesheet_cache_version().
- The three panel stylesheets carried their own tokens, so a browser could
  hold half an old cascade and half a new one. All app stylesheets now bust
  together.
2026-09-29 17:37:25 +02:00

6013 lines
173 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* Fragment 8/9 of the former static/style.css.
*
* This is a mechanical, order-preserving slice: rules were moved verbatim
* and this file's position in the <link> order of static/index.html is what
* keeps the cascade identical. Reordering the links, or moving a rule between
* fragments, can change which of two competing declarations wins.
*
* static/index.html and the PRECACHE list in static/sw.js must list every
* fragment in the same order. tests/test_static_stylesheet_manifest.py and
* tests/test_css_computed_style_snapshot.py both fail if that drifts.
*/
.doc-editor-textarea,
#doc-editor-code.email-mode .doc-editor-textarea {
color: var(--fg) !important;
caret-color: var(--fg) !important;
z-index: 1;
}
/* Emoji picker (monochrome icon picker) */
.emoji-picker-btn {
background: none; border: none; color: var(--fg); opacity: 0.35;
padding: 4px 7px; cursor: pointer; min-height: 28px;
display: inline-flex; align-items: center; justify-content: center;
transition: opacity 0.1s;
}
.emoji-picker-btn:hover { opacity: 1; }
.emoji-picker {
width: min(300px, 92vw); max-height: min(300px, 55vh);
background: var(--panel); border: 1px solid var(--border); border-radius: 8px;
box-shadow: 0 8px 24px rgba(0,0,0,0.3);
display: flex; flex-direction: column; overflow: hidden;
}
.emoji-picker-search {
padding: 8px 12px; background: var(--panel); border: none;
border-bottom: 1px solid var(--border); color: var(--fg);
font-size: 12px; font-family: inherit; outline: none;
}
.emoji-picker-groups { overflow-y: auto; padding: 4px 0; flex: 1; }
.emoji-picker-group { padding: 0 6px 4px 6px; }
.emoji-picker-group-name {
font-size: 10px; font-weight: 600; opacity: 0.5;
text-transform: uppercase; letter-spacing: 0.5px;
padding: 4px 4px 2px 4px;
}
.emoji-picker-grid { display: grid; grid-template-columns: repeat(8, 1fr); gap: 1px; }
.emoji-picker-item {
background: none; border: none; cursor: pointer;
padding: 4px; border-radius: 4px;
display: flex; align-items: center; justify-content: center;
color: var(--fg); transition: background 0.1s;
}
.emoji-picker-item:hover { background: color-mix(in srgb, var(--accent) 15%, transparent); }
.emoji-picker-item svg { width: 16px; height: 16px; }
.email-avatar {
width: 28px; height: 28px; border-radius: 50%; background: var(--accent, #4a9eff);
color: #fff; display: flex; align-items: center; justify-content: center;
font-size: 12px; font-weight: 600; flex-shrink: 0; margin-top: 1px;
}
.email-item-content { flex: 1; min-width: 0; overflow: hidden; }
.email-item-top { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; }
.email-sender { font-size: 12px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.email-filter-chip {
display: flex;
align-items: center;
justify-content: space-between;
gap: 6px;
margin: 4px 8px 6px;
padding: 4px 8px;
border-radius: 12px;
font-size: 11px;
background: color-mix(in srgb, var(--accent, var(--red)) 14%, transparent);
border: 1px solid color-mix(in srgb, var(--accent, var(--red)) 40%, transparent);
color: var(--fg);
}
.email-filter-chip-clear {
background: none;
border: none;
color: inherit;
cursor: pointer;
font-size: 14px;
line-height: 1;
padding: 0 2px;
opacity: 0.6;
}
.email-date { font-size: 10px; opacity: 0.5; white-space: nowrap; flex-shrink: 0; }
.email-subject { font-size: 11px; opacity: 0.6; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-top: 1px; }
.email-sent-chip,
.email-folder-chip {
display: inline-flex;
align-items: center;
height: 14px;
padding: 0 5px;
margin-right: 5px;
border-radius: 999px;
font-size: 8px;
line-height: 1;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0;
color: var(--accent, var(--red));
background: color-mix(in srgb, var(--accent, var(--red)) 14%, transparent);
border: 1px solid color-mix(in srgb, var(--accent, var(--red)) 28%, transparent);
vertical-align: 1px;
}
.email-folder-chip {
position: relative;
top: 4px;
color: color-mix(in srgb, var(--fg) 75%, transparent);
background: rgba(127, 127, 127, 0.13);
border-color: rgba(127, 127, 127, 0.24);
}
.email-meta-date-group {
display: inline-flex;
align-items: center;
gap: 5px;
white-space: nowrap;
}
.email-meta-date-group .email-folder-chip {
margin-right: 0;
}
.email-card-expanded .email-sent-chip,
.email-card-reader .email-sent-chip {
position: relative;
top: 4px;
}
.email-tags { display: inline-flex; align-items: center; flex-wrap: nowrap; gap: 3px; margin-left: 6px; vertical-align: middle; position: relative; top: -2px; }
.email-card-tags {
flex: 0 0 auto;
min-width: 0;
max-width: 48%;
position: relative;
top: -4px;
}
.email-card-expanded .email-tags,
.email-card-reader .email-tags { top: -4px; }
.doclib-card-expanded .email-card-tags { top: -4px; }
.email-card-expanded .email-card-titlerow .email-tag,
.email-card-expanded .email-card-titlerow .email-tags-more {
transform: translateY(-2px);
}
@media (max-width: 768px) {
.email-card-expanded .email-card-titlerow .email-tag,
.email-card-expanded .email-card-titlerow .email-tags-more {
transform: translateY(2px);
}
}
.email-card-tags.email-tags-expanded {
position: absolute;
z-index: 4;
right: calc(var(--email-status-width, 44px) + 6px);
top: -5px;
max-width: min(58%, 260px);
padding: 4px 5px;
border: 1px solid var(--border);
border-radius: 6px;
background: var(--panel, var(--bg));
box-shadow: 0 5px 14px color-mix(in srgb, #000 20%, transparent);
}
.email-tags-more {
appearance: none;
border: 0;
box-sizing: border-box;
border-radius: 999px;
background: rgba(127, 127, 127, 0.16);
color: var(--fg);
cursor: pointer;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 1px;
height: 13px !important;
min-height: 0 !important;
min-width: 23px;
padding: 1px 4px;
font-family: inherit;
font-size: 9px;
line-height: 1;
margin: 0;
opacity: 0.68;
position: relative;
top: 0;
vertical-align: middle;
}
.email-tags-more svg { display: block; flex: 0 0 auto; }
.email-tags-expanded .email-tags-more svg { transform: rotate(180deg); }
.email-tags-toggle-inline {
position: absolute;
right: 94px;
top: 50%;
transform: translateY(calc(-50% - 5px));
height: 20px !important;
min-width: 34px;
padding: 2px 6px !important;
font-size: 10px !important;
line-height: 1 !important;
opacity: 0.62;
border-radius: 999px !important;
}
.email-tags-toggle-inline.active {
opacity: 1;
color: var(--accent, var(--red));
background: color-mix(in srgb, var(--accent, var(--red)) 12%, transparent);
border-color: color-mix(in srgb, var(--accent, var(--red)) 36%, transparent);
}
.email-tags-toggle-inline.email-tags-empty {
color: var(--warning, #d6b35a);
background: color-mix(in srgb, var(--warning, #d6b35a) 12%, transparent);
border-color: color-mix(in srgb, var(--warning, #d6b35a) 34%, transparent);
}
.email-tag {
display: inline-block;
font-size: 9px;
line-height: 1;
padding: 2px 5px;
border-radius: 8px;
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0.3px;
background: rgba(127, 127, 127, 0.18);
color: var(--fg);
}
.email-tag-clickable {
appearance: none;
border: 0;
cursor: pointer;
display: inline-flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
font-family: inherit;
font-size: 9px;
font-weight: 500;
height: 13px !important;
min-height: 0 !important;
line-height: 1;
margin: 0;
padding: 2px 5px !important;
text-transform: uppercase;
vertical-align: middle;
flex: 0 0 auto;
}
.email-tag-work { background: rgba(96, 165, 250, 0.22); color: #60a5fa; }
.email-tag-personal { background: rgba(74, 222, 128, 0.22); color: #4ade80; }
.email-tag-finance { background: rgba(250, 204, 21, 0.22); color: #facc15; }
.email-tag-bills { background: rgba(251, 146, 60, 0.22); color: #fb923c; }
.email-tag-receipt { background: rgba(251, 146, 60, 0.22); color: #fb923c; }
.email-tag-travel { background: rgba(167, 139, 250, 0.22); color: #a78bfa; }
.email-tag-newsletter { background: rgba(148, 163, 184, 0.22); color: #94a3b8; }
.email-tag-promo,
.email-tag-marketing { background: rgba(244, 114, 182, 0.22); color: #f472b6; }
.email-tag-notification { background: rgba(148, 163, 184, 0.22); color: #94a3b8; }
.email-tag-security { background: rgba(248, 113, 113, 0.22); color: #f87171; }
.email-tag-urgent { background: color-mix(in srgb, var(--color-error, #e06c75) 25%, transparent); color: var(--color-error, #e06c75); font-weight: 600; }
.email-tag-reply-soon { background: rgba(240, 173, 78, 0.22); color: #f0ad4e; }
.email-tag-social { background: rgba(56, 189, 248, 0.22); color: #38bdf8; }
.email-tag-shopping { background: rgba(236, 72, 153, 0.22); color: #ec4899; }
.email-tag-calendar { background: rgba(167, 139, 250, 0.22); color: #a78bfa; }
.email-menu-wrap { position: relative; flex-shrink: 0; }
.email-menu-btn {
background: none; border: none; color: var(--fg); opacity: 0; cursor: pointer;
padding: 4px; transition: opacity 0.15s;
position: relative; top: 0px;
}
.email-dropdown {
position: absolute; right: 0; top: 100%; z-index: 9999;
min-width: 120px; background: var(--bg); border: 1px solid var(--border);
border-radius: 6px; box-shadow: 0 4px 12px rgba(0,0,0,0.3); padding: 4px 0;
}
.email-loading { padding: 16px; text-align: center; font-size: 12px; opacity: 0.5; }
.email-load-more { padding: 8px; text-align: center; }
.email-load-more-btn {
background: transparent; border: 1px solid var(--border); border-radius: 4px;
color: var(--fg); padding: 4px 12px; font-size: 11px; cursor: pointer;
}
.email-load-more-btn:hover { background: var(--hover-bg, rgba(255,255,255,0.05)); }
.email-spinner {
display: inline-block; width: 12px; height: 12px; border: 2px solid rgba(255,255,255,0.3);
border-top-color: #fff; border-radius: 50%; animation: email-spin 0.6s linear infinite;
vertical-align: middle; margin-right: 4px;
}
/* Email section doesn't collapse — hide the auto-injected chevron */
#email-section .section-collapse-btn { display: none !important; }
#email-section:hover #email-compose-btn {
opacity: 0.7 !important;
}
#email-compose-btn:hover {
opacity: 1 !important;
background: none !important;
}
#email-compose-btn svg {
width: 11px;
height: 11px;
transition: transform 0.45s cubic-bezier(0.34, 1.56, 0.64, 1);
}
#email-compose-btn .list-item-plus-label {
top: calc(50% - 0.5px);
color: var(--fg);
font-size: 10px;
}
#email-compose-btn:hover svg {
transform: rotate(180deg) scale(1.15);
}
/* Library row "+" — identical to the email compose "+": hidden until the row
is hovered, no accent box, and the same rotate-in animation. */
#library-new-doc-btn,
#notes-new-note-btn {
opacity: 0.4 !important;
transition: opacity 0.15s ease;
}
#tool-library-btn:hover #library-new-doc-btn,
#tool-notes-btn:hover #notes-new-note-btn {
opacity: 0.7 !important;
}
#library-new-doc-btn:hover,
#notes-new-note-btn:hover {
opacity: 1 !important;
background: none !important;
}
#library-new-doc-btn svg,
#notes-new-note-btn svg {
transition: transform 0.45s cubic-bezier(0.34, 1.56, 0.64, 1);
}
#library-new-doc-btn .list-item-plus-label,
#notes-new-note-btn .list-item-plus-label {
top: calc(50% + 1px);
}
#library-new-doc-btn:hover svg,
#notes-new-note-btn:hover svg {
transform: rotate(180deg) scale(1.15);
}
/* MD toolbar attach button — matches other toolbar buttons */
.md-toolbar-attach-btn {
background: none; border: none; color: var(--fg); opacity: 0.35;
padding: 4px 7px; cursor: pointer; min-height: 28px;
display: inline-flex; align-items: center; justify-content: center;
transition: opacity 0.1s;
}
.md-toolbar-attach-btn:hover { opacity: 1; }
/* Email reader icon buttons — vertical icon + label stack. */
.memory-toolbar-btn.reader-icon-btn {
width: auto;
height: 44px;
/* padding: 4px 2px; */
position: relative;
top: 1px;
display: inline-flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 3px;
flex: 0 0 auto;
}
.memory-toolbar-btn.reader-icon-btn svg { width: 18px; height: 18px; }
.memory-toolbar-btn.reader-icon-btn[data-act="reply"] svg {
color: inherit;
stroke: currentColor;
}
.memory-toolbar-btn.reader-icon-btn.active {
background: color-mix(in srgb, var(--accent, var(--red)) 16%, transparent);
border-color: color-mix(in srgb, var(--accent, var(--red)) 40%, transparent);
color: var(--accent, var(--red));
}
.memory-toolbar-btn.reader-icon-btn[data-act="more"] {
color: inherit;
}
.memory-toolbar-btn.reader-icon-btn[data-act="more"] svg { fill: currentColor; }
.memory-toolbar-btn.reader-icon-btn.reader-more-active {
background: color-mix(in srgb, var(--fg) 12%, transparent);
border-color: color-mix(in srgb, var(--fg) 24%, transparent);
color: inherit;
}
/* Cookbook Serve dropdown triggers (the cached-model kebab + the saved-config
arrow) — accent-colored to signal they open a menu, with a filled tint when
their dropdown is open. Matches the email reader More button pattern. */
.hwfit-cached-menu-btn,
.cookbook-saved-arrow {
color: var(--accent, var(--red));
/* Base .memory-item-btn is flex with align-items but no justify-content,
so the kebab SVG sat left-aligned inside the button instead of being
horizontally centered. Pin it center. */
justify-content: center;
}
.hwfit-cached-menu-btn.cookbook-menu-active,
.cookbook-saved-arrow.cookbook-menu-active {
background: color-mix(in srgb, var(--accent, var(--red)) 18%, transparent);
border-color: color-mix(in srgb, var(--accent, var(--red)) 45%, transparent);
color: var(--accent, var(--red));
}
/* Card action menus share one hit target and baseline. Keep this late in the
cascade because modal buttons and Cookbook Serve add their own offsets. */
.memory-item-actions > .memory-item-btn,
.memory-item-actions .hwfit-cached-menu-btn {
box-sizing: border-box;
width: 28px;
min-width: 28px;
height: 22px;
min-height: 22px;
margin: 0 !important;
padding: 0;
border: 1px solid transparent;
border-radius: 6px;
color: var(--color-muted);
font-size: 11px;
display: inline-flex;
align-items: center;
align-self: center;
justify-content: center;
position: relative;
top: 0 !important;
transform: none !important;
line-height: 1;
transition: background 0.15s, border-color 0.15s, color 0.15s, opacity 0.15s;
}
.memory-item-actions .hwfit-cached-menu-btn:hover {
opacity: 1 !important;
background: color-mix(in srgb, var(--fg) 8%, transparent);
border-color: color-mix(in srgb, var(--fg) 24%, transparent);
color: var(--fg);
}
.memory-item-actions .hwfit-cached-menu-btn {
transform: translateY(2px) !important;
}
@media (min-width: 769px) {
.task-card .memory-item-actions {
top: 6px;
}
.task-card .memory-item-actions > .memory-item-btn {
transform: none !important;
}
}
/* All kebab menus use the same muted tone as the expand/collapse chevron. */
:is(
.memory-menu-btn,
.memory-item-actions .memory-item-btn:not(.save):not(.pin):not(.delete):not(.doclib-card-action-btn),
.hwfit-cached-menu-btn,
.cookbook-task-menu-btn,
.skill-kebab-btn,
.archive-menu-btn,
.doc-tab-menu-btn,
.email-menu-btn
) {
color: var(--color-muted, var(--fg)) !important;
}
:is(
.memory-menu-btn,
.memory-item-actions .memory-item-btn:not(.save):not(.pin):not(.delete):not(.doclib-card-action-btn),
.hwfit-cached-menu-btn,
.cookbook-task-menu-btn,
.skill-kebab-btn,
.archive-menu-btn,
.doc-tab-menu-btn,
.email-menu-btn
) svg {
color: inherit;
fill: currentColor;
}
/* Card kebabs are lightweight menu affordances, not bordered buttons. The
old base hover rule gave only some library cards a boxed outline while
chats, tasks, and cookbook stayed borderless. */
:is(
.memory-menu-btn,
.memory-item-actions .memory-item-btn:not(.save):not(.pin):not(.delete):not(.doclib-card-action-btn),
.hwfit-cached-menu-btn,
.cookbook-task-menu-btn,
.skill-kebab-btn,
.archive-menu-btn,
.doc-tab-menu-btn,
.email-menu-btn
):hover {
background: none !important;
border-color: transparent !important;
color: var(--fg) !important;
opacity: 1;
}
/* Skills used a separate, larger kebab with a different hover treatment.
Match every other card action trigger. */
.skill-kebab-btn {
box-sizing: border-box;
width: 28px;
min-width: 28px;
height: 22px;
min-height: 22px;
padding: 0;
border: 1px solid transparent;
border-radius: 6px;
color: var(--color-muted) !important;
opacity: 0.55;
top: -2px;
}
@media (max-width: 768px) {
.memory-item-actions > .memory-item-btn,
.memory-item-actions .hwfit-cached-menu-btn {
width: 40px;
min-width: 40px;
height: 40px;
min-height: 40px;
}
/* Card menus all need the same comfortable tap target. These components
previously escaped the shared action-button sizing through more-specific
desktop selectors. */
.memory-menu-btn,
.skill-kebab-btn,
.task-card .memory-item-actions .memory-item-btn {
width: 40px !important;
min-width: 40px !important;
height: 40px !important;
min-height: 40px !important;
}
.memory-menu-btn { opacity: 0.7; }
/* Document cards seat their actions on a slightly higher title baseline
than chats/research cards. Bring only that kebab down 4px. */
#doclib-modal .doclib-card[data-doc-id] > .doclib-document-header .memory-item-actions .memory-item-btn {
transform: translateY(-2px) !important;
}
}
/* Mobile: center the kebab/menu dropdowns in the viewport so they don't
slide left/right as the window width changes (they were positioned via
inline `right: ...px` relative to the kebab button). Stable position is
easier to land on by touch. The inline `top:` set by the menu code is
preserved; we only override the horizontal axis. */
@media (max-width: 768px) {
.email-card-dropdown,
.cookbook-saved-menu,
.cookbook-dep-menu {
left: 50% !important;
right: auto !important;
transform: translateX(-50%);
}
}
/* Mobile-only Cancel item appended to dropdowns (kebab/More menus). On
desktop outside-click closes them cleanly; on touch that's fiddly, so
give an explicit Cancel row. Visually separated from the action items
above by a top divider + slight muted color. */
.dropdown-cancel-mobile { display: none; }
@media (max-width: 768px) {
.dropdown-cancel-mobile {
display: flex;
border-top: 1px solid var(--border);
margin-top: 4px;
padding-top: 8px;
opacity: 0.85;
}
}
/* Launch-command Copy button morphs into Cancel once Launch has been clicked. */
.hwfit-serve-copy.hwfit-serve-cancel {
border-color: var(--color-danger, #e06c75) !important;
color: var(--color-danger, #e06c75) !important;
}
.hwfit-serve-copy.hwfit-serve-cancel:hover {
background: color-mix(in srgb, var(--color-danger, #e06c75) 14%, transparent);
}
/* One visual contract for card kebab menus. These menus are built by several
modules, and native button defaults previously made identical rows render
with different fonts, heights, and hover movement. */
:is(
.session-dropdown-menu,
.email-card-dropdown,
.memory-item-dropdown,
.task-dropdown,
.skill-kebab-menu,
.doclib-card-dropdown,
.gallery-detail-menu
) {
box-sizing: border-box;
padding: 4px !important;
color: var(--fg);
background: var(--panel, var(--bg)) !important;
border: 1px solid var(--border) !important;
border-radius: 8px !important;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3) !important;
font-family: inherit !important;
font-size: 11px !important;
line-height: 1.2;
}
:is(
.session-dropdown-menu,
.email-card-dropdown,
.memory-item-dropdown,
.task-dropdown,
.skill-kebab-menu,
.doclib-card-dropdown,
.gallery-detail-menu
) > .dropdown-item-compact {
box-sizing: border-box;
width: 100%;
min-height: 28px;
padding: 6px 8px;
gap: 10px;
border: 0;
border-radius: 6px;
color: var(--fg);
background: transparent;
font: inherit !important;
line-height: 1.2;
text-align: left;
white-space: nowrap;
}
:is(
.session-dropdown-menu,
.email-card-dropdown,
.memory-item-dropdown,
.task-dropdown,
.skill-kebab-menu,
.doclib-card-dropdown,
.gallery-detail-menu
) > .dropdown-item-compact:hover:not(:disabled) {
color: var(--fg);
background: color-mix(in srgb, var(--accent, var(--red)) 10%, transparent);
transform: none;
}
@media (max-width: 768px) {
:is(
.session-dropdown-menu,
.email-card-dropdown,
.memory-item-dropdown,
.task-dropdown,
.skill-kebab-menu,
.doclib-card-dropdown,
.gallery-detail-menu
) > .dropdown-item-compact {
min-height: 44px;
padding: 12px !important;
gap: 10px !important;
font-size: 14px !important;
}
}
/* Email modal title unread badge — small accent pill next to "Email". */
.email-lib-unread-badge {
display: inline-block;
font-size: 0.55em;
font-weight: 700;
background: var(--accent-primary, var(--red));
color: var(--bg, #1a1a1a);
border-radius: 9px;
padding: 1px 7px;
margin-left: 8px;
vertical-align: 2px;
line-height: 1.3;
letter-spacing: 0.02em;
cursor: pointer;
}
.email-lib-unread-badge.email-lib-away-badge {
background: color-mix(in srgb, var(--accent, var(--red)) 18%, transparent);
color: var(--accent, var(--red));
border: 1px solid color-mix(in srgb, var(--accent, var(--red)) 42%, transparent);
padding: 0 7px;
}
.email-lib-auto-reply-badge {
display: inline-block;
margin-left: 7px;
padding: 1px 7px;
border: 1px solid color-mix(in srgb, var(--accent, var(--red)) 48%, var(--border));
border-radius: 9px;
background: color-mix(in srgb, var(--accent, var(--red)) 15%, transparent);
color: var(--accent, var(--red));
font-size: 0.55em;
font-weight: 700;
line-height: 1.3;
letter-spacing: 0.01em;
vertical-align: 2px;
cursor: pointer;
}
.email-lib-auto-reply-status-dot {
width: 6px;
height: 6px;
margin-left: 6px;
border-radius: 50%;
background: var(--accent, var(--red));
box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent, var(--red)) 18%, transparent),
0 0 8px color-mix(in srgb, var(--accent, var(--red)) 72%, transparent);
vertical-align: 2px;
}
.modal-header h4 > .email-lib-auto-reply-badge {
font-size: 0.65em;
white-space: nowrap;
vertical-align: 1px;
}
#email-lib-modal.email-lib-unread-active .doclib-modal-content {
box-shadow:
0 0 0 1px color-mix(in srgb, var(--accent, var(--red)) 22%, transparent),
0 0 18px color-mix(in srgb, var(--accent, var(--red)) 18%, transparent),
var(--shadow-lg, 0 18px 50px rgba(0, 0, 0, 0.35));
}
#email-lib-modal .email-lib-header-actions .minimize-btn {
position: relative;
left: 6px;
}
/* Per-card prev/next nav — only visible on the currently expanded card,
sits at the right of the title row next to the done check. */
.email-card-nav-arrows {
display: none;
margin-left: auto;
gap: 2px;
flex-shrink: 0;
align-items: center;
position: relative;
top: -3px;
left: 19px;
}
.doclib-card.email-card-expanded .email-card-nav-arrows {
display: inline-flex;
}
.email-card-header-menu {
display: none;
align-items: center;
justify-content: center;
flex-shrink: 0;
width: 28px;
height: 28px;
padding: 0;
border: none;
border-radius: 6px;
background: none;
color: var(--fg);
opacity: 0.65;
cursor: pointer;
position: relative;
top: -3px;
transition: opacity 0.12s, background 0.12s;
}
.doclib-card.email-card-expanded .email-card-header-menu {
display: inline-flex;
}
.email-card-header-menu:hover {
opacity: 1;
background: color-mix(in srgb, var(--fg) 8%, transparent);
}
.email-card-nav-btn {
background: none;
border: none;
color: var(--fg);
opacity: 0.65;
cursor: pointer;
padding: 6px 8px;
border-radius: 6px;
display: inline-flex;
align-items: center;
justify-content: center;
transition: opacity 0.12s, background 0.12s;
}
.email-card-nav-btn:hover {
opacity: 1;
background: color-mix(in srgb, var(--fg) 8%, transparent);
}
/* ── Email document editor ── */
.doc-email-header {
display: flex; flex-direction: column; gap: 6px; padding: 10px 12px;
border-bottom: 1px solid var(--border); background: var(--bg); flex-shrink: 0;
}
.doc-email-fields {
display: flex;
flex-direction: column;
gap: 6px;
min-height: 0;
}
.doc-email-collapse-btn {
width: 100%;
min-height: 24px;
display: none;
align-items: center;
gap: 7px;
padding: 2px 4px 3px;
border: none;
background: transparent;
color: var(--fg);
font: inherit;
font-size: 11px;
cursor: pointer;
opacity: 0.72;
text-align: left;
}
.doc-email-collapse-btn:hover { opacity: 1; color: var(--accent, var(--red)); }
.doc-email-collapse-btn svg {
flex-shrink: 0;
opacity: 0.65;
transition: transform 0.14s ease;
}
.doc-email-collapse-summary {
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
opacity: 0.74;
}
.doc-email-header.doc-email-header-collapsed .doc-email-collapse-btn svg {
transform: rotate(180deg);
}
.email-field { display: flex; align-items: center; gap: 8px; position: relative; }
.email-field label { font-size: 11px; font-weight: 600; color: var(--fg); opacity: 0.5; min-width: 50px; text-align: right; flex-shrink: 0; }
.email-field input {
flex: 1; width: 100%; background: transparent; border: 1px solid var(--border); border-radius: 4px;
padding: 5px 8px; font-size: 13px; font-family: inherit; color: var(--fg); outline: none;
min-width: 0;
}
.email-field input:focus { border-color: var(--accent, #4a9eff); }
@container docpane (max-width: 460px) {
.doc-email-header .email-field {
display: grid;
grid-template-columns: 1fr;
gap: 3px;
align-items: stretch;
}
.doc-email-header .email-field label {
min-width: 0;
text-align: left;
}
.doc-email-header .email-field input {
width: 100%;
}
}
/* Cc toggle and attach button are absolute so they don't steal width
from the To input. Anchored to the input's vertical center + 4px
nudge so the label sits where the user expects it. */
.email-field .email-cc-toggle {
position: absolute; right: 6px; top: calc(50% + 1px); transform: translateY(-50%);
z-index: 2;
}
/* Accent-tinted prefix label (To / Cc / Bcc / Subject) sitting at
the left edge of each input. Replaces both the old <label> tag
and the all-placeholder accent. */
.email-field .email-field-prefix {
position: absolute;
left: 10px;
top: 50%;
transform: translateY(-50%);
font-size: 11px;
font-weight: 600;
color: var(--accent-primary, var(--red));
pointer-events: none;
z-index: 1;
line-height: 1;
}
.email-field input { padding-left: 44px; }
.email-field #doc-email-subject { padding-left: 64px; }
/* X close button inside Cc / Bcc fields. */
.email-field .email-cc-close {
position: absolute; right: 6px; top: calc(50% + 1px); transform: translateY(-50%);
background: none; border: none; color: var(--fg);
opacity: 0.4; cursor: pointer;
width: 22px; height: 22px;
display: inline-flex; align-items: center; justify-content: center;
border-radius: 4px;
padding: 0;
z-index: 2;
}
.email-field .email-cc-close:hover {
opacity: 1;
color: var(--accent, var(--red));
background: color-mix(in srgb, currentColor 10%, transparent);
}
.email-field input { padding-right: 60px; }
.email-field #doc-email-cc, .email-field #doc-email-bcc { padding-right: 32px; }
.email-field #doc-email-subject { padding-right: 8px; }
.doc-email-actions {
display: flex; gap: 8px; justify-content: flex-end; padding: 10px 14px;
border-top: 1px solid var(--border); background: var(--bg); flex-shrink: 0;
align-items: center;
position: relative;
z-index: 30;
pointer-events: auto;
}
#doc-actions-footer .email-send-split {
margin-left: auto;
}
.doc-save-state-icon { display: none; flex: 0 0 auto; }
.doc-save-button[data-save-state="dirty"] { color: var(--accent, var(--red)); }
.doc-save-button[data-save-state="saving"] { color: var(--fg-muted, var(--fg)); }
.doc-save-button[data-save-state="saved"] { color: var(--fg); }
.doc-save-button[data-save-state="error"] { color: var(--color-danger, #e06c75); }
.doc-stats-wrap {
position: relative;
margin-left: 0;
flex: 0 0 auto;
}
.doc-stats-btn {
height: 28px;
border: 0;
border-radius: 4px;
padding: 0 7px;
background: transparent;
color: var(--fg-muted, var(--fg));
font: inherit;
font-size: 10px;
cursor: pointer;
white-space: nowrap;
}
.doc-stats-btn:hover,
.doc-stats-btn[aria-expanded="true"] {
color: var(--fg);
background: color-mix(in srgb, var(--fg) 7%, transparent);
}
.doc-stats-btn.doc-stats-selected {
color: var(--accent, var(--red));
font-weight: 600;
}
.doc-stats-popover {
position: fixed;
right: auto;
bottom: auto;
width: 190px;
padding: 8px 10px;
border: 1px solid var(--border);
border-radius: 6px;
background: var(--panel, var(--bg));
box-shadow: 0 8px 22px rgba(0, 0, 0, 0.24);
color: var(--fg);
font-size: 11px;
}
.doc-stats-scope {
padding-bottom: 6px;
margin-bottom: 5px;
border-bottom: 1px solid var(--border);
color: var(--fg-muted, var(--fg));
font-size: 10px;
font-weight: 600;
text-transform: uppercase;
}
.doc-stats-row {
min-height: 22px;
display: flex;
align-items: center;
justify-content: space-between;
gap: 14px;
}
/* WYSIWYG email body — what the recipient sees, edited in place. */
.doc-email-richbody {
flex: 1;
min-height: 0;
overflow-y: auto;
padding: 12px 16px;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
font-size: 14px;
line-height: 1.6;
color: var(--fg);
background: var(--bg);
outline: none;
white-space: pre-wrap;
text-align: left;
word-wrap: break-word;
}
.doc-email-richbody.richtext-mode {
background: var(--bg);
}
.doc-rich-empty-import {
position: absolute;
top: 90px;
right: 18px;
bottom: auto;
left: auto;
z-index: 2;
display: flex;
pointer-events: none;
}
.doc-rich-empty-import .doc-rich-empty-import-btn {
position: static;
float: none;
margin: 0;
opacity: 1;
pointer-events: auto;
transform: none;
}
.doc-email-richbody.richtext-mode ul.rich-checklist {
list-style: none;
padding-left: 1.8em;
}
.doc-email-richbody.richtext-mode ul.rich-checklist > li {
position: relative;
min-height: 1.6em;
}
.doc-email-richbody.richtext-mode ul.rich-checklist > li::before {
content: "";
position: absolute;
left: -1.55em;
top: 0.3em;
width: 0.95em;
height: 0.95em;
box-sizing: border-box;
border: 1.5px solid color-mix(in srgb, var(--fg) 48%, transparent);
border-radius: 3px;
background: var(--sidebar-bg, var(--panel));
cursor: pointer;
}
.doc-email-richbody.richtext-mode ul.rich-checklist > li[data-checked="true"]::before {
border-color: var(--accent, var(--red));
background: var(--accent, var(--red));
}
.doc-email-richbody.richtext-mode ul.rich-checklist > li[data-checked="true"]::after {
content: "";
position: absolute;
left: -1.27em;
top: 0.44em;
width: 0.28em;
height: 0.5em;
border: solid #fff;
border-width: 0 1.5px 1.5px 0;
transform: rotate(45deg);
pointer-events: none;
}
.doc-email-richbody.richtext-mode ul.rich-checklist > li[data-checked="true"] {
color: color-mix(in srgb, var(--fg) 62%, transparent);
text-decoration: line-through;
}
.doc-email-richbody.richtext-mode hr {
border: 0;
border-top: 1px solid var(--border);
margin: 1.25em 0;
}
.doc-email-richbody.richtext-mode hr.richtext-page-break {
height: 8px;
border-top: 1px dashed color-mix(in srgb, var(--fg) 42%, transparent);
border-bottom: 1px dashed color-mix(in srgb, var(--fg) 42%, transparent);
margin: 1.6em 0;
opacity: 0.8;
}
.doc-email-richbody.richtext-mode table {
width: 100%;
margin: 12px 0;
border-collapse: collapse;
table-layout: fixed;
}
.doc-email-richbody.richtext-mode th,
.doc-email-richbody.richtext-mode td {
min-width: 48px;
padding: 7px 8px;
border: 1px solid var(--border);
vertical-align: top;
overflow-wrap: anywhere;
}
.doc-email-richbody.richtext-mode th {
background: color-mix(in srgb, var(--sidebar-bg, var(--panel)) 85%, var(--fg) 15%);
font-weight: 600;
}
.doc-email-richbody.richtext-mode code,
.doc-email-richbody.richtext-mode span[style*="OdysseusInlineCode"] {
padding: 0.12em 0.35em;
border: 1px solid color-mix(in srgb, var(--border) 80%, transparent);
border-radius: 3px;
background: color-mix(in srgb, var(--fg) 8%, transparent);
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
font-size: 0.9em;
white-space: break-spaces;
}
.doc-email-richbody.richtext-mode pre {
margin: 1em 0;
padding: 12px 14px;
overflow-x: auto;
border: 1px solid var(--border);
border-radius: 4px;
background: color-mix(in srgb, var(--sidebar-bg, var(--panel)) 82%, #000 18%) !important;
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
font-size: 0.9em;
line-height: 1.5;
white-space: pre-wrap;
tab-size: 2;
}
::highlight(doc-find-results) {
color: inherit;
background-color: color-mix(in srgb, #facc15 48%, transparent);
}
::highlight(doc-find-current) {
color: inherit;
background-color: color-mix(in srgb, var(--accent, #ef4444) 68%, #facc15);
}
::highlight(doc-ai-selections) {
color: inherit;
background-color: color-mix(in srgb, var(--accent, #ef4444) 30%, transparent);
}
.doc-email-richbody img.richtext-image {
display: block;
margin: 12px 0;
max-width: 100%;
height: auto;
border-radius: 4px;
cursor: pointer;
}
.doc-email-richbody figure.richtext-image {
margin: 12px 0;
max-width: 100%;
}
.doc-email-richbody figure.richtext-image:not(:has(img)) { display: none; }
.doc-email-richbody figure.richtext-image img.richtext-image {
display: block;
margin-top: 0;
margin-bottom: 0;
max-width: 100%;
height: auto;
border-radius: 4px;
}
.doc-email-richbody figure.richtext-image:has(img.richtext-image-size-60) .richtext-image-caption { width: 60%; }
.doc-email-richbody figure.richtext-image:has(img.richtext-image-size-35) .richtext-image-caption { width: 35%; }
.doc-email-richbody figure.richtext-image:has(img.richtext-image-align-left) .richtext-image-caption { margin-left: 0; margin-right: auto; }
.doc-email-richbody figure.richtext-image:has(img.richtext-image-align-center) .richtext-image-caption { margin-left: auto; margin-right: auto; }
.doc-email-richbody figure.richtext-image:has(img.richtext-image-align-right) .richtext-image-caption { margin-left: auto; margin-right: 0; }
.doc-email-richbody img.richtext-image-size-100 { width: 100%; }
.doc-email-richbody img.richtext-image-size-60 { width: 60%; }
.doc-email-richbody img.richtext-image-size-35 { width: 35%; }
.doc-email-richbody img.richtext-image-align-left { margin-left: 0; margin-right: auto; }
.doc-email-richbody img.richtext-image-align-center { margin-left: auto; margin-right: auto; }
.doc-email-richbody img.richtext-image-align-right { margin-left: auto; margin-right: 0; }
.doc-email-richbody img.richtext-image[data-editor-image-selected] {
outline: 2px solid var(--accent, var(--red));
outline-offset: 3px;
}
.doc-rich-image-toolbar {
position: fixed;
display: inline-flex;
align-items: center;
gap: 2px;
padding: 2px;
border: 1px solid var(--border);
border-radius: 5px;
background: var(--bg);
color: var(--fg);
box-shadow: 0 3px 12px color-mix(in srgb, var(--fg) 18%, transparent);
z-index: 10032;
}
.doc-rich-image-toolbar button {
width: 24px;
height: 24px;
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0;
border: 0;
border-radius: 3px;
background: transparent;
color: inherit;
cursor: pointer;
}
.doc-rich-image-toolbar button:hover {
background: color-mix(in srgb, var(--accent, var(--red)) 14%, transparent);
color: var(--accent, var(--red));
}
.doc-rich-image-toolbar .doc-rich-image-remove:hover {
color: var(--accent, var(--red));
}
.doc-rich-image-source-menu {
position: fixed;
width: 260px;
min-width: 260px;
padding: 5px;
border: 1px solid var(--border);
border-radius: 6px;
background: var(--bg);
color: var(--fg);
box-shadow: 0 4px 16px color-mix(in srgb, var(--fg) 20%, transparent);
z-index: 10033;
font-size: 11px;
}
.doc-rich-image-source-title {
padding: 5px 7px 4px;
color: var(--fg);
font-weight: 700;
opacity: .75;
}
.doc-rich-image-source-menu > button,
.doc-rich-gallery-item {
width: 100%;
display: flex;
align-items: center;
gap: 7px;
padding: 7px 8px;
border: 0;
border-radius: 4px;
background: transparent;
color: var(--fg);
font: inherit;
text-align: left;
cursor: pointer;
}
.doc-rich-image-source-menu > button[data-image-source="computer"] {
padding-left: 9px;
}
.doc-rich-image-source-menu > button:hover,
.doc-rich-gallery-item:hover {
background: color-mix(in srgb, var(--accent, var(--red)) 14%, transparent);
color: var(--accent, var(--red));
}
.doc-rich-gallery-list {
display: grid;
gap: 2px;
max-height: 300px;
overflow-y: auto;
}
.doc-rich-gallery-item {
min-height: 44px;
min-width: 0;
}
.doc-rich-gallery-item > span:last-child {
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.doc-rich-gallery-thumb {
width: 40px;
height: 40px;
flex: 0 0 40px;
border: 1px solid var(--border);
border-radius: 4px;
background-position: center;
background-size: cover;
background-repeat: no-repeat;
}
.rich-color-letter {
border-bottom: 2px solid var(--accent, var(--red));
font-weight: 700;
line-height: 14px;
}
.rich-color-swatch {
width: 13px !important;
height: 13px !important;
border: 1px solid color-mix(in srgb, var(--fg) 35%, transparent);
border-radius: 50%;
}
.rich-highlight-swatch { border-radius: 50%; }
.rich-color-swatch.is-transparent {
background:
linear-gradient(135deg, transparent 43%, var(--red) 44%, var(--red) 56%, transparent 57%),
var(--bg);
}
.rich-color-palette-menu {
min-width: min(292px, calc(100vw - 16px));
}
.rich-color-palette-menu .rich-color-reset {
border-bottom: 1px solid color-mix(in srgb, var(--border) 70%, transparent);
margin-bottom: 3px;
padding-bottom: 7px;
}
.rich-color-palette-grid {
display: grid;
grid-template-columns: repeat(2, minmax(126px, 1fr));
gap: 0 4px;
padding: 0 4px;
}
.rich-color-palette-group {
min-width: 0;
}
.rich-color-palette-label {
padding: 4px 8px 3px;
color: color-mix(in srgb, var(--fg) 58%, transparent);
font-size: 9px;
font-weight: 600;
text-transform: uppercase;
}
.rich-color-palette-group .doc-overflow-item {
min-width: 0;
padding-inline: 8px;
}
.rich-toolbar-color-custom {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
margin-top: 3px;
padding: 7px 9px 4px 10px;
border-top: 1px solid color-mix(in srgb, var(--border) 70%, transparent);
color: var(--fg);
font-size: 11px;
}
.rich-toolbar-color-input.cp-swatch-input {
width: 22px;
height: 22px;
flex: 0 0 22px;
padding: 0;
border: 1px solid color-mix(in srgb, var(--fg) 28%, var(--border));
border-radius: 50%;
cursor: pointer;
}
.rich-toolbar-color-input.cp-swatch-input:focus-visible {
outline: 2px solid var(--accent, var(--red));
outline-offset: 2px;
}
.rich-toolbar-slider-row {
display: grid;
grid-template-columns: auto minmax(104px, 1fr) 42px;
align-items: center;
gap: 9px;
min-width: 220px;
padding: 10px;
color: var(--fg);
font-size: 11px;
}
.rich-toolbar-range {
width: 100%;
min-width: 0;
height: 8px;
margin: 0;
border: 0;
border-radius: 999px;
background: color-mix(in srgb, var(--fg) 25%, transparent);
accent-color: var(--red);
cursor: pointer;
-webkit-appearance: none;
appearance: none;
}
.rich-toolbar-range::-webkit-slider-thumb {
width: 9px;
height: 9px;
border: 0;
border-radius: 50%;
background: var(--red);
cursor: pointer;
-webkit-appearance: none;
appearance: none;
transition: width 0.12s ease, height 0.12s ease;
}
.rich-toolbar-range:hover::-webkit-slider-thumb,
.rich-toolbar-range:focus::-webkit-slider-thumb,
.rich-toolbar-range:active::-webkit-slider-thumb {
width: 16px;
height: 16px;
}
.rich-toolbar-range::-moz-range-thumb {
width: 9px;
height: 9px;
border: 0;
border-radius: 50%;
background: var(--red);
cursor: pointer;
transition: width 0.12s ease, height 0.12s ease;
}
.rich-toolbar-range:hover::-moz-range-thumb,
.rich-toolbar-range:focus::-moz-range-thumb,
.rich-toolbar-range:active::-moz-range-thumb {
width: 16px;
height: 16px;
}
.rich-toolbar-range:focus-visible {
outline: 2px solid var(--accent, var(--red));
outline-offset: 4px;
}
.rich-toolbar-slider-value {
width: 42px;
box-sizing: border-box;
padding: 2px 3px;
border: 1px solid transparent;
border-radius: 3px;
background: transparent;
text-align: right;
color: color-mix(in srgb, var(--fg) 68%, transparent);
font-variant-numeric: tabular-nums;
-webkit-appearance: textfield;
appearance: textfield;
}
.rich-toolbar-slider-value::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
.rich-toolbar-slider-value:focus {
border-color: var(--accent, var(--red));
outline: none;
color: var(--fg);
}
.rich-script-icon,
.rich-font-icon,
.rich-font-size-icon {
display: inline-block;
line-height: 1;
font-size: 11px;
}
.rich-highlight-icon {
display: block;
flex-shrink: 0;
color: var(--accent-primary, var(--red));
}
.rich-script-icon sup,
.rich-script-icon sub {
font-size: 7px;
line-height: 0;
}
.rich-font-icon {
font-family: Georgia, serif;
font-size: 12px;
}
.rich-font-size-icon {
min-width: 16px;
font-size: 10px;
font-weight: 600;
font-variant-numeric: tabular-nums;
text-align: center;
}
.rich-align-center { text-align: center; }
.rich-align-right { text-align: right; }
.doc-email-richbody .email-quoted-history {
margin-top: 14px;
padding: 10px 0 10px 12px;
border-left: 3px solid var(--border);
color: color-mix(in srgb, var(--fg) 70%, transparent);
font-size: 0.92em;
line-height: 1.45;
white-space: pre-wrap;
user-select: text;
pointer-events: none;
}
.doc-email-richbody h1, .doc-email-richbody h2, .doc-email-richbody h3,
.doc-email-richbody h4, .doc-email-richbody h5, .doc-email-richbody h6 { margin: 0.4em 0; }
.email-more-menu {
position: absolute; bottom: 100%; right: 0; margin-bottom: 6px;
min-width: 160px; background: var(--bg); border: 1px solid var(--border);
border-radius: 6px; box-shadow: 0 -4px 12px rgba(0,0,0,0.2); padding: 4px;
z-index: 100;
}
.email-send-btn {
background: color-mix(in srgb, var(--accent-primary, var(--red)) 20%, transparent);
color: var(--accent-primary, var(--red));
border: 1px solid color-mix(in srgb, var(--accent-primary, var(--red)) 50%, transparent);
border-radius: 6px;
padding: 0 14px; height: 28px; font-size: 11px; font-weight: 600; cursor: pointer;
font-family: inherit; transition: all 0.15s; white-space: nowrap;
display: inline-flex; align-items: center; gap: 6px;
}
/* Split send button: [ Send │ ▾ ] — the caret drops the send-options menu UP. */
.email-send-split { position: relative; display: inline-flex; }
.email-send-split .email-send-main {
border-top-right-radius: 0; border-bottom-right-radius: 0; border-right: none;
}
.email-send-split .email-send-caret {
border-top-left-radius: 0; border-bottom-left-radius: 0;
padding: 0 8px; gap: 0;
/* its left border is the single divider between the two halves */
border-left: 1px solid color-mix(in srgb, var(--accent-primary, var(--red)) 50%, transparent);
}
.email-send-split .email-send-caret svg { transition: transform 0.15s ease; }
.email-send-split .email-send-caret[aria-expanded="true"] svg { transform: none; }
.email-send-btn svg { flex-shrink: 0; }
.email-send-btn:hover {
background: color-mix(in srgb, var(--accent-primary, var(--red)) 30%, transparent);
border-color: var(--accent-primary, var(--red));
}
.email-draft-btn {
background: none; border: 1px solid var(--border);
color: color-mix(in srgb, var(--fg) 60%, transparent);
border-radius: 6px;
padding: 0 12px; height: 28px; font-size: 11px; cursor: pointer;
font-family: inherit; transition: all 0.15s; white-space: nowrap;
}
.email-draft-btn:hover { border-color: var(--fg); color: var(--fg); }
.email-discard-btn {
background: transparent;
/* Dim the label text via color-mix instead of `opacity:0.6` on the whole
button — opacity multiplies through to the SVG and washes out the accent
X glyph. Per-element color dimming keeps the X at full accent strength. */
color: color-mix(in srgb, var(--fg) 60%, transparent);
border: 1px solid var(--border); border-radius: 6px;
padding: 6px 14px; font-size: 12px; cursor: pointer; font-family: inherit;
}
/* The ✕ glyph itself reads in accent. */
.email-discard-btn svg { color: var(--accent-primary, var(--red)); opacity: 1; }
.email-discard-btn:hover { opacity: 1; color: var(--red, #e55); border-color: var(--red, #e55); }
/* Compose email "more" menu button — icon only, matches draft btn height */
#doc-email-more-btn {
background: none; border: 1px solid var(--border);
color: color-mix(in srgb, var(--fg) 60%, transparent);
border-radius: 6px;
width: 28px; height: 28px; padding: 0;
cursor: pointer; font-family: inherit; transition: all 0.15s;
display: inline-flex; align-items: center; justify-content: center;
}
#doc-email-more-btn:hover {
border-color: var(--fg); color: var(--fg);
}
.email-more-wrap { display: inline-flex; }
.email-attachments {
display: flex; flex-wrap: wrap; gap: 6px; padding: 4px 0 0 58px;
}
.email-attachment-chip {
display: inline-flex; align-items: center; gap: 4px;
padding: 4px 8px; font-size: 11px; background: var(--hover-bg, rgba(255,255,255,0.05));
border: 1px solid var(--border); border-radius: 12px; color: var(--fg);
text-decoration: none; cursor: pointer; transition: background 0.15s, border-color 0.15s;
max-width: 200px; min-width: 0;
}
.email-attachment-chip:hover {
background: color-mix(in srgb, var(--accent) 15%, transparent);
border-color: var(--accent);
}
.email-attachment-chip.is-expanded {
max-width: 90vw;
}
.email-attachment-chip > span:not(.att-size):not(.email-attachment-open):not(.email-attachment-download):not(.email-attachment-calendar-open) {
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
flex: 1 1 auto; min-width: 0;
}
.email-attachment-chip.is-expanded > span:not(.att-size):not(.email-attachment-open):not(.email-attachment-download):not(.email-attachment-calendar-open) {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.email-attachment-chip-related {
border-color: color-mix(in srgb, var(--accent) 30%, var(--border));
}
/* "Open in editor" launch icon — same prominent style on desktop AND mobile
(was 24px / dim / no border on desktop, easy to miss). Accent-tinted
background + border makes it read as a real action. */
.email-attachment-open,
.email-attachment-download,
.email-attachment-calendar-open,
.cal-event-email-source {
display: inline-flex; align-items: center; gap: 4px;
height: 22px; padding: 0 9px; border-radius: 999px;
margin-left: 6px; flex: 0 0 auto;
min-width: 52px; justify-content: center;
font-size: 10px; font-weight: 500; letter-spacing: 0.02em;
color: var(--accent-primary, var(--red));
background: color-mix(in srgb, var(--accent-primary, var(--red)) 10%, transparent);
border: 1px solid color-mix(in srgb, var(--accent-primary, var(--red)) 40%, transparent);
cursor: pointer; transition: background 0.1s, border-color 0.1s, color 0.1s;
}
.email-attachment-open {
width: 24px;
min-width: 24px;
padding: 0;
margin-left: 4px;
}
.email-attachment-open svg,
.email-attachment-open > svg,
.email-attachment-download svg,
.email-attachment-download > svg,
.email-attachment-calendar-open svg,
.email-attachment-calendar-open > svg,
.cal-event-email-source svg,
.cal-event-email-source > svg {
width: 12px; height: 12px;
opacity: 0.9;
}
.email-attachment-open:hover,
.email-attachment-download:hover,
.email-attachment-calendar-open:hover,
.cal-event-email-source:hover {
background: color-mix(in srgb, var(--accent-primary, var(--red)) 22%, transparent);
border-color: color-mix(in srgb, var(--accent-primary, var(--red)) 70%, transparent);
}
.email-attachment-download {
width: 24px;
min-width: 24px;
padding: 0;
margin-left: 4px;
}
.email-attachment-calendar-open {
width: 24px;
min-width: 24px;
padding: 0;
margin-left: 4px;
}
.cal-event-email-source {
width: 24px;
min-width: 24px;
padding: 0;
margin-left: 4px;
}
.email-attachment-open-label { line-height: 1; }
.email-attachment-chip.is-expanded .email-attachment-open,
.email-attachment-chip.is-expanded .email-attachment-download,
.email-attachment-chip.is-expanded .email-attachment-calendar-open {
width: 24px;
min-width: 24px;
padding: 0;
margin-left: 4px;
}
.email-attachment-chip.is-expanded .email-attachment-open-label {
display: none;
}
@media (max-width: 768px) {
.doc-email-collapse-btn {
background: inherit;
}
/* Mobile: keep the pill but ensure a comfortable touch target. */
.email-attachment-open {
height: 26px; padding: 0 10px;
min-height: 26px !important;
min-width: 58px;
}
.email-attachments,
.email-compose-atts {
flex-wrap: nowrap;
overflow-x: auto;
overflow-y: hidden;
-webkit-overflow-scrolling: touch;
scrollbar-width: none;
padding-left: 0;
padding-bottom: 2px;
}
.email-attachments::-webkit-scrollbar,
.email-compose-atts::-webkit-scrollbar {
display: none;
}
/* Attachment chip body — modest minimum height so the open icon sits
neatly without dominating. */
.email-attachment-chip,
.email-compose-chip {
flex: 0 0 auto;
padding: 6px 8px !important;
min-height: 36px !important;
}
.email-attachment-chip.is-expanded {
flex-wrap: nowrap;
align-items: center;
max-width: min(92vw, 360px);
}
.email-attachment-chip.is-expanded > span:not(.att-size):not(.email-attachment-open):not(.email-attachment-download):not(.email-attachment-calendar-open) {
flex: 1 1 auto;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
line-height: 1.25;
min-width: 0;
}
.email-attachment-chip.is-expanded .att-size {
margin-left: 0;
}
.email-attachment-chip.is-expanded .email-attachment-open,
.email-attachment-chip.is-expanded .email-attachment-download,
.email-attachment-chip.is-expanded .email-attachment-calendar-open {
width: 28px;
min-width: 28px;
padding: 0;
margin-left: 4px;
}
.email-compose-chip .compose-chip-name {
max-width: 190px;
}
}
/* Compose attachment chips (when sending new email) */
.email-compose-atts {
display: flex; flex-direction: row; flex-wrap: wrap; align-items: center; gap: 6px;
padding: 6px 0 0 0;
}
.email-compose-chip {
display: inline-flex; align-items: center; gap: 4px;
flex: 0 1 auto;
min-width: 0;
max-width: min(240px, 100%);
height: 24px; min-height: 24px; box-sizing: border-box;
padding: 2px 3px 2px 7px; font-size: 11px;
background: var(--hover-bg, rgba(255,255,255,0.05));
border: 1px solid var(--border); border-radius: 12px; color: var(--fg);
}
.email-compose-chip .compose-chip-name { max-width: 180px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.email-compose-chip .compose-chip-remove {
background: none; border: none; color: var(--fg); opacity: 0.5;
height: 18px; font-size: 14px; line-height: 18px; padding: 0 3px; cursor: pointer;
flex-shrink: 0;
}
.email-compose-chip .compose-chip-remove:hover { opacity: 1; color: var(--red, #e55); }
.pdf-annotation-line-value {
width: 48px;
height: 22px;
box-sizing: border-box;
padding: 0 5px;
border: 1px solid var(--border);
border-radius: 4px;
outline: none;
background: var(--bg-elev, var(--panel));
color: var(--fg);
font-family: inherit;
font-size: 10px;
font-weight: 500;
line-height: 1;
text-align: right;
}
.pdf-annotation-line-value:hover { border-color: color-mix(in srgb, var(--fg) 38%, var(--border)); }
.pdf-annotation-line-value:focus { border-color: var(--accent, var(--red)); }
.email-odysseus-attach-menu {
position: fixed;
z-index: 10050;
width: 300px;
max-width: calc(100vw - 16px);
max-height: min(420px, calc(100vh - 16px));
padding: 7px;
border: 1px solid var(--border);
border-radius: 7px;
background: var(--bg);
color: var(--fg);
box-shadow: 0 12px 30px rgba(0,0,0,0.28);
overflow: hidden;
}
.email-odysseus-attach-local {
width: 100%;
height: 30px;
display: flex;
align-items: center;
gap: 7px;
padding: 0 9px;
border: 1px solid color-mix(in srgb, var(--accent-primary, var(--red)) 35%, var(--border));
border-radius: 5px;
background: color-mix(in srgb, var(--accent-primary, var(--red)) 9%, transparent);
color: var(--fg);
font: inherit;
font-size: 11px;
cursor: pointer;
}
.email-odysseus-attach-local:hover {
background: color-mix(in srgb, var(--accent-primary, var(--red)) 16%, transparent);
border-color: color-mix(in srgb, var(--accent-primary, var(--red)) 55%, var(--border));
}
.email-odysseus-attach-tabs {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 5px;
margin: 7px 0;
}
.email-odysseus-attach-tabs button {
height: 26px;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 6px;
border: 1px solid var(--border);
border-radius: 5px;
background: transparent;
color: var(--fg);
opacity: 0.72;
font: inherit;
font-size: 11px;
cursor: pointer;
}
.email-odysseus-attach-tabs button.active {
opacity: 1;
color: var(--accent-primary, var(--red));
border-color: color-mix(in srgb, var(--accent-primary, var(--red)) 45%, var(--border));
background: color-mix(in srgb, var(--accent-primary, var(--red)) 8%, transparent);
}
.email-odysseus-attach-tabs button svg {
flex-shrink: 0;
}
.email-odysseus-attach-search-wrap {
height: 28px;
display: flex;
align-items: center;
gap: 6px;
margin: -1px 0 7px;
padding: 0 8px;
border: 1px solid var(--border);
border-radius: 5px;
background: color-mix(in srgb, var(--fg) 3%, transparent);
color: color-mix(in srgb, var(--fg) 48%, transparent);
}
.email-odysseus-attach-search-wrap:focus-within {
border-color: color-mix(in srgb, var(--accent-primary, var(--red)) 45%, var(--border));
color: var(--accent-primary, var(--red));
background: color-mix(in srgb, var(--accent-primary, var(--red)) 6%, transparent);
}
.email-odysseus-attach-search {
min-width: 0;
flex: 1;
border: 0;
outline: 0;
background: transparent;
color: var(--fg);
font: inherit;
font-size: 11px;
}
.email-odysseus-attach-search::placeholder {
color: color-mix(in srgb, var(--fg) 38%, transparent);
}
.email-odysseus-attach-list {
max-height: 320px;
overflow: auto;
display: flex;
flex-direction: column;
gap: 4px;
}
.email-odysseus-attach-row {
width: 100%;
min-height: 38px;
display: flex;
align-items: center;
gap: 8px;
padding: 6px 7px;
border: 1px solid transparent;
border-radius: 5px;
background: transparent;
color: var(--fg);
text-align: left;
font: inherit;
cursor: pointer;
}
.email-odysseus-attach-row:hover {
background: var(--hover-bg, rgba(255,255,255,0.06));
border-color: var(--border);
}
.email-odysseus-attach-row.is-selected {
background: color-mix(in srgb, var(--accent-primary, var(--red)) 10%, transparent);
border-color: color-mix(in srgb, var(--accent-primary, var(--red)) 45%, var(--border));
}
.email-odysseus-attach-dot {
width: 8px;
height: 8px;
flex: 0 0 auto;
display: inline-block;
border: 1px solid var(--border);
border-radius: 50%;
background: color-mix(in srgb, var(--fg) 4%, transparent);
}
.email-odysseus-attach-row.is-selected .email-odysseus-attach-dot {
border-color: var(--accent-primary, var(--red));
background: var(--accent-primary, var(--red));
box-shadow: 0 0 0 1px color-mix(in srgb, var(--accent-primary, var(--red)) 18%, transparent);
}
.email-odysseus-attach-icon,
.email-odysseus-attach-thumb {
width: 28px;
height: 28px;
flex: 0 0 auto;
display: inline-flex;
align-items: center;
justify-content: center;
border-radius: 4px;
background: color-mix(in srgb, var(--fg) 7%, transparent);
overflow: hidden;
}
.email-odysseus-attach-main {
min-width: 0;
flex: 1;
display: flex;
flex-direction: column;
gap: 2px;
}
.email-odysseus-attach-title,
.email-odysseus-attach-meta {
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.email-odysseus-attach-title {
font-size: 11px;
line-height: 1.2;
}
.email-odysseus-attach-meta {
font-size: 10px;
line-height: 1.15;
opacity: 0.52;
}
.email-odysseus-attach-empty {
padding: 14px 8px;
color: var(--muted, #888);
font-size: 11px;
text-align: center;
}
.email-odysseus-attach-actions {
display: flex;
align-items: center;
gap: 6px;
margin-top: 2px;
padding-top: 5px;
border-top: 1px solid color-mix(in srgb, var(--border) 75%, transparent);
background: var(--bg);
position: sticky;
bottom: 0;
}
.email-odysseus-attach-count {
flex: 1;
min-width: 0;
color: var(--muted, #888);
font-size: 11px;
}
.email-odysseus-attach-selected {
height: 28px;
min-width: 72px;
padding: 0 12px;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 6px;
border-radius: 999px;
border: 1px solid color-mix(in srgb, var(--accent-primary, var(--red)) 45%, var(--border));
background: var(--accent-primary, var(--red));
color: #fff;
font: inherit;
font-size: 11px;
cursor: pointer;
}
.email-odysseus-attach-selected svg {
flex-shrink: 0;
}
.email-cc-toggle {
background: none; border: none; color: var(--fg);
opacity: 0.4; font-size: 11px; cursor: pointer;
padding: 4px 8px; font-family: inherit;
}
.email-cc-toggle:hover {
opacity: 1;
color: var(--accent, #4a9eff);
background: none !important;
}
@media (max-width: 768px) {
.doc-email-collapse-btn {
display: flex;
}
}
.email-autocomplete {
position: absolute; top: 100%; left: 58px; right: 0; z-index: 1000;
background: var(--bg); border: 1px solid var(--border); border-radius: 6px;
box-shadow: 0 4px 12px rgba(0,0,0,0.2); max-height: 240px; overflow-y: auto;
margin-top: 2px;
}
.contact-suggestion {
display: flex; justify-content: space-between; gap: 8px;
padding: 6px 10px; font-size: 12px; cursor: pointer;
border-bottom: 1px solid var(--border);
}
.contact-suggestion:last-child { border-bottom: none; }
.contact-suggestion:hover,
.contact-suggestion.active,
.contact-suggestion[aria-selected="true"] {
background: color-mix(in srgb, var(--accent-primary, var(--accent, var(--red))) 15%, transparent);
outline: 1px solid color-mix(in srgb, var(--accent-primary, var(--accent, var(--red))) 40%, transparent);
outline-offset: -1px;
}
.contact-suggestion .contact-name { font-weight: 600; color: var(--fg); }
.contact-suggestion .contact-email { opacity: 0.6; font-size: 11px; }
.contact-suggestion-status {
padding: 7px 10px;
color: color-mix(in srgb, var(--fg) 65%, transparent);
font-size: 11px;
cursor: default;
}
.contact-suggestion-status.is-loading { opacity: 0.72; }
.contact-suggestion-status.is-unavailable {
color: color-mix(in srgb, var(--red) 82%, var(--fg));
}
.email-ai-reply-btn {
background: none;
color: color-mix(in srgb, var(--fg) 60%, transparent);
border: 1px solid var(--border);
border-radius: 6px;
padding: 0 12px; height: 28px; font-size: 11px; cursor: pointer;
font-family: inherit; transition: all 0.15s;
display: inline-flex; align-items: center; white-space: nowrap;
}
.email-ai-reply-btn:hover {
border-color: var(--accent, #4a9eff);
color: var(--accent, #4a9eff);
}
/* Align select/new buttons in popup library toolbar */
#email-lib-select-btn, #email-lib-refresh-btn, #email-lib-settings-btn, #email-lib-compose-btn { position: relative; top: -4px; }
/* Select + Refresh sit slightly lower than Compose on desktop. */
#email-lib-select-btn, #email-lib-refresh-btn, #email-lib-settings-btn { top: -2px; }
#email-lib-modal.email-settings-mode .email-accounts-row,
#email-lib-modal.email-settings-mode .admin-card > .memory-toolbar,
#email-lib-modal.email-settings-mode #email-lib-bulk,
#email-lib-modal.email-settings-mode #email-lib-grid,
#email-lib-modal.email-settings-mode #email-lib-sync-status,
#email-lib-modal.email-settings-mode #email-lib-fab {
display: none !important;
}
#email-lib-settings-page[hidden] {
display: none !important;
}
#email-lib-modal.email-settings-mode #email-lib-settings-page {
display: flex;
}
.email-settings-page {
display: flex;
flex: 1;
min-height: 0;
min-width: 0;
flex-direction: column;
gap: 6px;
overflow: hidden;
padding: 2px 0 8px;
width: 100%;
box-sizing: border-box;
-webkit-overflow-scrolling: touch;
}
.settings-email-preferences-card {
display: contents;
}
.settings-email-preferences-card .email-settings-section {
margin: 0 0 10px;
padding: 14px 12px 12px;
background: var(--panel);
}
.settings-email-preferences-card .email-settings-section:last-child {
margin-bottom: 0;
}
.settings-email-preferences-card .email-settings-style-section {
margin-bottom: 4px;
}
.settings-email-default-card #settings-email-default-host {
display: flex;
justify-content: flex-end;
min-width: 0;
margin-left: auto;
}
.settings-email-default-card .settings-email-default-title {
display: flex;
align-items: center;
justify-content: space-between;
gap: 10px;
}
.settings-email-default-card .settings-email-default-title > span {
min-width: 0;
}
.settings-email-default-card .settings-email-default-title > span > svg {
color: var(--accent, var(--red));
}
.settings-email-default-card .email-settings-account-picker {
margin-left: 0 !important;
}
.settings-email-default-card .email-settings-support-copy {
position: relative;
top: 6px;
}
.settings-email-default-spacer {
height: 12px;
}
.settings-email-default-card .cookbook-srv-default-label {
position: relative;
top: 2px;
}
.settings-email-default-card .cookbook-srv-default-icon > svg {
position: relative;
top: 7px;
}
.settings-email-settings-legacy {
display: none;
}
/* Keep the standalone Email Settings cards aligned with the expandable
preference cards below them. */
[data-settings-panel="email"] > .admin-card {
padding-top: 14px;
}
.email-settings-page-host {
display: flex;
flex: 0 0 auto;
min-height: 0;
padding: 0;
overflow: visible;
}
.settings-email-preferences-card > .email-settings-page-host { width: 100%; }
.email-settings-page-head {
display: flex;
align-items: center;
gap: 8px;
min-width: 0;
min-height: 32px;
padding-bottom: 2px;
border-bottom: 1px solid color-mix(in srgb, var(--border) 70%, transparent);
}
.email-settings-account-picker {
min-width: 0;
max-width: 100%;
}
.email-settings-account-picker select {
min-width: 0;
max-width: 100%;
}
.email-settings-back {
position: relative;
top: -2px;
}
.email-settings-header-back {
background: transparent;
color: color-mix(in srgb, var(--fg) 58%, transparent);
border: 1px solid transparent;
width: auto;
height: 24px;
padding: 0 8px 0 6px;
align-items: center;
justify-content: center;
gap: 4px;
cursor: pointer;
border-radius: 999px;
flex-shrink: 0;
position: relative;
font-size: 11px;
font-weight: 600;
line-height: 1;
}
.email-settings-header-back:hover {
background: color-mix(in srgb, var(--fg) 10%, transparent);
border-color: color-mix(in srgb, var(--fg) 12%, transparent);
color: var(--fg);
}
.email-settings-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
margin-bottom: 8px;
}
.email-settings-title {
display: inline-flex;
align-items: center;
gap: 6px;
flex: 1 1 auto;
width: 100%;
min-width: 0;
font-size: 12px;
font-weight: 700;
}
.email-settings-title svg {
color: var(--accent, var(--red));
flex-shrink: 0;
}
.email-settings-close {
width: 24px;
height: 24px;
border: 1px solid var(--border);
border-radius: 6px;
background: transparent;
color: color-mix(in srgb, var(--fg) 70%, transparent);
cursor: pointer;
font-size: 14px;
line-height: 1;
}
.email-settings-close:hover {
color: var(--fg);
border-color: color-mix(in srgb, var(--accent, var(--red)) 45%, var(--border));
}
.email-settings-body {
display: flex;
flex-direction: column;
flex: 1 1 auto;
gap: 6px;
padding-top: 4px;
box-sizing: border-box;
min-width: 0;
min-height: 0;
overflow-y: auto;
overflow-x: hidden;
overscroll-behavior: contain;
}
.email-settings-loading,
.email-settings-error {
font-size: 12px;
color: color-mix(in srgb, var(--fg) 65%, transparent);
padding: 8px 2px;
}
.email-settings-loading {
display: inline-flex;
align-items: center;
gap: 7px;
}
.email-settings-loading-css-whirlpool {
display: inline-block;
width: 14px;
height: 14px;
box-sizing: border-box;
border: 1.5px solid color-mix(in srgb, var(--accent, var(--red)) 28%, transparent);
border-top-color: var(--accent, var(--red));
border-right-color: color-mix(in srgb, var(--accent, var(--red)) 72%, transparent);
border-radius: 50%;
animation: whirlpool-spin 0.72s linear infinite;
flex: 0 0 auto;
}
.email-settings-loading-spinner {
display: inline-flex;
align-items: center;
justify-content: center;
width: 16px;
height: 16px;
color: var(--accent, var(--red));
}
.email-settings-section {
display: flex;
flex-direction: column;
flex: 0 0 auto;
gap: 7px;
margin: 0;
padding: 14px 8px 8px;
min-width: 0;
box-sizing: border-box;
border: 1px solid var(--border);
border-radius: 8px;
background: color-mix(in srgb, var(--fg) 3%, transparent);
transition: opacity 0.15s ease, background 0.15s ease;
}
.email-settings-section.is-disabled {
opacity: 0.58;
background: color-mix(in srgb, var(--fg) 2%, transparent);
}
.email-settings-section-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
}
.email-settings-section-head > div:first-child {
min-width: 0;
flex: 1 1 auto;
}
.email-settings-section-head > .email-settings-enabled-control,
.email-settings-section-head > button {
margin-left: auto;
}
.email-settings-section-toggle {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
width: 100%;
min-width: 0;
padding: 0;
border: 0;
background: transparent;
color: inherit;
text-align: left;
cursor: pointer;
}
.email-settings-section-toggle:hover,
.email-settings-section-toggle:active {
background: transparent;
}
.email-settings-section-toggle-copy {
display: flex;
flex-direction: column;
align-items: flex-start;
min-width: 0;
flex: 1 1 auto;
}
.email-settings-section-toggle > .email-settings-enabled-control {
margin-left: auto;
flex: 0 0 auto;
}
.email-settings-section-chevron {
flex: 0 0 auto;
color: color-mix(in srgb, var(--fg) 62%, transparent);
transition: transform .14s ease, color .14s ease;
}
.email-settings-section-toggle:hover .email-settings-section-chevron,
.email-settings-section-toggle:focus-visible .email-settings-section-chevron {
color: var(--accent, var(--red));
}
.email-settings-section-title {
display: inline-flex;
align-items: center;
gap: 6px;
font-size: 14px;
line-height: 1;
font-weight: 600;
letter-spacing: 0;
margin: 0;
padding: 0;
}
.email-settings-section-title svg {
color: var(--accent, var(--red));
opacity: 0.6;
flex-shrink: 0;
}
.email-settings-account-scope {
margin-left: 4px;
font-size: 11px;
font-weight: 500;
color: color-mix(in srgb, var(--fg) 60%, transparent);
}
.email-settings-section-body {
display: flex;
flex-direction: column;
gap: 7px;
min-width: 0;
width: 100%;
}
.email-settings-section[open] > .email-settings-section-body {
min-height: 0;
flex: 0 0 auto;
height: auto;
max-height: none;
overflow: visible;
overscroll-behavior: contain;
padding: 0 4px 4px 0;
scrollbar-width: thin;
}
.email-settings-section[open] {
min-height: 0;
flex: 0 0 auto;
}
.email-settings-auto-reply-section[open],
.email-settings-cleanup-section[open]:has(.email-unsub-card) {
flex: 1 1 auto;
display: grid;
grid-template-rows: auto minmax(0, 1fr);
align-content: stretch;
}
.email-settings-auto-reply-section[open] > .email-settings-section-body,
.email-settings-cleanup-section[open]:has(.email-unsub-card) > .email-settings-section-body {
flex: 0 0 auto;
height: 100%;
max-height: 100%;
overflow-y: auto;
}
.email-settings-section[open] > .email-settings-section-body > * {
flex: 0 0 auto;
}
.email-settings-section-body-head {
display: flex;
justify-content: flex-end;
}
.email-settings-display-heading {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
}
.email-settings-display-title {
display: inline-flex;
align-items: center;
gap: 6px;
min-width: 0;
}
.email-settings-display-title > svg {
flex: 0 0 auto;
color: var(--accent, var(--red));
}
.email-settings-display-title-row {
display: flex;
align-items: center;
gap: 12px;
width: 100%;
position: relative;
top: 10px;
padding-bottom: 6px;
border-bottom: 1px solid color-mix(in srgb, var(--border) 40%, transparent);
}
.email-settings-display-title-row .email-settings-section-title {
flex: 1 1 auto;
width: auto;
padding-bottom: 0;
border-bottom: 0;
}
.email-settings-style-section .email-settings-section-title {
display: flex;
width: 100%;
position: relative;
top: 0;
padding-bottom: 8px;
border-bottom: 1px solid color-mix(in srgb, var(--border) 40%, transparent);
}
.email-settings-style-section .email-settings-section-head,
.email-settings-style-section .email-settings-section-body {
position: static;
}
.email-settings-style-section .email-settings-section-head { margin-top: 8px; }
.email-settings-style-section .email-settings-section-body { margin-top: 12px; }
.email-settings-style-section .email-settings-section-desc {
margin-top: 16px;
top: 0;
}
.email-settings-auto-reply-section .email-settings-section-title,
.email-settings-cleanup-section .email-settings-section-title {
display: flex;
width: 100%;
padding-bottom: 6px;
border-bottom: 1px solid color-mix(in srgb, var(--border) 40%, transparent);
}
.email-settings-cleanup-section .email-settings-section-title {
position: relative;
top: 10px;
}
.email-settings-auto-reply-section .email-settings-section-desc,
.email-settings-cleanup-section .email-settings-section-desc {
margin-top: 10px;
}
.email-settings-display-section .email-settings-section-desc,
.email-settings-cleanup-section .email-settings-section-desc,
.email-settings-inline-images-section .email-settings-section-desc {
margin-top: 12px;
top: 12px;
}
.email-settings-auto-reply-title-row {
display: flex;
align-items: center;
gap: 12px;
width: 100%;
position: relative;
top: 10px;
padding-bottom: 6px;
border-bottom: 1px solid color-mix(in srgb, var(--border) 40%, transparent);
}
.email-settings-auto-reply-section .email-settings-section-head {
margin-top: 8px;
}
.email-settings-auto-reply-section .email-settings-section-body {
margin-top: 8px;
}
.email-settings-auto-reply-section .email-settings-section-desc {
margin-top: 12px;
top: 0;
}
.email-settings-display-section .email-settings-section-desc {
margin-top: 10px;
top: 10px;
}
.email-settings-auto-reply-section .email-settings-section-body {
margin-top: 14px;
}
.email-settings-auto-reply-title-row .email-settings-section-title {
flex: 1 1 auto;
width: auto;
padding-bottom: 0;
border-bottom: 0;
}
.email-settings-support-copy {
color: color-mix(in srgb, var(--fg) 65%, transparent);
font-size: 11px;
line-height: 1.3;
}
.email-settings-clean-btn > svg {
color: var(--accent, var(--red));
}
.email-settings-clean-btn {
height: 32px;
}
.email-unsub-rescan-btn {
height: 32px;
}
.email-settings-clean-actions {
display: flex;
align-items: center;
justify-content: flex-end;
flex-wrap: wrap;
gap: 7px;
min-width: 0;
margin-left: auto;
}
.email-settings-clean-status {
display: none;
font-size: 10.5px !important;
flex: 0 1 auto;
width: auto !important;
max-width: min(52vw, 360px);
min-width: 0;
overflow: hidden;
text-align: right;
white-space: nowrap;
text-overflow: ellipsis;
position: relative;
top: 2px;
}
.email-settings-clean-status.is-busy {
order: 0;
align-self: center;
width: auto !important;
max-width: 100%;
margin-right: auto;
text-align: left;
}
.email-settings-clean-btn {
flex: 0 0 auto;
}
.email-settings-default .cookbook-srv-default-icon > svg {
position: relative;
top: 3px;
}
.email-unsub-auto-safe-btn > svg {
position: relative;
top: 2px;
}
.email-unsub-auto-safe-btn {
height: 29px;
}
.email-unsub-status,
.email-unsub-panel-status {
position: relative;
top: 2px;
}
.email-unsub-panel-status {
flex: 1 1 220px;
min-width: 0;
margin-right: auto;
overflow: hidden;
color: color-mix(in srgb, var(--fg) 68%, transparent);
font-size: 11px;
line-height: 1.3;
text-align: left;
text-overflow: ellipsis;
white-space: nowrap;
}
.email-unsub-panel-status.is-error {
color: var(--red, #e57373);
}
.email-unsub-card .email-tag {
color: var(--accent, var(--red));
border-color: color-mix(in srgb, var(--accent, var(--red)) 42%, var(--border));
background: color-mix(in srgb, var(--accent, var(--red)) 10%, transparent);
}
.email-unsub-duplicate-badge {
position: relative;
top: 2px;
}
.email-unsub-accent-icon {
color: var(--accent, var(--red));
flex-shrink: 0;
}
.email-unsub-card {
position: relative;
transition: opacity .16s ease;
}
.email-unsub-card-details {
display: flex;
flex-direction: column;
gap: 7px;
}
.email-unsub-card-toggle {
display: inline-flex;
align-items: center;
justify-content: center;
flex: 0 0 auto;
width: 24px;
height: 24px;
padding: 0;
border: 0;
background: transparent;
color: color-mix(in srgb, var(--fg) 62%, transparent);
cursor: pointer;
}
.email-unsub-card-toggle:hover,
.email-unsub-card-toggle:focus-visible {
color: var(--accent, var(--red));
}
.email-unsub-card-toggle > svg {
transition: transform .14s ease;
}
.email-unsub-done-badge {
display: inline-flex;
align-items: center;
gap: 3px;
}
.email-unsub-done-btn {
display: inline-flex;
align-items: center;
gap: 3px;
flex: 0 0 auto;
padding: 3px 6px;
position: relative;
top: -6px;
}
.email-unsub-card-details .email-unsub-done-btn {
top: 0;
}
.email-unsub-done-btn > svg {
color: var(--accent, var(--red));
}
.email-unsub-ignore-btn {
display: inline-flex;
align-items: center;
justify-content: center;
flex: 0 0 auto;
width: 22px;
height: 22px;
padding: 0;
position: absolute;
top: 5px;
right: 6px;
color: color-mix(in srgb, var(--fg) 58%, transparent);
}
.email-unsub-card-details .email-unsub-ignore-btn {
position: static;
}
.email-unsub-ignore-btn:hover {
color: var(--accent, var(--red));
}
.email-unsub-remaining-actions {
display: inline-flex;
align-items: center;
gap: 7px;
flex-wrap: wrap;
}
.email-unsub-remaining-actions button {
display: inline-flex;
align-items: center;
gap: 4px;
position: relative;
top: -2px;
}
.email-unsub-remaining-actions svg {
flex: 0 0 auto;
}
.email-unsub-link-btn {
position: relative;
top: 2px;
}
.email-unsub-status.is-error {
color: var(--accent, var(--red)) !important;
}
.email-settings-section-desc {
position: relative;
top: 8px;
margin-top: 4px;
font-size: 10.5px;
line-height: 1.25;
color: color-mix(in srgb, var(--fg) 55%, transparent);
}
.email-settings-inline-images-section .email-settings-section-desc {
margin-bottom: 4px;
}
.email-settings-inline-images-spacer {
height: 12px;
}
.email-settings-display-spacer {
height: 10px;
}
.email-settings-display-section .email-settings-section-desc {
margin-top: 10px;
top: 10px;
}
.email-settings-display-section,
.email-settings-inline-images-section {
padding-bottom: 18px;
}
.email-settings-cleanup-section .email-settings-section-desc {
margin-top: 14px;
top: 14px;
}
.email-settings-auto-reply-section .email-settings-section-desc {
margin-top: 12px;
top: 10px;
}
.email-settings-toggle,
.email-settings-check {
display: flex;
align-items: center;
gap: 7px;
font-size: 12px;
line-height: 1.25;
}
.email-settings-toggle {
flex-shrink: 0;
}
.email-settings-enabled-control {
display: inline-flex;
align-items: center;
gap: 7px;
flex-shrink: 0;
}
.email-settings-enabled-state {
font-size: 10px;
font-weight: 700;
color: color-mix(in srgb, var(--fg) 50%, transparent);
}
.email-settings-section.is-enabled .email-settings-enabled-state {
color: var(--accent, var(--red));
}
.email-settings-section.is-disabled .email-settings-enabled-state {
color: color-mix(in srgb, var(--fg) 50%, transparent);
}
.email-settings-display-section.is-enabled .email-settings-enabled-state {
color: var(--accent, var(--red));
}
.email-settings-check {
min-height: 24px;
padding: 3px 0;
}
.email-settings-check > span:first-child {
min-width: 0;
margin-right: auto;
}
.email-settings-check-spacer {
flex: 1;
}
.email-settings-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 7px;
min-width: 0;
}
.email-settings-grid label,
.email-settings-field {
display: flex;
flex-direction: column;
gap: 4px;
min-width: 0;
}
.email-settings-grid span,
.email-settings-field > span {
font-size: 10px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0;
color: color-mix(in srgb, var(--fg) 56%, transparent);
}
.email-settings-page input[type="date"],
.email-settings-page input[type="datetime-local"],
.email-settings-page select,
.email-settings-page textarea {
width: 100%;
min-width: 0;
border: 1px solid var(--border);
border-radius: 6px;
background: var(--panel, var(--bg));
color: var(--fg);
font: inherit;
font-size: 12px;
}
.email-settings-page input[type="date"],
.email-settings-page input[type="datetime-local"],
.email-settings-page select {
height: 28px;
padding: 0 7px;
}
.email-settings-page textarea {
resize: vertical;
min-height: 72px;
padding: 7px;
line-height: 1.35;
}
.email-settings-static-value {
min-height: 28px;
display: flex;
align-items: center;
padding: 0 7px;
border: 1px solid var(--border);
border-radius: 6px;
background: color-mix(in srgb, var(--panel, var(--bg)) 74%, transparent);
color: color-mix(in srgb, var(--fg) 72%, transparent);
font-size: 12px;
}
.email-settings-actions {
display: flex;
align-items: center;
justify-content: flex-end;
flex-wrap: wrap;
gap: 8px;
margin-top: 2px;
}
/* Email Settings actions use the same quiet outlined treatment everywhere:
the Settings links, the modal settings page, and unsubscribe actions. */
[data-settings-panel="email"] #set-email-open-integrations,
[data-settings-panel="email"] #set-email-open-tasks,
[data-settings-panel="email"] .email-settings-section button.memory-toolbar-btn,
#email-lib-settings-page .email-settings-section button.memory-toolbar-btn {
background: transparent;
border: 1px solid var(--border);
color: var(--fg);
font-family: inherit;
font-weight: 400;
}
[data-settings-panel="email"] #set-email-open-integrations:hover,
[data-settings-panel="email"] #set-email-open-tasks:hover,
[data-settings-panel="email"] .email-settings-section button.memory-toolbar-btn:hover,
#email-lib-settings-page .email-settings-section button.memory-toolbar-btn:hover {
background: color-mix(in srgb, var(--fg) 8%, transparent);
border-color: var(--fg);
color: var(--fg);
}
[data-settings-panel="email"] #set-email-open-integrations > svg,
[data-settings-panel="email"] #set-email-open-tasks > svg {
color: var(--accent, var(--red));
opacity: 1 !important;
}
[data-settings-panel="email"] .email-style-settings-extract,
[data-settings-panel="email"] .email-style-settings-save,
#email-lib-settings-page .email-style-settings-extract,
#email-lib-settings-page .email-style-settings-save {
background: transparent;
border: 1px solid var(--border);
color: var(--fg);
font-weight: 400;
}
[data-settings-panel="email"] .email-style-settings-extract:hover,
[data-settings-panel="email"] .email-style-settings-save:hover,
#email-lib-settings-page .email-style-settings-extract:hover,
#email-lib-settings-page .email-style-settings-save:hover {
background: color-mix(in srgb, var(--fg) 8%, transparent);
border-color: var(--fg);
color: var(--fg);
}
.email-settings-status,
.email-style-settings-status {
margin-right: auto;
font-size: 11px;
color: color-mix(in srgb, var(--fg) 62%, transparent);
}
.email-settings-status.is-success,
.email-style-settings-status.is-success {
color: var(--color-success, #4caf50);
position: relative;
top: 2px;
}
.email-settings-status.is-error,
.email-style-settings-status.is-error {
color: var(--accent, var(--red));
position: relative;
top: 2px;
}
.email-settings-save,
.email-style-settings-save {
height: 28px;
min-width: 64px;
justify-content: center;
display: inline-flex;
align-items: center;
gap: 5px;
}
.email-settings-save {
height: 32px;
}
.email-style-settings-extract {
height: 32px;
}
.email-style-settings-save {
height: 32px;
}
.email-settings-save svg,
.email-style-settings-save svg {
color: var(--accent, var(--red));
flex-shrink: 0;
}
.email-style-settings-extract svg {
color: var(--accent, var(--red));
position: relative;
top: 2px;
}
.email-settings-task-setting {
color: color-mix(in srgb, var(--fg) 72%, transparent);
}
.email-settings-inline-link {
appearance: none;
border: 0;
padding: 0;
background: transparent;
color: var(--accent, var(--red));
font: inherit;
text-decoration: underline;
cursor: pointer;
}
.email-style-extract-help {
width: 18px;
height: 18px;
min-width: 18px;
padding: 0;
border-radius: 999px;
border: 1px solid color-mix(in srgb, var(--fg) 18%, transparent);
background: color-mix(in srgb, var(--fg) 5%, transparent);
color: color-mix(in srgb, var(--fg) 68%, transparent);
display: inline-flex;
align-items: center;
justify-content: center;
font: inherit;
font-size: 11px;
font-weight: 700;
line-height: 1;
cursor: help;
}
.email-style-extract-help:hover {
color: var(--fg);
border-color: color-mix(in srgb, var(--accent, var(--red)) 38%, var(--border));
background: color-mix(in srgb, var(--accent, var(--red)) 10%, transparent);
}
@media (max-width: 420px) {
.email-settings-grid {
grid-template-columns: 1fr;
}
}
/* ── Notes ── */
/* Notes panel — body-level flex sibling of chat-container */
body.notes-view .chat-container { flex: 1; min-width: 0; }
/* Mobile: notes panel takes over full screen */
@media (max-width: 768px) {
body.notes-view .notes-pane {
position: fixed;
inset: 0;
max-width: 100%;
width: 100% !important;
/* Desktop sets height: min(80vh, 820px) which wins over inset:0's bottom:0
and leaves a gap at the bottom of the viewport. Force full height here. */
height: 100dvh !important;
max-height: 100dvh !important;
z-index: 170;
/* Bottom-sheet treatment like the document editor: stroked, rounded top,
slides up from the bottom. */
border: 1px solid var(--border);
border-bottom: none;
border-radius: 14px 14px 0 0;
/* Pane itself never scrolls — its inner .notes-pane-body is the scroller.
Two nested scrollers caused the body's flex:1 to lose its height bound
on Firefox mobile and the last row got clipped off-screen. */
overflow: hidden;
animation: sheet-enter 0.25s cubic-bezier(0.2, 0.8, 0.2, 1) both;
transform-origin: bottom center;
}
/* Required for the flex:1 body to actually constrain to remaining pane
height instead of expanding to its content (default min-height:auto on
flex items). Without this both grid and list views overflow the viewport
bottom on phones. */
body.notes-view .notes-pane-body {
min-height: 0;
-webkit-overflow-scrolling: touch;
}
body.notes-view #notes-divider {
display: none;
}
body.notes-view .notes-mobile-grabber {
display: block;
flex-shrink: 0;
height: 18px;
position: relative;
background: var(--bg);
touch-action: none;
cursor: grab;
}
body.notes-view .notes-mobile-grabber::before {
content: '';
position: absolute;
top: 7px;
left: 50%;
transform: translateX(-50%);
width: 36px;
height: 4px;
background: var(--fg);
opacity: 0.25;
border-radius: 2px;
}
body.notes-view .chat-container {
display: none;
}
body.notes-view .mobile-new-chat-btn,
body.notes-view .hamburger-btn {
display: none !important;
}
}
/* ── Mobile notes UX ────────────────────────────────────
Tiles become read-only previews on touch ≤768px wide.
Tap opens a fullscreen overlay where editing happens; long-press
toggles drag-to-reorder. Wired up in static/js/notes.js. */
body.notes-mobile-mode .note-card-corner,
body.notes-mobile-mode .note-card-corner-edit,
body.notes-mobile-mode .note-card-corner-archive,
body.notes-mobile-mode .note-card-corner-copy,
body.notes-mobile-mode .note-card-corner-trash,
body.notes-mobile-mode .note-card-corner-unarchive,
body.notes-mobile-mode .note-card-corner-done,
body.notes-mobile-mode .note-card-edit-corner,
body.notes-mobile-mode .note-card-done,
body.notes-mobile-mode .note-card-actions,
body.notes-mobile-mode .note-cl-quickadd,
body.notes-mobile-mode .note-card .note-checkbox-rm,
/* Panel-fullscreen toggle is redundant on mobile — the panel always
fills the viewport already. */
body.notes-mobile-mode #notes-fullscreen-toggle {
display: none !important;
}
/* Header toggle icons (archive view, list/grid switch) — defaults are
tuned for the dense desktop header; on mobile bump them slightly so
they read as tap targets without dominating the header. */
body.notes-mobile-mode #notes-archive-toggle,
body.notes-mobile-mode #notes-view-toggle {
width: 30px;
height: 30px;
padding: 6px;
}
body.notes-mobile-mode #notes-archive-toggle svg,
body.notes-mobile-mode #notes-view-toggle svg {
width: 17px;
height: 17px;
}
/* The whole card is the tap target on mobile — bigger feedback */
body.notes-mobile-mode .note-card {
cursor: pointer;
-webkit-tap-highlight-color: transparent;
transition: transform 0.12s ease, box-shadow 0.12s ease;
}
/* Drag-to-reorder mode — desaturate the grid and sweep a subtle
shimmer across every tile so it's obvious you're in rearrange mode
(the Google Keep "active edit" cue). Also disable scroll inside the
panel so the drag works smoothly. */
body.notes-drag-mode .notes-pane-body {
overflow: hidden;
touch-action: none;
}
body.notes-drag-mode .note-card {
cursor: grab;
transform: scale(0.985);
filter: saturate(0.7);
opacity: 0.92;
position: relative;
overflow: hidden;
transition: transform 0.22s cubic-bezier(0.2, 0.7, 0.3, 1),
filter 0.18s ease,
opacity 0.18s ease;
}
@media (max-width: 768px) {
body.notes-drag-mode .note-card {
filter: none;
opacity: 0.96;
box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent, var(--red)) 28%, transparent);
}
body.notes-drag-mode .note-card::after {
display: none;
}
}
/* Placeholder — same footprint as the lifted card, dotted outline so
the drop target is visible while the card follows the finger. */
.note-card-placeholder {
background: color-mix(in srgb, var(--fg) 5%, transparent);
border: 2px dashed color-mix(in srgb, var(--fg) 25%, transparent);
border-radius: 8px;
box-sizing: border-box;
flex-shrink: 0;
transition: width 0.18s ease, height 0.18s ease;
}
/* ── Fullscreen single-note edit overlay ──────────────── */
.note-fullscreen-overlay {
position: fixed;
inset: 0;
z-index: 10500;
background: var(--bg);
display: flex;
flex-direction: column;
opacity: 0;
/* Bigger zoom range so the transition reads as a real "tile expands
into a page" motion. transform-origin is set per-tile by JS. */
transform: scale(0.45);
transform-origin: center center;
transition: opacity 0.28s ease, transform 0.32s cubic-bezier(0.18, 0.74, 0.24, 1.06);
will-change: transform, opacity;
}
.note-fullscreen-overlay.open {
opacity: 1;
transform: scale(1);
}
.note-fullscreen-overlay.closing {
opacity: 0;
transform: scale(0.7);
transition: opacity 0.22s ease, transform 0.22s cubic-bezier(0.4, 0, 0.6, 1);
}
.note-fullscreen-header {
flex-shrink: 0;
padding: 8px 12px;
display: flex;
align-items: center;
gap: 6px;
border-bottom: 1px solid var(--border);
}
.note-fullscreen-actions {
margin-left: auto;
display: flex;
align-items: center;
gap: 6px;
}
/* Compact the relocated Archive/Delete buttons so two of them fit
alongside the back chevron without crowding. */
.note-fullscreen-actions .note-form-text-btn {
padding: 8px 12px;
font-size: 12px;
border-radius: 8px;
}
.note-fullscreen-actions .note-form-text-btn svg {
width: 14px;
height: 14px;
margin-right: 4px;
}
.note-fullscreen-back {
display: inline-flex;
align-items: center;
justify-content: center;
width: 40px; height: 40px;
background: none;
border: none;
color: var(--fg);
border-radius: 8px;
cursor: pointer;
-webkit-tap-highlight-color: transparent;
}
.note-fullscreen-back:active {
background: color-mix(in srgb, var(--fg) 8%, transparent);
}
.note-fullscreen-body {
flex: 1;
min-height: 0;
overflow-y: auto;
padding: 8px 14px 24px;
}
/* The reused .note-form inside the fullscreen overlay should breathe —
it was originally sized to slot into a grid cell. */
.note-fullscreen-body .note-form {
max-width: 720px;
margin: 0 auto;
border: none;
box-shadow: none;
background: transparent;
}
/* Bigger touch targets inside the fullscreen overlay. The default form
is tuned for the grid-card context (tiny icons fit a 200px wide
tile); on a phone-sized full-bleed page we want chunky thumb-sized
controls. */
.note-fullscreen-back svg {
width: 28px;
height: 28px;
}
.note-fullscreen-overlay .note-form-type-pill svg {
width: 16px;
height: 16px;
}
.note-fullscreen-overlay .note-cl-row {
padding: 8px 0;
gap: 8px;
align-items: center;
}
.note-fullscreen-overlay .note-cl-grip {
font-size: 22px;
line-height: 1;
padding: 6px 8px;
opacity: 0.5;
cursor: grab;
touch-action: none;
user-select: none;
/* Pull 4px toward the left edge of the row. */
margin-left: -4px;
}
.note-fullscreen-overlay .note-cl-dot {
width: 16px;
height: 16px;
border-width: 2px;
border-radius: 50%;
flex-shrink: 0;
position: relative;
/* Generous invisible tap target around the visible dot */
}
/* Filled checkmark glyph when the row is marked done — gives a clear
visual cue beyond the colored fill. Nudged up 2px so it sits
centered in the smaller dot. */
.note-fullscreen-overlay .note-cl-row.done .note-cl-dot::after {
content: '';
position: absolute;
left: 2px; top: 1px;
width: 8px; height: 4px;
border-left: 2px solid #fff;
border-bottom: 2px solid #fff;
transform: rotate(-45deg);
}
.note-fullscreen-overlay .note-cl-rm {
width: 40px;
height: 40px;
font-size: 28px;
line-height: 1;
display: inline-flex;
align-items: center;
justify-content: center;
opacity: 0.7;
/* Nudge 4px further toward the right edge of the row. */
margin-right: -4px;
}
/* Lifted row + placeholder while dragging a checklist item. Mirrors
the card-drag look so the two interactions feel consistent. */
.note-cl-row-dragging {
box-shadow: 0 12px 28px rgba(0,0,0,0.4);
background: var(--bg);
border-radius: 8px;
opacity: 0.98;
}
.note-cl-row-placeholder {
background: color-mix(in srgb, var(--fg) 5%, transparent);
border: 2px dashed color-mix(in srgb, var(--fg) 22%, transparent);
border-radius: 6px;
margin: 4px 0;
box-sizing: border-box;
transition: height 0.16s ease;
}
.note-fullscreen-overlay .note-form-text-btn {
padding: 10px 16px;
font-size: 14px;
}
.note-fullscreen-overlay .note-form-text-btn svg {
width: 16px;
height: 16px;
}
/* + Add and the camera/photo button share a row inside checklists, so
they're both within thumb reach when editing items. The whole row
reads as a single dashed "tap to add" surface — tapping ANYWHERE
on it triggers + Add (the photo button stays its own target). */
.note-fullscreen-overlay .note-cl-add-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
margin-top: 10px;
padding: 4px 8px 4px 4px;
border: 1px solid color-mix(in srgb, var(--fg) 22%, transparent);
border-radius: 10px;
cursor: pointer;
transition: background 0.12s ease, border-color 0.12s ease;
}
.note-fullscreen-overlay .note-cl-add-row:active {
background: color-mix(in srgb, var(--fg) 6%, transparent);
border-color: color-mix(in srgb, var(--fg) 36%, transparent);
}
.note-fullscreen-overlay .note-cl-add-row .note-cl-add {
flex: 1;
justify-content: flex-start;
background: transparent;
border: none;
}
.note-fullscreen-overlay .note-cl-add-row .note-form-photo-btn {
display: inline-flex;
align-items: center;
gap: 4px;
width: auto;
height: 36px;
padding: 0 12px 0 10px;
border-radius: 8px;
/* No border / no background — the surrounding +Add row provides the
bordered container, the camera is just an icon inside it. */
border: none;
background: transparent;
}
/* Read-mode overlay shown over the textarea for plain notes. Renders
linkified content so URLs are tappable. Click anywhere off a link
to flip to edit mode (focuses the underlying textarea). */
.note-form-content-reader {
font-size: 15px;
line-height: 1.55;
padding: 10px 6px;
white-space: pre-wrap;
word-wrap: break-word;
color: var(--fg);
cursor: text;
min-height: 40px;
}
/* Per-row read mode for todo items — replaces the bare <input> with a
clickable linkified span when the value contains a URL. */
.note-fullscreen-overlay .note-cl-text-reader {
flex: 1;
padding: 7px 6px;
font-size: 14px;
line-height: 1.4;
min-height: 32px;
display: inline-flex;
align-items: center;
word-break: break-word;
color: var(--fg);
cursor: text;
}
.note-fullscreen-overlay .note-cl-row.done .note-cl-text-reader {
opacity: 0.5;
text-decoration: line-through;
}
.note-fullscreen-overlay .note-form-icon-btn svg {
width: 16px;
height: 16px;
}
/* Tags input is JS-relocated into the bottom actions row, pinned
left of Cancel/Update. Style it as a dashed pill so it reads as
metadata rather than another control. */
.note-fullscreen-overlay .note-form-actions-group .note-form-label {
flex: 1 1 auto;
min-width: 0;
font-size: 13px;
padding: 8px 10px;
margin: 0 auto 0 0;
background: transparent;
border: 1px dashed color-mix(in srgb, var(--fg) 16%, transparent);
border-radius: 6px;
text-align: left;
}
.note-fullscreen-overlay .note-color-picker { order: 1; }
.note-fullscreen-overlay .note-form-type-seg {
order: 3;
margin-left: auto; /* shove right */
/* The overlay enlarges the pills (padding 10px), but the base seg is only
28px tall with overflow:hidden — which clipped them. Grow the track so
the bigger touch targets fit. */
height: 40px;
border-radius: 12px;
}
.note-fullscreen-overlay .note-form-actions-group {
order: 4;
width: 100%;
display: flex;
align-items: center;
gap: 8px;
margin-top: 6px;
}
.notes-mobile-grabber { display: none; }
/* Notes panel: mounted like a window, docked to the right on desktop. */
.notes-pane-backdrop {
position: fixed;
inset: 0;
z-index: 200;
display: flex;
align-items: center;
justify-content: center;
background: transparent;
backdrop-filter: none;
-webkit-backdrop-filter: none;
pointer-events: none;
animation: notes-backdrop-fade-in 180ms ease both;
}
.notes-pane-backdrop .notes-pane {
pointer-events: auto;
}
.notes-pane-backdrop:has(.notes-pane.modal-right-docked),
.notes-pane-backdrop:has(.notes-pane.modal-left-docked) {
background: transparent;
backdrop-filter: none;
-webkit-backdrop-filter: none;
pointer-events: none;
}
.notes-pane-backdrop:has(.notes-pane.modal-right-docked) .notes-pane,
.notes-pane-backdrop:has(.notes-pane.modal-left-docked) .notes-pane {
pointer-events: auto;
}
.notes-pane-backdrop:has(.notes-pane.notes-window-fullscreen) {
background: transparent;
backdrop-filter: none;
-webkit-backdrop-filter: none;
}
.notes-pane {
display: flex;
flex-direction: column;
background: var(--panel);
border: 1px solid var(--border);
border-radius: 10px;
overflow: hidden;
width: min(880px, 92vw);
height: min(80vh, 820px);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.45);
box-sizing: border-box;
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
letter-spacing: -0.015em;
/* Smooth open: scale up + fade in from the centre. */
animation: notes-pane-enter 200ms cubic-bezier(0.22, 0.61, 0.36, 1) both;
transform-origin: center center;
will-change: transform, opacity;
}
.notes-pane.modal-right-docked {
border-left: 1px solid var(--border);
border-radius: 0;
box-shadow: -4px 0 14px rgba(0, 0, 0, 0.18);
transition: none !important;
}
.notes-pane.modal-left-docked {
border-right: 1px solid var(--border);
border-radius: 0;
box-shadow: 4px 0 14px rgba(0, 0, 0, 0.18);
transition: none !important;
}
.notes-pane-header {
display: flex;
align-items: center;
gap: 4px;
justify-content: space-between;
padding: 0 0 6px;
margin: 10px 10px 0;
border-bottom: 1px solid var(--border);
background: inherit;
flex-shrink: 0;
flex-wrap: nowrap;
min-height: 30px;
overflow: hidden;
}
/* Archive mode — sepia tint over the panel + a header strip so it's clearly
a different view. Active reminders sort + glow rules don't apply here. */
.notes-pane-archive {
background: color-mix(in srgb, #b48a4a 6%, var(--bg));
}
.notes-pane-archive .notes-pane-header {
background: color-mix(in srgb, #b48a4a 12%, var(--bg));
border-bottom-color: color-mix(in srgb, #b48a4a 35%, var(--border));
}
.notes-pane-archive .notes-pane-body {
background: color-mix(in srgb, #b48a4a 4%, var(--bg));
}
/* Smooth the archive↔active swap so the colour tint eases in/out instead
of snapping. Covers the pane, its header, and its body. */
.notes-pane,
.notes-pane .notes-pane-header,
.notes-pane .notes-pane-body {
transition: background 0.28s ease, border-color 0.28s ease;
}
.notes-pane-archive .notes-pane-title::after {
content: 'Archive';
margin-left: 8px;
padding: 2px 8px 2px 22px;
font-size: 9px;
font-weight: 700;
letter-spacing: 1px;
text-transform: uppercase;
color: #b48a4a;
background-color: color-mix(in srgb, #b48a4a 18%, transparent);
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23b48a4a' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='2' y='3' width='20' height='5' rx='1'/%3E%3Cpath d='M4 8v11a2 2 0 002 2h12a2 2 0 002-2V8'/%3E%3Cpath d='M10 12h4'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: 6px center;
background-size: 11px 11px;
border: 1px solid color-mix(in srgb, #b48a4a 45%, transparent);
border-radius: 10px;
vertical-align: middle;
}
.notes-pane-archive .note-card {
background: color-mix(in srgb, #b48a4a 8%, var(--panel));
border-color: color-mix(in srgb, #b48a4a 25%, var(--border));
}
.notes-pane-header .doc-action-icon-btn {
flex-shrink: 0;
}
.notes-pane-header .notes-pane-title {
overflow: hidden;
text-overflow: ellipsis;
min-width: 0;
flex-shrink: 1;
}
.notes-pane-footer {
padding: 6px 8px;
border-top: 1px solid var(--border);
background: var(--panel);
flex-shrink: 0;
display: flex;
gap: 6px;
}
.notes-new-btn {
background: none;
border: 1px dashed color-mix(in srgb, var(--accent) 40%, transparent);
color: color-mix(in srgb, var(--fg) 50%, transparent);
border-radius: 6px;
padding: 6px 0;
flex: 1;
cursor: pointer;
font-size: 11px;
font-family: inherit;
display: flex;
align-items: center;
justify-content: center;
gap: 4px;
transition: border-color 0.15s, color 0.15s;
}
.notes-new-btn:hover {
border-color: var(--accent);
color: var(--fg);
}
.notes-pane-title {
/* Match the other tool headers (.modal-header h4). */
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
font-size: 1rem;
font-weight: 600;
letter-spacing: -0.03em;
color: var(--red);
white-space: nowrap;
height: 24px;
line-height: 22px;
padding: 0 6px;
margin: 6px 0 0 0;
display: inline-block;
vertical-align: middle;
/* Optical nudge — sits 1px above its row baseline on desktop, more on mobile
where the surrounding controls are taller. Overridden in the mobile
media block below. */
position: relative;
top: -1px;
box-sizing: border-box;
}
@media (max-width: 768px) {
.notes-pane-title { top: -4px; }
.notes-pane-title svg {
position: relative;
top: -2px;
}
/* Mobile header is tight — keep Archive / Toggle View icon-only. */
.notes-header-btn-label { display: none; }
.notes-header-text-btn { width: 32px !important; padding: 0 !important; }
}
.notes-header-btn-label {
font-size: 11px;
font-weight: 500;
line-height: 1;
letter-spacing: 0.2px;
white-space: nowrap;
}
.notes-header-text-btn {
width: auto !important;
padding: 0 8px !important;
}
.notes-pane-body {
flex: 1;
overflow-y: auto;
scroll-behavior: smooth;
padding: 10px 8px 8px;
display: flex;
flex-direction: column;
gap: 6px;
scrollbar-width: thin;
}
.notes-pane-body > .doclib-chip-scroll-frame:has(> .notes-labels-bar) {
/* The shared Library wrapper grows to fill available flex space. Notes
needs this to remain a content-height toolbar or it can create a huge
blank gap above the cards after filtering/re-rendering. */
flex: 0 0 auto;
width: 100%;
}
.note-card.note-card-sliding-out {
transform: translateX(120%);
opacity: 0;
transition: transform 0.32s ease-in, opacity 0.32s ease-in;
pointer-events: none;
}
/* ⋯ corner menu button (replaced the copy corner button) */
.note-card-corner-menu {
background: none;
border: none;
color: var(--fg);
cursor: pointer;
padding: 2px;
opacity: 0.5;
transition: opacity 0.15s;
display: inline-flex;
}
.note-card-corner-menu:hover { opacity: 0.9; }
/* Dropdown spawned by the ⋯ menu */
.note-corner-menu-dropdown {
background: var(--panel);
border: 1px solid var(--border);
border-radius: 8px;
box-shadow: 0 8px 24px rgba(0,0,0,0.3);
padding: 4px;
min-width: 168px;
font-size: 12px;
animation: ncm-pop 0.12s ease-out both;
}
@keyframes ncm-pop { from { opacity: 0; transform: scale(0.96); } to { opacity: 1; transform: scale(1); } }
.note-corner-menu-dropdown .ncm-item {
display: flex;
align-items: center;
gap: 9px;
width: 100%;
background: none;
border: none;
color: var(--fg);
font-family: inherit;
font-size: 12px;
text-align: left;
padding: 8px 10px;
border-radius: 6px;
cursor: pointer;
}
.note-corner-menu-dropdown .ncm-item:hover {
background: color-mix(in srgb, var(--fg) 8%, transparent);
}
.note-checkbox-agent {
display: inline-flex;
align-items: center;
justify-content: center;
width: 14px;
height: 14px;
padding: 0;
margin: 0 1px;
border: 0;
background: transparent;
color: var(--accent, var(--red));
box-shadow: none;
cursor: pointer;
opacity: 0;
transition: opacity 0.12s, color 0.12s;
}
.note-checkbox-agent:hover {
background: transparent;
opacity: 1 !important;
}
.note-checkbox-agent.is-agent-stream-complete {
color: #50fa7b;
opacity: 0.9;
}
.note-checkbox-agent svg {
display: block;
}
.note-card {
/* Same tint that .doclib-card uses so a default (uncolored) note
visually separates from the panel background it sits on. */
background: color-mix(in srgb, var(--fg) 3%, transparent);
border: 1px solid var(--border);
border-radius: 8px;
/* Extra right padding so the corner buttons (pin / edit / copy / done)
never collide with the title, and a min-height so an empty/short
note is still tall enough to fit that row of corner controls. */
padding: 10px 14px;
padding-right: 30px;
min-height: 64px;
cursor: default;
transition: background 0.15s;
display: flex;
flex-direction: column;
gap: 4px;
/* Keep drawings/images clipped to the card so they can't spill outside it —
but allow a small overhang (the pin bubble sits at right:-8px and would
otherwise be cropped). overflow-clip-margin extends the clip-box without
letting full images bleed past. */
overflow: clip;
overflow-clip-margin: 14px;
/* Don't shrink inside the flex-column list pane — otherwise cards squish to
fit (clipped/too short) and the container never overflows, so it won't
scroll. Keeping natural height makes the list overflow → scrollable. */
flex-shrink: 0;
}
.note-card:hover:not([class*="note-color-"]) {
background: color-mix(in srgb, var(--fg) 6%, transparent);
}
.note-card { position: relative; }
.note-card-image { max-width: 100%; }
/* Mobile: bigger, more legible note cards + a sticky quick-add bar so you can
add a to-do without scrolling back up; and keep media inside the card. */
@media (max-width: 768px) {
.note-card { padding: 14px 16px; padding-right: 34px; min-height: 84px; font-size: 15px; }
.note-card-image { max-height: 260px; max-width: 100%; object-fit: cover; }
/* Sticky create-todo bar — pin it to the top of the scrolling list pane.
Safe now that the cards no longer shrink (the list actually overflows). */
.notes-quick-add {
position: sticky;
top: -8px;
z-index: 12;
flex-shrink: 0;
margin-top: 0;
box-shadow: 0 -8px 0 8px var(--panel), 0 8px 0 0 var(--panel);
}
}
.note-card-pinned {
border-top: 2px solid color-mix(in srgb, var(--fg) 30%, transparent);
}
.note-card.note-card-reminder-fired {
animation: note-reminder-pulse 1.2s ease-in-out 2;
}
/* Sticky outside glow — applied to the exact note whose reminder fired.
It stays until the user interacts with that card. */
.note-card.note-card-reminder-fired-sticky {
position: relative;
outline: 1px solid color-mix(in srgb, var(--accent, var(--red)) 36%, transparent);
outline-offset: 2px;
animation: note-reminder-glow 1.6s ease-in-out infinite;
}
/* Hover-only buttons (Google Keep style) */
.note-card-select,
.note-card-pin {
position: absolute;
top: -8px;
background: var(--bg);
border: 1px solid var(--border);
border-radius: 50%;
width: 18px;
height: 18px;
padding: 0;
cursor: pointer;
display: none;
align-items: center;
justify-content: center;
color: var(--fg);
opacity: 0.7;
z-index: 2;
transition: opacity 0.15s, transform 0.15s, background 0.15s;
}
/* Pencil + checkmark glyphs both have empty space along the top of their
24×24 viewBox, so flex-centering leaves them sitting visually high.
Nudge the inner SVG down a touch to compensate. */
.note-card-edit-corner svg,
.note-card-done svg {
position: relative;
top: 0.5px;
}
.note-card-edit-corner {
position: absolute;
/* Both Edit + Done at top-right: Edit on the left (right:40px),
Done on the right (right:6px). */
top: 6px; right: 40px;
width: 28px; height: 28px;
/* Fully invisible at rest. Materializes (with a solid panel fill blocking
any text underneath) only when the card is hovered or the button is
focused. Same rule on touch — opacity stays 0 until the card is tapped
to expose actions. */
background: transparent;
border: 1px solid transparent;
border-radius: 50%;
cursor: pointer; padding: 0;
display: inline-flex;
align-items: center;
justify-content: center;
color: var(--fg); opacity: 0;
touch-action: manipulation;
transition: opacity 0.15s, background 0.15s, border-color 0.15s;
z-index: 2;
}
.note-card:hover .note-card-edit-corner {
opacity: 0.85;
background: var(--panel);
border-color: color-mix(in srgb, var(--fg) 18%, transparent);
}
.note-card-edit-corner:hover,
.note-card-edit-corner:focus-visible {
opacity: 1 !important;
background: color-mix(in srgb, var(--accent) 18%, var(--panel)) !important;
border-color: color-mix(in srgb, var(--accent) 50%, var(--border)) !important;
}
@media (hover: none) {
.note-card-edit-corner {
opacity: 0.7;
background: var(--panel);
border-color: color-mix(in srgb, var(--fg) 18%, transparent);
}
}
/* Copy corner — bottom-right counterpart to the edit/done corner buttons.
Round, subtle, hover-reveal on desktop and always faintly visible on
touch so mobile users can tap it without needing hover. */
.note-card-copy-corner {
position: absolute;
bottom: 6px;
right: 6px;
top: auto;
width: 26px;
height: 26px;
background: transparent;
border: 1px solid transparent;
border-radius: 50%;
cursor: pointer;
padding: 0;
display: inline-flex;
align-items: center;
justify-content: center;
color: var(--fg);
opacity: 0;
touch-action: manipulation;
transition: opacity 0.15s, background 0.15s, border-color 0.15s;
z-index: 2;
}
.note-card:hover .note-card-copy-corner {
opacity: 0.7;
background: var(--panel);
border-color: color-mix(in srgb, var(--fg) 18%, transparent);
}
.note-card-copy-corner:hover,
.note-card-copy-corner:focus-visible {
opacity: 1 !important;
background: color-mix(in srgb, var(--accent, var(--red)) 18%, var(--panel)) !important;
border-color: color-mix(in srgb, var(--accent, var(--red)) 50%, var(--border)) !important;
}
@media (hover: none) {
.note-card-copy-corner {
opacity: 0.6;
background: var(--panel);
border-color: color-mix(in srgb, var(--fg) 18%, transparent);
}
}
/* Unarchive corner reuses the pencil's spot in archive view. */
.note-card-unarchive-corner:hover,
.note-card-unarchive-corner:focus-visible {
background: color-mix(in srgb, var(--accent) 22%, transparent) !important;
border-color: color-mix(in srgb, var(--accent) 50%, var(--border)) !important;
color: var(--accent);
}
/* "Done" pill in the bottom-right of every active note card. Visible-only on
hover (and always on touch) so it's clearly readable but doesn't clutter
the grid at rest. Distinct from the edit pencil so it's obvious what it
does — green checkmark + label, not just an icon. */
/* Matches .note-card-edit-corner footprint (22×22 circle), just anchored
to the bottom-right corner instead of top-right. */
.note-card-done {
position: absolute;
top: 6px;
right: 6px;
width: 28px;
height: 28px;
background: transparent;
border: 1px solid transparent;
border-radius: 50%;
cursor: pointer;
padding: 0;
display: inline-flex;
align-items: center;
justify-content: center;
color: var(--green, #98c379);
opacity: 0;
touch-action: manipulation;
transition: opacity 0.15s, background 0.15s, border-color 0.15s;
z-index: 2;
}
.note-card:hover .note-card-done {
opacity: 0.85;
background: var(--panel);
border-color: color-mix(in srgb, var(--fg) 18%, transparent);
}
.note-card-done:hover,
.note-card-done:focus-visible {
opacity: 1 !important;
background: color-mix(in srgb, var(--green, #98c379) 22%, var(--panel)) !important;
border-color: color-mix(in srgb, var(--green, #98c379) 50%, var(--border)) !important;
}
@media (hover: none) {
.note-card-done {
opacity: 0.7;
background: var(--panel);
border-color: color-mix(in srgb, var(--fg) 18%, transparent);
}
}
/* Copy corner — bottom-right of the card. Same opaque-fill pattern as
trash/unarchive so the underlying text/image never bleeds through. */
.note-card-corner-copy {
position: absolute;
bottom: 6px;
right: 6px;
width: 28px;
height: 28px;
background: var(--panel);
border: 1px solid color-mix(in srgb, var(--fg) 18%, transparent);
border-radius: 50%;
cursor: pointer;
padding: 0;
display: inline-flex;
align-items: center;
justify-content: center;
color: var(--fg);
visibility: hidden;
touch-action: manipulation;
transition: background 0.15s, border-color 0.15s, color 0.15s;
z-index: 2;
}
.note-card-corner-copy svg { position: relative; top: 1px; opacity: 0.85; transition: opacity 0.15s; }
.note-card-corner-copy:hover,
.note-card-corner-copy:focus-visible {
background: color-mix(in srgb, var(--accent) 18%, var(--panel));
border-color: color-mix(in srgb, var(--accent) 50%, var(--border));
color: var(--accent);
}
.note-card-corner-copy:hover svg { opacity: 1; }
@media (hover: none) {
.note-card-corner-copy { visibility: visible; }
.note-card-corner-copy svg { opacity: 0.7; }
}
/* ── Archive view corners — trash (top-left) + unarchive (top-right) ── */
/* Background fill stays fully opaque (var(--panel)) so the note text or
image behind doesn't bleed through. Visibility is gated by `visibility`
+ a faded ICON instead of `opacity` on the whole button. */
.note-card-corner-trash,
.note-card-corner-unarchive {
position: absolute;
top: 6px;
width: 28px;
height: 28px;
background: var(--panel);
border: 1px solid color-mix(in srgb, var(--fg) 18%, transparent);
border-radius: 50%;
cursor: pointer;
padding: 0;
display: inline-flex;
align-items: center;
justify-content: center;
color: var(--fg);
visibility: hidden;
touch-action: manipulation;
transition: background 0.15s, border-color 0.15s, color 0.15s;
z-index: 2;
}
.note-card-corner-trash svg,
.note-card-corner-unarchive svg { opacity: 0.85; transition: opacity 0.15s; }
.note-card-corner-trash:hover,
.note-card-corner-trash:focus-visible {
background: color-mix(in srgb, var(--red) 18%, var(--panel));
border-color: color-mix(in srgb, var(--red) 50%, var(--border));
color: var(--red);
}
.note-card-corner-trash:hover svg,
.note-card-corner-unarchive:hover svg { opacity: 1; }
.note-card-corner-unarchive:hover,
.note-card-corner-unarchive:focus-visible {
background: color-mix(in srgb, var(--accent) 18%, var(--panel));
border-color: color-mix(in srgb, var(--accent) 50%, var(--border));
color: var(--accent);
}
@media (hover: none) {
.note-card-corner-trash,
.note-card-corner-unarchive { visibility: visible; }
.note-card-corner-trash svg,
.note-card-corner-unarchive svg { opacity: 0.7; }
}
/* ─── Auto-AI ✨ chip on note cards ─────────────────────────────────── */
.note-card-ai-chip {
display: inline-flex;
align-items: center;
gap: 4px;
margin-left: 6px;
padding: 2px 8px;
border-radius: 999px;
font-size: 11px;
font-weight: 500;
font-family: inherit;
background: color-mix(in srgb, var(--accent, var(--red)) 14%, transparent);
border: 1px solid color-mix(in srgb, var(--accent, var(--red)) 35%, transparent);
color: var(--accent, var(--red));
cursor: pointer;
transition: background 0.12s, transform 0.12s, box-shadow 0.12s;
vertical-align: middle;
}
.note-card-ai-chip:hover {
background: color-mix(in srgb, var(--accent, var(--red)) 22%, transparent);
transform: translateY(-1px);
box-shadow: 0 2px 6px color-mix(in srgb, var(--accent, var(--red)) 30%, transparent);
}
.note-card-ai-chip svg {
flex-shrink: 0;
animation: note-ai-shine 2.4s ease-in-out infinite;
}
.note-card-ai-solving {
cursor: default;
background: color-mix(in srgb, var(--fg) 8%, transparent);
border-color: color-mix(in srgb, var(--fg) 18%, transparent);
color: color-mix(in srgb, var(--fg) 70%, transparent);
}
.note-card-ai-solving svg { animation: spin 0.9s linear infinite; filter: none; }
.note-card-ai-done { background: color-mix(in srgb, var(--accent, var(--red)) 8%, transparent); }
.note-card-ai-done svg { animation: none; }
#notes-auto-ai-toggle.active { color: var(--accent, var(--red)); }
/* ─── AI improve button (note form header) ───────────────────────────── */
.note-form-improve-btn {
width: 38px !important;
height: 38px !important;
color: var(--accent, var(--red));
}
.note-form-improve-btn svg {
width: 22px !important;
height: 22px !important;
animation: note-ai-shine 2.4s ease-in-out infinite;
}
.note-form-improve-btn.busy svg {
animation: spin 0.9s linear infinite;
filter: none;
}
.note-card:hover .note-card-select,
.note-card:hover .note-card-pin,
.note-card-selected .note-card-select,
.note-card-pinned .note-card-pin {
display: flex;
}
.note-card-select:hover, .note-card-pin:hover {
opacity: 1;
transform: scale(1.15);
background: color-mix(in srgb, var(--accent) 15%, var(--bg));
}
.note-card-pin.active {
display: flex;
background: color-mix(in srgb, var(--accent, var(--red)) 12%, var(--bg));
border-color: color-mix(in srgb, var(--accent, var(--red)) 45%, var(--border));
color: var(--accent, var(--red));
opacity: 1;
}
.note-card-selected .note-card-select {
background: var(--accent);
border-color: var(--accent);
color: #fff;
opacity: 1;
}
/* Select-mode checkbox on cards (mirrors docs library) */
.note-card-cb {
position: absolute;
top: 6px;
left: 6px;
z-index: 3;
margin: 0;
}
.note-card-selectmode {
padding-left: 28px;
cursor: pointer;
}
.note-card-selectmode:hover { background: color-mix(in srgb, var(--fg) 3%, transparent) !important; }
@media (max-width: 768px) {
body.notes-mobile-mode .note-card-selectmode {
animation: notes-select-jiggle 0.34s cubic-bezier(0.42, 0, 0.58, 1) infinite;
transform-origin: 50% 50%;
}
body.notes-mobile-mode .note-card-selectmode:nth-child(2n) {
animation-delay: -0.08s;
}
/* Keep the subtle edit-mode cue only on Notes and Gallery. */
:is(
body.gallery-selecting .gallery-card
) {
animation: notes-select-jiggle 0.34s cubic-bezier(0.42, 0, 0.58, 1) infinite;
transform-origin: 50% 50%;
}
:is(
body.gallery-selecting .gallery-card:nth-child(2n)
) { animation-delay: -0.11s; }
}
@media (prefers-reduced-motion: reduce) {
body.notes-mobile-mode .note-card-selectmode,
body.gallery-selecting .gallery-card { animation: none; }
}
/* Bottom action row — hidden everywhere. The archive/delete actions and the
color picker now live inside the edit form (click the pencil corner). */
.note-card-actions { display: none; }
.note-agent-menu {
background: var(--panel, var(--bg));
border: 1px solid var(--border);
border-radius: 6px;
box-shadow: 0 4px 16px rgba(0,0,0,0.3);
padding: 4px 0;
min-width: 140px;
font-size: 12px;
}
.note-card-colors {
display: flex;
gap: 3px;
}
/* Re-asserted AFTER the base rule above so the mobile-hide actually
wins the cascade — earlier @media (hover:none) block was being
overridden because the unconditional display:flex rule came later. */
@media (hover: none) {
.note-card-colors { display: none; }
}
.note-card-color-dot {
width: 12px;
height: 12px;
border-radius: 50%;
cursor: pointer;
border: 1.5px solid color-mix(in srgb, var(--fg) 20%, transparent);
transition: transform 0.15s, border-color 0.15s;
}
.note-card-color-dot:hover {
transform: scale(1.25);
border-color: var(--fg);
}
.note-card-color-dot.active {
border-color: var(--fg);
border-width: 2px;
}
.note-card-action {
background: none;
border: none;
cursor: pointer;
padding: 3px;
color: var(--fg);
opacity: 0.4;
display: flex;
align-items: center;
border-radius: 3px;
transition: opacity 0.15s, background 0.15s;
}
/* Note image */
.note-card-image {
width: 100%;
max-height: 180px;
object-fit: cover;
border-radius: 4px;
margin: 4px 0;
display: block;
}
.note-form-image-wrap {
position: relative;
margin: 4px 0;
}
.note-form-image {
width: 100%;
max-height: 200px;
object-fit: cover;
border-radius: 4px;
display: block;
/* Images are draggable=true by default; that catches the mousedown
and beats the X button to the click. Disabling drag at the CSS
level (the -webkit-user-drag prop) keeps the X button reliably
clickable even if the JS forgets to set draggable="false" on the
element. Unprefixed user-drag was never standardized — Firefox
drops it with a warning. */
-webkit-user-drag: none;
user-select: none;
}
.note-form-image-rm {
position: absolute;
top: 6px;
right: 6px;
z-index: 5;
background: rgba(0,0,0,0.65);
border: none;
color: #fff;
width: 32px;
height: 32px;
border-radius: 50%;
cursor: pointer;
font-size: 20px;
line-height: 1;
display: flex;
align-items: center;
justify-content: center;
}
.note-form-photo-btn {
flex: 0 0 auto;
background: transparent;
border: 1px solid var(--border);
color: var(--fg);
cursor: pointer;
border-radius: 4px;
width: auto;
min-width: 32px;
height: 32px;
padding: 0 6px;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 3px;
opacity: 1;
transition: opacity 0.15s, border-color 0.15s, background 0.15s;
}
.note-form-photo-btn:hover { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 8%, transparent); }
/* Quick-add bar (always at top) */
.notes-quick-add {
display: flex;
align-items: center;
transform: translateY(-2px);
gap: 4px;
background: var(--panel);
border: 1px solid color-mix(in srgb, var(--accent, var(--red)) 35%, var(--border));
border-radius: 6px;
/* Toggle pill sits at the very left of the bar — no inset padding. The
pill's own border provides visual breathing room from the wrapper edge. */
padding: 4px 6px 4px 4px;
margin-top: 2px;
margin-bottom: 8px;
transition: border-color 0.15s, box-shadow 0.15s, background 0.15s;
/* Subtle idle glow so the field reads as "you can type here" without
the user having to click it first. Fades out the moment the user
hovers or focuses it. */
animation: notes-quick-pulse 2.8s ease-in-out infinite;
}
.notes-quick-add:hover {
border-color: color-mix(in srgb, var(--accent, var(--red)) 55%, var(--border));
box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent, var(--red)) 18%, transparent);
animation: none;
}
.notes-quick-add:focus-within {
border-color: var(--accent, var(--red));
box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent, var(--red)) 25%, transparent);
background: color-mix(in srgb, var(--fg) 3%, var(--panel));
animation: none;
}
.notes-quick-input {
flex: 1;
background: transparent;
border: none;
outline: none;
color: var(--fg);
caret-color: var(--accent, var(--red));
font-family: inherit;
font-size: 12px;
padding: 6px 0;
}
.notes-quick-icon {
background: none;
border: none;
color: var(--fg);
opacity: 0.45;
cursor: pointer;
padding: 5px;
border-radius: 4px;
display: flex;
align-items: center;
transition: opacity 0.15s, background 0.15s;
}
.notes-quick-icon:hover {
opacity: 1;
background: color-mix(in srgb, var(--fg) 8%, transparent);
}
/* 2-pill Note/Todo toggle in the quick-add bar — same look as the form's
type-seg but slimmer to fit the compact row. */
.notes-quick-type-seg {
display: inline-flex;
height: 28px;
border: 1px solid var(--border);
border-radius: 8px;
overflow: hidden;
position: relative;
flex-shrink: 0;
/* Negative order pushes the toggle BEFORE the wrapper's ::before caret
hint, so the blinking | sits between the toggle and the input rather
than at the far-left edge. */
order: -1;
}
.notes-quick-type-seg::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 50%;
height: 100%;
background: color-mix(in srgb, var(--fg) 10%, transparent);
border-radius: 6px;
transition: transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1);
z-index: 0;
}
.notes-quick-type-pill {
background: none;
border: none;
color: color-mix(in srgb, var(--fg) 40%, transparent);
cursor: pointer;
padding: 0 11px;
font-family: inherit;
transition: color 0.2s;
white-space: nowrap;
height: 100%;
display: inline-flex;
align-items: center;
position: relative;
z-index: 1;
}
.notes-quick-type-pill svg {
width: 16px;
height: 16px;
}
.notes-quick-type-pill:not(.active):hover {
color: color-mix(in srgb, var(--fg) 65%, transparent);
}
.notes-quick-type-pill.active,
.notes-quick-type-pill.active:hover,
.notes-quick-type-pill.active:focus {
color: var(--fg);
cursor: default;
}
/* Mobile: thumb-sized Note/Todo toggle. The 22px desktop pill is too
small to hit reliably on a phone. */
@media (max-width: 768px) {
.notes-quick-type-seg {
height: 36px;
border-radius: 10px;
}
.notes-quick-type-seg::before {
border-radius: 9px;
}
.notes-quick-type-pill {
padding: 0 14px;
}
.notes-quick-type-pill svg {
width: 17px;
height: 17px;
}
/* Match the input + photo button heights to the bigger toggle so the
row reads as one consistent bar. */
.notes-quick-input {
height: 36px;
font-size: 15px;
}
.notes-quick-icon {
padding: 9px;
}
.notes-quick-icon svg {
width: 18px;
height: 18px;
}
}
.notes-empty-msg {
text-align: center;
/* 0.4 dropped this empty-state text to ~2.8:1; 0.65 keeps it readable
(WCAG AA) while staying visibly secondary. */
opacity: 0.65;
padding: 30px 20px;
font-size: 11px;
}
/* Loading skeleton */
.notes-skeleton {
display: flex;
flex-direction: column;
gap: 8px;
margin-top: 4px;
}
.notes-skeleton-card {
height: 72px;
border-radius: 6px;
border: 1px solid var(--border);
background: linear-gradient(
90deg,
color-mix(in srgb, var(--fg) 4%, transparent) 0%,
color-mix(in srgb, var(--fg) 10%, transparent) 50%,
color-mix(in srgb, var(--fg) 4%, transparent) 100%
);
background-size: 200% 100%;
animation: notes-skeleton-shimmer 1.4s ease-in-out infinite;
}
/* Type toggle (note vs todo) */
.note-form-type-row {
display: flex;
gap: 4px;
margin-top: -2px;
}
/* Reminder bell button */
/* Mobile-only: bell icon in the note editor is accent-coloured so it pops as
the primary "set a reminder" affordance. The Archive button is hidden — the
Update (✓) button morphs into an Archive action when the user opens a note
and clicks without making any edits (see notes.js `archive-mode` toggle). */
@media (max-width: 768px) {
.note-form-remind-btn { color: var(--accent, var(--red)) !important; }
.note-form-remind-btn > svg { color: var(--accent, var(--red)); }
.note-form-archive-btn { display: none !important; }
.notes-pane #notes-archive-toggle { display: none !important; }
.note-form-save.archive-mode {
color: var(--accent, var(--red)) !important;
border-color: color-mix(in srgb, var(--accent, var(--red)) 50%, transparent) !important;
background: color-mix(in srgb, var(--accent, var(--red)) 10%, transparent) !important;
}
}
.note-form-remind-btn {
flex: 0 0 auto;
background: transparent;
border: 1px solid var(--border);
color: var(--fg);
border-radius: 4px;
width: 32px;
height: 32px;
display: inline-flex;
align-items: center;
justify-content: center;
cursor: pointer;
opacity: 1;
position: relative;
top: -2px;
transition: opacity 0.15s, border-color 0.15s, background 0.15s, color 0.15s;
}
.note-form-remind-btn:hover { opacity: 1; border-color: var(--accent); background: color-mix(in srgb, var(--accent) 8%, transparent); }
.note-form-remind-btn.has-date { color: var(--accent); border-color: var(--accent); }
/* Calendar event form + notes form: jingle the little bell when the user
picks a reminder. Anchored near the top of the bell so the swing reads
as the bell clanging side-to-side. */
.cal-remind-bell,
.note-form-remind-btn > svg {
transform-origin: 50% 4px;
transition: transform 0.1s ease;
}
.cal-remind-bell.jingling,
.note-form-remind-btn > svg.jingling {
animation: cal-bell-jingle 0.65s cubic-bezier(0.36, 0, 0.66, -0.56) both;
}
@media (prefers-reduced-motion: reduce) {
.cal-remind-bell.jingling,
.note-form-remind-btn > svg.jingling { animation: none; }
}
/* Reminder tag inside form */
.note-form-reminder-tags {
display: flex;
flex-wrap: wrap;
gap: 4px;
}
.note-reminder-tag {
display: inline-flex;
align-items: center;
gap: 6px;
background: color-mix(in srgb, var(--accent) 14%, transparent);
color: var(--accent);
border: none;
border-radius: 12px;
padding: 4px 4px 4px 9px;
font-size: 10px;
font-family: inherit;
cursor: pointer;
font-weight: 500;
}
.note-reminder-tag:hover { background: color-mix(in srgb, var(--accent) 22%, transparent); }
.note-reminder-tag-x {
display: inline-flex;
align-items: center;
justify-content: center;
width: 14px;
height: 14px;
border-radius: 50%;
background: color-mix(in srgb, var(--accent) 25%, transparent);
font-size: 12px;
line-height: 1;
position: relative;
top: -2px;
}
.note-reminder-tag-x:hover { background: var(--red); color: #fff; }
/* Reminder tag on card */
.note-card-reminder {
display: inline-flex;
align-items: center;
gap: 4px;
background: color-mix(in srgb, var(--accent) 12%, transparent);
color: var(--accent);
font-size: 9px;
font-weight: 500;
padding: 2px 7px;
border-radius: 10px;
align-self: flex-start;
margin-top: 2px;
}
.note-card-reminder.overdue {
background: color-mix(in srgb, var(--red) 18%, transparent);
color: var(--red);
}
/* Reminder dropdown menu */
.note-reminder-menu {
position: fixed;
background: var(--bg);
border: 1px solid var(--border);
border-radius: 8px;
box-shadow: 0 6px 24px rgba(0,0,0,0.25);
/* Above the fullscreen note overlay (z-index: 10500) — otherwise the
reminder picker opens hidden behind it on mobile and reads as
"broken". */
z-index: 12000;
min-width: 220px;
padding: 6px 0;
font-family: inherit;
font-size: 12px;
}
.note-reminder-menu-title {
font-size: 10px;
font-weight: 600;
text-transform: uppercase;
opacity: 0.5;
padding: 6px 14px 4px;
letter-spacing: 0.5px;
}
.note-reminder-menu-item {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
background: none;
border: none;
color: var(--fg);
font-family: inherit;
font-size: 12px;
padding: 7px 14px;
cursor: pointer;
text-align: left;
transition: background 0.1s;
}
.note-reminder-menu-item:hover { background: color-mix(in srgb, var(--fg) 6%, transparent); }
.note-reminder-menu-item.active { color: var(--accent); }
.note-reminder-menu-sub {
font-size: 10px;
opacity: 0.5;
margin-left: 12px;
}
.note-reminder-menu-check { color: var(--accent); font-size: 12px; }
.note-reminder-menu-divider {
height: 1px;
background: var(--border);
margin: 4px 0;
}
.note-reminder-menu-picker {
padding: 6px 14px 8px;
}
.note-reminder-date-input {
width: 100%;
background: color-mix(in srgb, var(--fg) 5%, transparent);
border: 1px solid var(--border);
border-radius: 4px;
color: var(--fg);
font-family: inherit;
font-size: 12px;
padding: 6px 8px;
outline: none;
color-scheme: dark light;
box-sizing: border-box;
}
.note-reminder-date-input:focus { border-color: var(--accent); }
.note-reminder-menu-confirm {
font-weight: 600;
color: var(--accent);
justify-content: center;
}
.note-reminder-menu-confirm.disabled,
.note-reminder-menu-confirm[disabled] {
opacity: 0.4;
cursor: not-allowed;
color: var(--fg);
}
.note-reminder-menu-arrow {
opacity: 0.5;
margin-left: 8px;
font-size: 14px;
line-height: 1;
}
.note-reminder-menu-back {
display: flex;
align-items: center;
gap: 4px;
width: 100%;
background: none;
border: none;
color: var(--fg);
font-family: inherit;
font-size: 11px;
opacity: 0.7;
padding: 6px 12px;
cursor: pointer;
text-align: left;
transition: opacity 0.1s, background 0.1s;
}
.note-reminder-menu-back:hover { opacity: 1; background: color-mix(in srgb, var(--fg) 6%, transparent); }
.note-reminder-menu-arrow-back {
font-size: 14px;
line-height: 1;
}
.note-reminder-menu-sublabel {
font-size: 10px;
opacity: 0.5;
padding: 6px 14px 2px;
letter-spacing: 0.3px;
}
.note-reminder-weekday-row {
display: flex;
gap: 4px;
padding: 4px 12px 8px;
flex-wrap: wrap;
}
.note-reminder-day-chip {
flex: 1 1 0;
min-width: 24px;
height: 28px;
background: color-mix(in srgb, var(--fg) 5%, transparent);
border: 1px solid var(--border);
border-radius: 4px;
color: var(--fg);
font-family: inherit;
font-size: 11px;
font-weight: 600;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: background 0.1s, border-color 0.1s, color 0.1s;
padding: 0;
}
.note-reminder-day-chip:hover {
background: color-mix(in srgb, var(--accent) 10%, transparent);
border-color: color-mix(in srgb, var(--accent) 40%, var(--border));
}
.note-reminder-day-chip.active {
background: var(--accent);
border-color: var(--accent);
color: #fff;
}
.note-form-type-btn,
.note-form-type-toggle {
background: transparent;
border: 1px solid var(--border);
color: var(--fg);
cursor: pointer;
border-radius: 4px;
width: 32px;
height: 32px;
display: inline-flex;
align-items: center;
justify-content: center;
opacity: 1;
transition: opacity 0.15s, background 0.15s, border-color 0.15s;
}
.note-form-type-toggle:hover { opacity: 1; border-color: var(--accent); background: color-mix(in srgb, var(--accent) 8%, transparent); }
.note-form-type-toggle[data-type="todo"] { color: var(--accent); }
/* Note | Todo | Draw segmented toggle — mirrors .mode-toggle (agent/chat) */
.note-form-type-seg {
display: inline-flex;
height: 32px;
border: 1px solid var(--border);
border-radius: 10px;
overflow: hidden;
position: relative;
flex-shrink: 0;
}
.note-form-type-pill {
background: none;
border: none;
color: color-mix(in srgb, var(--fg) 40%, transparent);
cursor: pointer;
padding: 0 12px;
font-size: 13px;
font-weight: 500;
font-family: inherit;
transition: color 0.2s;
white-space: nowrap;
height: 100%;
display: inline-flex;
align-items: center;
gap: 4px;
position: relative;
z-index: 1;
}
.note-form-type-pill:not(.active):hover { color: color-mix(in srgb, var(--fg) 60%, transparent); }
.note-form-type-pill.active,
.note-form-type-pill.active:hover,
.note-form-type-pill.active:focus {
color: var(--fg);
cursor: default;
}
@media (max-width: 480px) {
.note-form-type-pill span { display: none; }
.note-form-type-pill { padding: 0 8px; }
}
.note-card-action:hover {
opacity: 1;
background: color-mix(in srgb, var(--fg) 10%, transparent);
}
.note-card-delete:hover { color: var(--red); }
/* Tag/label */
.note-card-label {
display: flex;
flex-wrap: wrap;
gap: 4px;
margin-top: 2px;
}
.note-card-label-chip {
border: 1px solid color-mix(in srgb, var(--accent) 35%, var(--border));
background: color-mix(in srgb, var(--accent) 10%, transparent);
color: var(--accent);
border-radius: 999px;
padding: 2px 6px;
font: inherit;
font-size: 9px;
font-weight: 600;
line-height: 1.2;
cursor: pointer;
}
.note-card-label-chip:hover {
background: color-mix(in srgb, var(--accent) 18%, transparent);
border-color: color-mix(in srgb, var(--accent) 60%, var(--border));
}
/* Search bar */
.notes-search-bar {
padding: 6px 8px;
display: flex;
align-items: center;
gap: 6px;
}
.notes-select-trigger {
position: relative;
top: 3px;
flex-shrink: 0;
background: var(--bg);
color: var(--fg);
border: 1px solid var(--border);
border-radius: 6px;
font-family: inherit;
font-size: 11px;
height: 30px;
padding: 0 12px;
cursor: pointer;
opacity: 0.75;
transition: opacity 0.15s, border-color 0.15s, background 0.15s, color 0.15s;
}
.notes-select-trigger:hover { opacity: 1; border-color: color-mix(in srgb, var(--accent) 50%, var(--border)); }
.notes-select-trigger.active {
opacity: 1;
background: color-mix(in srgb, var(--accent) 18%, transparent);
color: var(--accent);
border-color: color-mix(in srgb, var(--accent) 50%, var(--border));
}
.notes-search-bar .memory-search-input {
flex: 1;
min-width: 0;
height: 30px;
min-height: 30px;
font-size: 11px;
padding: 0 10px 0 28px;
background-color: var(--bg);
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;
border: 1px solid var(--border);
border-radius: 6px;
color: var(--fg);
font-family: inherit;
outline: none;
transition: border-color 0.15s, background-color 0.15s;
}
.notes-search-bar .memory-search-input:focus {
border-color: var(--red);
}
/* Grid view: true CSS Grid plus JS-computed row spans, so cards masonry-pack
vertically without the jumpy rebalancing of CSS columns. */
.notes-pane.notes-view-grid .notes-pane-body {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
grid-auto-rows: 4px;
grid-auto-flow: dense;
gap: 0 8px;
padding: 10px 8px 8px;
overflow-x: hidden;
align-items: start;
align-content: start;
}
.notes-pane.notes-view-grid .note-card {
margin: 0 0 8px;
min-width: 0;
max-width: 100%;
overflow-wrap: anywhere;
word-break: break-word;
display: flex;
flex-direction: column;
gap: 4px;
}
.notes-pane.notes-view-grid .note-form,
.notes-pane.notes-view-grid .notes-quick-add {
grid-column: 1 / -1;
margin-bottom: 0;
grid-row-end: span 16;
}
/* Edit form in grid view: span the full row and size naturally — same shape
as the new-note form. The earlier max-width: 380px + max-height: 220px
inner-scroll combo read as a tiny popup floating in a wider panel and
didn't actually fit the form's content. */
.notes-pane.notes-view-grid .note-form {
width: 100%;
max-width: none;
margin-left: 0;
margin-right: 0;
box-sizing: border-box;
}
/* Pinned section break: the first unpinned card jumps to column 1, leaving
any leftover cell in the pinned row empty. Reads as a visual divider
between pinned and unpinned without needing a separator element. */
.notes-pane.notes-view-grid .note-card-pinned + .note-card:not(.note-card-pinned) {
grid-column-start: 1;
}
/* Mobile: 2-lane masonry via the CSS-Grid row-span trick. Each card spans
N tiny rows (4px each) based on its measured height; the grid auto-places
cards into the two columns so left/right lanes flow independently — no
row alignment between them. JS in notes.js sets `grid-row-end: span N`
on every card after render. Pure CSS multi-column was tried but its
`column-span: all` interaction with sticky positioning broke clicks on
the quick-add bar (Firefox mobile). */
@media (max-width: 768px) {
.notes-pane.notes-view-grid .notes-pane-body {
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-auto-rows: 4px;
grid-auto-flow: dense;
gap: 0 8px;
align-content: start;
}
.notes-pane.notes-view-grid .note-card {
margin: -8px 0 6px;
transform: translateY(-12px);
/* grid-row-end set inline by JS (_applyMasonry) */
}
/* Full-width quick-add + edit form. Quick-add stays sticky at top so
the user can always reach it; it's NOT inside the masonry pack. */
.notes-pane.notes-view-grid .notes-label-toggle,
.notes-pane.notes-view-grid .notes-labels-bar,
.notes-pane.notes-view-grid .doclib-chip-scroll-frame:has(> .notes-labels-bar),
.notes-pane.notes-view-grid .notes-quick-add,
.notes-pane.notes-view-grid .note-form {
grid-column: 1 / -1;
}
.notes-pane.notes-view-grid .notes-label-toggle { grid-row: span 8; }
.notes-pane.notes-view-grid .notes-labels-bar { grid-row: span 16; }
.notes-pane.notes-view-grid .doclib-chip-scroll-frame:has(> .notes-labels-bar) { grid-row: span 16; }
.notes-pane.notes-view-grid .notes-quick-add { grid-row: span 12; }
.notes-pane.notes-view-grid .note-form {
width: 100%;
max-width: none;
margin-left: 0;
margin-right: 0;
box-sizing: border-box;
grid-row: auto / span 64;
}
.notes-pane.notes-view-grid .note-form:has(.note-form-type-seg.is-draw) {
grid-row: auto / span 152;
}
.notes-pane.notes-view-grid .note-form.note-form-new {
transform: translateY(-28px);
}
.notes-pane.notes-view-grid .notes-labels-bar {
padding-top: 0;
margin-top: -6px;
margin-bottom: 0;
}
.notes-pane.notes-view-grid .notes-quick-add {
margin-top: -32px;
margin-bottom: 4px;
}
/* Pinned-section break: first unpinned card jumps to column 1. */
.notes-pane.notes-view-grid .note-card-pinned + .note-card:not(.note-card-pinned) {
grid-column-start: 1;
}
}
/* Label filter bar */
.notes-label-toggle {
align-self: flex-start;
margin: -6px 8px 2px;
top: 0;
}
.notes-search-bar .notes-label-toggle {
align-self: center;
flex: 0 0 auto;
height: 30px;
margin: 0;
top: 4px;
padding: 0 10px;
border-radius: 6px;
font-size: 11px;
white-space: nowrap;
}
.notes-pane-body .doclib-chip-scroll-arrow.right {
top: calc(50% - 6px) !important;
}
.doclib-chip-scroll-frame:has(> #tasks-filter-chips) .doclib-chip-scroll-arrow {
top: calc(50% - 9px) !important;
}
@media (max-width: 768px) {
#doclib-modal .doclib-lang-chips {
position: relative;
top: -2px;
}
#doclib-chats-tidy-btn,
#doclib-chats-select-btn,
#doclib-arc-select-btn,
#doclib-research-tidy-btn,
#doclib-research-select-btn,
#doclib-tidy-btn,
#doclib-select-btn {
height: 30px !important;
min-height: 30px !important;
box-sizing: border-box;
}
}
/* Keep filter chips consistent across Skills, Tasks, and the document
library. Documents use the shared compact chip treatment as the baseline. */
.skills-summary-chip,
.memory-cat-chip,
.doclib-chip {
height: 23px;
padding: 0 8px;
border: 1px solid color-mix(in srgb, var(--fg) 12%, transparent);
border-radius: 6px;
background: color-mix(in srgb, var(--fg) 4%, transparent);
color: color-mix(in srgb, var(--fg) 70%, transparent);
font-size: 10px;
line-height: 1;
font-family: inherit;
text-transform: none;
transition: background 0.15s, border-color 0.15s, color 0.15s;
}
.skills-summary-chip:hover,
.memory-cat-chip:hover,
.doclib-chip:hover {
background: color-mix(in srgb, var(--fg) 8%, transparent);
border-color: color-mix(in srgb, var(--fg) 18%, transparent);
color: color-mix(in srgb, var(--fg) 70%, transparent);
}
.skills-summary-chip.active,
.memory-cat-chip.active,
.doclib-chip.active {
background: color-mix(in srgb, var(--accent, var(--red)) 13%, transparent);
border-color: color-mix(in srgb, var(--accent, var(--red)) 28%, transparent);
color: var(--fg);
}
.notes-labels-bar {
display: flex;
flex-wrap: wrap;
gap: 4px;
padding: 0 8px 0;
margin-top: -6px;
margin-bottom: -2px;
}
.notes-label-chip {
background: transparent;
border: 1px solid var(--border);
color: color-mix(in srgb, var(--fg) 60%, transparent);
font-size: 10px;
padding: 3px 10px;
border-radius: 10px;
cursor: pointer;
font-family: inherit;
transition: background 0.15s, color 0.15s, border-color 0.15s;
}
.notes-label-chip:hover {
color: var(--fg);
background: color-mix(in srgb, var(--fg) 6%, transparent);
border-color: color-mix(in srgb, var(--accent) 40%, var(--border));
}
.notes-label-chip.active {
background: color-mix(in srgb, var(--accent) 18%, transparent);
color: var(--accent);
border-color: color-mix(in srgb, var(--accent) 60%, transparent);
font-weight: 600;
}
.notes-label-chip-reminders {
display: inline-flex;
align-items: center;
gap: 2px;
}
.notes-label-chip-count {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 14px;
height: 14px;
padding: 0 4px;
border-radius: 7px;
background: color-mix(in srgb, var(--fg) 12%, transparent);
color: inherit;
font-size: 9px;
font-weight: 600;
margin-left: 3px;
}
.notes-label-chip-reminders.active .notes-label-chip-count {
background: color-mix(in srgb, var(--accent) 30%, transparent);
color: var(--accent);
}
.notes-label-chip-reminders.active.negated {
background: color-mix(in srgb, var(--red, #e55) 14%, transparent);
color: var(--red, #e55);
border-color: color-mix(in srgb, var(--red, #e55) 50%, transparent);
}
.notes-label-chip-reminders.active.negated .notes-label-chip-count {
background: color-mix(in srgb, var(--red, #e55) 25%, transparent);
color: var(--red, #e55);
}
.notes-label-clear-past {
display: inline-flex;
align-items: center;
gap: 4px;
color: var(--red, #e55);
border-color: color-mix(in srgb, var(--red, #e55) 45%, var(--border));
}
.notes-label-clear-past:hover {
color: var(--red, #e55);
background: color-mix(in srgb, var(--red, #e55) 12%, transparent);
border-color: color-mix(in srgb, var(--red, #e55) 65%, var(--border));
}
/* Today + Goals filter chips — share styling, tint with a warm accent so
they read as "long-term work" alongside the cool reminder chip. */
.notes-label-chip-today,
.notes-label-chip-goals {
display: inline-flex;
align-items: center;
gap: 2px;
}
.notes-label-chip-today.active,
.notes-label-chip-goals.active {
background: color-mix(in srgb, var(--accent-warm) 22%, transparent);
color: var(--accent-warm);
border-color: color-mix(in srgb, var(--accent-warm) 60%, transparent);
}
.notes-label-chip-today.active .notes-label-chip-count,
.notes-label-chip-goals.active .notes-label-chip-count {
background: color-mix(in srgb, var(--accent-warm) 30%, transparent);
color: var(--accent-warm);
}
/* ── Goal cards ──────────────────────────────────────────────────────── */
/* A goal note is structurally a checklist (note_type='goal') but visually
marked with a small Goal pill in the corner + a slightly warmer accent
so users can spot it at a glance among regular todos. */
.note-card-goal {
border-left: 3px solid color-mix(in srgb, var(--accent-warm) 80%, transparent);
}
.note-goal-pill {
position: absolute;
top: 6px;
left: 8px;
display: inline-flex;
align-items: center;
gap: 3px;
padding: 2px 7px 2px 5px;
background: color-mix(in srgb, var(--accent-warm) 18%, transparent);
color: var(--accent-warm);
border-radius: 999px;
font-size: 9px;
font-weight: 600;
letter-spacing: 0.04em;
text-transform: uppercase;
line-height: 1;
z-index: 2;
}
/* Description blurb above the checklist on goal cards */
.note-goal-desc {
font-size: 12px;
opacity: 0.7;
margin: 4px 0 6px;
white-space: pre-wrap;
line-height: 1.4;
}
/* ── Goal form (Break-down editor) ───────────────────────────────────── */
.note-form-goal {
display: flex;
flex-direction: column;
gap: 8px;
}
.note-form-goal-desc {
width: 100%;
box-sizing: border-box;
background: transparent;
border: 1px solid var(--border);
border-radius: 6px;
color: var(--fg);
font-family: inherit;
font-size: 13px;
padding: 8px 10px;
resize: vertical;
min-height: 60px;
}
.note-form-goal-desc:focus {
outline: none;
border-color: color-mix(in srgb, var(--accent-warm) 60%, var(--border));
}
.note-form-goal-actions {
display: flex;
align-items: center;
gap: 8px;
}
.note-form-goal-ai {
display: inline-flex;
align-items: center;
background: color-mix(in srgb, var(--accent-warm) 16%, transparent);
color: var(--accent-warm);
border: 1px solid color-mix(in srgb, var(--accent-warm) 45%, transparent);
border-radius: 6px;
padding: 5px 10px;
font-size: 12px;
font-weight: 600;
cursor: pointer;
transition: background 0.15s, border-color 0.15s;
}
.note-form-goal-ai:hover:not(:disabled) {
background: color-mix(in srgb, var(--accent-warm) 26%, transparent);
border-color: color-mix(in srgb, var(--accent-warm) 65%, transparent);
}
.note-form-goal-hint {
font-size: 11px;
opacity: 0.55;
}
/* ── Today view ──────────────────────────────────────────────────────── */
.notes-today-wrap {
display: flex;
flex-direction: column;
gap: 4px;
margin: 4px 0 12px;
}
.notes-today-header {
display: inline-flex;
align-items: center;
gap: 6px;
font-size: 11px;
font-weight: 600;
letter-spacing: 0.06em;
text-transform: uppercase;
color: var(--accent-warm);
padding: 6px 10px 4px;
}
.notes-today-list {
display: flex;
flex-direction: column;
gap: 6px;
}
.notes-today-row {
display: flex;
align-items: center;
gap: 10px;
padding: 10px 12px;
background: var(--panel, var(--bg));
border: 1px solid var(--border);
border-left: 3px solid color-mix(in srgb, var(--accent-warm) 70%, transparent);
border-radius: 8px;
transition: opacity 0.2s, transform 0.2s;
}
.notes-today-row .note-check-dot {
flex-shrink: 0;
width: 18px;
height: 18px;
border-radius: 50%;
border: 2px solid color-mix(in srgb, var(--fg) 40%, transparent);
cursor: pointer;
transition: background 0.15s, border-color 0.15s;
}
.notes-today-row .note-check-dot:hover {
border-color: var(--accent-warm);
background: color-mix(in srgb, var(--accent-warm) 20%, transparent);
}
.notes-today-row.done .note-check-dot {
background: var(--accent-warm);
border-color: var(--accent-warm);
}
.notes-today-text {
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
gap: 2px;
}
.notes-today-title {
font-size: 11px;
font-weight: 600;
color: var(--accent-warm);
letter-spacing: 0.03em;
cursor: pointer;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.notes-today-step {
font-size: 14px;
color: var(--fg);
line-height: 1.35;
}
.notes-today-progress {
flex-shrink: 0;
font-size: 10px;
font-weight: 600;
opacity: 0.6;
font-variant-numeric: tabular-nums;
}
.notes-empty {
text-align: center;
padding: 32px 16px;
font-size: 13px;
opacity: 0.55;
font-style: italic;
}
/* Bulk action bar */
.notes-bulk-info {
font-size: 10px;
opacity: 0.6;
margin-left: 4px;
}
/* Form label input */
.note-form-label {
background: transparent;
border: 1px dashed color-mix(in srgb, var(--border) 60%, transparent);
color: var(--fg);
font-size: 11px;
padding: 3px 6px;
border-radius: 4px;
outline: none;
width: 80px;
font-family: inherit;
opacity: 0.6;
transition: opacity 0.15s, border-color 0.15s;
}
.note-form-label:hover, .note-form-label:focus { opacity: 1; border-color: var(--border); }
@keyframes noteLabelFlash {
0% { background: color-mix(in srgb, var(--accent) 35%, transparent); }
100% { background: transparent; }
}
.note-card-header {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 6px;
}
.note-card-title {
font-size: 13px;
font-weight: 600;
cursor: pointer;
flex: 1;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.note-content-preview {
font-size: 12px;
opacity: 0.6;
line-height: 1.4;
/* Roomy preview: up to ~14 lines. Content is also sliced to 600 chars
client-side, so cards still stay reasonable in the list. */
max-height: 240px;
overflow: hidden;
cursor: pointer;
white-space: pre-wrap;
word-break: break-word;
}
.note-pin-btn {
background: none;
border: none;
cursor: pointer;
padding: 2px;
flex-shrink: 0;
display: flex;
align-items: center;
}
.note-pin-dot {
width: 7px;
height: 7px;
border-radius: 50%;
border: 1.5px solid color-mix(in srgb, var(--fg) 25%, transparent);
transition: all 0.15s;
}
.note-pin-btn:hover .note-pin-dot { border-color: var(--fg); }
.note-pin-btn.active .note-pin-dot {
background: var(--accent);
border-color: var(--accent);
}
.note-x-btn {
background: none;
border: none;
cursor: pointer;
padding: 2px;
flex-shrink: 0;
color: var(--fg);
opacity: 0.25;
display: flex;
align-items: center;
transition: opacity 0.15s, color 0.15s;
}
.note-x-btn:hover {
opacity: 0.9;
color: var(--red);
}
/* Inline due date next to title */
.note-due-inline {
font-size: 9px;
padding: 1px 6px;
border-radius: 3px;
background: color-mix(in srgb, var(--fg) 8%, transparent);
color: color-mix(in srgb, var(--fg) 60%, transparent);
opacity: 0.7;
white-space: nowrap;
flex-shrink: 0;
align-self: center;
}
.note-due-inline.note-due-overdue {
background: color-mix(in srgb, var(--red) 18%, transparent);
color: var(--red);
opacity: 1;
font-weight: 600;
}
.note-card:active { cursor: grabbing; }
/* Dragged card = "drop preview" — it already sits at the swap-target slot,
so making it the most visible card on screen tells the user exactly where
the note will land on release. */
.note-card.dragging {
opacity: 0.92;
cursor: grabbing;
transform: scale(1.03) rotate(-0.6deg);
box-shadow: 0 14px 32px rgba(0,0,0,0.4), 0 0 0 2px var(--accent, var(--red));
border-color: var(--accent, var(--red)) !important;
background: color-mix(in srgb, var(--accent, var(--red)) 6%, var(--panel)) !important;
z-index: 10;
position: relative;
/* Let elementFromPoint see THROUGH the dragged card so the swap detector
can find the sibling underneath the finger. Without this, in single-row
(list view) the dragged card follows the finger and forever occludes
anything else, so no swap ever fires. The body-level touchmove listener
still receives events regardless. */
pointer-events: none;
}
.notes-pane-body.drag-active .note-card:not(.dragging) {
transition: transform 0.22s cubic-bezier(0.34, 1.2, 0.64, 1), border-color 0.15s, opacity 0.15s;
opacity: 0.78;
}
.notes-pane-body.drag-active .note-card:not(.dragging):hover {
border-color: color-mix(in srgb, var(--accent, var(--red)) 50%, var(--border));
opacity: 1;
}
/* Checklist drag grip */
.note-cl-grip {
cursor: grab;
opacity: 0.2;
font-size: 9px;
letter-spacing: -2px;
user-select: none;
flex-shrink: 0;
width: 14px;
height: 14px;
display: flex;
align-items: center;
justify-content: center;
transition: opacity 0.15s;
}
.note-cl-row.dragging {
opacity: 0.4;
background: color-mix(in srgb, var(--accent) 8%, transparent);
border-radius: 4px;
}
.note-cl-row.drop-before {
box-shadow: 0 -2px 0 0 var(--accent);
}
.note-cl-row.drop-after {
box-shadow: 0 2px 0 0 var(--accent);
}
.note-card-footer {
display: flex;
align-items: center;
gap: 6px;
margin-top: 2px;
}
.note-delete-btn {
background: none;
border: none;
color: var(--fg);
opacity: 0.2;
cursor: pointer;
padding: 2px;
transition: opacity 0.15s;
}
.note-delete-btn:hover { opacity: 0.8; color: var(--red); }
.note-archive-btn {
background: none; border: none; color: var(--fg); opacity: 0.2; cursor: pointer; padding: 2px; transition: opacity 0.15s;
}
/* Checklist preview — cap height so cards with 30 items don't push the
grid layout into oblivion; the inner list scrolls inside the card. */
.note-checklist-preview {
display: flex;
flex-direction: column;
gap: 0;
min-height: 18px;
max-height: 240px;
overflow-y: auto;
/* Let wheel/touch scrolling continue into the Notes pane when this nested
checklist is already at its top or bottom. */
overscroll-behavior-y: auto;
/* Card has padding-right:30px reserved for the top-corner edit/done/pin
buttons — but those sit above the checklist, not next to it. Pull the
checklist back into that reserved gutter so todo text can extend
further right. The copy button (bottom-right, 28×28) only appears on
hover; leave just enough room (last row) so it doesn't hide the final
item's tail. */
margin-right: -22px;
padding-right: 4px;
}
.note-cl-quickadd {
/* In flow now (was position:absolute), rendered AFTER the reminder badge
so the "+ Add item" input sits underneath the reminder instead of
overlapping it. Slight right inset keeps clear of the bottom-right
copy button on hover. */
display: block;
padding-top: 2px;
padding-right: 32px;
margin-top: 2px;
opacity: 0;
pointer-events: none;
transition: opacity 0.15s;
}
.note-cl-quickadd-input {
width: 100%;
background: transparent;
border: none;
border-top: 1px dashed color-mix(in srgb, var(--border) 60%, transparent);
color: var(--fg);
font-size: 11px;
font-family: inherit;
padding: 4px 2px 2px;
outline: none;
opacity: 0.6;
transition: opacity 0.15s, border-color 0.15s;
}
.note-cl-quickadd-input:focus { opacity: 1; border-top-color: var(--border); }
.note-checkbox {
display: flex;
align-items: center;
gap: 8px;
font-size: 11px;
cursor: pointer;
/* Vertical padding stays 0 so short single-line rows pack tightly.
Left padding bumped so the dot's hover-scale (1.15x) doesn't clip
against the card edge. */
padding: 0 4px 0 8px;
line-height: 1.25;
border-radius: 4px;
user-select: none;
-webkit-tap-highlight-color: transparent;
}
.note-checkbox:hover {
background: color-mix(in srgb, var(--fg) 5%, transparent);
}
.note-check-text { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.note-link {
color: var(--accent-primary, var(--red));
text-decoration: underline;
word-break: break-all;
}
.note-link:hover { opacity: 0.8; }
.note-checkbox-edit, .note-checkbox-rm {
flex: 0 0 auto;
background: transparent;
border: none;
color: var(--fg);
opacity: 0;
cursor: pointer;
padding: 2px;
border-radius: 3px;
display: flex;
align-items: center;
justify-content: center;
margin-left: 2px;
transition: opacity 0.12s, background 0.12s, color 0.12s;
}
.note-checkbox-rm:hover { opacity: 1 !important; color: var(--red); background: color-mix(in srgb, var(--red) 12%, transparent); }
.note-checkbox-edit:hover { opacity: 1 !important; color: var(--accent, var(--blue)); background: color-mix(in srgb, var(--accent, var(--blue)) 12%, transparent); }
.note-check-text[contenteditable="true"] {
background: color-mix(in srgb, var(--fg) 8%, transparent);
outline: 1px solid var(--accent, var(--blue));
border-radius: 2px;
cursor: text;
padding: 0 2px;
margin: 0 -2px;
}
.note-check-dot {
width: 16px;
height: 16px;
border-radius: 50%;
border: 1.75px solid color-mix(in srgb, var(--fg) 35%, transparent);
/* Solid panel fill so the dot reads as a tappable target even when an
image or colored card background sits behind it. */
background: var(--panel);
flex-shrink: 0;
position: relative;
/* Anchor the hover/active scale to the LEFT edge so the dot grows
rightward only. Default center origin pushed the scaled dot off the
left of the card (the parent .note-checklist-preview has overflow:auto
and clips horizontally as a side-effect of overflow-y:auto). */
transform-origin: left center;
transition: background 0.2s, border-color 0.2s, transform 0.15s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.notes-select-mode .note-checkbox:hover { background: transparent; }
.notes-select-mode .note-checkbox:hover .note-check-dot { transform: none; border-color: color-mix(in srgb, var(--fg) 35%, transparent); }
.note-checkbox:hover .note-check-dot {
border-color: var(--accent);
transform: scale(1.15);
}
.note-checkbox.done .note-check-dot {
background: var(--accent);
border-color: var(--accent);
animation: note-check-pop 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.note-check-text {
transition: opacity 0.25s;
line-height: 1.3;
padding-right: 4px;
word-break: break-word;
}
/* Due date badge */
.note-due-badge {
font-size: 10px;
padding: 1px 6px;
border-radius: 4px;
background: color-mix(in srgb, var(--fg) 10%, transparent);
color: var(--fg);
opacity: 0.6;
}
.note-due-overdue {
background: color-mix(in srgb, var(--red) 20%, transparent);
color: var(--red);
opacity: 1;
font-weight: 600;
}
/* Color classes — theme-aware via color-mix with --panel */
.note-color-red { background: color-mix(in srgb, var(--red) 18%, var(--panel)); border-color: color-mix(in srgb, var(--red) 30%, var(--border)); }
.note-color-orange { background: color-mix(in srgb, #d19a66 18%, var(--panel)); border-color: color-mix(in srgb, #d19a66 30%, var(--border)); }
.note-color-yellow { background: color-mix(in srgb, var(--hl-string) 18%, var(--panel)); border-color: color-mix(in srgb, var(--hl-string) 30%, var(--border)); }
.note-color-green { background: color-mix(in srgb, #98c379 18%, var(--panel)); border-color: color-mix(in srgb, #98c379 30%, var(--border)); }
.note-color-blue { background: color-mix(in srgb, var(--hl-function) 18%, var(--panel)); border-color: color-mix(in srgb, var(--hl-function) 30%, var(--border)); }
.note-color-purple { background: color-mix(in srgb, var(--hl-keyword) 18%, var(--panel)); border-color: color-mix(in srgb, var(--hl-keyword) 30%, var(--border)); }
/* Standard notes use a small identity palette when no color was selected.
The variation is deliberately limited to the card tint, top edge, and
title accent so the notes still read as one collection. */
.note-card.note-standard {
border-top-width: 3px;
background: color-mix(in srgb, var(--note-accent) 7%, var(--panel));
border-color: color-mix(in srgb, var(--note-accent) 24%, var(--border));
box-shadow: inset 0 2px 0 0 color-mix(in srgb, var(--note-accent) 72%, transparent);
}
.note-card.note-standard:hover {
background: color-mix(in srgb, var(--note-accent) 11%, var(--panel));
}
.note-card.note-standard .note-card-title {
color: color-mix(in srgb, var(--note-accent) 82%, var(--fg));
}
.note-card.note-standard .note-card-label-chip {
border-color: color-mix(in srgb, var(--note-accent) 38%, var(--border));
background: color-mix(in srgb, var(--note-accent) 10%, transparent);
color: color-mix(in srgb, var(--note-accent) 86%, var(--fg));
}
/* Color picker dots */
.note-color-picker {
display: flex;
gap: 5px;
align-items: center;
}
.note-color-dot {
width: 16px;
height: 16px;
border-radius: 50%;
cursor: pointer;
border: 2px solid transparent;
transition: border-color 0.15s, transform 0.15s;
flex-shrink: 0;
}
.note-color-dot:hover { transform: scale(1.15); }
.note-color-dot.active {
border-color: var(--fg);
}
/* Note form */
.note-form {
background: var(--panel);
border: 1px solid var(--border);
border-radius: 8px;
padding: 12px 14px;
display: flex;
flex-direction: column;
gap: 8px;
margin-bottom: 10px;
transition: background 0.2s, border-color 0.2s;
/* Container so the action buttons can collapse to icons when the note
card is narrow (see .note-form-collapsible). */
container-type: inline-size;
container-name: noteform;
}
@media (max-width: 768px) {
.notes-pane:not(.notes-view-grid) .note-form.note-form-new {
transform: translateY(6px);
}
}
/* Label sits after the icon in each action button */
.note-form-text-btn .nft-label { margin-left: 5px; }
/* Never let the action buttons spill outside the card */
.note-form-actions-group { flex-wrap: wrap; row-gap: 6px; }
/* When the note card is narrow, collapse Archive / Delete / Cancel to
icon-only (their text label hides; tooltip via title= remains). The
Save/Update button is NOT collapsible — it always keeps its label and
stays last. */
@container noteform (max-width: 360px) {
.note-form-collapsible .nft-label { display: none; }
.note-form-collapsible { padding-left: 9px; padding-right: 9px; }
}
.note-form.note-color-red { background: color-mix(in srgb, var(--red) 18%, var(--panel)) !important; border-color: color-mix(in srgb, var(--red) 30%, var(--border)) !important; }
.note-form.note-color-orange { background: color-mix(in srgb, #d19a66 18%, var(--panel)) !important; border-color: color-mix(in srgb, #d19a66 30%, var(--border)) !important; }
.note-form.note-color-yellow { background: color-mix(in srgb, var(--hl-string) 18%, var(--panel)) !important; border-color: color-mix(in srgb, var(--hl-string) 30%, var(--border)) !important; }
.note-form.note-color-green { background: color-mix(in srgb, #98c379 18%, var(--panel)) !important; border-color: color-mix(in srgb, #98c379 30%, var(--border)) !important; }
.note-form.note-color-blue { background: color-mix(in srgb, var(--hl-function) 18%, var(--panel)) !important; border-color: color-mix(in srgb, var(--hl-function) 30%, var(--border)) !important; }
.note-form.note-color-purple { background: color-mix(in srgb, var(--hl-keyword) 18%, var(--panel)) !important; border-color: color-mix(in srgb, var(--hl-keyword) 30%, var(--border)) !important; }
.note-form-header {
display: flex;
align-items: center;
gap: 8px;
padding-right: 0;
}
.note-form-header .note-form-remind-btn {
margin-right: -7px; /* align bell center with X-button column on todo rows */
position: relative;
top: -2px;
}
.note-form-title {
flex: 1;
min-width: 0;
background: transparent;
border: none;
border-bottom: 1px solid var(--border);
color: var(--fg);
font-size: 14px;
font-weight: 600;
padding: 4px 0;
outline: none;
}
.note-form-title:focus { border-color: var(--fg); }
.note-form-header { position: relative; }
.note-form-header .note-form-due {
position: absolute;
width: 1px;
height: 1px;
opacity: 0;
pointer-events: none;
border: 0;
padding: 0;
margin: 0;
right: 0;
bottom: 0;
}
.note-form-due-btn {
flex: 0 0 auto;
background: transparent;
border: 1px solid var(--border);
color: var(--fg);
border-radius: 4px;
width: 26px;
height: 26px;
display: inline-flex;
align-items: center;
justify-content: center;
cursor: pointer;
opacity: 0.85;
transition: opacity 0.15s, border-color 0.15s, background 0.15s;
}
.note-form-due-btn:hover { opacity: 1; border-color: var(--accent); background: color-mix(in srgb, var(--accent) 8%, transparent); }
.note-form-due-btn.has-date {
opacity: 1;
border-style: solid;
background: color-mix(in srgb, var(--accent) 18%, transparent);
border-color: color-mix(in srgb, var(--accent) 50%, var(--border));
}
.note-type-toggle {
display: flex;
gap: 4px;
}
.note-type-btn {
background: transparent;
border: 1px solid var(--border);
color: var(--fg);
font-size: 11px;
padding: 3px 10px;
border-radius: 4px;
cursor: pointer;
opacity: 0.5;
transition: opacity 0.15s, background 0.15s;
}
.note-type-btn.active {
opacity: 1;
background: color-mix(in srgb, var(--fg) 10%, transparent);
}
.note-form-content {
background: transparent;
border: 1px solid var(--border);
color: var(--fg);
font-size: 12px;
padding: 8px;
border-radius: 4px;
resize: vertical;
/* Roomier default so editing a note isn't cramped; JS auto-grow takes
it further as you type. */
min-height: 120px;
line-height: 1.5;
font-family: inherit;
outline: none;
}
.note-form-content:focus { border-color: var(--fg); }
.note-form-meta {
display: flex;
align-items: center;
gap: 6px;
flex-wrap: wrap;
}
.note-form-meta .note-color-picker { gap: 3px; }
.note-form-actions-group {
display: flex;
gap: 6px;
align-items: center;
/* Take the full width of the meta row so Archive/Delete can sit on the
LEFT side and the spacer pushes Cancel + Update to the right edge. */
flex: 1 1 auto;
flex-shrink: 0;
flex-wrap: nowrap;
}
.note-form-actions-spacer { flex: 1 1 auto; }
/* Unified text+icon action button — used for Archive, Delete, Cancel, Update
so all 4 read as a matched set. Matches the existing .note-form-save
sizing/padding via the rules at ~25023. */
.note-form-text-btn {
display: inline-flex;
align-items: center;
justify-content: center;
background: color-mix(in srgb, var(--fg) 6%, transparent);
border: 1px solid var(--border);
color: var(--fg);
border-radius: 6px;
padding: 5px 12px;
font-size: 12px;
font-family: inherit;
font-weight: 500;
cursor: pointer;
transition: background 0.12s, border-color 0.12s, color 0.12s;
white-space: nowrap;
}
.note-form-text-btn:hover {
background: color-mix(in srgb, var(--fg) 14%, transparent);
border-color: color-mix(in srgb, var(--fg) 28%, var(--border));
}
.note-form-text-btn.note-form-save {
background: color-mix(in srgb, var(--accent, var(--red)) 18%, transparent);
border-color: color-mix(in srgb, var(--accent, var(--red)) 45%, var(--border));
color: var(--accent, var(--red));
font-weight: 600;
}
.note-form-text-btn.note-form-save:hover {
background: color-mix(in srgb, var(--accent, var(--red)) 28%, transparent);
}
.note-form-text-btn.danger:hover {
background: color-mix(in srgb, var(--red) 14%, transparent);
border-color: color-mix(in srgb, var(--red) 45%, var(--border));
color: var(--red);
}
.note-form-icon-btn {
background: transparent;
border: 1px solid var(--border);
color: var(--fg);
cursor: pointer;
border-radius: 4px;
width: 38px;
height: 38px;
display: inline-flex;
align-items: center;
justify-content: center;
opacity: 0.65;
transition: opacity 0.15s, border-color 0.15s, background 0.15s, color 0.15s;
}
/* Force the inner icons to render at the inline-attribute size — some other
stylesheets clamp `svg { width: ... }` globally and that shrinks them. */
.note-form-icon-btn svg { width: 31px !important; height: 31px !important; }
.note-form-icon-btn:hover { opacity: 1; border-color: var(--accent); background: color-mix(in srgb, var(--accent) 8%, transparent); }
.note-form-delete-btn:hover { color: var(--red); border-color: color-mix(in srgb, var(--red) 50%, var(--border)); background: color-mix(in srgb, var(--red) 8%, transparent); }
/* Draw mode — canvas + small toolbar */
.note-form-draw-wrap {
display: flex;
flex-direction: column;
gap: 6px;
position: relative;
}
/* X overlay on the canvas — appears only when a photo is loaded as the
background (via _wireCanvas). Clicking it restores the theme surface. */
.note-form-draw-bg-rm {
position: absolute;
top: 8px;
right: 8px;
z-index: 3;
width: 28px;
height: 28px;
border: none;
border-radius: 50%;
background: rgba(0, 0, 0, 0.6);
color: #fff;
font-size: 18px;
line-height: 1;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
}
.note-form-draw-bg-rm:hover { background: rgba(0, 0, 0, 0.8); }
/* Draw mode hides the note's background-color picker and the standalone
image preview — they don't make sense alongside a canvas. Uses :has() so
it kicks in whenever the type-seg flips to .is-draw, in addition to the
JS that sets display:none. */
.note-form:has(.note-form-type-seg.is-draw) .note-color-picker,
.note-form:has(.note-form-type-seg.is-draw) .note-form-image-wrap {
display: none !important;
}
.note-form-canvas {
background: var(--panel, var(--bg));
border: 1px solid var(--border);
border-radius: 6px;
touch-action: none;
max-width: 100%;
cursor: crosshair;
}
.note-form-draw-toolbar {
display: flex;
align-items: center;
gap: 6px;
flex-wrap: wrap;
}
.note-form-draw-tool {
display: inline-flex;
align-items: center;
height: 26px;
}
/* Color picker rendered as a flat circular swatch — the native chrome around
<input type=color> would clash with the rest of the toolbar. */
.note-form-draw-color {
appearance: none;
-webkit-appearance: none;
width: 24px;
height: 24px;
border-radius: 50%;
border: 1px solid color-mix(in srgb, var(--fg) 25%, transparent);
background: none;
cursor: pointer;
padding: 0;
overflow: hidden;
box-sizing: border-box;
flex: 0 0 24px;
}
.note-form-draw-size-wrap { width: 110px; display: inline-flex; align-items: center; }
.note-form-photo-plus {
font-size: 16px;
line-height: 1;
font-weight: 600;
opacity: 0.8;
}
/* Mirrors .gallery-editor-container input[type=range] — slim pill track that
grows on interaction, red circular thumb. */
.note-form-draw-size {
-webkit-appearance: none;
appearance: none;
width: 100%;
height: 4px;
background: color-mix(in srgb, var(--fg) 25%, transparent);
border-radius: 999px;
accent-color: var(--red);
cursor: pointer;
transition: height 0.15s ease;
}
/* Brush | Eraser segmented toggle — sliding pill, same recipe as Note/Todo. */
.note-form-draw-be {
display: inline-flex;
height: 32px;
/* Accent-colored box around the whole control so it's instantly readable
as "switch is on", and the sliding pill inside indicates which side. */
border: 2px solid var(--accent);
border-radius: 10px;
overflow: hidden;
position: relative;
flex-shrink: 0;
background: color-mix(in srgb, var(--fg) 5%, transparent);
}
.note-form-draw-be-btn {
background: none;
border: none;
color: color-mix(in srgb, var(--fg) 50%, transparent);
cursor: pointer;
padding: 0 8px;
width: 34px;
height: 100%;
display: inline-flex;
align-items: center;
justify-content: center;
position: relative;
z-index: 1;
transition: color 0.18s;
}
.note-form-draw-be-btn:hover { color: var(--fg); }
/* Active side picks up the theme accent so brush vs eraser is unmistakable. */
.note-form-draw-be-btn.active { color: var(--accent-primary, var(--red)); }
.note-form-draw-text,
.note-form-draw-line,
.note-form-draw-circle,
.note-form-draw-undo {
background: transparent;
border: 1px solid var(--border);
color: var(--fg);
cursor: pointer;
border-radius: 4px;
height: 32px;
width: 34px;
font-family: inherit;
font-size: 14px;
display: inline-flex;
align-items: center;
justify-content: center;
opacity: 0.7;
position: relative;
transition: opacity 0.15s, border-color 0.15s, background 0.15s;
}
.note-form-draw-text { font-weight: 700; font-family: Georgia, serif; font-size: 16px; }
.note-form-draw-undo.has-undo {
opacity: 1;
color: var(--accent-primary, var(--red));
border-color: color-mix(in srgb, var(--accent-primary, var(--red)) 55%, var(--border));
background: color-mix(in srgb, var(--accent-primary, var(--red)) 12%, transparent);
}
.note-form-draw-undo:disabled {
opacity: 0.35;
cursor: default;
}
/* Size badge in the bottom-right of T — empty until a size is chosen. */
.note-form-draw-text-badge {
position: absolute;
right: 3px;
bottom: 1px;
font-family: inherit;
font-weight: 700;
font-size: 8px;
line-height: 1;
letter-spacing: 0.3px;
/* Bare --accent is undefined here, was rendering invisible — use the
defined accent so the S/M/L size badge actually shows in theme colour. */
color: var(--accent-primary, var(--red));
}
.note-form-draw-shape-badge {
position: absolute;
right: 3px;
bottom: 1px;
font-family: inherit;
font-weight: 700;
font-size: 8px;
line-height: 1;
letter-spacing: 0.3px;
color: var(--accent-primary, var(--red));
}
.note-form-draw-text:hover,
.note-form-draw-line:hover,
.note-form-draw-circle:hover,
.note-form-draw-undo:hover {
opacity: 1;
border-color: var(--accent);
background: color-mix(in srgb, var(--accent) 8%, transparent);
}
.note-form-draw-text.active,
.note-form-draw-line.active,
.note-form-draw-circle.active {
opacity: 1;
background: color-mix(in srgb, var(--accent) 18%, transparent);
color: var(--accent);
border-color: color-mix(in srgb, var(--accent) 50%, var(--border));
}
.note-form-due {
background: transparent;
border: 1px dashed color-mix(in srgb, var(--border) 60%, transparent);
color: var(--fg);
font-size: 11px;
padding: 3px 6px;
border-radius: 4px;
outline: none;
opacity: 0.4;
transition: opacity 0.15s, border-color 0.15s;
}
.note-form-due:hover, .note-form-due:focus { opacity: 0.9; border-color: var(--border); }
.note-form-actions {
display: flex;
gap: 6px;
justify-content: flex-end;
}
.note-form-save,
.note-form-cancel,
.note-form-archive {
background: transparent;
border: 1px solid var(--border);
color: var(--fg);
font-size: 11px;
padding: 4px 12px;
border-radius: 4px;
cursor: pointer;
transition: background 0.15s;
}
.note-form-save { background: color-mix(in srgb, var(--fg) 12%, transparent); font-weight: 600; }
.note-form-save:hover { background: color-mix(in srgb, var(--fg) 20%, transparent); }
.note-form-cancel:hover { background: color-mix(in srgb, var(--fg) 8%, transparent); }
.note-form-archive:hover { background: color-mix(in srgb, var(--fg) 8%, transparent); }
/* Checklist inputs in form */
.note-checklist-inputs {
display: flex;
flex-direction: column;
gap: 4px;
}
.note-cl-row {
display: flex;
align-items: center;
gap: 6px;
}