.section {
  display: flex;
  flex-direction: column;
  gap: 12px;
  max-width: 720px;
  color: var(--dsw-alias-label-primary);
}

.title {
  margin: 0;
  font-size: 18px;
  font-weight: 600;
}

.intro {
  margin: 0;
  font-size: 13px;
  color: var(--dsw-alias-label-tertiary);
}

/* Cards, not rows: a preset is a thing you pick, and the description is the
   part that tells them apart — a row would bury it beside the actions. */
.group {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

/* Group-to-group breathing room: the section's 12px gap plus 20px reads the
   two rosters as separate blocks (32px total). */
.group + .group {
  margin-top: 20px;
}

.groupHead {
  margin: 0;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--dsw-alias-label-tertiary);
}

.cards {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(268px, 1fr));
  /* Every row the same height, so a short description does not make its card
     shorter than the one beside it. */
  grid-auto-rows: 1fr;
  gap: 12px;
}

.card {
  border: 1px solid var(--dsw-alias-border-l2);
  border-radius: 12px;
  display: flex;
  flex-direction: column;
  background: var(--dsw-alias-bg-layer-3);
  transition: border-color .16s, background .16s;
}


.card:hover:not(.cardActive) {
  border-color: var(--dsw-alias-label-dimmed);
}

/* The default preset reads as selected, not merely badged. */
.cardActive {
  background: var(--dsw-alias-bg-layer-2);
  border-color: var(--dsw-alias-label-primary);
}

/* A broken preset reads as damaged before anything else: the card cannot be
   picked, so its border carries the warning the disabled body cannot. */
.cardBroken {
  border-color: var(--dsw-alias-state-error-primary);
}

.cardBroken:hover {
  border-color: var(--dsw-alias-state-error-primary);
}

.brokenBadge {
  border-radius: 999px;
  padding: 1px 8px;
  font-size: 11px;
  line-height: 17px;
  white-space: nowrap;
  font-weight: 500;
  background: var(--dsw-alias-state-error-primary);
  color: var(--dsw-alias-bg-layer-3);
}

/* The discovery-reported reason, verbatim: it names the rows and the fix.
   A real element rather than the icon row's `data-tip` pseudo-element, for two
   reasons: generated content joins the card's accessible text, where this would
   repeat what the alert already carries, and that tooltip is one `nowrap` line
   for an icon label while this names package specifiers one per line. */
.brokenTip {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  z-index: 1;
  width: max-content;
  max-width: 100%;
  padding: 6px 8px;
  border-radius: 6px;
  background: var(--dsw-alias-label-primary);
  color: var(--dsw-alias-bg-layer-3);
  font-size: 11px;
  font-weight: 400;
  line-height: 1.5;
  text-align: left;
  white-space: pre-line;
  overflow-wrap: anywhere;
  opacity: 0;
  pointer-events: none;
  transition: opacity .12s;
}

/* Focusing the card reveals it too: a broken card keeps its place in the tab
   order (`aria-disabled`, not `disabled`), so this is the keyboard path to a
   reason the card face no longer shows. */
.brokenBadge:hover .brokenTip,
.cardMain:focus-visible .brokenTip {
  opacity: 1;
}

.cardMain[aria-disabled='true'] {
  cursor: default;
}

.cardMain:focus-visible {
  outline: 2px solid var(--dsw-alias-brand-primary);
  outline-offset: -2px;
}

/* The same reason, for a screen reader. A pointer reveals the badge's tooltip
   and a keyboard reveals it by focusing the card, but neither announces it;
   this node is what does. Keeping it out of the card face is what lets a
   picker card show the preset's own description rather than a package
   specifier. */
