/*
 * ds/overlay.css — drawers, modals, tooltips, the command palette.
 * Everything that sits above the page. All of it reads --z-* from tokens, so
 * nothing can land under a sticky header by accident again.
 */

.ds-scrim {
    position: fixed; inset: 0;
    background: var(--overlay);
    z-index: var(--z-drawer);
    animation: ds-fade var(--dur-base) var(--ease-out);
}
@keyframes ds-fade { from { opacity: 0; } }

/* =========================== Drawer ============================= */
/*
 * Sentry's move: tags, breadcrumbs and activity went into drawers so the page
 * stopped needing an inner scroll. A drawer scrolls; a nested pane inside a
 * scrolling page does not.
 */
.ds-drawer {
    position: fixed; top: 0; right: 0; bottom: 0;
    width: min(560px, 100vw);
    display: flex; flex-direction: column;
    background: var(--raised);
    border-left: 1px solid var(--line-firm);
    box-shadow: var(--shadow-xl);
    z-index: calc(var(--z-drawer) + 1);
    animation: ds-slide-in var(--dur-base) var(--ease-out);
}
@keyframes ds-slide-in { from { transform: translateX(100%); } }
.ds-drawer[hidden] { display: none !important; }
/*
 * 70% of the window, not 880px. A report holds a five-column table of file paths and
 * symbol names, a change document and a conversation; at 880 on a 1512px screen the
 * table wrapped and the page behind it -- which the reader is deciding ABOUT -- kept
 * two thirds of the width to show six rows they had already read.
 * `max()` keeps it usable on a narrow screen, where 70% of 900px is a column.
 */
.ds-drawer--wide { width: min(100vw, max(640px, 70vw)); }

.ds-drawer-head {
    display: flex; align-items: center; gap: var(--sp-2);
    padding: var(--sp-4);
    border-bottom: 1px solid var(--line);
    flex: none;
}
.ds-drawer-title { font-size: var(--fs-lead); font-weight: var(--fw-semibold); min-width: 0; }
.ds-drawer-head > .ds-iconbtn { margin-left: auto; flex: none; }
.ds-drawer-body { padding: var(--sp-4); overflow-y: auto; flex: 1 1 auto; min-height: 0; }
.ds-drawer-foot { padding: var(--sp-3) var(--sp-4); border-top: 1px solid var(--line); background: var(--panel-bg); flex: none; display: flex; gap: var(--sp-2); }

/* =========================== Modal ============================== */
.ds-modal-wrap { position: fixed; inset: 0; display: flex; align-items: center; justify-content: center; padding: var(--sp-4); z-index: var(--z-modal); }
/*
 * THE MODAL SAT UNDER ITS OWN SCRIM, and every modal in the product did.
 *
 * `.ds-modal-wrap` is a stacking context (z-index: 400). Inside it the scrim is
 * POSITIONED with `z-index: 300` and the dialog was STATIC with `z-index: auto` --
 * and a positioned descendant with a non-auto z-index paints above every
 * non-positioned one, whatever the numbers say. 300 > auto is not the comparison the
 * browser makes; "positioned beats static" is.
 *
 * So `elementFromPoint` anywhere over the change document returned `div.ds-scrim`.
 * Every click landed on the scrim's `onclick="closeDoc()"`, which is why the document
 * closed wherever you clicked it; every wheel event went to an element with nothing
 * to scroll, which is why a document twice the height of its box could not be read
 * past the first screen. Edit could not be pressed. Close could not be pressed.
 *
 * The drawer escaped it only by accident -- `.ds-drawer` is positioned and carries
 * `z-index: calc(var(--z-drawer) + 1)`, so it happened to win.
 *
 * Stated here rather than by raising the dialog's z-index, because a number that
 * must stay above another number is the bug waiting to happen again: `position:
 * relative` makes the dialog a positioned sibling and `z-index: 1` puts it above any
 * scrim the wrap contains, no matter what the scrim's own value is.
 */
.ds-modal { position: relative; z-index: 1; }
.ds-modal-wrap > .ds-scrim { z-index: 0; }
.ds-modal {
    width: min(560px, 100%);
    max-height: calc(100vh - var(--sp-12));
    display: flex; flex-direction: column;
    background: var(--raised);
    border: 1px solid var(--line-firm);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-xl);
    animation: ds-pop var(--dur-base) var(--ease-out);
}
@keyframes ds-pop { from { opacity: 0; transform: translateY(6px) scale(0.99); } }
.ds-modal--wide { width: min(880px, 100%); }
.ds-modal-head { display: flex; align-items: center; gap: var(--sp-2); padding: var(--sp-4); border-bottom: 1px solid var(--line); flex: none; }
/* `flex: 1 1 auto` is not decoration: without a grow the body takes its content
   height inside a column capped by `max-height`, and the overflow lands on the
   dialog -- which has no scroller. */
