71e93e6
/* The workspace uses one visual language across every feature and overlay. */
.workspace-shell,
.workspace-overlay {
--primary: var(--shell-action);
--primary-foreground: #fff;
--foreground: var(--shell-ink);
--card: var(--shell-surface);
--muted: var(--shell-field);
--muted-foreground: var(--shell-ink-muted);
--border: var(--shell-hairline);
--ring: var(--shell-focus);
color: var(--shell-ink);
font-size: 14px;
line-height: 1.6;
}
.workspace-shell {
--nav-rail: 76px;
--nav-side: 280px;
--nav-motion: 230ms;
--nav-ease: cubic-bezier(0.22, 0.68, 0.28, 1);
display: flex;
width: 100%;
height: 100dvh;
overflow: hidden;
background: var(--shell-sidebar);
}
/*
* Collapsing the sidebar animates the width of the navigation column and
* clips it, instead of toggling `display: none` on the sidebar. The sidebar
* keeps its own width inside that clip, so its contents never reflow while
* the column closes — only the main column relayouts, which it must anyway.
*/
.workspace-navigation {
display: flex;
flex-direction: column;
flex-shrink: 0;
overflow: hidden;
width: calc(var(--nav-rail) + var(--nav-side));
background: linear-gradient(to right, var(--shell-rail) 0 var(--nav-rail), var(--shell-sidebar) var(--nav-rail) 100%);
transition: width var(--nav-motion) var(--nav-ease);
}
.workspace-navigation-columns {
display: flex;
flex: 1;
min-height: 0;
}
.workspace-rail {
display: flex;
width: var(--nav-rail);
flex-shrink: 0;
flex-direction: column;
align-items: center;
gap: 14px;
overflow-y: auto;
padding: 20px 0;
background: var(--shell-rail);
}
.workspace-sidebar {
display: flex;
flex-direction: column;
width: var(--nav-side);
border-right: 1px solid var(--shell-hairline);
background: var(--shell-sidebar);
transition:
opacity calc(var(--nav-motion) * 0.45) ease calc(var(--nav-motion) * 0.4),
visibility 0s;
}
.workspace-sidebar-header {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
min-height: 76px;
padding: 14px 20px;
border-bottom: 1px solid var(--shell-hairline);
}
.workspace-sidebar-header > div {
min-width: 0;
}
/* The community header borrows Discord's compact-cover treatment: a real
* uploaded banner when available, a stable colour cover otherwise, and the
* community identity kept legible over both. */
.workspace-sidebar-header:has(.space-community-header) {
position: relative;
align-items: stretch;
min-height: 132px;
padding: 0;
gap: 0;
}
.workspace-sidebar-header:has(.space-community-header) > .space-community-header {
width: 100%;
}
.workspace-sidebar-header:has(.space-community-header) .workspace-drawer-close {
position: absolute;
z-index: 42;
top: 10px;
right: 10px;
color: #fff;
background: rgb(10 14 24 / 28%);
backdrop-filter: blur(8px);
}
.workspace-sidebar-header:has(.space-community-header) .workspace-drawer-close:hover {
color: #fff;
background: rgb(10 14 24 / 50%);
}
.space-community-header {
position: relative;
z-index: 1;
min-width: 0;
min-height: 132px;
isolation: isolate;
}
.space-community-banner {
position: absolute;
inset: 0;
z-index: -1;
overflow: hidden;
background:
radial-gradient(132px 88px at 8% -14%, hsl(var(--space-banner-hue) 94% 82% / 88%), transparent 72%),
radial-gradient(142px 112px at 104% 2%, hsl(calc(var(--space-banner-hue) + 46) 78% 58% / 90%), transparent 72%),
linear-gradient(145deg, hsl(var(--space-banner-hue) 62% 42%), hsl(calc(var(--space-banner-hue) + 26) 70% 27%));
}
.space-community-banner::before,
.space-community-banner::after {
position: absolute;
inset: 0;
content: "";
pointer-events: none;
}
.space-community-banner::before {
background: linear-gradient(
116deg,
rgb(255 255 255 / 14%) 0 12%,
transparent 12% 42%,
rgb(255 255 255 / 9%) 42% 52%,
transparent 52%
);
mix-blend-mode: soft-light;
}
.space-community-banner::after {
background: linear-gradient(180deg, rgb(8 12 20 / 4%) 0%, rgb(8 12 20 / 15%) 44%, rgb(8 12 20 / 74%) 100%);
}
.space-community-banner > img {
width: 100%;
height: 100%;
object-fit: cover;
transform: scale(1.02);
}
.space-community-menu-trigger {
position: relative;
z-index: 1;
display: flex;
width: 100%;
min-height: 132px;
align-items: flex-end;
gap: 10px;
padding: 15px 16px;
color: #fff;
text-align: left;
text-shadow: 0 1px 2px rgb(0 0 0 / 40%);
transition: background 160ms;
}
.space-community-menu-trigger:hover,
.space-community-menu-trigger[aria-expanded="true"] {
background: rgb(7 10 16 / 15%);
}
.space-community-avatar {
display: grid;
width: 42px;
height: 42px;
flex: 0 0 auto;
place-items: center;
overflow: hidden;
border: 2px solid rgb(255 255 255 / 74%);
border-radius: 13px;
background: rgb(255 255 255 / 18%);
box-shadow: 0 3px 12px rgb(0 0 0 / 28%);
font-size: 17px;
font-weight: 700;
text-shadow: none;
}
.space-community-avatar > img {
width: 100%;
height: 100%;
object-fit: cover;
}
.space-community-name {
display: block;
overflow: hidden;
color: #fff;
font-size: 15px;
font-weight: 700;
line-height: 1.2;
text-overflow: ellipsis;
white-space: nowrap;
}
.space-community-members {
display: inline-flex;
align-items: center;
min-height: 18px;
margin-top: 4px;
padding: 1px 6px;
border: 1px solid rgb(255 255 255 / 20%);
border-radius: 999px;
background: rgb(255 255 255 / 16%);
color: rgb(255 255 255 / 92%);
font-size: 10px;
font-weight: 700;
line-height: 1;
text-shadow: none;
}
.space-community-members:hover {
background: rgb(255 255 255 / 28%);
}
.space-community-menu-trigger svg {
color: rgb(255 255 255 / 88%);
}
.workspace-nav-caption {
display: flex;
align-items: center;
justify-content: space-between;
padding: 18px 16px 8px 20px;
color: var(--shell-ink-muted);
font-size: 12px;
font-weight: 600;
letter-spacing: 0.06em;
}
.workspace-nav-pinned {
flex-shrink: 0;
padding: 10px 12px 2px;
}
.workspace-nav {
flex: 1;
overflow-y: auto;
padding: 0 12px 20px;
}
/* User bar at the foot of the navigation column: docked into the bottom-left
corner, floating clear of the rail above and of the channel list on its
right — the space it leaves shows the rail and sidebar surfaces as-is. */
.workspace-navigation-footer {
display: flex;
min-height: 60px;
flex-shrink: 0;
align-items: center;
gap: 10px;
margin: 8px 8px 0 0;
padding: 12px 16px;
border-top-right-radius: 12px;
background: var(--shell-surface);
box-shadow: var(--shell-shadow);
}
.workspace-main {
position: relative;
display: flex;
flex: 1;
min-width: 0;
min-height: 0;
flex-direction: column;
background: var(--shell-surface);
}
.workspace-main:focus {
outline: none;
}
.workspace-icon-button {
display: inline-flex;
align-items: center;
justify-content: center;
width: 36px;
height: 36px;
flex-shrink: 0;
border-radius: 10px;
color: var(--shell-ink-muted);
transition:
background 160ms,
color 160ms;
}
.workspace-icon-button:hover {
background: var(--shell-active);
color: var(--shell-ink);
}
/* Three footer controls instead of two: the row tightens to keep the name legible. */
.workspace-icon-button.is-compact {
width: 32px;
height: 32px;
border-radius: 9px;
}
/* A toggle that is "off" (muted microphone, deafened headphones) reads red. */
.workspace-icon-button.is-off {
color: var(--error-foreground);
background: color-mix(in srgb, var(--destructive) 14%, transparent);
}
.workspace-icon-button.is-off:hover {
background: color-mix(in srgb, var(--destructive) 22%, transparent);
color: var(--error-foreground);
}
.workspace-collapse {
width: 28px;
height: 28px;
}
.workspace-expand {
position: absolute;
z-index: 15;
top: 20px;
left: 14px;
background: var(--shell-field);
opacity: 0;
visibility: hidden;
transform: translateX(-8px) scale(0.94);
transition:
opacity 120ms ease,
transform 180ms ease,
background 160ms,
color 160ms,
visibility 0s linear 120ms;
}
.navigation-collapsed .workspace-expand {
opacity: 1;
visibility: visible;
transform: none;
transition:
opacity 180ms ease calc(var(--nav-motion) * 0.5),
transform 300ms var(--nav-ease) calc(var(--nav-motion) * 0.45),
background 160ms,
color 160ms,
visibility 0s;
}
/*
* Directory column (explore): the rail is the whole navigation, so the space
* sidebar is dropped and the navigation column narrows to the rail width. The
* mobile drawer keeps the same rule; there is nothing behind it to open.
*/
.rail-only .workspace-navigation {
width: var(--nav-rail);
}
.rail-only .workspace-sidebar {
display: none;
}
.navigation-collapsed .workspace-navigation {
width: var(--nav-rail);
}
.navigation-collapsed .workspace-sidebar {
opacity: 0;
visibility: hidden;
transition:
opacity calc(var(--nav-motion) * 0.45) ease,
visibility 0s linear calc(var(--nav-motion) * 0.45);
}
.navigation-collapsed .workspace-navigation-footer,
.rail-only .workspace-navigation-footer {
display: none;
}
/*
* The collapsed-nav expand button floats over the top-left of the content
* column, so the bar underneath it reserves that gutter. The button is
* `main`'s own first child, which rules out a structural `first-child`
* match, and the chat header sits four levels deep — so the two bars that
* can lead the column are named here.
*/
.workspace-main :is(.shell-top-bar, .chat-header) {
transition: padding-left var(--nav-motion) var(--nav-ease);
}
.navigation-collapsed .workspace-main :is(.shell-top-bar, .chat-header) {
padding-left: 64px;
}
/*
* The global search box is a fixed overlay pinned to the top-right of the
* window, so every bar that can lead the content column reserves a gutter for
* it — otherwise it sits on top of the bar's own actions. Below `lg` the
* overlay collapses to its icon, so the gutter stays small enough that the bar
* keeps a usable title. The overlay also centres on the bar's own height
* (76px, 36px box), so it never drifts off the bar's optical centre line.
*/
@media (min-width: 768px) {
.workspace-main :is(.shell-top-bar, .chat-header) {
padding-right: 64px;
}
}
@media (min-width: 1024px) {
.workspace-main :is(.shell-top-bar, .chat-header) {
padding-right: calc(clamp(200px, 22vw, 300px) + 28px);
}
}
/*
* An open chat panel owns the same top-right corner, so the overlay steps left
* by the panel's live width — otherwise it lands inside a resized detail pane.
* Below 1201px the panel is a modal drawer behind a scrim, and the trigger
* hides with the page it covers.
*/
@media (max-width: 1200px) {
body:has(.chat-side-panel) .global-search-trigger {
display: none;
}
}
@media (min-width: 1201px) {
body:has(.chat-side-panel) .global-search-trigger {
right: calc(var(--global-chat-panel-width, 380px) + 16px);
}
}
/*
* A docked detail pane pulls the search box off the window corner and into the
* chat column, so the header has to reserve the field's gutter. Below the width
* that can host both, that reservation starved the very header it floats over —
* at a 1243px window the column is 539px, the gutter took 302px of it and the
* title collapsed to zero width, stacking the topic one character per line in a
* 300px-tall bar. Under that width the trigger renders as its icon only (same
* affordance as the bar's other actions, still opens the palette on click) and
* the header reserves just the icon.
*/
@media (min-width: 1201px) and (max-width: 1599px) {
body:has(.chat-side-panel) .global-search-trigger {
width: 36px;
justify-content: center;
padding-inline: 0;
}
body:has(.chat-side-panel) .global-search-trigger > :is(span, kbd) {
display: none;
}
body:has(.chat-side-panel) .workspace-main .chat-header {
padding-right: 64px;
}
}
@media (min-width: 1201px) {
/* A custom-width detail pane becomes the reading focus. Hide the global
* command until that pane closes, and release its former header gutter.
* Declared after the width ladder above so it wins at every width. */
body:has(.chat-panel-resized) .global-search-trigger {
display: none;
}
body:has(.chat-panel-resized) .workspace-main .chat-header {
padding-right: 24px;
}
}
.global-search-overlay {
animation: global-search-fade 140ms ease-out both;
}
.global-search-dialog {
animation: global-search-pop 180ms cubic-bezier(0.2, 0.8, 0.2, 1) both;
transform-origin: 50% 0;
}
@keyframes global-search-fade {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes global-search-pop {
from {
opacity: 0;
transform: translateY(-10px) scale(0.985);
}
to {
opacity: 1;
transform: translateY(0) scale(1);
}
}
@media (prefers-reduced-motion: reduce) {
.global-search-overlay,
.global-search-dialog {
animation: none;
}
}
.workspace-mobile-bar,
.workspace-drawer-close,
.workspace-scrim {
display: none;
}
.workspace-skip {
position: fixed;
left: 12px;
top: -80px;
z-index: 100;
padding: 10px 16px;
border-radius: 10px;
color: white;
background: var(--shell-action);
}
.workspace-skip:focus {
top: 12px;
}
.shell-top-bar {
display: flex;
align-items: center;
gap: 12px;
min-height: 76px;
flex-shrink: 0;
padding: 14px 24px;
border-bottom: 1px solid var(--shell-hairline);
}
.shell-top-icon {
display: grid;
place-items: center;
width: 38px;
height: 38px;
flex-shrink: 0;
border-radius: 12px;
color: var(--shell-ink);
background: transparent;
}
.shell-top-icon svg {
color: inherit;
}
.shell-top-actions {
display: flex;
flex-shrink: 0;
align-items: center;
gap: 10px;
color: var(--shell-ink-muted);
}
.workspace-nav-row {
position: relative;
min-height: 32px;
margin-bottom: 2px;
gap: 10px;
border-radius: 8px;
transition:
background 160ms,
color 160ms;
}
.workspace-nav-row:is(a, button, [data-kind="folder"]):hover {
background: var(--shell-active);
}
/* Selected rows sit two shades below the hover gray instead of flipping to white. */
.workspace-nav-row[aria-current="page"] {
color: var(--shell-ink);
background: color-mix(in srgb, var(--shell-ink) 4%, var(--shell-tile));
font-weight: 600;
}
.workspace-nav-row[aria-current="page"] > span:first-child {
color: var(--shell-ink-muted);
}
.workspace-nav-row[data-kind="folder"] {
margin-top: 12px;
}
/* Rail tiles rest as circles and square off on hover or when they own the route. */
.workspace-rail a,
.workspace-rail button {
border-radius: 9999px;
transition:
background 160ms,
color 160ms,
border-color 160ms,
border-radius 200ms,
box-shadow 160ms;
}
.workspace-rail a:hover,
.workspace-rail button:hover,
.workspace-rail a[aria-current="page"] {
border-radius: 16px;
}
.workspace-rail a[aria-current="page"] {
color: var(--shell-ink);
}
/* The dashed create / discover ring follows the same morph, without changing its fill. */
.rail-dashed-ring-shape {
rx: 22px;
transition: rx 200ms;
}
.workspace-rail a:hover .rail-dashed-ring-shape,
.workspace-rail button:hover .rail-dashed-ring-shape,
.workspace-rail a[aria-current="page"] .rail-dashed-ring-shape {
rx: 14px;
}
/* Keyboard focus for controls. */
.workspace-shell :is(button, a, summary, [role="button"], [role="option"]):focus-visible,
.workspace-overlay :is(button, a, summary, [role="button"], [role="option"]):focus-visible {
outline: 2px solid color-mix(in srgb, var(--shell-focus) 70%, transparent);
outline-offset: 2px;
}
/*
* Fields: one hairline, real corners, and a soft ring on focus. The 2px
* near-black frame these used to get read as an error state rather than a
* focused input, and the bare `<input>` inside an icon row has no radius of
* its own, so the browser outline drew square corners.
*/
.workspace-shell :is(input, select, textarea):not([type="checkbox"]):not([type="radio"]):not(.bg-transparent),
.workspace-overlay :is(input, select, textarea):not([type="checkbox"]):not([type="radio"]):not(.bg-transparent) {
border-width: 1px;
border-radius: 9px;
}
.workspace-shell :is(input, select, textarea):not(.bg-transparent):focus,
.workspace-overlay :is(input, select, textarea):not(.bg-transparent):focus {
border-color: var(--shell-tile);
outline: none;
box-shadow: 0 0 0 3px color-mix(in srgb, var(--shell-focus) 20%, transparent);
}
.workspace-shell :is(input, select, textarea):not(.bg-transparent):hover:not(:focus),
.workspace-overlay :is(input, select, textarea):not(.bg-transparent):hover:not(:focus) {
border-color: color-mix(in srgb, var(--shell-tile) 70%, var(--shell-hairline));
}
/* A transparent field is bare: its rounded wrapper owns the border and ring. */
.workspace-shell .bg-transparent:focus-visible,
.workspace-overlay .bg-transparent:focus-visible {
outline: none;
}
.workspace-shell :is(button, [role="button"]):not(:disabled),
.workspace-overlay :is(button, [role="button"]):not(:disabled) {
cursor: pointer;
touch-action: manipulation;
}
.workspace-shell :is(button, input, select, textarea),
.workspace-overlay :is(button, input, select, textarea) {
font-family: inherit;
}
.workspace-shell .bg-primary.font-mono,
.workspace-overlay .bg-primary.font-mono {
font-family: var(--font-sans);
letter-spacing: normal;
}
.workspace-shell ::selection,
.workspace-overlay ::selection {
background: var(--shell-active);
color: var(--shell-ink);
}
.workspace-shell *,
.workspace-overlay * {
scrollbar-width: thin;
scrollbar-color: var(--shell-tile) transparent;
}
.workspace-overlay {
background: rgb(18 20 22 / 46%);
backdrop-filter: blur(5px);
}
.workspace-dialog {
max-height: calc(100dvh - 32px);
overflow-y: auto;
border: 1px solid var(--shell-hairline);
border-radius: 20px;
padding: 28px;
box-shadow: 0 24px 80px rgb(15 17 19 / 20%);
}
.workspace-dialog h2 {
font-size: 20px;
line-height: 1.4;
}
.workspace-dialog :is(input, select, textarea) {
border-width: 1px;
border-radius: 10px;
font-size: 14px;
}
.workspace-dialog :is(input:not([type="checkbox"]), select) {
min-height: 42px;
}
.workspace-dialog .dialog-close {
display: grid;
place-items: center;
width: 32px;
height: 32px;
border-radius: 10px;
background: var(--shell-field);
}
.settings-dialog {
display: flex;
position: relative;
width: min(1320px, calc(100vw - 3rem));
height: min(860px, calc(100dvh - 3rem));
overflow: hidden;
border: 1px solid var(--shell-hairline);
border-radius: 18px;
background: var(--shell-surface);
box-shadow: 0 24px 80px rgb(15 17 19 / 22%);
}
.settings-nav {
display: flex;
width: 264px;
flex-shrink: 0;
flex-direction: column;
gap: 2px;
overflow-y: auto;
padding: 16px 12px 20px;
background: var(--shell-sidebar);
border-right: 1px solid var(--shell-hairline);
}
.settings-nav-body {
display: flex;
min-height: 0;
flex: 1;
flex-direction: column;
gap: 2px;
}
.settings-nav-title {
padding: 8px 10px 12px;
font-size: 16px;
font-weight: 700;
color: var(--shell-ink);
}
.settings-nav-caption {
padding: 14px 10px 4px;
font-size: 11px;
font-weight: 700;
letter-spacing: 0.06em;
color: var(--shell-ink-muted);
}
.settings-nav-item {
display: flex;
width: 100%;
min-height: 36px;
align-items: center;
gap: 10px;
padding: 7px 10px;
border-radius: 8px;
color: var(--shell-ink-muted);
font-size: 14px;
text-align: left;
transition:
background 160ms,
color 160ms;
}
.settings-nav-item:hover {
background: var(--shell-active);
color: var(--shell-ink);
}
.settings-nav-item[aria-current="page"] {
background: var(--shell-active);
color: var(--shell-ink);
font-weight: 600;
}
/* Destructive sections read red wherever they sit in a settings nav. */
.settings-nav-item.settings-nav-danger,
.settings-nav-item.settings-nav-danger[aria-current="page"] {
color: #f23f43;
}
.settings-nav-item.settings-nav-danger:hover {
background: color-mix(in srgb, #f23f43 10%, transparent);
color: #f23f43;
}
.settings-pane {
display: flex;
flex: 1;
min-width: 0;
flex-direction: column;
}
.settings-pane-header {
display: flex;
min-height: 60px;
align-items: center;
justify-content: space-between;
gap: 12px;
padding: 10px 16px 10px 28px;
border-bottom: 1px solid var(--shell-hairline);
}
.settings-pane-header h2 {
min-width: 0;
overflow: hidden;
font-size: 17px;
font-weight: 700;
text-overflow: ellipsis;
white-space: nowrap;
}
.settings-content {
flex: 1;
min-width: 0;
min-height: 0;
overflow-y: auto;
scrollbar-gutter: stable;
padding: 32px 40px 56px;
}
.settings-content > section {
max-width: 720px;
}
/* Swapped panes cross-fade in place: no movement, no empty flash. */
.settings-swap {
position: relative;
}
.settings-swap-out {
position: absolute;
top: 0;
left: 0;
right: 0;
pointer-events: none;
animation: settings-swap-out 200ms ease both;
}
.settings-swap-in {
animation: settings-swap-in 200ms ease both;
}
@keyframes settings-swap-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes settings-swap-out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
/* The pane header already names the section, so the body keeps only its note. */
.settings-content > section > .settings-section-head > h2 {
display: none;
}
.settings-content :is(input, select, textarea) {
border-width: 1px;
border-radius: 10px;
min-height: 40px;
font-size: 14px;
}
.settings-content input[type="checkbox"] {
min-height: 0;
}
.settings-close {
flex-shrink: 0;
background: var(--shell-field);
}
/*
* Settings lists (user / space / repo): one card per entry, its inline editor
* revealed below. Surfaces stay neutral — selection is shown by weight and a
* hairline, never by a tint, so a page of rows does not turn into a colour chart.
*/
.settings-row {
display: flex;
min-width: 0;
align-items: center;
gap: 12px;
}
/*
* A card is filled rather than outlined onto the same colour as the dialog, so
* its padding reads as part of the container. Everything inside steps back up
* to the dialog surface, and `--muted` is remapped so a secondary button keeps
* a hover state darker than the card instead of the same colour as it.
*/
.settings-card {
--card: var(--shell-surface);
--muted: var(--shell-active);
--input: var(--shell-tile);
border: 1px solid var(--shell-hairline);
border-radius: 14px;
background: var(--shell-field);
}
.settings-card > .settings-row {
padding: 12px 14px;
}
.settings-card :is(input, select, textarea):not([type="color"]) {
background: var(--shell-surface);
}
.settings-card .settings-chip {
background: var(--shell-surface);
}
.settings-card .settings-segment-group {
background: var(--shell-active);
}
.settings-card .settings-segment[aria-pressed="true"] {
background: var(--shell-surface);
}
.settings-card .settings-facts code {
background: var(--shell-surface);
}
.settings-card.is-danger {
border-color: color-mix(in srgb, #f23f43 45%, var(--shell-hairline));
background: color-mix(in srgb, #f23f43 7%, var(--shell-field));
padding: 16px;
}
.settings-subpanel {
padding: 14px 14px 16px;
border-top: 1px solid var(--shell-hairline);
}
.settings-subpanel.is-flat {
border-top: 0;
}
.settings-disclose {
display: inline-flex;
align-items: center;
gap: 4px;
padding: 4px 9px;
border-radius: 8px;
color: var(--shell-ink-muted);
font-size: 12.5px;
transition:
background 160ms,
color 160ms;
}
.settings-disclose:hover {
color: var(--shell-ink);
background: color-mix(in srgb, var(--shell-ink) 8%, transparent);
}
.settings-disclose svg {
transition: transform 180ms;
}
.settings-segment-group {
display: inline-flex;
gap: 2px;
padding: 2px;
border-radius: 10px;
background: var(--shell-field);
}
.settings-segment {
min-height: 28px;
padding: 3px 10px;
border-radius: 8px;
color: var(--shell-ink-muted);
font-size: 12.5px;
transition:
background 160ms,
color 160ms,
box-shadow 160ms;
}
.settings-segment:hover:not(:disabled) {
color: var(--shell-ink);
}
.settings-segment[aria-pressed="true"] {
color: var(--shell-ink);
font-weight: 600;
background: var(--shell-surface);
box-shadow: inset 0 0 0 1px var(--shell-hairline);
}
.settings-segment:disabled {
opacity: 0.55;
}
.settings-chip {
padding: 4px 10px;
border: 1px solid var(--shell-hairline);
border-radius: 999px;
background: var(--shell-field);
color: var(--shell-ink-muted);
font-size: 12px;
transition:
border-color 160ms,
background 160ms,
color 160ms;
}
.settings-chip:hover {
color: var(--shell-ink);
}
.settings-chip.is-on {
color: var(--shell-ink);
font-weight: 600;
background: var(--shell-surface);
border-color: var(--shell-ink-muted);
}
.settings-facts {
display: grid;
gap: 9px;
margin: 0;
}
.settings-facts > div {
display: flex;
flex-wrap: wrap;
align-items: baseline;
gap: 10px;
}
.settings-facts dt {
width: 96px;
flex-shrink: 0;
color: var(--shell-ink-muted);
font-size: 12px;
}
.settings-facts dd {
display: flex;
align-items: center;
gap: 8px;
margin: 0;
font-size: 13px;
}
.settings-facts code {
padding: 2px 6px;
border-radius: 5px;
background: var(--shell-field);
font-family: var(--font-mono);
font-size: 11.5px;
}
.settings-danger-btn {
background: #f23f43;
color: #fff;
}
.settings-danger-btn:hover {
background: color-mix(in srgb, #f23f43 88%, #000);
}
.board-toolbar {
padding: 16px 24px;
gap: 12px;
border-bottom: 1px solid var(--shell-hairline);
}
.board-canvas {
min-height: 0;
padding: 20px 24px;
background: var(--shell-field);
}
.board-track {
gap: 18px;
}
.repo-toolbar {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 12px;
padding: 12px 24px 0;
border-bottom: 1px solid var(--shell-hairline);
}
.repo-toolbar-refs {
display: flex;
min-width: 0;
flex-shrink: 0;
flex-wrap: wrap;
gap: 8px;
}
.repo-toolbar-clone {
display: flex;
flex-shrink: 0;
align-items: center;
gap: 8px;
}
.repo-toolbar-clone.empty .repo-overview-toggle {
margin-left: auto;
}
.repo-toolbar-tabs {
display: flex;
min-width: 0;
max-width: 100%;
align-items: center;
overflow-x: auto;
padding-left: 12px;
border-left: 1px solid var(--shell-hairline);
overscroll-behavior-x: contain;
scrollbar-width: none;
}
.repo-toolbar-tabs::-webkit-scrollbar {
display: none;
}
.repo-toolbar-tabs > nav {
flex: 0 0 auto;
}
.repo-content-layout {
display: flex;
flex: 1;
min-height: 0;
gap: 24px;
padding: 16px 24px 24px;
background: var(--shell-field);
}
.repo-content-layout > aside {
width: 260px;
}
.repo-overview-toggle {
display: none;
}
@media (max-width: 1200px) {
.workspace-shell {
--nav-rail: 68px;
--nav-side: 224px;
}
.repo-content-layout > aside {
display: none;
}
.repo-toolbar-tabs {
padding-left: 0;
border-left: 0;
}
.repo-content-layout.overview-open > aside {
display: block;
width: 260px;
}
.repo-overview-toggle {
display: flex;
}
}
/* Appearance picker: swatch cards for the base64-persisted palettes. */
.palette-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(128px, 1fr));
gap: 8px;
}
.palette-card {
display: flex;
flex-direction: column;
gap: 5px;
padding: 9px 10px;
border: 1px solid var(--shell-hairline);
border-radius: 12px;
background: var(--shell-surface);
text-align: left;
transition:
border-color 160ms,
box-shadow 160ms;
}
.palette-card:hover {
border-color: var(--shell-tile);
}
.palette-card.is-active {
border-color: var(--shell-ink-muted);
box-shadow: inset 0 0 0 1px var(--shell-ink-muted);
}
.palette-swatches {
display: flex;
height: 22px;
gap: 3px;
}
.palette-swatches > i {
flex: 1;
border: 1px solid rgb(0 0 0 / 8%);
border-radius: 4px;
}
.palette-swatches > i:first-child {
flex: 2.4;
}
.palette-name {
font-size: 13px;
font-weight: 600;
}
.palette-origin {
font-size: 11px;
color: var(--shell-ink-muted);
}
.palette-meta {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 8px;
margin-top: 10px;
font-size: 12px;
color: var(--shell-ink-muted);
}
.palette-meta code {
max-width: 100%;
overflow: hidden;
padding: 2px 6px;
border-radius: 5px;
background: var(--shell-field);
font-family: var(--font-mono);
font-size: 11px;
}
.palette-restore {
color: var(--shell-ink);
text-decoration: underline;
text-underline-offset: 2px;
}
@media (max-width: 760px) {
.workspace-shell {
--nav-rail: 64px;
flex-direction: column;
}
.workspace-mobile-bar {
display: flex;
min-height: 52px;
flex-shrink: 0;
align-items: center;
gap: 10px;
padding: 0 12px;
border-bottom: 1px solid var(--shell-hairline);
}
.workspace-navigation,
.navigation-collapsed .workspace-navigation {
position: fixed;
inset: 0 auto 0 0;
z-index: 45;
width: min(338px, calc(100vw - 44px));
visibility: hidden;
transform: translateX(-100%);
transition:
transform var(--nav-motion) var(--nav-ease),
visibility 0s linear var(--nav-motion);
}
.navigation-open .workspace-navigation {
visibility: visible;
transform: translateX(0);
box-shadow: 20px 0 60px rgb(15 17 19 / 18%);
transition-delay: 0s, 0s;
}
.workspace-sidebar,
.navigation-collapsed .workspace-sidebar {
display: flex;
flex: 1;
min-width: 0;
width: auto;
opacity: 1;
visibility: visible;
}
.rail-only .workspace-sidebar,
.rail-only .navigation-collapsed .workspace-sidebar {
display: none;
}
.rail-only .workspace-navigation,
.rail-only.navigation-open .workspace-navigation {
width: 64px;
}
.workspace-sidebar-header {
padding: 14px;
}
.workspace-sidebar-header:has(.space-community-header) {
min-height: 124px;
padding: 0;
}
.space-community-header,
.space-community-menu-trigger {
min-height: 124px;
}
.workspace-rail {
width: 64px;
}
.workspace-drawer-close,
.workspace-scrim {
display: flex;
}
.workspace-collapse,
.workspace-expand {
display: none;
}
.workspace-scrim {
position: fixed;
inset: 0;
z-index: 40;
background: rgb(15 17 19 / 42%);
backdrop-filter: blur(3px);
}
.shell-top-bar,
.navigation-collapsed .workspace-main :is(.shell-top-bar, .chat-header) {
min-height: 68px;
padding: 12px 16px;
}
.shell-top-actions {
gap: 6px;
}
.shell-top-icon {
width: 32px;
height: 32px;
border-radius: 10px;
}
.workspace-overlay {
padding: 12px;
}
.workspace-dialog {
padding: 22px;
max-height: calc(100dvh - 24px);
}
.settings-dialog {
width: 100%;
height: calc(100dvh - 24px);
border-radius: 16px;
flex-direction: column;
}
.settings-nav {
width: 100%;
flex-direction: row;
align-items: center;
gap: 4px;
padding: 12px 14px;
border-right: 0;
border-bottom: 1px solid var(--shell-hairline);
overflow-x: auto;
flex-shrink: 0;
}
.settings-nav-title {
padding: 0 10px 0 2px;
font-size: 15px;
white-space: nowrap;
}
.settings-nav-caption {
display: none;
}
.settings-nav-item {
width: auto;
flex-shrink: 0;
white-space: nowrap;
}
.settings-pane-header {
min-height: 56px;
padding: 10px 12px 10px 18px;
}
.settings-content {
padding: 20px 18px 32px;
}
.settings-row {
flex-wrap: wrap;
align-items: flex-start;
}
.settings-card > .settings-row {
padding: 12px;
}
.settings-subpanel {
padding: 12px;
}
.settings-facts dt {
width: 100%;
}
.board-toolbar {
padding: 12px 16px;
}
.board-canvas {
padding: 16px;
}
.repo-toolbar {
padding: 10px 16px 0;
}
.repo-toolbar-refs {
flex: 1 1 100%;
min-width: 0;
}
.repo-toolbar-clone {
max-width: 100%;
flex-wrap: wrap;
margin-left: 0;
}
.repo-content-layout {
padding: 12px 16px 16px;
}
.repo-content-layout.overview-open {
flex-direction: column;
overflow-y: auto;
}
.repo-content-layout.overview-open > section {
flex: none;
overflow: visible;
}
.repo-content-layout.overview-open > aside {
width: 100%;
overflow: visible;
}
.workspace-shell input,
.workspace-shell textarea,
.workspace-overlay input,
.workspace-overlay textarea,
.workspace-overlay select {
font-size: 16px;
}
}
@media (prefers-reduced-motion: reduce) {
.workspace-shell *,
.workspace-overlay * {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
transition-delay: 0s !important;
scroll-behavior: auto !important;
}
}
/* 用户与流水线产出的 Markdown(描述、评论、release 正文)。语义与 README 的
* markdown-body 一致,但作用域是应用内部,不依赖服务端片段样式。 */
.gitdata-markdown {
font-size: 13px;
line-height: 1.65;
color: var(--shell-ink);
word-break: break-word;
}
.gitdata-markdown-compact {
font-size: 12.5px;
}
.gitdata-markdown > :first-child {
margin-top: 0;
}
.gitdata-markdown > :last-child {
margin-bottom: 0;
}
.gitdata-markdown h1,
.gitdata-markdown h2 {
border-bottom: 1px solid var(--shell-hairline);
padding-bottom: 0.25em;
margin: 0.9em 0 0.4em;
font-weight: 700;
}
.gitdata-markdown h1 {
font-size: 1.35em;
}
.gitdata-markdown h2 {
font-size: 1.2em;
}
.gitdata-markdown h3 {
font-size: 1.08em;
font-weight: 700;
margin: 0.9em 0 0.35em;
}
.gitdata-markdown h4,
.gitdata-markdown h5,
.gitdata-markdown h6 {
font-weight: 700;
margin: 0.8em 0 0.3em;
}
.gitdata-markdown p {
margin: 0.5em 0;
}
.gitdata-markdown ul,
.gitdata-markdown ol {
padding-left: 1.5em;
margin: 0.5em 0;
}
.gitdata-markdown ul {
list-style: disc;
}
.gitdata-markdown ol {
list-style: decimal;
}
.gitdata-markdown li {
margin: 0.15em 0;
}
.gitdata-markdown blockquote {
margin: 0.6em 0;
padding: 0.15em 0.9em;
border-left: 3px solid var(--shell-active);
color: var(--shell-ink-muted);
}
.gitdata-markdown a {
color: inherit;
text-decoration: underline;
text-underline-offset: 3px;
}
.gitdata-markdown code {
background: var(--shell-field);
border: 1px solid var(--shell-hairline);
border-radius: 4px;
padding: 0.05em 0.35em;
font-family: ui-monospace, monospace;
font-size: 0.92em;
}
.gitdata-markdown pre {
background: var(--shell-field);
border: 1px solid var(--shell-hairline);
border-radius: 8px;
padding: 10px 12px;
overflow-x: auto;
margin: 0.6em 0;
}
.gitdata-markdown pre code {
background: none;
border: none;
padding: 0;
font-size: 12px;
}
.gitdata-markdown table {
border-collapse: collapse;
margin: 0.6em 0;
display: block;
overflow-x: auto;
}
.gitdata-markdown th,
.gitdata-markdown td {
border: 1px solid var(--shell-hairline);
padding: 5px 9px;
}
.gitdata-markdown th {
background: var(--shell-field);
font-weight: 600;
}
.gitdata-markdown img {
max-width: 100%;
border-radius: 6px;
}
.gitdata-markdown hr {
border: none;
border-top: 1px solid var(--shell-hairline);
margin: 1em 0;
}