.cardBrokenReason {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

/* The card body is the control that picks the preset. */
.cardMain {
  flex: 1;
  appearance: none;
  border: 0;
  background: none;
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 14px 16px 12px;
  border-radius: 12px 12px 0 0;
}

.cardMain:disabled {
  cursor: default;
}

.cardMain:focus-visible {
  outline: 2px solid var(--dsw-alias-brand-primary);
  outline-offset: -2px;
}

.cardHead {
  display: flex;
  align-items: center;
  gap: 8px;
  /* Anchors the broken badge's tooltip: the badge itself stays unpositioned so
     its `::after` resolves against the card's own width instead of against a
     badge that sits partway across it. A tooltip grown from the badge would
     run past the card, and past the section for a card in the last column. */
  position: relative;
}

.cardName {
  font-size: 15px;
  font-weight: 600;
  line-height: 1.4;
}

.badge,
.inUse {
  border-radius: 999px;
  padding: 1px 8px;
  font-size: 11px;
  line-height: 17px;
  white-space: nowrap;
  font-weight: 500;
}

.badge {
  border: 1px solid var(--dsw-alias-border-l2);
  color: var(--dsw-alias-label-tertiary);
}

.inUse {
  margin-left: auto;
  background: var(--dsw-alias-label-primary);
  color: var(--dsw-alias-bg-layer-3);
}

/* Bounded to four lines. A preset publishes its own description, so one long
   one would otherwise stretch every card in its grid row (`.cards` sizes rows
   1fr). Clamping is CSS alone: the whole text stays in the DOM for assistive
   tech, and the card offers it on hover when it is actually cut off. The
   description does not grow to fill the card — `-webkit-line-clamp` on a
   flex-stretched box leaves the clamp height and the box height disagreeing,
   so `.cardId` takes the free space with an auto margin instead. */
.cardDesc {
  font-size: 13px;
  line-height: 1.55;
  color: var(--dsw-alias-label-secondary);
  min-height: 42px;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 4;
  overflow: hidden;
  /* A user-authored description may carry an unbreakable path or URL. */
  overflow-wrap: anywhere;
}

.cardId {
  margin-top: auto;
  font-family: var(--dsw-font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  font-size: 11px;
  color: var(--dsw-alias-label-dimmed);
}

.cardFoot {
  display: flex;
  justify-content: flex-end;
  gap: 2px;
  padding: 6px 10px;
  border-top: 1px solid var(--dsw-alias-border-l2);
}

/* Icon-only actions: the label rides `title` so the row stays quiet until
   someone reaches for it. */
.iconButton {
  position: relative;
  appearance: none;
  border: 0;
  border-radius: 7px;
  padding: 6px;
  background: none;
  color: var(--dsw-alias-label-tertiary);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
}

.iconButton:disabled {
  opacity: 0.4;
  cursor: default;
}

.iconButton:hover:not(:disabled) {
  background: var(--dsw-alias-bg-layer-1);
  color: var(--dsw-alias-label-primary);
}

.iconButton:focus-visible {
  outline: 2px solid var(--dsw-alias-brand-primary);
  outline-offset: -1px;
}

.iconButton::after {
  content: attr(data-tip);
  position: absolute;
  bottom: calc(100% + 6px);
  left: 50%;
  transform: translateX(-50%);
  padding: 3px 8px;
  border-radius: 6px;
  background: var(--dsw-alias-label-primary);
  color: var(--dsw-alias-bg-layer-3);
  font-size: 11px;
  line-height: 17px;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity .12s;
}

.iconButton:hover::after,
.iconButton:focus-visible::after {
  opacity: 1;
}

.iconDanger:hover:not(:disabled) {
  background: var(--dsw-alias-interactive-bg-hover-danger);
  color: var(--dsw-alias-state-error-primary);
}

/* Where the host has no desktop opener, the row answers with the directory
   itself — text to copy, not a control that would spawn into nothing. */
.revealedPath {
  margin: 0;
  padding: 6px 16px 10px;
  font-size: 11px;
  color: var(--dsw-alias-label-tertiary);
  display: flex;
  gap: 6px;
  align-items: baseline;
}

.revealedPath code {
  font-family: var(--dsw-font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  color: var(--dsw-alias-label-secondary);
  user-select: all;
  overflow-wrap: anywhere;
}

.revealedPathLabel {
  white-space: nowrap;
}

.secondaryButton {
  border: none;
  border-radius: 7px;
  padding: 5px 8px;
  background: none;
  color: var(--dsw-alias-label-secondary);
  font: inherit;
  font-size: 12.5px;
  cursor: pointer;
}


.secondaryButton:hover:not(:disabled) {
  background: var(--dsw-alias-bg-layer-1);
}

.secondaryButton:disabled {
  opacity: 0.5;
  cursor: default;
}

.field {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.fieldLabel {
  font-size: 12px;
  font-weight: 500;
  color: var(--dsw-alias-label-secondary);
}

.input {
  box-sizing: border-box;
  padding: 9px 12px;
  border: 1px solid var(--dsw-alias-border-l2);
  border-radius: 10px;
  font: inherit;
  font-size: 13px;
  background: var(--dsw-alias-bg-layer-1);
  color: var(--dsw-alias-label-primary);
}

.input:focus {
  outline: none;
  border-color: var(--dsw-alias-brand-primary);
}

.input::placeholder {
  color: var(--dsw-alias-label-dimmed);
}

.dialog {
  width: min(560px, 100%);
}

.dialogFields {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

/* A shipped composition can be long; the dialog scrolls it rather than grow. */
.viewerCode {
  margin: 0;
  padding: 12px;
  max-height: min(52vh, 480px);
  overflow: auto;
  border: 1px solid var(--dsw-alias-border-l2);
  border-radius: 10px;
  background: var(--dsw-alias-bg-layer-2);
  color: var(--dsw-alias-label-secondary);
  font-family: var(--dsw-font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  font-size: 12.5px;
  line-height: 1.5;
  white-space: pre;
  tab-size: 2;
  --dsh-scrollbar-thumb: var(--dsw-alias-scrollbar-bg-l2);
  --dsh-scrollbar-thumb-hover: var(--dsw-alias-scrollbar-hover-l2);
}

.error {
  margin: 0;
  font-size: 12px;
  color: var(--dsw-alias-state-error-primary);
}

.deleteDialog {
  width: min(480px, 100%);
}

.deleteConfirm:not(:disabled) {
  border-color: var(--dsw-alias-state-error-primary);
  color: var(--dsw-alias-state-error-primary);
}

.deleteConfirm:hover:not(:disabled) {
  background: var(--dsw-alias-interactive-bg-hover-danger);
}

/* The conversational authoring entry, after the card grid in the spot the
   create button vacated. Dashed like the Models page's add affordances: it
   reads as a place a preset will appear, not a command. */
.creatorButton {
  box-sizing: border-box;
  align-self: stretch;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  height: 44px;
  border: 1px dashed var(--dsw-alias-border-l3);
  border-radius: 12px;
  font: inherit;
  font-size: 14px;
  line-height: 22px;
  background: transparent;
  color: var(--dsw-alias-label-primary);
  cursor: pointer;
}

.creatorButton:hover:not(:disabled) {
  background: var(--dsw-alias-interactive-bg-hover);
}

.creatorButton:disabled {
  opacity: 0.4;
  cursor: default;
}