/* SCROLL CHAINING. The body scrolls, and when it reaches either end the wheel keeps
   going -- straight into the page behind the scrim, which then moves under a dialog
   that cannot. From the reader's side the document "will not scroll" and the page
   does, which is exactly backwards. `contain` keeps the gesture in the dialog; the
   page is also frozen while one is open (`ds-ui.js`), because a short document has
   nothing to scroll and the wheel would reach the page on the first notch. */
.ds-modal-body {
    padding: var(--sp-4); overflow-y: auto; flex: 1 1 auto; min-height: 0;
    overscroll-behavior: contain;
}
/* Actions belong at the far end of the head, not touching the title. The document's
   Close and Edit sat against the heading in the middle of an 880px dialog. */
.ds-modal-head > .ds-modal-actions { margin-left: auto; display: flex; align-items: center; gap: var(--sp-2); flex: none; }
/* A reading column centred in the dialog it is in. `.ds-prose` caps the measure at
   68ch, which is right; left-aligned in an 880px dialog it left a 300px gutter on one
   side and nothing on the other, which reads as a layout that gave up. */
.ds-modal-body.ds-prose { margin-inline: auto; }
/* The decision in a drawer's foot is a control, not a field in a form: stretched to
   the full width of a 1040px drawer it made its own label wrap onto two lines. */
.ds-drawer-foot > .ds-select { flex: 0 1 240px; }
.ds-modal-foot { display: flex; gap: var(--sp-2); justify-content: flex-end; padding: var(--sp-3) var(--sp-4); border-top: 1px solid var(--line); background: var(--panel-bg); flex: none; }

/* =========================== Tooltip ============================ */
.ds-tip { position: relative; display: inline-flex; }
.ds-tip-text {
    position: absolute; bottom: calc(100% + 6px); left: 50%;
    transform: translateX(-50%);
    padding: var(--sp-1) var(--sp-2);
    background: var(--ink);
    color: var(--ground);
    border-radius: var(--radius-xs);
    font-size: var(--fs-micro);
    white-space: nowrap;
    opacity: 0; pointer-events: none;
    transition: opacity var(--dur-fast) var(--ease-out);
    z-index: var(--z-tooltip);
}
.ds-tip:hover .ds-tip-text, .ds-tip:focus-within .ds-tip-text { opacity: 1; }

/* =========================== Palette =========================== */
/*
 * Cmd-K. In a product this dense it is not a power-user luxury: it is how the
 * rail gets to stay at nine rows while everything stays reachable.
 */
.ds-palette-wrap { position: fixed; inset: 0; display: flex; align-items: flex-start; justify-content: center; padding: 12vh var(--sp-4) var(--sp-4); z-index: var(--z-palette); }
.ds-palette {
    width: min(560px, 100%);
    background: var(--raised);
    border: 1px solid var(--line-firm);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-xl);
    overflow: hidden;
    display: flex; flex-direction: column;
    max-height: 60vh;
}
.ds-palette-input { padding: var(--sp-3) var(--sp-4); border: 0; border-bottom: 1px solid var(--line); background: none; font-size: var(--fs-lead); width: 100%; }
.ds-palette-input:focus { outline: none; }
.ds-palette-list { overflow-y: auto; padding: var(--sp-1); min-height: 0; }
.ds-palette-group { padding: var(--sp-2) var(--sp-3) var(--sp-1); font-size: var(--fs-micro); text-transform: uppercase; letter-spacing: 0.05em; color: var(--mute); }
.ds-palette-item { display: flex; align-items: center; gap: var(--sp-2); width: 100%; padding: var(--sp-2) var(--sp-3); border-radius: var(--radius-sm); font-size: var(--fs-dense); text-align: left; }
.ds-palette-item[aria-selected="true"] { background: var(--accent-soft); color: var(--accent-text); }
.ds-palette-item > .ds-kbd { margin-left: auto; }

