/* Directory-browser dialog (figma 813-23126 family). The shared Modal renders * headless here — mask, card, Escape only — and this module owns the figma * frame: 680×500 card (viewport-clamped; upsized from the figma 600×420), * header (title + crumbs, l3 separator), * the one-or-two-column Miller content, and the bordered footer. */ /* Doubled class beats Modal's own .dialog regardless of stylesheet order. */ /* Short viewports clamp the card: header/footer are flex-none and the * columns scroll, so shrinking the height keeps Open/Cancel reachable * instead of clipping them below a fixed overlay. */ .dialog.dialog { width: min(680px, 100%); height: min(500px, calc(100dvh - 32px)); padding: 0; gap: 0; /* The Modal card is an l2 surface and the columns below scroll on it: * rebind the scrollbar indirection to the elevation pair here, on the * surface, so it inherits down to whichever descendant scrolls (the * rebinding contract in ui-theme styles/scrollbar.css). */ --dsh-scrollbar-thumb: var(--dsw-alias-scrollbar-bg-l2); --dsh-scrollbar-thumb-hover: var(--dsw-alias-scrollbar-hover-l2); } /* Card-scope wrapper hosting the path editor's Escape and focus-leave * observers; display:contents keeps header/content/footer as direct flex * children of the Modal card. */ .editorScope { display: contents; } /* Header block: pl24 pr14 pt16 pb8, 8px between title row and crumb row. */ .header { display: flex; flex-direction: column; gap: 8px; flex: none; padding: 16px 14px 8px 24px; border-bottom: 1px solid var(--dsw-alias-border-l3); } .title { display: flex; align-items: flex-end; min-height: 28px; margin: 0; font-size: 16px; line-height: 24px; font-weight: 510; color: var(--dsw-alias-label-primary); } .crumbBar { display: flex; align-items: center; gap: 4px; min-height: 20px; } /* Deep chains scroll inside the trail (the effect pins the tail into view) * so the edit zone to the right never leaves the bar. */ /* The Miller columns keep their own row so a status/error line below never * competes with the fixed column widths for horizontal space. */ /* A narrow viewport shrinks the dialog below two fixed panes; the row * scrolls horizontally (the effect pins the child pane into view) so * descent never hides behind the Modal's clipping. */ .millerRow { display: flex; align-items: stretch; flex: 1 1 0; min-height: 0; /* 12px of row gap on each side of the divider; the left side reads wider * by the column's trailing 8px scrollbar clearance, which is deliberate — * the thumb needs that room, the right pane's rows do not. */ gap: 12px; overflow-x: auto; scrollbar-width: none; } .crumbTrail { display: flex; align-items: center; gap: 4px; flex: 0 1 auto; min-width: 0; overflow-x: auto; scrollbar-width: none; } .crumbSeat { display: inline-flex; align-items: center; gap: 4px; flex: none; min-width: 0; } .crumb { border: none; background: transparent; padding: 0; max-width: 160px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13px; line-height: 20px; font-weight: 500; color: var(--dsw-alias-label-tertiary); cursor: pointer; } .crumb:hover { color: var(--dsw-alias-label-primary); } .crumbChevron { flex: none; color: var(--dsw-alias-label-tertiary); } /* The empty remainder of the bar: invisible, but a real click target that * flips the bar into path-edit mode. */ .crumbEditZone { flex: 1 0 34px; min-width: 34px; align-self: stretch; border: none; background: transparent; cursor: text; } .pathInput { box-sizing: border-box; flex: 1 1 0; min-width: 0; height: 24px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2); border-radius: 8px; outline: none; background: transparent; font-size: 13px; line-height: 20px; color: var(--dsw-alias-label-primary); } /* Miller content: symmetric 16px vertical padding so the divider clears the * header and footer rules evenly; each column scrolls alone (column widths * live at .column). */ .content { display: flex; flex-direction: column; flex: 1 1 0; min-height: 0; /* Anchors the floating loading pill (.loadingFloat). */ position: relative; /* Right inset is slimmer than the left: the trailing column's own 8px * scrollbar clearance makes up the optical difference. */ padding: 16px 16px 16px 24px; } /* Columns split the row evenly around the divider (a solo column takes the * whole row); 256px is the floor below which the row scrolls (scrollbar * hidden, the effect pins the child pane into view) instead of squeezing * the panes. */ .column { display: flex; flex-direction: column; gap: 2px; flex: 1 1 0; min-width: 256px; overflow-y: auto; /* The themed scrollbar occupies the column's edge (styled scrollbars are * classic, gutter-taking ones); the extra clearance keeps the row pills * clear of the thumb. */ padding-right: 8px; } .divider { flex: none; width: 1px; background: var(--dsw-alias-border-l3); } .rowSeat { display: flex; flex: none; } .row { width: 100%; display: flex; align-items: center; gap: 4px; height: 28px; flex: none; padding: 4px; border: none; border-radius: 6px; background: transparent; text-align: left; cursor: pointer; } .row:hover { background: var(--dsw-alias-interactive-bg-hover); } /* Selection: pill fill + the open-folder glyph in the info accent. */ .rowSelected, .rowSelected:hover { background: var(--dsw-alias-interactive-bg-active, var(--dsw-alias-interactive-bg-hover)); } .rowIcon { flex: none; color: var(--dsw-alias-label-secondary); } .rowIconSelected { flex: none; color: var(--dsw-alias-button-info-fill); } .rowName { flex: 1 1 0; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13px; line-height: 20px; font-weight: 500; color: var(--dsw-alias-label-primary); } .rowChevron { flex: none; color: var(--dsw-alias-label-tertiary); } .status, .error { padding: 4px; /* The loading pill occupies the opposite corner while a stale status stays * visible. Reserve its widest localized footprint so wrapped text cannot * run underneath it on a narrow card. */ padding-right: 120px; font-size: 12px; line-height: 18px; } .status { color: var(--dsw-alias-label-secondary); } .error { color: var(--dsw-alias-state-error-primary); } /* The slow-scan indicator floats over the content's bottom-RIGHT corner on * the card background instead of occupying a row: a scan must never shift * the columns' height, and the stale view keeps rendering beneath it (it * only appears at all once a scan outlives SLOW_SCAN_DELAY_MS). Right, * not left: the truncated/error status rows flow at the bottom LEFT and * stay on screen through a scan, with their reserved right padding keeping * both legible even on a narrow card. After .status in the cascade — the * element carries both classes and this padding must win the * same-specificity race. */ .loadingFloat { position: absolute; right: 16px; bottom: 8px; padding: 2px 8px; background: var(--dsw-alias-bg-layer-2); } /* Footer: l3 separator on top, symmetric padding so the row sits vertically * centered in the bar; New-folder and the show-hidden toggle pin left. */ .footerBar { display: flex; align-items: center; /* Narrow viewports wrap the confirm/cancel pair onto their own row * instead of clipping Open past the card's hidden overflow. */ flex-wrap: wrap; gap: 8px; flex: none; padding: 16px 24px; border-top: 1px solid var(--dsw-alias-border-l3); } /* Show-hidden toggle: a subtle fixed-label text button left of the gap; * the pressed state seats a check glyph after the label (Menu's selected * vocabulary; trailing so the label never shifts) instead of flipping the * wording. */ .showHiddenToggle { display: inline-flex; align-items: center; gap: 4px; border: none; background: transparent; padding: 0; font-size: 13px; line-height: 20px; font-weight: 500; color: var(--dsw-alias-label-secondary); cursor: pointer; white-space: nowrap; } .showHiddenToggle:hover { color: var(--dsw-alias-label-primary); } .showHiddenToggle:disabled { color: var(--dsw-alias-label-caption); cursor: default; } .showHiddenToggleActive { color: var(--dsw-alias-label-primary); } .footerGap { flex: 1 1 0; } .footerAction { min-width: 72px; } /* Nested create dialog (figma 813:23278): a small centered card. */ .createDialog.createDialog { width: min(380px, 100%); padding: 0; gap: 0; } .createBody { display: flex; flex-direction: column; gap: 12px; padding: 22px 24px 20px; } .createTitle { margin: 0; font-size: 16px; line-height: 24px; font-weight: 510; color: var(--dsw-alias-label-primary); } .createIn { margin: 0; font-size: 14px; line-height: 22px; color: var(--dsw-alias-label-primary); } .createInput { box-sizing: border-box; width: 100%; height: 44px; padding: 7px 14px; border: 1px solid var(--dsw-alias-border-l2); border-radius: 22px; outline: none; background: transparent; font-size: 14px; line-height: 22px; color: var(--dsw-alias-label-primary); } .createInput::placeholder { color: var(--dsw-alias-label-caption); } .createActions { display: flex; align-items: center; justify-content: flex-end; gap: 8px; margin-top: 8px; }