/* Portal components (plan.md 1.3): every ds-* component of the design system, and the .ds-tone-* classes. Loaded on
   every page, AI Chat included (the navbar's dialogs, toasts and Appearance control use it there), so it holds
   class-scoped rules only: nothing here styles a bare element or a global class name. Page-level element styles, and
   the global .btn* / .card / .toggle-switch, are in portal-base.css (pages on the design system only). The look is
   the Scheduling redesign's (SP kit: kit.css). JS: Portal.ui (static/js/portal-ui.js). Tokens: portal-tokens.css.
   Order: self-contained basics - tones - controls - fields - select - segmented - badges - cards and page head -
   states - lists - surfaces - media queries last. */

/* =========================================================================================
   SELF-CONTAINED BASICS (the navbar and these components also work on pages without portal-base.css)
   ========================================================================================= */
:where(.portal-topbar, .portal-surface, [data-portal-slot], .ds-overlay, .ds-pop, .ds-sheet-wrap, .ds-toasts, .ds-seg) [hidden],
:where(.portal-topbar, .portal-surface, [data-portal-slot], .ds-overlay, .ds-pop, .ds-sheet-wrap, .ds-toasts, .ds-seg)[hidden] { display: none !important; }
.ds-sr-only { position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
:where(.ds-overlay, .ds-pop, .ds-sheet-wrap, .ds-toasts) { font: var(--fw-regular) var(--fs-md)/var(--lh-base) var(--font-sans); }
:where(.ds-overlay, .ds-pop, .ds-sheet-wrap, .ds-toasts) :where(*, *::before, *::after) { box-sizing: border-box; }
:where(.ds-overlay, .ds-pop, .ds-sheet-wrap, .ds-toasts) :where(button, input, select, textarea) { font: inherit; }
svg.ds-i { width: var(--icon-md); height: var(--icon-md); flex: none; display: inline-block; vertical-align: middle; }
/* One scrollbar look for every internal scroll (pages never style scrollbars). */
.ds-scroll, .ds-listbox, .ds-dialog-body, .ds-sheet-body, .ds-drawer-body, .ds-pane-body, .ds-pop { scrollbar-width: thin; scrollbar-color: var(--scrollbar-thumb) var(--scrollbar-track); }
:is(.ds-scroll, .ds-listbox, .ds-dialog-body, .ds-sheet-body, .ds-drawer-body, .ds-pane-body, .ds-pop, .portal-scroll)::-webkit-scrollbar { width: 10px; height: 10px; }
:is(.ds-scroll, .ds-listbox, .ds-dialog-body, .ds-sheet-body, .ds-drawer-body, .ds-pane-body, .ds-pop, .portal-scroll)::-webkit-scrollbar-thumb { background: var(--scrollbar-thumb); border-radius: var(--radius-pill); border: 3px solid transparent; background-clip: content-box; }
:is(.ds-scroll, .ds-listbox, .ds-dialog-body, .ds-sheet-body, .ds-drawer-body, .ds-pane-body, .ds-pop, .portal-scroll)::-webkit-scrollbar-track { background: var(--scrollbar-track); }
/* Lane S: a sideways strip (tabs, chips, a section nav) that scrolls without a scrollbar, and the same thin scrollbar
   for an internal scroll that is not one of the boxes above. */
.ds-strip { scrollbar-width: none; }
.ds-strip::-webkit-scrollbar { display: none; }
.ds-scrollbar { scrollbar-width: thin; scrollbar-color: var(--scrollbar-thumb) var(--scrollbar-track); }
.ds-scrollbar::-webkit-scrollbar { width: 10px; height: 10px; }
.ds-scrollbar::-webkit-scrollbar-thumb { background: var(--scrollbar-thumb); border-radius: var(--radius-pill); border: 3px solid transparent; background-clip: content-box; }
.ds-scrollbar::-webkit-scrollbar-track { background: var(--scrollbar-track); }
/* Scroll lock (Portal.ui.lockScroll, shared with the navbar's surfaces: PortalSurface.lockScroll uses the same class). */
html.portal-scroll-locked body { overflow: hidden !important; padding-right: var(--portal-lock-pr, var(--portal-sbw, 0px)); }
/* Plain fields inside pages on the design system and inside Portal.ui surfaces look like .ds-input (zero specificity:
   a page's own class always wins). */
:where(.portal-page .app-main, .ds-dialog, .ds-sheet, .ds-drawer) :where(input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="file"]):not([type="color"]):not([type="hidden"]), textarea) {
    min-height: var(--field-h); padding: 8px 12px; border: 1px solid var(--clr-border); border-radius: var(--radius-md);
    background: var(--clr-surface); color: var(--clr-text-heading); font-size: var(--fs-md); line-height: var(--lh-snug);
    transition: border-color var(--transition-speed), box-shadow var(--transition-speed);
}
/* The field ring is for text fields only: a checkbox, radio, range, file or color input keeps its own focus outline. */
:where(.portal-page .app-main, .ds-dialog, .ds-sheet, .ds-drawer) :where(input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="file"]):not([type="color"]), textarea):focus { outline: none; border-color: var(--clr-primary); box-shadow: var(--ring); }
:where(.portal-page .app-main, .ds-dialog, .ds-sheet, .ds-drawer) :where(input, textarea)::placeholder { color: var(--clr-text-muted); }
:where(.portal-page .app-main, .ds-dialog, .ds-sheet, .ds-drawer) :where(input, textarea):disabled { background: var(--clr-surface-muted); color: var(--clr-text-muted); cursor: not-allowed; }

/* =========================================================================================
   TONES (set --t-bg / --t-ink / --t-solid / --t-line) and the category palette (.ds-cat-N sets --c / --c-bg / --c-ink)
   ========================================================================================= */
.ds-tone-neutral { --t-bg: var(--clr-surface-muted); --t-ink: var(--clr-text-body); --t-solid: var(--clr-text-muted); --t-line: var(--clr-border); }
.ds-tone-primary, .ds-tone-info { --t-bg: var(--clr-primary-light); --t-ink: var(--clr-primary-ink); --t-solid: var(--clr-primary); --t-line: var(--clr-primary-line); }
.ds-tone-success { --t-bg: var(--clr-success-soft); --t-ink: var(--clr-success-tone-ink); --t-solid: var(--clr-success); --t-line: var(--clr-success-line); }
.ds-tone-warning { --t-bg: var(--clr-warning-soft); --t-ink: var(--clr-amber-ink); --t-solid: var(--clr-warning); --t-line: var(--clr-warning-line); }
.ds-tone-danger { --t-bg: var(--clr-danger-soft); --t-ink: var(--clr-danger-tone-ink); --t-solid: var(--clr-danger); --t-line: var(--clr-danger-line); }
.ds-tone-purple { --t-bg: var(--clr-purple-soft); --t-ink: var(--clr-purple-ink); --t-solid: var(--clr-purple); --t-line: var(--clr-purple-line); }
.ds-tone-pink { --t-bg: var(--clr-pink-soft); --t-ink: var(--clr-pink-ink); --t-solid: var(--clr-pink); --t-line: var(--clr-pink-line); }
.ds-tone-indigo { --t-bg: var(--clr-indigo-soft); --t-ink: var(--clr-indigo-ink); --t-solid: var(--clr-indigo); --t-line: var(--clr-indigo-line); }
.ds-tone-teal { --t-bg: var(--clr-teal-soft); --t-ink: var(--clr-teal-ink); --t-solid: var(--clr-teal); --t-line: var(--clr-teal-line); }
.ds-tone-sky { --t-bg: var(--clr-sky-soft); --t-ink: var(--clr-sky-ink); --t-solid: var(--clr-sky); --t-line: var(--clr-sky-line); }
.ds-cat-0 { --c: var(--cat-0); --c-bg: var(--cat-0-bg); --c-ink: var(--cat-0-ink); --cat: var(--c); --cat-bg: var(--c-bg); --cat-ink: var(--c-ink); }
.ds-cat-1 { --c: var(--cat-1); --c-bg: var(--cat-1-bg); --c-ink: var(--cat-1-ink); --cat: var(--c); --cat-bg: var(--c-bg); --cat-ink: var(--c-ink); }
.ds-cat-2 { --c: var(--cat-2); --c-bg: var(--cat-2-bg); --c-ink: var(--cat-2-ink); --cat: var(--c); --cat-bg: var(--c-bg); --cat-ink: var(--c-ink); }
.ds-cat-3 { --c: var(--cat-3); --c-bg: var(--cat-3-bg); --c-ink: var(--cat-3-ink); --cat: var(--c); --cat-bg: var(--c-bg); --cat-ink: var(--c-ink); }
.ds-cat-4 { --c: var(--cat-4); --c-bg: var(--cat-4-bg); --c-ink: var(--cat-4-ink); --cat: var(--c); --cat-bg: var(--c-bg); --cat-ink: var(--c-ink); }
.ds-cat-5 { --c: var(--cat-5); --c-bg: var(--cat-5-bg); --c-ink: var(--cat-5-ink); --cat: var(--c); --cat-bg: var(--c-bg); --cat-ink: var(--c-ink); }
.ds-cat-none { --c: var(--cat-none); --c-bg: var(--cat-none-bg); --c-ink: var(--cat-none-ink); --cat: var(--c); --cat-bg: var(--c-bg); --cat-ink: var(--c-ink); }
.ds-cat-indigo { --c: var(--clr-indigo); --c-bg: var(--clr-indigo-soft); --c-ink: var(--clr-indigo-ink); --cat: var(--c); --cat-bg: var(--c-bg); --cat-ink: var(--c-ink); }
.ds-icon-btn { width: var(--ctl-h-md); height: var(--ctl-h-md); display: inline-grid; place-items: center; border-radius: var(--radius-md); border: 1px solid transparent; background: transparent; color: var(--clr-text-body); cursor: pointer; position: relative; flex: none; padding: 0; }
@media (hover: hover) { .ds-icon-btn:hover:not(:disabled, :where([aria-disabled="true"]:not(.is-loading))) { background: var(--clr-surface-muted); color: var(--clr-text-heading); } }
.ds-icon-btn:disabled { opacity: 0.45; cursor: default; }
.ds-icon-btn:where([aria-disabled="true"]:not(.is-loading)) { opacity: 0.45; cursor: default; }
.ds-icon-btn svg.ds-i { width: var(--icon-lg); height: var(--icon-lg); }
.ds-icon-btn.is-bordered { border-color: var(--clr-border); background: var(--clr-surface); width: var(--ctl-h-sm); height: var(--ctl-h-sm); }
.ds-icon-btn.is-bordered svg.ds-i { width: var(--icon-md); height: var(--icon-md); }
/* .is-field: the bordered icon button at a field's height (--field-h: 40 px, 44 px on touch and phones), level with a
   search box or a select beside it (a narrow column's Filters button). Its border darkens on hover, and while what it
   opens is open ([aria-expanded="true"]) it takes the primary tint. */
.ds-icon-btn.is-bordered.is-field { width: var(--field-h); height: var(--field-h); }
@media (hover: hover) { .ds-icon-btn.is-bordered.is-field:hover:not(:disabled, :where([aria-disabled="true"]:not(.is-loading))) { border-color: var(--clr-border-hover); } }
.ds-icon-btn.is-bordered.is-field[aria-expanded="true"] { border-color: var(--clr-primary); background: var(--clr-primary-light); color: var(--clr-primary-ink); }
.ds-icon-btn.is-sm { width: var(--ctl-h-sm); height: var(--ctl-h-sm); }
.ds-icon-btn.is-lg { width: var(--ctl-h-lg); height: var(--ctl-h-lg); }
/* A toggle (.is-toggle: AI Chat's message-box options): aria-pressed="true" shows it on, in the primary tint, or in the
   tone of a .ds-tone-* on the button itself (dictation: danger). Opt-in: an icon button with aria-pressed and no
   .is-toggle (Account's password eye, User Management's reveal, Build's review toggle) keeps its own look. */
.ds-icon-btn.is-toggle[aria-pressed="true"]:not([class*="ds-tone-"]) { background: var(--clr-primary-light); color: var(--clr-primary-ink); border-color: var(--clr-primary-line); }
.ds-icon-btn.is-toggle[aria-pressed="true"][class*="ds-tone-"] { background: var(--t-bg); color: var(--t-ink); border-color: var(--t-line); }
/* A live button (.is-live: recording, speaking): a ring pulses out of it in --t-solid (its own tone, else the primary).
   None under reduced motion. */
.ds-icon-btn.is-live:not(.is-loading)::after { content: ""; position: absolute; inset: -1px; border-radius: inherit; pointer-events: none; color: var(--clr-primary); animation: ds-live-ring 1.6s var(--ease-out) infinite; }
.ds-icon-btn.is-live[class*="ds-tone-"]:not(.is-loading)::after { color: var(--t-solid); }
@keyframes ds-live-ring { 0% { box-shadow: 0 0 0 0 currentColor; opacity: 0.7; } 100% { box-shadow: 0 0 0 8px currentColor; opacity: 0; } }
/* Corner marks: a count (.ds-count: "3", "Draft") over the top right corner, or a dot (.ds-dot) inside it; a 2 px ring
   in the surface color keeps either apart from the icon. */
.ds-icon-btn > .ds-count { position: absolute; top: -4px; right: -6px; min-width: 16px; height: 16px; padding: 0 4px; font-size: var(--fs-2xs); pointer-events: none; box-shadow: 0 0 0 2px var(--clr-surface); }
.ds-icon-btn > .ds-count.is-muted { box-shadow: inset 0 0 0 1px var(--clr-border), 0 0 0 2px var(--clr-surface); }
.ds-icon-btn > .ds-count.is-warning { box-shadow: inset 0 0 0 1px var(--clr-warning-line), 0 0 0 2px var(--clr-surface); }
.ds-icon-btn > .ds-dot { position: absolute; top: 5px; right: 5px; pointer-events: none; box-shadow: 0 0 0 2px var(--clr-surface); }
.ds-linkbtn { border: 0; background: none; color: var(--clr-link); font-weight: var(--fw-semibold); font-size: var(--fs-sm); cursor: pointer; padding: 5px 6px; border-radius: var(--radius-sm); white-space: nowrap; display: inline-flex; align-items: center; gap: 4px; }
@media (hover: hover) { .ds-linkbtn:hover:not(:disabled) { background: var(--clr-primary-light); } }
.ds-linkbtn:disabled { color: var(--clr-text-muted); cursor: default; opacity: 0.7; }
.ds-linkbtn.is-danger { color: var(--clr-danger-text); padding: 4px 8px; }   /* danger words use -text (AA); the solid is for icons and borders */
@media (hover: hover) { .ds-linkbtn.is-danger:hover:not(:disabled) { background: var(--clr-danger-soft); } }
/* .is-wrap: a link button that names a record ("Back to “Weekly report”"): a long name wraps inside the box it is in
   (it never pushes that box sideways), left aligned, with the icon on the first line. The icon is the kit's
   svg.ds-i (Portal.iconEl) or an element holding one; anything else (a name in a <b> or <span>) wraps as text. */
.ds-linkbtn.is-wrap { white-space: normal; text-align: left; overflow-wrap: anywhere; max-width: 100%; align-items: flex-start; }
.ds-linkbtn.is-wrap > :is(svg.ds-i, :has(> svg.ds-i)) { flex: none; display: inline-flex; align-items: center; height: 1lh; }
/* Row link: the text button in a list row that opens the row's details (a name, a test's date). Heading ink,
   semibold, left-aligned, block and full width (a page may make it inline so a badge can follow); link ink and an
   underline on hover; 44 px on touch screens (a block or inline-block one). Pages keep only layout (ellipsis, nowrap).
   Used by EPOC, HR Compliance and Ticket Admin. */
.ds-rowlink { display: block; width: 100%; padding: 0; border: 0; border-radius: var(--radius-xs); background: none; font: inherit; font-weight: var(--fw-semibold); color: var(--clr-text-heading); text-decoration: none; text-align: left; cursor: pointer; }
@media (hover: hover) { .ds-rowlink:hover { color: var(--clr-link); text-decoration: underline; } }
.ds-rowlink:focus-visible { outline: 2px solid var(--clr-focus-ring); outline-offset: 2px; }
.ds-chipbtn { height: 30px; padding: 0 12px; border-radius: var(--radius-pill); border: 1px solid var(--clr-border); background: var(--clr-surface); font-size: var(--fs-label); font-weight: var(--fw-semibold); color: var(--clr-text-body); cursor: pointer; display: inline-flex; align-items: center; gap: 6px; }
/* A tone (.ds-tone-warning: something in what the chip filters needs attention) tints the chip until it is pressed. */
.ds-chipbtn[class*="ds-tone-"]:not([aria-pressed="true"]) { border-color: var(--t-line); background: var(--t-bg); color: var(--t-ink); }
@media (hover: hover) { .ds-chipbtn:hover:not(:disabled) { border-color: var(--clr-primary); color: var(--clr-primary); } }
.ds-chipbtn[aria-pressed="true"] { border-color: var(--clr-primary); background: var(--clr-primary-light); color: var(--clr-primary-hover); }
.ds-chipbtn:disabled { opacity: 0.5; cursor: not-allowed; }
.ds-actionbar { display: flex; gap: 8px; align-items: center; width: 100%; }
.ds-actionbar > * { flex: 1 1 auto; }
.ds-actionbar button { min-height: var(--ctl-h-touch); }
.ds-input, .ds-textarea {
    width: 100%; min-height: var(--field-h); padding: 8px 12px; border: 1px solid var(--clr-border); border-radius: var(--radius-md);
    background: var(--clr-surface); color: var(--clr-text-heading); font-size: var(--fs-md); font-family: inherit; line-height: var(--lh-snug);
    transition: border-color var(--transition-speed), box-shadow var(--transition-speed);
}
.ds-input::placeholder, .ds-textarea::placeholder { color: var(--clr-text-muted); }
@media (hover: hover) { .ds-input:hover, .ds-textarea:hover { border-color: var(--clr-border-hover); } }
.ds-input:focus, .ds-textarea:focus { outline: none; border-color: var(--clr-primary); box-shadow: var(--ring); }
.ds-input:disabled, .ds-textarea:disabled { background: var(--clr-surface-muted); color: var(--clr-text-muted); cursor: not-allowed; }
.ds-textarea { resize: vertical; min-height: 72px; display: block; }
:is(.ds-input, .ds-textarea, .ds-select-trigger, .ds-numin, .ds-search)[aria-invalid="true"], .ds-numin.is-invalid { border-color: var(--clr-danger) !important; }
:is(.ds-input, .ds-textarea, .ds-select-trigger)[aria-invalid="true"]:focus-visible { box-shadow: var(--ring-danger); }
.ds-form { display: flex; flex-direction: column; gap: 14px; }
.ds-form-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px 16px; }
.ds-form-grid.is-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.ds-form-grid > .is-full { grid-column: 1 / -1; }
.ds-field { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.ds-label { font-size: var(--fs-label); font-weight: var(--fw-semibold); color: var(--clr-text-body); }
.ds-optional { font-weight: var(--fw-medium); color: var(--clr-text-muted); }
.ds-hint { font-size: var(--fs-xs); font-weight: var(--fw-regular); color: var(--clr-text-muted); line-height: 1.4; }
.ds-field-error { display: block; margin-top: 2px; font-size: var(--fs-xs); font-weight: var(--fw-semibold); color: var(--clr-danger-text); line-height: var(--lh-snug); }
/* A warning hint (Portal.ui.warnHint, fieldWarning): the warning icon, the text in --clr-amber-ink, as the Notifications
   kit's .is-warn hint; .is-line keeps the size and weight around it (a line among others). */
.ds-hint.is-warn { display: flex; align-items: flex-start; gap: var(--space-1-5); margin: 0; font-weight: var(--fw-semibold); color: var(--clr-amber-ink); }
.ds-hint.is-warn > svg.ds-i { flex: none; width: var(--icon-sm); height: var(--icon-sm); margin-top: 1px; color: var(--clr-warning-hover); }
.ds-hint.is-warn.is-line { font-size: inherit; font-weight: inherit; line-height: inherit; }
.ds-hint.is-warn.is-line > svg.ds-i { margin-top: 0.2em; }
.ds-fieldset { border: 1px solid var(--clr-border); border-radius: var(--radius-lg); padding: 12px 16px 16px; margin: 0; min-width: 0; }
.ds-fieldset > legend { padding: 0 6px; font-size: var(--fs-label); font-weight: var(--fw-semibold); color: var(--clr-text-body); }
.ds-check { display: flex; align-items: flex-start; gap: 10px; font-size: var(--fs-md); color: var(--clr-text-heading); cursor: pointer; }
.ds-check input { width: 18px; height: 18px; margin: 2px 0 0; flex: none; accent-color: var(--clr-primary); }
.ds-check input:focus-visible { outline: 2px solid var(--clr-focus-ring); outline-offset: 2px; }
.ds-check.is-disabled { color: var(--clr-text-muted); cursor: not-allowed; }
.ds-check-text { display: flex; flex-direction: column; gap: 1px; }
.ds-numin { display: flex; align-items: center; height: var(--field-h); border: 1px solid var(--clr-border); border-radius: var(--radius-md); background: var(--clr-surface); padding: 0 12px; gap: 6px; }
.ds-numin:focus-within { border-color: var(--clr-primary); box-shadow: var(--ring); }
.ds-numin-input { border: 0; outline: 0; box-shadow: none; background: transparent; width: 100%; min-width: 0; padding: 0; font-size: var(--fs-md); font-weight: var(--fw-semibold); color: var(--clr-text-heading); }
.ds-numin-unit { color: var(--clr-text-muted); font-size: var(--fs-sm); white-space: nowrap; }
.ds-numin-step { width: 28px; height: 28px; margin-right: -6px; display: grid; place-items: center; border: 0; border-radius: var(--radius-sm); background: none; color: var(--clr-text-muted); cursor: pointer; }
@media (hover: hover) { .ds-numin-step:hover { background: var(--clr-surface-muted); color: var(--clr-text-heading); } }
.ds-search { display: flex; align-items: center; gap: 8px; height: var(--field-h); padding: 0 6px 0 12px; border: 1px solid var(--clr-border); border-radius: var(--radius-md); background: var(--clr-surface); color: var(--clr-text-muted); min-width: 0; transition: border-color var(--transition-speed), box-shadow var(--transition-speed); }
@media (hover: hover) { .ds-search:hover { border-color: var(--clr-border-hover); } }
.ds-search:focus-within { border-color: var(--clr-primary); box-shadow: var(--ring); }
.ds-search-input { flex: 1; min-width: 0; border: 0; outline: 0; box-shadow: none; background: transparent; padding: 0; font-size: var(--fs-md); color: var(--clr-text-heading); }
.ds-search-input::placeholder { color: var(--clr-text-muted); }
/* The kit draws its own clear button (.ds-search-x): the browser's own on a type="search" field stays hidden. */
.ds-search-input::-webkit-search-cancel-button, .ds-search-input::-webkit-search-decoration { -webkit-appearance: none; appearance: none; }
.ds-search-x { width: 28px; height: 28px; display: grid; place-items: center; border: 0; border-radius: var(--radius-sm); background: none; color: var(--clr-text-muted); cursor: pointer; flex: none; }
@media (hover: hover) { .ds-search-x:hover { background: var(--clr-surface-muted); color: var(--clr-text-heading); } }
.ds-search-x svg.ds-i { width: var(--icon-sm); height: var(--icon-sm); }
.ds-kbd { display: inline-flex; align-items: center; padding: 0 6px; border: 1px solid var(--clr-border); border-bottom-width: 2px; border-radius: var(--radius-sm); background: var(--clr-surface); color: var(--clr-text-muted); font: inherit; font-size: 11px; font-weight: var(--fw-semibold); line-height: 18px; white-space: nowrap; }
/* A search box's key hint ("/") is for a keyboard and a mouse: it shows only where the pointer is fine and hovers
   (search({kbd})), never on a touch screen. */
@media (hover: none), (pointer: coarse), (pointer: none) { .ds-search > .ds-kbd { display: none; } }
.ds-daterange { display: inline-flex; width: 100%; align-items: center; gap: 0; border: 1px solid var(--clr-border); border-radius: var(--radius-md); background: var(--clr-surface); height: var(--field-h); max-width: 100%; }
.ds-daterange .ds-input { border: 0; min-height: 0; height: 100%; width: auto; min-width: 0; flex: 1 1 120px; padding: 0 8px 0 12px; background: transparent; box-shadow: none; }
.ds-daterange-sep { color: var(--clr-text-muted); font-size: var(--fs-sm); padding: 0 2px; flex: none; }
.ds-daterange-presets { border-left: 1px solid var(--clr-border); align-self: stretch; display: flex; align-items: center; padding: 0 3px; flex: none; }
.ds-daterange .ds-date { flex: 1 1 120px; width: auto; min-width: 0; height: 100%; }
/* dateRange({openEnd}): the range, then its check ("No return date yet") under it; while ticked the To field is
   disabled and empty. */
.ds-daterange-open { display: flex; flex-direction: column; align-items: stretch; gap: var(--space-2); min-width: 0; }
.ds-daterange-check { align-self: flex-start; max-width: 100%; }
.ds-daterange .ds-date.is-disabled .ds-input { background: transparent; }
/* Date field (Portal.ui.dateInput): a text field for typed dates, and a calendar button inside its right edge. The
   field stands in for the native date input; its calendar (.ds-cal) runs Monday to Sunday. */
.ds-date { position: relative; display: block; width: 100%; min-width: 0; }
.ds-date .ds-input.ds-date-input { width: 100%; padding-right: calc(var(--ctl-h-sm) + var(--space-2)); font-variant-numeric: tabular-nums; }
.ds-date-btn { position: absolute; top: 50%; right: var(--space-1); transform: translateY(-50%); width: var(--ctl-h-sm); height: var(--ctl-h-sm); padding: 0; display: grid; place-items: center; border: 0; border-radius: var(--radius-sm); background: none; color: var(--clr-text-muted); cursor: pointer; }
.ds-date.is-open .ds-date-btn { background: var(--clr-surface-muted); color: var(--clr-primary); }
@media (hover: hover) { .ds-date-btn:hover:not(:disabled) { background: var(--clr-surface-muted); color: var(--clr-primary); } }
.ds-date-btn:disabled, .ds-date-input:disabled ~ .ds-date-btn { cursor: not-allowed; opacity: 0.5; pointer-events: none; }
.ds-date-btn svg.ds-i { width: var(--icon-md); height: var(--icon-md); }
/* The calendar: in a popover (.ds-pop.ds-cal-pop) on desktop, a bottom sheet (.ds-sheet.ds-cal-sheet) on phones. */
.ds-cal { display: flex; flex-direction: column; gap: var(--space-1); width: calc(7 * var(--ctl-h-lg) + 2 * var(--space-2)); max-width: 100%; padding: var(--space-2) var(--space-2) var(--space-1-5); }
.ds-cal-head { display: flex; align-items: center; gap: var(--space-1); }
/* A calendar taller than its sheet or popover (a short screen: a phone on its side; .is-scrolls, set when it opens)
   scrolls under its month row and weekday row, which stay at the top, and its box keeps what it scrolls into view clear
   of them (scroll-padding-top). --ds-cal-head-h, set on the popover and the sheet, is the month row's height: its arrow
   buttons'. */
.ds-cal-pop { --ds-cal-head-h: var(--ctl-h-sm); }
.ds-cal.is-scrolls .ds-cal-head { position: sticky; top: 0; z-index: 2; background: var(--clr-surface); }
.ds-cal.is-scrolls .ds-cal-grid th { position: sticky; top: var(--ds-cal-head-h, var(--ctl-h-sm)); z-index: 2; background: var(--clr-surface); }
:is(.ds-pop, .ds-sheet-body):has(> .ds-cal.is-scrolls) { scroll-padding-top: calc(var(--ds-cal-head-h, var(--ctl-h-sm)) + var(--ctl-h-xs)); }
.ds-cal-title { flex: 1 1 auto; margin: 0; text-align: center; font-size: var(--fs-title); font-weight: var(--fw-bold); color: var(--clr-text-heading); }
.ds-cal-nav.ds-icon-btn { width: var(--ctl-h-sm); height: var(--ctl-h-sm); }
.ds-cal-grid { width: 100%; table-layout: fixed; border-collapse: separate; border-spacing: 0 2px; }
.ds-cal-grid th { height: var(--ctl-h-xs); padding: 0; text-align: center; font-size: var(--fs-2xs); font-weight: var(--fw-bold); letter-spacing: var(--tracking-caps); text-transform: uppercase; color: var(--clr-text-muted); }
.ds-cal-day { position: relative; height: var(--ctl-h-md); padding: 0; text-align: center; vertical-align: middle; cursor: pointer; color: var(--clr-text-heading); outline: none; }
.ds-cal-n { display: inline-grid; place-items: center; width: var(--ctl-h-sm); height: var(--ctl-h-sm); border-radius: var(--radius-pill); font-size: var(--fs-sm); font-weight: var(--fw-semibold); font-variant-numeric: tabular-nums; }
@media (hover: hover) { .ds-cal-day:hover .ds-cal-n { background: var(--clr-surface-muted); } }
.ds-cal-day.is-other { color: var(--clr-text-muted); }
.ds-cal-day.is-other .ds-cal-n { font-weight: var(--fw-regular); }
.ds-cal-day.is-today .ds-cal-n { box-shadow: inset 0 0 0 1.5px var(--clr-primary); color: var(--clr-primary-ink); font-weight: var(--fw-bold); }
.ds-cal-day.is-inrange { background: var(--clr-primary-light); }
.ds-cal-day.is-rstart { border-radius: var(--radius-pill) 0 0 var(--radius-pill); }
.ds-cal-day.is-rend { border-radius: 0 var(--radius-pill) var(--radius-pill) 0; }
.ds-cal-day.is-rstart.is-rend { border-radius: var(--radius-pill); }
.ds-cal-day:is(.is-sel, .is-rstart, .is-rend) .ds-cal-n { background: var(--clr-primary-fill); color: var(--clr-on-accent); box-shadow: none; }
.ds-cal-day[aria-disabled="true"] { color: var(--clr-text-muted); cursor: not-allowed; }
.ds-cal-day[aria-disabled="true"] .ds-cal-n { background: none; font-weight: var(--fw-regular); opacity: 0.45; }
.ds-cal-day:focus-visible .ds-cal-n { box-shadow: var(--ring), inset 0 0 0 1.5px var(--clr-primary); }
.ds-cal-mark { position: absolute; left: 50%; bottom: 1px; width: 5px; height: 5px; margin-left: -2.5px; border-radius: 50%; background: var(--t-ink); pointer-events: none; }
.ds-cal-foot { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); padding-top: var(--space-1); border-top: 1px solid var(--clr-border); }
.ds-cal-clear { margin-left: auto; }
/* A calendar sheet stays calendar-sized where the screen is wide (a phone on its side, a short window). */
.ds-sheet.ds-cal-sheet { width: 100%; max-width: 480px; margin-inline: auto; --ds-cal-head-h: var(--ctl-h-touch); }
.ds-cal-sheet .ds-cal { width: 100%; padding: 0 0 var(--space-1); }
.ds-cal-sheet .ds-cal-nav.ds-icon-btn { width: var(--ctl-h-touch); height: var(--ctl-h-touch); }
.ds-cal-sheet .ds-cal-day { height: var(--ctl-h-touch); }
.ds-cal-sheet .ds-cal-n { width: var(--ctl-h-lg); height: var(--ctl-h-lg); font-size: var(--fs-md); }
.ds-cal-sheet .ds-cal-mark { width: 6px; height: 6px; margin-left: -3px; }
.ds-cal-sheet .ds-cal-foot .ds-linkbtn { min-height: var(--ctl-h-touch); padding-inline: var(--space-3); font-size: var(--fs-md); }
/* =========================================================================================
   SELECT (searchable combobox) AND MULTI-SELECT
   ========================================================================================= */