/* =========================== Branch picker ======================
 * A menu anchored to the control that opens it. The list is fetched when it opens, not
 * on render: a report drawer per repository would otherwise make twelve forge calls
 * before the page could draw anything.
 */
.ds-base { position: relative; display: flex; align-items: center; gap: var(--sp-2); }
.ds-base-menu {
    position: absolute; top: calc(100% + 4px); left: 0;
    width: min(320px, 90vw);
    display: flex; flex-direction: column; gap: var(--sp-2);
    padding: var(--sp-3);
    background: var(--raised);
    border: 1px solid var(--line-firm);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-lg);
    z-index: var(--z-popover);
}
.ds-base-menu.is-hidden { display: none; }
.ds-base-list { display: flex; flex-direction: column; max-height: 220px; overflow-y: auto; }
.ds-base-option {
    display: flex; align-items: baseline; gap: var(--sp-2);
    padding: var(--sp-1) var(--sp-2);
    border-radius: var(--radius-sm);
    font-family: var(--font-mono);
    font-size: var(--fs-meta);
    text-align: left;
}
.ds-base-option:hover { background: var(--bg-hover); }
.ds-base-option.is-current { color: var(--accent-text); font-weight: var(--fw-semibold); }
.ds-base-option > em { margin-left: auto; font-family: var(--font-ui); font-size: var(--fs-micro); color: var(--mute); font-style: normal; }

/* ===========================================================================
 * THE INDEXING EXPLAINER
 *
 * "Indexing" is jargon, and a progress bar attached to a word somebody does not
 * know is an unexplained delay -- a thing to resent rather than to wait for. This
 * dialog says what each step is doing and what it buys.
 *
 * PORTED, NOT INVENTED. It was `explain-*` in `codepixel.css`, which `ds_base.html`
 * does not load, so from the moment Overview moved onto the new shell all fourteen
 * of its classes resolved to no rule: an 980px two-column dialog rendering as a
 * single column of unstyled text. Every hex value here resolved to a token.
 * ======================================================================== */

.ds-explain { width: min(980px, 100%); }

/* THE SHAPE OF THE WAIT, in one line. Chevrons rather than pills because these happen
   in an order and each one feeds the next -- a row of equal badges would say they are
   alternatives. */
.ds-explain-flow {
    display: flex; flex-wrap: wrap; gap: 3px;
    padding: var(--sp-3) var(--sp-4);
    border-top: 1px solid var(--line);
    border-bottom: 1px solid var(--line);
    background: var(--sunken);
    flex: none;
}
.ds-explain-chip {
    display: inline-flex; align-items: center; justify-content: center; gap: 6px;
    flex: 1 1 auto; min-width: 0;
    padding: 7px var(--sp-3) 7px var(--sp-5);
    font-size: var(--fs-micro); font-weight: var(--fw-semibold);
    white-space: nowrap;
    background: var(--surface);
    border: 1px solid var(--line);
    clip-path: polygon(0 0, calc(100% - 9px) 0, 100% 50%, calc(100% - 9px) 100%, 0 100%, 9px 50%);
}
.ds-explain-chip:first-child {
    padding-left: var(--sp-3);
    clip-path: polygon(0 0, calc(100% - 9px) 0, 100% 50%, calc(100% - 9px) 100%, 0 100%);
}
.ds-explain-chip:last-child {
    clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%, 9px 50%);
}
.ds-explain-chip i { font-size: var(--fs-micro); color: var(--accent-text); }

/* TWO COLUMNS, because "what is happening" and "why it is worth waiting for" are
   different questions and reading one should not require reading the other. */
.ds-explain-panes {
    display: grid;
    grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
    gap: 0; padding: 0;
}
.ds-explain-pane { padding: var(--sp-5) var(--sp-5); min-width: 0; }
.ds-explain-pane--why { border-left: 1px solid var(--line); background: var(--sunken); }
.ds-explain-head {
    margin: 0 0 var(--sp-3);
    font-size: var(--fs-micro); font-weight: var(--fw-semibold);
    letter-spacing: 0.05em; text-transform: uppercase; color: var(--mute);
}
.ds-explain-lede {
    font-size: var(--fs-dense); line-height: var(--lh-loose);
    margin: 0 0 var(--sp-4); color: var(--soft);
}
/* Numbered because they happen in an order, and the order is half of what makes the
   wait make sense. */
