Correct behavior:
1. Cached draft + first click → opens the cached reply
2. Cached draft + second click → clears the cache and opens the
Fast/Full + context menu so the user can request a fresh draft
3. No cache → opens the menu directly
Per-button shownOnce dataset tracks the first-click state so the
second click triggers the menu instead of replaying the cached
reply again.
- AI reply: removed the cached_ai_reply shortcut so clicking the
button always reopens the Fast/Full + context menu. Lets the user
ask for a fresh draft (with new steering) instead of being locked
into the cached one.
- .email-cc-toggle gets position:relative + top:2px so it
baseline-aligns with the To: field chips next to it in the
document email compose.
- Initial button: dot-in-circle SVG + "Select" label
- After click (select-mode on): X SVG + "Cancel" label + .active class
- Same SVG glyphs as memory.js so the two pages feel consistent.
Hooked into the toolbar Select toggle AND the bulk-bar Cancel button
so both reset the icon state.
When the chevron opens the details, the To/Cc rows pop up as an
absolutely-positioned panel anchored to the bottom of the meta
block — with bg, border, rounded corners and a shadow. Nothing
in the rest of the header reflows: From row stays put, the action
cluster stays put, the email body content stays put. This kills
all the height-/spacing-jump quirks the inline-expanded design
was fighting.
- .email-reader-meta .recipient-chip drops max-width and overflow
truncation so the full name renders in each chip. The parent
.recipient-chips span already has overflow-x:auto, so users can
swipe horizontally to reveal any chip whose tail is clipped off
the right edge of the row.
- Strong (From: / To: / Cc:) labels get explicit white-space:nowrap
+ flex-shrink:0 so they never truncate even when the row is
squeezed to its minimum width.
- Horizontal: max-width and left already clamped to viewport-16.
- Vertical: prefer below the button, but flip ABOVE if there's
more space there (e.g. button near the bottom of the viewport).
- max-height clamped to viewport-16 with overflow:auto as a final
guard so the menu can never extend past the screen edge.
Dropped the two-step (pick mode → context → OK) flow. Now the
context textarea is at the top of the popover and Fast (left) /
Full (right) sit below as the confirm buttons themselves — they
fire the draft with whatever's currently in the textarea (empty
= no steering).
The document-level capture listener was closing the popover on
ANY click — including clicks inside the context textarea, which
made it impossible to focus the input. Replaced with an inline
handler that bails when the click target is inside the menu.
Restructured flow:
1. Click Fast or Full → reveals an optional context textarea
("Add context (optional)") below
2. Type optional steering note or leave blank
3. Click OK → triggers the draft with the chosen mode + note
Dropped the standalone … note-toggle button — the textarea is now
gated on picking a mode, which makes it easier to discover.
- Removed the conditional Draft fast / Draft full buttons. Note
textarea is always-on via the … toggle, and whatever's in it
is picked up by the existing Fast / Full buttons as noteHint.
- Clamped the popover max-width and left position to
Math.min(220, viewport-16) + 8px margin so the (now wider) menu
doesn't spill off the right edge on narrow mobile screens.
Top row keeps Fast / Full + a new horizontal-dots button. Clicking
the dots reveals a textarea ("e.g. reply nicely but say no"); as
soon as text is in it the panel shows Draft fast / Draft full
buttons that pass the note through as noteHint to the AI reply
endpoint. Empty textarea hides the draft buttons so the user only
gets the steered draft when they've actually typed direction.
Firefox mobile rendered the backdrop-filter:blur + var(--panel)
combination on the slide-out sidebar as semi-transparent, so the
chat input bar's selected-model label (e.g. "minimax") was
visible behind the drawer. Force background:var(--panel) and
backdrop-filter:none inside the mobile @media block.
The left-edge gradient fade was likely the source of the perceived
shadow under the icons on mobile. Forced background:none and the
matching padding-left:0 on mobile so the cluster reads as bare
icons without any soft edge.
Was only the date moving — the expanded card had a more-specific
`padding: 4px 0 6px` shorthand on the title row that zeroed out
the padding-left from my earlier nudge. Added the expanded-card
selector to the padding-left:4px rule so the title now lines up
with the meta line in both list and expanded states.
Was using flex-wrap:wrap on the From row, which let the chip span
flip onto a new row below From: when the available width briefly
dropped — then snap back as the chip span's overflow-scroll kicked
in. Switching to flex-wrap:nowrap keeps the label glued to the
chip; the chip span shrinks/scrolls horizontally instead.
In docked mode the header already reserves vertical space for the
absolute action cluster, so the To/Cc details fit without any
height tradeoff — force [hidden] open and hide the chevron toggle
so the recipients are always visible there.
Was From→To = 0 (meta gap 2 + details margin-top 0) while To→Cc
was 6 (details gap). Set details gap to 2 in docked too so all
three meta rows have the same vertical distance. Dropped the
per-row margin-top:4 docked override since spacing now comes
entirely from gaps.
Docked header is flex-direction:column, and the base
align-items:flex-start was sizing the meta to its chip width and
parking it at the left — the absolute cluster's right:0 then
landed at the meta's right edge in the middle of the pane.
align-items:stretch makes meta fill the header width so right:0
hits the actual right edge.
Dropped the docked-specific overrides (cluster flowing below meta,
padding-right:0, header min-height:0). The same container-query
rules drive both: cluster floats top-right and wraps to 2 rows
when the reader width crosses 600px, snaps to overlay below 380px.
Docked pane width is just another container width.
1. Moved the min-height from .email-reader-header to .email-reader-meta
(92px) inside the <600 container query. Targeting the container
itself in its own @container rule was flaky; using a descendant
that affects the parent's intrinsic height works reliably.
2. Dropped the margin-top:0 reset on the cluster in the <380 overlay
rule — that was clearing the base -7px lift and sliding the
cluster ~7px downward at the breakpoint. Now both states use the
same -7px lift so the visual position is stable across the
transition.
Dropped the @media(769px) from-row min-height + align-items:center
and the strong > top:-2px nudge — leftovers from the grid layout
that were forcing extra height and label offsets the block-flow
meta doesn't need.
Consolidated docked overrides into a single flat block (no @media
wrapper) and merged the two .email-reader-meta declarations into
one. Same visual result, much less competing CSS to debug.
When the cluster wraps to 2 rows (44 + 4 gap + 44 = 92px tall), it
was peeking out below the header bottom because min-height stayed
at 60px (only ~44px of cluster room). Bumped min-height to 108px
inside the same <600 container query so the wrapped cluster sits
fully inside the header with 8px breathing room top + bottom.
Replaced the grid layout (which made From row height depend on
cluster height, causing To/Cc to shoot up or down at the wrap
breakpoint) with a plain block stack:
- meta = position:relative block
- From row + details = natural block flow with padding-right
reserving space for the absolute cluster on the right
- cluster = position:absolute top-right, width changes per
container query (308px wide / 158px narrow / 180px overlay)
- padding-right tightens from 320px → 170px → 0 as the cluster
shrinks and finally goes overlay
- details margin-top dropped from -10px to 0 since there's no
grid row gap to compensate for
To/Cc now hugs From with no jumps when the cluster wraps or
overlays.
Removed the medium-mode -12px details margin compensation — it
under/over-shot depending on grid row sizing. Replaced with a
:has() rule: when the user expands To/Cc, the From row gets
min-height 92px (matching the cluster's 2-row max height). Row 1
becomes the same size whether the cluster is 1 row (wide) or 2
rows (narrow), so resizing across the 600px wrap breakpoint no
longer makes To/Cc shoot up 4px.
When the cluster snaps to absolute overlay at <380px, it stops
contributing to grid row sizing — row 1 was collapsing to the From
row's natural height, which made the To/Cc details slide upward and
left the floating cluster visually misaligned against them. Setting
min-height:88px on the From row inside the same container query
holds row 1 at the cluster's two-row height so nothing jumps.
Was fanning out to 3 rows because the 152px max-width (3 icons +
2 gaps exact) had no slack — subpixel rounding could push the
third icon over and trigger another wrap. Bumped to 158px in the
in-grid mode (600px breakpoint) and 180px in the absolute-overlay
mode (380px breakpoint, where the 22px padding-left from the
gradient fade was also eating into the 3-icon row width).
Was wrapping into 4+ rows at narrow widths because the cluster's
grid column could shrink below the 3-icon cap. Set both min-width
and max-width to the 3-icon row width and justify-self:end on the
cluster so the icons stay glued to the right edge instead of
sliding toward the middle when the cluster is wider than its
content.
The 600px / 380px breakpoints were @container docpane queries but
the email reader isn't inside a docpane container — they never
fired and the cluster wrapped to 3+ rows at narrow widths. Added
container-type:inline-size + container-name:emailreader on
.email-reader-header and switched the queries to that container,
so the 2-row cap now actually applies.
Three-step shrink:
1. > 600px pane: cluster sits in col 2 as 1 row of 6
2. 380-600px pane: cluster capped at 3-icon width so wrapping
stops at 3 + 3 (max 2 rows) — chips share width with the 2-row
cluster instead of multiplying into 3+ rows
3. < 380px pane: cluster snaps to absolute overlay with left-edge
box-shadow, still capped at 3-icon width so it's the same 2-row
shape but floating above the truncated chips
Grid tracks now:
- col 1: minmax(60px, 250px) — chip natural width capped at 250px,
with the 60px (4 char) floor enforced on From / To / Cc alike
- col 2: minmax(48px, 1fr) — takes the rest, shrinks first when
the pane narrows
Removed the hard max-width on the action cluster so on wide panes
it stays as one row of 6. Once col 2 shrinks below the 1-row width,
flex-wrap kicks in and the icons re-stack to 3+3. Chips only start
to shrink past that point.
- Action cluster's max-width is calc(48*3 + 4*2) so the 6 icons
always lay out as 3 top / 3 bottom by default.
- When the pane narrows the chips in col 1 shrink first (with 60px
min so 4 chars + ellipsis stay visible).
- At <380px the cluster snaps to absolute overlay with a left-edge
box-shadow so it reads as floating above the truncated chip.
Two-step shrink behavior:
1. As the pane narrows, the action cluster (max-width:50% of meta)
wraps to a 2-row icon stack first
2. Then the recipient chip span starts overflow-scrolling, but
keeps a 60px min-width (~4 chars) so the first chars of the
sender/recipient name stay visible
Previously only the From row affected the action cluster's column
width — To/Cc detail rows spanned both columns and ignored the
cluster. Now:
- meta-details lives in col 1 only so the To/Cc chips shrink
together with the From chip when the pane narrows
- action cluster spans rows 1 and 2 so its width is set by the
widest col-1 content; a long To/Cc list triggers the wrap to a
2-row icon stack just like a long From sender does
Meta switched to CSS grid in undocked mode:
- row 1, col 1: From row (label + chip + chevron)
- row 1, col 2: action cluster
- row 2, span: To/Cc details
The cluster shrinks alongside the chip and flex-wraps into a 2-row
icon stack before crowding the chip. At very narrow pane widths
(< 380px via @container docpane) it snaps back to absolute overlay
so From: still fits.
Docked mode overrides meta back to flex column so the cluster
flows naturally last — under From, and under To/Cc when expanded.
Was rendering as a transparent ghost — From chip / sender text bled
through the gaps between icons. Added a left-fading gradient
backed by var(--bg) so the cluster reads as an opaque overlay
while chips poking out from underneath blend smoothly into its
left edge.
- Window-level recipient-chip click handler now bails if the chip
is inside .email-reader-meta — the per-reader handler still
toggles the expanded-address view on click.
- The from-sender (magnifying glass) search button SVG is now
tinted with var(--accent-primary) so it stands out as a deliberate
search action against the neutral Reply / Forward / etc icons.