.ds-select { position: relative; display: inline-flex; min-width: 180px; max-width: 100%; vertical-align: middle; }
.ds-select.is-block { display: flex; width: 100%; min-width: 0; }
.ds-select-trigger { display: flex; align-items: center; gap: 8px; width: 100%; min-width: 0; min-height: var(--field-h); padding: 0 10px 0 12px; border: 1px solid var(--clr-border); border-radius: var(--radius-md); background: var(--clr-surface); color: var(--clr-text-heading); font-size: var(--fs-md); font-weight: var(--fw-medium); text-align: left; cursor: pointer; transition: border-color var(--transition-speed), box-shadow var(--transition-speed); }
@media (hover: hover) { .ds-select-trigger:hover:not(:disabled) { border-color: var(--clr-border-hover); } }
.ds-select-trigger:focus-visible { outline: none; border-color: var(--clr-primary); box-shadow: var(--ring); }
.ds-select.is-open .ds-select-trigger { border-color: var(--clr-primary); box-shadow: var(--ring); }
.ds-select-trigger:disabled { background: var(--clr-surface-muted); color: var(--clr-text-muted); cursor: not-allowed; }
.ds-select-value { flex: 1 1 auto; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ds-select-trigger.is-placeholder .ds-select-value { color: var(--clr-text-muted); }
.ds-select-icon, .ds-select-chev { display: inline-grid; color: var(--clr-text-muted); flex: none; }
.ds-select-chev svg.ds-i { width: var(--icon-sm); height: var(--icon-sm); transition: transform var(--dur) var(--ease); }
.ds-select.is-open .ds-select-chev svg.ds-i { transform: rotate(180deg); }
.ds-select.is-sm .ds-select-trigger { min-height: var(--ctl-h-sm); font-size: var(--fs-sm); padding: 0 8px 0 10px; }
.ds-multi.is-filtered .ds-select-trigger { border-color: var(--clr-filtered-line); background: var(--clr-primary-light); }
.ds-multi.is-filtered .ds-select-icon { color: var(--clr-primary); }
.ds-listpop { display: flex; flex-direction: column; min-height: 0; max-height: inherit; flex: 1 1 auto; }
.ds-listpop-search { display: flex; align-items: center; gap: 8px; margin: 8px 8px 4px; padding: 0 10px; height: var(--ctl-h-md); border: 1px solid var(--clr-border); border-radius: var(--radius-md); background: var(--clr-surface); color: var(--clr-text-muted); flex: none; }
.ds-listpop-search:focus-within { border-color: var(--clr-primary); box-shadow: var(--ring); }
.ds-listpop-input { border: 0; outline: 0; background: transparent; box-shadow: none; flex: 1; min-width: 0; padding: 0; font-size: var(--fs-md); color: var(--clr-text-heading); }
.ds-listpop-input::placeholder { color: var(--clr-text-muted); }
.ds-listpop-tools { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 2px 10px 4px 12px; flex: none; min-height: 30px; }
.ds-listpop-note { font-size: var(--fs-xs); color: var(--clr-text-muted); }
.ds-listpop-tools.is-foot { padding: 8px 10px; border-top: 1px solid var(--clr-border); background: var(--clr-head-bg); }
.ds-listpop-tools.is-foot .ds-listpop-note { flex: 1 1 auto; text-align: center; }
.ds-listbox { list-style: none; margin: 0; padding: 4px 6px 6px; overflow: auto; overscroll-behavior: contain; position: relative; min-height: 0; flex: 1 1 auto; outline: none; }
.ds-opt { display: flex; align-items: center; gap: 10px; min-height: 34px; padding: 5px 10px; border-radius: 7px; cursor: pointer; font-size: var(--fs-md); color: var(--clr-text-heading); line-height: 1.3; }
.ds-opt.is-active { background: var(--clr-row-hover); box-shadow: inset 0 0 0 1px var(--clr-border-hover); }
.ds-opt.is-selected, .ds-opt.is-pinned { font-weight: var(--fw-semibold); }
.ds-opt.is-disabled { cursor: not-allowed; color: var(--clr-text-muted); }
.ds-opt-main { display: flex; flex-direction: column; min-width: 0; flex: 1 1 auto; }
.ds-opt-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ds-opt-detail, .ds-opt-reason { font-size: var(--fs-xs); font-weight: var(--fw-regular); color: var(--clr-text-muted); }
.ds-opt-reason { font-style: italic; }
.ds-opt-aside { margin-left: auto; font-size: var(--fs-xs); color: var(--clr-text-muted); font-weight: var(--fw-semibold); white-space: nowrap; flex: none; }
.ds-opt-check { color: var(--clr-primary); display: inline-grid; flex: none; }
/* An option's icon (items {icon}): muted before its label, the label's color while it is the chosen one. */
.ds-opt-ic { display: inline-grid; flex: none; color: var(--clr-text-muted); }
.ds-opt-ic svg.ds-i { width: var(--icon-md); height: var(--icon-md); }
.ds-opt.is-selected .ds-opt-ic { color: var(--clr-text-heading); }
/* Options with a status dot and badges (select() items {dot, dotLabel, badges}: AI Chat's model picker). The dot is an
   8 px circle in its tone's --t-solid, level with the first line; the chosen item's dot shows in the trigger too
   (.ds-select-dot); the badges (small kit badges) follow the label and wrap under it when the list is narrow. */
.ds-opt-dot, .ds-select-dot { width: 8px; height: 8px; border-radius: 50%; flex: none; background: var(--t-solid, var(--clr-text-muted)); }
.ds-opt-dot { align-self: flex-start; margin-top: calc(0.65em - 4px); }
.ds-opt-head { display: flex; flex-wrap: wrap; align-items: center; gap: 2px 6px; min-width: 0; }
.ds-opt-badges { display: inline-flex; flex-wrap: wrap; gap: 4px; min-width: 0; }
.ds-opt-group { position: sticky; top: -4px; z-index: 1; margin: 4px -6px 2px; padding: 6px 16px 4px; font-size: var(--fs-xs); font-weight: var(--fw-bold); letter-spacing: var(--tracking-caps); text-transform: uppercase; color: var(--clr-head-ink); background: var(--clr-surface); border-bottom: 1px solid var(--clr-border); list-style: none; }
/* One option group: its heading and its options share a box, so the sticky heading scrolls away with its group
   (a wrapped, taller heading never stays pinned under the next group's). */
.ds-opt-gblock, .ds-opt-gl { display: block; list-style: none; margin: 0; padding: 0; }
.ds-opt-sep { height: 1px; background: var(--clr-border); margin: 4px; list-style: none; }
.ds-listpop-empty { padding: 14px 16px 16px; font-size: var(--fs-sm); color: var(--clr-text-muted); text-align: center; }
.ds-cbx { width: 16px; height: 16px; border-radius: var(--radius-xs); border: 1.5px solid var(--clr-border-hover); display: grid; place-items: center; flex: none; background: var(--clr-surface); color: var(--clr-on-accent); }
.ds-cbx svg.ds-i { width: 12px; height: 12px; stroke-width: 3; visibility: hidden; }
.ds-cbx.is-on, .ds-cbx.is-mixed { background: var(--clr-primary); border-color: var(--clr-primary); }
.ds-cbx.is-on svg.ds-i, .ds-cbx.is-mixed svg.ds-i { visibility: visible; }
.ds-tick { flex: none; display: grid; place-items: center; width: 26px; height: 26px; margin: -5px; padding: 0; border: 0; border-radius: var(--radius-sm); background: none; cursor: pointer; }
@media (hover: hover) { .ds-tick:not(:disabled, [aria-disabled="true"]):hover { background: var(--clr-row-hover); } .ds-tick:not(:disabled, [aria-disabled="true"]):hover .ds-cbx { border-color: var(--clr-primary); } }
.ds-tick:focus-visible { outline: 2px solid var(--clr-focus-ring); outline-offset: 0; }
.ds-tick:disabled, .ds-tick[aria-disabled="true"] { cursor: default; opacity: 0.6; }
.ds-returnbar { display: flex; align-items: center; gap: 12px; padding: 8px 14px 8px 8px; border: 1px solid var(--clr-primary-line); border-radius: var(--radius-lg); background: var(--clr-current-bg); }
.ds-returnbar > .btn-primary { flex: none; gap: 6px; }
.ds-returnbar-t { min-width: 0; font-size: var(--fs-sm); color: var(--clr-text-body); }
.ds-returnbar-t b { color: var(--clr-text-heading); }
.ds-railtoggle { flex: none; width: 32px; height: 32px; }
.ds-rail-head { flex: none; display: flex; align-items: center; justify-content: center; min-height: 46px; padding: 6px 2px; }
.ds-rail-name { display: flex; align-items: center; gap: 8px; width: 100%; padding: 12px 0; border: 0; background: none; color: var(--clr-text-heading); font: inherit; font-size: var(--fs-sm); font-weight: var(--fw-bold); writing-mode: vertical-rl; cursor: pointer; }
.ds-rail-name:focus-visible { outline: 2px solid var(--clr-focus-ring); outline-offset: -2px; }
@media (hover: hover) { .ds-rail-name:hover { color: var(--clr-primary-ink); } }
.ds-chip { display: inline-flex; align-items: center; gap: 2px; height: 28px; padding: 0 3px 0 10px; border-radius: var(--radius-pill); background: var(--clr-primary-light); color: var(--clr-primary-hover); font-size: var(--fs-label); font-weight: var(--fw-semibold); max-width: 100%; }
.ds-chip-x { width: 24px; height: 24px; flex: none; border-radius: 50%; border: 0; background: transparent; color: inherit; display: grid; place-items: center; cursor: pointer; padding: 0; }
@media (hover: hover) { .ds-chip-x:hover { background: var(--clr-primary-line); } }
.ds-chip-x svg.ds-i { width: var(--icon-xs); height: var(--icon-xs); }
/* File chip (.ds-chip.is-file: an attachment, a produced or fetched file): a tile (.ds-chip-tile, an icon) or a
   thumbnail (.ds-chip-thumb), the name (.ds-chip-name, an ellipsis) and its meta (.ds-chip-meta: size, progress) in
   .ds-chip-text, on the surface with a border on every ground; 40 px tall (44 on touch screens), 280 px wide at most.
   The link form (a.ds-chip.is-file) downloads or opens it, an icon at its end (a direct svg.ds-i) says which;
   .ds-chip-bar is an upload's progress along the bottom edge (the page sets its width); .is-error is a failed upload
   (its bar goes). */
.ds-chip.is-file { position: relative; overflow: hidden; height: 40px; max-width: min(280px, 100%); gap: 8px; padding: 0 8px 0 6px; border-radius: var(--radius-md); background: var(--clr-surface); color: var(--clr-text-heading); box-shadow: inset 0 0 0 1px var(--clr-border); font-size: var(--fs-sm); font-weight: var(--fw-regular); text-decoration: none; vertical-align: top; }
.ds-chip-tile { display: grid; place-items: center; width: 28px; height: 28px; flex: none; border-radius: var(--radius-sm); background: var(--clr-surface-muted); color: var(--clr-text-muted); }
.ds-chip-thumb { display: block; width: 28px; height: 28px; flex: none; border-radius: var(--radius-sm); object-fit: cover; background: var(--clr-paper); }
.ds-chip-text { display: flex; align-items: baseline; gap: 6px; min-width: 0; flex: 1 1 auto; }
.ds-chip-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: var(--fw-semibold); }
.ds-chip-meta { flex: none; white-space: nowrap; font-size: var(--fs-xs); color: var(--clr-text-muted); font-variant-numeric: tabular-nums; }
.ds-chip.is-file > svg.ds-i { color: var(--clr-text-muted); }
.ds-chip.is-file > .ds-chip-x { color: var(--clr-text-muted); }
@media (hover: hover) {
    .ds-chip.is-file > .ds-chip-x:hover { background: var(--clr-surface-muted); color: var(--clr-text-heading); }
    a.ds-chip.is-file:hover { background: var(--clr-surface-muted); box-shadow: inset 0 0 0 1px var(--clr-border-hover); }
    a.ds-chip.is-file:hover > svg.ds-i { color: var(--clr-text-heading); }
}
.ds-chip-bar { position: absolute; left: 0; bottom: 0; width: 0; height: 3px; background: var(--clr-primary); transition: width var(--dur) var(--ease); }
.ds-chip.is-file.is-error { background: var(--clr-danger-soft); color: var(--clr-danger-tone-ink); box-shadow: inset 0 0 0 1px var(--clr-danger-line); }
.ds-chip.is-file.is-error .ds-chip-meta, .ds-chip.is-file.is-error .ds-chip-tile, .ds-chip.is-file.is-error > svg.ds-i { color: inherit; }
.ds-chip.is-file.is-error > .ds-chip-bar { display: none; }
/* =========================================================================================
   SEGMENTED, SWITCH
   ========================================================================================= */