.ds-explain-steps { margin: 0; padding-left: var(--sp-5); }
.ds-explain-steps li { margin-bottom: var(--sp-3); line-height: var(--lh-normal); }
.ds-explain-steps li:last-child { margin-bottom: 0; }
.ds-explain-steps strong { display: block; font-size: var(--fs-dense); }
.ds-explain-steps span { font-size: var(--fs-dense); color: var(--soft); }

.ds-explain-wins { margin: 0 0 var(--sp-4); padding-left: var(--sp-5); }
.ds-explain-wins li {
    margin-bottom: var(--sp-2); font-size: var(--fs-dense);
    line-height: var(--lh-normal); color: var(--soft);
}
.ds-explain-wins strong { color: var(--ink); }
.ds-explain-note {
    padding: var(--sp-3);
    border-radius: var(--radius-md);
    background: var(--accent-soft);
    font-size: var(--fs-dense); line-height: var(--lh-normal); color: var(--soft);
}
.ds-explain-note strong { display: block; color: var(--ink); }
.ds-explain-note--quiet { background: var(--sunken); margin-top: var(--sp-2); }

/* THIS PROJECT'S OWN NUMBERS. A general description of indexing is a thing to skim;
   "4,633 files became 26,000 searchable pieces, in your code" is a thing to read. */
.ds-explain-stats {
    display: flex; gap: var(--sp-5); flex-wrap: wrap;
    padding: var(--sp-3); margin-bottom: var(--sp-3);
    border-radius: var(--radius-md);
    background: var(--surface);
    border: 1px solid var(--line);
}
.ds-explain-stats div { display: flex; flex-direction: column; }
.ds-explain-stats strong {
    font-size: var(--fs-h3); line-height: var(--lh-tight); color: var(--ink);
    font-variant-numeric: tabular-nums;
}
.ds-explain-stats span { font-size: var(--fs-micro); color: var(--mute); }

.ds-explain-steps code,
.ds-explain-wins code,
.ds-explain-lede code {
    font-family: var(--font-mono); font-size: var(--fs-micro);
    padding: 1px 4px; border-radius: var(--radius-xs); background: var(--sunken);
}

@media (max-width: 900px) {
    .ds-explain-chip { flex: 1 1 30%; }
}
@media (max-width: 820px) {
    .ds-explain-panes { grid-template-columns: minmax(0, 1fr); }
    .ds-explain-pane--why { border-left: 0; border-top: 1px solid var(--line); }
}

/* ===========================================================================
 * THE TWO-PANE PICKER — one vocabulary for both setup dialogs
 *
 * "Link repositories" and "Bring in work from Jira" are the same dialog: left
 * asks which group, right lists what is in it and you tick what you want. Their
 * own comments say so -- "SAME SHAPE AS BRINGING IN WORK ... a product that
 * answers it two different ways on two screens makes a person learn it twice" --
 * and they were then written with two sets of class names (`jira-*` and
 * `repo-*`), one of which reused the other's by hanging `.repo-row` off
 * `.jira-issue`. One set now, named for the shape rather than for Jira.
 *
 * WHY THIS IS A FIX AND NOT A RESTYLE. All three dialogs lived in `modal-overlay`,
 * whose `display: flex` and `position: fixed` come from `project_detail.css`.
 * `ds_base.html` does not load that file, and `.active` -- the class the open
 * functions set -- has no rule there either. So on every screen already migrated,
 * these dialogs were not closed and not hidden: they were `display: block`,
 * static, unstyled, and rendered inline at the foot of the page, all three at
 * once. They are `[hidden]` now and the open functions clear the attribute.
 * ======================================================================== */

/* The dialog is a column with a fixed height so the list scrolls and the footer
   does not. `overflow: hidden` beats `.ds-modal`'s own scroller, or the whole
   dialog scrolls as one and takes the Import button with it. */
.ds-modal:has(> .ds-panes) {
    height: 88vh; max-height: 88vh; overflow: hidden;
}
.ds-panes {
    display: grid;
    grid-template-columns: 296px minmax(0, 1fr);
    gap: 0; padding: 0;
    flex: 1; min-height: 0;
}
.ds-pane { padding: var(--sp-4) var(--sp-5); min-width: 0; }
.ds-pane--ask { border-right: 1px solid var(--line); overflow-y: auto; }
.ds-pane--pick { display: flex; flex-direction: column; min-height: 0; }
.ds-pane .ds-field { margin-bottom: var(--sp-4); }
.ds-pane-go { width: 100%; justify-content: center; }
.ds-pane-note {
    margin-top: var(--sp-2); font-size: var(--fs-micro);
    line-height: var(--lh-normal); color: var(--soft);
}

