Files
deepseek-harness/packages/client/ui-plugin-manager/src/client/PluginManagerPage.module.css
T

1437 lines
30 KiB
CSS

/* Plugin manager page: a centred column with its header, notices, and the package cards. */
.page {
display: flex;
flex-direction: column;
align-items: center;
gap: 32px;
box-sizing: border-box;
height: 100%;
overflow: auto;
/* Inline and bottom insets only: the 28px top inset belongs to the head row
(`.pageHead`, `.detailTop`). macOS window dragging is owned by a row's own box,
so an inset above that box leaves a top strip no drag region covers. */
padding: 0 clamp(24px, 4vw, 48px) 48px;
color: var(--dsw-alias-label-primary);
}
.page > * {
width: 100%;
max-width: 960px;
}
.pageHead {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 16px;
box-sizing: border-box;
/* The page's former top inset: the row starts at the window's top edge, so the whole
strip above the page content drags the window. */
padding-top: 28px;
}
/* macOS hiddenInset titlebar: the frame's top clearance keeps the head below
the window's top strip in both sidebar states so it never jumps, and the head
owns the window drag over its own box — clearance included — so this page's
top strip drags without a frame band. */
:global([data-platform='darwin']) .pageHead {
padding-top: calc(28px + var(--dsh-frame-top-clearance, 0px));
}
.pageTitle {
margin: 0;
font-size: 20px;
font-weight: 500;
line-height: 28px;
}
.pageIntro {
display: flex;
align-items: center;
gap: 4px;
margin: 4px 0 0;
font-size: 13px;
line-height: 20px;
color: var(--dsw-alias-label-secondary);
}
.infoButton {
flex: none;
width: 20px;
height: 20px;
padding: 0;
color: var(--dsw-alias-label-caption);
}
.toolbar {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: flex-end;
gap: 16px;
}
.addMenu {
width: 320px;
max-width: calc(100vw - 48px);
}
.addMenu [role='menuitem'] {
height: 72px;
box-sizing: border-box;
align-items: center;
gap: 10px;
padding: 6px 12px;
}
/* Keep both action icons centred beside the complete text block. */
.addMenu [role='menuitem'] > span:first-child:has(> svg) {
width: 16px;
height: 16px;
}
.addMenu [role='menuitem'] > span:first-child:has(> svg) > svg {
width: 16px;
height: 16px;
}
.addMenuItem {
display: flex;
flex-direction: column;
gap: 2px;
white-space: normal;
}
.addMenuDescription {
font-size: 12px;
line-height: 18px;
color: var(--dsw-alias-label-secondary);
}
.status,
.failure p,
.empty {
margin: 0;
font-size: 13px;
line-height: 20px;
color: var(--dsw-alias-label-tertiary);
}
.failure {
display: flex;
align-items: center;
gap: 10px;
color: var(--dsw-alias-state-error-primary);
}
.statusWithDot {
display: inline-flex;
align-items: center;
gap: 6px;
}
.group {
display: flex;
flex-direction: column;
gap: 8px;
}
.groupHead {
display: flex;
align-items: baseline;
gap: 8px;
}
.groupTitle {
margin: 0;
font-size: 14px;
line-height: 22px;
font-weight: 500;
}
.count {
font-size: 14px;
color: var(--dsw-alias-label-caption);
font-variant-numeric: tabular-nums;
}
/* The group's explanation, folded behind a hover/focus tooltip. */
.groupInfo {
display: inline-flex;
align-items: center;
align-self: center;
color: var(--dsw-alias-label-caption);
}
.groupInfo:hover,
.groupInfo:focus-visible {
color: var(--dsw-alias-label-secondary);
}
/* Center the status label geometrically: beside larger titles the capsule's line-box offset shows. */
.statusTag {
height: 18px;
padding: 0 7px;
font-size: 10px;
line-height: 1;
}
/* The package an install just enabled: a ring that fades while the list scrolls to it. */
.card[data-plugin-highlight] {
animation: dsh-plugin-highlight 2400ms ease-out;
}
@keyframes dsh-plugin-highlight {
0%,
55% {
box-shadow: 0 0 0 2px color-mix(in srgb, var(--dsw-alias-state-business-primary) 40%, transparent);
}
100% {
box-shadow: 0 0 0 0 transparent;
}
}
@media (prefers-reduced-motion: reduce) {
.card[data-plugin-highlight] {
animation: none;
box-shadow: 0 0 0 2px color-mix(in srgb, var(--dsw-alias-state-business-primary) 40%, transparent);
}
}
.iconButton:focus-visible {
outline: var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary));
outline-offset: 1px;
}
.cards {
margin: 0;
padding: 0;
list-style: none;
}
.cards {
display: flex;
flex-direction: column;
gap: 2px;
}
.card {
min-width: 0;
/* The hover surface reaches 8px past the content on both sides while the
row's content stays aligned with the page header. */
margin: 0 -8px;
border-radius: var(--dsw-radius-xl);
/* The page itself scrolls on the base surface. Anything that scrolls inside
a card draws the l2 thumb (ui-theme styles/scrollbar.css rebinding contract). */
--dsh-scrollbar-thumb: var(--dsw-alias-scrollbar-bg-l2);
--dsh-scrollbar-thumb-hover: var(--dsw-alias-scrollbar-hover-l2);
}
.cardHead {
display: flex;
align-items: center;
gap: 14px;
padding: 8px;
}
.cardIcon {
display: inline-flex;
flex: none;
align-items: center;
justify-content: center;
width: 48px;
height: 48px;
/* The same hairline frame as the component rows below. */
border: 0.5px solid var(--dsw-alias-border-l3);
border-radius: var(--dsw-radius-lg);
color: var(--dsw-alias-label-secondary);
}
.packageImage {
object-fit: contain;
}
.cardMain {
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
gap: 4px;
}
.titleRow {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 8px;
min-width: 0;
}
.cardTitle {
font-size: 14px;
line-height: 20px;
font-weight: 500;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
/*
* A package card opens its page: the title button stretches over the whole
* card, and the controls at the card's end sit above that stretch, so the
* switch and the Add to… menu keep their own clicks.
*/
.cardLink {
position: relative;
}
.cardLink:hover {
background: var(--dsw-alias-interactive-bg-hover);
}
.cardOpen {
max-width: 100%;
padding: 0;
border: 0;
background: transparent;
color: inherit;
/* font: inherit resets the size, so the card title's own size follows. */
font: inherit;
font-size: 14px;
line-height: 20px;
font-weight: 500;
text-align: left;
cursor: pointer;
}
.cardOpen::after {
content: '';
position: absolute;
inset: 0;
border-radius: var(--dsw-radius-xl);
}
.cardOpen:focus-visible {
outline: none;
}
.cardOpen:focus-visible::after {
outline: var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary));
outline-offset: 2px;
}
.cardDesc {
font-size: 13px;
line-height: 18px;
color: var(--dsw-alias-label-tertiary);
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
overflow: hidden;
}
/* Match Session search's pulse without coupling the two feature packages. */
.skeletonFill {
background: var(--dsw-alias-bg-skeleton);
animation: dsh-plugin-skeleton 2s cubic-bezier(0.36, 0, 0.64, 1) infinite;
}
/* Keep each real text line's height; center the shorter painted bar within it. */
.skeletonText {
display: flex;
align-items: center;
height: 1lh;
}
.skeletonBar {
width: 100%;
height: 12px;
border-radius: var(--dsw-radius-xs);
}
.skeletonHeading { width: 48px; }
.skeletonTitle { width: min(144px, 60%); }
.skeletonDescription { width: min(280px, 85%); }
.skeletonIcon { border-color: transparent; }
/* Keep text-column metrics while leaving the action area blank. */
.skeletonActions {
width: 36px;
height: 20px;
}
@keyframes dsh-plugin-skeleton {
0% { opacity: 1; }
40% { opacity: 0.6; }
80%, 100% { opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
.skeletonFill { animation: none; }
}
.cardEnd {
position: relative;
z-index: 1;
display: inline-flex;
flex: none;
align-items: center;
gap: 8px;
}
/* The toolbar's icon action, round like the message-row actions. */
.iconButton {
display: inline-flex;
align-items: center;
justify-content: center;
width: 28px;
height: 28px;
border: 0;
border-radius: var(--dsw-radius-sm);
background: transparent;
color: var(--dsw-alias-label-caption);
cursor: pointer;
}
.iconButton:hover:not(:disabled) {
background: var(--dsw-alias-interactive-bg-hover);
color: var(--dsw-alias-label-secondary);
}
.iconButton:disabled {
opacity: 0.5;
cursor: default;
}
/* The toolbar's Add plugin action, one step up from the 28px sm capsule. */
.addButton,
.addPrimary,
.addMore {
height: 32px;
font-size: 13px;
line-height: 20px;
padding: 0 12px;
border-radius: var(--dsw-radius-md);
}
.addGroup {
display: inline-flex;
flex: none;
align-items: stretch;
}
.addPrimary {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.addMore {
width: 32px;
padding: 0;
border-left: 0.5px solid color-mix(in srgb, var(--dsw-alias-label-primary-foreground) 30%, transparent);
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.iconWrap {
display: inline-flex;
}
/* The destructive text action in a card body: red ink inside a 30% red frame,
and the outline hover rebinds to a red wash instead of the gray one. */
.danger {
color: var(--dsw-alias-state-error-primary);
border-color: color-mix(in srgb, var(--dsw-alias-state-error-primary) 30%, transparent);
--dsw-alias-interactive-bg-hover: color-mix(in srgb, var(--dsw-alias-state-error-primary) 8%, transparent);
}
/* Retry, uninstall, and the switch at the end of the page's head. */
.detailActions {
display: flex;
flex: none;
align-items: center;
gap: 16px;
}
.actions {
display: flex;
align-items: center;
gap: 16px;
}
/* The delete of a row the person added: red on its own, not only on hover. */
.deleteButton {
display: inline-flex;
align-items: center;
justify-content: center;
width: 28px;
height: 28px;
border: 0;
border-radius: var(--dsw-radius-sm);
background: transparent;
color: var(--dsw-alias-state-error-primary);
cursor: pointer;
}
.deleteButton:hover:not(:disabled) {
background: var(--dsw-alias-interactive-bg-hover-danger, var(--dsw-alias-interactive-bg-hover));
}
.deleteButton:disabled {
opacity: 0.5;
cursor: default;
}
.deleteButton:focus-visible {
outline: var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary));
outline-offset: 1px;
}
.reason {
margin: 0;
font-size: 12px;
line-height: 18px;
color: var(--dsw-alias-state-error-primary);
overflow-wrap: anywhere;
/* The Host's captured tail, when no output streamed, keeps its lines. */
white-space: pre-wrap;
}
.partsHead .subLabel {
margin: 0;
}
.partsFilter {
width: 200px;
}
.partsFilter:focus-visible {
outline: var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary));
outline-offset: 1px;
}
/* Wider than the default dialog: pnpm's lines are long, and the terminal keeps them unwrapped. The card never
outgrows the Modal's padding box and shares the settings panel's 800px height cap; the running screens
scroll inside it so the head's controls stay reachable. */
.installDialog {
width: min(560px, 100%);
max-height: min(800px, 100%);
}
/* The spec screen's content scrolls inside the card when the guide is open on a short viewport; the footer stays put. */
.installContent {
min-height: 0;
overflow-y: auto;
}
.installBody {
display: flex;
flex-direction: column;
gap: 12px;
min-width: 0;
}
.installFooter {
display: flex;
flex: 1;
flex-direction: column;
gap: 20px;
min-width: 0;
}
.templateHint {
margin: -4px 0 0;
font-size: 12px;
line-height: 18px;
color: var(--dsw-alias-label-secondary);
}
/* Where pnpm installs: the profile directory the first run names. */
.installLocation {
margin: 0;
font-size: 12px;
line-height: 18px;
color: var(--dsw-alias-label-tertiary);
overflow-wrap: anywhere;
}
.installField {
display: flex;
flex-direction: column;
gap: 6px;
font-size: 13px;
}
.installField input[type='text'] {
height: 40px;
padding: 0 14px;
border: 0.5px solid var(--dsw-alias-border-l4);
border-radius: var(--dsw-radius-md);
outline: none;
background: var(--dsw-alias-bg-layer-3);
font: inherit;
font-size: 13px;
color: var(--dsw-alias-label-primary);
}
.installField input[type='text']:focus,
.registryCustomField:focus {
border-color: var(--dsw-alias-state-business-primary);
box-shadow: inset 0 0 0 0.5px var(--dsw-alias-state-business-primary);
}
.installField input[type='text'][aria-invalid='true'],
.registryCustomField[aria-invalid='true'] {
border-color: var(--dsw-alias-state-error-primary);
box-shadow: none;
}
.installField input[type='text'][aria-invalid='true']:focus,
.registryCustomField[aria-invalid='true']:focus {
box-shadow: inset 0 0 0 0.5px var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary));
}
/* The guide under the field: opened by a text button, it says what an ID is and shows the three forms with examples. */
.guideToggle {
display: inline-flex;
align-items: center;
align-self: flex-start;
gap: 4px;
margin-top: 4px;
padding: 0;
border: 0;
background: none;
font: inherit;
font-size: 12.5px;
color: var(--dsw-alias-label-secondary);
cursor: pointer;
}
.guideToggle:hover {
color: var(--dsw-alias-label-primary);
}
.guideChevron {
transition: transform 160ms ease;
}
.guideToggle[aria-expanded='true'] .guideChevron {
transform: rotate(180deg);
}
.guide {
display: flex;
flex-direction: column;
gap: 10px;
padding: 8px 14px 14px;
border: 0.5px solid var(--dsw-alias-border-l4);
border-radius: var(--dsw-radius-lg);
background: var(--dsw-alias-bg-layer-1);
}
.guideHint {
margin: 0;
font-size: 12px;
line-height: 18px;
color: var(--dsw-alias-label-secondary);
}
/* Trust guidance stays beside the install action, including while examples are collapsed. */
.installSafety {
display: flex;
align-items: flex-start;
gap: 8px;
margin: 0;
padding: 10px 12px;
border-radius: var(--dsw-radius-md);
background: var(--dsw-alias-state-warn-tertiary);
font-size: 12px;
line-height: 18px;
color: var(--dsw-alias-label-secondary);
}
.installSafety > svg {
flex: none;
margin-top: 2px;
color: var(--dsw-alias-state-warn-primary);
}
.guideList {
display: flex;
flex-direction: column;
gap: 2px;
margin: 0;
padding: 0;
list-style: none;
}
.guideItem {
display: flex;
align-items: flex-start;
gap: 10px;
padding: 8px 0;
}
.guideItem > button {
align-self: center;
}
.guideIndex {
display: inline-flex;
flex: none;
align-items: center;
justify-content: center;
width: 20px;
height: 20px;
border-radius: 999px;
corner-shape: round;
background: var(--dsw-alias-bg-module-platform);
font-size: 11px;
font-weight: 500;
color: var(--dsw-alias-label-secondary);
}
.guideMain {
display: flex;
flex: 1;
flex-direction: column;
gap: 0;
min-width: 0;
}
.guideTitle {
font-size: 13px;
font-weight: 500;
line-height: 20px;
color: var(--dsw-alias-label-primary);
}
.guideExample {
font-size: 12px;
line-height: 20px;
color: var(--dsw-alias-label-secondary);
overflow-wrap: anywhere;
}
.guideExample code {
font-family: var(--ds-font-family-code);
}
.guideExampleLabel {
color: var(--dsw-alias-label-tertiary);
}
/* The row under the field: the guide's toggle on the left, the registry's on the right, both folded by default. */
.optionsRow {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
gap: 8px 12px;
}
/* The registry toggle names the registry the install asks first, so the choice reads without unfolding. */
.registryToggle {
display: inline-flex;
align-items: center;
gap: 6px;
height: 28px;
padding: 0 8px 0 10px;
border: 0.5px solid var(--dsw-alias-border-l4);
border-radius: var(--dsw-radius-md);
background: var(--dsw-alias-bg-layer-2);
font: inherit;
font-size: 12.5px;
color: var(--dsw-alias-label-secondary);
cursor: pointer;
}
.registryToggle:hover:not(:disabled) {
color: var(--dsw-alias-label-primary);
}
.registryToggle:disabled {
cursor: default;
opacity: 0.6;
}
.registryToggle[aria-expanded='true'] {
border-color: var(--dsw-alias-border-l3);
background: var(--dsw-alias-bg-layer-3);
}
.registryToggle[aria-expanded='true'] .guideChevron {
transform: rotate(180deg);
}
.registryChosen {
font-weight: 500;
color: var(--dsw-alias-label-primary);
}
/* The registry options float from their toggle over the dialog: pnpm's own, the configured mirrors, and a typed
address, with the order asked under them. Portaled and fixed, so the dialog keeps its height. */
.registry {
position: fixed;
z-index: 1100;
display: flex;
flex-direction: column;
gap: 4px;
box-sizing: border-box;
width: min(440px, calc(100vw - 24px));
margin: 0;
padding: 8px;
border: 0;
/* An opaque layer keeps the registry form controls readable over the dialog. */
background: var(--dsw-alias-bg-layer-2);
border-radius: var(--dsw-radius-lg);
--dsw-elevation-stroke-color: var(--dsw-alias-border-l1);
box-shadow: var(--dsw-elevation-prominent);
min-width: 0;
}
.registryOption {
display: flex;
flex-direction: column;
gap: 4px;
padding: 8px 10px;
border: 0;
border-radius: var(--dsw-radius-md);
cursor: pointer;
}
.registryOption:hover {
background: var(--dsw-alias-interactive-bg-hover);
}
/* An offered registry is one row: the radio beside its title and the line under it. */
label.registryOption {
flex-direction: row;
align-items: flex-start;
gap: 10px;
}
.registryOption input[type='radio'] {
flex: none;
width: 16px;
height: 16px;
margin: 2px 0 0;
accent-color: var(--dsw-alias-brand-primary);
}
.registryTitle {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 8px;
font-size: 13px;
line-height: 20px;
color: var(--dsw-alias-label-primary);
}
.registryHint {
font-size: 12px;
line-height: 18px;
color: var(--dsw-alias-label-tertiary);
overflow-wrap: anywhere;
}
.registryCustomPick {
display: flex;
align-items: flex-start;
gap: 10px;
cursor: pointer;
}
.registryCustomField {
outline: none;
height: 32px;
margin-left: 26px;
padding: 0 10px;
border: 0.5px solid var(--dsw-alias-border-l4);
border-radius: var(--dsw-radius-md);
background: var(--dsw-alias-bg-layer-3);
font: inherit;
font-size: 13px;
color: var(--dsw-alias-label-primary);
}
/* The typed address's field, refusal, and line sit under its title, past the radio and its gap. */
.registryOption > .inputError,
.registryOption > .registryHint {
margin-left: 26px;
}
/* What the check refused, under the field. */
.inputError {
margin: -4px 0 0;
font-size: 12px;
line-height: 18px;
color: var(--dsw-alias-state-error-primary);
}
/* The footer's only action spans the dialog, as the primary action of a short form does. */
.wide {
width: 100%;
height: 40px;
justify-content: center;
border-radius: var(--dsw-radius-md);
}
/* The installing, installed, and failed screens: a head row, the centred
state, the subject card, then the details toggle beside the screen's action. */
.wizard {
display: flex;
flex: 1 1 auto;
flex-direction: column;
gap: 16px;
min-width: 0;
min-height: 0;
padding: 16px 20px 0;
}
/* Everything under the head: it scrolls when the runs' output makes the screen taller than the card. */
.wizardScroll {
display: flex;
flex: 1 1 auto;
flex-direction: column;
gap: 16px;
min-height: 0;
overflow-y: auto;
}
.wizardHead {
display: flex;
align-items: center;
justify-content: space-between;
min-height: 24px;
}
.wizardBack {
display: inline-flex;
align-items: center;
gap: 4px;
padding: 0;
border: 0;
background: none;
font: inherit;
font-size: 15px;
font-weight: 600;
color: var(--dsw-alias-label-primary);
cursor: pointer;
}
.wizardClose {
display: inline-flex;
align-items: center;
justify-content: center;
width: 24px;
height: 24px;
padding: 0;
border: 0;
border-radius: var(--dsw-radius-sm);
background: none;
color: var(--dsw-alias-label-tertiary);
cursor: pointer;
}
.wizardClose:hover {
background: var(--dsw-alias-bg-layer-3);
color: var(--dsw-alias-label-primary);
}
.wizardHero {
display: flex;
flex-direction: column;
align-items: center;
gap: 10px;
padding: 8px 0 4px;
text-align: center;
}
.wizardIcon {
display: inline-flex;
align-items: center;
justify-content: center;
width: 44px;
height: 44px;
color: var(--dsw-alias-label-secondary);
}
.wizardIcon[data-state='done'] {
color: var(--dsw-alias-state-success-secondary);
}
.wizardIcon[data-state='error'] {
color: var(--dsw-alias-state-warn-label);
}
.wizardTitle {
margin: 0;
font-size: 18px;
line-height: 26px;
font-weight: 600;
}
.wizardSub {
margin: 0;
font-size: 13px;
line-height: 20px;
color: var(--dsw-alias-label-secondary);
overflow-wrap: anywhere;
}
.subject {
display: flex;
flex-direction: column;
align-items: center;
gap: 6px;
padding: 16px;
border: 0.5px solid var(--dsw-alias-border-l3);
border-radius: var(--dsw-radius-lg);
text-align: center;
}
.subjectName {
margin: 0;
font-size: 15px;
line-height: 22px;
font-weight: 600;
overflow-wrap: anywhere;
}
.subjectDesc,
.subjectMeta {
margin: 0;
font-size: 13px;
line-height: 20px;
color: var(--dsw-alias-label-secondary);
overflow-wrap: anywhere;
}
.wizardFoot {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
}
.footAction {
height: 32px;
border-radius: var(--dsw-radius-md);
}
.detailsToggle {
display: inline-flex;
align-items: center;
gap: 4px;
padding: 0;
border: 0;
background: none;
font: inherit;
font-size: 13px;
color: var(--dsw-alias-label-secondary);
cursor: pointer;
}
.detailsChevron {
transition: transform 160ms ease;
}
.detailsToggle[aria-expanded='true'] .detailsChevron {
transform: rotate(180deg);
}
.detailsBody {
display: flex;
flex-direction: column;
gap: 8px;
min-width: 0;
}
/* The failed screen's actions beside the details toggle: change the registry, retry. */
.wizardActions {
display: flex;
align-items: center;
gap: 8px;
}
/* One pnpm run of the install; once several registries were asked, a badge names each run's. */
.run {
display: flex;
flex-direction: column;
gap: 4px;
min-width: 0;
}
.attemptBadge {
align-self: flex-start;
margin: 0;
padding: 0 6px;
border-radius: var(--dsw-radius-sm);
background: var(--dsw-alias-bg-layer-3);
font-size: 11px;
line-height: 18px;
color: var(--dsw-alias-label-secondary);
}
@media (prefers-reduced-motion: reduce) {
.detailsChevron {
transition: none;
}
}
.result,
.resultWarn {
margin: 0;
padding: 8px 12px;
border-radius: var(--dsw-radius-md);
font-size: 13px;
line-height: 20px;
background: color-mix(in srgb, var(--dsw-alias-state-success-primary) 10%, transparent);
color: var(--dsw-alias-label-primary);
}
.resultWarn {
background: var(--dsw-alias-state-warn-tertiary);
}
/* The approval a blocked run asks for: the packages whose install scripts pnpm did not run, and the one action. */
.approval {
display: flex;
flex-direction: column;
gap: 8px;
padding: 12px 14px;
border: 0.5px solid color-mix(in srgb, var(--dsw-alias-state-warn-primary) 40%, transparent);
border-radius: var(--dsw-radius-lg);
background: var(--dsw-alias-state-warn-tertiary);
}
.approvalTitle {
margin: 0;
font-size: 13px;
font-weight: 600;
color: var(--dsw-alias-label-primary);
}
.approvalText {
margin: 0;
font-size: 12.5px;
line-height: 18px;
color: var(--dsw-alias-label-secondary);
}
.approvalCaution {
margin: 0;
font-size: 12.5px;
line-height: 18px;
font-weight: 500;
color: var(--dsw-alias-label-secondary);
}
.approvalList {
display: flex;
flex-wrap: wrap;
gap: 6px;
margin: 0;
padding: 0;
list-style: none;
}
.approvalList code {
display: inline-block;
padding: 2px 8px;
border-radius: var(--dsw-radius-sm);
background: var(--dsw-alias-bg-layer-3);
font-family: var(--ds-font-family-code);
font-size: 12px;
color: var(--dsw-alias-label-primary);
}
/* The install terminal: the shared TerminalBlock at the bash card's smaller
size, its output capped so an expanded log scrolls inside the dialog. */
.terminal {
--dsl-terminal-font: var(--dsw-font-markdown-code-block-small);
--dsl-terminal-line-height: 18px;
--dsl-terminal-output-max-height: 240px;
margin: 4px 0 0;
border: 0.5px solid var(--dsw-alias-border-l1);
}
.dependents {
margin: 8px 0 0;
padding-left: 18px;
font-size: 13px;
line-height: 20px;
color: var(--dsw-alias-label-secondary);
}
.dangerButton {
--dsw-alias-button-primary-fill: var(--dsw-alias-state-error-primary);
--dsw-alias-button-primary-hover: var(--dsw-alias-state-error-primary);
}
.detail {
display: flex;
flex-direction: column;
}
/* The head row every detail view shares: the crumb over the icon/actions row.
It carries the same top clearance as .pageHead — the crumb is the detail
views' leading content and otherwise lands under the traffic lights — and the
same drag ownership: it marks itself `data-window-drag`, so this row's own box
is the window's draggable geometry. The detail container below stays
content: marking it would drag the window over its text and form labels. */
.detailTop {
display: flex;
flex-direction: column;
/* The same 28px top inset `.pageHead` carries, so the row starts at the window's
top edge and the strip above the detail content drags the window. */
padding-top: 28px;
}
:global([data-platform='darwin']) .detailTop {
padding-top: calc(28px + var(--dsh-frame-top-clearance, 0px));
}
.crumb {
display: inline-flex;
align-items: center;
gap: 6px;
border: 0;
padding: 0;
background: none;
color: var(--dsw-alias-label-tertiary);
font: inherit;
font-size: 12.5px;
cursor: pointer;
}
.crumb:hover {
color: var(--dsw-alias-label-primary);
}
.crumb:focus-visible {
outline: var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary));
outline-offset: 2px;
}
.crumbIcon {
transform: rotate(90deg);
}
/* Head row: the pack's icon at one edge, its actions at the other; the name
block sits under the icon (figma detail handoff). */
.detailHead {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
margin: 32px 0 0;
}
.detailMain {
display: flex;
flex-direction: column;
gap: 8px;
min-width: 0;
margin-top: 20px;
}
.detailTitle {
margin: 0;
font-size: 20px;
line-height: 28px;
font-weight: 500;
}
.versionTag {
flex: none;
font-variant-numeric: tabular-nums;
}
.detailDesc {
margin: 0;
color: var(--dsw-alias-label-secondary);
font-size: 14px;
line-height: 22px;
}
/* The package or row identity under the title: the exact spec that installs the
package elsewhere, where a title of its own or a shortened name hides it. */
.detailName {
margin: 0;
font-size: 12px;
line-height: 18px;
color: var(--dsw-alias-label-tertiary);
overflow-wrap: anywhere;
}
.detailName code {
font-family: var(--dsw-font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
}
/* The unknown-package note under the name block. */
.detail > .detailDesc {
margin-top: 12px;
}
.detailSections {
display: flex;
flex-direction: column;
gap: 32px;
margin-top: 32px;
}
.detailSection {
display: flex;
flex-direction: column;
gap: 12px;
}
.sectionHead {
display: flex;
align-items: baseline;
gap: 10px;
}
.sectionTitle {
margin: 0;
font-size: 14px;
line-height: 20px;
font-weight: 500;
}
.sectionCount {
font-size: 12px;
line-height: 18px;
color: var(--dsw-alias-label-secondary);
}
/* The way into a package's page. */
.cardArrow {
flex: none;
color: var(--dsw-alias-label-tertiary);
}
/* Rows sit on the page ground, one hairline apart, so they read on a white page too. */
.rows {
display: flex;
flex-direction: column;
margin: 0;
padding: 0;
list-style: none;
}
.row {
padding: 12px 2px;
border-bottom: 0.5px solid var(--dsw-alias-border-l2);
}
.row:last-child {
border-bottom: 0;
}
.rowLine {
display: flex;
align-items: center;
gap: 16px;
min-width: 0;
}
.rowIcon {
display: inline-flex;
flex: none;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
border: 0.5px solid var(--dsw-alias-border-l3);
border-radius: var(--dsw-radius-md);
color: var(--dsw-alias-label-secondary);
}
.rowMain {
display: flex;
flex: 1;
flex-direction: column;
gap: 2px;
min-width: 0;
}
.rowId {
font-size: 13.5px;
line-height: 20px;
font-weight: 500;
color: var(--dsw-alias-label-primary);
overflow-wrap: anywhere;
}
.row[data-state='off'] .rowId {
color: var(--dsw-alias-label-secondary);
}
.rowModule {
font-family: var(--dsw-font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
font-size: 11.5px;
line-height: 16px;
color: var(--dsw-alias-label-tertiary);
overflow-wrap: anywhere;
}
/* A row with a configuration page: its name opens the page, the arrow says so. */
.rowOpen {
display: inline-flex;
align-items: center;
gap: 2px;
padding: 0;
border: 0;
background: transparent;
color: inherit;
font: inherit;
text-align: left;
cursor: pointer;
}
.rowOpen:hover .rowId {
text-decoration: underline;
text-underline-offset: 3px;
}
.rowOpenIcon {
flex: none;
color: var(--dsw-alias-label-tertiary);
}
.rowOpen:hover .rowOpenIcon {
color: var(--dsw-alias-label-primary);
}
.rowState {
display: inline-flex;
flex: none;
align-items: center;
gap: 6px;
font-size: 12.5px;
line-height: 18px;
color: var(--dsw-alias-label-secondary);
white-space: nowrap;
}
.row[data-state='failed'] .rowState {
color: var(--dsw-alias-state-error-primary);
}
.rowFailure {
margin: 4px 0 0 56px;
font-size: 12px;
line-height: 18px;
color: var(--dsw-alias-state-error-primary);
overflow-wrap: anywhere;
}