.ds-seg { display: inline-flex; align-items: center; min-height: var(--ctl-h-md); padding: 3px; border: 1px solid var(--clr-border); border-radius: var(--radius-md); background: var(--clr-seg-track); gap: 2px; flex: none; max-width: 100%; overflow-x: auto; scrollbar-width: none; }
/* A segmented strip wider than its box (segmented() marks what scrolls it) fades at the edge where there is more. */
.ds-hfade-end { -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent); mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent); }
.ds-hfade-start { -webkit-mask-image: linear-gradient(to left, #000 calc(100% - 28px), transparent); mask-image: linear-gradient(to left, #000 calc(100% - 28px), transparent); }
.ds-hfade-start.ds-hfade-end { -webkit-mask-image: linear-gradient(to right, transparent, #000 28px, #000 calc(100% - 28px), transparent); mask-image: linear-gradient(to right, transparent, #000 28px, #000 calc(100% - 28px), transparent); }
.ds-seg::-webkit-scrollbar { display: none; }
.ds-seg.is-block { display: flex; width: 100%; }
.ds-seg.is-block .ds-seg-btn { flex: 1; justify-content: center; }
/* Groups (segmented() items with sep: true): each group is its own track, side by side; one control for the keyboard. */
.ds-seg.is-split { padding: 0; border: 0; border-radius: 0; background: none; gap: var(--space-2); }
.ds-seg-group { display: inline-flex; align-items: center; align-self: stretch; gap: 2px; padding: 3px; border: 1px solid var(--clr-border); border-radius: var(--radius-md); background: var(--clr-seg-track); flex: none; }
.ds-seg.is-block.is-split .ds-seg-group { flex: 1 1 auto; }
.ds-seg-btn { display: inline-flex; align-items: center; gap: 6px; height: 28px; padding: 0 10px; border: 0; border-radius: var(--radius-sm); background: transparent; font-size: var(--fs-sm); font-weight: var(--fw-semibold); color: var(--clr-text-body); cursor: pointer; white-space: nowrap; flex: none; }
@media (hover: hover) { .ds-seg-btn:hover:not(:disabled) { color: var(--clr-text-heading); } }
.ds-seg-btn[aria-checked="true"] { background: var(--clr-seg-on); color: var(--clr-text-heading); box-shadow: var(--shadow-seg-on); }
.ds-seg-btn:disabled { opacity: 0.5; cursor: not-allowed; }
.ds-seg-btn svg.ds-i { width: var(--icon-sm); height: var(--icon-sm); }
.ds-seg.is-sm { min-height: var(--ctl-h-sm); }
.ds-seg.is-sm .ds-seg-btn { height: var(--ctl-h-xs); padding: 0 9px; font-size: var(--fs-label); }
.ds-seg-count { font-size: var(--fs-xs); font-weight: var(--fw-bold); color: var(--clr-text-muted); }
/* segmented({narrow: "select"}): the track and a select of the same choices in one .ds-seg-wrap; at 600 px and below
   only the select shows (a phone never scrolls a strip of choices sideways), with the counts as its items' asides. */
.ds-seg-wrap { display: inline-flex; min-width: 0; max-width: 100%; }
.ds-seg-wrap.is-block { display: flex; width: 100%; }
.ds-seg-wrap > .ds-seg-narrow { display: none; }
.ds-switch { display: inline-flex; align-items: flex-start; gap: 10px; cursor: pointer; font-size: var(--fs-md); color: var(--clr-text-heading); }
.ds-switch .toggle-switch { margin-top: 1px; }
.ds-switch-text { display: flex; flex-direction: column; gap: 1px; }
.ds-switch-label { font-weight: var(--fw-medium); }
.ds-switch.is-disabled { color: var(--clr-text-muted); cursor: not-allowed; }
/* =========================================================================================
   BADGES, COUNTS, TAGS, DOTS, AVATAR, CODE
   ========================================================================================= */
.ds-badge { display: inline-flex; align-items: center; gap: 4px; height: 22px; padding: 0 8px; border-radius: var(--radius-sm); font-size: var(--fs-xs); font-weight: var(--fw-semibold); white-space: nowrap; line-height: 1; background: var(--t-bg, var(--clr-surface-muted)); color: var(--t-ink, var(--clr-text-body)); vertical-align: middle; }
.ds-badge.ds-tone-neutral { box-shadow: inset 0 0 0 1px var(--clr-border); }
.ds-badge svg.ds-i { width: var(--icon-xs); height: var(--icon-xs); stroke-width: 2.1; }
.ds-badge.is-sm { height: 20px; padding: 0 6px; }
.ds-count { display: inline-grid; place-items: center; min-width: 20px; height: 18px; padding: 0 6px; border-radius: var(--radius-pill); background: var(--clr-danger-fill); color: var(--clr-on-accent); font-size: var(--fs-xs); font-weight: var(--fw-bold); line-height: 1; font-variant-numeric: tabular-nums; }
.ds-count.is-primary { background: var(--clr-primary-fill); color: var(--clr-on-accent); }
.ds-count.is-muted { background: var(--clr-surface-muted); color: var(--clr-text-body); box-shadow: inset 0 0 0 1px var(--clr-border); }
.ds-gcount { display: inline-grid; place-items: center; min-width: 22px; height: 20px; padding: 0 7px; border-radius: var(--radius-pill); background: var(--clr-surface); box-shadow: inset 0 0 0 1px var(--clr-border-hover); font-size: var(--fs-xs); font-weight: var(--fw-bold); color: var(--clr-text-heading); }
.ds-pill { display: inline-flex; align-items: center; gap: 6px; height: 24px; padding: 0 10px; border-radius: var(--radius-pill); background: var(--t-bg, var(--clr-primary-light)); color: var(--t-ink, var(--clr-primary-hover)); font-size: var(--fs-xs); font-weight: var(--fw-bold); letter-spacing: 0.04em; text-transform: uppercase; white-space: nowrap; }
.ds-pill.is-live::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: var(--t-solid, var(--clr-success)); }
.ds-tag { display: inline-flex; align-items: center; gap: 5px; font-size: var(--fs-xs); font-weight: var(--fw-semibold); padding: 1px 7px; border-radius: var(--radius-sm); line-height: var(--lh-base); background: var(--c-bg); color: var(--c-ink); white-space: nowrap; }
.ds-tag.is-dot::before { content: ""; width: 7px; height: 7px; border-radius: 2px; background: var(--c); }
.ds-dot { width: 8px; height: 8px; border-radius: 2px; display: inline-block; flex: none; background: var(--c, var(--clr-primary)); }
.ds-dot.is-round { border-radius: 50%; }
.ds-avatar { width: 30px; height: 30px; border-radius: 50%; background: var(--clr-avatar-bg); color: var(--clr-avatar-ink); font-size: var(--fs-xs); font-weight: var(--fw-bold); display: grid; place-items: center; flex: none; box-shadow: inset 0 0 0 1px var(--clr-primary-line); letter-spacing: 0.02em; overflow: hidden; }
.ds-avatar.is-lg { width: 42px; height: 42px; font-size: var(--fs-md); }
/* Smaller avatars: .is-sm 24 px (a list row), .is-xs 20 px (a post's head, a property); .is-empty: a dashed ring for
   "nobody" (no initials; its tip says so), which may hold an icon (a role). */
.ds-avatar.is-sm { width: 24px; height: 24px; font-size: var(--fs-2xs); line-height: 1; letter-spacing: 0; }
.ds-avatar.is-xs { width: 20px; height: 20px; font-size: var(--fs-3xs); line-height: 1; letter-spacing: 0; }
.ds-avatar.is-empty { background: none; color: var(--clr-text-muted); box-shadow: none; border: 1.5px dashed var(--clr-border-hover); }
.ds-avatar.is-empty svg.ds-i { width: 60%; height: 60%; }
.ds-code { margin: 0; padding: 12px 14px; border-radius: var(--radius-md); background: var(--clr-code-bg); color: var(--clr-code-ink); border: 1px solid var(--clr-code-border); font-family: var(--font-mono); font-size: var(--fs-sm); line-height: var(--lh-relaxed); overflow: auto; }
.ds-code .c-meta { color: var(--clr-code-meta); }
/* Code block (.ds-codeblock: rendered markdown's fenced code, AI Chat's code runs): a 32 px head on --clr-code-head with
   the language (.ds-codeblock-lang) and a Copy button (.ds-codeblock-copy: its copy icon, then its check icon, which
   replaces it while .is-copied, then its words), over a .ds-code body: 400 px tall at most outside page flow, as tall as
   its code where the page flows, scrolling sideways. .ds-hl-* color the syntax with the --clr-code-* tokens (fixed: the
   code ground is dark in both themes); comments are italic. */
.ds-codeblock { min-width: 0; border: 1px solid var(--clr-code-border); border-radius: var(--radius-md); background: var(--clr-code-bg); overflow: hidden; }
.ds-codeblock-head { display: flex; align-items: center; gap: 8px; min-height: 32px; padding: 2px 4px 2px 12px; background: var(--clr-code-head); }
.ds-codeblock-lang { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--clr-code-meta); }
.ds-codeblock-copy { flex: none; display: inline-flex; align-items: center; justify-content: center; gap: 6px; height: 26px; padding: 0 8px; border: 1px solid var(--clr-code-border); border-radius: var(--radius-sm); background: transparent; color: var(--clr-code-meta); font: inherit; font-size: var(--fs-xs); font-weight: var(--fw-semibold); cursor: pointer; }
.ds-codeblock-copy:focus-visible { outline-offset: 0; }
.ds-codeblock-copy svg.ds-i { width: var(--icon-sm); height: var(--icon-sm); }
.ds-codeblock-copy > svg.ds-i:nth-of-type(2), .ds-codeblock-copy.is-copied > svg.ds-i:nth-of-type(1) { display: none; }
.ds-codeblock-copy.is-copied > svg.ds-i:nth-of-type(2) { display: inline-block; }
.ds-codeblock-copy.is-copied { color: var(--clr-code-ink); }
@media (hover: hover) { .ds-codeblock-copy:hover { background: var(--clr-code-hover); color: var(--clr-code-ink); } }
.ds-codeblock > .ds-code { margin: 0; border: 0; border-top: 1px solid var(--clr-code-border); border-radius: 0; max-height: 400px; scrollbar-width: thin; scrollbar-color: var(--scrollbar-thumb) var(--scrollbar-track); }
.ds-codeblock code { padding: 0; border-radius: 0; background: none; box-shadow: none; color: inherit; font: inherit; }
.ds-hl-kw { color: var(--clr-code-kw); }
.ds-hl-str { color: var(--clr-code-str); }
.ds-hl-com { color: var(--clr-code-com); font-style: italic; }
.ds-hl-num { color: var(--clr-code-num); }
.ds-desc { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: 8px 16px; margin: 0; font-size: var(--fs-md); }
.ds-desc dt { color: var(--clr-text-muted); font-weight: var(--fw-medium); }
.ds-desc dd { margin: 0; color: var(--clr-text-heading); min-width: 0; overflow-wrap: anywhere; }
/* .is-compact: in a small card (a facts card, the keyboard shortcuts' popover): --fs-sm, closer together. */
.ds-desc.is-compact { gap: 6px 12px; font-size: var(--fs-sm); }
/* Property list (Portal.ui.props: a record's properties, each a label and its control or value). Two columns, labels
   at the start; .is-row: one row of equal columns, labels above, never wrapping above 600 px (a row too narrow for its values goes two by two,
   .is-pairs; a value still too long ends in an ellipsis and its tip shows it whole); .is-readonly: plain values. Selects inside stay
   bordered. At 600 px and below a row stacks (media queries, below). */
.ds-props { display: grid; grid-template-columns: max-content minmax(0, 1fr); align-items: start; gap: 6px 12px; margin: 0; }
.ds-prop { display: contents; }
.ds-prop-label { line-height: var(--ctl-h-sm); font-size: var(--fs-label); font-weight: var(--fw-medium); color: var(--clr-text-muted); }
.ds-prop-value { margin: 0; min-width: 0; display: flex; flex-direction: column; align-items: flex-start; gap: 2px; color: var(--clr-text-heading); font-size: var(--fs-md); }
.ds-prop-value > .ds-select { width: 100%; min-width: 0; max-width: none; }
.ds-prop-text { display: block; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ds-prop-note { font-size: var(--fs-xs); color: var(--clr-text-muted); }
.ds-props.is-readonly .ds-prop-value { min-height: var(--ctl-h-sm); justify-content: center; }
.ds-props.is-row { grid-template-columns: repeat(var(--ds-props-n, 4), minmax(0, 1fr)); gap: 0 12px; }
.ds-props.is-row .ds-prop { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.ds-props.is-row .ds-prop-label { display: flex; align-items: center; gap: 6px; min-width: 0; height: 16px; line-height: 16px; font-size: var(--fs-xs); font-weight: var(--fw-semibold); white-space: nowrap; }
.ds-props.is-row .ds-prop-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
/* A label's action ("Assign to me") reaches above and below the 16 px line, so every value in the row starts level. */
.ds-props.is-row .ds-prop-label .ds-linkbtn { flex: none; margin: -5px -6px -5px auto; font-size: var(--fs-xs); font-weight: var(--fw-semibold); }
.ds-props.is-row .ds-prop-value { width: 100%; }
/* .is-pairs: a row too narrow for every value whole, measured by props() from the row's own width: two by two. Not on a
   phone, where a row stacks. */
@media (min-width: 601px) {
    .ds-props.is-row.is-pairs { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px 12px; }
}
/* In a low window (wider than 1100 px, under 640 px tall: a laptop with a docked console; Portal.ui.lowMQ) a row drops
   its label line, unless a label carries an action: each control keeps its name (aria-labelledby reads a hidden label
   too), and props() puts the label first in the value's tip. */
@media (min-width: 1101px) and (max-height: 639px) {
    .ds-props.is-row:not(:has(.ds-prop-label > :not(.ds-prop-name))) .ds-prop-label { display: none; }
}
/* Facts row (Portal.ui.facts: a record's facts, the requester, a tag, linked records, times, history): small bordered
   pills, each opening its card (a popover; a sheet on phones). It wraps. A fact is --ctl-h-sm tall, 44 px on touch
   (below); its words are cut with an ellipsis past 260 px and the button's name says them whole. */
.ds-facts { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; min-width: 0; }
.ds-fact { display: inline-flex; align-items: center; gap: 6px; flex: none; max-width: min(260px, 100%); height: var(--ctl-h-sm); padding: 0 8px 0 10px; border: 1px solid var(--clr-border); border-radius: var(--radius-pill); background: var(--clr-surface); color: var(--clr-text-body); font: inherit; font-size: var(--fs-label); font-weight: var(--fw-medium); line-height: 1; white-space: nowrap; cursor: pointer; }
.ds-fact-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; line-height: var(--lh-snug); }
.ds-fact > svg.ds-i { flex: none; width: var(--icon-sm); height: var(--icon-sm); color: var(--clr-text-muted); }
.ds-fact > svg.ds-i.ds-fact-chev { width: 14px; height: 14px; margin-left: -2px; }
.ds-fact b { font-weight: var(--fw-bold); color: var(--clr-text-heading); }
/* A person's fact: the avatar (.ds-avatar.is-xs) sits in the pill's round end. */
.ds-fact.has-avatar { padding-left: 4px; }
.ds-fact > .ds-avatar { flex: none; }
/* A tone (.ds-tone-danger: a red tag) tints the pill; its words and icons take the tone's ink. */
.ds-fact[class*="ds-tone-"] { background: var(--t-bg); border-color: var(--t-line); color: var(--t-ink); }
.ds-fact[class*="ds-tone-"] b, .ds-fact[class*="ds-tone-"] > svg.ds-i { color: inherit; }
@media (hover: hover) {
    .ds-fact:hover { border-color: var(--clr-border-hover); background: var(--clr-surface-muted); }
    .ds-fact[class*="ds-tone-"]:hover { border-color: var(--t-solid); background: var(--t-bg); }
}
.ds-fact[aria-expanded="true"] { border-color: var(--clr-primary); background: var(--clr-primary-light); }
/* Its card pads itself in a popover (.ds-pop has no padding), at most 380 px wide; in a sheet the sheet pads it and its
   heading hides, since the sheet's title says it. Focused from code as it opens (the dialog's content): no ring. */
.ds-fact-card { display: flex; flex-direction: column; gap: 10px; min-width: 0; max-width: 380px; padding: 14px 16px; font-size: var(--fs-sm); color: var(--clr-text-body); line-height: var(--lh-base); }
.ds-fact-card:focus { outline: none; }
.ds-fact-card > p { margin: 0; }
.ds-fact-card-title { margin: 0; font-size: var(--fs-xs); font-weight: var(--fw-bold); letter-spacing: var(--tracking-caps); text-transform: uppercase; color: var(--clr-text-muted); }
.ds-fact-links { display: flex; flex-direction: column; align-items: flex-start; gap: 2px; margin: 0 -6px; }
.ds-sheet .ds-fact-card { padding: 0; max-width: none; }
.ds-sheet .ds-fact-card > .ds-fact-card-title { display: none; }
/* =========================================================================================
   CARD, STAT, PAGE HEAD, SECTION HEAD, NOTICE
   ========================================================================================= */
.ds-card-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 8px 16px; flex-wrap: wrap; margin-bottom: 14px; }
.ds-card-title { margin: 0; font-size: var(--fs-lg); font-weight: var(--fw-bold); color: var(--clr-text-heading); letter-spacing: -0.005em; line-height: 1.3; }
/* A card title focused from code (tabindex="-1": "Show the guide again" brings its card back) draws no ring, as a page
   head's h1. */
.ds-card-title[tabindex="-1"]:focus { outline: none; }
.ds-card-desc { margin: 2px 0 0; font-size: var(--fs-sm); color: var(--clr-text-muted); line-height: var(--lh-base); max-width: 68ch; }
.ds-card-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-left: auto; }
.ds-card-foot { display: flex; justify-content: flex-end; gap: 8px; margin: 16px -20px -20px; padding: 12px 16px; border-top: 1px solid var(--clr-border); background: var(--clr-bg); border-radius: 0 0 var(--radius-lg) var(--radius-lg); }
.ds-card-foot:not(:has(> :not([hidden]))) { display: none; }   /* every button in it hidden: no empty strip */
.ds-stats { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 8px; }
.ds-stat { display: flex; flex-direction: column; gap: 2px; padding: 10px 12px; border-radius: var(--radius-md); border: 1px solid var(--clr-border); background: var(--clr-bg); }
.ds-stat-n { font-size: 20px; font-weight: var(--fw-bold); line-height: 1.1; color: var(--clr-text-heading); font-variant-numeric: tabular-nums; }
.ds-stat-l { font-size: var(--fs-xs); color: var(--clr-text-muted); }
.ds-stat-d { font-size: var(--fs-xs); font-weight: var(--fw-semibold); color: var(--t-ink); display: inline-flex; align-items: center; gap: 3px; }
.ds-page-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 12px 24px; padding: 22px 0 18px; margin: 0; flex-wrap: wrap; }
.ds-page-title { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1 1 420px; }
.ds-page-back { display: inline-flex; align-items: center; gap: 2px; align-self: flex-start; margin: 0 0 4px -4px; padding: 2px 6px 2px 2px; border-radius: var(--radius-sm); font-size: var(--fs-sm); font-weight: var(--fw-semibold); color: var(--clr-text-muted); text-decoration: none; min-width: 0; max-width: 100%; }
@media (hover: hover) { .ds-page-back:hover { color: var(--clr-text-heading); background: var(--clr-surface-muted); } }
.ds-page-back svg.ds-i { width: var(--icon-md); height: var(--icon-md); }
/* A label in a span (a pane bar's Back with a long view name) is cut with an ellipsis when its row is narrow. */
.ds-page-back > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ds-eyebrow { font-size: var(--fs-xs); font-weight: var(--fw-bold); letter-spacing: 0.08em; text-transform: uppercase; color: var(--clr-text-muted); }
.ds-page-head h1 { margin: 0; font-size: var(--fs-3xl); line-height: var(--lh-tight); font-weight: var(--fw-bold); color: var(--clr-text-heading); letter-spacing: var(--tracking-tight); }
/* A section's heading that a section switch focuses (tabindex="-1": page_head's id) takes focus for screen readers; it draws no ring. */
.ds-page-head h1[tabindex="-1"]:focus { outline: none; }
.ds-page-desc { margin: 2px 0 0; font-size: var(--fs-md); color: var(--clr-text-muted); line-height: var(--lh-base); }
.ds-page-actions { margin-left: auto; display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.ds-how { display: inline-flex; align-items: center; gap: 4px; padding: 0; border: 0; background: none; color: var(--clr-link); font-weight: var(--fw-semibold); font-size: var(--fs-sm); cursor: pointer; white-space: nowrap; }
@media (hover: hover) { .ds-how:hover { text-decoration: underline; } }
.ds-how svg.ds-i { width: var(--icon-sm); height: var(--icon-sm); }
/* howButton(title, body, {iconOnly}): the help icon alone, a small icon button whose name and tip are the title. */
.ds-how.is-icon { justify-content: center; flex: none; width: var(--ctl-h-sm); height: var(--ctl-h-sm); border-radius: var(--radius-md); color: var(--clr-text-muted); }
.ds-how.is-icon svg.ds-i { width: var(--icon-md); height: var(--icon-md); }
@media (hover: hover) { .ds-how.is-icon:hover { background: var(--clr-surface-muted); color: var(--clr-text-heading); text-decoration: none; } }
.ds-how.is-icon[aria-expanded="true"] { background: var(--clr-surface-muted); color: var(--clr-text-heading); }
.ds-how-pop { padding: 14px 16px; font-size: var(--fs-sm); color: var(--clr-text-body); line-height: var(--lh-relaxed); }
.ds-how-pop p { margin: 0 0 8px; }
/* A description list in it (the keyboard shortcuts: .ds-desc.is-compact) keeps a note under it at a distance. */
.ds-how-pop > .ds-desc + p { margin: 12px 0 0; }
.ds-how-title { font-weight: var(--fw-bold); color: var(--clr-text-heading); font-size: var(--fs-md); margin-bottom: 6px; }
/* As a phone's bottom sheet the sheet's own head names it and pads it: no second title, no second padding. */
.ds-sheet .ds-how-pop { padding: 0; }
.ds-sheet .ds-how-pop > .ds-how-title { display: none; }
.ds-how-list { margin: 0; padding-left: 18px; display: flex; flex-direction: column; gap: 6px; }
.ds-sec-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
.ds-sec-head h2 { margin: 0 0 2px; font-size: var(--fs-xl); font-weight: var(--fw-bold); color: var(--clr-text-heading); letter-spacing: -0.01em; }
.ds-sec-head p { margin: 0; max-width: 68ch; font-size: var(--fs-sm); line-height: var(--lh-base); color: var(--clr-text-muted); }
.ds-notice { display: flex; gap: 12px; align-items: flex-start; padding: 12px 16px; border-radius: var(--radius-lg); background: var(--t-bg); border: 1px solid var(--t-line); color: var(--t-ink); font-size: var(--fs-sm); }
.ds-notice > svg.ds-i { width: var(--icon-lg); height: var(--icon-lg); margin-top: 1px; }
.ds-notice > .ds-spinner { flex: none; width: var(--icon-lg); height: var(--icon-lg); margin-top: 1px; }   /* a notice for something under way */
.ds-notice-text { flex: 1; min-width: 0; }
.ds-notice-text strong { display: block; font-size: var(--fs-md); }
.ds-notice .ds-linkbtn { color: inherit; text-decoration: underline; padding: 0; }
.ds-notice-x { margin: -6px -8px -6px 0; color: inherit; width: 32px; height: 32px; }
/* notice({compact}): a record head's one- or two-line notice. The title runs into the text (.ds-notice-line holds
   both), the icon is --icon-md, padding 7px 12px. Folded (.is-folded: notice({fold}) or the page's class, whenever
   the notice whole would take its band too far; and always in a low window, wider than 1100 px and under 640 px
   tall: Portal.ui.lowMQ) it is one line cut with an ellipsis, its action still beside it, and More
   (.ds-notice-more, shown only when the line is cut: .is-cut) opens it whole (.is-open, More reads Less). Opened
   from folded it lies over what is under it (.is-over: raised with a shadow; the script gives it a negative bottom
   margin of the height it gained), so the band under it never moves. The rules are written twice, for the class
   and for the low window. */
.ds-notice.is-compact { gap: 8px; padding: 7px 12px; line-height: var(--lh-snug); }
.ds-notice.is-compact > svg.ds-i { width: var(--icon-md); height: var(--icon-md); margin-top: 1px; }
.ds-notice.is-compact .ds-notice-text strong { display: inline; font-size: inherit; }
.ds-notice.is-compact .ds-notice-x { margin-block: -7px; }
.ds-notice-more { display: none; }
.ds-notice.is-compact.is-over { position: relative; z-index: 4; box-shadow: var(--shadow-md); }
.ds-notice.is-compact.is-folded:not(.is-open) .ds-notice-text { display: flex; align-items: baseline; gap: 6px; }
.ds-notice.is-compact.is-folded:not(.is-open) .ds-notice-line { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ds-notice.is-compact.is-folded:not(.is-open) .ds-notice-text > .ds-linkbtn { flex: none; }
.ds-notice.is-compact.is-folded:is(.is-cut, .is-open) .ds-notice-more { display: inline-flex; }
@media (min-width: 1101px) and (max-height: 639px) {
    .ds-notice.is-compact:not(.is-open) .ds-notice-text { display: flex; align-items: baseline; gap: 6px; }
    .ds-notice.is-compact:not(.is-open) .ds-notice-line { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    .ds-notice.is-compact:not(.is-open) .ds-notice-text > .ds-linkbtn { flex: none; }
    .ds-notice.is-compact:is(.is-cut, .is-open) .ds-notice-more { display: inline-flex; }
}
/* =========================================================================================
   EMPTY, ERROR, SKELETON, PROGRESS
   ========================================================================================= */
.ds-empty { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 6px; padding: 40px 24px; color: var(--clr-text-muted); }
.ds-empty.is-compact { padding: 24px 16px; }
.ds-empty-ic { width: 44px; height: 44px; border-radius: var(--radius-lg); display: grid; place-items: center; background: var(--clr-primary-light); color: var(--clr-primary); margin-bottom: 4px; }
.ds-empty-ic svg.ds-i { width: var(--icon-2xl); height: var(--icon-2xl); }
.ds-empty[role="alert"] .ds-empty-ic { background: var(--clr-danger-soft); color: var(--clr-danger); }
.ds-empty-title { margin: 0; font-size: var(--fs-title); font-weight: var(--fw-bold); color: var(--clr-text-heading); }
/* A state's title focused from code (tabindex="-1", a pane that became this state) draws no ring on a heading. */
.ds-empty-title[tabindex="-1"]:focus { outline: none; }
.ds-empty-body { margin: 0; font-size: var(--fs-sm); max-width: 420px; }
.ds-empty > button { margin-top: 8px; }
.ds-skel { display: flex; flex-direction: column; gap: 10px; padding: 12px 14px; }
.ds-skel-row { display: flex; align-items: center; gap: 12px; }
.ds-skel-line, .ds-skel-dot, .ds-skel-card { display: block; border-radius: var(--radius-sm); background: linear-gradient(90deg, var(--clr-skel) 25%, var(--clr-skel-hi) 50%, var(--clr-skel) 75%); background-size: 200% 100%; animation: ds-shimmer 1.3s ease-in-out infinite; }
.ds-skel-line { height: 12px; }
.ds-skel-line.is-short { height: 10px; opacity: 0.7; }
.ds-skel-dot { width: 30px; height: 30px; border-radius: var(--radius-md); flex: none; }
.ds-skel-card { height: 84px; border-radius: var(--radius-lg); }
.ds-skel-cards { gap: 12px; }
@keyframes ds-shimmer { from { background-position: 100% 0; } to { background-position: -100% 0; } }
/* A live dot's ring (On site, the notification center's live dot): it grows from 0.3846 of its box (the dot's own
   size when the box is 2.6 times the dot) to the whole box, fading out. The box is the ring at its largest. */
@keyframes ds-pulse { 0% { transform: scale(0.3846); opacity: 0.9; } 80%, 100% { transform: scale(1); opacity: 0; } }
/* A status dot that is busy: it dims and comes back. */
@keyframes ds-blink { 50% { opacity: 0.3; } }
.ds-progress { display: flex; flex-direction: column; gap: 6px; }
.ds-progress-top { display: flex; justify-content: space-between; gap: 8px; font-size: var(--fs-sm); color: var(--clr-text-body); }
.ds-progress-top b { color: var(--clr-text-heading); font-weight: var(--fw-semibold); font-variant-numeric: tabular-nums; }
.ds-progress-bar { height: 6px; border-radius: 3px; background: var(--clr-surface-muted); box-shadow: inset 0 0 0 1px var(--clr-border); overflow: hidden; }
.ds-progress-bar > i { display: block; height: 100%; border-radius: 3px; background: var(--t-solid, var(--clr-primary)); }
.ds-progress.is-indeterminate .ds-progress-bar > i { width: 35%; animation: ds-indet 1.4s var(--ease-out) infinite; }
@keyframes ds-indet { from { transform: translateX(-100%); } to { transform: translateX(300%); } }
.ds-spinner { width: 16px; height: 16px; border-radius: 50%; border: 2px solid var(--clr-primary); border-right-color: transparent; border-bottom-color: transparent; animation: ds-spin 0.7s linear infinite; display: inline-block; }
/* Typing dots (.ds-typing holding three spans: a reply on its way): 6 px muted dots that rise in turn every 1.4 s;
   still under reduced motion. */
.ds-typing { display: inline-flex; align-self: flex-start; align-items: center; gap: 4px; padding: 8px 2px; }
.ds-typing > span { width: 6px; height: 6px; border-radius: 50%; background: var(--clr-text-muted); opacity: 0.4; animation: ds-typing 1.4s var(--ease) infinite; }
.ds-typing > span:nth-child(2) { animation-delay: 0.16s; }
.ds-typing > span:nth-child(3) { animation-delay: 0.32s; }
@keyframes ds-typing { 0%, 60%, 100% { transform: none; opacity: 0.4; } 30% { transform: translateY(-4px); opacity: 1; } }
/* Meter (.ds-meter: a total in parts, AI Chat's context use): a 6 px bar of .ds-meter-seg slices, each painting --c
   from its .ds-cat-* class (the page sets their widths); .is-striped stripes a slice, or a .ds-dot swatch, with --c-ink
   (a part not committed yet); .is-warn and .is-over outline the bar in --clr-warning and --clr-danger. */
.ds-meter { display: flex; height: 6px; min-width: 0; border-radius: var(--radius-pill); background: var(--clr-surface-muted); box-shadow: inset 0 0 0 1px var(--clr-border); overflow: hidden; }
.ds-meter-seg { flex: none; height: 100%; background: var(--c, var(--clr-primary)); transition: width var(--dur-slow) var(--ease-out); }
.ds-meter-seg + .ds-meter-seg { box-shadow: inset 1px 0 0 var(--clr-surface); }
:is(.ds-meter-seg, .ds-dot).is-striped { background: repeating-linear-gradient(135deg, var(--c, var(--clr-primary)) 0 3px, var(--c-ink, var(--clr-primary-ink)) 3px 6px); }
.ds-meter.is-warn { outline: 1px solid var(--clr-warning); outline-offset: 1px; }
.ds-meter.is-over { outline: 1px solid var(--clr-danger); outline-offset: 1px; }
/* =========================================================================================
   BOUNDED SCROLL, DATA LIST, TABLE, PAGER
   ========================================================================================= */
.ds-scroll { max-height: var(--ds-scroll-max, min(65vh, 720px)); overflow-y: auto; overscroll-behavior: contain; --ds-fade: 22px; --ds-list-top: 0px; scrollbar-width: thin; scrollbar-color: var(--scrollbar-thumb) var(--scrollbar-track); }
.ds-scroll:focus-visible { outline: 2px solid var(--clr-focus-ring); outline-offset: -2px; }
.ds-scroll.has-below { -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - var(--ds-fade)), transparent); mask-image: linear-gradient(to bottom, #000 calc(100% - var(--ds-fade)), transparent); }
.ds-scroll-head { position: sticky; top: var(--ds-list-top, 0px); z-index: 3; background: var(--clr-head-bg); color: var(--clr-head-ink); border-bottom: 1px solid var(--clr-head-line); font-size: var(--fs-xs); font-weight: var(--fw-bold); letter-spacing: var(--tracking-caps); text-transform: uppercase; }
.ds-scroll-head.is-stuck { box-shadow: var(--shadow-head); }
.ds-dl { display: flex; flex-direction: column; min-height: 0; background: var(--clr-surface); border: 1px solid var(--clr-border); border-radius: var(--radius-lg); overflow: hidden; }
/* Loading again while rows show (dataList setLoading(true)): the rows dim and ignore presses until the new ones come. */
.ds-dl.is-refreshing .ds-dl-body { opacity: 0.55; pointer-events: none; transition: opacity var(--dur) var(--ease-out); }
.ds-dl.is-refreshing.is-pressable .ds-dl-body { pointer-events: auto; }
/* dataList({maxHeight: "none"}): the list grows with its rows, no scroll box of its own. */
.ds-scroll.is-unbounded { max-height: none; overflow: visible; }
.ds-dl-head, .ds-dl-row { display: grid; grid-template-columns: var(--ds-dl-cols); column-gap: 14px; padding: 0 16px 0 8px; }
.ds-dl-head { position: sticky; top: var(--ds-list-top, 0px); z-index: 4; min-height: 40px; align-items: center; background: var(--clr-head-bg); border-bottom: 1px solid var(--clr-head-line); font-size: var(--fs-xs); font-weight: var(--fw-bold); text-transform: uppercase; letter-spacing: var(--tracking-caps); color: var(--clr-head-ink); }
.ds-dl-head.is-stuck { box-shadow: var(--shadow-head); }
.ds-dl-th { min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ds-dl-th.is-right, .ds-dl-cell.is-right { text-align: right; justify-content: flex-end; align-items: flex-end; }
.ds-dl-sort { display: inline-flex; align-items: center; gap: 4px; padding: 4px 0; border: 0; background: none; font: inherit; color: inherit; text-transform: inherit; letter-spacing: inherit; cursor: pointer; }
.ds-dl-sort.is-active { color: var(--clr-primary-ink); }   /* as a table's sorted head: AA on the tinted band */
.ds-dl-sort svg.ds-i { width: var(--icon-xs); height: var(--icon-xs); stroke-width: 2.2; }
/* .ds-dl-gsec wraps one group (its band and rows): the band's sticky range ends with its group, so it scrolls away
   as the next band arrives. No position on it: rows keep their offsetTop in the scroll box. */
.ds-dl-group { display: flex; align-items: center; gap: 8px; min-height: 32px; padding: 4px 16px; position: sticky; top: calc(var(--ds-list-top, 0px) + 40px + var(--ds-dl-cue-h, 0px)); z-index: 3; background: var(--clr-group-neutral); border-bottom: 1px solid var(--clr-border); font-size: var(--fs-sm); font-weight: var(--fw-bold); color: var(--clr-text-heading); }
.ds-dl-group.is-pending, .ds-dl-group.ds-group-pending { background: var(--clr-group-pending); }
.ds-dl-group.is-review, .ds-dl-group.ds-group-review { background: var(--clr-group-review); }
.ds-dl-group-ic { display: inline-grid; color: var(--clr-text-muted); }
.ds-dl-group:is(.is-pending, .ds-group-pending) .ds-dl-group-ic { color: var(--clr-warning-hover); }
.ds-dl-group:is(.is-review, .ds-group-review) .ds-dl-group-ic { color: var(--clr-purple); }
.ds-dl-group-note { font-weight: var(--fw-medium); color: var(--clr-text-muted); font-size: var(--fs-label); }
.ds-dl-row { min-height: 50px; padding-top: 6px; padding-bottom: 6px; align-items: center; border-bottom: 1px solid var(--clr-border); background: var(--clr-surface); position: relative; }
@media (hover: hover) { .ds-dl-row:hover { background: var(--clr-row-hover); } }
.ds-dl-row.is-expanded { background: var(--clr-primary-light); border-bottom-color: transparent; }
.ds-dl-row.is-expanded::before, .ds-dl-detail::before { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 3px; background: var(--clr-primary); }
.ds-dl-cell { min-width: 0; font-size: var(--fs-md); color: var(--clr-text-heading); display: flex; flex-direction: column; justify-content: center; align-items: flex-start; gap: 2px; overflow-wrap: anywhere; }
.ds-dl-cell > * { max-width: 100%; }
.ds-dl-exp { width: 28px; height: 28px; display: grid; place-items: center; border-radius: 7px; border: 1px solid transparent; background: transparent; color: var(--clr-text-muted); cursor: pointer; }
@media (hover: hover) { .ds-dl-exp:hover { background: var(--clr-surface-muted); border-color: var(--clr-border); color: var(--clr-text-heading); } }
.is-expanded .ds-dl-exp { color: var(--clr-primary); }
.is-expanded .ds-dl-exp svg.ds-i { transform: rotate(180deg); }
.ds-dl-detail { position: relative; background: var(--clr-surface); border-bottom: 1px solid var(--clr-border); padding: 4px 16px 14px 56px; font-size: var(--fs-sm); color: var(--clr-text-body); }
.ds-dl-foot { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 8px 12px 8px 16px; border-top: 1px solid var(--clr-border); font-size: var(--fs-sm); color: var(--clr-text-muted); background: var(--clr-surface); flex: none; flex-wrap: wrap; }
.ds-pager { display: inline-flex; align-items: center; gap: 6px; }
.ds-pager-label { font-weight: var(--fw-semibold); color: var(--clr-text-body); padding: 0 4px; }
.ds-cell-main { font-weight: var(--fw-semibold); color: var(--clr-text-heading); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ds-cell-sub { font-size: var(--fs-label); color: var(--clr-text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* A cell's two lines (.ds-cell-main over .ds-cell-sub): a column that can shrink, so they end in an ellipsis instead of
   widening the cell. */
.ds-cell-stack { display: flex; flex-direction: column; min-width: 0; }
/* In a table (a column is as wide as its widest text) a cell's lines are blocks of at most 320 px that end in an
   ellipsis (Portal.ui.tipWhenCut shows the whole text in a tip); in cards they wrap (below). */
.ds-table td .ds-cell-main, .ds-table td .ds-cell-sub { display: block; max-width: 320px; }
/* The column that takes the width the others leave (td.is-fill: the table's name): its lines end in an ellipsis at
   whatever width that is, so a long name never makes the table wider than its box. The other cells keep their text on
   one line at its own width (else the fill would squeeze them to their narrowest); long text belongs in the fill. */
.ds-table td.is-fill { width: 100%; max-width: 0; }
.ds-table td.is-fill :is(.ds-cell-main, .ds-cell-sub) { max-width: none; }
.ds-table:has(td.is-fill) :is(th, td):not(.is-fill, .ds-table-state) { white-space: nowrap; }
.ds-table-wrap { border: 1px solid var(--clr-border); border-radius: var(--radius-lg); background: var(--clr-surface); overflow: hidden; }
.ds-table { width: 100%; border-collapse: separate; border-spacing: 0; font-size: var(--fs-md); color: var(--clr-text-heading); background: var(--clr-surface); }
.ds-table thead th { position: sticky; top: var(--ds-list-top, 0px); z-index: 2; height: 40px; padding: 0 14px; text-align: left; background: var(--clr-head-bg); color: var(--clr-head-ink); border-bottom: 1px solid var(--clr-head-line); font-size: var(--fs-xs); font-weight: var(--fw-bold); letter-spacing: var(--tracking-caps); text-transform: uppercase; white-space: nowrap; }
.ds-table thead.is-stuck th { box-shadow: var(--shadow-head); }
.ds-table th[aria-sort] { cursor: pointer; }
.ds-table th[aria-sort] svg.ds-i { width: var(--icon-xs); height: var(--icon-xs); stroke-width: 2.2; margin-left: 2px; }
.ds-table th[aria-sort="ascending"], .ds-table th[aria-sort="descending"] { color: var(--clr-primary-ink); }
.ds-table td { height: 50px; padding: 6px 14px; border-bottom: 1px solid var(--clr-border); color: var(--clr-text-heading); vertical-align: middle; }
@media (hover: hover) { .ds-table tbody tr:hover td { background: var(--clr-row-hover); } }
.ds-table tbody tr:last-child td { border-bottom: 0; }
.ds-table .is-num { text-align: right; font-variant-numeric: tabular-nums; }
.ds-table .is-muted { color: var(--clr-text-muted); }
/* A table's loading, empty or error state: one cell across every column (Portal.ui.tableState). */
.ds-table tbody tr > td.ds-table-state { height: auto; padding: 0; white-space: normal; }
@media (hover: hover) { .ds-table tbody tr:hover > td.ds-table-state { background: none; } }
/* =========================================================================================
   POPOVER, MENU, SHEET, DRAWER, DIALOG, TOAST, TOOLTIP
   ========================================================================================= */
.ds-pop { position: fixed; z-index: var(--z-pop); left: 0; top: 0; background: var(--clr-surface); border: 1px solid var(--clr-pop-border); border-radius: var(--radius-lg); box-shadow: var(--shadow-pop); overflow: auto; overscroll-behavior: contain; display: flex; flex-direction: column; opacity: 0; transform: translateY(-4px); transition: opacity var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease); }
.ds-pop.is-open { opacity: 1; transform: none; }
.ds-pop.is-list { overflow: hidden; }
.ds-menu { padding: 6px; display: flex; flex-direction: column; }
.ds-menu-head { font-size: var(--fs-xs); font-weight: var(--fw-bold); letter-spacing: 0.07em; text-transform: uppercase; color: var(--clr-text-muted); padding: 8px 10px 4px; }
.ds-menu-item { display: flex; align-items: center; gap: 10px; min-height: 36px; padding: 6px 10px; border-radius: 7px; color: var(--clr-text-heading); text-decoration: none; font-size: 13.5px; font-weight: var(--fw-medium); background: none; border: 0; width: 100%; text-align: left; cursor: pointer; }
.ds-menu-item:focus-visible, .ds-menu-item.is-active { background: var(--clr-row-hover); outline: none; }
@media (hover: hover) { .ds-menu-item:hover:not(:disabled):not([aria-disabled="true"]) { background: var(--clr-row-hover); outline: none; } }
.ds-menu-item.is-danger { color: var(--clr-danger-text); }
.ds-menu-item .ds-count { margin-left: auto; }
.ds-menu-ic { display: inline-grid; place-items: center; color: var(--clr-text-muted); flex: none; }
.ds-menu-item.is-danger .ds-menu-ic { color: inherit; }
.ds-menu-item.has-desc { align-items: flex-start; padding: 8px 10px; }
.ds-menu-item.has-desc .ds-menu-ic { width: 30px; height: 30px; border-radius: var(--radius-md); background: var(--clr-surface-muted); color: var(--clr-primary); margin-top: 1px; }
/* An unavailable item (its description says why): muted, no hover, not clickable. */
.ds-menu-item:is(:disabled, [aria-disabled="true"]), .ds-menu-item:is(:disabled, [aria-disabled="true"]) .ds-menu-ic { color: var(--clr-text-muted); cursor: not-allowed; }
.ds-menu-text { display: flex; flex-direction: column; min-width: 0; line-height: 1.3; }
.ds-menu-label { font-weight: var(--fw-semibold); }
/* As a phone's bottom sheet a menu's title is the sheet's own title: not a second time inside. */
.ds-sheet .ds-menu > .ds-menu-head { display: none; }
/* A checked choice (menu() items {checked}): a tint and a check at the end. */
.ds-menu-item[aria-checked="true"] { background: var(--clr-primary-light); }
.ds-menu-check { margin-left: auto; display: inline-grid; color: var(--clr-primary-ink); flex: none; }
.ds-menu-check svg.ds-i { width: var(--icon-sm); height: var(--icon-sm); }
/* A menu's note line (menu() items {note}): context above the choices, not a choice. */
.ds-menu-note { margin: 2px 4px 6px; padding: 6px 8px; border-radius: var(--radius-sm); background: var(--clr-surface-muted); font-size: var(--fs-label); color: var(--clr-text-body); line-height: var(--lh-snug); }
.ds-menu-desc { font-size: var(--fs-xs); color: var(--clr-text-muted); white-space: normal; }
.ds-menu-sep { height: 1px; background: var(--clr-border); margin: 4px 4px; }
.ds-menu-kbd { margin-left: auto; }
.ds-sheet-wrap { position: fixed; inset: 0; z-index: var(--z-sheet); display: flex; flex-direction: column; justify-content: flex-end; }
.ds-sheet-scrim { position: absolute; inset: 0; background: var(--clr-scrim); opacity: 0; transition: opacity var(--dur-slow) var(--ease); }
.ds-sheet { position: relative; background: var(--clr-surface); border-radius: var(--radius-2xl) var(--radius-2xl) 0 0; max-height: min(92dvh, calc(100dvh - env(safe-area-inset-top, 0px) - 8px)); display: flex; flex-direction: column; box-shadow: var(--shadow-sheet); padding-bottom: env(safe-area-inset-bottom); transform: translateY(100%); transition: transform var(--dur-slow) var(--ease-out); outline: none; }
.ds-sheet-wrap.is-open .ds-sheet-scrim { opacity: 1; }
.ds-sheet-wrap.is-open .ds-sheet { transform: none; }
.ds-sheet-grab { width: 40px; height: 5px; border-radius: 3px; background: var(--clr-border-hover); margin: 8px auto 4px; flex: none; }
/* A phone on its side with a notch (the app, a home-screen web app): the sheet runs edge to edge, its contents keep
   clear of the notch and the rounded corners (the insets are 0 in a browser tab). */
.ds-sheet { padding-left: env(safe-area-inset-left, 0px); padding-right: env(safe-area-inset-right, 0px); }
/* A title wraps anywhere, so a long name with no spaces never pushes the Close button out of the panel. */
.ds-sheet-head { display: flex; align-items: center; gap: 8px; padding: 4px 12px 8px 16px; flex: none; }
.ds-sheet-title { margin: 0; font-size: var(--fs-lg); font-weight: var(--fw-bold); color: var(--clr-text-heading); min-width: 0; overflow-wrap: anywhere; }
.ds-sheet-close { margin-left: auto; width: var(--ctl-h-lg); height: var(--ctl-h-lg); }
.ds-sheet-body { overflow: auto; overscroll-behavior: contain; padding: 0 16px 16px; min-height: 0; flex: 1 1 auto; }
.ds-sheet-body > .ds-listpop { margin: 0 -16px; }
/* Portal.ui.sheet() (.ds-sheet-wrap.is-app) where popovers stay anchored (wider than 600 px and taller than 500 px,
   or wider than 1100 px): a centered panel, 560 px at most, that rises a little and fades in; no grab handle (the
   swipe that closes a bottom sheet is off here). Phones and short screens keep the bottom sheet. */
@media (min-width: 601px) and (min-height: 501px), (min-width: 1101px) {
    .ds-sheet-wrap.is-app { justify-content: center; align-items: center; padding: 24px; }
    .ds-sheet-wrap.is-app .ds-sheet { width: min(560px, 100%); border-radius: var(--radius-xl); transform: translateY(12px); opacity: 0; transition: transform var(--dur-slow) var(--ease-out), opacity var(--dur-slow) var(--ease); }
    .ds-sheet-wrap.is-app.is-open .ds-sheet { transform: none; opacity: 1; }
    .ds-sheet-wrap.is-app .ds-sheet-grab { display: none; }
    .ds-sheet-wrap.is-app .ds-sheet-head { padding-top: 12px; }
}
.ds-sheet-foot { padding: 10px 16px calc(12px + env(safe-area-inset-bottom)); border-top: 1px solid var(--clr-border); flex: none; }
/* A sheet with a foot: the foot keeps clear of the home indicator, so the sheet itself doesn't pad it a second time. */
.ds-sheet:has(> .ds-sheet-foot) { padding-bottom: 0; }
/* A sheet opened without a title still gets its Close button (a head with only the button). */
.ds-sheet-head.is-bare { padding-bottom: 0; }
/* Phone sheets and the on-screen keyboard (portal-surface.js sets these classes, and --portal-kb / --portal-vvh on :root,
   while the keyboard is up): a bottom sheet (the navbar's sheets, .ds-sheet, a dialog as a sheet) sits on the keyboard's
   top edge and fits the visible area; a kit wrapper ends there and its sheet or dialog fits inside it; while one of its
   text fields has focus, a bottom sheet keeps the height it had when typing began, capped at the visible area. Full-screen
   panels and dialogs end at the keyboard with no gap on top.
   !important: every sheet sets its own bottom and heights, later in the cascade. */
.portal-kb-lift { bottom: var(--portal-kb, 0px) !important; max-height: calc(var(--portal-vvh, 100dvh) - var(--space-2)) !important; }
.portal-kb-lift.portal-kb-wrap { max-height: none !important; }
.portal-kb-lift.portal-kb-full { max-height: var(--portal-vvh, 100dvh) !important; }
.portal-kb-fit { max-height: calc(100% - var(--space-2)) !important; }
.ds-dialog.portal-kb-fit:is(.is-md, .is-lg) { max-height: 100% !important; }
.portal-kb-hold { min-height: min(var(--portal-kb-hold, 0px), calc(var(--portal-vvh, 100dvh) - var(--space-2))) !important; }
.portal-kb-spacer { flex: none; }
.ds-drawer { background: var(--clr-surface); border-left: 1px solid var(--clr-pop-border); box-shadow: var(--shadow-pop-lg); width: 460px; max-width: 100%; display: flex; flex-direction: column; }
.ds-overlay { position: fixed; inset: 0; z-index: var(--z-modal); background: var(--clr-scrim); display: flex; align-items: center; justify-content: center; padding: 24px; opacity: 0; transition: opacity var(--dur) var(--ease); overflow: hidden; }
.ds-overlay.is-open { opacity: 1; }
.ds-dialog { position: relative; background: var(--clr-surface); border-radius: var(--radius-xl); box-shadow: var(--shadow-pop); width: 100%; max-height: calc(100dvh - 48px); display: flex; flex-direction: column; transform: translateY(8px) scale(0.985); transition: transform var(--dur) var(--ease); border: 1px solid var(--clr-dialog-border); }
.ds-overlay.is-open .ds-dialog { transform: none; }
.ds-dialog.is-sm { max-width: 440px; }
.ds-dialog.is-md { max-width: 560px; }
.ds-dialog.is-lg { max-width: 820px; }
.ds-dialog-head { display: flex; align-items: center; gap: 12px; padding: 16px 16px 12px 20px; flex: none; }
.ds-dialog-title { margin: 0; font-size: var(--fs-xl); font-weight: var(--fw-bold); color: var(--clr-text-heading); line-height: 1.3; min-width: 0; overflow-wrap: anywhere; }
.ds-dialog-x { margin-left: auto; }
.ds-dialog-body { padding: 0 20px 18px; overflow: auto; overscroll-behavior: contain; min-height: 0; flex: 1 1 auto; font-size: var(--fs-md); color: var(--clr-text-body); line-height: var(--lh-relaxed); }
.ds-dialog-msg { margin: 0 0 14px; }
.ds-dialog-msg:last-child { margin-bottom: 0; }
.ds-dialog-error { margin: 0 20px 12px; padding: 8px 12px; border-radius: var(--radius-md); background: var(--clr-danger-soft); color: var(--clr-danger-tone-ink); font-size: var(--fs-sm); font-weight: var(--fw-semibold); display: flex; gap: 8px; align-items: flex-start; }
.ds-dialog-error svg.ds-i { margin-top: 2px; }
/* ctx.setError(msg, {focus: true}) focuses the message to be read first: no ring on a message. */
.ds-dialog-error[tabindex="-1"]:focus { outline: none; }
/* A form's or a section's own error (a failed save, a server error with no field to point at): the dialog error's look,
   placed by the page (no margins of its own). Field errors are Portal.ui.fieldError's. */
.ds-form-error { margin: 0; padding: 8px 12px; border-radius: var(--radius-md); background: var(--clr-danger-soft); color: var(--clr-danger-tone-ink); font-size: var(--fs-sm); font-weight: var(--fw-semibold); display: flex; gap: 8px; align-items: flex-start; }
.ds-form-error svg.ds-i { margin-top: 2px; }
.ds-dialog-foot { display: flex; justify-content: flex-end; gap: 8px; padding: 12px 16px; border-top: 1px solid var(--clr-border); background: var(--clr-bg); border-radius: 0 0 var(--radius-xl) var(--radius-xl); flex: none; flex-wrap: wrap; }
.ds-dialog-foot > button { min-height: 38px; }
.ds-dialog-footnote { flex: 1 1 0; align-self: center; min-width: 0; font-size: var(--fs-sm); line-height: var(--lh-tight); color: var(--clr-text-muted); }
.ds-dialog-media { background: var(--clr-paper); border: 1px solid var(--clr-paper-line); border-radius: var(--radius-md); display: grid; place-items: center; min-height: 200px; color: var(--clr-paper-ink); }
.ds-toasts { position: fixed; bottom: max(calc(24px + env(safe-area-inset-bottom)), calc(var(--portal-float-clear, 0px) + var(--space-3))); left: 50%; transform: translateX(-50%); z-index: var(--z-toast); display: flex; flex-direction: column; gap: 8px; pointer-events: none; width: 420px; max-width: calc(100vw - 32px); }
.ds-toast { pointer-events: auto; display: flex; align-items: center; gap: 10px; padding: 11px 10px 11px 14px; border-radius: var(--radius-lg); background: var(--clr-surface); border: 1px solid var(--clr-pop-border); box-shadow: var(--shadow-toast); color: var(--clr-text-heading); font-size: var(--fs-md); font-weight: var(--fw-medium); }
.ds-toast-ic { display: inline-grid; flex: none; }
.ds-toast-ic svg.ds-i { width: var(--icon-xl); height: var(--icon-xl); }
.ds-toast.is-success .ds-toast-ic { color: var(--clr-success); }
.ds-toast.is-error { border-left: 3px solid var(--clr-danger); }
.ds-toast.is-error .ds-toast-ic { color: var(--clr-danger); }
.ds-toast.is-info .ds-toast-ic { color: var(--clr-primary); }
.ds-toast.is-warning .ds-toast-ic { color: var(--clr-warning-hover); }
.ds-toast-msg { flex: 1; line-height: 1.4; min-width: 0; }
.ds-toast-action { border: 0; background: none; color: var(--clr-link); font-weight: var(--fw-bold); font-size: var(--fs-sm); padding: 6px 8px; border-radius: var(--radius-sm); cursor: pointer; }
@media (hover: hover) { .ds-toast-action:hover { background: var(--clr-primary-light); } }
.ds-toast-close { width: 28px; height: 28px; display: grid; place-items: center; border: 0; background: none; color: var(--clr-text-muted); border-radius: var(--radius-sm); cursor: pointer; flex: none; }
@media (hover: hover) { .ds-toast-close:hover { background: var(--clr-surface-muted); color: var(--clr-text-heading); } }
/* Disclosure and timeline (plan CRITIC additions) */
.ds-disclosure { border: 1px solid var(--clr-border); border-radius: var(--radius-lg); background: var(--clr-surface); overflow: hidden; }
.ds-disclosure + .ds-disclosure { margin-top: 8px; }
.ds-disclosure-btn { display: flex; align-items: center; gap: 10px; width: 100%; min-height: 44px; padding: 8px 14px 8px 12px; border: 0; background: none; font: inherit; font-size: var(--fs-md); font-weight: var(--fw-semibold); color: var(--clr-text-heading); text-align: left; cursor: pointer; }
@media (hover: hover) { .ds-disclosure-btn:hover { background: var(--clr-row-hover); } }
.ds-disclosure-btn > svg.ds-i { color: var(--clr-text-muted); transition: transform var(--dur) var(--ease); }
.ds-disclosure-btn[aria-expanded="true"] > svg.ds-i { transform: rotate(90deg); }
.ds-disclosure-btn .ds-gcount { margin-left: auto; }
.ds-disclosure-body { padding: 2px 16px 14px 40px; font-size: var(--fs-sm); color: var(--clr-text-body); }
/* Variants (AI Chat's Thinking card and its cards; any page): .is-compact (36 px heads, 44 on touch screens, --fs-sm, a
   12 px body indent), .is-inset (a well on --clr-bg), both on --radius-md; a .ds-tone-* on the disclosure itself tints
   it (--t-bg, --t-line) and its head (--t-ink). The <details> form (details.ds-disclosure > summary.ds-disclosure-btn)
   opens natively: no marker, the chevron turns while it is open. */
.ds-disclosure:is(.is-compact, .is-inset) { border-radius: var(--radius-md); }
.ds-disclosure.is-compact > .ds-disclosure-btn { min-height: var(--ctl-h-md); padding: 6px 10px 6px 8px; gap: 8px; font-size: var(--fs-sm); }
.ds-disclosure.is-compact > .ds-disclosure-body { padding: 2px 12px 10px; }
.ds-disclosure.is-inset { background: var(--clr-bg); }
.ds-disclosure[class*="ds-tone-"] { background: var(--t-bg); border-color: var(--t-line); }
.ds-disclosure[class*="ds-tone-"] > .ds-disclosure-btn, .ds-disclosure[class*="ds-tone-"] > .ds-disclosure-btn > svg.ds-i { color: var(--t-ink); }
summary.ds-disclosure-btn { list-style: none; }
summary.ds-disclosure-btn::-webkit-details-marker { display: none; }
details[open] > summary.ds-disclosure-btn > svg.ds-i { transform: rotate(90deg); }
.ds-timeline { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.ds-tl-item { position: relative; display: grid; grid-template-columns: 22px minmax(0, 1fr); gap: 10px; padding-bottom: 14px; }
.ds-tl-item::before { content: ""; position: absolute; left: 10.5px; top: 22px; bottom: 0; width: 1px; background: var(--clr-border); }
.ds-tl-item:last-child::before { display: none; }
.ds-tl-dot { width: 22px; height: 22px; border-radius: 50%; display: grid; place-items: center; background: var(--t-bg); color: var(--t-ink); box-shadow: inset 0 0 0 1px var(--t-line); }
.ds-tl-dot svg.ds-i { width: var(--icon-xs); height: var(--icon-xs); stroke-width: 2.1; }
.ds-tl-top { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.ds-tl-title { font-size: var(--fs-md); font-weight: var(--fw-semibold); color: var(--clr-text-heading); }
.ds-tl-time { font-size: var(--fs-xs); color: var(--clr-text-muted); }
.ds-tl-body { font-size: var(--fs-sm); color: var(--clr-text-body); margin-top: 1px; }
/* Numbered steps (ol.ds-steps of li.ds-step): what to do, in order. The number is a 24 px circle in the primary tint;
   the step's content (.ds-step-text, a field, a QR code) sits beside it. Two-step sign-in, the 34 Lives App page. */
.ds-steps { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: var(--space-3); counter-reset: ds-step; }
.ds-step { display: grid; grid-template-columns: 24px minmax(0, 1fr); gap: var(--space-1) var(--space-2-5); align-items: start; }
.ds-step::before { counter-increment: ds-step; content: counter(ds-step); width: 24px; height: 24px; border-radius: 50%; display: grid; place-items: center; background: var(--clr-primary-light); color: var(--clr-primary-ink); font-size: var(--fs-xs); font-weight: var(--fw-bold); }
.ds-step > * { grid-column: 2; }
.ds-step-text { margin: 0; padding-top: var(--space-0-5); color: var(--clr-text-body); }
/* A QR code to scan (figure.ds-qr around its img): dark on white paper in both themes, so every camera reads it;
   184 px, 168 px at 600 px and below. */
.ds-qr { margin: var(--space-1) 0 0; justify-self: start; padding: var(--space-3); border-radius: var(--radius-lg); background: var(--clr-paper); border: 1px solid var(--clr-paper-line); line-height: 0; }
.ds-qr img { width: 184px; height: 184px; display: block; image-rendering: pixelated; }

/* =========================================================================================
   ADDITIONS (plan 1.3 components the kit did not draw, and Portal.ui hooks)
   ========================================================================================= */
.ds-toolbar { display: flex; align-items: center; gap: 8px 10px; flex-wrap: wrap; }
/* A toolbar at the top of a flush card (or the only thing in one): the card head's inset and a line under it. Its
   filters are labelled fields, so the row lines up on their bottom edge. */
.ds-toolbar.is-inset { align-items: flex-end; padding: var(--space-4) var(--space-5); border-bottom: 1px solid var(--clr-border); }
.ds-toolbar.is-inset:last-child { border-bottom: 0; }
.ds-toolbar > .ds-search { flex: 1 1 240px; max-width: 360px; }
/* The search box in a host of the page's own (a div the page appends Portal.ui.search()'s el to). */
.ds-toolbar > .ds-toolbar-search { flex: 1 1 240px; max-width: 360px; min-width: 0; }
.ds-toolbar-search > .ds-search { width: 100%; }
.ds-toolbar-actions { margin-left: auto; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
/* A row of filters. Labelled fields (.ds-field) line up on their bottom edge, 12 px apart, each 220 px wide unless the
   page sizes it (180 px at 900 px and below); a row of bare controls (Scheduling's scope bar) keeps 8 px, centred. */
.ds-toolbar-filters { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.ds-toolbar-filters:has(> .ds-field) { align-items: flex-end; gap: var(--space-3); }
:where(.ds-toolbar-filters) > :where(.ds-field) { width: 220px; }
.ds-toolbar-filterbtn { display: none; }
/* The list's count at the toolbar's end ("12 of 40 people" while a search or filter narrows it; role="status"). */
.ds-toolbar-count { font-size: var(--fs-sm); color: var(--clr-text-muted); white-space: nowrap; font-variant-numeric: tabular-nums; }
/* "Sort by" (a .ds-field among the filters): only where its list is cards, with no column heads to press. Alone it
   follows a dataList (cards at 900 px and below); .is-cards follows a .ds-table.is-cards (600 px and below) and
   .is-cards-flow a .ds-table.is-cards-flow (wherever the page flows). The show rules are in the width blocks below. */
.ds-field.ds-sortby { display: none; }
/* A small upper-case label over a group of details (Action History's "Details" in a row's details dialog). */
.ds-subhead { margin: 0 0 var(--space-2); font-size: var(--fs-xs); font-weight: var(--fw-bold); letter-spacing: var(--tracking-caps); text-transform: uppercase; color: var(--clr-text-muted); }
.ds-drawer-wrap { position: fixed; inset: 0; z-index: var(--z-sheet); display: flex; justify-content: flex-end; }
.ds-drawer-wrap > .ds-sheet-scrim { position: absolute; inset: 0; }
.ds-drawer-wrap.is-open > .ds-sheet-scrim { opacity: 1; }
.ds-drawer-wrap .ds-drawer { position: relative; height: 100%; transform: translateX(100%); transition: transform var(--dur-slow) var(--ease-out); outline: none; }
.ds-drawer-wrap.is-open .ds-drawer { transform: none; }
.ds-drawer-head { display: flex; align-items: center; gap: 12px; padding: 16px 16px 12px 20px; border-bottom: 1px solid var(--clr-border); flex: none; }
.ds-drawer-title { margin: 0; font-size: var(--fs-lg); font-weight: var(--fw-bold); color: var(--clr-text-heading); min-width: 0; overflow-wrap: anywhere; }
/* A drawer or sheet that shows a record may focus its title (tabindex -1) instead of its first button: no ring from
   code, the keyboard's focus draws it, as .ds-pane-title does. */
.ds-drawer-title:focus, .ds-sheet-title:focus { outline: none; }
.ds-drawer-title:focus-visible, .ds-sheet-title:focus-visible { outline: 2px solid var(--clr-focus-ring); outline-offset: 2px; border-radius: var(--radius-xs); }
.ds-drawer-body { padding: 16px 20px 20px; overflow: auto; overscroll-behavior: contain; min-height: 0; flex: 1 1 auto; }
.ds-drawer-foot { display: flex; justify-content: flex-end; gap: 8px; padding: 12px 16px; border-top: 1px solid var(--clr-border); background: var(--clr-bg); flex: none; }
/* A foot with nothing showing in it (its buttons hidden for this item, or a dialog opened with actions: []) draws no
   empty band. */
:is(.ds-drawer-foot, .ds-sheet-foot, .ds-dialog-foot):not(:has(> :not([hidden]))) { display: none; }
/* A drawer from the end side keeps clear of a notch on the right (a phone on its side); a start-side one pads the left
   instead (below). */
.ds-drawer-wrap:not(.is-start) .ds-drawer { padding-right: env(safe-area-inset-right, 0px); }
/* A drawer from the start side (Portal.ui.drawer({side: "start"}): a page's own start column as a layer): it slides in
   from the left and keeps clear of a notch on that side. */
.ds-drawer-wrap.is-start { justify-content: flex-start; }
.ds-drawer-wrap.is-start .ds-drawer { border-left: 0; border-right: 1px solid var(--clr-pop-border); padding-left: env(safe-area-inset-left, 0px); transform: translateX(-100%); }
.ds-drawer-wrap.is-start.is-open .ds-drawer { transform: none; }
.ds-image-view { margin: 0; display: flex; flex-direction: column; gap: 8px; }
.ds-image-view img { display: block; max-width: 100%; max-height: min(70vh, 720px); margin: 0 auto; object-fit: contain; }
.ds-image-view.is-zoomed img { max-width: none; max-height: none; cursor: zoom-out; }
.ds-image-view figcaption { font-size: var(--fs-sm); color: var(--clr-text-muted); text-align: center; }
.ds-dialog-media { overflow: auto; }
.ds-empty.is-error .ds-empty-ic { background: var(--clr-danger-soft); color: var(--clr-danger); }
.ds-progress-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ds-progress.is-failed .ds-progress-bar > i { background: var(--clr-danger); }
.ds-progress.is-done .ds-progress-bar > i { background: var(--clr-success); }
.ds-daterange-presets .ds-icon-btn { width: var(--ctl-h-sm); height: var(--ctl-h-sm); }
.ds-disclosure-body[hidden] { display: none; }
.ds-scroll-head > * { min-width: 0; }
/* Structure of Portal.ui.dataList (the Scheduling hub's data list): scroll area, table, sticky header group, body,
   group bands (a cell inside the band), detail rows, footer with the page size. */
.ds-dl-scroll { position: relative; }
.ds-dl-table { min-width: 0; }
.ds-dl-headgroup { position: sticky; top: var(--ds-list-top, 0px); z-index: 4; }
.ds-scroll.has-above .ds-dl-head { box-shadow: var(--shadow-head); }
.ds-dl.is-headless .ds-dl-group { top: calc(var(--ds-list-top, 0px) + var(--ds-dl-cue-h, 0px)); }
.ds-dl-body { display: block; }
.ds-dl-group-cell { display: flex; align-items: center; gap: 8px; min-width: 0; flex: 1 1 auto; }
.ds-dl-group-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ds-dl-row:focus-visible { outline: 2px solid var(--clr-focus-ring); outline-offset: -2px; }
/* The row whose details are open beside or over the list (a drawer, a docked panel, a detail pane): the current tint
   and a 3 px primary bar at its start, in a data list (.ds-dl-row) and a table (.ds-table tbody tr). */
.ds-dl-row.is-selected { background: var(--clr-current-bg); }
.ds-dl-row.is-selected::before { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 3px; background: var(--clr-primary); }
.ds-table tbody tr.is-selected > td { background: var(--clr-current-bg); }
.ds-table tbody tr.is-selected > td:first-child { box-shadow: inset 3px 0 0 var(--clr-primary); }
.ds-dl-row.is-flash { animation: ds-flash 1.6s ease; }
@keyframes ds-flash { 0%, 40% { background: var(--clr-warning-soft); } 100% { background: var(--ds-flash-to, var(--clr-surface)); } }
/* A live list that never moves its rows under the reader (dataList's pending, markGone and pin):
   .ds-dl-fresh, above the rows: "2 new tickets, Show them" as a pill button in a role="status" line that is in the
   list from the start (empty and without room while nothing waits, so each change that fills it is announced);
   .ds-dl-row.is-gone, a row that left the view while it shows: dimmed where it is, its note (.ds-dl-gone-note) one line
   cut with an ellipsis, in place of its .ds-dl-gone-slot's content (the slot keeps its height, so the row does) or at
   the end of its last cell;
   .ds-dl-pinned, a band above the rows holding one row that is not in the view (the open record's), with its label
   line (a pin, the words, an action at the end). */
.ds-dl-fresh { display: flex; justify-content: center; padding: 8px 12px; flex: none; }
.ds-dl-fresh:empty { padding: 0; }
.ds-dl-fresh-btn { display: inline-flex; align-items: center; gap: 6px; max-width: 100%; min-height: var(--ctl-h-sm); padding: 0 14px; border: 1px solid var(--clr-primary-line); border-radius: var(--radius-pill); background: var(--clr-primary-light); color: var(--clr-primary-ink); font: inherit; font-size: var(--fs-sm); font-weight: var(--fw-bold); cursor: pointer; box-shadow: var(--shadow-sm); }
.ds-dl-fresh-btn svg.ds-i { width: var(--icon-sm); height: var(--icon-sm); flex: none; }
.ds-dl-fresh-sub { font-weight: var(--fw-medium); white-space: nowrap; }
@media (hover: hover) { .ds-dl-fresh-btn:hover { background: var(--clr-primary-wash); } }
.ds-dl-fresh-btn:focus-visible { outline: 2px solid var(--clr-focus-ring); outline-offset: 2px; }
.ds-dl-row.is-gone { opacity: 0.62; }
.ds-dl-gone-note { display: block; min-width: 0; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--fs-xs); font-weight: var(--fw-semibold); color: var(--clr-text-muted); }
.ds-dl-row.is-gone .ds-dl-gone-slot > :not(.ds-dl-gone-note) { display: none; }
.ds-dl-row.is-gone .ds-dl-gone-slot { display: flex; align-items: center; min-width: 0; }   /* the slot's height is kept (dataList sets it) */
.ds-dl-gone-slot > .ds-dl-gone-note { flex: 0 1 auto; }
.ds-dl-pinned { flex: none; border-bottom: 1px solid var(--clr-border); background: var(--clr-surface-muted); }
.ds-dl-pinned-label { display: flex; align-items: center; gap: 6px; min-width: 0; padding: 6px 14px 2px 16px; font-size: var(--fs-2xs); font-weight: var(--fw-bold); letter-spacing: var(--tracking-caps); text-transform: uppercase; color: var(--clr-text-muted); }
.ds-dl-pinned-ic { display: inline-grid; flex: none; }
.ds-dl-pinned-ic svg.ds-i { width: var(--icon-xs); height: var(--icon-xs); }
.ds-dl-pinned-label .ds-linkbtn { margin: -5px -6px -5px auto; font-size: var(--fs-xs); letter-spacing: 0; text-transform: none; font-weight: var(--fw-semibold); }
.ds-dl-pinned > .ds-dl-row { border-bottom: 0; }
/* dataList({maxHeight: "pane"}) (.ds-dl.is-pane): a list that fills the pane it sits in (its parent is a flex column
   of fixed height, a pane's body) and scrolls its rows in its own box there, with no maxHeight of its own. In page flow
   that box flows in the page like any list's, except in an app view, where dataList marks it .is-boxed: a touch
   screen's split keeps the list's own scroll beside the record. */
.ds-dl.is-pane { flex: 1 1 auto; min-height: 0; }
.ds-dl.is-pane > .ds-dl-scroll { flex: 1 1 auto; min-height: 0; max-height: none; overflow-x: hidden; overscroll-behavior: contain; }
/* A list in a pane is a narrow column at every width: a group band's name wraps and its note takes a line of its own
   under it, so neither is cut off; the count stays beside the name's last line (the cards' grid, at 900 px and
   below). */
.ds-dl.is-pane .ds-dl-group-cell { display: grid; grid-template-columns: minmax(0, max-content) auto minmax(0, 1fr); align-items: center; row-gap: 0; }
.ds-dl.is-pane .ds-dl-group-cell:has(> .ds-dl-group-ic) { grid-template-columns: auto minmax(0, max-content) auto minmax(0, 1fr); }
.ds-dl.is-pane .ds-dl-group-label { white-space: normal; overflow-wrap: anywhere; }
.ds-dl.is-pane .ds-dl-group-cell > .ds-gcount { align-self: end; }
.ds-dl.is-pane .ds-dl-group-note { grid-column: 1 / -1; }
/* Beside the record (two panes, wider than 900 px), a pane list's rows, bands and foot start at the pane's inset
   (--ds-pane-x), in line with the pane head's title and search. One pane, it is the page's list and keeps the kit's
   own padding. */
@media (min-width: 901px) {
    .ds-dl.is-pane .ds-dl-row { padding: 10px 14px 10px var(--ds-pane-x, 16px); min-height: 0; }
    .ds-dl.is-pane .ds-dl-group { padding: 4px 14px 4px var(--ds-pane-x, 16px); }
    .ds-dl.is-pane .ds-dl-foot { padding: 6px 14px 6px var(--ds-pane-x, 16px); }
    .ds-dl.is-pane .ds-dl-pinned-label { padding-left: var(--ds-pane-x, 16px); }
    .ds-dl.is-pane .ds-dl-above { padding-left: var(--ds-pane-x, 16px); }
    .ds-split.is-one-pane .ds-dl.is-pane .ds-dl-row { padding: 6px 16px 6px 8px; min-height: 50px; }
    .ds-split.is-one-pane .ds-dl.is-pane .ds-dl-group { padding: 4px 16px; }
    .ds-split.is-one-pane .ds-dl.is-pane .ds-dl-foot { padding: 8px 12px 8px 16px; }
    .ds-split.is-one-pane .ds-dl.is-pane .ds-dl-pinned-label { padding-left: 16px; }
    .ds-split.is-one-pane .ds-dl.is-pane .ds-dl-above { padding-left: 14px; }
}
/* The open record's row and the rest of a live list's rows (dataList's selected, rowClass, onRowClick):
   .ds-dl-row.is-unread, a row with something new, has the primary wash, which yields to .is-selected (the open
   row keeps the current-row look); .ds-dl.has-row-click, rows that open on a press, show the pointer. */
.ds-dl-row.is-unread:not(.is-selected) { background: var(--clr-primary-wash); }
@media (hover: hover) { .ds-dl-row.is-unread:not(.is-selected):hover { background: var(--clr-row-hover); } }
.ds-dl.has-row-click .ds-dl-row { cursor: pointer; }
/* A group head that folds (dataList groupCollapse): its name is a button with a chevron (pointing right while the
   group's rows are hidden). The button is the band's height on touch screens. It reaches 4 px left of the name's
   place (its padding), so its widest is the label's width and those 4 px; a name that wraps keeps the chevron on its
   first line. */
.ds-dl-group-btn { display: inline-flex; align-items: flex-start; gap: 4px; max-width: calc(100% + 4px); margin: 0 0 0 -4px; padding: 2px 4px; border: 0; border-radius: var(--radius-sm); background: none; color: inherit; font: inherit; text-align: left; cursor: pointer; }
.ds-dl-group-btn:focus-visible { outline: 2px solid var(--clr-focus-ring); outline-offset: -2px; }
@media (hover: hover) { .ds-dl-group-btn:hover { background: var(--clr-row-hover); } }
.ds-dl-group-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
/* The label that holds the button does not clip it: the button's 4 px reach, its focus ring, its hover fill and its
   touch hit area show whole; a long name still ends in an ellipsis inside the button (.ds-dl-group-text). */
.ds-dl-group-label:has(> .ds-dl-group-btn) { overflow: visible; }
.ds-dl-group-chev { display: inline-grid; align-content: center; flex: none; height: 1lh; color: var(--clr-text-muted); }
.ds-dl-group-chev svg.ds-i { width: var(--icon-sm); height: var(--icon-sm); transition: transform var(--dur) var(--ease-out); }
.ds-dl-gsec.is-collapsed .ds-dl-group-chev svg.ds-i { transform: rotate(-90deg); }
/* "Show earlier" (dataList onEarlier): a line of its own above the first row. */
.ds-dl-earlier { display: flex; justify-content: center; padding: 8px 12px; border-bottom: 1px solid var(--clr-border); }
.ds-dl-earlier-cell { display: flex; justify-content: center; min-width: 0; }
.ds-dl-earlier-btn svg.ds-i { width: var(--icon-sm); height: var(--icon-sm); }
/* A declared group's empty line (dataList groups): muted, under its band counted 0; a line, not a row. */
.ds-dl-gempty { padding: 12px 16px; border-bottom: 1px solid var(--clr-border); background: var(--clr-surface); }
.ds-dl-gempty-cell { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 12px; min-width: 0; font-size: var(--fs-sm); color: var(--clr-text-muted); }
/* The above cue (dataList aboveCue): "5 more urgent above", then Show, stuck at the top of the rows while rows sit
   above the visible top. Its holder has no height (the band lies over the rows, so none moves as it comes and goes)
   and sticks under the column head, or at the top of a headless list; the stuck group band moves down under it
   (--ds-dl-cue-h, set while it shows). */
.ds-dl-above-host { position: sticky; top: calc(var(--ds-list-top, 0px) + 40px); z-index: 5; height: 0; }
.ds-dl.is-headless .ds-dl-above-host { top: var(--ds-list-top, 0px); }
.ds-dl-above { position: absolute; left: 0; right: 0; top: 0; display: flex; align-items: center; gap: 6px; min-height: 30px; padding: 2px 10px 2px 14px; border-bottom: 1px solid var(--clr-primary-line); background: var(--clr-primary-light); color: var(--clr-primary-ink); font-size: var(--fs-xs); font-weight: var(--fw-semibold); box-shadow: var(--shadow-head); }
.ds-dl-above[hidden] { display: none; }
.ds-dl-above svg.ds-i { width: var(--icon-xs); height: var(--icon-xs); flex: none; }
.ds-dl-above-text { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ds-dl-above .ds-linkbtn { flex: none; margin: -4px -4px -4px 0; font-size: var(--fs-xs); }
/* A card that was just linked to (a ring that fades), and one to look at (a ring that pulses: --ds-ring, primary by
   default; Build's warnings use --clr-warning-line). */
@keyframes ds-ring-flash { 0%, 30% { box-shadow: inset 0 0 0 2px var(--clr-primary), 0 0 0 4px var(--clr-primary-line); } 100% { box-shadow: inset 0 0 0 0 transparent, 0 0 0 0 transparent; } }
@keyframes ds-ring-pulse { 0%, 100% { box-shadow: 0 0 0 0 transparent; } 40% { box-shadow: 0 0 0 4px var(--ds-ring, var(--clr-primary-line)); } }
.ds-dl-cell.is-right { align-items: flex-end; }
.ds-dl-expcell { align-items: center; }
.ds-dl-detail-cell { min-width: 0; }
.ds-dl-sort-ic { display: inline-grid; }
.ds-dl-sort-ic svg.ds-i { width: var(--icon-xs); height: var(--icon-xs); stroke-width: 2.2; }
.ds-dl-count { font-variant-numeric: tabular-nums; }
.ds-dl-size { display: inline-flex; align-items: center; gap: 8px; margin-left: auto; white-space: nowrap; }
.ds-dl-size-l { font-size: var(--fs-sm); color: var(--clr-text-muted); }
/* A list with no visible column header: its group band pinned at the top edge (.ds-stick-band, marked .is-stuck by
   scrollFade while it sticks at top: 0) casts the same "more above" cue as a stuck heading. Its top comes from the
   list (.ds-dl-group: 40px under a column header, 0 when headless or on phones); a top here would pin a headed
   list's bands at 0, over its column header. */
.ds-stick-band { position: sticky; z-index: 3; }
.ds-scroll.has-above .ds-scroll-head.is-stuck, .ds-scroll.has-above .ds-stick-band.is-stuck { box-shadow: var(--shadow-head); }
.ds-pop-list { overflow: hidden; }
.ds-listpop-filter { display: flex; align-items: center; gap: 6px; margin: 6px 8px 0; padding: 4px 8px; border-radius: var(--radius-sm); background: var(--clr-primary-light); color: var(--clr-primary-hover); font-size: var(--fs-xs); font-weight: var(--fw-semibold); flex: none; }
.ds-listpop-filter svg.ds-i { width: var(--icon-xs); height: var(--icon-xs); }
.ds-listpop-done { margin-left: auto; }
.ds-seg-label { white-space: nowrap; }
.ds-badge-ic { display: inline-grid; }
.ds-badge-ic svg.ds-i { width: var(--icon-xs); height: var(--icon-xs); stroke-width: 2.1; }
.ds-badge-ic svg.ds-i path[fill="currentColor"] { stroke-width: 1.2; }
.ds-block { display: block; width: 100%; }
/* A native <select> the searchable select replaced: kept for forms and labels, never shown. */
.ds-native { background: transparent !important; color: inherit !important; appearance: none !important; position: absolute !important; width: 1px !important; height: 1px !important; min-width: 0 !important; padding: 0 !important; margin: 0 !important; border: 0 !important; opacity: 0 !important; pointer-events: none !important; clip: rect(0 0 0 0) !important; overflow: hidden !important; }
.ds-skel-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 6px; }
.ds-skel-cell { display: block; height: 84px; border-radius: var(--radius-sm); background: linear-gradient(90deg, var(--clr-skel) 25%, var(--clr-skel-hi) 50%, var(--clr-skel) 75%); background-size: 200% 100%; animation: ds-shimmer 1.3s ease-in-out infinite; }
.ds-search-ic { display: inline-grid; flex: none; }
.ds-th-sort { display: inline-grid; vertical-align: middle; margin-left: 2px; }
.ds-th-sort svg.ds-i { width: var(--icon-xs); height: var(--icon-xs); stroke-width: 2.2; }
.ds-toast.is-out { opacity: 0; transform: translateY(6px); transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease); }
.ds-drawer-head .ds-icon-btn { margin-left: auto; }

/* =========================================================================================
   CONVERSATION (AI Chat's thread and message box: bubble, prose, message box; with the code block, typing dots, file
   chip, meter and disclosure variants above. The Assistant widget and Help Desk's intake draw their own today.)
   ========================================================================================= */
/* Message bubble (.ds-bubble): a message on the surface with a 1 px ring, 78% of its column at most (88% at 900 px and
   below); .is-mine your own, in the primary tint with heading ink, keeping its line breaks; .is-wide a reply as a card
   across the column (a flex column, its parts 12 px apart; its prose sets the type); .is-editing a bubble given over to
   its edit field (no tint, ring or padding). The page places the bubbles in its rows (yours at the end). */
.ds-bubble { min-width: 0; max-width: 78%; padding: 10px 14px; border-radius: var(--radius-lg); background: var(--clr-surface); box-shadow: inset 0 0 0 1px var(--clr-border); color: var(--clr-text-heading); font-size: var(--fs-title); line-height: var(--lh-relaxed); overflow-wrap: anywhere; }
.ds-bubble.is-mine { background: var(--clr-primary-light); box-shadow: inset 0 0 0 1px var(--clr-primary-line); white-space: pre-wrap; }
.ds-bubble.is-wide { display: flex; flex-direction: column; gap: 12px; width: 100%; max-width: none; padding: 16px 20px; border: 1px solid var(--clr-border); box-shadow: var(--shadow-sm); color: var(--clr-text-body); overflow-wrap: break-word; }
.ds-bubble.is-editing { width: 100%; max-width: none; padding: 0; border: 0; background: none; box-shadow: none; white-space: normal; }
/* Prose (.ds-prose: rendered markdown, AI Chat's replies): --fs-title on --lh-relaxed in body ink; headings 22, 17, 16
   and 15 px; links underlined; list markers muted, numbers tabular; a quote with a bar, not italic; inline code in
   heading ink on grey; tables with the tinted heading band (no forced capitals), in a .ds-prose-table box that scrolls
   sideways (each column at least 6em at 600 px and below); images on the paper ground; a GFM right-aligned column keeps
   its alignment. .is-sm is the small form (--fs-sm on --lh-base, the headings a step down). */
.ds-prose { min-width: 0; font-size: var(--fs-title); line-height: var(--lh-relaxed); color: var(--clr-text-body); overflow-wrap: break-word; }
.ds-prose > :first-child { margin-top: 0; }
.ds-prose > :last-child { margin-bottom: 0; }
.ds-prose p { margin: 0 0 0.75em; }
.ds-prose :is(h1, h2, h3, h4, h5, h6) { margin: 1.3em 0 0.45em; font-weight: var(--fw-bold); line-height: var(--lh-tight); color: var(--clr-text-heading); }
.ds-prose :is(h3, h4, h5, h6) { margin: 1.1em 0 0.35em; }
.ds-prose h1 { font-size: var(--fs-2xl); }
.ds-prose h2 { font-size: var(--fs-xl); }
.ds-prose h3 { font-size: var(--fs-lg); }
.ds-prose h4 { font-size: var(--fs-title); }
.ds-prose :is(h5, h6) { font-size: var(--fs-md); color: var(--clr-text-body); }
.ds-prose :is(strong, b) { font-weight: var(--fw-bold); }
.ds-prose a { color: var(--clr-link); text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 2px; text-decoration-color: var(--clr-primary-line); }
@media (hover: hover) { .ds-prose a:hover { text-decoration-color: currentColor; } }
.ds-prose :is(ul, ol) { margin: 0 0 0.75em; padding-left: 1.4em; }
.ds-prose li + li { margin-top: 0.3em; }
.ds-prose li > :is(ul, ol) { margin: 0.3em 0 0; }
.ds-prose li > p { margin: 0 0 0.3em; }
.ds-prose li > p:last-child { margin-bottom: 0; }
.ds-prose li::marker { color: var(--clr-text-muted); }
.ds-prose ol > li::marker { font-variant-numeric: tabular-nums; }
.ds-prose blockquote { margin: 0 0 0.75em; padding: 2px 0 2px 14px; border-left: 3px solid var(--clr-border-hover); color: var(--clr-text-body); font-style: normal; }
.ds-prose hr { height: 0; margin: 1.2em 0; border: 0; border-top: 1px solid var(--clr-border); }
/* Inline code: a code in prose, and .ds-icode outside it (a department's code or key in a row, a group head, a meta
   line or a dialog) in the same look; .ds-icode.is-sm at --fs-xs for rows and group heads. (.ds-code is the block.) */
.ds-prose :not(pre) > code, .ds-icode { padding: 1px 5px; border-radius: var(--radius-xs); background: var(--clr-surface-muted); box-shadow: inset 0 0 0 1px var(--clr-border); color: var(--clr-text-heading); font-family: var(--font-mono); font-size: var(--fs-sm); overflow-wrap: anywhere; }
.ds-icode.is-sm { font-size: var(--fs-xs); }
/* A code or ID in running text that must stay on one line (never a non-breaking hyphen: a copy would carry it). */
.ds-nowrap { white-space: nowrap; }
.ds-prose :is(h1, h2, h3, h4, h5, h6) code { font-size: inherit; }
.ds-prose pre:not(.ds-code) { margin: 0 0 0.75em; padding: 12px 14px; border: 1px solid var(--clr-code-border); border-radius: var(--radius-md); background: var(--clr-code-bg); color: var(--clr-code-ink); font-family: var(--font-mono); font-size: var(--fs-sm); line-height: var(--lh-relaxed); overflow: auto; }
.ds-prose pre:not(.ds-code) code { padding: 0; background: none; box-shadow: none; color: inherit; font: inherit; }
.ds-prose :is(.ds-codeblock, .ds-prose-table) { margin: 0 0 0.75em; }
.ds-prose img { display: block; max-width: 100%; height: auto; margin: 0 0 0.75em; border: 1px solid var(--clr-border); border-radius: var(--radius-md); background: var(--clr-paper); }
.ds-prose-table { max-width: 100%; overflow-x: auto; border: 1px solid var(--clr-border); border-radius: var(--radius-md); }
.ds-prose table { width: 100%; border-collapse: collapse; font-size: var(--fs-md); font-variant-numeric: tabular-nums; }
/* In its box a table takes its columns' natural widths (at least the box's): numbers and short values never break, a
   long text or address wraps at 20em, and a table wider than the box scrolls sideways in it. */
.ds-prose-table > table { width: max-content; min-width: 100%; }
.ds-prose th { padding: 8px 12px; border-bottom: 1px solid var(--clr-head-line); background: var(--clr-head-bg); color: var(--clr-head-ink); font-size: var(--fs-sm); font-weight: var(--fw-bold); text-transform: none; vertical-align: bottom; }
.ds-prose th:not([align]) { text-align: start; }
.ds-prose td { max-width: 20em; padding: 8px 12px; border-bottom: 1px solid var(--clr-border); color: var(--clr-text-heading); vertical-align: top; overflow-wrap: anywhere; }
.ds-prose tbody tr:nth-child(even) > td { background: var(--clr-table-stripe); }
.ds-prose tbody tr:last-child > td { border-bottom: 0; }
.ds-prose input[type="checkbox"] { margin: 0 0.4em 0 0; vertical-align: middle; accent-color: var(--clr-primary); }
.ds-prose :is(sup, sub) { line-height: 0; }
.ds-prose.is-sm { font-size: var(--fs-sm); line-height: var(--lh-base); }
.ds-prose.is-sm h1 { font-size: var(--fs-xl); }
.ds-prose.is-sm h2 { font-size: var(--fs-lg); }
.ds-prose.is-sm h3 { font-size: var(--fs-title); }
.ds-prose.is-sm h4 { font-size: var(--fs-md); }
.ds-prose.is-sm :is(h5, h6) { font-size: var(--fs-sm); }
.ds-prose.is-sm :not(pre) > code { font-size: var(--fs-xs); }

/* Rich text (Portal.richText, static/js/portal-richtext.js). .ds-richtext is a document as a reader sees it, on .ds-prose;
   .ds-rte is the box it is written in, with its toolbar, on the same type so what is written is what is read. A large
   heading is --fs-xl and a small one --fs-lg whichever level they are in the page. Callouts are notices; colored words
   keep to the tones' inks, which hold their contrast in both themes. An image is Small (40%), Medium (70%) or Full width,
   all full width at 600 px and below, on the paper ground; it opens in the image viewer. */
.ds-richtext .ds-rich-lg, .ds-rte-area h2 { font-size: var(--fs-xl); }
.ds-richtext .ds-rich-sm, .ds-rte-area h3 { font-size: var(--fs-lg); }
.ds-rich-c-primary, .ds-rte-area font[face~="rte-tone-primary"] { color: var(--clr-primary-ink); }
.ds-rich-c-success, .ds-rte-area font[face~="rte-tone-success"] { color: var(--clr-success-tone-ink); }
.ds-rich-c-warning, .ds-rte-area font[face~="rte-tone-warning"] { color: var(--clr-amber-ink); }
.ds-rich-c-danger, .ds-rte-area font[face~="rte-tone-danger"] { color: var(--clr-danger-tone-ink); }
.ds-rich-c-purple, .ds-rte-area font[face~="rte-tone-purple"] { color: var(--clr-purple-ink); }
.ds-rich-c-muted, .ds-rte-area font[face~="rte-tone-muted"] { color: var(--clr-text-muted); }
.ds-richtext [class*="ds-rich-c-"] code { color: inherit; }
.ds-prose .ds-rich-callout { margin: 0 0 0.75em; }
.ds-rich-callout .ds-notice-text strong { display: inline; font-size: inherit; }
.ds-prose .ds-badge { vertical-align: 0.1em; }
.ds-rich-figure { max-width: 100%; margin: 0 0 0.75em; }
.ds-rich-figure.is-sm { max-width: 40%; }
.ds-rich-figure.is-md { max-width: 70%; }
@media (max-width: 600px) { .ds-rich-figure.is-sm, .ds-rich-figure.is-md { max-width: 100%; } }
.ds-rich-figure figcaption { margin-top: 6px; font-size: var(--fs-sm); line-height: var(--lh-snug); color: var(--clr-text-muted); }
.ds-prose .ds-rich-figure img { margin: 0; }
.ds-rich-image { display: block; max-width: 100%; padding: 0; border: 0; border-radius: var(--radius-md); background: none; cursor: zoom-in; }
.ds-rte { display: flex; flex-direction: column; min-width: 0; border: 1px solid var(--clr-border); border-radius: var(--radius-md); background: var(--clr-surface); transition: border-color var(--transition-speed), box-shadow var(--transition-speed); }
.ds-rte:has(.ds-rte-area:focus) { border-color: var(--clr-primary); box-shadow: var(--ring); }
.ds-rte:has(.ds-rte-area[aria-invalid="true"]) { border-color: var(--clr-danger); }
.ds-rte-toolbar { position: sticky; top: 0; z-index: 1; display: flex; flex-wrap: wrap; align-items: center; gap: 2px 10px; padding: 6px 8px; border-bottom: 1px solid var(--clr-border); border-radius: var(--radius-md) var(--radius-md) 0 0; background: var(--clr-surface-muted); }
.ds-rte-group { display: flex; align-items: center; gap: 2px; }
.ds-rte-btn { width: var(--ctl-h-sm); height: var(--ctl-h-sm); }
.ds-rte-btn svg.ds-i { width: var(--icon-md); height: var(--icon-md); }
.ds-rte-btn[aria-pressed="true"], .ds-rte-btn.is-on { background: var(--clr-primary-light); color: var(--clr-primary-ink); }
.ds-rte-block { display: inline-flex; align-items: center; justify-content: space-between; gap: 6px; min-width: 132px; height: var(--ctl-h-sm); padding: 0 8px; border: 0; border-radius: var(--radius-md); background: transparent; color: var(--clr-text-heading); font: inherit; font-size: var(--fs-sm); font-weight: var(--fw-semibold); cursor: pointer; }
.ds-rte-block-name { min-width: 0; }
.ds-rte-block svg.ds-i { width: var(--icon-sm); height: var(--icon-sm); color: var(--clr-text-muted); }
@media (hover: hover) { .ds-rte-block:hover { background: var(--clr-surface); } }
.ds-rte-area { position: relative; flex: 1; min-height: 280px; padding: 14px 16px; outline: none; overflow-wrap: anywhere; cursor: text; }
.ds-rte-area.is-empty::before { content: attr(data-placeholder); position: absolute; color: var(--clr-text-muted); pointer-events: none; }
.ds-rte-area font[face] { font-family: inherit; }
.ds-rte-area font[face~="rte-code"] { padding: 1px 5px; border-radius: var(--radius-xs); background: var(--clr-surface-muted); box-shadow: inset 0 0 0 1px var(--clr-border); font-family: var(--font-mono); font-size: var(--fs-sm); }
.ds-rte-area font[face="rte-code"] { color: var(--clr-text-heading); }
.ds-rte-area :is(aside, .ds-rte-callout) { margin: 0 0 0.75em; padding: 12px 16px; border: 1px solid var(--t-line, var(--clr-primary-line)); border-radius: var(--radius-lg); background: var(--t-bg, var(--clr-primary-light)); color: var(--t-ink, var(--clr-primary-ink)); }
.ds-rte-figure { position: relative; width: fit-content; cursor: default; }
.ds-rte-figure-more { position: absolute; top: 8px; right: 8px; }
.ds-rte-figure.is-uploading img { opacity: 0.5; }
.ds-rte-figure-busy { position: absolute; top: 8px; left: 8px; }
.ds-rte-link { display: flex; flex-direction: column; gap: var(--space-3); padding: var(--space-3); }
.ds-rte-link-actions { display: flex; justify-content: flex-end; gap: var(--space-2); }
@media (max-width: 768px), (pointer: coarse) {
    .ds-rte-btn { width: var(--ctl-h-touch); height: var(--ctl-h-touch); }
    .ds-rte-block { height: var(--ctl-h-touch); }
    .ds-rte-figure-more { width: var(--ctl-h-touch); height: var(--ctl-h-touch); }
}
/* Message box (.ds-composer: a chat's text box and its buttons in one frame): the surface with a 1 px border,
   --radius-lg, 6 px padding and gaps, the buttons level with the bottom; the focus ring while you type in it and while
   files are dragged over it (.is-drop, set by the page); the muted ground while its text area is disabled (locked).
   .ds-composer-input is its borderless text area: --fs-title (16 px on phones and touch screens), up to 200 px tall
   (min(200px, 28vh) at 900 px and below, 120 px on a short screen; the page grows it to its text), its own row above
   the buttons at 600 px and below. Enter and Send are the page's. */
.ds-composer { display: flex; align-items: flex-end; gap: 6px; min-width: 0; padding: 6px; border: 1px solid var(--clr-border); border-radius: var(--radius-lg); background: var(--clr-surface); transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease); }
.ds-composer:focus-within, .ds-composer.is-drop { border-color: var(--clr-primary); box-shadow: var(--ring); }
.ds-composer:has(> .ds-composer-input:disabled) { background: var(--clr-surface-muted); }
.ds-composer > * { flex: none; }   /* its buttons keep their size; the text area takes the rest */
.ds-composer-input { flex: 1 1 0%; width: 0; min-width: 0; min-height: 0; max-height: 200px; margin: 0; padding: 8px 6px; border: 0; border-radius: 0; outline: 0; box-shadow: none; background: transparent; resize: none; color: var(--clr-text-heading); font-family: inherit; font-size: var(--fs-title); line-height: var(--lh-base); }
.ds-composer-input:focus, .ds-composer-input:focus-visible { border: 0; outline: 0; box-shadow: none; }
.ds-composer-input::placeholder { color: var(--clr-text-muted); }
.ds-composer-input:disabled { background: transparent; color: var(--clr-text-muted); cursor: not-allowed; }
/* Note mode (.is-note: a staff note only colleagues read, written in the same box as a reply): the warning tint and
   line, and a warning ring while you type. The page switches the mode's placeholder, hint and button with it. */
.ds-composer.is-note { background: var(--clr-warning-soft); border-color: var(--clr-warning-line); }
.ds-composer.is-note:focus-within, .ds-composer.is-note.is-drop { border-color: var(--clr-warning); box-shadow: 0 0 0 3px var(--clr-warning-line); }

/* =========================================================================================
   MEDIA QUERIES (last)
   ========================================================================================= */
/* =========================================================================================
   Phase 2a additions (Lane K; kit_changes.md)
   ========================================================================================= */
/* App card (the home page grid; any page that lists apps): icon tile in the category tone, title, 2-line description. */
.ds-app-card { position: relative; display: grid; grid-template-columns: 40px minmax(0, 1fr); column-gap: var(--space-3); align-items: start; min-height: 84px; padding: var(--space-3) var(--space-4) var(--space-3) var(--space-3); border: 1px solid var(--clr-border); border-radius: var(--radius-lg); background: var(--clr-surface); box-shadow: var(--shadow-sm); color: inherit; text-decoration: none; transition: border-color var(--dur) var(--ease-out), box-shadow var(--dur) var(--ease-out), transform var(--dur) var(--ease-out); }
@media (hover: hover) { .ds-app-card:hover { border-color: var(--clr-primary-line); box-shadow: var(--shadow-md); transform: translateY(-1px); } }
@media (hover: hover) { .ds-app-card:hover .ds-app-t { color: var(--clr-primary-ink); } }
.ds-app-card:focus-visible { outline: none; border-color: var(--clr-primary); box-shadow: var(--ring); }
.ds-app-ic { display: grid; place-items: center; width: 40px; height: 40px; border-radius: var(--radius-md); background: var(--cat-bg, var(--clr-surface-muted)); color: var(--cat-ink, var(--clr-text-body)); }
.ds-app-ic svg.ds-i { width: var(--icon-xl); height: var(--icon-xl); }
.ds-app-ic.is-brand { background: var(--clr-paper); box-shadow: inset 0 0 0 1px var(--clr-paper-line); }
.ds-app-ic img { width: 24px; height: 24px; object-fit: contain; }
.ds-app-body { display: flex; flex-direction: column; gap: var(--space-0-5); min-width: 0; }
.ds-app-t { display: flex; align-items: center; gap: var(--space-1-5); padding-right: var(--space-6); font-size: var(--fs-md); font-weight: var(--fw-semibold); color: var(--clr-text-heading); line-height: var(--lh-snug); }
.ds-app-d { font-size: var(--fs-sm); color: var(--clr-text-muted); line-height: var(--lh-snug); display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.ds-app-meta { display: flex; flex-wrap: wrap; gap: var(--space-1-5); margin-top: var(--space-1-5); }
.ds-app-meta[hidden] { display: none; }
.ds-app-card .tile-unread-badge { position: absolute; top: var(--space-3); right: var(--space-3); display: none; }
.ds-app-card .tile-unread-badge.is-visible { display: inline-grid; place-items: center; min-width: 20px; height: 18px; padding: 0 var(--space-1-5); border-radius: var(--radius-pill); background: var(--clr-primary-fill); color: var(--clr-on-accent); font-size: var(--fs-xs); font-weight: var(--fw-bold); line-height: 1; font-variant-numeric: tabular-nums; }
/* A warning count; the segmented control as a tablist (Portal.ui.segmented({role: "tablist"})) with its dot. */
.ds-count.is-warning { background: var(--clr-warning-soft); color: var(--clr-amber-ink); box-shadow: inset 0 0 0 1px var(--clr-warning-line); }
.ds-seg-btn[aria-selected="true"] { background: var(--clr-seg-on); color: var(--clr-text-heading); box-shadow: var(--shadow-seg-on); }
.ds-seg-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--clr-primary); flex: none; }
/* A drawer beside the page (Portal.ui.drawer({modal: false})): no scrim, the page stays usable. */
.ds-drawer-wrap.is-modeless { z-index: var(--z-header); left: auto; pointer-events: none; }
.ds-drawer-wrap.is-modeless .ds-drawer { pointer-events: auto; box-shadow: var(--shadow-pop); }
.ds-drawer-wrap.is-modeless.is-start { left: 0; right: auto; }
/* The same toast again restarts it with a small nudge (Portal.ui.toast "bump"). */
@keyframes ds-toast-bump { 0% { transform: scale(1); } 40% { transform: scale(1.03); } 100% { transform: scale(1); } }
.ds-toast.is-bump { animation: ds-toast-bump var(--dur-slow) var(--ease-out); }
/* Filters moved into a phone sheet by Portal.ui.toolbar() stack in a column: labelled fields as wide as the sheet and
   16 px apart; a chip filter ("Mine only") keeps its own width. */
.ds-sheet .ds-toolbar-filters.is-collapsible { display: flex; flex-direction: column; align-items: stretch; }
.ds-sheet .ds-toolbar-filters.is-collapsible:has(> .ds-field) { gap: var(--space-4); }
.ds-sheet .ds-toolbar-filters.is-collapsible > .ds-field { flex: none; width: auto; min-width: 0; }
.ds-sheet .ds-toolbar-filters.is-collapsible > .ds-chipbtn { align-self: flex-start; }
.ds-toolbar-filterbtn .ds-count { margin-left: 2px; }
@media (max-width: 600px) {
    .ds-app-card { min-height: 64px; align-items: center; padding: var(--space-2-5) var(--space-3); }
    .ds-app-d { -webkit-line-clamp: 1; }
    .ds-qr img { width: 168px; height: 168px; }
    /* Visually hidden on phones only, still read (a conversation's avatars: .ds-sr-only at 600 px and below). */
    .ds-sr-only-phone { position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
}

@media (max-width: 900px) {
    /* Data list becomes cards */
    .ds-dl { border: 0; background: transparent; overflow: visible; border-radius: 0; }
    .ds-dl-head { display: none; }
    .ds-dl-group { position: sticky; top: calc(var(--ds-list-top, 0px) + var(--ds-dl-cue-h, 0px)); border: 0; background: var(--clr-bg) !important; padding: 10px 2px 6px; }
    /* A group band's name wraps and its note takes a line of its own, so neither is cut off (the kit's band cell
       only: a page's hand-drawn band keeps its own line). The cell is a grid: the icon, the name (as wide as its
       words, at most what is left), the count (as wide as its digits: 8 or 1234) and the rest; a wrapped name keeps
       its count beside its last line instead of dropping it to a line alone. */
    .ds-dl-group-cell { display: grid; grid-template-columns: minmax(0, max-content) auto minmax(0, 1fr); align-items: center; row-gap: 2px; }
    .ds-dl-group-cell:has(> .ds-dl-group-ic) { grid-template-columns: auto minmax(0, max-content) auto minmax(0, 1fr); }
    .ds-dl-group-cell > .ds-dl-group-label { white-space: normal; overflow-wrap: anywhere; }
    .ds-dl-group-cell > .ds-gcount { align-self: end; }
    .ds-dl-group-cell > .ds-dl-group-note { grid-column: 1 / -1; }
    .ds-dl-row { display: flex; flex-direction: column; align-items: stretch; gap: 6px; padding: 12px 14px; margin: 0 0 8px; border: 1px solid var(--clr-border); border-radius: var(--radius-lg); box-shadow: var(--shadow-sm); }
    .ds-dl-row.is-expanded { border-radius: var(--radius-lg) var(--radius-lg) 0 0; margin-bottom: 0; border-bottom: 1px dashed var(--clr-border); background: var(--clr-surface); }
    .ds-dl-row.is-expanded::before, .ds-dl-detail::before, .ds-dl-row.is-selected::before { display: none; }
    .ds-dl-cell { display: grid; grid-template-columns: minmax(76px, min-content) minmax(0, 1fr); align-items: start; justify-items: start; gap: 2px 10px; }   /* a label's longest word widens its column */
    .ds-dl-cell > * { grid-column: 2; }
    .ds-dl-cell::before { content: attr(data-label); grid-column: 1; grid-row: 1 / span 3; font-size: var(--fs-xs); font-weight: var(--fw-semibold); color: var(--clr-text-muted); text-transform: uppercase; letter-spacing: 0.05em; padding-top: 2px; overflow-wrap: normal; }   /* breaks between words only */
    .ds-dl-cell.is-phone-title, .ds-dl-cell[data-label=""] { display: flex; flex-direction: column; align-items: stretch; }
    .ds-dl-cell.is-phone-title::before, .ds-dl-cell[data-label=""]::before, .ds-dl-expcell::before { display: none; }
    .ds-dl-cell.is-phone-title { font-size: var(--fs-title); padding-right: calc(var(--ctl-h-touch) + var(--space-2)); }   /* clear of the expand button */
    .ds-dl:not(:has(.ds-dl-exp)) .ds-dl-cell.is-phone-title { padding-right: 0; }   /* no expand button: the whole width */
    .ds-dl-above-host { top: var(--ds-list-top, 0px); }   /* no column head on cards */
    .ds-dl-cell.is-right { justify-content: flex-start; text-align: left; align-items: start; }
    .ds-dl-row > .ds-dl-expcell { position: absolute; top: 6px; right: 6px; display: block; }
    .ds-dl-exp { width: 40px; height: 40px; }
    .ds-dl-detail { border: 1px solid var(--clr-border); border-top: 0; border-radius: 0 0 var(--radius-lg) var(--radius-lg); margin-bottom: 8px; padding: 12px 14px 14px; }
    .ds-dl-foot { border: 0; background: transparent; padding: 4px 2px 8px; justify-content: center; }
    .ds-dl-cell.hide-phone, .ds-dl-th.hide-phone { display: none; }
    .ds-dl-cell.is-phone-full { display: flex; flex-direction: column; align-items: stretch; }
    .ds-dl-cell.is-phone-full::before { display: none; }
    .ds-dl-pinned > .ds-dl-row { margin: 0; border: 0; border-radius: 0; box-shadow: none; background: transparent; }   /* a row in the band, not a card */
    .ds-dl-gempty { padding: 2px 2px 12px; border: 0; background: transparent; }   /* under its band, not a card */
    .ds-toasts { bottom: max(calc(12px + var(--portal-bottom-inset, 0px) + env(safe-area-inset-bottom)), calc(var(--portal-float-clear, 0px) + var(--space-3))); }
    :where(.ds-toolbar-filters) > :where(.ds-field) { width: 180px; }
    :where(.ds-toolbar-filters) > :where(.ds-field.ds-sortby) { width: 220px; }   /* its orders are long ("Next due, soonest first") */
    .ds-field.ds-sortby:not(.is-cards):not(.is-cards-flow) { display: flex; }   /* beside a dataList, now cards */
    /* A bubble may take more of a narrow column; the message box's text area leaves the thread room. */
    .ds-bubble { max-width: 88%; }
    .ds-composer-input { max-height: min(200px, 28vh); }
}
/* Page flow (phones, small tablets, short screens such as a phone on its side, and every touch screen: a tablet on
   its side keeps the desktop shell but scrolls like a phone): one vertical scroller per screen, the page. A bounded list in a page (.ds-scroll: dataList, bound(), a page's own list) has no height or
   scrollbar of its own here, so a swipe that starts on it scrolls the page like any other content, and its sticky
   headings and group bands stick under the portal top bar instead of the list's own top edge: the list sets
   --ds-list-top to --ds-stick-top (the top bar's height), and every sticky thing in a list offsets itself by
   var(--ds-list-top, 0px) (the kit's headings, bands and table heads do; a page's own sticky rows must too).
   Paging keeps long lists short. Lists in the shared surfaces (dialogs, sheets, drawers, popovers, the navbar's
   panels) keep their own scroll body, and so does a list marked .is-boxed (a chat thread, a grid that scrolls both
   ways, a list that fills a fixed-height pane). A table or grid that must keep its columns and is wider than the
   screen is .is-hscroll: its box scrolls sideways only, so vertical swipes still scroll the page (its headings do not
   stick: the sideways box is their scroll container). Wrappers that clip rounded corners use overflow: clip here:
   the corners stay, and the sticky headings inside are not trapped. Anything wider than its card is cut off by that
   clip, so a wide table is cards (.ds-table.is-cards-flow), fits, or is .is-hscroll. portal-ui.js uses the same
   query (Portal.ui.PAGE_FLOW_QUERY and Portal.ui.pageFlowMQ, for pages: never paste the string). */
@media (max-width: 900px), (max-height: 500px) and (max-width: 1100px), (pointer: coarse) {
    main.app-main .ds-scroll:not(.is-boxed, .is-hscroll):not(:is(.ds-dialog, .ds-sheet, .ds-drawer, .ds-pop, .portal-surface, .ds-scroll.is-boxed, .ds-scroll.is-hscroll) .ds-scroll) {
        max-height: none; overflow: visible; overscroll-behavior: auto; -webkit-mask-image: none; mask-image: none; --ds-list-top: var(--ds-stick-top); }
    main.app-main .ds-scroll.is-hscroll { max-height: none; overflow-x: auto; overflow-y: hidden; overscroll-behavior: auto; -webkit-mask-image: none; mask-image: none; --ds-list-top: 0px; }
    /* A code block is as tall as its code (no box to scroll up and down in), and still scrolls sideways. */
    .ds-codeblock > .ds-code { max-height: none; overflow-y: hidden; }
    /* A table that is cards wherever the page flows (.is-cards is cards on phones only): the same card rules. */
    .ds-table.is-cards-flow thead { display: none; }
    .ds-table.is-cards-flow, .ds-table.is-cards-flow tbody, .ds-table.is-cards-flow tr, .ds-table.is-cards-flow td { display: block; width: 100%; }
    .ds-table.is-cards-flow tr { border-bottom: 1px solid var(--clr-border); padding: 8px 0; }
    .ds-table.is-cards-flow tr:last-child { border-bottom: 0; }
    .ds-table.is-cards-flow td { height: auto; border: 0; padding: 3px 14px; display: grid; grid-template-columns: 90px minmax(0, 1fr); gap: 10px; text-align: left; }
    .ds-table.is-cards-flow td > .ds-badge { justify-self: start; }
    .ds-table.is-cards-flow td::before { content: attr(data-label); font-size: var(--fs-xs); font-weight: var(--fw-semibold); color: var(--clr-text-muted); text-transform: uppercase; letter-spacing: 0.05em; padding-top: 2px; }
    .ds-table.is-cards-flow td.ds-table-state { display: block; padding: 0; }
    .ds-table.is-cards-flow td.ds-table-state::before { display: none; }
    /* A card's title (td.is-card-title: no label, the title's size), a cell across the card without a label
       (td.is-card-full: the row's actions, a note; left out when empty) and a cell the cards leave out
       (td.is-card-hide): a dataList column's phone "title", "full" and "hide", for a table. */
    .ds-table.is-cards-flow td:is(.is-card-title, .is-card-full) { display: block; }
    .ds-table.is-cards-flow td:is(.is-card-title, .is-card-full)::before { display: none; }
    .ds-table.is-cards-flow td.is-card-title { font-size: var(--fs-title); padding-bottom: var(--space-1); }
    .ds-table.is-cards-flow td.is-card-full:empty, .ds-table.is-cards-flow td.is-card-hide { display: none; }
    .ds-table.is-cards-flow td :is(.ds-cell-main, .ds-cell-sub) { max-width: none; white-space: normal; overflow-wrap: anywhere; }
    .ds-table.is-cards-flow td.is-fill { max-width: none; }
    .ds-table.is-cards-flow:has(td.is-fill) :is(th, td) { white-space: normal; }
    /* A table's own footer (count, pager, "Show more") after its box: a line over it, as its cards have no frame. */
    .ds-scroll:has(> .ds-table.is-cards-flow) + .ds-dl-foot { border-top: 1px solid var(--clr-border); }
    .ds-field.ds-sortby.is-cards-flow { display: flex; }
    main.app-main :is(.ds-dl, .ds-table-wrap, .card.is-flush):not(:is(.ds-dialog, .ds-sheet, .ds-drawer, .ds-pop, .portal-surface) *) { overflow: clip; }
    /* A framed table with no list around it sticks to the page, so its head stops under the top bar too. */
    main.app-main .ds-table-wrap:not(:is(.ds-dialog, .ds-sheet, .ds-drawer, .ds-pop, .portal-surface, .ds-scroll.is-boxed, .ds-scroll.is-hscroll) *) { --ds-list-top: var(--ds-stick-top); }
}
/* Desktop with a mouse (outside page flow, which takes in every touch screen): a footer that ends at the window's
   bottom right keeps clear of the Assistant button, which the page's end leaves room for only where the page flows
   (portal-shell.css): .ds-fab-clear, or a dataList made with endsPage (desktop.md, "The Assistant button's corner").
   Not while the button is left out (an app view, PortalShell.hideAssistant). */
@media (min-width: 1101px) and (pointer: fine), (min-width: 901px) and (min-height: 501px) and (pointer: fine) {
    :where(html:not(.portal-app-view):not(.portal-no-assistant)) body:has(#helpdesk-widget .hd-fab) :is(.ds-fab-clear, .ds-dl.is-page-end > .ds-dl-foot) { padding-right: var(--fab-room); }
}
/* 16 px text in fields on phones and on any touch screen (a phone on its side is wider than 768 px): iOS zooms the
   page into a field whose text is smaller. */
@media (max-width: 768px), (pointer: coarse) {
    .ds-input, .ds-textarea, .ds-select-trigger, .ds-listpop-input, .ds-numin-input, .ds-search-input, .ds-composer-input, .ds-rte-area { font-size: 16px; }
    /* Plain fields too (it outranks portal-base.css's `input { font: inherit }`, which a zero-specificity rule loses to). */
    :is(.portal-page .app-main, .ds-dialog, .ds-sheet, .ds-drawer) :is(input, textarea, select) { font-size: 16px; }
}
@media (max-width: 768px) {
    .ds-form-grid, .ds-form-grid.is-3 { grid-template-columns: 1fr; }
}
@media (max-width: 600px) {
    .ds-icon-btn { width: var(--ctl-h-touch); height: var(--ctl-h-touch); }
    .ds-toasts { width: calc(100vw - 24px); max-width: calc(100vw - 24px); }
    /* A full-width toast would cover the Assistant button (56 px, 12 px above the dock; R13): while the button shows,
       stack the toasts 8 px above it (not while the button is left out: an app view, PortalShell.hideAssistant). The
       condition has no specificity, so AI Chat's own toast position still wins. */
    :where(html:not(.portal-app-view):not(.portal-no-assistant) body:has(#helpdesk-widget:not(.hd-open) .hd-fab)) .ds-toasts { bottom: max(calc(12px + 56px + var(--space-2) + var(--portal-bottom-inset, 0px) + env(safe-area-inset-bottom)), calc(var(--portal-float-clear, 0px) + 56px + var(--space-2))); }
    .ds-page-head { padding: 16px 0 12px; gap: 12px; }
    .ds-page-title { flex-basis: 100%; }
    .ds-page-head h1 { font-size: 21px; }
    .ds-page-actions { margin-left: 0; width: 100%; }
    .ds-page-actions > * { flex: 1 1 auto; justify-content: center; }
    .ds-toolbar > .ds-search { max-width: none; flex-basis: 100%; }
    .ds-toolbar-filterbtn { display: inline-flex; }
    .ds-toolbar-filters.is-collapsible { display: none; }
    .ds-table.is-cards thead { display: none; }
    .ds-table.is-cards, .ds-table.is-cards tbody, .ds-table.is-cards tr, .ds-table.is-cards td { display: block; width: 100%; }
    .ds-table.is-cards tr { border-bottom: 1px solid var(--clr-border); padding: 8px 0; }
    .ds-table.is-cards tr:last-child { border-bottom: 0; }
    .ds-table.is-cards td { height: auto; border: 0; padding: 3px 14px; display: grid; grid-template-columns: 90px minmax(0, 1fr); gap: 10px; text-align: left; }
    .ds-table.is-cards td > .ds-badge { justify-self: start; }   /* a badge keeps its own width, not the value column's */
    .ds-table.is-cards td::before { content: attr(data-label); font-size: var(--fs-xs); font-weight: var(--fw-semibold); color: var(--clr-text-muted); text-transform: uppercase; letter-spacing: 0.05em; padding-top: 2px; }
    .ds-table.is-cards td.ds-table-state { display: block; padding: 0; }
    .ds-table.is-cards td.ds-table-state::before { display: none; }
    .ds-table.is-cards td:is(.is-card-title, .is-card-full) { display: block; }   /* as .is-cards-flow's, above */
    .ds-table.is-cards td:is(.is-card-title, .is-card-full)::before { display: none; }
    .ds-table.is-cards td.is-card-title { font-size: var(--fs-title); padding-bottom: var(--space-1); }
    .ds-table.is-cards td.is-card-full:empty, .ds-table.is-cards td.is-card-hide { display: none; }
    .ds-table.is-cards td :is(.ds-cell-main, .ds-cell-sub) { max-width: none; white-space: normal; overflow-wrap: anywhere; }
    .ds-table.is-cards td.is-fill { max-width: none; }
    .ds-table.is-cards:has(td.is-fill) :is(th, td) { white-space: normal; }
    .ds-field.ds-sortby.is-cards { display: flex; }
    .ds-toolbar.is-inset { padding: var(--space-3) var(--space-4); align-items: center; }
    .ds-toolbar > .ds-toolbar-search { max-width: none; flex-basis: 100%; }
    /* Dialogs become sheets. Where the page is drawn under the phone's status bar (the 34 Lives app, home-screen web
       apps), a sheet stops below it, and a full-height dialog fills behind it but starts its header below it. */
    .ds-overlay { padding: 0; align-items: flex-end; }
    .ds-dialog { max-width: 100% !important; max-height: calc(100dvh - env(safe-area-inset-top, 0px)); border-radius: var(--radius-2xl) var(--radius-2xl) 0 0; transform: translateY(24px); }
    .ds-dialog.is-md, .ds-dialog.is-lg { height: 100dvh; max-height: 100dvh; border-radius: 0; padding-top: env(safe-area-inset-top, 0px); }
    .ds-dialog-foot { border-radius: 0; padding-bottom: calc(12px + env(safe-area-inset-bottom)); }
    .ds-dialog-foot > button { flex: 1 1 auto; min-height: var(--ctl-h-touch); }
    .ds-dialog-foot:has(> .ds-dialog-footnote) { flex-wrap: wrap; }
    .ds-dialog-footnote { flex: 1 0 100%; }
    .ds-drawer, .ds-drawer-wrap .ds-drawer { width: 100%; }
    /* A reply's card pads less; a prose table's columns stay readable (the table scrolls sideways in its box); the
       message box's text area takes its own row above the buttons. */
    .ds-bubble.is-wide { padding: 14px 16px; }
    .ds-prose :is(th, td) { min-width: 6em; }
    .ds-composer { flex-wrap: wrap; }
    .ds-composer-input { order: -1; flex-basis: 100%; }   /* its own row above the buttons */
    /* segmented({narrow: "select"}): the select alone, as wide as its row allows. */
    .ds-seg-wrap.is-narrow-select { display: flex; flex: 1 1 auto; }
    .ds-seg-wrap.is-narrow-select > .ds-seg { display: none; }
    .ds-seg-wrap.is-narrow-select > .ds-seg-narrow { display: flex; flex: 1 1 auto; width: 100%; min-width: 0; }
    /* A property row stacks: one property per line, in two columns (every value starts at the same place): the label
       at the start, wrapping, never cut, with its action under it; the value at the end, a read-only one wrapping. */
    .ds-props.is-row { grid-template-columns: minmax(0, 1fr); gap: 0; }
    .ds-props.is-row .ds-prop { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 3fr); align-items: center; gap: 12px; min-height: var(--ctl-h-touch); padding: 6px 0; border-top: 1px solid var(--clr-border); }
    .ds-props.is-row .ds-prop:first-child { border-top: 0; }
    .ds-props.is-row .ds-prop-label { flex-direction: column; align-items: flex-start; justify-content: center; gap: 2px; height: auto; line-height: var(--lh-snug); font-size: var(--fs-label); font-weight: var(--fw-medium); white-space: normal; }
    .ds-props.is-row .ds-prop-name { max-width: 100%; overflow-wrap: anywhere; }
    .ds-props.is-row .ds-prop-label .ds-linkbtn { margin: 0 -6px; }
    .ds-props.is-row .ds-prop-value { width: auto; align-items: flex-end; }
    .ds-props.is-row .ds-prop-text { white-space: normal; overflow-wrap: anywhere; text-align: right; }
}
@media (pointer: coarse) {
    /* Text buttons and segments are 44 px targets on touch screens (not a link inside a notice's sentence). */
    .ds-linkbtn:not(.ds-notice *) { min-height: var(--ctl-h-touch); min-width: var(--ctl-h-touch); }
    .ds-tick { width: var(--ctl-h-touch); height: var(--ctl-h-touch); margin: calc((26px - var(--ctl-h-touch)) / 2 - 5px); }
    .ds-railtoggle { width: var(--ctl-h-touch); height: var(--ctl-h-touch); }
    /* A wrapping one keeps its first line in the middle of the 44 px (its icon is on that line). */
    .ds-linkbtn.is-wrap:not(.ds-notice *) { padding-block: max(5px, calc((var(--ctl-h-touch) - 1lh) / 2)); }
    .ds-props.is-row .ds-prop-label .ds-linkbtn { margin-block: -14px; }   /* a 44 px target over the 16 px label line */
    .ds-dl-pinned-label .ds-linkbtn { margin-block: -14px; }   /* the same over the pinned band's label line */
    .ds-composer-to .ds-linkbtn { margin-block: -14px; }   /* the same in the recipient line: its lines stay together */
    /* A group head's fold button and the above cue are 44 px targets (the cue is as tall as its Show). The button
       keeps its words' height (the count stays level with its last line) and reaches 44 px through its hit area, which
       lies wholly in the head wherever it sits (first in its scroll box, stuck under the pane's band or the above cue,
       folded next to another folded head or above the list's foot), as each of those would cover what reaches past it.
       So the head's words start at its top, below what the area reaches above the button (half of 44 px less half the
       button's line and its 2 px padding: about 10 px), with 6 px under them (the phone band's padding, at every
       width), and the head is at least 45 px tall: a one-line head holds the whole area and a px to spare (a name with
       a code chip is half a px taller), a head whose note takes a line of its own is taller anyway. (The selectors
       match the pane list's own paddings, 901 px and wider.) */
    .ds-dl-group-btn { position: relative; }
    .ds-dl-group-btn::after { content: ""; position: absolute; left: 50%; top: 50%; width: max(100%, var(--ctl-h-touch)); height: max(100%, var(--ctl-h-touch)); transform: translate(-50%, -50%); }
    .ds-dl-group:has(.ds-dl-group-btn), .ds-dl.is-pane .ds-dl-group:has(.ds-dl-group-btn), .ds-split.is-one-pane .ds-dl.is-pane .ds-dl-group:has(.ds-dl-group-btn) {
        align-items: flex-start; box-sizing: content-box; padding-top: 11px; padding-bottom: 6px; min-height: 28px;
        padding-top: calc(var(--ctl-h-touch) / 2 - 0.5lh - 2px); min-height: calc(var(--ctl-h-touch) / 2 + 0.5lh - 3px); }
    .ds-dl-above { min-height: var(--ctl-h-touch); padding-block: 0; }
    .ds-dl-above .ds-linkbtn { margin-block: 0; }
    .ds-dl-fresh-btn { min-height: var(--ctl-h-touch); }
    .ds-rowlink { min-height: var(--ctl-h-touch); }
    .ds-seg-btn { min-width: var(--ctl-h-touch); }
    .ds-icon-btn { min-width: var(--ctl-h-touch); min-height: var(--ctl-h-touch); }
    .ds-chipbtn { height: var(--ctl-h-touch); border-radius: var(--radius-pill); }
    .ds-fact { height: var(--ctl-h-touch); }   /* a facts row's buttons (32 px with a mouse) */
    .ds-fact.has-avatar { padding-left: 11px; }   /* the 20 px avatar centred in the 44 px pill's round end */
    /* A table's column heads that sort (sortableTable) are 44 px targets, and so are a dataList's (its head shows on a
       touch screen wider than 900 px, a tablet on its side). */
    .ds-table thead th[aria-sort] { height: var(--ctl-h-touch); }
    .ds-dl-sort { min-height: var(--ctl-h-touch); }
    /* A chip's remove button keeps its 24 px circle; an invisible 44 px square around it takes the tap. */
    .ds-chip-x { position: relative; }
    .ds-chip-x::after { content: ""; position: absolute; left: 50%; top: 50%; width: var(--ctl-h-touch); height: var(--ctl-h-touch); transform: translate(-50%, -50%); }
    .ds-seg-btn, .ds-seg.is-sm .ds-seg-btn { height: var(--ctl-h-touch); }
    .ds-toast-close { width: var(--ctl-h-touch); height: var(--ctl-h-touch); }
    .ds-opt { min-height: var(--ctl-h-touch); }
    .ds-menu-item { min-height: var(--ctl-h-touch); }
    /* 2b kit round: dialog feet at any width (a phone in landscape is wider than 600 px), the page head's back
       link, checkbox rows, and "How X works" (it sits in the description's line: its hit area grows, the line does not). */
    .ds-dialog-foot > button { min-height: var(--ctl-h-touch); }
    /* A date range's fields reach over its 1 px frame, so they are 44 px targets like every other field. */
    .ds-daterange .ds-input { height: calc(100% + 2px); margin-block: -1px; }
    /* A calendar's days and month buttons are 44 px targets on touch screens (a popover on a tablet too). */
    .ds-cal { width: calc(7 * var(--ctl-h-touch) + 2 * var(--space-2)); }
    .ds-cal-pop { --ds-cal-head-h: var(--ctl-h-touch); }
    .ds-cal-day { height: var(--ctl-h-touch); }
    .ds-cal-nav.ds-icon-btn { width: var(--ctl-h-touch); height: var(--ctl-h-touch); }
    .ds-date-btn { width: var(--ctl-h-touch); height: var(--ctl-h-touch); right: 0; }
    .ds-date .ds-input.ds-date-input { padding-right: calc(var(--ctl-h-touch) + var(--space-1)); }
    .ds-page-back { min-height: var(--ctl-h-touch); margin-bottom: 0; }
    .ds-check { min-height: var(--ctl-h-touch); align-items: center; }
    .ds-check input { margin-top: 0; }
    .ds-how { padding-block: 12px; margin-block: -12px; }
    .ds-how.is-icon { width: var(--ctl-h-touch); height: var(--ctl-h-touch); padding-block: 0; margin-block: 0; }
    /* A search box's clear button fills the field's height at its right end, a small select is a full-size target, and
       a phone card's expand button is 44 px like every other icon button. */
    .ds-search-x { width: var(--ctl-h-touch); height: var(--field-h); margin: -1px -7px -1px 0; }
    .ds-select.is-sm .ds-select-trigger { min-height: var(--ctl-h-touch); }
    .ds-dl-exp { width: var(--ctl-h-touch); height: var(--ctl-h-touch); }
    .ds-dl { --ds-dl-exp-track: var(--ctl-h-touch); }
    .ds-listpop-search { height: var(--ctl-h-touch); }
    /* A list that keeps its box on a touch screen (.is-boxed, a list in a dialog's or drawer's own box): at its ends it
       hands the swipe on to the page, as a touch screen's own lists do, instead of keeping it. */
    .ds-scroll { overscroll-behavior: auto; }
    /* A switch row and a toast's action are 44 px targets, like a checkbox row and the toast's close button. */
    .ds-switch { min-height: var(--ctl-h-touch); align-items: center; }
    .ds-switch .toggle-switch { margin-top: 0; }
    .ds-toast-action { min-height: var(--ctl-h-touch); }
    .ds-listpop-input { align-self: stretch; margin-block: -1px; }   /* over the 1 px frame: a 44 px field */
    /* A compact disclosure's head, a file chip and a code block's head are 44 px targets: Copy fills the head's height at
       its right end, and a file chip's remove button keeps its 44 px tap square inside the chip. */
    .ds-disclosure.is-compact > .ds-disclosure-btn { min-height: var(--ctl-h-touch); }
    .ds-chip.is-file { height: var(--ctl-h-touch); }
    .ds-chip.is-file > .ds-chip-x { margin-right: 2px; }
    .ds-codeblock-head { min-height: var(--ctl-h-touch); padding: 0 0 0 12px; }
    .ds-codeblock-copy { align-self: stretch; height: auto; min-height: var(--ctl-h-touch); min-width: 64px; padding: 0 14px; border: 0; border-left: 1px solid var(--clr-code-border); border-radius: 0; }
    .ds-codeblock-copy:focus-visible { outline-offset: -3px; }
    .ds-composer-input { padding-block: 10px; }   /* one line is a 44 px target with 16 px text */
}
/* A short screen (a phone on its side): medium and large dialogs fill the height, as they do on a phone held
   upright, so their body is not a sliver between the head and the foot; small dialogs stay centered. */
@media (max-height: 500px) and (max-width: 1100px) {
    .ds-overlay { padding: 0 env(safe-area-inset-right, 0px) 0 env(safe-area-inset-left, 0px); }
    .ds-dialog.is-md, .ds-dialog.is-lg { height: 100dvh; max-height: 100dvh; border-radius: 0; padding-top: env(safe-area-inset-top, 0px); }
    .ds-dialog:is(.is-md, .is-lg) .ds-dialog-foot { border-radius: 0; padding-bottom: calc(12px + env(safe-area-inset-bottom)); }
    .ds-composer-input { max-height: 120px; }   /* the thread keeps room above the keyboard */
}
/* A date range: its two fields share one field's width, so each keeps room for a whole mm/dd/yyyy. At phone width the
   calendar buttons get smaller. On a touch screen of any width, where a tap on the field opens its calendar, they go:
   a 44 px button would leave too little room for the year on a tablet or a phone on its side. */
@media (max-width: 600px) {
    .ds-daterange .ds-date .ds-input.ds-date-input { padding-left: var(--space-2); padding-right: calc(var(--ctl-h-xs) + var(--space-1)); }
    .ds-daterange .ds-date-btn { width: var(--ctl-h-xs); height: var(--ctl-h-xs); right: 0; }
}
@media (pointer: coarse) {
    .ds-daterange .ds-date .ds-input.ds-date-input { padding-right: var(--space-1); }
    .ds-daterange .ds-date-btn { display: none; }
}
@media (prefers-reduced-motion: reduce) {
    :where(.ds-pop, .ds-sheet, .ds-sheet-scrim, .ds-overlay, .ds-dialog, .ds-drawer, .ds-toast, .ds-skel-line, .ds-skel-dot, .ds-skel-card, .ds-skel-cell, .ds-progress-bar > i, .ds-spinner, .ds-meter-seg, .ds-chip-bar, .ds-composer) { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
    /* Typing dots stand still; a live button has no ring (its pressed tint still shows it is on). */
    .ds-typing > span { animation: none !important; opacity: 0.6; }
    .ds-icon-btn.is-live::after { animation: none !important; display: none; }
}

/* =========================================================================================
   NOTIFICATION SETTINGS (Portal.ui.notifyMatrix; promoted from Scheduling's Notifications tab)
   What reaches a person's bell (the "Notifications" column, channel inapp) and inbox ("Email"), as a matrix: one
   bounded list (the kit's bound()) inside a card, a sticky column head that also carries the quiet save status ("Saving...",
   "Saved"), sticky group heads (headings, never rows: their names wrap, never cut), rows of a label, plain-words help
   and one cell per channel (a switch, a tri-state switch, the dash for a channel a row has nothing for, or a small
   select), a scope section (a heading, a caption, at most one hint, scope rows that fold out sub rows of any kind) and a
   foot. Notes and a callout above the card (at the top of the list on phones and short screens). Its own media queries
   follow its base rules here, at the end of the file, so they keep the order they had as Scheduling's page rules.
   ========================================================================================= */
.ds-notify, .ds-notify-card {
    --ds-notify-col: 132px;                     /* one channel column */
    --ds-notify-head-h: 40px;                   /* the sticky column head; group heads stick right under it */
    --ds-notify-pad-x: 20px;
    --ds-notify-help: var(--clr-text-muted);            /* help text: AA muted text (4.7:1 on the group band) */
    --ds-notify-off-track: var(--clr-switch-off);       /* a switch's off track: 3:1 against the surface */
    --ds-notify-mixed-track: var(--clr-switch-mixed);
}

/* Short notes above the card (what still lists everything; why the rows start off) */
.ds-notify-note { display: flex; align-items: flex-start; gap: 7px; margin: 0 0 12px; font-size: var(--fs-label); line-height: 1.45; color: var(--ds-notify-help); }
.ds-notify-note svg.ds-i { width: 15px; height: 15px; flex: none; margin-top: 1px; color: var(--clr-primary); }
.ds-notify-note b { font-weight: var(--fw-semibold); color: var(--clr-text-body); }
.ds-notify-note.is-warn svg.ds-i { color: var(--clr-warning-hover); }

/* The callout: why rows start off for this person, and one button that turns the usual set on */
.ds-notify-callout { display: flex; align-items: center; flex-wrap: wrap; gap: 10px 14px; margin: 0 0 12px; padding: 12px 16px;
    border: 1px solid var(--clr-primary-line); border-radius: var(--radius-lg);
    background: var(--clr-primary-light); color: var(--clr-text-body); font-size: var(--fs-sm); line-height: 1.45; }
.ds-notify-callout-ic { display: inline-grid; place-items: center; width: 32px; height: 32px; flex: none; border-radius: var(--radius-md); background: var(--clr-surface); color: var(--clr-primary); }
.ds-notify-callout-ic svg.ds-i { width: 17px; height: 17px; }
.ds-notify-callout-text { flex: 1 1 320px; min-width: 0; }
.ds-notify-callout-text b { color: var(--clr-text-heading); }
.ds-notify-callout .btn-secondary { flex: none; }
.ds-notify-callout .btn-secondary[aria-disabled="true"] { opacity: 0.6; cursor: progress; }   /* saving; keeps focus */

/* The card: the finder's toolbar, the bounded list, a foot */
.card.ds-notify-card { padding: 0; overflow: hidden; }
.ds-dialog .ds-notify-card { margin: 0; box-shadow: none; }   /* a matrix inside a dialog is flat */
.ds-notify-tools { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 14px; padding: 12px var(--ds-notify-pad-x); border-bottom: 1px solid var(--clr-border); }
.ds-notify-tools .ds-search { flex: 1 1 280px; max-width: 440px; }
.ds-notify-tools-meta { margin-left: auto; display: flex; align-items: center; gap: 4px 12px; flex-wrap: wrap; font-size: var(--fs-label); color: var(--ds-notify-help); }

.ds-notify-list { position: relative; background: var(--clr-surface); }
.ds-notify-list.ds-scroll { border-radius: 0; }

/* Rows: the label and its help, then one column per channel (--ds-notify-n: how many, 2 unless the page has more) */
.ds-notify-row, .ds-notify-head, .ds-notify-group { display: grid; grid-template-columns: minmax(0, 1fr) repeat(var(--ds-notify-n, 2), var(--ds-notify-col)); align-items: center; column-gap: 8px; }
.ds-notify-row { min-height: 58px; padding: 10px var(--ds-notify-pad-x); border-top: 1px solid var(--clr-border); background: var(--clr-surface); }
@media (hover: hover) { .ds-notify-row:hover { background: var(--clr-row-hover); } }
.ds-notify-row.is-flash { animation: ds-flash 1.6s ease; }   /* the kit's row flash */

/* The sticky column head: always in view while the list scrolls (in page flow too, where the list flows in the page
   and the head sticks under the top bar: --ds-list-top) */
.ds-notify-head { position: sticky; top: var(--ds-list-top, 0px); z-index: 4; height: var(--ds-notify-head-h); padding: 0 var(--ds-notify-pad-x); border-bottom: 1px solid var(--clr-head-line);
    background: var(--clr-head-bg); color: var(--clr-head-ink); font-size: var(--fs-xs); font-weight: var(--fw-bold); letter-spacing: var(--tracking-caps); text-transform: uppercase; }
.ds-notify-list.has-above .ds-notify-head { box-shadow: var(--shadow-head); }
.ds-notify-colh { display: flex; align-items: center; justify-content: center; gap: 6px; min-width: 0; white-space: nowrap; }
.ds-notify-colh svg.ds-i { width: 15px; height: 15px; flex: none; }
.ds-notify-colh .ds-notify-short { display: none; }
.ds-notify-head > :first-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* The head's first cell: "What", then the quiet save status that fades out on its own. It is always in view (the head
   is sticky), takes no room from anything, and is announced by the matrix's own live region. */
.ds-notify-head-what { display: flex; align-items: center; gap: 8px; min-width: 0; }
.ds-notify-status { display: inline-flex; align-items: center; gap: 4px; min-width: 0; font-size: var(--fs-label); font-weight: var(--fw-semibold);
    letter-spacing: 0; text-transform: none; white-space: nowrap; color: var(--clr-success-ink); opacity: 0; transition: opacity var(--dur-slow) ease; }
.ds-notify-status svg.ds-i { width: var(--icon-sm); height: var(--icon-sm); flex: none; }
.ds-notify-status.is-shown { opacity: 1; transition-duration: var(--dur); }
.ds-notify-status.is-saving { color: var(--ds-notify-help); font-weight: var(--fw-medium); }

/* Group heads: a tinted band that sticks under the column head (the kinds' groups and the scope's blocks). Its label
   is a heading (role="heading"); its name wraps, never cut. */
.ds-notify-group { position: sticky; top: calc(var(--ds-list-top, 0px) + var(--ds-notify-head-h)); z-index: 3; min-height: 36px; padding: 4px var(--ds-notify-pad-x);
    background: var(--clr-group-neutral); border-top: 1px solid var(--clr-border); border-bottom: 1px solid var(--clr-border);
    font-size: var(--fs-sm); font-weight: var(--fw-bold); color: var(--clr-text-heading); }
/* A group head sticks only while its own block (head and rows) is in view, so the next heading never slides under it */
.ds-notify-block { position: relative; }
.ds-notify-group + .ds-notify-row, .ds-notify-head + .ds-notify-block > .ds-notify-group, .ds-notify-head + .ds-notify-row { border-top: 0; }
.ds-notify-group-label { display: flex; align-items: center; gap: 8px; min-width: 0; }
.ds-notify-group-text { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 8px; min-width: 0; }
.ds-notify-group-name { min-width: 0; overflow-wrap: anywhere; }
.ds-notify-group-ic { display: inline-grid; flex: none; color: var(--clr-primary); }
.ds-notify-group-ic svg.ds-i { width: 15px; height: 15px; }
.ds-notify-group-sub { font-weight: var(--fw-medium); color: var(--ds-notify-help); white-space: nowrap; }

/* The scope section's title inside the list ("Departments"): larger, not sticky, distinct from rows */
.ds-notify-section { padding: 20px var(--ds-notify-pad-x) 12px; border-top: 6px solid var(--clr-bg); background: var(--clr-surface); }
.ds-notify-section h3 { display: flex; align-items: center; gap: 8px; margin: 0; font-size: var(--fs-title); font-weight: var(--fw-bold); color: var(--clr-text-heading); letter-spacing: -0.005em; }
.ds-notify-section h3 svg.ds-i { width: 17px; height: 17px; color: var(--clr-primary); }
.ds-notify-section p { margin: 3px 0 0; max-width: 68ch; font-size: var(--fs-label); line-height: 1.45; color: var(--ds-notify-help); }
/* At most one hint under the caption: why the switches below would change nothing, or reach nothing yet */
.ds-notify-section .ds-notify-hint { display: flex; align-items: flex-start; gap: 6px; margin-top: 8px; color: var(--ds-notify-help); }
.ds-notify-section .ds-notify-hint svg.ds-i { width: var(--icon-sm); height: var(--icon-sm); flex: none; margin-top: 2px; color: var(--clr-text-muted); }
.ds-notify-section .ds-notify-hint.is-warn { color: var(--clr-amber-ink); font-weight: var(--fw-semibold); }
.ds-notify-section .ds-notify-hint.is-warn svg.ds-i { color: var(--clr-warning-hover); }
.ds-notify-scope-empty { padding: 14px var(--ds-notify-pad-x) 18px; font-size: var(--fs-sm); color: var(--ds-notify-help); border-top: 1px solid var(--clr-border); }

.ds-notify-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.ds-notify-label { display: flex; align-items: center; flex-wrap: wrap; gap: 2px 8px; font-size: var(--fs-md); font-weight: var(--fw-semibold); color: var(--clr-text-heading); }
.ds-notify-help { margin: 0; font-size: var(--fs-label); line-height: 1.45; color: var(--ds-notify-help); }
.ds-notify-reason { margin: 0; font-size: var(--fs-xs); line-height: 1.4; color: var(--ds-notify-help); }
.ds-notify-changed { display: inline-flex; align-items: center; gap: 4px; font-size: var(--fs-xs); font-weight: var(--fw-medium); color: var(--ds-notify-help); }
.ds-notify-changed::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: var(--clr-primary); }
.ds-notify-changed .ds-linkbtn { padding: 1px 3px; font-size: var(--fs-xs); }
.ds-notify-changed-sep { color: var(--ds-notify-help); }

/* Fold buttons (a scope block's head, a scope row) */
.ds-notify-fold { appearance: none; display: inline-grid; place-items: center; width: 28px; height: 28px; flex: none; margin: -4px 0 -4px -6px; padding: 0;
    border: 0; border-radius: var(--radius-sm); background: none; color: var(--clr-text-muted); cursor: pointer; }
@media (hover: hover) { .ds-notify-fold:hover { background: var(--clr-surface-muted); color: var(--clr-text-heading); } }
.ds-notify-fold:focus-visible { outline: 2px solid var(--clr-focus-ring); outline-offset: 1px; }
.ds-notify-fold svg.ds-i { width: var(--icon-md); height: var(--icon-md); transition: transform var(--dur) ease; }
.ds-notify-fold[aria-expanded="false"] svg.ds-i { transform: rotate(-90deg); }
.ds-notify-fold-gap { width: 28px; flex: none; margin: 0 0 0 -6px; }   /* a scope row with nothing to fold keeps the names aligned */

/* Scope rows (.is-dept: a department) and the sub rows they fold out (.is-sub: a work role, a ticket kind) */
.ds-notify-row.is-dept { min-height: 52px; }
.ds-notify-row.is-dept .ds-notify-main { flex-direction: row; align-items: center; gap: 8px; }
.ds-notify-dept-text { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.ds-notify-dept-name { font-size: var(--fs-md); font-weight: var(--fw-semibold); color: var(--clr-text-heading); overflow-wrap: anywhere; }
.ds-notify-dept-sub { font-size: var(--fs-xs); color: var(--ds-notify-help); }
.ds-notify-dept-sub b { font-weight: var(--fw-semibold); color: var(--clr-text-body); }
.ds-notify-row.is-sub { min-height: 46px; padding-top: 6px; padding-bottom: 6px; padding-left: calc(var(--ds-notify-pad-x) + 30px); border-top-color: var(--clr-border); }
.ds-notify-row.is-sub .ds-notify-main { flex-direction: row; align-items: center; gap: 9px; }
/* A sub row's color dot: --c from the row's category class (.ds-cat-N) */
.ds-notify-sub-dot { width: 10px; height: 10px; flex: none; border-radius: var(--radius-xs); background: var(--c, var(--cat-none)); }
.ds-notify-sub-name { font-size: var(--fs-sm); font-weight: var(--fw-medium); color: var(--clr-text-body); overflow-wrap: anywhere; }
.ds-notify-row.is-off .ds-notify-dept-name, .ds-notify-row.is-off .ds-notify-sub-name { color: var(--ds-notify-help); }
.ds-notify-mark { display: inline-flex; align-items: center; height: 18px; padding: 0 6px; border-radius: var(--radius-sm); background: var(--clr-surface-muted); color: var(--ds-notify-help); font-size: var(--fs-2xs); font-weight: var(--fw-semibold); }
mark.ds-notify-hit { background: var(--clr-mark); color: var(--clr-text-heading); border-radius: var(--radius-xs); padding: 0 1px; }

/* Switch cells. The look of the kit's .toggle-switch (portal-base.css), with a darker off track and a mixed state
   (role="checkbox" aria-checked="mixed" and input.indeterminate: the knob in the middle, a bar on it, a half-tone
   track). A red ring for a few seconds marks a switch whose save failed and was switched back. */
.ds-notify-cell { display: flex; align-items: center; justify-content: center; min-width: 0; }
.ds-notify-sw { position: relative; }
.ds-notify-sw .toggle-slider { background-color: var(--ds-notify-off-track); }
.ds-notify-sw input:checked + .toggle-slider { background-color: var(--clr-primary); }
.ds-notify-sw input:indeterminate + .toggle-slider { background-color: var(--ds-notify-mixed-track); }
.ds-notify-sw input:indeterminate + .toggle-slider::before { transform: translateX(10px); }
.ds-notify-sw input:indeterminate + .toggle-slider::after { content: ""; position: absolute; left: 50%; top: 50%; width: 8px; height: 2px; margin: -1px 0 0 -4px; border-radius: var(--radius-xs); background: var(--clr-primary); }
.ds-notify-sw input:focus-visible + .toggle-slider { box-shadow: 0 0 0 2px var(--clr-surface), 0 0 0 4px var(--clr-focus-ring); }
.ds-notify-sw.is-error .toggle-slider { box-shadow: 0 0 0 2px var(--clr-surface), 0 0 0 4px var(--clr-danger); }
.ds-notify-sw input:disabled + .toggle-slider { opacity: 0.4; cursor: not-allowed; }
/* A row whose switches can't change now (disabledReason): the switches dim but keep focus, and the reason is a muted
   line under the name (.ds-notify-reason), which they name as their description. */
.ds-notify-sw input[aria-disabled="true"] + .toggle-slider { opacity: 0.4; cursor: not-allowed; }
.ds-notify-sw:has(> input[aria-disabled="true"]) { cursor: not-allowed; }
/* A channel a row has nothing for: a muted dash (its accessible name and tip say why) */
.ds-notify-na { display: inline-flex; align-items: center; justify-content: center; min-width: 44px; color: var(--clr-text-muted); font-weight: var(--fw-semibold); }
/* A select cell: a small kit select in a channel column, for a level per channel; a row holding one is .has-selects.
   Its channel's name above it (.ds-notify-cell-label) shows only on phones, where the row stacks. */
.ds-notify-cell.is-select { justify-content: stretch; padding: 0 6px; }
.ds-notify-cell.is-select > .ds-notify-select { width: 100%; min-width: 0; }
.ds-notify-cell-label { display: none; }
.ds-notify-row.has-selects { min-height: 56px; }

/* The foot: how saving works, where emails go, reset */
.ds-notify-foot { display: flex; align-items: center; flex-wrap: wrap; gap: 6px 16px; padding: 12px var(--ds-notify-pad-x); border-top: 1px solid var(--clr-border); font-size: var(--fs-label); color: var(--ds-notify-help); }
.ds-notify-foot-item { display: inline-flex; align-items: center; gap: 6px; min-width: 0; }
.ds-notify-foot-item svg.ds-i { width: var(--icon-sm); height: var(--icon-sm); flex: none; color: var(--clr-text-muted); }
.ds-notify-foot-item b { font-weight: var(--fw-semibold); color: var(--clr-text-body); overflow-wrap: anywhere; }
.ds-notify-foot-item.is-warn { color: var(--clr-amber-ink); font-weight: var(--fw-semibold); }
.ds-notify-foot-item.is-warn svg.ds-i { color: var(--clr-warning-hover); }
/* A foot switch (Ticket Admin and My Tickets: "Desktop alerts in this browser"): its words, then the switch; last */
.ds-notify-foot-item.is-switch { order: 1; gap: var(--space-2-5); cursor: pointer; }
.ds-notify-foot .ds-linkbtn { margin-left: auto; display: inline-flex; align-items: center; gap: 5px; }
.ds-notify-foot .ds-linkbtn svg.ds-i { width: var(--icon-sm); height: var(--icon-sm); }
.ds-notify-list > .ds-notify-foot { background: var(--clr-surface); }   /* phones and short screens: the foot ends the list */

.ds-notify-list > .ds-empty, .ds-notify-list > .ds-skel { border-top: 0; }
/* Phones and short screens: the notes scroll away at the top of the list, and the finder sits in the scope section */
.ds-notify-lead { padding: 12px var(--ds-notify-pad-x) 0; background: var(--clr-surface); }
.ds-notify-lead .ds-notify-note:last-child, .ds-notify-lead .ds-notify-callout:last-child { margin-bottom: 12px; }
.ds-notify-section .ds-notify-tools { margin: 12px 0 0; padding: 0; border: 0; }

@media (max-width: 900px) {
    .ds-notify, .ds-notify-card { --ds-notify-col: 104px; }
}
@media (max-width: 900px), (max-height: 500px) and (max-width: 1100px), (pointer: coarse) {
    /* Page flow: the list is part of the page, so the card clips its corners without being a scroll box (overflow:
       hidden would hold the sticky column head and group heads inside the card instead of under the top bar). */
    .card.ds-notify-card { overflow: clip; }
}
@media (max-width: 600px) {
    .ds-notify, .ds-notify-card { --ds-notify-col: 58px; --ds-notify-pad-x: 14px; }
    .ds-notify-colh { flex-direction: column; gap: 1px; font-size: var(--fs-2xs); letter-spacing: 0.04em; }
    .ds-notify-colh .ds-notify-long { display: none; }
    .ds-notify-colh .ds-notify-short { display: inline; }
    .ds-notify-row { min-height: 64px; padding-top: 12px; padding-bottom: 12px; align-items: start; }
    .ds-notify-row .ds-notify-cell { padding-top: 1px; }
    .ds-notify-row.is-dept, .ds-notify-row.is-sub { align-items: center; }
    .ds-notify-row.is-dept .ds-notify-cell, .ds-notify-row.is-sub .ds-notify-cell { padding-top: 0; }
    .ds-notify-row.is-sub { padding-left: calc(var(--ds-notify-pad-x) + 22px); min-height: 48px; }
    /* A row of selects stacks: its label on top, then one select per channel, each under its channel's name */
    .ds-notify-row.has-selects { grid-template-columns: repeat(var(--ds-notify-n, 2), minmax(0, 1fr)); row-gap: 8px; }
    .ds-notify-row.has-selects .ds-notify-main { grid-column: 1 / -1; }
    .ds-notify-row.has-selects .ds-notify-cell.is-select { flex-direction: column; align-items: stretch; gap: 2px; padding: 0; }
    .ds-notify-cell-label { display: block; font-size: var(--fs-xs); color: var(--ds-notify-help); }
    .ds-notify-tools { padding: 10px var(--ds-notify-pad-x); flex-wrap: nowrap; gap: 10px; }
    .ds-notify-tools .ds-search { flex: 1 1 0; max-width: none; }
    .ds-notify-tools-meta { flex: none; }
    .ds-notify-tools-count { display: none; }
    /* A scope block's head: the name above its summary, no icon, so long names still fit beside the switches */
    .ds-notify-group.is-site .ds-notify-group-ic { display: none; }
    .ds-notify-group.is-site .ds-notify-group-text { flex-direction: column; align-items: flex-start; gap: 0; }
    .ds-notify-group.is-site .ds-notify-group-sub { font-size: var(--fs-xs); }
    .ds-notify-foot .ds-notify-foot-item.is-save { display: none; }
    .ds-notify-foot { padding-top: 10px; padding-bottom: 10px; }
    .ds-notify-callout { display: grid; grid-template-columns: 32px minmax(0, 1fr); align-items: start; padding: 12px 14px; }
    .ds-notify-callout .btn-secondary { grid-column: 1 / -1; width: 100%; justify-content: center; }
    .ds-notify-foot .ds-linkbtn { margin-left: 0; }
}
@media (max-height: 500px) and (max-width: 1100px) {
    .ds-notify-tools-count { display: none; }
    .ds-notify-note { margin-bottom: 8px; }
    .ds-notify-row { min-height: 50px; padding-top: 8px; padding-bottom: 8px; }
    .ds-notify-foot .ds-notify-foot-item.is-save { display: none; }   /* one foot line, so more of the list fits */
}
@media (pointer: coarse) {
    /* 44 px targets: the 44x24 switch gets a 44x44 hit area; fold buttons grow to 44 px (a select cell's small select
       is 44 px tall here already: .ds-select.is-sm) */
    .ds-notify-sw::after { content: ""; position: absolute; left: -6px; right: -6px; top: -10px; bottom: -10px; }
    .ds-notify-fold { width: var(--ctl-h-touch); height: var(--ctl-h-touch); margin: -10px -4px -10px -12px; }
    .ds-notify-fold-gap { width: var(--ctl-h-touch); margin: 0 -4px 0 -12px; }
    /* "Use default" keeps its 44 px target (the kit's .ds-linkbtn on touch) without making the label's line 44 px tall */
    .ds-notify-changed .ds-linkbtn { margin: -12px 0; position: relative; z-index: 1; }   /* above the help line under it */
}
@media (prefers-reduced-motion: reduce) {
    .ds-notify-fold svg.ds-i, .ds-notify-sw .toggle-slider, .ds-notify-sw .toggle-slider::before, .ds-notify-status { transition: none; }
    .ds-notify-row.is-flash { animation: none; }
}

/* =========================================================================================
   RECORD GRID (Portal.ui.recordGrid; components.md "Record grid")
   A list card beside its open record's card, in the page flow under a page head (records looked up now and then, not
   a queue: a queue is a split view). The list card is clamp(280px, 36%, 400px) wide, the record's card the rest; both
   start at the top. Where the page flows (Portal.ui.pageFlowMQ) the builder sets .is-one-pane: the list alone, the
   record in the kit's drawer. .is-failed: the list could not load and its error takes the whole row. In the drawer the
   record is .ds-recgrid-layer: its key line, its actions (.ds-recgrid-actions), then its body.
   ========================================================================================= */
.ds-recgrid { display: grid; grid-template-columns: clamp(280px, 36%, 400px) minmax(0, 1fr); gap: var(--space-4); align-items: start; min-width: 0; }
.ds-recgrid.is-one-pane, .ds-recgrid.is-failed { grid-template-columns: minmax(0, 1fr); }
.ds-recgrid.is-one-pane > .ds-recgrid-detail, .ds-recgrid.is-failed > .ds-recgrid-detail { display: none; }
.ds-recgrid-list, .ds-recgrid-detail { min-width: 0; }
.ds-recgrid-layer { display: flex; flex-direction: column; gap: var(--space-4); min-width: 0; }
.ds-recgrid-layer > .ds-card-desc { margin: 0; }
.ds-recgrid-actions { display: flex; flex-wrap: wrap; gap: var(--space-2); }

/* =========================================================================================
   SPLIT VIEW AND PANES (Portal.ui.split; components.md "Split view")
   A list beside its records. .ds-split holds two panes: the list column (.ds-split-list, --ds-split-list wide: 372,
   340 or 300 px by window band, portal-tokens.css) and the detail (.ds-split-detail, the rest; a size container named
   ds-split-detail). Above the compact line (Portal.ui.compactMQ) the split is an app view (the builder enters it): the
   window keeps still and each pane scrolls its own body. Below the line the builder sets .is-one-pane and data-pane
   ("list" or "detail"): one pane shows, in page flow, and the other is out of the tree for readers too.
   .is-list-hidden folds the list away beside the detail (never in one pane).
   A pane (.ds-pane) is a column: .ds-pane-head (fixed: the surface with a rule under it, made of bands, .ds-pane-band,
   with a rule between two; .is-muted tints one), .ds-pane-body (the one scroller; .is-padded pads it at the inset) and
   .ds-pane-foot (fixed: the surface with a rule over it; the builder reports its height to PortalShell.setFloatClear,
   so toasts sit above it). --ds-pane-x is the side inset: 24 px in a detail pane and 16 in a list pane; 20 and 16
   under 1280 px; 16 and 12 under 1101 px. The pane head's title is .ds-pane-title (a record's subject: two lines,
   then an ellipsis; whole in one pane); in the list pane it is one line, the name (.ds-pane-title-text) and its count
   (.ds-gcount). The record bar (.ds-pane-bar: Back, the stepper .ds-stepper, the record's tools) heads the detail's
   first band beside the list; in one pane it is the detail pane's own first child, sticky under the top bar
   (--ds-pane-bar-h tall), and everything else in that pane scrolls into view below it. One pane at a time the head
   and foot lose their surface and rules, bands keep only a gap under them and a muted band becomes a card.
   ========================================================================================= */
.ds-split { display: grid; grid-template-columns: var(--ds-split-list) minmax(0, 1fr); flex: 1 1 auto; min-width: 0; min-height: 0; }
html.portal-app-view .ds-split { height: 100%; grid-template-rows: minmax(0, 1fr); }
.ds-split-list { min-width: 0; background: var(--clr-surface); border-right: 1px solid var(--clr-border); }
.ds-split-detail { container: ds-split-detail / inline-size; min-width: 0; background: var(--clr-bg); }
.ds-split.is-list-hidden:not(.is-one-pane) { grid-template-columns: minmax(0, 1fr); }
.ds-split.is-list-hidden:not(.is-one-pane) > .ds-split-list { display: none; }
/* Nothing selected: the detail pane's own state, centred, with what to do next (an .ds-empty inside). */
.ds-split-empty { flex: 1 1 auto; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; min-height: 0; padding: 32px 24px; text-align: center; overflow: auto; }
.ds-split-empty .ds-empty { max-width: 460px; }

.ds-pane { --ds-pane-x: 24px; display: flex; flex-direction: column; min-width: 0; min-height: 0; }
.ds-split-list.ds-pane { --ds-pane-x: 16px; }
.ds-pane-head { flex: none; min-width: 0; background: var(--clr-surface); border-bottom: 1px solid var(--clr-border); }
.ds-pane-band { min-width: 0; padding: 12px var(--ds-pane-x) 10px; }
.ds-pane-band + .ds-pane-band, .ds-pane-head > .ds-notice + .ds-pane-band { border-top: 1px solid var(--clr-border); }
/* A band's line: the title and its tools (.ds-pane-titlerow), or the search and what sits beside it (.ds-pane-row).
   .ds-pane-tools ends a line, in the record bar too. */
.ds-pane-titlerow { display: flex; align-items: center; gap: var(--space-2); min-width: 0; min-height: 32px; }
.ds-pane-titlerow > .ds-pane-title { flex: 1 1 auto; min-width: 0; }
.ds-pane-tools { margin-left: auto; display: inline-flex; align-items: center; gap: var(--space-1); flex: none; }
.ds-pane-row { display: flex; align-items: center; gap: var(--space-2); min-width: 0; }
.ds-pane-row[hidden] { display: none; }
.ds-pane-row > .ds-search { flex: 1 1 auto; min-width: 0; }
/* A list's Filters popover (Portal.ui.filtersFrame). */
.ds-filters { display: flex; flex-direction: column; gap: var(--space-3); padding: 14px 16px; min-width: 280px; }
.ds-sheet .ds-filters { padding: 0; min-width: 0; }
.ds-filters-foot { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding-top: var(--space-1); }
.ds-pane-band.is-muted { background: var(--clr-surface-muted); }
.ds-pane-head > .ds-notice { margin: 0 var(--ds-pane-x) 10px; }
.ds-pane-body { flex: 1 1 auto; min-width: 0; min-height: 0; }
.ds-pane-body.is-padded { padding: 14px var(--ds-pane-x) 20px; }
/* In the app view the body is the pane's one scroller; a list that fills it (dataList maxHeight "pane") scrolls its
   own rows instead, so the body is then a column that does not scroll. */
html.portal-app-view .ds-pane-body { overflow-x: hidden; overflow-y: auto; overscroll-behavior: contain; }
html.portal-app-view .ds-pane-body:focus-visible { outline: 2px solid var(--clr-focus-ring); outline-offset: -2px; }
html.portal-app-view .ds-pane-body:has(> .ds-dl.is-pane) { display: flex; flex-direction: column; overflow: hidden; }
.ds-pane-body > .ds-dl.is-pane { border: 0; border-radius: 0; }   /* the pane is the list's box */
.ds-pane-foot { flex: none; min-width: 0; padding: 10px var(--ds-pane-x) 12px; background: var(--clr-surface); border-top: 1px solid var(--clr-border); }
/* The pane head's title: a record's subject (two lines, then an ellipsis: its tip and the list row keep it whole).
   Focused from code (after a row's Enter, from history) it draws no ring; the keyboard's focus draws it. */
.ds-pane-title { margin: 0; font-size: var(--fs-lg); line-height: var(--lh-snug); font-weight: var(--fw-bold); color: var(--clr-text-heading); display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; overflow-wrap: anywhere; }
/* Two panes under 680 px tall, while the pane's box is open: one line, so the conversation keeps its floor (a laptop's
   browser window is about 650 px tall). */
@media (min-width: 1101px) and (max-height: 679px), (min-width: 901px) and (min-height: 501px) and (max-height: 679px) {
    .ds-pane:has(> .ds-composer-dock.is-writing) .ds-pane-title { -webkit-line-clamp: 1; }
    /* The line under the box goes while it holds only the keys, so the conversation keeps its floor. */
    .ds-composer-dock .ds-composer-hint:not(:has(.ds-composer-hint-text:not(:empty))) { display: none; }
}
.ds-pane-title:focus { outline: none; }
.ds-pane-title:focus-visible { outline: 2px solid var(--clr-focus-ring); outline-offset: 2px; border-radius: var(--radius-xs); }
/* The list pane's title: the view's name (cut with an ellipsis) and its count on one line, larger than the record's
   title beside it. */
.ds-split-list .ds-pane-title { display: flex; align-items: baseline; gap: 8px; min-width: 0; font-size: var(--fs-xl); -webkit-line-clamp: unset; }
.ds-pane-title-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ds-split-list .ds-pane-title > .ds-gcount { flex: none; }
/* The record bar: Back (one pane), the stepper and the record's tools, on one centred row. */
.ds-pane-bar { display: flex; align-items: center; gap: 8px; min-width: 0; min-height: 32px; }
/* The stepper: "7 of 14" with previous and next, then a rule before the tools after it. */
.ds-stepper { display: inline-flex; align-items: center; gap: 2px; flex: none; padding-right: 8px; margin-right: 4px; border-right: 1px solid var(--clr-border); }
/* With no tools after it, no rule. */
.ds-stepper:last-child { padding-right: 0; margin-right: 0; border-right: 0; }
.ds-stepper-pos { margin-right: 6px; font-size: var(--fs-label); color: var(--clr-text-muted); font-variant-numeric: tabular-nums; white-space: nowrap; }

/* One pane at a time (below the compact line): the split is a block, the shown pane flows in the page. */
.ds-split.is-one-pane { display: block; }
.ds-split.is-one-pane > .ds-split-list, .ds-split.is-one-pane > .ds-split-detail { border: 0; background: none; }
.ds-split.is-one-pane[data-pane="list"] > .ds-split-detail, .ds-split.is-one-pane:not([data-pane="list"]) > .ds-split-list { display: none; }
.ds-split.is-one-pane .ds-pane-head, .ds-split.is-one-pane .ds-pane-foot { background: none; border: 0; }
.ds-split.is-one-pane .ds-pane-band { padding: 0 0 10px; }
.ds-split.is-one-pane > .ds-split-list > .ds-pane-head.ds-pane-band:first-child,
.ds-split.is-one-pane > .ds-split-list > .ds-pane-head:first-child > .ds-pane-band:first-child { padding-top: 12px; }   /* off the top bar */
.ds-split.is-one-pane .ds-pane-band + .ds-pane-band, .ds-split.is-one-pane .ds-pane-head > .ds-notice + .ds-pane-band { border-top: 0; }
.ds-split.is-one-pane .ds-pane-band.is-muted { padding: 12px 14px; border: 1px solid var(--clr-border); border-radius: var(--radius-lg); background: var(--clr-surface); }
.ds-split.is-one-pane .ds-pane-head > .ds-notice { margin: 0 0 12px; }
.ds-split.is-one-pane .ds-pane-body.is-padded { padding: 14px 0 8px; }
.ds-split.is-one-pane .ds-pane-foot { padding: 10px 0 0; }
.ds-split.is-one-pane .ds-stepper { padding-right: 0; margin-right: 0; border: 0; }
/* One pane, the record's title is whole and larger; the list's names the screen, at a phone page head's size. */
.ds-split.is-one-pane .ds-pane-title { display: block; font-size: var(--fs-xl); -webkit-line-clamp: unset; }
.ds-split.is-one-pane .ds-split-list .ds-pane-title { display: flex; font-size: var(--fs-2xl); }
/* One pane, the record bar sticks under the top bar, across the page gutters, while the record scrolls (whatever made
   the split one pane: a narrow window or a short one, a phone on its side), and what scrolls into view in the window
   stops below it (focus given back after a dialog, Tab, scrollIntoView): the root's top scroll padding is the shell's
   (the top bar and 8 px) plus the bar (shell-and-navigation.md "The page area"). It is the root's, not a margin on the
   pane's elements, so a scroll box inside the pane (a list with a maxHeight) scrolls only by what it needs. While focus
   is in the bar the padding is the top bar's alone: the bar is always in view, and inside the padding each focus or
   Tab on its controls would scroll the page. */
.ds-split.is-one-pane[data-pane="detail"] > .ds-split-detail > .ds-pane-bar { position: sticky; top: var(--portal-topbar-h); z-index: 5; box-sizing: border-box; min-height: var(--ds-pane-bar-h); margin: 0 calc(-1 * var(--page-gutter)); padding: 4px var(--page-gutter); background: var(--clr-bg); }
html:has(.ds-split.is-one-pane[data-pane="detail"] > .ds-split-detail > .ds-pane-bar) { scroll-padding-top: var(--ds-pane-bar-h); }
html:has(.portal-topbar):has(.ds-split.is-one-pane[data-pane="detail"] > .ds-split-detail > .ds-pane-bar) { scroll-padding-top: calc(var(--portal-topbar-h) + var(--space-2) + var(--ds-pane-bar-h)); }
html:has(.ds-split.is-one-pane[data-pane="detail"] > .ds-split-detail > .ds-pane-bar:focus-within) { scroll-padding-top: 0px; }
html:has(.portal-topbar):has(.ds-split.is-one-pane[data-pane="detail"] > .ds-split-detail > .ds-pane-bar:focus-within) { scroll-padding-top: var(--portal-topbar-h); }

@media (max-width: 1279px) {
    .ds-pane { --ds-pane-x: 20px; }
    .ds-split-list.ds-pane { --ds-pane-x: 16px; }
}
@media (max-width: 1100px) {
    .ds-pane { --ds-pane-x: 16px; }
    .ds-split-list.ds-pane { --ds-pane-x: 12px; }
}
@media (max-width: 600px) {
    .ds-stepper-pos { display: none; }   /* previous and next stay; the bar names the record */
}

/* =========================================================================================
   THREAD (Portal.ui.thread; components.md "Thread")
   A record's conversation (a ticket's, a request's): .ds-thread is the feed (role="feed"), a column of posts 12 px
   apart. A post (.ds-post, an article) speaks in one of two voices, .is-them (the other side: left, on the surface)
   and .is-us (our reply: right, the primary tint), or is .is-note (a note the other side never sees: right, the
   warning tint); its head holds an .is-xs avatar, the author, what it is (.ds-post-source) and its time
   (.ds-post-time, relative, the full date in its tip), then the body (its line breaks kept), the file chips
   (.ds-post-files) and a foot (.ds-post-foot: "Status set to ..."). .is-event is one muted line between posts (an
   icon, the actor in bold, what happened, a quoted reason, the time). .is-new rings a post that came since the reader
   last looked, after the "New since you last looked" separator (.ds-thread-sep); .is-pending is a post still on its
   way. The "1 new post" chip (.ds-thread-chip) follows the feed, sticky at the bottom of what the reader sees: above
   the pane's own foot (its scroll box), or, in page flow, above the dock and a pinned foot.
   ========================================================================================= */
.ds-thread { display: flex; flex-direction: column; gap: 12px; min-width: 0; }
.ds-post { position: relative; max-width: min(640px, 88%); align-self: flex-start; padding: 10px 14px 12px; border-radius: var(--radius-lg); border: 1px solid var(--clr-border); background: var(--clr-surface); color: var(--clr-text-heading); }
.ds-post.is-us { align-self: flex-end; background: var(--clr-primary-light); border-color: var(--clr-primary-line); }
.ds-post.is-note { align-self: flex-end; background: var(--clr-warning-soft); border-color: var(--clr-warning-line); }
.ds-post.is-new:not(.is-event) { box-shadow: 0 0 0 2px var(--clr-primary-line); }
.ds-post.is-pending { opacity: 0.72; }
.ds-post:focus { outline: none; }   /* focused from code (the chip): no ring; the keyboard's focus draws it */
.ds-post:focus-visible { outline: 2px solid var(--clr-focus-ring); outline-offset: 2px; }
.ds-post-head { display: flex; align-items: center; flex-wrap: wrap; gap: 4px 8px; margin-bottom: 4px; font-size: var(--fs-xs); color: var(--clr-text-muted); }
.ds-post-author { font-size: var(--fs-sm); font-weight: var(--fw-semibold); color: var(--clr-text-heading); overflow-wrap: anywhere; }
.ds-post-source { font-weight: var(--fw-semibold); }
.ds-post.is-note .ds-post-source { color: var(--clr-amber-ink); }
.ds-post-time { margin-left: auto; white-space: nowrap; }
.ds-post-body { font-size: var(--fs-md); line-height: var(--lh-base); white-space: pre-wrap; overflow-wrap: anywhere; }
.ds-post-body.is-rich { white-space: normal; }   /* a body the page built (rendered markdown, its own nodes) */
.ds-post-files { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; min-width: 0; }
.ds-post-foot { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; margin-top: 8px; font-size: var(--fs-xs); color: var(--clr-text-muted); }
.ds-post.is-event { align-self: stretch; max-width: none; display: flex; align-items: flex-start; gap: 8px; padding: 2px 4px; border: 0; border-radius: 0; background: none; font-size: var(--fs-sm); color: var(--clr-text-muted); }
.ds-post-ic { display: inline-flex; flex: none; margin-top: 2px; }
.ds-post-ic svg.ds-i { width: var(--icon-sm); height: var(--icon-sm); }
.ds-post-event { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
.ds-post-event b { color: var(--clr-text-body); font-weight: var(--fw-semibold); }
.ds-post-event .ds-post-files { margin-top: 6px; }
.ds-post-quote { display: block; margin-top: 2px; font-style: italic; quotes: "\201C" "\201D"; }
.ds-post.is-event .ds-post-time { flex: none; margin-left: 8px; font-size: var(--fs-xs); }
.ds-thread-sep { display: flex; align-items: center; gap: 10px; color: var(--clr-primary-ink); font-size: var(--fs-xs); font-weight: var(--fw-bold); letter-spacing: var(--tracking-caps); text-transform: uppercase; }
.ds-thread-sep::before, .ds-thread-sep::after { content: ""; flex: 1 1 auto; height: 1px; background: var(--clr-primary-line); }
.ds-thread-chip { position: sticky; bottom: calc(var(--portal-bottom-inset, 0px) + var(--ds-pane-foot-h, 0px) + 12px); z-index: 2; display: flex; align-items: center; gap: 6px; width: max-content; max-width: 100%; height: var(--ctl-h-sm); margin: 12px auto 0; padding: 0 14px; border: 1px solid var(--clr-primary-line); border-radius: var(--radius-pill); background: var(--clr-primary-fill); color: var(--clr-on-accent); font: inherit; font-size: var(--fs-sm); font-weight: var(--fw-bold); box-shadow: var(--shadow-md); cursor: pointer; }
.ds-thread-chip.is-floating { position: fixed; bottom: auto; margin: 0; }   /* the reader is above the feed: placed by the script */
.ds-thread-chip svg.ds-i { width: var(--icon-sm); height: var(--icon-sm); }
.ds-thread-chip:focus-visible { outline: 2px solid var(--clr-focus-ring); outline-offset: 2px; }

/* =========================================================================================
   MESSAGE BOX DOCK (Portal.ui.composer; components.md "Message box")
   The kit's message box (.ds-composer) with what writes to a record around it, in a pane's foot: .ds-composer-dock is
   a .ds-pane-foot (a <form>). Its bar (.ds-composer-bar) holds the mode (.ds-composer-mode: a small segmented control,
   or .ds-composer-modename when there is one mode), who reads it (.ds-composer-to: wraps, never cut; "[N others]" is
   a .ds-linkbtn whose popover, .ds-composer-others, lists them), "Draft kept" (.ds-composer-draft) and "Then"
   (.ds-composer-then: a label and a small select); then the files being attached (.ds-composer-files), the box
   (Attach, the text area, Send: .ds-composer-send) and the hint line (.ds-composer-hint: the error, the hint, and
   "Ctrl Enter sends" with a fine pointer). .is-note tints it for a note. At rest (nothing written, focus elsewhere)
   it is one row, the mode, the box and Send, with "Then" too where the record's column is 800 px or wider; writing
   (.is-writing: focus in the box, text or files) opens the bar above the box. Pinned (one pane): .is-pinned-window,
   sticky at the window's bottom where the shell draws no dock (above 900 px: a short window, a phone on its side),
   and .is-pinned-dock, sticky above the dock at 601 to 900 px; across the page gutters, on the surface with a rule
   and the dock's shadow over it. Portal.ui.split writes a pinned foot's height to --ds-pane-foot-h and sets
   .has-pinned-foot: everything else in the record pane then scrolls into view above the foot, the page keeps no end
   padding under it, and toasts and the thread's chip sit above it. The sheet form (.ds-composer-sheet, .is-note) is
   the composer in a phone's bottom sheet: the bar wraps, the box is at least 112 px tall with Attach at its foot,
   the hint takes the note tone, "Then" and Send sit in the sheet's foot (.ds-composer-sheet-foot), and the quote of
   what it answers (.ds-composer-quote, a compact disclosure) heads it.
   ========================================================================================= */
.ds-composer-dock { display: flex; flex-direction: column; gap: 6px; padding-top: 8px; }
:is(.ds-composer-dock, .ds-composer-hint, .ds-composer-then, .ds-composer-files, .ds-composer-keys, .ds-thread-chip)[hidden] { display: none; }
.ds-composer-bar { display: flex; align-items: center; gap: 6px 12px; min-width: 0; min-height: var(--ctl-h-sm); }
.ds-composer-mode { flex: none; }
.ds-composer-modename { display: inline-flex; align-items: center; gap: 6px; font-size: var(--fs-sm); font-weight: var(--fw-semibold); color: var(--clr-text-heading); white-space: nowrap; }
:is(.ds-composer-dock, .ds-composer-sheet).is-note .ds-composer-modename { color: var(--clr-amber-ink); }
.ds-composer-modename svg.ds-i { width: var(--icon-sm); height: var(--icon-sm); }
.ds-composer-to { flex: 1 1 auto; min-width: 0; font-size: var(--fs-xs); line-height: 1.45; color: var(--clr-text-muted); overflow-wrap: anywhere; }
.ds-composer-to b { color: var(--clr-text-body); font-weight: var(--fw-semibold); }
.ds-composer-to svg.ds-i { width: 14px; height: 14px; vertical-align: -2px; }
.ds-composer-to .ds-linkbtn { display: inline; padding: 0 2px; font-size: inherit; font-weight: var(--fw-semibold); vertical-align: baseline; white-space: normal; }
.ds-composer-dock.is-note .ds-composer-to, .ds-composer-sheet.is-note .ds-composer-to { color: var(--clr-amber-ink); font-weight: var(--fw-semibold); }
.ds-composer-draft { flex: none; font-size: var(--fs-xs); color: var(--clr-text-muted); white-space: nowrap; }
.ds-composer-then { flex: none; display: inline-flex; align-items: center; gap: 8px; min-width: 0; }
.ds-composer-then > .ds-label { margin: 0; font-size: var(--fs-label); font-weight: var(--fw-medium); color: var(--clr-text-muted); white-space: nowrap; }
.ds-composer-then > .ds-select { min-width: 176px; }
.ds-composer-files { display: flex; flex-wrap: wrap; gap: 6px; min-width: 0; }
.ds-composer-send { flex: none; }
.ds-composer-hint { display: flex; align-items: flex-start; justify-content: space-between; gap: 4px 12px; min-height: 16px; font-size: var(--fs-xs); line-height: var(--lh-snug); color: var(--clr-text-muted); }
.ds-composer-hint-text { min-width: 0; }
.ds-composer-hint-text:empty { display: none; }
.ds-composer-error { color: var(--clr-danger-tone-ink); font-weight: var(--fw-semibold); }
.ds-composer-dock.is-note .ds-composer-hint-text, .ds-composer-sheet.is-note .ds-composer-hint-text { color: var(--clr-amber-ink); font-weight: var(--fw-semibold); }
.ds-composer-keys { display: inline-flex; align-items: center; gap: 3px; margin-left: auto; white-space: nowrap; }
/* At rest: one row, the mode, the box and Send; the placeholder keeps to one line. */
.ds-composer-dock:not(.is-writing) { flex-direction: row; flex-wrap: wrap; align-items: center; column-gap: 10px; row-gap: 4px; }
.ds-composer-dock:not(.is-writing) > .ds-composer-bar { display: contents; }
.ds-composer-dock:not(.is-writing) .ds-composer-mode { order: 1; }
.ds-composer-dock:not(.is-writing) > .ds-composer { order: 2; flex: 1 1 0; min-width: 0; }
.ds-composer-dock:not(.is-writing) .ds-composer-then { order: 3; }
.ds-composer-dock:not(.is-writing) :is(.ds-composer-to, .ds-composer-draft, .ds-composer-then, .ds-composer-hint, .ds-composer-files) { display: none; }
.ds-composer-dock:not(.is-writing) .ds-composer-input { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
@container ds-split-detail (min-width: 800px) {
    .ds-composer-dock:not(.is-writing) .ds-composer-then:not([hidden]) { display: inline-flex; }
}
/* Writing in a column under 700 px: the bar wraps, the mode and "Then" on its first row and who reads it on its own
   row under them, so the line is never squeezed into a narrow column between them. */
@container ds-split-detail (max-width: 699px) {
    .ds-composer-dock.is-writing > .ds-composer-bar { flex-wrap: wrap; }
    .ds-composer-dock.is-writing .ds-composer-to { order: 5; flex: 1 1 100%; }
    .ds-composer-dock.is-writing .ds-composer-then { margin-left: auto; }
}
/* Pinned in one pane: everything else in the record pane scrolls into view above the foot (the root's scroll padding
   counts it: --ds-pinned-foot-h, written on the root by the split; a scroll box inside the pane keeps its own). The
   padding drops while focus is in the foot: the foot is always in view, and inside the padding a focus, a Tab or each
   key typed would scroll the page by the foot's height. The page keeps no end padding under it (the second selector
   outranks the shell's room for the Assistant button, 1-2-2); toasts sit 12 px above it (outside an app view, where the shell's own rule does not reach). */
html:has(.ds-split.is-one-pane.has-pinned-foot[data-pane="detail"]):not(:has(.ds-split.is-one-pane[data-pane="detail"] > .ds-split-detail > .ds-pane-foot:focus-within)) { scroll-padding-bottom: calc(var(--portal-bottom-inset, 0px) + var(--space-2) + var(--ds-pinned-foot-h, 0px)); }
body:has(.ds-split.is-one-pane.has-pinned-foot[data-pane="detail"]) main.app-main,
body:has(#helpdesk-widget .hd-fab):has(.ds-split.is-one-pane.has-pinned-foot[data-pane="detail"]) main.app-main { padding-bottom: 0; }
html:not(.portal-app-view) body:has(.ds-split.is-one-pane.has-pinned-foot[data-pane="detail"]) .ds-toasts { bottom: calc(var(--portal-float-clear, 0px) + var(--space-3)); }
/* The sheet form. */
.ds-composer-sheet { display: flex; flex-direction: column; gap: 10px; min-width: 0; }
.ds-composer-sheet .ds-composer-bar { flex-wrap: wrap; }
.ds-composer-sheet .ds-composer-to { flex: 1 1 100%; }
.ds-composer-sheet .ds-composer-input { min-height: 112px; }
.ds-composer-sheet .ds-composer-hint { display: block; }
.ds-composer-sheet .ds-composer-hint > * + * { margin-top: 4px; }
.ds-composer-sheet .ds-composer-hint-text { display: block; }
.ds-composer-sheet .ds-composer-hint-text:empty { display: none; }
.ds-composer-sheet-foot { display: flex; align-items: center; gap: 10px; min-width: 0; }
.ds-composer-sheet-foot > .ds-composer-then { flex: 1 1 auto; }
.ds-composer-sheet-foot > .ds-composer-then > .ds-select { flex: 1 1 auto; min-width: 0; }
.ds-composer-sheet-foot > .ds-composer-send { margin-left: auto; }
/* A phone on its side: the recipient line beside the switch, a box that fits. With the keyboard up (300 px tall or
   less) the box and the foot are all that fits: the sheet's head, the quote and the bar come back with the height. */
@media (max-height: 500px) {
    .ds-composer-sheet { gap: 6px; }
    .ds-composer-sheet .ds-composer-to { flex: 1 1 0; }
    .ds-composer-sheet .ds-composer-input { min-height: 0; max-height: 72px; }
}
@media (max-height: 300px) {
    .ds-sheet:has(> .ds-sheet-body > .ds-composer-sheet) > :is(.ds-sheet-grab, .ds-sheet-head),
    .ds-composer-sheet > :is(.ds-composer-quote, .ds-composer-bar) { display: none; }
    .ds-sheet:has(> .ds-sheet-body > .ds-composer-sheet) > .ds-sheet-body { padding-top: 8px; padding-bottom: 8px; }
    .ds-composer-sheet .ds-composer-input { max-height: calc(100dvh - 104px); }
}
/* The quote of what it answers (composer {quote}): a compact disclosure, its label on one line and the text cut beside
   it; opened, the whole text in its body. */
.ds-composer-quote > .ds-disclosure-btn { min-width: 0; }
.ds-composer-quote-label { flex: none; white-space: nowrap; }
.ds-composer-quote-text { flex: 1 1 auto; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font-weight: var(--fw-normal); color: var(--clr-text-muted); }
.ds-composer-quote[open] .ds-composer-quote-text { display: none; }
.ds-composer-quote .ds-disclosure-body > p { margin: 0; white-space: pre-wrap; overflow-wrap: anywhere; }
/* "[N others]": its popover (a sheet on phones, whose title names it) lists each name with its record's ID. */
.ds-composer-others { min-width: 220px; padding: 12px 14px; font-size: var(--fs-sm); color: var(--clr-text-body); }
.ds-composer-others-title { margin: 0 0 6px; font-weight: var(--fw-bold); color: var(--clr-text-heading); }
.ds-sheet .ds-composer-others { min-width: 0; padding: 0; }
.ds-sheet .ds-composer-others-title { display: none; }
.ds-composer-others ul { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 4px; }
.ds-composer-others li { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; min-width: 0; overflow-wrap: anywhere; }
.ds-composer-others-id { flex: none; font-size: var(--fs-xs); color: var(--clr-text-muted); font-variant-numeric: tabular-nums; white-space: nowrap; }

/* One pane, the pinned foot: where the shell draws no dock (above 900 px), at the window's bottom; at 601 to 900 px
   above the dock. Across the page gutters, as the record bar is. */
@media (min-width: 901px) {
    .ds-split.is-one-pane[data-pane="detail"] > .ds-split-detail > .ds-pane-foot.is-pinned-window { position: sticky; bottom: 0; z-index: 5; margin: 8px calc(-1 * var(--page-gutter)) 0; padding: 8px var(--page-gutter) calc(10px + env(safe-area-inset-bottom, 0px)); border-top: 1px solid var(--clr-border); background: var(--clr-surface); box-shadow: var(--shadow-dock); }
}
@media (min-width: 601px) and (max-width: 900px) {
    .ds-split.is-one-pane[data-pane="detail"] > .ds-split-detail > .ds-pane-foot.is-pinned-dock { position: sticky; bottom: var(--portal-bottom-inset, 0px); z-index: 5; margin: 8px calc(-1 * var(--page-gutter)) 0; padding: 8px var(--page-gutter) 10px; border-top: 1px solid var(--clr-border); background: var(--clr-surface); box-shadow: var(--shadow-dock); }
}
@media (max-width: 600px) {
    .ds-post { max-width: 94%; }
}
@media (pointer: coarse) {
    .ds-thread-chip { height: var(--ctl-h-touch); }
}

/* =========================================================================================
   Automation kit additions (2026-10): day picker, number unit in formFields, showIf, tokenText, menu groups and
   reasons, the disclosure's head form, clamp, the button app card, drawer and sheet titles that take focus.
   ========================================================================================= */
/* formFields: a field hidden by showIf; a number with its unit (.ds-numin.is-field) reads like the form's other fields. */
.ds-form > [hidden] { display: none; }
.ds-numin.is-field { cursor: text; transition: border-color var(--transition-speed), box-shadow var(--transition-speed); }
@media (hover: hover) { .ds-numin.is-field:hover { border-color: var(--clr-border-hover); } }
.ds-numin.is-field > .ds-numin-input { font-weight: var(--fw-regular); line-height: var(--lh-snug); }
.ds-numin.is-field:has(> .ds-numin-input[aria-invalid="true"]) { border-color: var(--clr-danger); }
.ds-numin.is-field:has(> .ds-numin-input:disabled) { background: var(--clr-surface-muted); cursor: not-allowed; }
.ds-numin.is-field > .ds-numin-input:disabled { color: var(--clr-text-muted); }
/* Day picker (Portal.ui.dayPicker, formFields type "days"): one joined track of seven two-letter toggles, presets as text
   buttons beside it (under it when it is narrow). Each toggle's 2 px transparent border keeps a gap between the drawn
   tiles inside a target that fills its column: 36 x 34 here, 44 x 44 on touch screens (a 310 px track: it fits a
   phone dialog's 320 px body; in a narrower box the toggles narrow with it). */
.ds-daypick { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-2); min-width: 0; }
.ds-daypick-track { display: inline-grid; grid-template-columns: repeat(7, minmax(0, 36px)); max-width: 100%; border: 1px solid var(--clr-border); border-radius: var(--radius-md); background: var(--clr-seg-track); }
.ds-daypick-day { min-width: 0; height: 34px; padding: 0; border: 2px solid transparent; border-radius: var(--radius-md); background: transparent; background-clip: padding-box; font: inherit; font-size: var(--fs-sm); font-weight: var(--fw-semibold); color: var(--clr-text-body); cursor: pointer; }
@media (hover: hover) { .ds-daypick-day:hover:not(:disabled):not([aria-pressed="true"]) { background-color: var(--clr-seg-on); color: var(--clr-text-heading); } }
.ds-daypick-day[aria-pressed="true"] { background-color: var(--clr-primary-light); color: var(--clr-primary-ink); box-shadow: inset 0 0 0 1px var(--clr-primary); }
.ds-daypick-day:focus-visible { outline: 2px solid var(--clr-focus-ring); outline-offset: -2px; }
.ds-daypick-day:disabled, .ds-daypick-preset:disabled { cursor: not-allowed; }
.ds-daypick.is-disabled .ds-daypick-track { opacity: 0.6; }
.ds-daypick-presets { display: flex; flex-wrap: wrap; gap: 0 var(--space-1); }
.ds-daypick[aria-invalid="true"] .ds-daypick-track { border-color: var(--clr-danger); }
/* tokenText: "Insert a value" and the example line under the textarea. */
.ds-tokentext { display: flex; flex-direction: column; align-items: flex-start; gap: var(--space-0-5); min-width: 0; }
.ds-tokentext-insert { margin-left: -6px; }
.ds-tokentext-insert svg.ds-i { width: var(--icon-sm); height: var(--icon-sm); }
.ds-tokentext-example { margin: 0; max-width: 100%; font-size: var(--fs-label); line-height: var(--lh-snug); color: var(--clr-text-muted); white-space: pre-wrap; overflow-wrap: anywhere; display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden; }
.ds-tokentext-example[hidden] { display: none; }
.ds-tokentext-label { font-weight: var(--fw-semibold); color: var(--clr-text-body); }
.ds-tokentext-val { color: var(--clr-text-heading); }
.ds-tokentext-bad { -webkit-box-decoration-break: clone; box-decoration-break: clone; padding: 0 2px; border-radius: var(--radius-xs); background: var(--clr-danger-soft); color: var(--clr-danger-text); font-weight: var(--fw-semibold); text-decoration: underline wavy; text-underline-offset: 3px; }
/* Menu groups ({heading} items) and items unavailable for a reason ({disabled, reason}). */
.ds-menu-section { display: flex; flex-direction: column; }
.ds-menu-section + .ds-menu-section, .ds-menu-item + .ds-menu-section { margin-top: var(--space-1); padding-top: var(--space-1); border-top: 1px solid var(--clr-border); }
.ds-menu-group { padding: 8px 10px 4px; font-size: var(--fs-xs); font-weight: var(--fw-bold); letter-spacing: 0.07em; text-transform: uppercase; color: var(--clr-text-muted); }
.ds-menu-item[aria-disabled="true"]:focus-visible { background: var(--clr-row-hover); }
/* Disclosure, head form (Portal.ui.disclosure({title, sub, lead, actions})): the toggle and, beside it, actions that
   don't toggle; one hover band over both. */
.ds-disclosure-head { display: flex; align-items: center; min-width: 0; }
.ds-disclosure-head > .ds-disclosure-btn { flex: 1 1 auto; min-width: 0; }
.ds-disclosure-head > .ds-disclosure-btn:focus-visible { outline-offset: -2px; }
@media (hover: hover) {
    .ds-disclosure-head:has(> .ds-disclosure-btn:hover) { background: var(--clr-row-hover); }
    .ds-disclosure-head > .ds-disclosure-btn:hover { background: none; }
}
.ds-disclosure-actions { display: flex; align-items: center; gap: var(--space-1); flex: none; padding-right: var(--space-2); }
.ds-disclosure-lead { display: inline-flex; align-items: center; gap: var(--space-2); flex: none; }
.ds-disclosure-num { display: grid; place-items: center; min-width: 24px; height: 24px; padding: 0 6px; border-radius: var(--radius-pill); background: var(--clr-primary-light); color: var(--clr-primary-ink); font-size: var(--fs-xs); font-weight: var(--fw-bold); font-variant-numeric: tabular-nums; }
.ds-disclosure-ic { display: inline-grid; place-items: center; color: var(--clr-text-muted); }
.ds-disclosure-ic svg.ds-i { width: var(--icon-md); height: var(--icon-md); }
.ds-disclosure-text { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1 1 auto; }
.ds-disclosure-title { overflow-wrap: anywhere; }
/* With a badge (disclosure({badge})): the title, then the badge, which goes under the title when the row is short, so
   the title always keeps the row's width. */
.ds-disclosure-top { display: flex; flex-wrap: wrap; align-items: center; gap: 2px var(--space-2); min-width: 0; }
.ds-disclosure-top > .ds-disclosure-title { min-width: 0; }
.ds-disclosure-top > .ds-badge { flex: none; }
.ds-disclosure-sub { font-size: var(--fs-sm); font-weight: var(--fw-regular); color: var(--clr-text-muted); line-height: var(--lh-snug); overflow-wrap: anywhere; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.ds-disclosure-sub[hidden] { display: none; }
.ds-disclosure.has-head > .ds-disclosure-body { padding: var(--space-1) var(--space-4) var(--space-4); }
/* Clamp (Portal.ui.clamp): about 12 lines with a fade, then "Show all" opens it in place; no scrollbar of its own. */
.ds-clamp { min-width: 0; }
.ds-clamp-body { max-height: calc(var(--ds-clamp-lines, 12) * 1.5em); max-height: calc(var(--ds-clamp-lines, 12) * 1lh); overflow: hidden; }
.ds-clamp.is-clamped:not(.is-open) > .ds-clamp-body { -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 3em), transparent); mask-image: linear-gradient(to bottom, #000 calc(100% - 3em), transparent); }
.ds-clamp.is-open > .ds-clamp-body { max-height: none; }
.ds-clamp-btn { margin: var(--space-1) 0 0 -6px; }
.ds-clamp-btn[hidden] { display: none; }
/* App card as a button (a template to use, a tile to pick) and its disabled form (aria-disabled + .is-disabled: muted,
   no lift, a reason badge in .ds-app-meta). */
button.ds-app-card { width: 100%; font: inherit; text-align: left; cursor: pointer; }
/* In a list (role="list"), each button card sits in a list item of its own (.ds-app-item, role="listitem"): the button
   keeps its role and its name, and fills the item (a grid cell's full height). */
.ds-app-item { display: grid; min-width: 0; }
.ds-app-card:is(.is-disabled, [aria-disabled="true"]) { background: var(--clr-surface-muted); box-shadow: none; cursor: not-allowed; }
@media (hover: hover) {
    .ds-app-card:is(.is-disabled, [aria-disabled="true"]):hover { border-color: var(--clr-border); box-shadow: none; transform: none; }
    .ds-app-card:is(.is-disabled, [aria-disabled="true"]):hover .ds-app-t { color: var(--clr-text-body); }
}
.ds-app-card:is(.is-disabled, [aria-disabled="true"]) .ds-app-ic { background: var(--clr-surface); color: var(--clr-text-muted); box-shadow: inset 0 0 0 1px var(--clr-border); }
.ds-app-card:is(.is-disabled, [aria-disabled="true"]) .ds-app-t { color: var(--clr-text-body); }
/* A drawer's or sheet's title focused by setContent() (a record switched in place): no ring on a heading. */
:is(.ds-drawer-title, .ds-sheet-title).is-switched:focus { outline: none; }
@media (pointer: coarse) {
    .ds-daypick-track { grid-template-columns: repeat(7, minmax(0, var(--ctl-h-touch))); }
    .ds-daypick-day { height: var(--ctl-h-touch); font-size: var(--fs-md); }
}