/* The filter, above the list it filters. It narrows what is SHOWN, never what is
   selected -- ticking six, typing a word and pressing Import must import those six. */
.ds-pick-filter { display: flex; gap: var(--sp-2); align-items: center; padding-bottom: var(--sp-2); }
.ds-pick-filter .ds-input { flex: 1; min-width: 0; }
.ds-pick-filter .ds-toggle { flex: none; }

.ds-pick-head {
    display: flex; align-items: center; justify-content: space-between;
    gap: var(--sp-3); padding-bottom: var(--sp-2);
    border-bottom: 1px solid var(--line); min-height: 28px;
}
/* Nothing listed yet: a rule across an empty pane is a heading for a table that is
   not there. It appears with the rows it belongs to. */
.ds-pane--pick:not(:has(.ds-pick)) .ds-pick-head {
    border-bottom: 0; padding-bottom: 0; min-height: 0;
}
.ds-pick-meta { display: flex; align-items: center; gap: var(--sp-2); }
.ds-pick-count { font-size: var(--fs-micro); color: var(--soft); font-variant-numeric: tabular-nums; }
/* WHEN THE LIST ON SCREEN WAS READ. A restored list is a claim about a board that may
   have moved on, and "these are the issues" without a timestamp is a stronger claim
   than this dialog can make. */
.ds-pick-when { font-size: var(--fs-micro); color: var(--mute); }

.ds-picklist {
    flex: 1; min-height: 0; overflow-y: auto;
    /* No cap. The dialog's own height bounds it, so this grows to whatever is left --
       on a normal window twenty rows rather than six. */
    margin: 0 calc(var(--sp-1) * -1); padding: var(--sp-1);
}
.ds-pick-empty, .ds-pick-warn {
    font-size: var(--fs-dense); line-height: var(--lh-normal);
    color: var(--soft); padding: var(--sp-5) var(--sp-1);
}
.ds-pick-warn { color: var(--st-waiting-ink); padding: var(--sp-2) var(--sp-1); }

/* ONE LINE PER ROW. Key, name, and the state at the end -- the two-line row this
   started as spent a third of the list on a second line carrying "Task", and turned a
   board of ten into six visible rows and a scrollbar. Anything that does not fit is on
   the row's `title`, which is where a long summary belongs. */
