blob: a09bc4a5fe9e8f8cfc3de989ea8211c25a7c3be4 [file]
/* Composer — outer container, controls, pickers, tool buttons, send/workspace/branch/streaming. Composer block merged in from tool-output.css (was misplaced there) — issue #546 PR3. Runtime interaction prompt styles live in interaction-prompts.css. */
.composer {
flex: 0 0 auto;
display: flex;
flex-direction: column;
align-items: center;
padding: var(--space-2) var(--space-6) var(--space-2);
/* PR-GRAY-CARD-LIFT-5 (WAWQAQ msg `d4277aba` round 3): the composer
outer used to paint a vertical white-fade over `--background`,
designed for the older parchment shell where the page bg was
warm-white. Now that `--background` itself is pure white and the
shell is a visibly gray `--surface-canvas`, the composer outer
painted itself white-on-white, defeating the gray-plate / white-
card lift. Switch to transparent so the gray plate shows around
the composer card. */
background: transparent;
}
.maka-composer-astryx {
width: min(var(--maka-chat-measure), 100%);
max-width: var(--maka-chat-measure);
}
/* Row-flow, not the old stacked column: image thumbnails and file/quote
chips share one wrapping row. `width: 100%` is what makes the wrap real:
as a flex item of Astryx's drawer content this group would otherwise size
to max-content, run past the drawer edge, and get clipped by the drawer
root's overflow:hidden — the drawer must grow DOWN, never rightward. */
.maka-composer-context-drawer {
display: flex;
width: 100%;
min-width: 0;
flex-wrap: wrap;
align-items: center;
gap: var(--space-1-5);
flex-direction: row;
padding: var(--space-1) var(--space-3) var(--space-2);
}
/* Astryx ChatComposerDrawer wraps its content in a display:grid whose single
implicit column sizes to the content's max-content contribution — with a
long chip row that resolves WIDER than the grid (measured: 896px column in
a 648px grid), so the row wrapped against a phantom width and everything
past the drawer's right edge was clipped. Pin the column to the grid's own
width; the group above then wraps against the real edge. The content region
is the child carrying the disclosure id (aria-controls target). */
.maka-composer-astryx .astryx-chat-composer-drawer > div[id] {
grid-template-columns: minmax(0, 1fr);
}
/* The collapse toggle is a full-width 20px band whose only visible affordance
is a 20×2px pill — its aria-label («收起附加内容» / «展开附加内容») was
unreadable for sighted users, and a native `title` needs a ~1s motionless
hover that a thin band rarely gets. Surface the label as an instant CSS
tooltip instead: `attr(aria-label)` tracks the live attribute, so the text
flips with the collapse state and stays localized with no JS.
Placement is the hard constraint: the drawer root clips its own box
(overflow:hidden for the collapse animation), so the bubble can't rise
above the band, and the input card paints ABOVE the drawer (body z-index 2
vs drawer 1 — that overlap is the card's design), so anything hanging
below the collapsed band gets covered. The one strip clear of both is the
band's own height — within it the bubble tracks the pointer horizontally
(--maka-drawer-tooltip-x, set by the drawer's onPointerMove in
composer.tsx), falling back to beside the pill for keyboard focus. */
.maka-composer-astryx .astryx-chat-composer-drawer > [role='button'][aria-controls] {
position: relative;
}
.maka-composer-astryx .astryx-chat-composer-drawer > [role='button'][aria-controls]::after {
/* local: --maka-drawer-tooltip-x — bubble x within the band, written by
the drawer's onPointerMove in composer.tsx (cleared on pointer leave);
the fallback beside the pill serves keyboard focus. */
content: attr(aria-label);
position: absolute;
top: 50%;
left: var(--maka-drawer-tooltip-x, calc(50% + 20px));
transform: translateY(-50%);
padding: 3px 8px;
border-radius: var(--radius-control);
/* Astryx's fixed tooltip pair (same as Thumbnail's remove scrim): legible
in both themes without borrowing surface tokens for text. 11px matches
Astryx's own tooltip type — a lockstep exception, not the product scale. */
background-color: var(--color-overlay);
color: var(--color-on-dark);
font-size: 11px;
line-height: 1.4;
white-space: nowrap;
pointer-events: none;
opacity: 0;
visibility: hidden;
transition: opacity var(--duration-quick) var(--ease-out-strong);
z-index: var(--z-tooltip);
}
.maka-composer-astryx .astryx-chat-composer-drawer > [role='button'][aria-controls]:hover::after,
.maka-composer-astryx .astryx-chat-composer-drawer > [role='button'][aria-controls]:focus-visible::after {
opacity: 1;
visibility: visible;
}
/* Staged attachments share the quote chips' Token rhythm (maintainer
decision on the #2367 follow-up); the drawer stays a flat chip row. Cap
the chip and let Astryx Token's own ellipsis truncate, so a full
z-library book title cannot span the drawer — the full name rides the
chip's hover Tooltip instead. */
.maka-composer-context-drawer .maka-composer-attachment-token {
max-width: min(280px, 100%);
}
.maka-composer-input {
position: relative;
display: flex;
flex-direction: column;
gap: var(--space-1-5);
min-width: 0;
}
.maka-composer-left-controls,
.maka-composer-right-controls {
display: flex;
align-items: center;
/* PR-REFERENCE-PIXEL-8 (WAWQAQ msg `f79de85f` round 8): reference implementation's
bundle uses gap values centered on 4-8px (extracted from
`globals-UfMzAdiO.css` — 4px is the most common gap, 12px never
appears as a toolbar gap). Maka's 12px composer toolbar gap
read as too loose vs reference implementation's tighter density. 8px keeps
individual controls separable while pulling them into one
coherent toolbar group. */
gap: var(--space-1-5);
flex-wrap: wrap;
}
/* Shrinkable so the `flex-wrap: wrap` above can actually engage. At
`flex: 0 0 auto` this box sizes to max-content, which means it never has a
width to wrap inside — it just overflows, and the overflow runs under the
send button and past the card's right edge. That stayed invisible while the
row held four controls; the project picker adds to it and a 480px window has
nowhere to put the overflow. `min-width: 0` because the default
`auto` floor would keep the same overflow for a long model name. */
.maka-composer-left-controls {
flex: 1 1 auto;
min-width: 0;
}
.maka-composer-right-controls {
flex: 0 0 auto;
justify-content: flex-end;
}
/* Quiet footer: + and permission are both ghost icon buttons. */
.maka-composer-left-controls .permissionModeIcon,
.maka-composer-left-controls .maka-composer-plus-menu {
display: inline-flex;
align-items: center;
}
/* Cursor: product-wide native-cursor.css (maka.legacy) owns default vs pointer. */
/* Astryx sm list density: DropdownMenuItem + Selector options use
padding-block: var(--spacing-1) (4px) when size=sm. RadioItem only sizes its
radio glyph from menuSize and never applies itemSizeStyles, so it stays on
Item balanced (8px) and permission rows look taller than + / model. Quiet
menus force the sm block pad so all three composer popouts share one ladder.
Use product --space-1 (same 4px step as Astryx --spacing-1). Upstream
should wire itemSizeStyles into RadioItem; drop this when it does. */
.maka-composer-quiet-menu [role="menuitemradio"] {
padding-block: var(--space-1);
}
/* Astryx sizes the popover to its widest row (min-width:anchor-size, no max).
The model menu lost the 260px/56vw option-label cap with the Selector, so
the menu itself needs the ceiling: a long model name (BYOK catalogs love
`vendor/a-very-long-model-name`) must wrap inside the panel, never push it
off the window. Rows already wrap (Item has no nowrap) and the panel has
overflow-y:auto for the tall direction. */
.maka-composer-quiet-menu {
max-width: min(320px, 92vw);
}
/* Model chip (static fallback) still owns its own quiet geometry. */
.maka-composer-model-chip {
font: var(--maka-text-label);
/* #1879: was a bare 26px. It is NOT an Astryx component — `ModelChipStatic`
puts this class only on its inert `<span>` branch; the `onOpenSettings`
branch renders a `Button size="sm"` that carries no class at all
(chat-model-switcher.tsx). So nothing sizes this box but this rule, and
unpinning it measured 22px (the label role's 20px line box plus two
hairlines) against the 28px Selector beside it. `--h-control-md` resolves
to `--size-element-sm`, which is the token that Selector's own `size="sm"`
reads — so the two agree by deriving from one token rather than by two
product rules agreeing on a literal. */
height: var(--h-control-md);
display: inline-flex;
align-items: center;
justify-content: center;
gap: var(--space-1);
padding: 0 var(--space-2);
border: var(--border-width-hairline) solid transparent;
border-radius: var(--radius-pill);
background: transparent;
color: var(--foreground-secondary);
white-space: nowrap;
max-width: min(180px, 28vw);
transition:
background-color var(--duration-base) var(--ease-out-strong),
color var(--duration-base) var(--ease-out-strong);
}
.maka-composer-model-chip:hover {
background: var(--state-hover-bg);
color: var(--foreground);
border-color: transparent;
}
/* Mode ON marks sit at the tail of the footer's left controls (#1897) —
session state, not context staged for the next send, so they no longer live
in the drawer.
Maka blue is the single product accent (DESIGN.md), and an active mode is
exactly what it is for; which mode a mark is comes from its icon, not a hue,
so all three share the one accent. The wash derives from currentColor so a
disabled mark dims both layers together.
`background-color`, never the `background` shorthand: the shorthand would
suppress the ghost button's hover and active overlays and leave the one way
out of a mode with no pointer feedback.
`flex: 0 0 auto` keeps a long model name from compressing the mark away. */
.maka-composer-mode-button {
flex: 0 0 auto;
color: var(--accent);
background-color: color-mix(in srgb, currentColor 10%, transparent);
}
/* Model + thinking pair lives in left-controls (after permission), not send. */
.maka-composer-left-controls .maka-model-selection-controls {
min-width: 0;
max-width: min(420px, 52vw);
}
.maka-composer-left-controls .maka-model-switcher-trigger,
.maka-composer-left-controls .maka-new-chat-model-selector {
min-width: 100px;
max-width: min(220px, 28vw);
}
.maka-composer-model-chip-text {
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.maka-composer-model-status {
width: 6px;
height: 6px;
border-radius: var(--radius-pill);
background: var(--destructive);
flex: 0 0 auto;
}
/* The active transcript and docked card meet at one boundary. Keeping the
outer composer's default top padding here exposes an extra strip of panel
background after the transcript viewport has already ended. */
.mainColumn:not([data-home-surface="true"]) .composer {
padding-top: 0;
}
/* U3 no-model dead-end hint. Sits ABOVE the composer form (outside its box, so
it never touches the #740 constant footprint). Edged, not pill; quiet caption
text + one link-button into Settings · 模型. Theme-aware via tokens. Centered to the chat measure, matching the revision-notice layout. */
.maka-composer-no-model-hint {
font: var(--maka-text-supporting);
display: flex;
align-items: center;
gap: var(--space-2);
width: min(
var(--maka-chat-measure),
calc(100% - (2 * var(--space-6)) - (2 * var(--space-3)))
);
max-width: var(--maka-chat-measure);
margin: 0 auto var(--space-1-5);
padding: var(--space-1) var(--space-2-5);
border: var(--border-width-hairline) solid var(--warning);
border-radius: var(--radius-control);
color: var(--foreground-secondary);
}
.maka-composer-no-model-hint-action {
font: var(--maka-text-supporting);
flex-shrink: 0;
color: var(--link);
text-decoration: none;
border-radius: var(--radius-control);
}
.maka-composer-no-model-hint-action:hover {
text-decoration: underline;
}
.maka-composer-no-model-hint-action:focus-visible {
outline: var(--focus-ring-width) solid var(--focus-ring);
outline-offset: var(--focus-ring-offset);
}
/* Edit-and-resend notice. A single quiet inline pill above the composer form,
matching the composer toolbar chip family (not a heavy info card). */
.maka-composer-revision-notice {
font: var(--maka-text-supporting);
display: flex;
align-items: center;
gap: var(--space-1-5);
width: min(
var(--maka-chat-measure),
calc(100% - (2 * var(--space-6)) - (2 * var(--space-3)))
);
max-width: var(--maka-chat-measure);
margin: 0 auto var(--space-1);
padding: 0 var(--space-1-5);
box-sizing: border-box;
/* #1879: was `height: 26px`, an off-ruler literal. The floor is arithmetic
under `border-box`: a 20px supporting line box plus two hairline borders
needs 22px, so `--h-control-sm` (24px) is the smallest tier that holds it
without clipping. Loses 2px. */
height: var(--h-control-sm);
border: var(--border-width-hairline) solid var(--border);
border-radius: var(--radius-pill);
background: var(--background-elevated);
color: var(--foreground-secondary);
}
.maka-composer-revision-notice > svg {
flex: 0 0 auto;
color: var(--muted-foreground);
}
.maka-composer-revision-notice-text {
min-width: 0;
flex: 1 1 auto;
display: flex;
align-items: baseline;
gap: var(--space-1);
overflow: hidden;
white-space: nowrap;
}
.maka-composer-revision-notice-detail {
color: var(--muted-foreground);
overflow: hidden;
text-overflow: ellipsis;
}
/* #1879: the one site in this family where the old height was not merely
off-ruler but smaller than the line box it renders — measured, an 18px box
around a 20px line box, and `display: block` so the text was not centred
either. Nothing clipped (the 2px excess is half-leading, and there is no
`overflow: hidden` here), but a box shorter than its own line box has no
defensible height. `--h-control-xs` (20px) is that line box. Gains 2px. */
.maka-composer-revision-notice-cancel {
font: var(--maka-text-supporting);
appearance: none;
flex: 0 0 auto;
height: var(--h-control-xs);
display: inline-flex;
align-items: center;
padding: 0 var(--space-1-5);
border: none;
border-radius: var(--radius-pill);
background: transparent;
color: var(--muted-foreground);
white-space: nowrap;
transition: background-color var(--duration-base) var(--ease-out-strong), color var(--duration-base) var(--ease-out-strong);
}
.maka-composer-revision-notice-cancel:hover:not(:disabled) {
background: var(--state-hover-bg);
color: var(--foreground);
}
.maka-composer-revision-notice-cancel:focus-visible {
outline: var(--focus-ring-width) solid var(--focus-ring);
outline-offset: var(--focus-ring-offset);
}
.maka-composer-revision-notice-cancel:disabled {
opacity: var(--opacity-disabled);
}
/* The project picker, last in the composer footer's send-context group. It is
rendered only while no session owns the composer — the project is a
session-creation parameter. See packages/ui/src/workspace-picker.tsx. */
.maka-composer-workspace {
display: flex;
align-items: center;
min-width: 0;
}
/* Cap the open menu at the window. Astryx gives the popover
`min-width: anchor-size(width)` and no ceiling, and the item labels are not
truncated, so one long project name grows the shrink-to-fit popover past the
right edge of a narrow window — where the actions go with it and there is no
way to scroll them back. Same cap the model menus carry
(`.maka-composer-quiet-menu`), expressed in the workspace's own tokens.
The panel itself must not scroll: the catalogue scrolls inside its own
region below, and the actions after it must stay put. Astryx caps the menu
at 300px with `overflow-y: auto`, which scrolls the actions too and chains
overscroll to the page behind the popover — lift both so the only scroller
in this menu is the catalogue region. */
.maka-composer-workspace [role="menu"] {
max-width: min(320px, calc(100vw - var(--space-6)));
max-height: none;
overflow: visible;
}
/* The catalogue's own scroll region — the ONLY thing that scrolls in this
menu. `max-height` is the budget the whole popover used to share (224px of
catalogue + two action rows ≈ the old 300px ceiling); `overscroll-behavior:
contain` stops the wheel from chaining past the catalogue's ends into the
page behind the popover, which is what dragged the sticky-pinned actions
along before. `scrollbar-gutter: stable` keeps the row width constant when
the scrollbar appears. */
.maka-workspace-picker-scroll {
max-height: 224px;
overflow-y: auto;
overscroll-behavior: contain;
scrollbar-gutter: stable;
/* Ink tint, not a border — see --foreground-alpha-16 (same alpha, right family). */
scrollbar-color: var(--foreground-alpha-16) transparent;
scrollbar-width: thin;
}
/* The rule between catalogue and actions, drawn by the group's own top border.
`:not(:first-child)` covers first run — no projects yet — where the group
would open the menu with a rule dividing nothing. Nothing scrolls under the
group, so it needs no background of its own: the menu surface shows through
and Astryx keeps painting its hover and keyboard-highlight tints on the
rows. */
.maka-composer-workspace [role="menu"] > [role="group"]:not(:first-child) {
border-top: 1px solid var(--border);
}
.maka-workspace-picker-status {
font: var(--maka-text-supporting);
margin-left: auto;
color: var(--muted-foreground);
}