- 新 src/client/builtins/ 目录:tabs.tsx(6 个 tab descriptor + TERMINAL_LIMIT/uiTerminalCount,terminal 配额知识离开 state.ts)、 viewers.tsx(8 个 viewer descriptor)、index.ts(registerBuiltins 聚合 注册 + 幂等 disposer);删除旧 builtins.tsx - icons.tsx:删除零调用者的 tabTypeIcon 及多余 import(图标已归 descriptor.icon,映射随 tab 类型一起注册化) - OrphanedTab:内联 style → sidebar.module.css 新增 .orphanedType 类 - 新增 tests/builtins.spec.ts(6 tab + 8 viewer 注册断言、code catch-all、 binary-download NUL detect、office 优先级、disposer 幂等) - 新增 tests/orphaned-tab.spec.tsx(sanitize 保留未注册类型 tab、 OrphanedTab 占位渲染);tests/browser-globals.ts 供拉入 xterm/ CodeMirror 的 spec 首个 import(模块求值期需要 self/document/navigator) - service.spec 补 openDiffTab 与 diff dedupeKey 一致性用例
1575 lines
32 KiB
CSS
1575 lines
32 KiB
CSS
/**
|
|
* 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;
|
|
}
|
|
}
|