.ds-pick {
    display: flex; align-items: center; gap: var(--sp-2);
    padding: var(--sp-1) var(--sp-2);
    border-radius: var(--radius-sm);
    cursor: pointer; min-width: 0;
}
.ds-pick:hover { background: var(--sunken); }
.ds-pick input { flex: none; margin: 0; }
.ds-pick.is-filtered-out { display: none; }
.ds-pick-key {
    font-family: var(--font-mono); font-size: var(--fs-micro);
    font-weight: var(--fw-semibold); color: var(--accent-text); flex: none;
}
.ds-pick-name {
    flex: 1; min-width: 0; font-size: var(--fs-dense); color: var(--ink);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ds-pick-state {
    flex: none; font-size: var(--fs-micro); color: var(--soft);
    padding: 1px 7px; border-radius: var(--radius-full); background: var(--sunken);
}
/* ALREADY ON THE BOARD: shown, so the count reconciles with the tracker, and quiet, so
   it does not compete with the rows somebody is here to pick. */
.ds-pick.is-held .ds-pick-name,
.ds-pick.is-held .ds-pick-key { opacity: 0.55; }
.ds-pick--held { flex: none; font-size: var(--fs-micro); color: var(--accent-text); }

.ds-pick-icon { flex: none; color: var(--soft); font-size: var(--fs-dense); }
.ds-pick-lock { font-size: var(--fs-micro); color: var(--soft); }
/* WHAT A BIG REPOSITORY WILL COST IN TIME, said before it is chosen rather than
   discovered during the twenty minutes it indexes. Quiet, because it is a note and not
   a warning: nothing here stops anybody picking it. */
.ds-pick-note {
    flex: none; margin-left: auto; padding-left: var(--sp-2);
    color: var(--soft); font-size: var(--fs-micro);
}
/* THE BRANCH BELONGS ON THE ROW. One shared dropdown under a multi-select would be a
   single answer to a question each repository asks separately -- and guessing `main`
   failed inside `git clone` on every repository whose default is `master`. */
.ds-pick-branch {
    flex: none; max-width: 150px;
    font-size: var(--fs-micro); padding: 2px var(--sp-1);
    border: 1px solid var(--line); border-radius: var(--radius-sm);
    background: var(--surface); color: var(--soft); cursor: pointer;
}
.ds-pick input:checked ~ .ds-pick-branch { color: var(--ink); border-color: var(--accent); }

/* "2 repositories connected." The dialog used to close the instant the request
   returned, so the only evidence was a page that looked slightly different. */
.ds-pick--linked {
    display: flex; gap: var(--sp-3); align-items: flex-start;
    padding: var(--sp-4) var(--sp-2);
    font-size: var(--fs-dense); line-height: var(--lh-normal);
}
.ds-pick--linked i { color: var(--pass); font-size: var(--fs-lead); margin-top: 1px; }
.ds-pick--linked strong { display: block; color: var(--ink); }
.ds-pick--linked span { color: var(--soft); }

/* CHOSEN, NEVER TYPED. A typed status that does not exist matches nothing, the import
   returns zero issues, and nothing says the name was wrong -- which reads as "there is
   no work" and sends people to look at the board. */
.ds-states { display: flex; flex-wrap: wrap; gap: var(--sp-1); margin-top: var(--sp-2); }
.ds-toggle {
    border: 1px solid var(--line-firm); background: var(--surface);
    color: var(--soft); border-radius: var(--radius-full);
    padding: var(--sp-1) var(--sp-3); font-size: var(--fs-dense); cursor: pointer;
}
.ds-toggle:hover { border-color: var(--accent); }
.ds-toggle.is-on {
    background: var(--accent-soft); border-color: var(--accent);
    color: var(--accent-text); font-weight: var(--fw-semibold);
}

/* The per-repository stack rows, in the dialog Overview's checklist still opens. The
   Tech stack TAB is the table version of the same answer and posts to the same
   endpoint; this is the version that fits beside a checklist row. */
.ds-stackrows { display: grid; gap: var(--sp-2); }
.ds-stackrow {
    display: grid;
    grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr) 180px auto;
    gap: var(--sp-3); align-items: center;
}
.ds-stackrow-name {
    font-family: var(--font-mono); font-size: var(--fs-dense);
    font-weight: var(--fw-medium); overflow: hidden; text-overflow: ellipsis;
}
.ds-stackrow-langs { font-size: var(--fs-micro); color: var(--soft); }
.ds-stackrow-from { font-size: var(--fs-micro); color: var(--mute); }
/* WHY A CONTROL IS EMPTY. Spans the row rather than sitting in the 180px stack column,
   which would set a sentence four words to the line. */
.ds-stackrow-why {
    grid-column: 1 / -1; margin: 0;
    font-size: var(--fs-micro); color: var(--st-waiting-ink);
}

/* A short window -- a laptop with the dock and browser chrome -- has no room for a
   fixed 88vh dialog plus its padding, so give it the screen minus a margin rather than
   letting the footer fall off. */
@media (max-height: 680px) {
    .ds-modal:has(> .ds-panes) { height: 94vh; max-height: 94vh; }
}
@media (max-width: 820px) {
    .ds-panes { grid-template-columns: minmax(0, 1fr); overflow-y: auto; }
    .ds-pane--ask { border-right: 0; border-bottom: 1px solid var(--line); }
    /* Stacked, the list cannot own the remaining height -- there isn't any. It gets a
       readable window of its own and the panes scroll together. */
    .ds-picklist { max-height: 44vh; }
    .ds-stackrow { grid-template-columns: minmax(0, 1fr); gap: var(--sp-1); }
}

/* THE DIALOG'S OWN HEADING. Used by the run-more dialog on Implementation, both dialogs
   on Review and all three setup dialogs -- and defined by none of them. It inherited
   `h2`/`h3` sizing from `base.css`, so a dialog title rendered at page-heading size
   beside a 13px body, and the `ds-modal-head` flex row it sits in gave it the whole
   width. Found by checking rendered pages against the stylesheets they load, not by
   looking: the markup was right on every one of those five dialogs. */
.ds-modal-title {
    font-size: var(--fs-h3);
    font-weight: var(--fw-semibold);
    margin: 0;
    min-width: 0;
    display: flex; align-items: center; gap: var(--sp-2);
}
