/** * Sidebar styles. Per the DSH web-styling rules every visual value rides the * theme: --dsw-alias-* semantic tokens for colors, --dsw-font-* typography * roles (size paired with line-height), and --ds-* for motion. The chrome * mirrors the native DSH sidebar: flat (NO box-shadows anywhere), the * sidebar fill surface, hairline borders, and the 28/36px circular icon * controls with hover fills. No static palette values, no color literals, no * theme selectors — light/dark adaptation is the theme package's job. */ /* ── Shell ─────────────────────────────────────────────────────────────── */ .toggleRail { position: fixed; right: 0; top: 50%; transform: translateY(-50%); z-index: 55; display: flex; align-items: center; /* Native rail inset: the 36px control sits 10px off the column edge. */ padding: 0 10px; } /* The closed-state affordance is the native rail icon control: a plain 36px circle, transparent fill, secondary ink; hover raises the fill. No border, no shadow — the icon alone is the affordance (SidebarRoot .iconButton). */ .toggleButton { display: flex; align-items: center; justify-content: center; width: 36px; height: 36px; border: none; border-radius: 50%; background: transparent; color: var(--dsw-alias-label-secondary); cursor: pointer; transition: background var(--ds-transition-duration-slow) var(--ds-ease-in-out), color var(--ds-transition-duration-slow) var(--ds-ease-in-out); } .toggleButton:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); color: var(--dsw-alias-label-primary); } .toggleButton:disabled { opacity: 0.4; cursor: default; } .panel { position: fixed; top: 0; right: 0; bottom: 0; z-index: 50; display: flex; flex-direction: column; /* The native sidebar surface: bluish-50 over white / bluish-900 over dark, exactly like the app's own sidebar column (SidebarRoot .root). */ background: var(--dsw-specific-sidebar-fill); border-left: 1px solid var(--dsw-alias-border-l2); /* Expand/collapse slides the panel; fullscreen animates the width. */ transition: transform var(--ds-transition-duration-slow) var(--ds-ease-in-out), width var(--ds-transition-duration-slow) var(--ds-ease-in-out); } /* Collapsed: slid off-screen, interactive nothing, hidden after the slide. */ .panelHidden { transform: translateX(102%); pointer-events: none; visibility: hidden; transition: transform var(--ds-transition-duration-slow) var(--ds-ease-in-out), width var(--ds-transition-duration-slow) var(--ds-ease-in-out), visibility 0s linear var(--ds-transition-duration-slow); } /* Width drags write at pointer cadence; easing would detach the edge. */ .panel[data-dragging] { transition: none; } .panelResize { position: absolute; left: -4px; top: 0; bottom: 0; width: 8px; cursor: col-resize; z-index: 2; touch-action: none; } .panelResizeActive { background: var(--dsw-alias-interactive-bg-hover-accent); } .panelHeader { display: flex; align-items: center; justify-content: space-between; gap: 8px; height: 36px; padding: 0 8px 0 12px; border-bottom: 1px solid var(--dsw-alias-border-l1); flex: none; } .panelTitle { font: var(--dsw-font-s-14); color: var(--dsw-alias-label-secondary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .panelBody { flex: 1; min-height: 0; min-width: 0; display: flex; } /* Icon button: the app's own icon-button pattern (ui-workspace) — a 28px circle, secondary label, hover fill; no border so the icon alone is the affordance. */ .iconButton { display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; padding: 0; border: none; border-radius: 50%; background: transparent; color: var(--dsw-alias-label-secondary); cursor: pointer; flex: none; } .iconButton:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); color: var(--dsw-alias-label-primary); } .iconButton:disabled { opacity: 0.4; cursor: default; } /* ── Workbench / split panes ───────────────────────────────────────────── */ .workbench { flex: 1; min-width: 0; min-height: 0; display: flex; } .split { flex: 1; min-width: 0; min-height: 0; display: flex; } .splitRow { flex-direction: row; } .splitCol { flex-direction: column; } .splitChild { position: relative; display: flex; overflow: hidden; } .divider { position: relative; flex: none; z-index: 3; touch-action: none; } /* The hit area stays 7px wide enough to grab, but the visual is a 1px hairline centered in it — a divider line, not a thick band. */ .dividerRow::after, .dividerCol::after { content: ''; position: absolute; background: var(--dsw-alias-border-l2); transition: background var(--ds-transition-duration-slow) var(--ds-ease-in-out); } .dividerRow { width: 7px; margin: 0 -2px; cursor: col-resize; } .dividerRow::after { top: 0; bottom: 0; left: 50%; width: 1px; transform: translateX(-50%); } .dividerCol { height: 7px; margin: -2px 0; cursor: row-resize; } .dividerCol::after { left: 0; right: 0; top: 50%; height: 1px; transform: translateY(-50%); } .divider:hover::after, .dividerActive::after { background: var(--dsw-alias-interactive-bg-hover-accent); } .pane { position: relative; flex: 1; min-width: 0; min-height: 0; display: flex; flex-direction: column; background: var(--dsw-alias-bg-base); } .paneDrop { outline: 1px solid var(--dsw-alias-interactive-bg-hover-accent); outline-offset: -1px; } /* VSCode-style drag-to-edge drop zones (25% edges, 50% center). */ .dropOverlay { position: absolute; z-index: 6; pointer-events: none; background: var(--dsw-alias-interactive-bg-hover-accent); opacity: 0.5; } .dropLeft { left: 0; top: 0; bottom: 0; width: 25%; } .dropRight { right: 0; top: 0; bottom: 0; width: 25%; } .dropUp { top: 0; left: 0; right: 0; height: 25%; } .dropDown { bottom: 0; left: 0; right: 0; height: 25%; } .dropCenter { left: 25%; right: 25%; top: 25%; bottom: 25%; background: transparent; outline: 2px dashed var(--dsw-alias-interactive-bg-hover-accent); outline-offset: -2px; } .paneContent { flex: 1; min-height: 0; display: flex; flex-direction: column; overflow: hidden; } /* One tab's mounted content; inactive tabs stay mounted but hidden so switching never tears down terminals/editors (state survives). */ .paneTab { flex: 1; min-height: 0; display: flex; flex-direction: column; } .paneTabHidden { display: none; } .paneEmptyCards { flex: 1; min-height: 0; display: flex; flex-direction: column; justify-content: center; gap: 8px; padding: 16px; } .paneCard { display: flex; align-items: center; gap: 10px; padding: 10px 12px; border: 1px solid var(--dsw-alias-border-l1); border-radius: 8px; background: var(--dsw-alias-bg-layer-1); color: var(--dsw-alias-label-secondary); font: var(--dsw-font-xxs-strong-12); cursor: pointer; text-align: left; } .paneCard:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); color: var(--dsw-alias-label-primary); border-color: var(--dsw-alias-border-l2); } .paneCard:disabled { opacity: 0.45; cursor: default; } /* ── Tab strip ─────────────────────────────────────────────────────────── */ .tabBar { flex: none; display: flex; align-items: stretch; height: 34px; border-bottom: 1px solid var(--dsw-alias-border-l1); background: var(--dsw-alias-bg-layer-1); } .tabBarDrop { outline: 1px dashed var(--dsw-alias-interactive-bg-hover-accent); outline-offset: -1px; } .tabList { flex: 1; min-width: 0; display: flex; overflow-x: auto; scrollbar-width: none; } .tabList::-webkit-scrollbar { display: none; } .tab { flex: none; max-width: 160px; min-width: 64px; display: flex; align-items: center; gap: 4px; padding: 0 4px 0 10px; font: var(--dsw-font-xxs-12); color: var(--dsw-alias-label-secondary); border-right: 1px solid var(--dsw-alias-border-l1); background: transparent; cursor: pointer; user-select: none; } .tab:hover { background: var(--dsw-alias-interactive-bg-hover); } .tabActive { color: var(--dsw-alias-label-primary); /* Native selected fill (Rows .sessionRow.selected) — no underline, no shadow. */ background: var(--dsw-alias-interactive-bg-active); } .tabTitle { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .tabClose { display: inline-flex; align-items: center; justify-content: center; width: 18px; height: 18px; padding: 0; border: none; border-radius: 4px; background: transparent; color: var(--dsw-alias-label-tertiary); cursor: pointer; flex: none; } .tabClose:hover { background: var(--dsw-alias-interactive-bg-hover); color: var(--dsw-alias-label-primary); } .tabBarPlus { flex: none; align-self: center; /* Adjacent to the rightmost tab; sticky so overflowing tab rows keep it visible at the right edge of the scrollport. */ position: sticky; right: 0; display: inline-flex; align-items: center; justify-content: center; width: 22px; height: 22px; margin: 0 6px; padding: 0; border: none; border-radius: 5px; background: var(--dsw-alias-bg-layer-1); color: var(--dsw-alias-label-tertiary); cursor: pointer; } .tabBarPlus:hover { background: var(--dsw-alias-interactive-bg-hover); color: var(--dsw-alias-label-primary); } /* ── Explorer ──────────────────────────────────────────────────────────── */ .explorer { flex: 1; min-height: 0; display: flex; flex-direction: column; } .explorerHeader { flex: none; display: flex; align-items: center; justify-content: space-between; gap: 8px; height: 36px; padding: 0 8px 0 12px; } .explorerRoot { font: var(--dsw-font-s-14); color: var(--dsw-alias-label-secondary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .explorerBody { flex: 1; min-height: 0; overflow-y: auto; padding: 2px 6px 8px; } /* One tree row: the app's session-row cell (34px, radius 8, inset, hover fill, 22px indent step, 14px ink) with a mount fade so expanding a directory reveals its children gently (stable keys keep existing rows from replaying it). */ .explorerRow { display: flex; align-items: center; gap: 6px; width: 100%; height: 34px; padding: 0 8px; border: none; background: transparent; font: var(--dsw-font-s-14); color: var(--dsw-alias-label-primary); text-align: left; cursor: pointer; white-space: nowrap; border-radius: 8px; animation: dsh-row-in 150ms var(--ds-ease-in-out); } .explorerRow:hover { background: var(--dsw-alias-interactive-bg-hover); } .explorerDir { font: var(--dsw-font-s-strong-14); } .explorerHidden { opacity: 0.45; } .explorerName { overflow: hidden; text-overflow: ellipsis; } /* The hover-revealed @-reference button at the row's far right (and the transient "copied" label that replaces it after a copy). Hidden rows keep the name at full width; hovering or focusing the row reveals it. */ .explorerRef { flex: none; display: none; align-items: center; height: 20px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l1); border-radius: 999px; background: var(--dsw-alias-bg-layer-2); color: var(--dsw-alias-label-tertiary); font: var(--dsw-font-xxxs-strong-11); cursor: pointer; } .explorerRef:hover { background: var(--dsw-alias-interactive-bg-hover); color: var(--dsw-alias-label-primary); } .explorerRow:hover .explorerRef, .explorerRow:focus-within .explorerRef { display: inline-flex; } .explorerCopied { flex: none; font: var(--dsw-font-xxxs-11); color: var(--dsw-alias-label-tertiary); } .explorerError { font: var(--dsw-font-xxs-12); color: var(--dsw-alias-state-error-primary); cursor: default; } /* Mount fade for tree rows (the app's session-row reveal). */ @keyframes dsh-row-in { from { opacity: 0; } } .explorerEmpty { padding: 16px; font: var(--dsw-font-xxs-12); color: var(--dsw-alias-label-tertiary); text-align: center; } /* ── Editor ────────────────────────────────────────────────────────────── */ .editor { flex: 1; min-height: 0; display: flex; flex-direction: column; } .editorHeader { flex: none; display: flex; align-items: center; gap: 6px; padding: 4px 8px; border-bottom: 1px solid var(--dsw-alias-border-l1); } .editorTitle { flex: 1; min-width: 0; font: var(--dsw-font-xxs-strong-12); color: var(--dsw-alias-label-secondary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .editorStatus { font: var(--dsw-font-xxxs-11); color: var(--dsw-alias-label-tertiary); } .editorStatusError { color: var(--dsw-alias-state-error-primary); } .dirtyDot { width: 7px; height: 7px; border-radius: 50%; background: var(--dsw-alias-state-warn-primary); flex: none; } .editorPlaceholder { flex: 1; display: flex; align-items: center; justify-content: center; font: var(--dsw-font-xxs-12); color: var(--dsw-alias-label-tertiary); padding: 16px; text-align: center; } /* The unregistered tab type shown by the orphaned-tab placeholder. */ .orphanedType { display: block; margin-top: 8px; font-size: 12px; opacity: 0.7; overflow-wrap: anywhere; } /* Binary / download-only files (pptx, OLE .doc/.xls/.ppt, unknown binaries): a centered notice plus a download link — the user always gets the file. */ .editorBinary { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; padding: 24px 16px; text-align: center; } .editorBinaryNotice { font: var(--dsw-font-xxs-12); color: var(--dsw-alias-label-tertiary); } .editorDownloadLink { display: inline-flex; align-items: center; gap: 6px; padding: 6px 14px; border: 1px solid var(--dsw-alias-border-l2); border-radius: 6px; background: var(--dsw-alias-bg-layer-2); color: var(--dsw-alias-label-primary); font: var(--dsw-font-xxs-strong-12); text-decoration: none; cursor: pointer; transition: background var(--ds-transition-duration-slow) var(--ds-ease-in-out), border-color var(--ds-transition-duration-slow) var(--ds-ease-in-out); } .editorDownloadLink:hover { background: var(--dsw-alias-interactive-bg-hover); border-color: var(--dsw-alias-border-l2); } .editorError { padding: 12px 16px; font: var(--dsw-font-xxs-12); color: var(--dsw-alias-state-error-primary); } .editorBanner { flex: none; padding: 4px 12px; font: var(--dsw-font-xxxs-11); color: var(--dsw-alias-state-warn-label); background: var(--dsw-alias-state-warn-tertiary); } .editorCm { flex: 1; min-height: 0; overflow: hidden; background: transparent; } .editorCmHidden { display: none; } /* CodeMirror fills the pane; the theme supplies its own token palette (a designed dark theme, same policy as the xterm palette). */ .editorCm :global(.cm-editor) { height: 100%; } .editorCm :global(.cm-editor.cm-focused) { outline: none; } /* Preview / edit segmented toggle (markdown and other previewable files). */ .editorModeToggle { flex: none; display: inline-flex; align-items: center; gap: 2px; padding: 2px; border: 1px solid var(--dsw-alias-border-l1); border-radius: 6px; background: var(--dsw-alias-bg-layer-1); } .editorModeButton { padding: 2px 8px; border: none; border-radius: 4px; background: transparent; color: var(--dsw-alias-label-tertiary); font: var(--dsw-font-xxxs-11); cursor: pointer; } .editorModeButton:hover { color: var(--dsw-alias-label-primary); } .editorModeActive { background: var(--dsw-alias-bg-base); color: var(--dsw-alias-label-primary); } .editorImageWrap { flex: 1; min-height: 0; display: flex; align-items: center; justify-content: center; overflow: auto; padding: 12px; } .editorImage { max-width: 100%; max-height: 100%; object-fit: contain; } .editorMd { flex: 1; min-height: 0; overflow-y: auto; padding: 10px 14px; font: var(--dsw-font-xs-13); } /* Word preview: the document scrolls independently while the zoom control stays pinned to the bottom edge. */ .editorDocx { flex: 1; min-height: 0; display: flex; flex-direction: column; background: var(--dsw-alias-bg-base); } .editorDocxViewport { flex: 1; min-height: 0; display: flex; flex-direction: column; overflow: auto; background: var(--dsw-alias-bg-base); } /* docx-preview renders into a wrapper div with .docx className; the host above scrolls while the wrapper holds the page flow. */ .editorDocxWrap { flex: none; padding: 16px; } .editorDocxZoom { flex: none; display: flex; align-items: center; gap: 8px; min-height: 34px; padding: 4px 10px; border-top: 1px solid var(--dsw-alias-border-l1); background: var(--dsw-alias-bg-layer-1); } .editorDocxZoomHint, .editorDocxZoomValue { flex: none; font: var(--dsw-font-xxxs-11); color: var(--dsw-alias-label-tertiary); } .editorDocxZoomValue { width: 36px; text-align: right; } .editorDocxZoomRange { flex: 1; min-width: 72px; accent-color: var(--dsw-alias-brand-primary); cursor: pointer; } .editorPdf { flex: 1; min-height: 0; display: flex; flex-direction: column; background: var(--dsw-alias-bg-base); } .editorPdfToolbar { flex: none; display: flex; justify-content: flex-end; padding: 6px 8px; border-bottom: 1px solid var(--dsw-alias-border-l1); } .editorPdfStage { position: relative; flex: 1; min-height: 0; display: flex; } .editorPdfFrame { flex: 1; min-height: 0; width: 100%; border: none; background: var(--dsw-alias-bg-base); } .editorPdfFrameBlocked { pointer-events: none; } .editorPdfDragShield { position: absolute; inset: 0; z-index: 4; pointer-events: none; background: transparent; } .editorPdfDragShieldActive { pointer-events: auto; } /* Tab drag must switch iframe hit-testing before the pointer can enter the Chromium PDF browsing context. The body flag is set synchronously by the drag source, avoiding React render timing entirely. */ :global(body[data-dsh-tab-dragging]) .editorPdfFrame { pointer-events: none !important; } :global(body[data-dsh-tab-dragging]) .editorPdfDragShield { pointer-events: auto !important; } .editorXlsx { position: relative; flex: 1; min-height: 0; overflow: hidden; background: var(--dsw-alias-bg-base); } .editorUniverHost { width: 100%; height: 100%; min-width: 0; min-height: 0; } .editorOfficeOverlay { position: absolute; inset: 0; z-index: 2; display: flex; background: var(--dsw-alias-bg-base); } .editorPptx { flex: 1; min-height: 0; display: flex; flex-direction: column; background: var(--dsw-alias-bg-base); } .editorPptxToolbar { flex: none; display: flex; align-items: center; justify-content: center; gap: 8px; padding: 6px 8px; border-bottom: 1px solid var(--dsw-alias-border-l1); } .editorPptxToolbar .editorDownloadLink { margin-left: auto; } .editorPptxButton { height: 28px; padding: 0 10px; border: 1px solid var(--dsw-alias-border-l2); border-radius: 6px; background: var(--dsw-alias-bg-layer-2); color: var(--dsw-alias-label-secondary); font: var(--dsw-font-xxs-strong-12); cursor: pointer; } .editorPptxButton:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); color: var(--dsw-alias-label-primary); } .editorPptxButton:disabled { opacity: 0.4; cursor: default; } .editorPptxPosition { min-width: 64px; text-align: center; font: var(--dsw-font-xxs-12); color: var(--dsw-alias-label-tertiary); } .editorPptxStage { position: relative; flex: 1; min-height: 0; overflow: hidden; } .editorPptxHost { width: 100%; height: 100%; min-width: 0; min-height: 0; overflow: auto; } /* ── Terminal ──────────────────────────────────────────────────────────── */ .terminalWrap { flex: 1; min-height: 0; position: relative; display: flex; flex-direction: column; background: var(--dsw-alias-bg-base); } .terminal { flex: 1; min-height: 0; padding: 6px 4px 6px 8px; } .terminal :global(.xterm) { height: 100%; } .terminalBanner { flex: none; display: flex; align-items: center; flex-wrap: wrap; gap: 8px; padding: 3px 10px; font: var(--dsw-font-xxxs-11); color: var(--dsw-alias-state-warn-label); background: var(--dsw-alias-state-warn-tertiary); } /* The attempted ws URL, shown when the connection failed (diagnosis). */ .terminalBannerUrl { flex-basis: 100%; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; word-break: break-all; opacity: 0.85; } .boundaryError { position: fixed; right: 0; top: 0; bottom: 0; z-index: 50; display: flex; flex-direction: column; gap: 8px; align-items: flex-start; padding: 16px; background: var(--dsw-alias-bg-layer-1); border-left: 1px solid var(--dsw-alias-border-l2); font: var(--dsw-font-xxs-12); color: var(--dsw-alias-state-error-primary); overflow: auto; } .terminalRetry { flex: none; padding: 1px 8px; border: 1px solid var(--dsw-alias-border-l2); border-radius: 999px; background: var(--dsw-alias-bg-layer-2); color: var(--dsw-alias-label-secondary); font: var(--dsw-font-xxxs-strong-11); cursor: pointer; } .terminalRetry:hover { background: var(--dsw-alias-interactive-bg-hover); color: var(--dsw-alias-label-primary); } /* ── Git ───────────────────────────────────────────────────────────────── */ .git { flex: 1; min-height: 0; min-width: 0; display: flex; flex-direction: column; overflow-y: auto; /* Tab pages never scroll horizontally: content wraps or truncates to the panel width instead of panning sideways. */ overflow-x: hidden; } .gitHeader { flex: none; display: flex; align-items: center; gap: 8px; height: 36px; padding: 0 8px 0 12px; } .gitBranchSelect { flex: 1; min-width: 0; height: 26px; padding: 0 6px; border: 1px solid var(--dsw-alias-border-l2); border-radius: 6px; background: var(--dsw-alias-bg-base); color: var(--dsw-alias-label-primary); font: var(--dsw-font-xxs-12); } .gitSection { border-top: 1px solid var(--dsw-alias-border-l1); } .gitSectionHeader { display: flex; align-items: center; justify-content: space-between; padding: 6px 12px 4px; font: var(--dsw-font-xxxs-strong-11); color: var(--dsw-alias-label-tertiary); text-transform: uppercase; } .gitLink { border: none; background: transparent; font: var(--dsw-font-xxxs-11); color: var(--dsw-alias-brand-primary); cursor: pointer; padding: 0; } .gitLink:hover:not(:disabled) { text-decoration: underline; } .gitLink:disabled { opacity: 0.4; cursor: default; } .gitRow { display: flex; align-items: center; gap: 6px; min-height: 34px; margin: 0 6px; padding: 0 8px; border-radius: 8px; animation: dsh-row-in 150ms var(--ds-ease-in-out); } .gitRow:hover { background: var(--dsw-alias-interactive-bg-hover); } .gitRowSelected { background: var(--dsw-alias-interactive-bg-active); } .gitRowMain { flex: 1; min-width: 0; display: flex; align-items: center; gap: 8px; border: none; background: transparent; padding: 3px 0; cursor: pointer; text-align: left; } .gitBadge { flex: none; width: 20px; height: 16px; display: inline-flex; align-items: center; justify-content: center; border-radius: 4px; font: var(--dsw-font-xxxs-strong-11); background: var(--dsw-alias-interactive-bg-hover); color: var(--dsw-alias-label-secondary); } .gitName { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font: var(--dsw-font-s-14); color: var(--dsw-alias-label-primary); } .gitEmpty { padding: 4px 12px 8px; font: var(--dsw-font-xxs-12); color: var(--dsw-alias-label-tertiary); } .gitPlaceholder { padding: 16px; font: var(--dsw-font-xxs-12); color: var(--dsw-alias-label-tertiary); text-align: center; } .gitError { padding: 8px 12px; font: var(--dsw-font-xxs-12); color: var(--dsw-alias-state-error-primary); white-space: pre-wrap; } .gitDiff { border-top: 1px solid var(--dsw-alias-border-l1); padding: 8px; } /* The diff tab (a change opened from the git panel, like VSCode's diff editor): header + scrollable diff body, no horizontal panning. */ .gitDiffTab { flex: 1; min-height: 0; min-width: 0; display: flex; flex-direction: column; overflow-y: auto; overflow-x: hidden; } .gitDiffTabHeader { flex: none; display: flex; align-items: center; gap: 8px; height: 36px; padding: 0 8px 0 12px; border-bottom: 1px solid var(--dsw-alias-border-l1); } .gitDiffTabTitle { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font: var(--dsw-font-xxs-strong-12); color: var(--dsw-alias-label-primary); } /* One changed file's section: path header, hunk headers, aligned lines. */ .gitDiffFile { display: flex; align-items: baseline; gap: 6px; padding: 8px 2px 2px; } .gitDiffFilePath { font: var(--dsw-font-xxs-strong-12); color: var(--dsw-alias-label-primary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .gitDiffFileOld { flex: none; font: var(--dsw-font-xxxs-11); color: var(--dsw-alias-label-tertiary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 40%; } .gitDiffFileTag { flex: none; padding: 0 6px; border: 1px solid var(--dsw-alias-border-l2); border-radius: 999px; font: var(--dsw-font-xxxs-strong-11); color: var(--dsw-alias-label-secondary); } .gitDiffHunk { display: flex; gap: 8px; padding: 3px 2px; font: var(--dsw-font-markdown-code-block-small); color: var(--dsw-alias-label-tertiary); } .gitDiffHunkHeader { flex: none; color: var(--dsw-alias-label-secondary); } .gitDiffHunkSection { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } /* One aligned diff line: old gutter / new gutter / code. Lines WRAP instead of scrolling horizontally (the tab-page rule: fill the width adaptively), with the long-token fallback breaking anywhere a space never comes. */ .gitDiffLine { display: flex; align-items: stretch; font: var(--dsw-font-markdown-code-block-small); line-height: 20px; white-space: pre-wrap; overflow-wrap: anywhere; min-width: 0; } .gitDiffNum { flex: none; width: 36px; padding-right: 8px; text-align: right; color: var(--dsw-alias-label-tertiary); user-select: none; } .gitDiffCode { flex: 1; min-width: 0; overflow: visible; } .gitDiffCtx { color: var(--dsw-alias-label-primary); } .gitDiffDel { color: var(--dsw-alias-state-error-primary); background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 12%, transparent); } .gitDiffAdd { color: var(--dsw-alias-state-success-primary); background: color-mix(in srgb, var(--dsw-alias-state-success-primary) 12%, transparent); } .gitDiffMeta { padding-left: 2px; } .gitDiffMetaText { font: var(--dsw-font-xxxs-11); font-style: italic; color: var(--dsw-alias-label-tertiary); } .gitDiffExpand { display: block; width: 100%; margin: 4px 0; border: none; background: transparent; font: var(--dsw-font-xxs-12); color: var(--dsw-alias-brand-primary); cursor: pointer; text-align: center; } .gitDiffExpand:hover { background: var(--dsw-alias-interactive-bg-hover); } .gitConfirmDesc { margin: 0; font: var(--dsw-font-s-14); color: var(--dsw-alias-label-primary); white-space: pre-wrap; } .gitCommit { display: flex; gap: 6px; padding: 8px 12px; border-top: 1px solid var(--dsw-alias-border-l1); align-items: center; } .gitCommitInput { flex: 1; min-width: 0; } .gitCommitButton { flex: none; height: 26px; padding: 0 12px; border: none; border-radius: 6px; background: var(--dsw-alias-button-primary-fill); color: var(--dsw-alias-label-primary-inverted); font: var(--dsw-font-xxs-strong-12); cursor: pointer; } .gitCommitButton:hover:not(:disabled) { background: var(--dsw-alias-button-primary-hover); } .gitCommitButton:disabled { opacity: 0.45; cursor: default; } /* A history row: line 1 = hash + subject, line 2 = ref badges + author/date (badges live on the second line so they never crowd the subject). */ .gitLogRow { display: flex; flex-direction: column; gap: 2px; padding: 5px 12px; cursor: pointer; border-radius: 8px; } .gitLogRow:hover { background: var(--dsw-alias-interactive-bg-hover); } .gitLogLine1 { display: flex; align-items: baseline; gap: 8px; min-width: 0; } .gitLogHash { flex: none; font: var(--dsw-font-markdown-code-block-small); color: var(--dsw-alias-label-tertiary); } .gitLogLine2 { display: flex; align-items: center; gap: 6px; min-width: 0; flex-wrap: wrap; } .gitLogRef { flex: none; padding: 0 5px; border: 1px solid var(--dsw-alias-border-l2); border-radius: 999px; font: var(--dsw-font-xxxs-strong-11); color: var(--dsw-alias-brand-primary); white-space: nowrap; } .gitLogSubject { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font: var(--dsw-font-s-14); color: var(--dsw-alias-label-primary); } .gitLogMeta { font: var(--dsw-font-xxxs-11); color: var(--dsw-alias-label-tertiary); } .gitLogMore { display: block; width: calc(100% - 24px); margin: 4px 12px 8px; padding: 6px 0; border: 1px solid var(--dsw-alias-border-l2); border-radius: 6px; background: transparent; font: var(--dsw-font-xxs-12); color: var(--dsw-alias-label-secondary); cursor: pointer; } .gitLogMore:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); color: var(--dsw-alias-label-primary); } .gitLogMore:disabled { opacity: 0.5; cursor: default; } /* ── Intercepted produced-files row ────────────────────────────────────── */ .producedRow { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; padding: 4px 0; } .producedLabel { font: var(--dsw-font-xxs-12); color: var(--dsw-alias-label-tertiary); } .producedChip { display: inline-flex; align-items: center; gap: 4px; max-width: 200px; padding: 2px 8px; border: 1px solid var(--dsw-alias-border-l2); border-radius: 999px; background: var(--dsw-alias-bg-layer-2); color: var(--dsw-alias-label-secondary); font: var(--dsw-font-xxs-12); cursor: pointer; overflow: hidden; } .producedChip:hover { background: var(--dsw-alias-interactive-bg-hover); color: var(--dsw-alias-label-primary); } .producedChip span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .producedMore { font: var(--dsw-font-xxs-12); color: var(--dsw-alias-label-tertiary); } /* ── Shared interaction rules ──────────────────────────────────────────── */ /* Keyboard focus stays visible on every interactive control (the styling policy requires focus visibility; the accent token doubles as the ring). */ .toggleButton:focus-visible, .iconButton:focus-visible, .tab:focus-visible, .tabClose:focus-visible, .tabBarPlus:focus-visible, .paneCard:focus-visible, .explorerRow:focus-visible, .explorerRef:focus-visible, .gitRowMain:focus-visible, .gitLink:focus-visible, .gitCommitButton:focus-visible, .gitLogRow:focus-visible, .gitLogMore:focus-visible, .gitDiffExpand:focus-visible, .terminalRetry:focus-visible, .editorModeButton:focus-visible, .editorDownloadLink:focus-visible, .editorPptxButton:focus-visible, .editorDocxZoomRange:focus-visible { outline: 2px solid var(--dsw-alias-interactive-bg-hover-accent); outline-offset: -1px; } /* Reduced motion: no slides, fades or color transitions. */ @media (prefers-reduced-motion: reduce) { .panel, .panelHidden, .toggleButton, .tab, .tabBarPlus, .paneCard, .explorerRow, .gitRow, .divider, .dividerRow::after, .dividerCol::after { transition: none; animation: none; } }