Files
openchamber/packages/ui/src/index.css
T
RyderAsking b9447f0ffb fix(ui): preserve narrow desktop status-row behavior
Keep the active todo text hidden below 38rem, as before, while hiding only the changed-files secondary label below 30rem. This fixes the mobile collision without reintroducing the documented narrow desktop overlap.
2026-08-03 09:55:55 +00:00

1826 lines
48 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.
@import "tailwindcss";
@import "tw-animate-css";
@import "./styles/design-system.css";
@import "./styles/typography.css";
@import "./styles/mobile.css";
/* Load KaTeX styles eagerly with the main bundle. Importing them inside the
lazy MarkdownRendererImpl chunk meant a stylesheet was injected late on the
first markdown render of a session; that late injection triggered a style
recalc during which the layered `.chat-message-column` width clamp briefly
lost, flashing message text to full width before it snapped back. */
@import "katex/dist/katex.min.css";
@source "./**/*.{ts,tsx,css}";
/* KaTeX theme overrides for light/dark mode */
.katex {
color: var(--foreground);
}
.katex .mord,
.katex .mopen,
.katex .mclose,
.katex .mbin,
.katex .mrel,
.katex .mpunct,
.katex .mord,
.katex .mop,
.katex .minner {
color: inherit;
}
.katex-error {
color: var(--destructive);
}
@custom-variant dark (&:is(.dark *));
/* Buttons should never look selectable. */
button,
[role="button"] {
user-select: none !important;
-webkit-user-select: none !important;
}
:root.oc-theme-switching *,
:root.oc-theme-switching *::before,
:root.oc-theme-switching *::after {
transition: none !important;
animation: none !important;
}
[data-settings-search-highlight="true"] {
border-radius: 0.25rem;
background: color-mix(in srgb, var(--primary-base) 7%, transparent);
transition: background-color 180ms ease;
}
/* ── macOS vibrancy ───────────────────────────────────────────────────────
The window is created transparent with a native 'sidebar' NSVisualEffectView
behind it. We keep the whole app opaque (bg-background covers the window)
EXCEPT the left sidebar, which is the only translucent surface that lets the
native vibrancy show through. `data-oc-vibrancy` = vibrancy active;
`data-oc-vibrancy-ready` = native layer has settled (set from the main
process after show/restore) — until then the sidebar stays solid to avoid a
flash of raw transparency. */
html[data-oc-vibrancy] body,
html[data-oc-vibrancy] #root {
background: transparent !important;
background-color: transparent !important;
}
html[data-oc-vibrancy] .main-content-safe-area {
background: transparent !important;
background-color: transparent !important;
}
/* Left sidebar: solid until the native layer is ready, then a translucent
overlay so the vibrancy frosts through. */
html[data-oc-vibrancy] .oc-vibrancy-surface {
background: var(--sidebar) !important;
}
html[data-oc-vibrancy][data-oc-vibrancy-ready] .oc-vibrancy-surface {
background: var(--sidebar-vibrancy-overlay) !important;
}
/* Inner bg-sidebar elements inside the vibrant surface must not re-paint an
opaque fill, or they'd cover the frosted effect. */
html[data-oc-vibrancy] .oc-vibrancy-surface .bg-sidebar {
background: transparent !important;
background-color: transparent !important;
}
/* Project-actions pill over the open sidebar: drop its opaque surface so it
frosts to the exact same level as the sidebar (border keeps its outline). */
html[data-oc-vibrancy] .oc-vibrancy-pill {
background: transparent !important;
background-color: transparent !important;
}
/* Accessibility: drop translucency when the OS asks for reduced transparency. */
@media (prefers-reduced-transparency: reduce) {
html[data-oc-vibrancy] body,
html[data-oc-vibrancy] #root,
html[data-oc-vibrancy] .main-content-safe-area {
background: var(--surface-background) !important;
}
html[data-oc-vibrancy] .oc-vibrancy-surface,
html[data-oc-vibrancy][data-oc-vibrancy-ready] .oc-vibrancy-surface {
background: var(--sidebar) !important;
}
}
/* Ensure interactive controls consistently show pointer cursor */
:where(
button,
[role="button"],
a[href]
):not(:disabled) {
cursor: pointer;
}
:where(button, [role="button"]):disabled {
cursor: not-allowed;
}
/* Fractional line heights (1.625 × font-size) make streamed content grow by
sub-pixel amounts while scroll positions quantize to the device-pixel grid.
The residue accumulates and bottom-anchored rows (status indicator) creep
and snap by 1px per few lines during streaming. Rounding the line height to
whole pixels keeps content growth on the pixel grid. */
.message-content-text.leading-relaxed,
.message-content-text .leading-relaxed {
line-height: round(1.625em, 1px);
}
:root.light .message-content-text::selection,
:root.light .message-content-text ::selection {
background: color-mix(in srgb, var(--interactive-border-focus) 18%, transparent);
color: var(--surface-foreground);
}
.oc-cm-selected-line {
background: color-mix(in srgb, var(--primary-base) 22%, transparent);
}
.pierre-diff-wrapper {
--diffs-bg-selection-override: color-mix(in srgb, var(--primary-base) 22%, transparent);
--diffs-bg-selection-background-override: color-mix(in srgb, var(--primary-base) 14%, transparent);
--diffs-bg-selection-number-override: color-mix(in srgb, var(--primary-base) 28%, transparent);
--diffs-bg-selection-number-background-override: color-mix(in srgb, var(--primary-base) 18%, transparent);
--diffs-selection-color-override: var(--primary-base);
}
/* Codemirror syntax fallback for classHighlighter tokens */
.cm-editor .tok-comment,
.cm-editor .tok-docComment,
.cm-editor .tok-meta,
.cm-editor .tok-documentMeta {
color: var(--syntax-comment);
}
.cm-editor .tok-keyword,
.cm-editor .tok-controlKeyword,
.cm-editor .tok-definitionKeyword,
.cm-editor .tok-modifier,
.cm-editor .tok-moduleKeyword {
color: var(--syntax-keyword);
}
.cm-editor .tok-operator,
.cm-editor .tok-operatorKeyword,
.cm-editor .tok-derefOperator,
.cm-editor .tok-updateOperator,
.cm-editor .tok-definitionOperator,
.cm-editor .tok-typeOperator,
.cm-editor .tok-controlOperator,
.cm-editor .tok-logicOperator,
.cm-editor .tok-bitwiseOperator,
.cm-editor .tok-arithmeticOperator,
.cm-editor .tok-compareOperator {
color: var(--syntax-operator);
}
.cm-editor .tok-string,
.cm-editor .tok-special.tok-string,
.cm-editor .tok-escape,
.cm-editor .tok-regexp,
.cm-editor .tok-attributeValue,
.cm-editor .tok-monospace {
color: var(--syntax-string);
}
.cm-editor .tok-number,
.cm-editor .tok-bool,
.cm-editor .tok-atom,
.cm-editor .tok-null,
.cm-editor .tok-self {
color: var(--syntax-number);
}
.cm-editor .tok-function.tok-variableName,
.cm-editor .tok-function.tok-propertyName,
.cm-editor .tok-standard.tok-variableName,
.cm-editor .tok-special.tok-variableName {
color: var(--syntax-function);
}
.cm-editor .tok-variableName,
.cm-editor .tok-definition.tok-variableName,
.cm-editor .tok-local.tok-variableName,
.cm-editor .tok-constant.tok-variableName,
.cm-editor .tok-propertyName,
.cm-editor .tok-attributeName {
color: var(--syntax-variable);
}
.cm-editor .tok-className,
.cm-editor .tok-typeName,
.cm-editor .tok-namespace {
color: var(--syntax-type);
}
.cm-editor .tok-tagName,
.cm-editor .tok-labelName,
.cm-editor .tok-annotation,
.cm-editor .tok-macroName {
color: var(--syntax-keyword);
}
.cm-editor .tok-link {
color: var(--syntax-function);
text-decoration: underline;
}
.cm-editor .tok-punctuation,
.cm-editor .tok-separator,
.cm-editor .tok-bracket,
.cm-editor .tok-paren,
.cm-editor .tok-brace,
.cm-editor .tok-squareBracket,
.cm-editor .tok-angleBracket {
color: color-mix(in srgb, var(--syntax-comment) 85%, var(--syntax-foreground) 15%);
}
/* Codemirror syntax fallback for class-based HighlightStyle tokens */
.cm-editor .cm-comment,
.cm-editor .cm-meta {
color: var(--syntax-comment);
}
.cm-editor .cm-keyword,
.cm-editor .cm-tag {
color: var(--syntax-keyword);
}
.cm-editor .cm-operator {
color: var(--syntax-operator);
}
.cm-editor .cm-string,
.cm-editor .cm-string-2,
.cm-editor .cm-link {
color: var(--syntax-string);
}
.cm-editor .cm-number,
.cm-editor .cm-atom {
color: var(--syntax-number);
}
.cm-editor .cm-builtin,
.cm-editor .cm-def {
color: var(--syntax-function);
}
.cm-editor .cm-variable,
.cm-editor .cm-variable-2,
.cm-editor .cm-property,
.cm-editor .cm-attribute {
color: var(--syntax-variable);
}
.cm-editor .cm-variable-3 {
color: var(--syntax-type);
}
.cm-editor .cm-punctuation {
color: color-mix(in srgb, var(--syntax-comment) 85%, var(--syntax-foreground) 15%);
}
:root.vscode-runtime [data-chat-input="true"] .cm-placeholder {
color: color-mix(in srgb, var(--vscode-input-placeholderForeground, var(--muted-foreground)) 65%, transparent);
}
/* Match chat footer background to input in WebKit to avoid dual-tone hover/focus */
div[data-chat-input-footer="true"] {
background: transparent !important;
border: none;
box-shadow: none;
-webkit-appearance: none;
}
/* Scroll shadow (HeroUI) fallback styling to ensure visible gradients without the Tailwind plugin */
[data-scroll-shadow="true"] {
--scroll-shadow-size: var(--scroll-shadow-size, 48px);
}
[data-scroll-shadow="true"][data-orientation="vertical"] {
mask-mode: alpha;
-webkit-mask-repeat: no-repeat;
mask-repeat: no-repeat;
-webkit-mask-size: 100% 100%;
mask-size: 100% 100%;
}
[data-scroll-shadow="true"][data-orientation="vertical"][data-top-bottom-scroll="true"] {
mask-image: linear-gradient(
to bottom,
transparent 0%,
transparent var(--scroll-shadow-top-clear-size, 0px),
#000 var(--scroll-shadow-top-size, var(--scroll-shadow-size)),
#000 calc(100% - var(--scroll-shadow-size)),
transparent 100%
);
-webkit-mask-image: linear-gradient(
to bottom,
transparent 0%,
transparent var(--scroll-shadow-top-clear-size, 0px),
#000 var(--scroll-shadow-top-size, var(--scroll-shadow-size)),
#000 calc(100% - var(--scroll-shadow-size)),
transparent 100%
);
}
[data-scroll-shadow="true"][data-orientation="vertical"][data-top-scroll="true"] {
mask-image: linear-gradient(
to bottom,
transparent 0%,
transparent var(--scroll-shadow-top-clear-size, 0px),
#000 var(--scroll-shadow-top-size, var(--scroll-shadow-size)),
#000 100%
);
-webkit-mask-image: linear-gradient(
to bottom,
transparent 0%,
transparent var(--scroll-shadow-top-clear-size, 0px),
#000 var(--scroll-shadow-top-size, var(--scroll-shadow-size)),
#000 100%
);
}
/* Sticky-fade overlay (desktop sidebar): the crisp duplicate identity stays
mounted and its visibility is driven synchronously by the scroller's own
top-scroll data attribute — the same signal that engages the mask — so the
overlay appears in the exact frame the mask hides the real header (no blink).
ScrollShadow sets data-top-scroll when nothing is below the viewport and
data-top-bottom-scroll when content is both above and below. */
.oc-sticky-fade-overlay {
opacity: 0;
}
.oc-sticky-fade-root:has(.oc-sidebar-scroller[data-top-scroll="true"]) .oc-sticky-fade-overlay,
.oc-sticky-fade-root:has(.oc-sidebar-scroller[data-top-bottom-scroll="true"]) .oc-sticky-fade-overlay {
opacity: 1;
}
[data-scroll-shadow="true"][data-orientation="vertical"][data-bottom-scroll="true"] {
mask-image: linear-gradient(
to bottom,
#000 0%,
#000 calc(100% - var(--scroll-shadow-size)),
transparent 100%
);
-webkit-mask-image: linear-gradient(
to bottom,
#000 0%,
#000 calc(100% - var(--scroll-shadow-size)),
transparent 100%
);
}
@keyframes spin-once {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
@keyframes oc-migrate-up {
0% {
opacity: 1;
transform: translateY(0);
}
100% {
opacity: 0;
transform: translateY(-10px);
}
}
@keyframes gradient-shimmer {
0% {
stop-color: currentColor;
}
50% {
stop-color: color-mix(in srgb, currentColor 60%, white 40%);
}
100% {
stop-color: currentColor;
}
}
@keyframes shimmer-position {
0% {
x: -100%;
}
100% {
x: 100%;
}
}
@keyframes oc-file-mention-marquee {
0% {
transform: translateX(0%);
}
100% {
transform: translateX(calc(-100% + var(--file-mention-marquee-width, 360px)));
}
}
.file-mention-marquee-container {
--file-mention-marquee-width: 360px;
--file-mention-marquee-duration: 4s;
mask-image: linear-gradient(to right, black calc(100% - 24px), transparent 100%);
-webkit-mask-image: linear-gradient(to right, black calc(100% - 24px), transparent 100%);
}
.file-mention-marquee {
animation: oc-file-mention-marquee var(--file-mention-marquee-duration, 4s) linear 0.2s 1 both;
will-change: transform;
}
/* Safari/WebKit fixes for buttons and SVG icons */
/* Remixicon puts fill="currentColor" on root SVG which WebKit renders as background */
button svg.remixicon,
[role="button"] svg.remixicon,
button svg,
[role="button"] svg {
background: none !important;
background-color: transparent !important;
/* Override inline fill attribute on SVG root */
fill: none !important;
/* Ensure SVG uses CSS rendering, not native */
shape-rendering: geometricPrecision;
}
/* GPU acceleration for non-spinning SVGs */
button svg:not(.animate-spin),
[role="button"] svg:not(.animate-spin) {
transform: translateZ(0);
-webkit-transform: translateZ(0);
}
/* Fix SVG elements inside buttons - remove any rect/circle backgrounds */
button svg rect,
button svg circle,
[role="button"] svg rect,
[role="button"] svg circle {
fill: none !important;
}
/* Ensure SVG paths/shapes inherit color properly */
button svg.remixicon path,
button svg.remixicon circle[fill],
[role="button"] svg.remixicon path,
[role="button"] svg.remixicon circle[fill],
button svg path,
[role="button"] svg path {
fill: currentColor !important;
}
/* Safari/WebKit animation fixes - outside @layer for higher specificity */
.animate-spin {
animation: webkit-spin 1s linear infinite !important;
will-change: transform !important;
background: transparent !important;
background-color: transparent !important;
}
/* Specific SVG spinner fixes for WebKit */
svg.animate-spin {
/* Use CSS box as transform reference for proper centering with scaled SVGs */
transform-box: fill-box !important;
transform-origin: 50% 50% !important;
background: none !important;
background-color: transparent !important;
overflow: visible !important;
/* Ensure SVG content is centered */
display: block !important;
}
@keyframes webkit-spin {
0% {
transform: translateZ(0) rotate(0deg);
}
100% {
transform: translateZ(0) rotate(360deg);
}
}
@keyframes pulse-opacity {
0%,
100% {
opacity: 0.4;
}
50% {
opacity: 1;
}
}
@keyframes pulse-opacity-dim {
0%,
100% {
opacity: 0;
}
50% {
opacity: 0.7;
}
}
.app-region-drag {
-webkit-app-region: drag;
}
.app-region-no-drag {
-webkit-app-region: no-drag;
}
.animate-spin-once {
animation: spin-once 0.5s linear forwards;
}
/* Custom scrollbar styles */
*::-webkit-scrollbar {
width: 10px !important;
height: 10px !important;
background: transparent;
-webkit-appearance: none;
}
*::-webkit-scrollbar-track {
background: transparent;
}
*::-webkit-scrollbar-thumb {
background: var(--oc-scrollbar-thumb);
border-radius: 6px;
border: 2px solid transparent;
background-clip: padding-box;
}
*::-webkit-scrollbar-thumb:hover {
background: var(--oc-scrollbar-thumb-hover);
background-clip: padding-box;
}
.dark {
color-scheme: dark;
--oc-scrollbar-thumb: oklch(0.6 0.02 80 / 0.3);
--oc-scrollbar-thumb-hover: oklch(0.6 0.02 80 / 0.5);
}
[data-scrollbar="chat"]::-webkit-scrollbar-thumb {
border: 2px solid transparent;
background-clip: padding-box;
}
*::-webkit-scrollbar-corner {
background: transparent;
}
/* Fully hidden scrollbar for small mobile overlays (session switcher etc.)
where a visible bar reads as chrome noise. Scrolling stays intact. */
.oc-hide-scrollbar {
scrollbar-width: none;
-ms-overflow-style: none;
}
.oc-hide-scrollbar::-webkit-scrollbar {
display: none;
width: 0;
height: 0;
}
[data-scrollbar="chat"].chat-scroll,
.chat-scroll {
scrollbar-gutter: stable both-edges;
}
html:not(.dark) .chat-scroll {
color-scheme: dark;
}
[data-scrollbar="chat"]::-webkit-scrollbar {
width: 10px !important;
height: 10px !important;
background: transparent !important;
-webkit-appearance: none;
}
[data-scrollbar="chat"].chat-scroll::-webkit-scrollbar,
.chat-scroll::-webkit-scrollbar {
width: 10px !important;
height: 10px !important;
}
[data-scrollbar="chat"]::-webkit-scrollbar-track {
background: transparent !important;
}
[data-scrollbar="chat"].chat-scroll::-webkit-scrollbar-track,
.chat-scroll::-webkit-scrollbar-track {
background: transparent !important;
}
[data-scrollbar="chat"]::-webkit-scrollbar-thumb {
background: var(--oc-scrollbar-thumb) !important;
border-radius: 6px;
border: 2px solid transparent;
background-clip: padding-box;
}
[data-scrollbar="chat"].chat-scroll::-webkit-scrollbar-thumb,
.chat-scroll::-webkit-scrollbar-thumb {
background: var(--oc-scrollbar-thumb) !important;
border-radius: 6px;
border: 2px solid transparent;
background-clip: padding-box;
}
[data-scrollbar="chat"]::-webkit-scrollbar-thumb:hover {
background: var(--oc-scrollbar-thumb-hover) !important;
background-clip: padding-box;
}
[data-scrollbar="chat"].chat-scroll::-webkit-scrollbar-thumb:hover,
.chat-scroll::-webkit-scrollbar-thumb:hover {
background: var(--oc-scrollbar-thumb-hover) !important;
background-clip: padding-box;
}
[data-scrollbar="chat"]::-webkit-scrollbar-corner {
background: transparent !important;
}
/* Hide native scrollbars for overlay targets (all browsers) */
.overlay-scrollbar-target {
scrollbar-width: none !important;
-ms-overflow-style: none !important;
scrollbar-gutter: auto !important;
}
.overlay-scrollbar-target--no-gutter {
scrollbar-gutter: unset !important;
}
.overlay-scrollbar-target::-webkit-scrollbar {
width: 0 !important;
height: 0 !important;
display: none !important;
}
/* Firefox scrollbar support */
* {
scrollbar-width: thin;
scrollbar-color: var(--oc-scrollbar-thumb) transparent;
}
.scrollbar-hidden {
scrollbar-width: none !important;
}
.scrollbar-hidden::-webkit-scrollbar {
width: 0 !important;
height: 0 !important;
}
.dark * {
scrollbar-color: oklch(0.6 0.02 80 / 0.3) transparent;
}
/* Overlay scrollbar styling (custom thumb) */
.overlay-scrollbar {
position: absolute;
inset: 0;
pointer-events: none;
transition: opacity 0.2s ease;
/* Above sticky zone headers (z-20) — the thumb must never dive under
a stuck sidebar header while scrolling. */
z-index: 30;
}
.overlay-scrollbar--dense,
.overlay-scrollbar--bottom-right,
.overlay-scrollbar--zero,
.overlay-scrollbar--flush {
/* no-op: positioning handled inline */
}
.overlay-scrollbar__thumb {
pointer-events: auto;
position: absolute;
width: 6px;
background: var(--oc-scrollbar-thumb);
border-radius: 9999px;
opacity: 0.8;
transition: background-color 0.15s ease, opacity 0.15s ease;
will-change: transform, height;
}
.overlay-scrollbar__thumb:hover,
.overlay-scrollbar__thumb:active {
background: var(--oc-scrollbar-thumb-hover);
opacity: 1;
}
.overlay-scrollbar__thumb--horizontal {
height: 6px;
margin: 0;
}
.overlay-scrollbar__thumb--vertical {
margin: 0;
}
/* Pierre diff viewer styling */
.pierre-diff-wrapper {
--diffs-font-family: var(--font-mono, ui-monospace, monospace);
--diffs-font-size: var(--text-code);
--diffs-line-height: 24px;
--diffs-tab-size: 2;
--diffs-header-font-family: var(--font-sans, system-ui, sans-serif);
--diffs-min-number-column-width: 4ch;
--diffs-gap-inline: 0;
--diffs-gap-block: 0;
/* Prevent browser scroll anchoring jumps during async highlight/virtualization */
overflow-anchor: none;
}
/* Prevent scroll anchoring in stacked diff scroll container */
[data-diff-virtual-root] {
overflow-anchor: none;
}
/* Desktop: slightly smaller diff code text */
.pierre-diff-wrapper diffs-container {
display: block;
}
/* Header tab responsiveness */
:root:not(.mobile-pointer):not(.vscode-runtime) .header-tab-label {
display: inline;
}
:root:not(.mobile-pointer):not(.vscode-runtime) .header-open-label {
display: inline;
}
@media (max-width: 940px) {
:root:not(.mobile-pointer):not(.vscode-runtime) .header-tab-label {
display: none;
}
:root:not(.mobile-pointer):not(.vscode-runtime) .header-open-label {
display: none;
}
:root:not(.mobile-pointer):not(.vscode-runtime) .header-tab-badge {
margin-left: -0.125rem;
}
}
/* ============================================
Streamdown Styles
Minimal overrides - fonts only, using Streamdown defaults
============================================ */
/* VS Code webviews can inject default pre/code/blockquote backgrounds; tool input/output should inherit the card surface. */
.tool-input-surface pre,
.tool-input-surface code,
.tool-input-surface blockquote,
.tool-input-text {
background: transparent !important;
background-color: transparent !important;
}
/* VSCode: tool cards should honor semantic code sizing, even when syntax themes inject sizes. */
:root.vscode-runtime .tool-input-surface,
:root.vscode-runtime .tool-output-surface {
font-size: var(--text-code) !important;
}
:root.vscode-runtime .tool-input-surface code,
:root.vscode-runtime .tool-input-surface pre,
:root.vscode-runtime .tool-output-surface code,
:root.vscode-runtime .tool-output-surface pre {
font-size: inherit !important;
}
/* Model/agent controls: progressively collapse labels to icon-only as the row narrows.
Hide priority (most aggressive first → most resilient last): agent, variant, model. */
/* Desktop (non-VSCode): pick thresholds that fire BEFORE the per-label `max-w-[Xpx]`
constraints would truncate text with an ellipsis. */
@container model-controls (max-width: 22rem) {
:root:not(.vscode-runtime) .model-controls__agent-label {
display: none;
}
}
@container model-controls (max-width: 14rem) {
:root:not(.vscode-runtime) .model-controls__variant-label {
display: none;
}
}
@container model-controls (max-width: 10rem) {
:root:not(.vscode-runtime) .model-controls__model-label {
display: none;
}
}
/* VS Code side panel: tighter thresholds since the panel is narrow and labels are smaller. */
@container model-controls (max-width: 11rem) {
:root.vscode-runtime .model-controls__agent-label {
display: none;
}
}
@container model-controls (max-width: 9rem) {
:root.vscode-runtime .model-controls__variant-label {
display: none;
}
}
@container model-controls (max-width: 10rem) {
:root.vscode-runtime .model-controls__model-label {
display: none;
}
}
/* Commit actions: collapse labels when narrow. */
@container commit-actions (max-width: 21rem) {
.commit-actions__label--long {
display: none;
}
}
@container commit-actions (max-width: 22rem) {
.commit-actions__label--push {
display: none;
}
}
@container commit-actions (max-width: 19rem) {
.commit-actions__label {
display: none;
}
.commit-actions__btn {
padding-inline: 0.5rem;
}
}
/* Utility: hide scrollbars without affecting layout */
.scrollbar-none {
-ms-overflow-style: none;
scrollbar-width: none;
}
.scrollbar-none::-webkit-scrollbar {
width: 0;
height: 0;
display: none;
}
/* Git right-sidebar header/actions collapse to icon-only when narrow. */
@container git-header (max-width: 26rem) {
.git-header-label {
display: none;
}
}
/* Diff toolbar: the walkthrough label goes first. Review is the primary action
in this row, so it keeps its label longest; the walkthrough is reachable from
the rail as well and reads fine as an icon. */
@container diff-toolbar (max-width: 36rem) {
.diff-toolbar__walkthrough-label {
display: none;
}
.diff-toolbar__walkthrough-button {
padding-inline: 0.5rem;
}
}
/* Then the rest, once the panel is genuinely tight. */
@container diff-toolbar (max-width: 28rem) {
.diff-toolbar__scope-count,
.diff-toolbar__review-label,
.diff-toolbar__expand-label {
display: none;
}
.diff-toolbar__review-button,
.diff-toolbar__expand-button {
padding-inline: 0.5rem;
}
}
/* Pull request actions: the walkthrough label goes first, since merge controls
are the reason the row exists. */
@container pr-actions (max-width: 30rem) {
.pr-actions__walkthrough-label {
display: none;
}
.pr-actions__walkthrough-button {
padding-inline: 0.5rem;
}
}
/* Hide the long active todo before it can collide with the changed-files summary. */
@container status-row (max-width: 38rem) {
.status-row__active-todo {
display: none;
}
}
/* Hide the secondary changed-files label on narrow mobile layouts. */
@container status-row (max-width: 30rem) {
.status-row__changed-label {
display: none;
}
}
/* Assistant message footer: collapse text labels only on very narrow layouts. */
@container message-footer (max-width: 16rem) {
.message-footer__label {
display: none;
}
}
/* Animated tabs: collapse labels based on local container width. */
@container animated-tabs (max-width: 23rem) {
.animated-tabs__label {
display: none;
}
.animated-tabs__button {
padding-inline: 0.5rem;
gap: 0;
}
}
.pill-tabs__track {
padding-inline: 0.125rem;
}
@container pill-tabs (max-width: 23rem) {
.pill-tabs__track {
padding-inline: 1px;
}
.pill-tabs__button {
padding-inline: 0.5rem;
}
}
/*
* Active pill indicator motion. Transitions are opt-in via the --is-animated
* modifier so first measurement and container resizes reposition instantly
* instead of sliding in from the track origin.
*/
.pill-tabs__indicator--is-animated {
/* Decelerating ease with no overshoot: the indicator settles rather than
bouncing back at the end of its travel. */
transition:
transform 280ms cubic-bezier(0.22, 1, 0.36, 1),
width 260ms cubic-bezier(0.22, 1, 0.36, 1),
height 260ms cubic-bezier(0.22, 1, 0.36, 1);
}
/* Non-composited variant (left/top-positioned indicator, see
nonCompositedIndicator in sortable-tabs-strip): same travel curve. */
.pill-tabs__indicator--is-animated-layout {
transition:
left 280ms cubic-bezier(0.22, 1, 0.36, 1),
top 260ms cubic-bezier(0.22, 1, 0.36, 1),
width 260ms cubic-bezier(0.22, 1, 0.36, 1),
height 260ms cubic-bezier(0.22, 1, 0.36, 1);
}
/* Underline indicator shares the pill's travel curve so both tab styles feel
like the same control. */
.underline-tabs__indicator--is-animated {
transition:
transform 280ms cubic-bezier(0.22, 1, 0.36, 1),
width 260ms cubic-bezier(0.22, 1, 0.36, 1);
}
.pill-tabs__button {
transition-property: color, transform;
transition-duration: 150ms;
transition-timing-function: cubic-bezier(0.22, 1, 0.36, 1);
}
.pill-tabs__button:active {
transform: scale(0.97);
}
@media (prefers-reduced-motion: reduce) {
.pill-tabs__indicator--is-animated,
.pill-tabs__indicator--is-animated-layout,
.underline-tabs__indicator--is-animated {
transition: none;
}
.pill-tabs__button:active {
transform: none;
}
}
/* Text font */
.markdown-content {
font-family: var(--font-sans);
font-size: var(--text-markdown);
line-height: inherit;
}
.markdown-content p,
.markdown-content li,
.markdown-content blockquote,
.markdown-content td,
.markdown-content th {
line-height: inherit;
}
/* Restore paragraph block spacing inside markdown content. The
--markdown-paragraph-spacing token existed but was never wired, so Tailwind
preflight's zeroed <p> margins left adjacent paragraphs collapsed into one
visual line. */
.markdown-content p {
margin: 0 0 var(--markdown-paragraph-spacing) 0;
}
/* The markdown renderer wraps each block in a display:contents [data-md-block]
element, so the message-level [&_.markdown-content>*:last-child]:mb-0
nullifiers target the wrapper (where margin is ignored), not the paragraph.
Drop the trailing margin on the last paragraph of the last block directly so
messages don't gain extra space at the bottom. */
.markdown-content > [data-md-block]:last-child p:last-child {
margin-bottom: 0;
}
/* Tool cards (code size) and reasoning (meta size, dimmed) are intentionally
compact — keep their paragraphs tight, matching prior behavior. */
.markdown-content.markdown-tool p,
.markdown-content.markdown-reasoning p {
margin-bottom: 0;
}
/* Tool markdown should render at code size to match tool card typography. */
.markdown-content.markdown-tool {
font-size: var(--text-code) !important;
}
/* Reasoning markdown renders at meta size, dimmed. */
.markdown-content.markdown-reasoning {
font-size: var(--text-markdown);
color: var(--surface-muted-foreground);
--markdown-heading1: inherit;
--markdown-heading2: inherit;
--markdown-heading3: inherit;
--markdown-heading4: inherit;
--markdown-link: inherit;
--markdown-link-hover: var(--surface-foreground);
--markdown-blockquote: inherit;
--markdown-bold: inherit;
--markdown-italic: inherit;
--markdown-strikethrough: inherit;
}
.markdown-content.markdown-reasoning p,
.markdown-content.markdown-reasoning li,
.markdown-content.markdown-reasoning td,
.markdown-content.markdown-reasoning th,
.markdown-content.markdown-reasoning h1,
.markdown-content.markdown-reasoning h2,
.markdown-content.markdown-reasoning h3,
.markdown-content.markdown-reasoning h4,
.markdown-content.markdown-reasoning h5,
.markdown-content.markdown-reasoning h6,
.markdown-content.markdown-reasoning strong,
.markdown-content.markdown-reasoning b,
.markdown-content.markdown-reasoning em,
.markdown-content.markdown-reasoning del,
.markdown-content.markdown-reasoning [data-markdown="strong"],
.markdown-content.markdown-reasoning [data-markdown="bold"] {
color: var(--surface-muted-foreground) !important;
}
.markdown-content.markdown-reasoning a,
.markdown-content.markdown-reasoning [data-openchamber-file-link="true"] {
color: var(--surface-muted-foreground) !important;
}
.markdown-content.markdown-reasoning a:hover,
.markdown-content.markdown-reasoning [data-openchamber-file-link="true"]:hover {
color: var(--surface-foreground) !important;
}
.markdown-content.markdown-reasoning strong,
.markdown-content.markdown-reasoning b,
.markdown-content.markdown-reasoning [data-markdown="strong"],
.markdown-content.markdown-reasoning [data-markdown="bold"] {
font-weight: inherit !important;
color: inherit !important;
font-style: inherit !important;
}
.markdown-content.markdown-tool code,
.markdown-content.markdown-tool pre {
font-size: inherit !important;
}
/* Streamdown headers: keep proportional but not oversized */
.markdown-content h1 {
font-size: 1.125em;
font-weight: 600;
margin-top: 1em;
margin-bottom: 0.5em;
}
.markdown-content h2 {
font-size: 1.0625em;
font-weight: 600;
margin-top: 0.875em;
margin-bottom: 0.375em;
}
.markdown-content h3 {
font-size: 1em;
font-weight: 600;
margin-top: 0.75em;
margin-bottom: 0.25em;
}
.markdown-content h4,
.markdown-content h5,
.markdown-content h6 {
font-size: 1em;
font-weight: 600;
margin-top: 0.625em;
margin-bottom: 0.25em;
}
/* Code font */
.markdown-content code,
.markdown-content pre {
font-family: var(--font-mono);
font-size: var(--text-code);
}
/* Override Streamdown's hardcoded bg-muted for inline code - use theme colors instead */
.markdown-content code[data-markdown="inline-code"] {
background-color: var(--markdown-inline-code-bg, var(--surface-muted)) !important;
color: var(--markdown-inline-code, var(--foreground)) !important;
word-break: break-all;
overflow-wrap: break-word;
}
/* Markdown headings - use theme colors */
.markdown-content h1 {
color: var(--markdown-heading1, var(--primary));
}
.markdown-content h2 {
color: var(--markdown-heading2, var(--primary));
}
.markdown-content h3 {
color: var(--markdown-heading3, var(--primary));
}
.markdown-content h4,
.markdown-content h5,
.markdown-content h6 {
color: var(--markdown-heading4, var(--foreground));
}
/* Markdown links - use theme colors */
.markdown-content a {
color: var(--markdown-link, var(--primary));
}
.markdown-content a:hover {
color: var(--markdown-link-hover, var(--primary));
}
.markdown-content [data-openchamber-file-link="true"] {
color: var(--markdown-link, var(--primary));
cursor: pointer;
text-decoration: underline;
text-underline-offset: 2px;
user-select: text !important;
-webkit-user-select: text !important;
}
.markdown-content [data-openchamber-file-link="true"]:hover {
color: var(--markdown-link-hover, var(--primary));
}
/* Agent/skill mentions use the primary accent, not the markdown link color */
.markdown-content a[data-openchamber-agent-mention="true"],
.markdown-content a[data-skill-name] {
color: var(--primary);
}
.markdown-content a[data-openchamber-agent-mention="true"]:hover,
.markdown-content a[data-skill-name]:hover {
color: var(--primary);
}
/* Markdown blockquote - use theme colors */
.markdown-content blockquote {
color: var(--markdown-blockquote, var(--muted-foreground));
border-left-color: var(--markdown-blockquote-border, var(--border));
}
/* Markdown horizontal rule - use theme colors */
.markdown-content hr {
border-color: var(--markdown-hr, var(--border));
}
/* Markdown bold/italic/strikethrough - use theme colors */
.markdown-content strong {
color: var(--markdown-bold, var(--foreground));
}
.markdown-content em {
color: var(--markdown-italic, var(--foreground));
}
.markdown-content del {
color: var(--markdown-strikethrough, var(--muted-foreground));
}
/* Streamdown code blocks: ensure light/dark Shiki vars work even when Tailwind doesn't scan Streamdown's internal class names. */
.markdown-content [data-markdown="code-block-body"] {
font-size: var(--text-code);
background-color: transparent;
color: var(--shiki-light, inherit);
}
.markdown-content [data-markdown="code-block-body"] span[style*="--sdm-c"] {
color: var(--sdm-c) !important;
}
.markdown-content [data-markdown="code-block-body"] span[style*="--sdm-tbg"] {
background-color: var(--sdm-tbg) !important;
}
.markdown-content [data-markdown="code-block-body"] span[style*="--shiki-light"] {
color: var(--shiki-light) !important;
}
.markdown-content [data-markdown="code-block-body"] span[style*="--shiki-light-bg"] {
background-color: var(--shiki-light-bg) !important;
}
.dark .markdown-content [data-markdown="code-block-body"] {
background-color: transparent;
color: var(--shiki-dark, var(--shiki-light, inherit));
}
.dark .markdown-content [data-markdown="code-block-body"] span[style*="--shiki-dark"] {
color: var(--shiki-dark) !important;
}
.dark .markdown-content [data-markdown="code-block-body"] span[style*="--shiki-dark-bg"] {
background-color: var(--shiki-dark-bg) !important;
}
/* Reduce code block header height */
[data-markdown="code-block-header"] {
margin: 0;
padding: 0.375rem 0.75rem;
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
padding-right: 5.25rem;
border: 0;
border-bottom: 1px solid var(--interactive-border);
border-radius: 0;
background: var(--surface-muted);
}
/* Disable Streamdown's code block virtualization and keep block chrome fixed */
.markdown-content [data-markdown="code-block"] {
content-visibility: visible !important;
contain-intrinsic-size: none !important;
position: relative;
display: flex;
flex-direction: column;
padding: 0 !important;
box-sizing: border-box;
inline-size: 100%;
max-inline-size: 100%;
min-inline-size: 0;
overflow: hidden;
background: var(--surface-background);
border: 1px solid var(--interactive-border);
border-radius: 0.75rem;
}
.markdown-content [data-markdown="code-block"] > div:not([data-markdown]) {
position: absolute;
top: 0;
right: 0;
margin-top: 0;
height: 2rem;
z-index: 6;
pointer-events: none;
}
/* Streamdown code block body: scroll text content within the card body */
.markdown-content [data-markdown="code-block-body"] {
display: block;
inline-size: 100%;
min-width: 0;
max-width: 100%;
margin: 0;
padding: 0;
overflow-x: auto;
overflow-y: hidden;
box-sizing: border-box;
scrollbar-gutter: stable;
background: transparent;
border: 0;
border-radius: 0;
}
.markdown-content [data-markdown="code-block-body"] pre {
display: block;
width: 100%;
min-width: 100%;
max-width: 100%;
margin: 0 !important;
padding: 0.75rem !important;
border: 0 !important;
border-radius: 0 !important;
box-shadow: none !important;
background: transparent !important;
}
.markdown-content [data-markdown="code-block-body"] > * {
border: 0 !important;
border-radius: 0 !important;
box-shadow: none !important;
background: transparent !important;
}
.markdown-content [data-markdown="code-block-body"] code {
white-space: pre;
overflow-wrap: normal;
word-break: normal;
background: transparent !important;
}
.markdown-content [data-md-code-lines] {
display: block;
min-width: 100%;
}
.markdown-content [data-md-code-line] {
display: grid;
grid-template-columns: 2rem minmax(0, 1fr);
column-gap: 0.75rem;
min-width: 100%;
}
.markdown-content [data-md-code-line-number] {
align-self: stretch;
padding-right: 0.75rem;
border-right: 1px solid color-mix(in srgb, var(--border) 50%, transparent);
color: color-mix(in srgb, var(--muted-foreground) 45%, transparent);
font-variant-numeric: tabular-nums;
text-align: right;
user-select: none;
}
.markdown-content [data-md-code-line-content] {
min-width: 0;
}
.markdown-content [data-md-code-line-break] {
display: none;
}
[data-message-image-export="true"] [data-md-code-body] {
overflow: visible !important;
}
[data-message-image-export="true"] [data-md-code-line-content] {
white-space: pre-wrap !important;
overflow-wrap: anywhere !important;
}
[data-message-image-export="true"] [data-md-code-actions] {
display: none !important;
}
.markdown-content [data-markdown="code-block-actions"] {
pointer-events: auto;
transition: opacity 0.15s ease;
border: 0 !important;
background: transparent !important;
box-shadow: none !important;
gap: 0.125rem;
}
.markdown-content [data-markdown="code-block-actions"] button {
border: 0 !important;
background: transparent !important;
box-shadow: none !important;
padding: 0.25rem !important;
min-width: 1.5rem;
min-height: 1.5rem;
}
.markdown-content [data-markdown="code-block-actions"] button svg {
width: 0.875rem;
height: 0.875rem;
}
@media (hover: hover) and (pointer: fine) {
.markdown-content [data-markdown="code-block"] [data-markdown="code-block-actions"] {
opacity: 0;
pointer-events: none;
}
.markdown-content [data-markdown="code-block"]:hover [data-markdown="code-block-actions"],
.markdown-content [data-markdown="code-block"]:focus-within [data-markdown="code-block-actions"] {
opacity: 1;
pointer-events: auto;
}
}
/* Mermaid block: position context for controls wrapper. */
[data-markdown="mermaid-block"] {
position: relative;
border-radius: 0.75rem;
border: 1px solid var(--interactive-border);
background: var(--surface-elevated);
padding: 0.5rem;
}
[data-markdown="mermaid-block"] [data-markdown="mermaid-scroll"] {
overflow: auto;
min-width: 0;
}
[data-markdown="mermaid-block"][data-mermaid-render="svg"] [data-markdown="mermaid-scroll"] {
overflow: hidden;
}
[data-markdown="mermaid-block"] [data-markdown="mermaid-viewport"] {
width: 100%;
min-width: 0;
height: min(24rem, 70vh);
min-height: 12rem;
overflow: hidden;
touch-action: none;
border-radius: 0.5rem;
background: var(--surface-elevated);
}
[data-markdown="mermaid-block"] [data-markdown="mermaid"] {
width: 100%;
height: 100%;
display: block;
}
[data-markdown="mermaid-block"][data-mermaid-panning="true"] [data-markdown="mermaid-viewport"] {
cursor: grabbing;
}
[data-markdown="mermaid-block"] [data-markdown="mermaid-ascii"] {
margin: 0;
white-space: pre;
width: max-content;
min-width: 100%;
font-family: var(--font-mono);
color: var(--surface-foreground);
background: transparent;
}
[data-markdown="mermaid-block"] [data-markdown="mermaid"] svg {
width: 100% !important;
height: 100% !important;
min-width: 0;
max-width: none !important;
display: block;
background: var(--surface-elevated);
}
/* Fullscreen Mermaid popup: scale diagrams to fill available viewport panel area. */
.markdown-mermaid-fullscreen {
height: 100%;
width: 100%;
}
.markdown-mermaid-fullscreen .markdown-content {
height: 100%;
width: 100%;
}
.markdown-mermaid-fullscreen [data-markdown="mermaid-block"] {
width: 100%;
height: 100%;
min-height: 100%;
padding: 0.75rem;
border: 0;
border-radius: 0;
background: var(--surface-elevated);
}
.markdown-mermaid-fullscreen [data-markdown="mermaid-block"] [data-markdown="mermaid-scroll"] {
width: 100%;
height: 100%;
overflow: auto;
}
.markdown-mermaid-fullscreen [data-markdown="mermaid-block"][data-mermaid-render="svg"] [data-markdown="mermaid-scroll"] {
overflow: hidden;
}
.markdown-mermaid-fullscreen [data-markdown="mermaid-block"] [data-markdown="mermaid-viewport"] {
width: 100%;
height: 100%;
min-width: 100%;
min-height: 100%;
overflow: hidden;
}
.markdown-mermaid-fullscreen [data-markdown="mermaid-block"] [data-markdown="mermaid"] {
width: 100%;
height: 100%;
display: block;
}
.markdown-mermaid-fullscreen [data-markdown="mermaid-block"] [data-markdown="mermaid-ascii"] {
margin: 0;
white-space: pre;
width: max-content;
min-width: 100%;
min-height: 100%;
font-family: var(--font-mono);
color: var(--surface-foreground);
background: transparent;
}
.markdown-mermaid-fullscreen [data-markdown="mermaid-block"] [data-markdown="mermaid"] svg {
width: 100% !important;
height: 100% !important;
max-width: none !important;
max-height: none !important;
min-width: 100%;
display: block;
background: transparent;
}
/* Terminal touch input is portaled to document.body; keep it fully non-painting across engines. */
input[data-terminal-hidden-input="true"],
textarea[data-terminal-hidden-input="true"] {
caret-color: transparent !important;
color: transparent !important;
-webkit-text-fill-color: transparent !important;
background: transparent !important;
border: 0 !important;
outline: none !important;
box-shadow: none !important;
text-shadow: none !important;
-webkit-appearance: none;
appearance: none;
}
input[data-terminal-hidden-input="true"]::selection,
textarea[data-terminal-hidden-input="true"]::selection {
background: transparent;
color: transparent;
}
input[data-terminal-hidden-input="true"]::placeholder,
textarea[data-terminal-hidden-input="true"]::placeholder {
color: transparent !important;
}
/* Hide browser/system caret for Ghostty's own input surfaces.
Terminal cursor is rendered by the canvas renderer. */
.terminal-viewport-container[contenteditable="true"][aria-label="Terminal input"],
.terminal-viewport-container [contenteditable="true"][aria-label="Terminal input"] {
caret-color: transparent !important;
outline: none !important;
}
textarea[aria-label="Terminal input"],
input[aria-label="Terminal input"] {
caret-color: transparent !important;
outline: none !important;
}
/* When touch terminal input uses the portaled overlay, keep Ghostty's
internal editable surfaces fully non-painting to avoid duplicate cursors. */
.terminal-viewport-container[data-hidden-input-overlay-active="true"] textarea:not([data-terminal-hidden-input="true"]),
.terminal-viewport-container[data-hidden-input-overlay-active="true"] input:not([data-terminal-hidden-input="true"]),
.terminal-viewport-container[data-hidden-input-overlay-active="true"] [contenteditable="true"] {
caret-color: transparent !important;
color: transparent !important;
-webkit-text-fill-color: transparent !important;
background: transparent !important;
border: 0 !important;
outline: none !important;
box-shadow: none !important;
text-shadow: none !important;
}
.terminal-viewport-container[data-hidden-input-overlay-active="true"] textarea:not([data-terminal-hidden-input="true"]),
.terminal-viewport-container[data-hidden-input-overlay-active="true"] input:not([data-terminal-hidden-input="true"]),
.terminal-viewport-container[data-hidden-input-overlay-active="true"] [contenteditable="true"] {
opacity: 0 !important;
font-size: 0 !important;
line-height: 0 !important;
pointer-events: none !important;
user-select: none !important;
-webkit-user-select: none !important;
}
/* Mobile Terminal Optimizations */
@media (max-width: 1024px) {
.terminal-viewport-container {
font-variant-ligatures: none;
font-feature-settings: "liga" 0, "calt" 0;
}
}
/* Font loading states */
.fonts-loading .terminal-viewport-container {
font-family: monospace;
}
.fonts-loaded .terminal-viewport-container {
font-family: "JetBrainsMono Nerd Font", "FiraCode Nerd Font", "Fira Code", "JetBrains Mono", "SFMono-Regular", Menlo, Consolas, "Liberation Mono", "Courier New", monospace;
}
@keyframes oc-busy-pulse {
0%, 100% {
opacity: 0.2;
}
50% {
opacity: 1;
}
}
.animate-busy-pulse {
animation: oc-busy-pulse 1.2s ease-in-out infinite;
}
@keyframes navrail-dot-wave {
0%, 100% {
transform: scale(0.72);
opacity: 0.52;
}
50% {
transform: scale(1);
opacity: 1;
}
}
.animate-navrail-dot-wave {
animation: navrail-dot-wave 1.2s ease-in-out infinite;
}
@keyframes border-glow-pulse {
0%, 100% {
border-color: var(--interactive-border);
outline-color: transparent;
}
12.5% {
border-color: color-mix(in srgb, var(--primary) 22%, var(--interactive-border));
outline-color: color-mix(in srgb, var(--primary) 8%, transparent);
}
25% {
border-color: color-mix(in srgb, var(--primary) 40%, var(--interactive-border));
outline-color: color-mix(in srgb, var(--primary) 16%, transparent);
}
37.5% {
border-color: color-mix(in srgb, var(--primary) 62%, var(--interactive-border));
outline-color: color-mix(in srgb, var(--primary) 26%, transparent);
}
50% {
border-color: color-mix(in srgb, var(--primary) 78%, var(--interactive-border));
outline-color: color-mix(in srgb, var(--primary) 34%, transparent);
}
62.5% {
border-color: color-mix(in srgb, var(--primary) 62%, var(--interactive-border));
outline-color: color-mix(in srgb, var(--primary) 26%, transparent);
}
75% {
border-color: color-mix(in srgb, var(--primary) 40%, var(--interactive-border));
outline-color: color-mix(in srgb, var(--primary) 16%, transparent);
}
87.5% {
border-color: color-mix(in srgb, var(--primary) 22%, var(--interactive-border));
outline-color: color-mix(in srgb, var(--primary) 8%, transparent);
}
}
.animate-border-glow-pulse {
outline: 1px solid transparent;
outline-offset: 1px;
will-change: border-color, outline-color;
animation: border-glow-pulse 3.8s linear infinite;
}
@keyframes marquee-scroll {
0% { transform: translateX(0); }
100% { transform: translateX(-100%); }
}
@keyframes open-file-name-marquee-scroll {
0% { transform: translateX(0); }
100% { transform: translateX(-50%); }
}
.open-file-name-marquee-track {
display: inline-flex;
min-width: max-content;
animation: open-file-name-marquee-scroll var(--open-file-name-marquee-duration, 14s) linear infinite;
will-change: transform;
}
.open-file-name-marquee-item {
flex-shrink: 0;
padding-right: 2rem;
}
.marquee-text {
display: inline-block;
white-space: nowrap;
}
.marquee-text--auto {
animation: marquee-scroll 6s linear infinite alternate;
will-change: transform;
}
.group:hover .marquee-text--active,
.marquee-text--active:hover {
animation: marquee-scroll 5s linear infinite alternate;
}
@media (prefers-reduced-motion: reduce) {
.marquee-text--auto,
.open-file-name-marquee-track,
.group:hover .marquee-text--active,
.marquee-text--active:hover {
animation: none;
}
.open-file-name-marquee-track {
display: block;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
will-change: auto;
}
.open-file-name-marquee-track .open-file-name-marquee-item {
display: inline;
padding-right: 0;
}
.open-file-name-marquee-track .open-file-name-marquee-item[aria-hidden="true"] {
display: none;
}
.animate-busy-pulse {
animation: none;
}
}
/* Settings dialog: hide the overlay scrollbar; wheel/keyboard scroll still works. */
[data-settings-view="true"] .overlay-scrollbar {
display: none;
}
/* Desktop app shell (Electron/native window): native apps use the arrow cursor
for clickable controls, not the web's hand/pointer. Neutralize pointer
cursors under the desktop runtime only — web in a browser keeps them.
Resize/grab/text cursors are untouched. */
html.desktop-runtime
:where(button, [role="button"], a[href], summary, label[for]):not(:disabled):not([aria-disabled="true"]) {
cursor: default;
}
html.desktop-runtime [class*="cursor-pointer"] {
cursor: default !important;
}
html.desktop-runtime .markdown-content [data-openchamber-file-link="true"] {
cursor: default;
}