| /* Maka product compositions shared across desktop renderer surfaces. Astryx |
| owns generic component chrome; these selectors own only product semantics. */ |
| |
| .maka-quote-chip-remove { display: inline-flex; flex: 0 0 auto; align-items: center; justify-content: center; border: 0; color: var(--muted-foreground); background: transparent; transition: color var(--duration-quick) var(--ease-out-strong), background var(--duration-quick) var(--ease-out-strong); } |
| .maka-quote-chip-remove:hover { color: var(--foreground); background: var(--state-hover-bg); } |
| .maka-quote-chip-remove:focus-visible { color: var(--foreground); background: var(--state-hover-bg); outline: var(--focus-ring-width) solid var(--focus-ring); outline-offset: 1px; } |
| |
| .maka-page-header-title, |
| .maka-page-header-eyebrow, |
| .maka-page-header-subtitle { margin: 0; } |
| .maka-page-header-content { min-width: 0; } |
| .maka-page-header-heading-row { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; } |
| |
| |
| .maka-stat-tile { display: flex; min-width: 0; flex-direction: column; align-items: flex-start; gap: 4px; padding: 12px; } |
| /* Visual System 2.0 (T4): flat. DESIGN.md §5 says default surfaces are flat and |
| depth comes from the ladder, then a line, then shadow only for something that |
| genuinely floats — a stat tile sits on the plate. It already states its edge |
| with a border, so the resting shadow was also a second separator on the same |
| edge (§4's One Means Rule). Dropping it retires --card-shadow's last consumer |
| rather than promoting it to --elevation-raised, which would have made a |
| stationary tile float harder than it did before. */ |
| .maka-stat-tile-outline { border: 1px solid var(--card-border-color, var(--border)); border-radius: var(--radius-surface); background: var(--card-bg, var(--background)); } |
| .maka-stat-tile-filled { border-radius: var(--radius-control); background: var(--foreground-5); } |
| .maka-stat-tile-border-info { border-color: oklch(from var(--info) l c h / 0.24); } |
| .maka-stat-tile-border-success { border-color: oklch(from var(--success) l c h / 0.24); } |
| .maka-stat-tile-border-warning { border-color: oklch(from var(--warning) l c h / 0.28); } |
| .maka-stat-tile-border-destructive { border-color: oklch(from var(--destructive) l c h / 0.3); } |
| .maka-stat-tile-empty { opacity: var(--opacity-disabled); } |
| .maka-stat-tile-value-outline { font: var(--maka-text-heading-1); } |
| .maka-stat-tile-value-filled { font: var(--maka-text-heading-4); } |
| /* After the two role rules, not before them. The `font:` shorthand resets |
| `font-variant-numeric` along with the four axes the role names, and both |
| modifiers land on this same element — so declared first, the tabular figures |
| these tiles exist to align were being reset away by the role. Ordering is |
| the fix rather than repeating the declaration on each modifier: it is one |
| authority, and it is the general rule for any sub-property the roles do not |
| carry. */ |
| .maka-stat-tile-value { display: block; min-width: 0; max-width: 100%; overflow-wrap: anywhere; color: var(--foreground); font-variant-numeric: tabular-nums; white-space: normal; } |
| .maka-stat-tile-value-info { color: var(--info-text); } |
| .maka-stat-tile-value-success { color: var(--success-text); } |
| .maka-stat-tile-value-warning { color: var(--warning-text); } |
| .maka-stat-tile-value-destructive { color: var(--destructive-text); } |
| .maka-stat-tile-label { |
| font: var(--maka-text-supporting); |
| color: var(--foreground-secondary); letter-spacing: 0.025em; } |
| .maka-stat-tile-detail { |
| font: var(--maka-text-supporting); |
| color: var(--muted-foreground); } |
| |
| .maka-quote-chip { display: inline-flex; gap: 4px; padding-left: 8px; background: var(--foreground-alpha-6); box-shadow: inset 0 0 0 1px var(--foreground-alpha-12); } |
| .maka-quote-chip-expanded { width: 100%; max-width: 100%; align-items: flex-start; padding-block: 4px; border-radius: var(--radius-surface); } |
| /* #1879: measured 24px natural — a 20px line box plus 2 x 2px padding — and |
| `--h-control-sm` IS 24, so the pin is pixel-neutral today and load-bearing |
| the next time a leading moves. This is the collapsed state only; the |
| expanded twin above wraps to many lines and must keep growing. The chip's |
| type lives on `.maka-quote-chip-text`, which is why the derived scan needed |
| two arms rather than three to see it at all. */ |
| .maka-quote-chip-collapsed { height: var(--h-control-sm); max-width: 240px; align-items: center; padding-block: 2px; border-radius: var(--radius-pill); } |
| .maka-composer-running-actions { display: inline-flex; align-items: center; gap: var(--space-1); } |
| .maka-quote-chip-removable { padding-right: 2px; } |
| .maka-quote-chip-readonly { padding-right: 8px; } |
| .maka-quote-chip-icon { width: var(--icon-meta); height: var(--icon-meta); flex: 0 0 auto; color: var(--muted-foreground); } |
| .maka-quote-chip-icon-expanded { margin-top: 2px; } |
| .maka-quote-chip-text { |
| font: var(--maka-text-supporting); |
| min-width: 0; |
| min-height: 0; |
| flex: 1; |
| height: auto; |
| border: 0; |
| padding: 0; |
| color: var(--foreground-secondary); |
| background: transparent; |
| text-align: left; |
| box-shadow: none; |
| } |
| .maka-quote-chip-text-body { |
| display: block; |
| min-width: 0; |
| max-width: 100%; |
| } |
| .maka-quote-chip-text-expanded { max-height: 128px; overflow-y: auto; overflow-wrap: break-word; white-space: pre-wrap; } |
| .maka-quote-chip-text-clipped { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } |
| .maka-quote-chip-label { color: var(--muted-foreground); } |
| .maka-quote-chip-remove { |
| width: 16px; |
| height: 16px; |
| min-width: 16px; |
| min-height: 16px; |
| border-radius: 50%; |
| padding: 0; |
| } |
| .maka-quote-chip-remove > svg, |
| .maka-quote-chip-remove svg { width: var(--icon-meta); height: var(--icon-meta); } |
| |
| .maka-task-ledger-empty { |
| margin: 0; |
| } |
| |
| /* The meta row holds two different kinds of thing, so it gets two different |
| rules. The time is content — a fact about the message — and stays put; gating |
| it on hover is what hid it from touch and from assistive tech. The actions are |
| chrome and only surface on hover or focus. Astryx already splits these into a |
| `timestamp` and a `footer` slot; the gate belongs on the slot, not on the row |
| that contains both. |
| |
| The `· ` between the two slots is Astryx's own separator, rendered whenever |
| the timestamp has something to be separated FROM. It is dropped rather than |
| gated: the two slots already read as separate at rest, since one is text and |
| the other a row of controls that fades in beside it, so the bullet adds a mark |
| without adding a distinction. The slots carry no class of their own, so it is |
| addressed positionally — the timestamp is the first child span and the |
| separator the one right after it (the footer's own children are buttons). |
| |
| A transparent action still takes clicks, here and on the assistant footer. |
| `pointer-events: none` looks like the fix and is not obviously safe: it makes |
| the pointer fall through to the ancestor whose `:hover` is what restores the |
| button, so being clickable again depends on the browser redoing hit-testing |
| on a later mouse event. Continuous movement gets there; a jump that lands and |
| stops was not something this surface could be made to reproduce. Left as-is |
| rather than traded for a failure mode that could not be demonstrated. */ |
| .maka-message-meta > span + span { |
| display: none; |
| } |
| .maka-message-meta .maka-turn-footer-action { |
| opacity: 0; |
| transition: opacity var(--duration-quick) var(--ease-out-strong); |
| } |
| .maka-user-message:hover .maka-message-meta .maka-turn-footer-action, |
| .maka-user-message:focus-within .maka-message-meta .maka-turn-footer-action { |
| opacity: 1; |
| } |
| .maka-user-quotes { display: flex; max-width: 100%; flex-wrap: wrap; align-items: flex-start; gap: 4px; } |
| .maka-assistant-answer-content { display: flex; width: 100%; min-width: 0; flex-direction: column; gap: 8px; } |
| .maka-subagent-session-label, |
| .maka-subagent-session-end { |
| display: flex; |
| align-items: center; |
| gap: var(--space-2); |
| } |
| .maka-subagent-session-label { width: 100%; min-width: 0; } |
| .maka-subagent-session-summary { min-width: 0; flex: 1 1 auto; } |
| .maka-subagent-session-end { color: var(--muted-foreground); } |
| .maka-live-turn-footer-placeholder { height: 32px; margin-top: 2px; } |
| .maka-turn-processing, |
| .maka-turn-status { |
| font: var(--maka-text-body); |
| display: flex; align-items: center; gap: 8px; padding-block: 2px; color: var(--muted-foreground); } |
| /* The live status is the one thing in the turn that is about to happen rather |
| than something that already did, so it gets air the blocks above it do not |
| (they sit on the column's own 8px). Hugging the last tool card read as part |
| of that card. */ |
| .maka-turn-processing { margin-top: 8px; } |
| .maka-turn-indicator-text { display: inline-flex; min-width: 0; align-items: center; gap: 6px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } |
| /* Duration must match `WORKING_PHRASE_FADE_MS` in chat-turn.tsx: the swap is a |
| fade out, then a text change, then a fade in, and the JS timer is what waits |
| out this transition before rewriting the word. */ |
| .maka-turn-working-phrase { font-weight: var(--font-weight-medium); transition: opacity var(--duration-large) var(--ease-out-strong); } |
| .maka-turn-working-phrase[data-fading="true"] { opacity: 0; } |
| .maka-turn-status-separator { color: var(--foreground-alpha-16); } |
| /* Tabular figures so a ticking clock changes glyphs without changing width. */ |
| .maka-turn-elapsed { font-variant-numeric: tabular-nums; } |
| /* #1879: an Astryx `Badge variant="yellow"` now — the warning tone it used to |
| draw by hand (hairline + 5% wash) is a variant, and the box comes with it. |
| Product CSS keeps only what is layout: it is a block-level note under the |
| bubble, so it needs its own line and the gap above it. */ |
| .maka-turn-truncation-badge { display: flex; width: fit-content; margin-top: 6px; cursor: help; } |
| .maka-deep-thinking { min-width: 0; } |
| /* The reasoning body inside the Astryx ChatReasoning disclosure. The official |
| atoms own no white-space (the shell assumes children are pre-rendered), so |
| the inherited `white-space: normal` collapses every newline in thinking |
| text. Restore the pre-wrap reading contract the pre-Astryx disclosure had |
| (dropped in the #1748 migration). `word-break` keeps long tokens from |
| overflowing the box, as the old body did. */ |
| .maka-chat-reasoning-content { white-space: pre-wrap; word-break: break-word; } |
| |
| @keyframes maka-spin { to { transform: rotate(360deg); } } |
| .maka-spin { animation: maka-spin 1s linear infinite; } |
| |
| /* --------------------------------------------------------------------------- |
| Transcript markdown rhythm — the single authority for compact prose spacing. |
| |
| Astryx's `density` only reaches the blocks Markdown renders itself. Lists are |
| delegated to the List control, and Markdown hands it a hardcoded |
| `density="compact"` in BOTH modes — so a markdown list is spaced as a |
| clickable row (4px block padding, the RFC #839 control value), not as prose. |
| The result under `density="compact"` was a broken order: list items sat 10px |
| apart while paragraphs sat 4px apart, so same-level items read as further |
| apart than different paragraphs. |
| |
| This table restores one rule — visual distance rises with semantic distance — |
| by owning every compact prose gap in one place: |
| |
| 4px list items (same level) |
| 8px blocks (paragraph, list, quote, table, code) |
| 16px section (h3-h6, and either side of an `hr`) |
| 24px chapter (h1, h2) |
| |
| Three deliberate choices: |
| |
| - Only `[data-density="compact"]`. The document mode is not broken (its |
| lists sit 10px apart against 12px paragraphs, which is already in order), |
| and the Daily Review renders through it. Fixing only the broken half keeps |
| that surface out of the blast radius. |
| - Scoped to Astryx's own `data-density`, not to a `.maka-turn` ancestor. |
| `themeProps()` reflects every visual prop as a data attribute for exactly |
| this ("consumers target stable data-attribute selectors"), so the rhythm |
| follows the `density` prop instead of where the markdown happens to sit. |
| Storybook then reproduces the transcript by passing the prop, which the |
| old ancestor-scoped rules could not. |
| - Top level only. `>` keeps every gap on the document's own children, so |
| blocks nested inside a list item or a blockquote keep Astryx's own compact |
| 4px instead of the 8px block gap. That tier difference is the point, not |
| an oversight: a list item should read as one unit, so two paragraphs |
| inside it belong closer together than two paragraphs in the transcript. |
| The ladder extends downward (4px nested < 8px block) rather than |
| inverting, which is the invariant that matters. |
| |
| A gap is a relation BETWEEN two blocks, so every gap rule is an adjacent |
| sibling rule. Two consequences, both load-bearing: |
| |
| - The first block matches no gap rule at all, so it needs no reset. The |
| reset form (`> *` for the gap, `> :first-child` to take it back) looks |
| equivalent and is not: `:first-child` scores (0,4,0) against the heading |
| rules' (0,5,0), so a turn that OPENS with a heading — which is most of |
| them — kept the 24px chapter gap above its first line and pushed itself |
| off the top of the bubble. Expressing the relation directly is what makes |
| that unrepresentable rather than merely fixed. |
| - Gaps are margin-top only, on top of a blanket `margin-block: 0` that |
| clears Astryx's own margins. Nothing collapses, so the distance between |
| two blocks is the value declared here. */ |
| [data-maka-contract="markdown"] .astryx-markdown[data-density="compact"] { |
| --md-gap-list: var(--space-1); |
| --md-gap-block: var(--space-2); |
| --md-gap-section: var(--space-4); |
| --md-gap-chapter: var(--space-6); |
| } |
| [data-maka-contract="markdown"] .astryx-markdown[data-density="compact"] > * { |
| margin-block: 0; |
| } |
| /* `:not(dialog)` because a gap is a relation between two blocks in the document |
| flow, and a dialog is not one. Astryx's `Dialog` does not portal, so the |
| Mermaid fullscreen overlay renders as a direct child of the markdown document |
| while being `position: fixed; inset: 0` — an adjacent-sibling margin there |
| pushes the whole viewport-filling overlay off the top of the screen rather |
| than spacing anything (caught by the Mermaid E2E journey, 8px off). The |
| exclusion belongs on the side that RECEIVES the margin; an overlay sitting |
| between two blocks is fine as the `+` antecedent. */ |
| [data-maka-contract="markdown"] .astryx-markdown[data-density="compact"] > * + *:not(dialog) { |
| margin-block-start: var(--md-gap-block); |
| } |
| [data-maka-contract="markdown"] .astryx-markdown[data-density="compact"] > * + .astryx-markdown-heading:is([data-level="1"], [data-level="2"]) { |
| margin-block-start: var(--md-gap-chapter); |
| } |
| [data-maka-contract="markdown"] .astryx-markdown[data-density="compact"] > * + .astryx-markdown-heading:not([data-level="1"], [data-level="2"]) { |
| margin-block-start: var(--md-gap-section); |
| } |
| /* An `hr` is the only break the author typed by hand. Left on the generic block |
| step it reads no wider than the paragraph boundary above it, so writing one |
| changes nothing — which is the same failure as the flattened heading scale, |
| in a different place. It sits at the section step because that is what it |
| separates. A following h1/h2 still wins on specificity ((0,5,0) beats |
| (0,3,1)) and keeps the chapter gap, so `hr` before a major heading is |
| unaffected. */ |
| [data-maka-contract="markdown"] .astryx-markdown[data-density="compact"] > * + hr, |
| [data-maka-contract="markdown"] .astryx-markdown[data-density="compact"] > hr + *:not(dialog) { |
| margin-block-start: var(--md-gap-section); |
| } |
| /* Prose list, not a control list: drop the ListItem row padding and express the |
| row rhythm as a gap, so it stays below the block gap above. */ |
| [data-maka-contract="markdown"] .astryx-markdown[data-density="compact"] .astryx-list-item { |
| padding-block: 0; |
| } |
| [data-maka-contract="markdown"] .astryx-markdown[data-density="compact"] .astryx-list { |
| gap: var(--md-gap-list); |
| } |
| /* Heading scale: size says "this is a heading", weight and colour say which |
| level. Astryx's document ladder (20/18/16/14) is a page scale and an agent |
| turn emits `##` every few lines, so the transcript keeps two size steps — |
| but it keeps TWO, not one. The previous rule flattened h2-h6 onto a single |
| size, which left h2 and h3 identical in size, weight AND colour: three |
| levels of structure rendered as three identical bold lines. |
| Cursor (1.43/1.32/1.21), Claude Code (1.14/1.07/1.0) and Codex |
| (1.71/1.43/1.21) all flatten here relative to their own document styles, and |
| opencode goes further — 17/15/13 with h4+ dropped to a muted colour. Nobody |
| flattens to zero. Two steps plus colour sits inside that range. |
| |
| RISK, not just a choice: these are the only rules here that are typography |
| rather than spacing, and Astryx's density RFC (facebook/astryx#839) draws |
| the line at "density shifts heights and spacing, not typography". Keying |
| them on `data-density` is honest only while `compact` and "transcript" name |
| the same set — true today, since the transcript is the only caller asking |
| for compact and the Daily Review renders a document at the default. A |
| second compact surface would silently inherit transcript heading sizes and |
| dimmed deep headings. Giving typography its own surface attribute would |
| decouple them, but nothing needs it yet; the assumption is held by a test |
| instead (packages/ui/src/__tests__/markdown-rhythm-dom-contract.test.tsx, |
| "keeps compact markdown a transcript-only surface"), which fails the moment |
| the sets diverge and says what the choice is. */ |
| [data-maka-contract="markdown"] .astryx-markdown[data-density="compact"] .astryx-markdown-heading:is([data-level="1"], [data-level="2"]) { |
| font: var(--maka-text-heading-3); |
| } |
| [data-maka-contract="markdown"] .astryx-markdown[data-density="compact"] .astryx-markdown-heading:not([data-level="1"], [data-level="2"]) { |
| font: var(--maka-text-heading-4); |
| } |
| /* Below h3 the size ladder is spent — h4-h6 already sit at body size, and |
| growing them back would re-create the slabs the flattening exists to avoid. |
| Colour is the one axis left that costs no vertical space, so the deepest |
| levels step down in ink instead. opencode makes the same call at the same |
| point (13px h4-h6 dropped to muted); it is why a turn can carry four levels |
| of structure inside two type sizes. */ |
| [data-maka-contract="markdown"] .astryx-markdown[data-density="compact"] .astryx-markdown-heading:not([data-level="1"], [data-level="2"], [data-level="3"]) { |
| color: var(--foreground-secondary); |
| } |
| |
| /* Markdown code renderers are custom components so Mermaid can be loaded only |
| for settled Mermaid fences. Astryx skips its own spacing wrapper when |
| `components.code` is set, so the custom block sits directly in the document |
| flow — the compact rhythm above already carries it, and only the document |
| mode needs its margins declared here. */ |
| .maka-markdown-code { min-width: 0; } |
| .maka-markdown-code-default { margin-block: var(--space-3) var(--space-4); } |
| [role="document"] > .maka-markdown-code:first-child { margin-block-start: 0; } |
| [role="document"] > .maka-markdown-code:last-child { margin-block-end: 0; } |
| .maka-mermaid-diagram { |
| display: flex; |
| max-width: 100%; |
| min-height: 0; |
| flex-direction: column; |
| overflow: hidden; |
| container-type: inline-size; |
| border: 1px solid var(--border); |
| border-radius: var(--radius-surface); |
| background: var(--background); |
| } |
| .maka-mermaid-toolbar { |
| min-height: 36px; |
| flex: 0 0 auto; |
| border-bottom: 1px solid var(--border); |
| background: var(--foreground-3); |
| } |
| .maka-mermaid-title { font: var(--maka-text-supporting); color: var(--muted-foreground); } |
| .maka-mermaid-actions { display: flex; align-items: center; gap: 2px; } |
| .maka-mermaid-zoom-actions { display: flex; align-items: center; gap: 2px; } |
| .maka-mermaid-zoom-level { |
| font: var(--maka-text-code); |
| min-width: 4.5ch; |
| color: var(--muted-foreground); |
| text-align: center; |
| font-variant-numeric: tabular-nums; |
| } |
| .maka-mermaid-viewport { |
| position: relative; |
| display: grid; |
| min-width: 0; |
| align-items: center; |
| overflow: auto; |
| padding: var(--space-3); |
| cursor: default; |
| outline: none; |
| overscroll-behavior: auto; |
| touch-action: pan-y; |
| } |
| .maka-mermaid-viewport:focus-visible { box-shadow: inset 0 0 0 2px var(--focus-ring); } |
| .maka-mermaid-viewport[data-maka-mermaid-pannable="horizontal"] { cursor: grab; overscroll-behavior-x: contain; } |
| .maka-mermaid-viewport[data-maka-mermaid-pannable="vertical"], |
| .maka-mermaid-viewport[data-maka-mermaid-pannable="both"] { |
| cursor: grab; |
| overscroll-behavior: contain; |
| touch-action: none; |
| } |
| .maka-mermaid-viewport[data-maka-mermaid-panning="true"] { cursor: grabbing; user-select: none; } |
| .maka-mermaid-canvas { min-width: 0; margin-inline: auto; } |
| .maka-mermaid-svg { display: flex; width: 100%; height: 100%; min-width: 0; justify-content: center; } |
| .maka-mermaid-svg > svg { |
| display: block; |
| width: 100%; |
| max-width: none !important; |
| height: 100%; |
| overflow: visible; |
| } |
| /* Legal square (DESIGN.md §6): the expanded diagram fills its viewport with |
| margin 0 on every side, so it is full-bleed rather than a card that lost its |
| corners. The collapsed state above keeps its radius. */ |
| .maka-mermaid-diagram-expanded { |
| width: 100%; |
| height: 100%; |
| max-width: none; |
| margin: 0 !important; |
| border: 0; |
| border-radius: 0; |
| } |
| .maka-mermaid-diagram-expanded .maka-mermaid-toolbar { |
| padding-left: max(var(--space-3), var(--maka-titlebar-area-x, 0px)); |
| padding-right: calc(var(--space-1) + var(--maka-titlebar-overlay-right-width, 0px)); |
| } |
| .maka-mermaid-diagram-expanded .maka-mermaid-actions { -webkit-app-region: no-drag; } |
| .maka-mermaid-diagram-expanded .maka-mermaid-viewport { min-height: 0; flex: 1 1 auto; } |
| .maka-mermaid-dialog { -webkit-app-region: no-drag; } |
| .maka-mermaid-source { |
| max-height: min(40%, 320px); |
| flex: 0 1 auto; |
| overflow: auto; |
| padding: var(--space-1) var(--space-3) var(--space-2); |
| border-top: 1px solid var(--border); |
| } |
| .maka-mermaid-fallback { display: grid; gap: var(--space-1-5); } |
| .maka-mermaid-fallback-actions { |
| display: flex; |
| align-items: center; |
| justify-content: space-between; |
| gap: var(--space-2); |
| } |
| .maka-mermaid-status { |
| font: var(--maka-text-supporting); |
| color: var(--muted-foreground); |
| } |
| |
| @container (max-width: 520px) { |
| .maka-mermaid-title { display: none; } |
| } |
| |
| @container (max-width: 360px) { |
| .maka-mermaid-diagram:not(.maka-mermaid-diagram-expanded) .maka-mermaid-zoom-actions { display: none; } |
| } |
| |
| .maka-tool-output-panel { display: grid; gap: 8px; margin-top: 4px; padding: 10px 12px; border: 1px solid var(--border); border-radius: var(--radius-surface); background: var(--foreground-3); } |
| .maka-tool-output-command { |
| font: var(--maka-text-code); |
| display: block; min-width: 0; color: var(--foreground); font-variant-ligatures: none; white-space: pre-wrap; word-break: break-word; } |
| /* The command reads as the surface's header, not as the first line of the |
| output: it keeps the foreground colour the body gives up, and a hairline |
| separates the two. The rule is on the row rather than the panel so a |
| command with nothing under it (a failed launch) does not end in a stray |
| line — the panel's own 8px gap supplies the space below. */ |
| .maka-tool-output-command-row { display: flex; min-width: 0; align-items: flex-start; gap: 8px; } |
| .maka-tool-output-command-row:not(:last-child) { padding-bottom: 8px; border-bottom: 1px solid var(--border); } |
| .maka-tool-output-command-row .maka-tool-output-command { flex: 1 1 auto; } |
| .maka-tool-output-command-actions { display: flex; flex: 0 0 auto; align-items: center; gap: 2px; } |
| .maka-tool-output-command-copy { flex: 0 0 auto; } |
| .maka-tool-output-command-copy[data-copy-feedback="pending"] { cursor: progress; } |
| .maka-tool-output-command-copy[data-copy-feedback="copied"] { color: var(--link); } |
| .maka-tool-output-command-copy[data-copy-feedback="failed"] { color: var(--destructive); } |
| .maka-tool-output-body { |
| font: var(--maka-text-code); |
| max-height: 256px; margin: 0; overflow-y: auto; color: var(--muted-foreground); font-variant-ligatures: none; scroll-behavior: auto; white-space: pre-wrap; word-break: break-word; } |
| .maka-tool-output-note { |
| font: var(--maka-text-body); |
| margin: 0; color: var(--muted-foreground); } |
| .maka-tool-output-wrap { min-width: 0; overflow-wrap: anywhere; } |
| .maka-tool-output-destructive { color: var(--destructive); } |
| .maka-tool-output-warning { color: var(--warning-text, var(--info-text)); } |
| .maka-tool-output-warning-border { border-color: oklch(from var(--warning) l c h / 0.32); } |
| .maka-tool-output-destructive-border { border-color: oklch(from var(--destructive) l c h / 0.28); } |
| .maka-tool-output-stack { display: flex; min-width: 0; flex-direction: column; gap: 6px; margin-top: 4px; } |
| .maka-pty-shell { gap: 0; overflow: hidden; padding: 0; } |
| .maka-pty-shell-header { display: flex; min-width: 0; align-items: center; padding: 10px 12px 4px; } |
| .maka-pty-shell-title { |
| font: var(--maka-text-label); |
| color: var(--foreground-secondary); } |
| .maka-pty-shell-body { display: grid; min-width: 0; gap: 8px; padding: 6px 12px; } |
| .maka-pty-shell-footer { |
| font: var(--maka-text-body); |
| display: flex; min-height: 32px; align-items: center; justify-content: flex-end; gap: 6px; padding: 4px 12px 10px; color: var(--muted-foreground); } |
| .maka-pty-terminal-body { overflow: auto; white-space: pre; word-break: normal; } |
| |
| .maka-web-result { display: grid; gap: 8px; } |
| .maka-web-result-header { display: grid; gap: 2px; } |
| .maka-web-result-header strong { |
| font: var(--maka-text-heading-4); |
| color: var(--foreground); } |
| .maka-web-result-header small, |
| .maka-web-result-list small { |
| font: var(--maka-text-body); |
| color: var(--muted-foreground); } |
| .maka-web-result-list { display: grid; gap: 8px; margin: 0; padding: 0; list-style: none; } |
| .maka-web-result-list li { display: grid; gap: 2px; } |
| .maka-web-result-list a { |
| font: var(--maka-text-label); |
| color: var(--link); } |
| .maka-web-result-list p { |
| font: var(--maka-text-body); |
| margin: 0; color: var(--foreground-secondary); } |
| .maka-web-result-error { gap: 6px; } |
| .maka-web-result-error-message, |
| .maka-web-result-repair { |
| font: var(--maka-text-body); |
| margin: 0; } |
| .maka-web-result-error-message { color: var(--destructive); } |
| .maka-web-result-repair { color: var(--muted-foreground); } |
| .maka-tool-call-detail { display: flex; flex-direction: column; gap: 6px; margin-top: 4px; } |
| /* A CodeBlock title (a file path, a result headline) sits at the same tier as |
| the command header beside it. Astryx hard-codes that title to the supporting |
| tier, which is 12px against the block's own 14px code — rebinding the role |
| token reaches it through inheritance, the same move chat-message.css makes |
| on the tool and reasoning rows. Only the size: `medium` on a header is |
| Astryx's intent and the surface command's foreground colour carries the same |
| weight of emphasis without it. */ |
| .maka-tool-call-detail .astryx-codeblock { |
| /* Geist Mono ligates `--`, `!==` and friends into single glyphs that sit |
| outside the cell they started in, so a `---` line looked like it had |
| escaped the block's left edge — measured, its box starts on the same x as |
| every other line. The product's own wells all disable this; Astryx's |
| CodeBlock does not, and tool output is transcript text where the literal |
| characters are the point. */ |
| font-variant-ligatures: none; |
| --text-supporting-size: var(--text-code-size); |
| /* Unitless, so it has to move with the size: left at the supporting leading |
| it would multiply the larger size into a 23px line box and give the header |
| a rhythm no other row in the panel has. */ |
| --text-supporting-leading: var(--text-code-leading); |
| } |
| .maka-tool-output-chunk { display: contents; } |
| .maka-tool-output-chunk-stderr { color: var(--destructive); } |
| .maka-tool-output-chunk-redacted { opacity: 0.65; } |
| .maka-tool-output-redacted { display: inline; margin-left: 2px; color: var(--warning-text, var(--info-text)); } |
| .maka-sandbox-blocked-banner { margin-bottom: 10px; } |
| .maka-sandbox-blocked-description { |
| font: var(--maka-text-supporting); |
| display: flex; flex-direction: column; gap: 4px; white-space: pre-wrap; word-break: break-word; } |
| .maka-sandbox-blocked-error { |
| font: var(--maka-text-supporting); |
| } |
| .maka-sandbox-blocked-copy { align-self: start; } |
| .maka-sandbox-blocked-copy[data-pending="true"] { cursor: progress; } |
| .maka-sandbox-blocked-copy[data-copy-feedback="copied"] { border-color: oklch(from var(--link) l c h / 0.35); color: var(--link); } |
| .maka-sandbox-blocked-copy[data-copy-feedback="failed"] { border-color: oklch(from var(--destructive) l c h / 0.35); color: var(--destructive); } |
| .maka-turn-status-icon { flex: 0 0 auto; } |
| |
| .maka-turn-aborted-marker, |
| .maka-turn-host-origin, |
| .maka-turn-failed-banner { |
| font: var(--maka-text-supporting); |
| display: inline-flex; |
| width: fit-content; |
| align-items: center; |
| margin-inline: 0; |
| border-radius: var(--radius-control); |
| } |
| |
| .maka-turn-aborted-marker { |
| gap: var(--space-1); |
| margin-block: var(--space-0-5) var(--space-1); |
| padding: var(--space-0-5) var(--space-1-5); |
| background: var(--foreground-5); |
| color: var(--foreground-secondary); |
| font-style: italic; |
| } |
| |
| .maka-turn-aborted-marker em { font-style: italic; } |
| |
| .maka-turn-host-origin { |
| align-self: flex-end; |
| gap: var(--space-1); |
| margin-bottom: var(--space-1); |
| padding: var(--space-0-5) var(--space-1-5); |
| background: var(--foreground-5); |
| color: var(--muted-foreground); |
| } |
| |
| .maka-turn-failed-banner { |
| flex-wrap: wrap; |
| gap: var(--space-1-5); |
| margin-block: var(--space-0-5) var(--space-1-5); |
| padding: var(--space-1) var(--space-2); |
| border: 1px solid oklch(from var(--destructive) l c h / 0.28); |
| background: oklch(from var(--destructive) l c h / 0.1); |
| color: var(--destructive); |
| } |
| |
| .maka-turn-failed-icon { display: inline-flex; align-items: center; } |
| .maka-turn-failed-recovery { color: var(--text-muted); } |
| .maka-turn-failed-recovery::before { |
| margin-right: var(--space-1-5); |
| color: var(--foreground-alpha-16); |
| content: "·"; |
| } |
| |
| .maka-turn-lineage-row, |
| .maka-turn-footer { |
| display: flex; |
| width: 100%; |
| max-width: var(--maka-chat-measure, 680px); |
| flex-wrap: wrap; |
| align-items: center; |
| justify-content: flex-start; |
| gap: var(--space-0-5); |
| margin-left: 0; |
| margin-right: auto; |
| } |
| |
| .maka-turn-lineage-row { |
| margin-top: var(--space-0-5); |
| margin-bottom: var(--space-1); |
| opacity: 0.82; |
| } |
| |
| .maka-turn-lineage-row-reverse { margin-top: var(--space-1); } |
| |
| .maka-turn-lineage-badge { |
| border: 0; |
| border-radius: var(--radius-pill); |
| background: oklch(from var(--foreground) l c h / 0.05); |
| color: var(--muted-foreground); |
| } |
| |
| .maka-turn-lineage-badge[data-direction="forward"] { |
| background: oklch(from var(--info) l c h / 0.06); |
| color: oklch(from var(--info-text) calc(l - 0.06) c h); |
| } |
| |
| .maka-turn-lineage-badge[data-direction="reverse"] { |
| background: oklch(from var(--brand-deep) l c h / 0.06); |
| color: oklch(from var(--brand-deep) calc(l - 0.04) c h); |
| } |
| |
| .maka-turn-footer { |
| margin-top: var(--space-0-5); |
| padding: 0; |
| opacity: 0; |
| transition: opacity var(--duration-quick) var(--ease-out-strong); |
| } |
| |
| .maka-assistant-answer:hover .maka-turn-footer, |
| .maka-turn-footer:focus-within { opacity: 1; } |
| |
| .maka-turn-footer-action { |
| border: 0; |
| border-radius: var(--radius-surface); |
| color: var(--muted-foreground); |
| } |
| |
| .maka-turn-footer-action[data-pending="true"] { |
| cursor: progress; |
| opacity: 0.78; |
| } |
| |
| .maka-turn-footer-action[aria-disabled="true"][data-pending="true"] { opacity: 0.78; } |
| .maka-turn-footer-action[data-copy-feedback="copied"] { color: var(--link); } |
| .maka-turn-footer-action[data-copy-feedback="failed"] { color: var(--destructive); } |
| |
| .maka-overlay-preview { |
| font: var(--maka-text-supporting); |
| max-height: 180px; |
| margin: var(--space-1) 0 0; |
| overflow: auto; |
| font-variant-ligatures: none; |
| white-space: pre-wrap; |
| word-break: break-word; |
| } |
| .maka-overlay-close { justify-self: end; } |
| .maka-tool-diff, |
| .maka-tool-terminal { |
| display: grid; |
| gap: 0; |
| padding: 0; |
| border-radius: var(--radius-surface); |
| background: var(--background); |
| box-shadow: var(--ring-soft); |
| white-space: normal; |
| } |
| .maka-tool-diff-paths, |
| .maka-tool-terminal-head { |
| font: var(--maka-text-supporting); |
| display: flex; |
| flex-wrap: wrap; |
| gap: var(--space-1-5); |
| padding: var(--space-1) var(--space-2); |
| border-bottom: 1px solid var(--border); |
| background: var(--foreground-2); |
| } |
| .maka-tool-terminal-head { align-items: center; font-variant-ligatures: none; } |
| .maka-tool-diff-paths code { color: var(--foreground-secondary); background: transparent; } |
| .maka-tool-diff-body { |
| font: var(--maka-text-supporting); |
| max-height: 320px; |
| margin: 0; |
| padding-block: var(--space-1); |
| overflow: auto; |
| font-variant-ligatures: none; |
| white-space: pre; |
| word-break: normal; |
| } |
| /* Only the chat consumer moved into `.maka-tool-output-panel`, where the diff |
| sits beside a command on the code tier and a 12px body next to 14px reads as |
| a different kind of text. `apps/desktop`'s artifact pane still draws this as |
| a standalone card at the supporting tier its container asks for, so the tier |
| belongs to the panel, not to the shared class. */ |
| .maka-tool-output-panel .maka-tool-diff-body { |
| font: var(--maka-text-code); |
| /* The `font` shorthand resets `font-variant-ligatures`, and this rule |
| outranks the `none` the shared class declares — so the panel's diff was |
| the one code surface in the app rendering `===` as `⩶` and `=>` as `⇒`. |
| Every other `font: var(--maka-text-code)` rule restates it for the same |
| reason; this one had not. */ |
| padding-block: 0; |
| font-variant-ligatures: none; |
| } |
| .maka-tool-diff-line { display: block; padding-inline: var(--space-2); white-space: pre; } |
| .maka-tool-diff-gutter { |
| display: inline-block; |
| box-sizing: content-box; |
| text-align: right; |
| padding-right: var(--space-2); |
| margin-right: var(--space-1); |
| border-right: 1px solid var(--border); |
| color: var(--muted-foreground); |
| user-select: none; |
| } |
| /* The marker column: two character cells, the sign and a blank, so an |
| addition's code starts in the same place as the context line above it and |
| the sign is not crowding the first token. `ch` rather than a px gap because |
| this sits in a monospace body — one more cell keeps the code on the same |
| grid the file itself is written on, where 4px would leave it between two. |
| The column keeps the line's tint colour — the sign is what the colour is |
| naming — while `.maka-tool-diff-code` hands the code back to syntax |
| colouring. Every row gets the cell, including the markerless ones: a |
| `\ No newline at end of file` that hugged column 0 while the code beside it |
| did not was the same misalignment on a different row. */ |
| .maka-tool-diff-marker { |
| display: inline-block; |
| width: 2ch; |
| } |
| /* Neutral base under the `astryx-token-*` spans. Without it an added line's |
| uncoloured text would stay green and a deleted line's red, which is the |
| flat single-tint reading the tokens exist to break up; the row's background |
| tint and its marker carry add/del on their own. |
| |
| This is also what brings context lines up from `--foreground-secondary` to |
| full foreground, which is deliberate rather than collateral: once a context |
| line's keywords and strings are syntax-coloured, dimming only the text |
| between them reads as damage, not as de-emphasis. The row's flat background |
| is what says "unchanged" now. */ |
| .maka-tool-diff-code { color: var(--foreground); } |
| .maka-tool-diff-line[data-line="meta"] .maka-tool-diff-code { color: inherit; } |
| .maka-tool-diff-line[data-line="add"] { background: oklch(from var(--success) l c h / 0.1); color: var(--success-text); } |
| .maka-tool-diff-line[data-line="del"] { background: oklch(from var(--destructive) l c h / 0.1); color: var(--destructive); } |
| .maka-tool-diff-line[data-line="hunk"] { |
| font: var(--maka-text-heading-5); |
| background: oklch(from var(--link) l c h / 0.08); color: var(--foreground-secondary); } |
| .maka-tool-diff-line[data-line="meta"] { color: var(--muted-foreground); } |
| .maka-tool-diff-line[data-line="ctx"] { color: var(--foreground-secondary); } |
| .maka-tool-terminal-cwd { color: var(--muted-foreground); background: transparent; } |
| .maka-tool-terminal-cmd { |
| font: var(--maka-text-heading-5); |
| min-width: 0; flex: 1 1 auto; overflow: hidden; background: transparent; color: var(--foreground); text-overflow: ellipsis; white-space: nowrap; } |
| /* Pinned like every other pill in the scan, even though the whole |
| `.maka-tool-terminal-*` family is currently unreachable: |
| `previewVariants({part: 'terminal-*'})` has no call site — `TerminalPreview` |
| renders `maka-tool-output-stack` / `ShellOutputBody` / `ToolCodeBlock` |
| instead — and `check-dead-css` cannot see that because the literals still |
| exist in `previewVariants`. The alternative is an exemption whose reason is |
| "nothing renders this", which is a fact about call sites recorded in a |
| stylesheet and would outlive the day someone wires the family back up. |
| Deleting the family is its own change. */ |
| .maka-tool-terminal-exit { |
| font: var(--maka-text-heading-5); |
| height: var(--h-control-sm); display: inline-flex; align-items: center; white-space: nowrap; padding: 1px var(--space-1-5); border-radius: var(--radius-pill); background: var(--foreground-5); color: var(--foreground-secondary); letter-spacing: var(--tracking-wide); } |
| .maka-tool-terminal-exit[data-ok="true"] { background: oklch(from var(--success) l c h / 0.14); color: var(--success); } |
| .maka-tool-terminal-exit[data-ok="false"] { background: oklch(from var(--destructive) l c h / 0.14); color: var(--destructive); } |
| .maka-tool-terminal-empty { |
| font: var(--maka-text-supporting); |
| margin: 0; padding: var(--space-2); color: var(--muted-foreground); font-style: italic; } |
| .maka-tool-terminal-stream { |
| font: var(--maka-text-supporting); |
| max-height: 180px; margin: 0; padding: var(--space-1-5) var(--space-2); overflow: auto; font-variant-ligatures: none; white-space: pre-wrap; word-break: break-word; } |
| .maka-tool-terminal-stream[data-stream="stdout"] { color: var(--foreground); } |
| .maka-tool-terminal-stream[data-stream="stderr"] { border-top: 1px solid var(--border); background: oklch(from var(--destructive) l c h / 0.04); color: var(--destructive); } |
| .maka-tool-terminal-truncated-note { |
| font: var(--maka-text-supporting); |
| display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); padding: var(--space-1-5) var(--space-2); border-top: 1px solid var(--border); background: oklch(from var(--warning) l c h / 0.06); color: var(--foreground-secondary); } |
| .maka-tool-terminal-truncated-note > span { min-width: 0; } |
| .maka-tool-terminal-copy, |
| .maka-agent-preview-copy { flex: 0 0 auto; } |
| .maka-tool-terminal-copy[data-pending="true"], |
| .maka-agent-preview-copy[data-pending="true"] { cursor: progress; } |
| .maka-tool-terminal-copy[data-copy-error="true"], |
| .maka-agent-preview-copy[data-copy-error="true"] { border-color: oklch(from var(--destructive) l c h / 0.35); color: var(--destructive); } |
| |
| .maka-agent-preview { |
| font: var(--maka-text-supporting); |
| display: grid; gap: var(--space-2-5); padding: var(--space-2-5) var(--space-3); border: 1px solid var(--foreground-10); border-radius: var(--radius-surface); background: var(--foreground-3); white-space: normal; } |
| .maka-agent-preview[data-ok="false"], |
| .maka-agent-preview[data-status="failed"], |
| .maka-agent-preview[data-status="cancelled"] { border-color: oklch(from var(--destructive) l c h / 0.22); } |
| .maka-agent-preview-head { display: grid; gap: var(--space-0-5); padding-bottom: var(--space-1-5); border-bottom: 1px solid var(--foreground-10); } |
| .maka-agent-preview-head strong { |
| font: var(--maka-text-heading-4); |
| min-width: 0; overflow: hidden; color: var(--foreground); text-overflow: ellipsis; white-space: nowrap; } |
| .maka-agent-preview-head small, |
| .maka-agent-preview-section small, |
| .maka-agent-preview-meta dt { |
| font: var(--maka-text-supporting); |
| color: var(--muted-foreground); letter-spacing: var(--tracking-wider); text-transform: uppercase; } |
| .maka-agent-preview-summary-line, |
| .maka-agent-preview-section-head { display: flex; min-width: 0; align-items: center; justify-content: space-between; gap: var(--space-2); } |
| .maka-agent-preview-summary-line small { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } |
| .maka-agent-preview-actions { display: flex; align-items: center; justify-content: flex-end; gap: var(--space-1-5); margin-top: var(--space-1); } |
| .maka-agent-preview-message { |
| font: var(--maka-text-supporting); |
| padding: var(--space-2) var(--space-2-5); border-radius: var(--radius-control); background: oklch(from var(--destructive) l c h / 0.07); color: var(--destructive); } |
| .maka-agent-preview-meta { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-2); margin: 0; } |
| .maka-agent-preview-meta > div { display: grid; min-width: 0; gap: var(--space-0-5); } |
| .maka-agent-preview-meta dd { |
| font: var(--maka-text-supporting); |
| min-width: 0; margin: 0; overflow: hidden; color: var(--foreground-secondary); text-overflow: ellipsis; white-space: nowrap; } |
| .maka-agent-preview-section { display: grid; gap: var(--space-1-5); } |
| .maka-agent-preview-section > strong, |
| .maka-agent-preview-section-head > strong { |
| font: var(--maka-text-heading-5); |
| min-width: 0; color: var(--foreground); } |
| .maka-agent-preview-section ul { display: grid; gap: var(--space-1-5); margin: 0; padding: 0; list-style: none; } |
| .maka-agent-preview-section li { display: grid; min-width: 0; gap: var(--space-0-5); padding-block: var(--space-1-5); border-top: 1px solid var(--foreground-5); } |
| .maka-agent-preview-section li:first-child { padding-top: 0; border-top: 0; } |
| .maka-agent-preview-section code { |
| font: var(--maka-text-supporting); |
| min-width: 0; overflow: hidden; background: transparent; color: var(--foreground); text-overflow: ellipsis; white-space: nowrap; } |
| .maka-agent-preview-section p, |
| .maka-agent-preview-section span { |
| font: var(--maka-text-supporting); |
| margin: 0; color: var(--foreground-secondary); white-space: pre-wrap; word-break: break-word; } |
| .maka-agent-preview-copy[data-copied="true"] { border-color: oklch(from var(--link) l c h / 0.35); color: var(--link); } |
| |
| .maka-web-search-preview { display: grid; gap: var(--space-2); padding: var(--space-2-5) var(--space-3); border: 1px solid var(--foreground-10); border-radius: var(--radius-surface); background: var(--foreground-3); } |
| .maka-web-search-preview > header { display: flex; flex-direction: column; gap: var(--space-0-5); padding-bottom: var(--space-1-5); border-bottom: 1px solid var(--foreground-10); } |
| .maka-web-search-preview > header strong { |
| font: var(--maka-text-heading-4); |
| color: var(--foreground); } |
| .maka-web-search-preview > header small, |
| .maka-web-search-preview li small { |
| font: var(--maka-text-supporting); |
| color: var(--muted-foreground); letter-spacing: var(--tracking-wider); text-transform: uppercase; } |
| .maka-web-search-preview ul { display: grid; gap: var(--space-2); margin: 0; padding: 0; list-style: none; } |
| .maka-web-search-preview li { display: grid; gap: var(--space-0-5); padding-block: var(--space-2); border-top: 1px solid var(--foreground-5); } |
| .maka-web-search-preview li:first-child { padding-top: 0; border-top: 0; } |
| .maka-web-search-preview a { |
| font: var(--maka-text-heading-4); |
| color: var(--foreground); text-decoration: none; } |
| .maka-web-search-preview a:hover, |
| .maka-web-search-preview a:focus-visible { text-decoration: underline; } |
| .maka-web-search-preview li p { |
| font: var(--maka-text-supporting); |
| margin: 0; color: var(--foreground-secondary); white-space: pre-wrap; word-break: break-word; } |
| .maka-web-search-error { border-color: color-mix(in oklab, var(--destructive-text) 32%, var(--foreground-10)); background: color-mix(in oklab, var(--destructive-text) 8%, var(--foreground-3)); } |
| .maka-web-search-error-message, |
| .maka-web-search-error-repair { |
| font: var(--maka-text-supporting); |
| margin: 0; white-space: pre-wrap; word-break: break-word; } |
| .maka-web-search-error-message { color: var(--destructive-text); } |
| .maka-web-search-error-repair { color: var(--foreground-secondary); } |
| |
| .maka-load-tool-preview { |
| font: var(--maka-text-supporting); |
| display: grid; gap: var(--space-0-5); margin: var(--space-1) 0 0; padding: var(--space-1) var(--space-2); border-radius: var(--radius-control); background: var(--background); box-shadow: var(--ring-soft); } |
| .maka-load-tool-preview p { margin: 0; } |
| .maka-load-tool-title { |
| font: var(--maka-text-heading-5); |
| } |
| .maka-load-tool-count, |
| .maka-load-tool-footer { color: var(--muted-foreground); } |
| .maka-load-tool-tools { |
| font: var(--maka-text-supporting); |
| word-break: break-word; } |
| .maka-load-tool-footer { |
| font: var(--maka-text-supporting); |
| } |
| |
| /* Turn-footer action rings go inset (T5 geometry probe): the Astryx chat |
| layout's scrollport clips an outward ring on the first visible row's |
| actions. Same idiom as the titlebar strip and workbar launcher. The |
| layout's own scroll-to-bottom control has the same clip inside vendor |
| DOM — upstream item, not fixable from product CSS. */ |
| .maka-turn-footer-action:focus-visible { |
| outline: none; |
| box-shadow: inset 0 0 0 var(--focus-ring-width) var(--focus-ring); |
| } |