/* /Components/Layout/MainLayout.razor.rz.scp.css */
/* The shell is shell.css. The only thing the handoff has no slot for is the
   antiforgery-protected sign-out POST: its top bar signs out with a plain
   button, ours needs a form wrapper, and a bare <form> would introduce a block
   box into the .app__top-cluster flex row. */

.signout-form[b-xcxj5zj9ni] {
    margin: 0;
    display: inline-flex;
}

/* shell.css's .app__brand is a flex row over .brand__mark / .brand__name, but
   the mark and name have to be one link and .brand__toggle a sibling button —
   a <button> cannot live inside an <a>. .brand__link re-forms the row the
   handoff's rule expects. */
.brand__link[b-xcxj5zj9ni] {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    min-width: 0;
    color: inherit;
    text-decoration: none;
}

/* shell.css owns .brand__toggle's layout and, crucially, its `display` — that
   is what hides it above the drawer breakpoint. So this styles appearance only
   and never sets display; borrowing .nav-link-btn for the look instead would
   re-introduce the bug it was written to fix. */
.brand__toggle[b-xcxj5zj9ni] {
    width: 26px;
    height: 26px;
    place-items: center;
    padding: 0;
    background: none;
    border: 0;
    border-radius: var(--r-control);
    color: var(--ink-3);
    cursor: pointer;
    transition: background var(--transition-fast), color var(--transition-fast);
}

.brand__toggle:hover[b-xcxj5zj9ni] {
    background: var(--surface-sunken);
    color: var(--ink);
}

.brand__toggle:focus-visible[b-xcxj5zj9ni] {
    outline: var(--focus-ring);
    outline-offset: var(--focus-offset);
}

/* The drawer's OPEN control. shell.css ships .brand__toggle for the close side,
   but below 700px .app__brand is hidden until the drawer is already open, so
   there is nothing to open it with. Same breakpoint, same container. */
.app__top-menu[b-xcxj5zj9ni] {
    display: none;
}

@container (max-width: 700px) {
    .app__top-menu[b-xcxj5zj9ni] {
        display: inline-flex;
    }
}

/* Once the drawer is open its own .brand__toggle is the close control, and the
   absolutely-positioned brand row overlaps the top bar — leaving the opener
   underneath it shows half a second button poking out. */
.app.is-drawer-open .app__top-menu[b-xcxj5zj9ni] {
    display: none;
}

/* The site banner's row. Without this the shell keeps height: 100% of the
   frame and the banner pushes the bottom of the page out of view. */
.app-frame[b-xcxj5zj9ni] {
    display: flex;
    flex-direction: column;
    height: 100%;
    min-height: 0;
}

.app-frame > .shell-root[b-xcxj5zj9ni] {
    flex: 1 1 auto;
    min-height: 0;
}

/* The brand carries the organisation as a second line. shell.css's .app__brand
   is a flex row of mark + name, so the two text lines need a column between
   them; .brand__name keeps its own rule untouched, including the display: none
   that hides it at rail width. 64px of --top-h holds 16px + 12px comfortably. */
.brand__text[b-xcxj5zj9ni] {
    display: flex;
    flex-direction: column;
    justify-content: center;
    min-width: 0;
    line-height: 1.25;
}

.brand__org[b-xcxj5zj9ni] {
    font-size: var(--text-xs);
    color: var(--ink-3);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Rail width: shell.css hides .brand__name and centres the mark on its own, so
   the subtitle has to go with it or the rail grows a stray caption. Same
   container and breakpoint as that rule. */
@container (max-width: 1080px) {
    .brand__org[b-xcxj5zj9ni] {
        display: none;
    }
}

/* ---------- The command palette's visible way in (#888) ----------
   shell.css has no slot for it: the handoff's top bar is a menu button and a
   user cluster. It goes here rather than in command-palette.css because this
   button is the one part of the palette that Razor renders in place - the
   overlay's rows are script clones, which is why THAT sheet has to be global.

   It is drawn as the search field it stands in for. A button that looks like a
   button says "something happens"; a button that looks like a search box says
   "type here", which is the whole message. */

.cmdp-open[b-xcxj5zj9ni] {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    width: min(320px, 100%);
    height: var(--control-h);
    min-width: 0;
    padding: 0 var(--space-2);
    background: var(--input-bg);
    border: 1px solid var(--input-border);
    border-radius: var(--r-control);
    color: var(--ink-3);
    font-family: var(--font-sans);
    font-size: var(--text-base);
    text-align: left;
    cursor: pointer;
    transition: background var(--transition-fast), border-color var(--transition-fast);
}

.cmdp-open:hover[b-xcxj5zj9ni] {
    background: var(--surface-sunken);
    border-color: var(--input-border-hover);
}

.cmdp-open:focus-visible[b-xcxj5zj9ni] {
    outline: var(--focus-ring);
    outline-offset: var(--focus-offset);
}

.cmdp-open__icon[b-xcxj5zj9ni] {
    display: flex;
    flex: none;
    color: var(--ink-4);
}

.cmdp-open__label[b-xcxj5zj9ni] {
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

/* Pushed to the far edge, where the keyboard hint sits in every other search
   box this audience uses. */
.cmdp-open__keys[b-xcxj5zj9ni] {
    display: inline-flex;
    flex: none;
    gap: 2px;
    margin-left: auto;
}

/* Rail width is the first place the top bar runs out of room, and it is also
   roughly where a tablet lands - no keyboard, so nothing to hint at. */
@container (max-width: 1080px) {
    .cmdp-open[b-xcxj5zj9ni] {
        width: auto;
    }

    .cmdp-open__keys[b-xcxj5zj9ni] {
        display: none;
    }
}

/* Phone: the magnifier alone, and it is now the ONLY way into the palette -
   there is no Ctrl+K to press. The label is CLIPPED rather than removed, so it
   stays in the accessibility tree and the button keeps the name "Search or
   jump to..., Ctrl K" instead of falling back to the bare shortcut. */
@container (max-width: 700px) {
    .cmdp-open[b-xcxj5zj9ni] {
        gap: 0;
        width: var(--control-h);
        padding: 0;
        justify-content: center;
        background: none;
        border-color: transparent;
    }

    .cmdp-open:hover[b-xcxj5zj9ni] {
        background: var(--surface-sunken);
        border-color: transparent;
    }

    .cmdp-open__label[b-xcxj5zj9ni] {
        position: absolute;
        width: 1px;
        height: 1px;
        padding: 0;
        margin: -1px;
        overflow: hidden;
        clip-path: inset(50%);
        white-space: nowrap;
        border: 0;
    }
}

/* ...and come back with it when the drawer is open. A 700px-wide container
   matches the rule above too, so this has to out-specify it, the way
   shell.css's own `display: revert` rules do for .brand__name. */
@container (max-width: 700px) {
    .app.is-drawer-open .brand__org[b-xcxj5zj9ni] {
        display: revert;
    }
}
/* /Components/Layout/NavMenu.razor.rz.scp.css */
/* Release stamp under the copyright line (issue #604). It sits inside
   .nav-copy, so it inherits that block's micro size and muted colour - and
   its display:none in the collapsed rail - and only needs the second-line
   break plus a hover affordance. Deliberately quiet: the version is
   reference information, not navigation, so it gains colour and an underline
   only on hover/focus. The release date rides on the link's title. */
.nav-version[b-i5tanpdiqz] {
    display: block;
    margin-top: 2px;
    color: inherit;
    text-decoration: none;
    transition: color var(--transition-fast);
}

.nav-version:hover[b-i5tanpdiqz],
.nav-version:focus-visible[b-i5tanpdiqz] {
    color: var(--ink-2);
    text-decoration: underline;
}

/* ---------- Arrange mode (issue #956) ----------
   wwwroot/nav-arrange.js puts .is-arranging on the <nav class="app__nav">
   MainLayout owns, and copies .nav-arrange onto every group and every row.
   No sheet exists for this yet - see divergence 74 in
   .design/design-migration.md - so it is built from the sidebar's own parts:
   the controls are sized like .nav-link-btn and coloured like the group heads. */

/* A bare wrapper with no box of its own, so the grid gap and the active
   keyline still belong to the .nav-item inside it. */
.nav-row[b-i5tanpdiqz] { display: block; }

/* Where the script copies the row controls from; never shown itself. */
.nav-arrange-source[b-i5tanpdiqz] { display: none; }
.nav-arrange-toggle[b-i5tanpdiqz] { margin-left: auto; }
.nav-arrange-bar[b-i5tanpdiqz] { display: none; gap: var(--space-2); }
.nav-arrange-status[b-i5tanpdiqz] { display: flex; align-items: center; gap: var(--space-2); min-height: var(--control-h-sm); font-size: var(--text-2xs); color: var(--ink-3); }
.nav-arrange-actions[b-i5tanpdiqz] { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); }
.app__nav.is-arranging .nav-links[b-i5tanpdiqz] { display: none; }
.app__nav.is-arranging .nav-arrange-bar[b-i5tanpdiqz] { display: grid; }

/* Everything is laid out flat while arranging: every group open, links and
   group heads inert so a stray click cannot navigate away or fold a group
   mid-arrange. Sub-pages stay in view, dimmed and without controls of their
   own, so moving Solutions visibly carries Environments with it - someone
   who came to move a sub-page sees where it went. */
.app__nav.is-arranging .nav-group.is-collapsed > .nav-group__items[b-i5tanpdiqz] { display: grid; }
.app__nav.is-arranging .nav-sub[b-i5tanpdiqz] { opacity: .55; }
.app__nav.is-arranging .nav-group[data-group][b-i5tanpdiqz],
.app__nav.is-arranging .nav-row[b-i5tanpdiqz] { cursor: grab; }
.app__nav.is-arranging .app__nav-scroll[b-i5tanpdiqz]  a,
.app__nav.is-arranging .nav-group[b-i5tanpdiqz]  .nav-group__head { pointer-events: none; }
.app__nav.is-arranging .nav-group[b-i5tanpdiqz]  .nav-group__caret { visibility: hidden; }

/* Room on the right of each row for the controls laid over it. */
.app__nav.is-arranging .nav-row[b-i5tanpdiqz] { position: relative; }
.app__nav.is-arranging .nav-row[b-i5tanpdiqz]  .nav-item,
.app__nav.is-arranging .nav-group[b-i5tanpdiqz]  .nav-group__head { padding-right: 80px; }

.nav-arrange[b-i5tanpdiqz] {
    position: absolute; top: 0; right: 0; height: 34px;
    display: flex; align-items: center; gap: 2px; padding-right: var(--space-1);
}
/* A group's controls share the head's grid cell rather than being positioned
   from the group's top edge, which carries the rule and padding between groups. */
.app__nav.is-arranging .nav-group[b-i5tanpdiqz]  .nav-group__head { grid-area: 1 / 1; }
.nav-group > .nav-arrange[b-i5tanpdiqz] { position: static; grid-area: 1 / 1; justify-self: end; height: 26px; }
.nav-arrange__grip[b-i5tanpdiqz] {
    width: 20px; height: 24px; display: grid; place-items: center;
    color: var(--ink-4); cursor: grab;
}
.nav-arrange__btn[b-i5tanpdiqz] {
    width: 24px; height: 24px; display: grid; place-items: center;
    background: none; border: 0; border-radius: var(--r-control);
    color: var(--ink-3); cursor: pointer;
    transition: background var(--transition-fast), color var(--transition-fast);
}
.nav-arrange__btn:hover[b-i5tanpdiqz] { background: var(--surface-sunken); color: var(--primary-ink); }
.nav-arrange__btn:focus-visible[b-i5tanpdiqz] { outline: var(--focus-ring); outline-offset: -2px; }
.nav-arrange__btn[disabled][b-i5tanpdiqz] { color: var(--ink-4); opacity: .5; background: none; cursor: default; }
.is-dragging[b-i5tanpdiqz] { opacity: .5; }

/* Dragging is unreliable under a finger, so a touch screen gets the Move up
   and Move down buttons alone, at a size a thumb can hit, rather than a grip
   that half works. */
@media (pointer: coarse) {
    .nav-arrange__grip[b-i5tanpdiqz] { display: none; }
    .nav-arrange__btn[b-i5tanpdiqz] { width: 32px; height: 32px; }
}

/* The icon rail has no labels to arrange by. The phone drawer does, so it
   gets the controls back while it is open. */
@container (max-width: 1080px) {
    .nav-arrange-toggle[b-i5tanpdiqz], .app__nav.is-arranging .nav-arrange-bar[b-i5tanpdiqz], .nav-arrange[b-i5tanpdiqz] { display: none; }
}
@container (max-width: 700px) {
    .app.is-drawer-open .nav-arrange-toggle[b-i5tanpdiqz] { display: inline-flex; }
    .app.is-drawer-open .app__nav.is-arranging .nav-arrange-bar[b-i5tanpdiqz] { display: grid; }
    .app.is-drawer-open .nav-arrange[b-i5tanpdiqz] { display: flex; }
}
/* /Components/Layout/NotificationBell.razor.rz.scp.css */
.notif-bell[b-gs4gog18t0] {
    position: relative;
}

/* The unread count, pinned to the bell's top right like a mail badge. */
.notif-bell__count[b-gs4gog18t0] {
    position: absolute;
    top: 1px;
    right: -2px;
    min-width: 16px;
    height: 16px;
    padding: 0 4px;
    border-radius: var(--r-pill);
    background: var(--primary);
    color: var(--on-primary);
    font-size: var(--text-2xs);
    font-weight: var(--fw-semibold);
    line-height: 16px;
    text-align: center;
    pointer-events: none;
}

/* The flyout the bell opens: a native popover, so it sits in the top layer
   above the page and the drawer. It hangs under the top bar at its right edge,
   where the bell is, rather than anchored to the bell itself, which not every
   browser can do yet; on a phone it spans the width less the gutters. */
.notif-flyout[b-gs4gog18t0] {
    position: fixed;
    inset: auto;
    top: calc(var(--top-h) - var(--space-2));
    right: var(--space-4);
    width: min(400px, calc(100vw - 2 * var(--space-4)));
    max-height: min(560px, calc(100vh - var(--top-h) - var(--space-5)));
    margin: 0;
    padding: 0;
    flex-direction: column;
    background: var(--surface);
    color: var(--ink-2);
    border: 1px solid var(--border-strong);
    border-radius: var(--r);
    box-shadow: var(--shadow-lg);
    overflow: hidden;
}

.notif-flyout:popover-open[b-gs4gog18t0] { display: flex; }

.notif-flyout__head[b-gs4gog18t0] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    border-bottom: 1px solid var(--border);
}

.notif-flyout__title[b-gs4gog18t0] {
    margin: 0;
    font-size: var(--text-md);
    font-weight: var(--fw-semibold);
    color: var(--ink);
}

.notif-flyout__head form[b-gs4gog18t0] { margin: 0; }

/* Where the script says how "Mark all as read" went; empty until then. */
.notif-flyout__status[b-gs4gog18t0] {
    flex: 1;
    text-align: right;
    color: var(--ink-3);
    font-size: var(--text-sm);
}

.notif-flyout__status:empty[b-gs4gog18t0] { display: none; }

.notif-flyout__title:focus[b-gs4gog18t0] { outline: none; }

/* A quiet text button: the flyout is a glance, not a page with actions. */
.notif-flyout__action[b-gs4gog18t0] {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    padding: 2px var(--space-1);
    background: none;
    border: 0;
    border-radius: var(--r-control);
    color: var(--primary-ink);
    font: inherit;
    font-size: var(--text-sm);
    cursor: pointer;
}

.notif-flyout__action:hover[b-gs4gog18t0] { background: var(--surface-sunken); }
.notif-flyout__action:focus-visible[b-gs4gog18t0] { outline: var(--focus-ring); outline-offset: var(--focus-offset); }

/* Only the list scrolls; the heading and the links stay put. */
.notif-flyout__body[b-gs4gog18t0] {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
}

.notif-flyout__note[b-gs4gog18t0] {
    margin: 0;
    padding: var(--space-4);
    color: var(--ink-3);
    font-size: var(--text-sm);
}

.notif-flyout__foot[b-gs4gog18t0] {
    display: flex;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    border-top: 1px solid var(--border);
    font-size: var(--text-sm);
}

.notif-flyout__foot a[b-gs4gog18t0] { color: var(--primary-ink); text-decoration: none; }
.notif-flyout__foot a:hover[b-gs4gog18t0] { text-decoration: underline; }

/* The bell reads as pressed while its flyout is open. */
.notif-bell:has(+ .notif-flyout:popover-open)[b-gs4gog18t0] {
    background: var(--surface-sunken);
    color: var(--primary-ink);
}

/* On a touch screen the flyout's text actions need a finger-sized target. */
@media (pointer: coarse) {
    .notif-flyout__action[b-gs4gog18t0],
    .notif-flyout__foot a[b-gs4gog18t0] {
        display: inline-flex;
        align-items: center;
        min-height: 40px;
    }
    .notif-flyout__foot[b-gs4gog18t0] { padding-block: var(--space-1); }
}
/* /Components/Layout/ReconnectModal.razor.rz.scp.css */
.components-reconnect-first-attempt-visible[b-yysgq5od1p],
.components-reconnect-repeated-attempt-visible[b-yysgq5od1p],
.components-reconnect-failed-visible[b-yysgq5od1p],
.components-pause-visible[b-yysgq5od1p],
.components-resume-failed-visible[b-yysgq5od1p],
.components-rejoining-animation[b-yysgq5od1p] {
    display: none;
}

#components-reconnect-modal.components-reconnect-show .components-reconnect-first-attempt-visible[b-yysgq5od1p],
#components-reconnect-modal.components-reconnect-show .components-rejoining-animation[b-yysgq5od1p],
#components-reconnect-modal.components-reconnect-paused .components-pause-visible[b-yysgq5od1p],
#components-reconnect-modal.components-reconnect-resume-failed .components-resume-failed-visible[b-yysgq5od1p],
#components-reconnect-modal.components-reconnect-retrying[b-yysgq5od1p],
#components-reconnect-modal.components-reconnect-retrying .components-reconnect-repeated-attempt-visible[b-yysgq5od1p],
#components-reconnect-modal.components-reconnect-retrying .components-rejoining-animation[b-yysgq5od1p],
#components-reconnect-modal.components-reconnect-failed[b-yysgq5od1p],
#components-reconnect-modal.components-reconnect-failed .components-reconnect-failed-visible[b-yysgq5od1p] {
    display: block;
}


/* The design system's .reconnect__card, expressed on the ids Blazor's
   reconnect JS drives — those class names are not ours to rename. Square,
   surface-filled, with the warning keyline the handoff puts on top and a
   danger one once the rejoin has actually failed. */
#components-reconnect-modal[b-yysgq5od1p] {
    background-color: var(--surface);
    color: var(--ink);
    width: min(400px, 100%);
    margin: 20vh auto;
    padding: var(--space-5);
    border: 1px solid var(--border-strong);
    border-top: 3px solid var(--warning);
    border-radius: var(--r);
    box-shadow: var(--shadow-lg);
    opacity: 0;
    transition: display 0.5s allow-discrete, overlay 0.5s allow-discrete;
    animation: components-reconnect-modal-fadeOutOpacity-b-yysgq5od1p 0.5s both;
    &[open]

{
    animation: components-reconnect-modal-slideUp-b-yysgq5od1p 1.5s cubic-bezier(.05, .89, .25, 1.02) 0.3s, components-reconnect-modal-fadeInOpacity-b-yysgq5od1p 0.5s ease-in-out 0.3s;
    animation-fill-mode: both;
}

}

#components-reconnect-modal.components-reconnect-failed[b-yysgq5od1p] {
    border-top-color: var(--danger-strong);
}

#components-reconnect-modal[b-yysgq5od1p]::backdrop {
    background-color: color-mix(in oklab, var(--ink) 55%, transparent);
    backdrop-filter: blur(2px);
    animation: components-reconnect-modal-fadeInOpacity-b-yysgq5od1p 0.5s ease-in-out;
    opacity: 1;
}

@keyframes components-reconnect-modal-slideUp-b-yysgq5od1p {
    0% {
        transform: translateY(30px) scale(0.95);
    }

    100% {
        transform: translateY(0);
    }
}

@keyframes components-reconnect-modal-fadeInOpacity-b-yysgq5od1p {
    0% {
        opacity: 0;
    }

    100% {
        opacity: 1;
    }
}

@keyframes components-reconnect-modal-fadeOutOpacity-b-yysgq5od1p {
    0% {
        opacity: 1;
    }

    100% {
        opacity: 0;
    }
}

.components-reconnect-container[b-yysgq5od1p] {
    display: grid;
    justify-items: center;
    gap: var(--space-2);
    text-align: center;
}

#components-reconnect-modal p[b-yysgq5od1p] {
    margin: 0;
    max-width: 40ch;
    font-size: var(--text-sm);
    color: var(--ink-3);
    text-wrap: pretty;
}

#components-reconnect-modal .btn[b-yysgq5od1p] {
    margin-top: var(--space-2);
}


.components-rejoining-animation[b-yysgq5od1p] {
    position: relative;
    width: 64px;
    height: 64px;
}

    .components-rejoining-animation div[b-yysgq5od1p] {
        position: absolute;
        border: 3px solid var(--primary);
        opacity: 1;
        border-radius: 50%;
        animation: components-rejoining-animation-b-yysgq5od1p 1.5s cubic-bezier(0, 0.2, 0.8, 1) infinite;
    }

        .components-rejoining-animation div:nth-child(2)[b-yysgq5od1p] {
            animation-delay: -0.5s;
        }

@keyframes components-rejoining-animation-b-yysgq5od1p {
    0% {
        top: 32px;
        left: 32px;
        width: 0;
        height: 0;
        opacity: 0;
    }

    4.9% {
        top: 32px;
        left: 32px;
        width: 0;
        height: 0;
        opacity: 0;
    }

    5% {
        top: 32px;
        left: 32px;
        width: 0;
        height: 0;
        opacity: 1;
    }

    100% {
        top: 0px;
        left: 0px;
        width: 64px;
        height: 64px;
        opacity: 0;
    }
}
/* /Components/Pages/Admin/AdminCookbook.razor.rz.scp.css */
/* The keywords cell is the only free-form-width column in this table, and a
   17-file module recipe carries a dozen keywords. Left unbounded its max-content
   width drives the whole table past the viewport, which squeezes Title down to
   its min-content — one word per line — and pushes Last updated off the edge.

   Capping the chip row caps the cell's max-content contribution, so the table
   fits and the keywords wrap instead of the title. */
.ac-keywords[b-yakogylb39] {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1);
    max-width: 32ch;
}

/* .data-table sets a fixed row height for single-line cells; a wrapped chip row
   needs its own breathing room top and bottom. */
.data-table td:has(.ac-keywords)[b-yakogylb39] {
    padding-block: var(--space-2);
}

/* Recipe titles are sentences. Give the column enough room to break on words
   rather than characters once the keywords stop hogging the width. */
.data-table td:first-child[b-yakogylb39] {
    min-width: 18ch;
}
/* /Components/Pages/Admin/AdminCookbookSuggestionReview.razor.rz.scp.css */
/* A suggestion can carry any number of keywords; a row that never wraps
   widens the page and pushes the head's actions off screen. */
.suggestion-tags[b-vi02v029tq] { flex-wrap: wrap; min-width: 0; }

/* .page and .form-sec are grids with auto tracks, so a child's min-content
   width sets the track's floor: one unwrapped code line used to widen every
   card on the page (#1003 wrapped the tags, but at that widened width). A
   zero floor keeps the cards at the page's width and leaves the scrolling to
   whatever holds the long line. */
.card[b-vi02v029tq] { min-width: 0; }
.form-sec[b-vi02v029tq] { grid-template-columns: minmax(0, 1fr); }

.suggestion-reject-note[b-vi02v029tq] { width: 16rem; }

/* The description and instructions are what the reviewer is here to read, so
   body text at a wider measure than the 68ch caption style they used to
   borrow. The description is plain text typed into a textarea: keep its line
   breaks. */
.suggestion-text[b-vi02v029tq] { margin: 0; max-width: 100ch; font-size: var(--text-sm); color: var(--ink-2); line-height: var(--leading-normal); }
.suggestion-desc[b-vi02v029tq] { white-space: pre-line; text-wrap: pretty; }
.hint-details__intro.suggestion-text[b-vi02v029tq] { margin: var(--space-2) 0; }

/* The suggested instructions are rendered Markdown, so they can hold a fenced
   code block, a table or a long URL. Inside the bounded track above those
   would spill past the card; scroll them instead, and break long words. */
.hint-details[b-vi02v029tq] { min-width: 0; }
.hint-details[b-vi02v029tq]  .hint-details__intro { overflow-wrap: anywhere; }
.hint-details[b-vi02v029tq]  pre,
.hint-details[b-vi02v029tq]  table { display: block; max-width: 100%; overflow-x: auto; }
.suggestion-tags .tag[b-vi02v029tq] { max-width: 100%; overflow-wrap: anywhere; }

/* The facts line under the title: who and when, then the recipe's type,
   version floor and value, wrapping as a unit on a narrow window. */
.suggestion-meta[b-vi02v029tq] { display: inline-flex; flex-wrap: wrap; align-items: center; column-gap: var(--space-3); row-gap: var(--space-1); }

.suggestion-more[b-vi02v029tq] { height: auto; padding-block: 1px; font-size: var(--text-xs); }
.suggestion-tags__label[b-vi02v029tq] { font-size: var(--text-xs); color: var(--ink-3); }
/* /Components/Pages/Admin/Administration/AdminAdministrationBusinessCentral.razor.rz.scp.css */
/* The setup checklist beside the form. Moved here from the solution's Business
   Central tab with the registration it describes. */
.bc-setup[b-uecsmvkmeq] { display: grid; gap: var(--space-3); margin: 0; padding: 0 0 0 var(--space-4); font-size: var(--text-xs); color: var(--ink-3); }
.bc-setup li[b-uecsmvkmeq] { display: grid; gap: 2px; text-wrap: pretty; }
.bc-setup li[b-uecsmvkmeq]::marker { color: var(--ink-4); font-weight: var(--fw-semibold); }
.bc-setup__where[b-uecsmvkmeq] { font-weight: var(--fw-medium); color: var(--ink); overflow-wrap: anywhere; }
.bc-setup code[b-uecsmvkmeq] { font-family: var(--font-mono); font-size: var(--text-2xs); overflow-wrap: anywhere; }
.bc-setup__lead[b-uecsmvkmeq] { margin: 0; font-size: var(--text-xs); color: var(--ink-3); text-wrap: pretty; }
.bc-setup__note[b-uecsmvkmeq] { margin: 0; padding-top: var(--space-2); border-top: 1px solid var(--border); font-size: var(--text-2xs); color: var(--ink-4); text-wrap: pretty; }


/* The default delivery windows: the same From / To / clear line as the editor on
   the environment page. */
.bc-window[b-uecsmvkmeq] { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
.bc-window__time[b-uecsmvkmeq] { display: inline-flex; align-items: center; gap: var(--space-2); font-size: var(--text-sm); color: var(--ink-2); }
/* /Components/Pages/Admin/AdminReleasesImportArtifacts.razor.rz.scp.css */
/* The preview option belongs to "Import new releases automatically": indented
   under it so the dependency is visible, with its hint carrying the reason
   while the parent is off. */
.auto-previews[b-muwqrabj3y] {
    display: grid;
    gap: var(--space-1);
    margin-left: var(--space-6);
}
/* /Components/Pages/Admin/AdminTranslationMemory.razor.rz.scp.css */
/* Translation memory management page. Reuses .admin-page / .data-table from
   admin.css; these are the page-specific bits. */

.tr-mem-filters[b-184apg9c9s] { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 14px; }
.tr-mem-mini[b-184apg9c9s] {
    font-size: 11.9px; padding: 6px 9px; border: 1px solid var(--border);
    border-radius: var(--r); background: var(--surface); color: var(--ink);
}
.tr-mem-incl[b-184apg9c9s] { margin: 0; display: inline-flex; align-items: center; gap: 6px; font-size: 11.9px; }

.tr-mem-count[b-184apg9c9s] { font-size: 11.2px; margin-bottom: 8px; }

.tr-mem-table[b-184apg9c9s] { width: 100%; }
.tr-mem-num[b-184apg9c9s] { text-align: center; white-space: nowrap; }
.tr-mem-actions[b-184apg9c9s] { text-align: right; white-space: nowrap; }
.tr-mem-src[b-184apg9c9s] { font-weight: 500; }
.tr-mem-lang[b-184apg9c9s] {
    display: inline-block; margin-left: 8px; font-size: 9.24px; font-weight: 700; letter-spacing: 0.04em;
    color: var(--ink-4); background: var(--surface-2);
    border: 1px solid var(--border); padding: 1px 5px; border-radius: 4px; vertical-align: middle;
}
.tr-mem-kind[b-184apg9c9s] {
    font-size: 9.24px; text-transform: uppercase; letter-spacing: 0.04em; font-weight: 600;
    color: var(--ink-4); background: var(--surface-2);
    padding: 2px 6px; border-radius: 4px;
}
.tr-mem-removed[b-184apg9c9s] { opacity: 0.55; }
.tr-mem-removed .tr-mem-src[b-184apg9c9s] { text-decoration: line-through; }

.tr-mem-pager[b-184apg9c9s] { display: flex; align-items: center; gap: 12px; margin-top: 14px; justify-content: center; }

/* Vote controls (mirrors the Translator chip controls). */
.tr-vote[b-184apg9c9s] { display: inline-flex; align-items: center; gap: 4px; }
.tr-vbtn[b-184apg9c9s] {
    appearance: none; border: 1px solid var(--border); background: var(--surface);
    color: var(--ink-4); border-radius: 6px; padding: 3px; cursor: pointer;
    display: grid; place-items: center; line-height: 0;
}
.tr-vbtn:hover[b-184apg9c9s] { background: var(--surface-2); color: var(--ink); }
.tr-vbtn.on[b-184apg9c9s] { color: var(--primary-ink); border-color: var(--primary-ink); background: var(--primary-weak); }
.tr-vscore[b-184apg9c9s] { font-size: 10.08px; font-weight: 700; min-width: 16px; text-align: center; color: var(--ink-3); font-variant-numeric: tabular-nums; }
.tr-vscore.pos[b-184apg9c9s] { color: var(--success); }
.tr-vscore.neg[b-184apg9c9s] { color: var(--danger-text); }

/* The dismiss sits at the end of the banner, not in its flow of words. */
.tr-mem-refresh__dismiss[b-184apg9c9s] { margin-left: auto; }
.tr-mem-from[b-184apg9c9s] { max-width: 220px; }
.tr-mem-from a[b-184apg9c9s] { display: inline-flex; align-items: center; gap: 4px; color: var(--ink-3); text-decoration: none; }
.tr-mem-from a:hover[b-184apg9c9s] { color: var(--primary-ink); text-decoration: underline; }
.tr-mem-from span[b-184apg9c9s] { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tr-mem-from[b-184apg9c9s]  svg { flex: none; }
/* /Components/Pages/CookbookBrowser.razor.rz.scp.css */
/* Cookbook's take on the handoff's .browse-card.

   The handoff's card is a <div> whose title carries the link. Ours is the whole
   card, because a browse grid is scanned and clicked, not read — so the anchor
   needs the card's own text treatment back and hover has to reach the title.
   Everything else (fill, border, radius, hover keyline) comes from
   pages.css unchanged. */

.browse-card[b-ie16xuedi5] {
    color: inherit;
    text-decoration: none;
}

/* Same stack, expressed as flex rather than grid, so the foot can be pushed to
   the bottom: recipe descriptions and keyword rows vary in height, and with the
   handoff's `align-content: start` the "N files / View recipe" line floats at a
   different height in every card. Identical rendering when the cards match. */
.browse-card[b-ie16xuedi5] {
    display: flex;
    flex-direction: column;
}

.browse-card__foot[b-ie16xuedi5] {
    margin-top: auto;
}

.browse-card:hover .browse-card__title[b-ie16xuedi5] {
    color: var(--primary-ink);
}

.browse-card:focus-visible[b-ie16xuedi5] {
    outline: var(--focus-ring);
    outline-offset: var(--focus-offset);
}

/* Descriptions run to a paragraph; clamped so a long one doesn't leave a hole
   beside its neighbours. */
.browse-card__text[b-ie16xuedi5] {
    display: -webkit-box;
    -webkit-line-clamp: 3;
    line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.cb-card__files[b-ie16xuedi5],
.cb-card__go[b-ie16xuedi5] {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
}

.cb-card__go[b-ie16xuedi5] {
    font-weight: var(--fw-medium);
    transition: gap var(--transition-fast), color var(--transition-fast);
}

.browse-card:hover .cb-card__go[b-ie16xuedi5] {
    color: var(--primary-ink);
    gap: var(--space-2);
}

/* "+3 more" reads as a count, not another keyword. */
.cb-card__more[b-ie16xuedi5] {
    color: var(--ink-4);
}

/* The minimum-version subtitle. It sits under the title, above the
   description — it qualifies the recipe rather than describing it, and a BC
   release name is a sentence, so it gets normal prose treatment rather than the
   mono chip it used to be. */
.cb-card__req[b-ie16xuedi5] {
    font-size: var(--text-xs);
    color: var(--ink-4);
    text-wrap: pretty;
}

/* The type badge and, when present, the Deprecated pill. Both are 20px tall so
   they sit on one line; the title is what shrinks. */
.cb-card__badges[b-ie16xuedi5] {
    display: flex;
    align-items: center;
    gap: var(--space-1);
    flex: none;
    flex-wrap: wrap;
    justify-content: flex-end;
}

/* Keywords are author-written, so one long enough to escape the card is always
   possible. .tag already wraps, unlike the .code chip these used to be, so this
   is only the belt for a single unbroken word. */
.browse-card__tags .tag[b-ie16xuedi5] {
    max-width: 100%;
}
/* /Components/Pages/Docs/McpDocs.razor.rz.scp.css */
/* The client picker. Everything else on this page comes from the design layer;
   this is the one thing with no counterpart there - a label + select + submit
   on one line, sitting between two .prose articles. */

.mcp-client-pick[b-vuyv28ukog] {
    display: flex;
    align-items: flex-end;
    gap: var(--space-2);
    flex-wrap: wrap;
}

.mcp-client-pick .field[b-vuyv28ukog] {
    flex: 1 1 220px;
    max-width: 320px;
}
/* /Components/Pages/Docs/WhatsNextDocs.razor.rz.scp.css */
/* Every other page in the app ends with something to click; this one ended on a
   paragraph. Two outline buttons, no primary - the primary on this journey was
   Generate and it has already happened. */
.wn-acts[b-b28kz7n118] {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
}
/* /Components/Pages/Environments/EnvironmentDetail.razor.rz.scp.css */
/* What PageEnvironmentDetail.dc.html sets inline, named so the page does not. */

/* A count badge beside a card title. */
.env-detail__counted[b-b2mkqx0xkp] {
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

.env-detail__filter[b-b2mkqx0xkp] {
    width: 220px;
}

.env-detail__mono[b-b2mkqx0xkp] {
    font-family: var(--font-mono);
}

.env-detail__tags[b-b2mkqx0xkp] {
    flex-wrap: wrap;
    gap: var(--space-1);
}

/* The foot is a right-aligned row; the count keeps to the left of its button. */
.env-detail__count[b-b2mkqx0xkp] {
    margin-right: auto;
}


/* Rendered by FieldError, so it carries no page scope of its own. */
[b-b2mkqx0xkp] .env-detail__later {
    margin: var(--space-3) 0 0;
    font-size: var(--text-sm);
}


/* A setting somebody may read but not change. It sits where the control would be,
   so it has to read as a stated value rather than as an input that failed to draw:
   the label's own weight and ink, not body text. */
.env-detail__value[b-b2mkqx0xkp] {
    font-size: var(--text-base);
    font-weight: var(--fw-medium);
    color: var(--ink);
}


/* The UTC equivalent of a local scheduled time, as a second line under it. */
.env-detail__utc[b-b2mkqx0xkp] {
    display: block;
    font-size: var(--text-sm);
}

/* The apps that move with the one being updated. Capped and scrollable: an app
   can wait for a dozen others, and the question below must stay on screen. */
.env-detail__alongside[b-b2mkqx0xkp] {
    margin: var(--space-3) 0 0;
    display: grid;
    gap: var(--space-2);
}

.env-detail__alongside-list[b-b2mkqx0xkp] {
    margin: 0;
    padding: 0;
    list-style: none;
    max-height: 220px;
    overflow-y: auto;
    border: 1px solid var(--border);
    border-radius: var(--r);
}

/* The name gets the row: app names run long ("Continia Banking - CSV Import") and
   were wrapping a word a line beside two fixed columns. The publisher drops under
   it, and the version keeps the right edge on one line. */
.env-detail__alongside-list li[b-b2mkqx0xkp] {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    column-gap: var(--space-3);
    align-items: baseline;
    padding: var(--space-2) var(--space-3);
    font-size: var(--text-sm);
    color: var(--ink-2);
}

.env-detail__alongside-name[b-b2mkqx0xkp] { grid-column: 1; color: var(--ink); overflow-wrap: anywhere; }
.env-detail__alongside-pub[b-b2mkqx0xkp] { grid-column: 1; font-size: var(--text-xs); }
.env-detail__alongside-ver[b-b2mkqx0xkp] { grid-column: 2; grid-row: 1; white-space: nowrap; }

.env-detail__alongside-list li + li[b-b2mkqx0xkp] { border-top: 1px solid var(--border); }

.env-detail__when-legend[b-b2mkqx0xkp] {
    padding: 0 var(--space-1);
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--ink-2);
}

/* The delivery window's editor, under the two windows it is compared with. */
.env-detail__window-open[b-b2mkqx0xkp],
.env-detail__window[b-b2mkqx0xkp] {
    margin-top: var(--space-4);
}

.env-detail__window[b-b2mkqx0xkp] { display: grid; gap: var(--space-2); }

.env-detail__window-row[b-b2mkqx0xkp] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
}

.env-detail__window-time[b-b2mkqx0xkp] {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--text-sm);
    color: var(--ink-2);
}

/* The Recover button inside the deleted-environment alert. On its own line so the
   sentence above it reads as a sentence rather than wrapping around a control. */
.env-detail__recover[b-b2mkqx0xkp] {
    display: block;
    margin-top: var(--space-3);
}

/* The facts in the rail: one to a line beside the content, two or more to a row once
   the rail drops under it on a narrower screen. Values wrap rather than clip - the
   rail is narrower than the meta row they came from, and a delivery window with its
   time zone is the longest of them. */
.env-detail__facts[b-b2mkqx0xkp] {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    gap: var(--space-3) var(--space-5);
    align-items: start;
}

.env-detail__facts .meta-item__value[b-b2mkqx0xkp] {
    white-space: normal;
    overflow-wrap: anywhere;
}

/* The tab row with the page's actions at its end, GitHub's shape: one rule under
   both, which the row draws instead of the tab strip so it runs the full width. The
   active tab's underline still lands on it, since the strip sits on the row's bottom
   edge. On a narrow page the actions take their own line above the tabs, so the tabs
   keep the rule their underline belongs to. */
.env-detail__tabs[b-b2mkqx0xkp] {
    flex-wrap: wrap;
    align-items: flex-end;
    column-gap: var(--space-4);
    row-gap: var(--space-2);
    border-bottom: 1px solid var(--border);
}

.env-detail__tabs[b-b2mkqx0xkp]  .header-tabs {
    border-bottom: 0;
}

.env-detail__actions[b-b2mkqx0xkp] {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    padding-bottom: var(--space-1);
}

@container (max-width: 720px) {
    .env-detail__actions[b-b2mkqx0xkp] {
        order: -1;
        flex-basis: 100%;
    }
}
/* /Components/Pages/Environments/EnvironmentsList.razor.rz.scp.css */

/* The environment is what the row is and what its first link opens, so it reads as
   the link: the stacked cell's main line is ink by default, which left the solution
   beside it looking like the only thing to click. */
a.cell-stack__main[b-kkuqdso5i7] {
    color: var(--primary-ink);
    font-weight: var(--fw-semibold);
}

/* Storage: the environment's size, then the customer's whole tenant against its allowance.
   The bar is the design system's .progress, toned amber from 80% and red at or over the
   allowance - Business Central lets a tenant go over, so red is a state, not a ceiling. */
.env-storage[b-kkuqdso5i7] { min-width: 11rem; }
.env-storage__bar[b-kkuqdso5i7] { height: 6px; margin: 2px 0; }
.env-storage__bar--warn[b-kkuqdso5i7]::-webkit-progress-value { background: var(--warning); }
.env-storage__bar--warn[b-kkuqdso5i7]::-moz-progress-bar { background: var(--warning); }
.env-storage__bar--danger[b-kkuqdso5i7]::-webkit-progress-value { background: var(--danger); }
.env-storage__bar--danger[b-kkuqdso5i7]::-moz-progress-bar { background: var(--danger); }
.env-storage__note--warn[b-kkuqdso5i7] { color: var(--warning-text); }
.env-storage__note--danger[b-kkuqdso5i7] { color: var(--danger-text); font-weight: var(--fw-semibold); }

/* The auto-refresh switch sits in the freshness strip, so it takes the strip's type size
   rather than a form's. */
.freshness__auto[b-kkuqdso5i7] { font-size: var(--text-sm); }
/* /Components/Pages/Mcp.razor.rz.scp.css */
/* What is left of this page's own CSS after the move onto page archetype 13.

   The step cards, the code block, the callouts and the pill tabs all come from
   the design layer now (pages-content.css / components.css). What remains has
   no counterpart there: a two-up card row inside a step body, the example
   prompts, and the folded tool reference.

   The old sheet was 190 lines and three of its colours were dead - it painted
   with `var(--blue)`, `var(--blue-50)` and `var(--mono)`, none of which
   survived into tokens.css. */

.mcp-choice[b-ufojqp9z9h] {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-3);
}

/* The two cards hold different amounts of prose, so without this the shorter
   one's button floats mid-card and the pair reads as two unrelated things
   rather than one either/or. */
.mcp-choice .card[b-ufojqp9z9h] {
    display: flex;
    flex-direction: column;
}

.mcp-choice .card__foot[b-ufojqp9z9h] {
    margin-top: auto;
}

.mcp-choice .card__body[b-ufojqp9z9h] {
    display: grid;
    gap: var(--space-3);
}

.mcp-choice .card__body p[b-ufojqp9z9h] {
    margin: 0;
}

@media (max-width: 720px) {
    .mcp-choice[b-ufojqp9z9h] {
        grid-template-columns: 1fr;
    }
}

.mcp-prompts[b-ufojqp9z9h] {
    margin: 0;
    padding-left: var(--space-5);
    display: grid;
    gap: var(--space-1);
    font-size: var(--text-sm);
    color: var(--ink-3);
}

/* ---------- the tool reference ----------
   Folded shut by default. Thirty-eight rows is lookup material, and nobody
   needs it before they are connected - open it was a wall between the setup
   steps and the troubleshooting a stuck reader is actually scrolling for.
   The design system has no disclosure component; this borrows its card
   surface rather than inventing a second one. */

/* No max-width: the page is .steps--wide now, and a 82ch reference under a
   full-width step list is the ragged edge this page just lost. */
.mcp-tools[b-ufojqp9z9h] {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r);
    box-shadow: var(--shadow-xs);
}

.mcp-tools > summary[b-ufojqp9z9h] {
    padding: var(--space-3) var(--space-4);
    cursor: pointer;
    font-size: var(--text-md);
    font-weight: var(--fw-semibold);
    color: var(--ink);
    list-style: none;
}

.mcp-tools > summary[b-ufojqp9z9h]::-webkit-details-marker {
    display: none;
}

.mcp-tools > summary:focus-visible[b-ufojqp9z9h] {
    outline: var(--focus-ring);
    outline-offset: calc(var(--focus-offset) * -1);
    border-radius: var(--r);
}

.mcp-tools__caret[b-ufojqp9z9h] {
    color: var(--ink-3);
    transition: transform var(--transition-fast);
}

.mcp-tools[open] .mcp-tools__caret[b-ufojqp9z9h] {
    transform: rotate(90deg);
}

.mcp-tools__body[b-ufojqp9z9h] {
    padding: 0 var(--space-4) var(--space-4);
    display: grid;
    gap: var(--space-2);
}

.mcp-tools__group[b-ufojqp9z9h] {
    margin: var(--space-4) 0 0;
    font-size: var(--text-sm);
    font-weight: var(--fw-semibold);
    color: var(--ink-2);
}

/* The wire name is the answer to "what did the assistant just call?", not
   something to read first - so it follows the sentence and sits back. */
.mcp-tools__name[b-ufojqp9z9h] {
    color: var(--ink-4);
}

/* The inline-bar code block is built for one short line and clips what doesn't
   fit; in a half-width card a real server address does not fit, so it read as
   "http://localhost:" with the rest silently scrolled off. It scrolls, but
   nothing says so - and this is the one string on the card the reader has to
   get whole. Let it wrap instead. */
.mcp-choice .code-block--inlinebar pre[b-ufojqp9z9h] {
    white-space: normal;
    overflow-wrap: anywhere;
}
/* /Components/Pages/NewExtension.razor.rz.scp.css */
/* The .field__label and .form-grid resets that used to live here became the
   design-layer bridge in base.css, and the bridge itself retired in PR 17e when
   the legacy sheets it was undoing were deleted. There is nothing to patch any
   more: .field and .form-grid mean one thing now, and it is the component's. */

/* The GitHub cards (#623). A stack with one rhythm - the picker or the
   sentence, then whatever the last action had to say. Deliberately margins
   rather than a grid: a grid would stretch the "Add to repository" button to
   the full column, and the only full-width button in this aside is Generate. */
.ext-repo > * + *[b-vh89n9u8vc],
/* The card foot is a right-aligned row by default, which in a column this
   narrow squeezes the sentence into four words a line beside the button. Here
   the sentence is the point - it says what pressing the button will do - so
   these stack. */
.ext-deliver[b-vh89n9u8vc] {
    display: grid;
    justify-items: start;
    gap: var(--space-2);
}

/* ::deep: the alert is rendered by the Alert component, outside this file's scope. */
.ext-deliver[b-vh89n9u8vc]  > .alert {
    justify-self: stretch;
}

/* ::deep so the rule also reaches a paragraph a child component renders (an Alert). */
.ext-repo[b-vh89n9u8vc]  p,
.ext-deliver[b-vh89n9u8vc]  p {
    margin: 0;
}

/* Same floor the Create repository button gets on New Workspace: this label
   swaps between three strings ("Add to repository", "Open another pull
   request" and the busy "Opening pull request..."), and without a minimum the
   button resizes under the pointer at the moment it is pressed. Sized to the
   longest of them. */
.ext-repo__go[b-vh89n9u8vc] {
    min-width: 14rem;
}

/* The one line on the card that reports what just happened. The static caption
   above it is .field__hint; if this looked the same, the only news on the card
   would read as more boilerplate. */
.ext-repo__outcome[b-vh89n9u8vc] {
    display: flex;
    gap: var(--space-2);
    align-items: flex-start;
    padding: var(--space-2) var(--space-3);
    border-left: 3px solid var(--primary);
    background: var(--surface-2);
    font-size: var(--text-xs);
    color: var(--ink-2);
}

.ext-repo__outcome svg[b-vh89n9u8vc] {
    flex: none;
    margin-top: 2px;
    color: var(--ink-3);
}

/* Import-a-config card. The file input is hidden behind its own .btn label, so
   the control reads as a button rather than the browser's native file widget. */
.ext-import[b-vh89n9u8vc] {
    display: grid;
    gap: var(--space-2);
}

.ext-import__row[b-vh89n9u8vc] {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex-wrap: wrap;
}

.ext-import__button[b-vh89n9u8vc] {
    position: relative;
    overflow: hidden;
    cursor: pointer;
}

/* ::deep because <InputFile> renders its <input> inside its own component, so
   this page's scope attribute never lands on it — without it the browser's
   native file widget sits visible beside our styled button. */
[b-vh89n9u8vc] .ext-import__input {
    position: absolute;
    inset: 0;
    opacity: 0;
    cursor: pointer;
}

.ext-import__filename[b-vh89n9u8vc] {
    min-width: 0;
    flex: 1;
    font-family: var(--font-mono);
    font-size: var(--text-xs);
    color: var(--ink-3);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.ext-import__errors[b-vh89n9u8vc] {
    display: grid;
    gap: var(--space-1);
    margin: 0;
    padding: 0;
    list-style: none;
}

/* The drop-in instructions: prose plus one copyable line. */
.ext-after[b-vh89n9u8vc] {
    display: grid;
    gap: var(--space-2);
    font-size: var(--text-sm);
    color: var(--ink-3);
}

.ext-after p[b-vh89n9u8vc] {
    margin: 0;
    text-wrap: pretty;
}
/* /Components/Pages/NewWorkspace.razor.rz.scp.css */
/* The .field__label and .form-grid resets that used to live here became the
   design-layer bridge in base.css, and the bridge itself retired in PR 17e when
   the legacy sheets it was undoing were deleted. There is nothing to patch any
   more: .field and .form-grid mean one thing now, and it is the component's. */

/* The hidden-checkbox and focus-within rules that used to live here moved into
   components.css: .module-card is a shared component and every call site that
   wraps a real checkbox needs them (the per-org tool switches, for one). */

/* The create-a-repository card (#622). A plain stack with one rhythm - the
   sentence, the two fields, then whatever the last attempt had to say.
   Margins rather than a grid: a grid would stretch the button to the full
   column, and the only full-width button in this aside is Generate. */
.ws-repo > * + *[b-f0j5s9zbnc] {
    margin-top: var(--space-2);
}

/* ::deep so the rule also reaches a paragraph a child component renders (an Alert). */
.ws-repo[b-f0j5s9zbnc]  p {
    margin: 0;
}

/* A clone command is one long unbreakable token, and .code is nowrap by
   design - together they widen the sticky aside and push the whole page
   sideways. Inside this card it wraps instead. */
.ws-repo code[b-f0j5s9zbnc] {
    white-space: normal;
    overflow-wrap: anywhere;
}

/* "Creating repository..." is a longer string than "Create repository", so
   without a floor the button grows at the moment it is pressed - which reads
   as the layout twitching rather than as work starting. Sized to hold the
   busy label, which is the wider of the two. */
.ws-repo__create[b-f0j5s9zbnc] {
    min-width: 12.5rem;
}

/* The two ways on from a repository that now exists (#812). They wrap rather
   than shrink: the aside is narrow and a truncated "Clone in VS Cod" would be
   worse than a second line. */
.ws-repo-actions[b-f0j5s9zbnc] {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
}

/* The clone command and its copy button. The command wraps (see the .ws-repo
   code rule above) and the button stays whole on the end of it. */
.ws-repo-clone[b-f0j5s9zbnc] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--text-sm);
}

.ws-repo-clone__label[b-f0j5s9zbnc] {
    flex-basis: 100%;
}

/* The picked customer's existing repositories (#758). A plain list of links -
   this is something to notice on the way past, not a control. */
.ws-solution-repos[b-f0j5s9zbnc] {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: var(--space-1);
    font-size: var(--text-sm);
}
/* /Components/Pages/ObjectExplorer/OeKindCell.razor.rz.scp.css */
/* Badge and word on one line, the badge never squeezed by a long kind. */
.okind-cell[b-uf90mmynmu] { display: inline-flex; align-items: center; gap: var(--space-2); }

/* A legacy C/AL kind (form, dataport) has no search prefix and so no badge.
   Reserve the badge's width anyway: without it those rows started ~28px left
   of every other row and the column read as missing data rather than as "this
   kind has no letters". Matches .okind's min-width + padding in
   pages-power.css. */
.okind-cell__gap[b-uf90mmynmu] { flex: none; width: 25px; }
/* /Components/Pages/ObjectExplorer/OeObjectResults.razor.rz.scp.css */
/*
    Scoped chrome for the objects grid.

    These rules used to live in tools.css under `.object-explorer__browser`,
    which is the container OeReleaseDetail dropped when it moved onto the
    `.page` archetype - a descendant selector is a poor way to scope a
    component's own cells. Everything the design layer already answers
    (.data-table, .data-table__num, .data-table__actions, .okind) is gone from
    here; what is left is the two things the design system has no opinion
    about: the namespace's head/tail split, and the column widths.
*/

/* Fixed column widths, so sorting or lazy-loading the next page cannot reflow
   the table as the content per page changes - the rows below the fold arrive
   while the user is reading the ones above. Name + Namespace (the two
   width-less <col>s) share what is left; long values wrap rather than widen.

   The actions column is sized to the wider of the two things the cell holds: a
   26px kebab, or the words "no source" for a row whose extension shipped
   without any. The design layer's `.data-table__actions { width: 1% }`
   shrink-to-fit does not apply under `table-layout: fixed` - the colgroup
   governs. It was 200px while this cell carried a "View source" split button;
   the design review swapped that for the handoff's kebab, which left 162px of
   dead space to the right of a 26px button. */
/* .data-table already sets width: 100%. */
.oe-objects[b-ftv0xkwjoy] { table-layout: fixed; }
.oe-objects td[b-ftv0xkwjoy] { overflow-wrap: anywhere; }

/* Type (kind keywords like "reportextension") and ID (negative interface ids
   like -818523667) must never wrap - give them room and keep them single-line. */
.oe-objects td:first-child[b-ftv0xkwjoy],
.oe-objects td:nth-child(2)[b-ftv0xkwjoy] { white-space: nowrap; overflow-wrap: normal; }

.oe-objects__col-type[b-ftv0xkwjoy] { width: 152px; }
.oe-objects__col-id[b-ftv0xkwjoy] { width: 92px; }
.oe-objects__col-ext[b-ftv0xkwjoy] { width: 186px; }
.oe-objects__col-actions[b-ftv0xkwjoy] { width: 96px; }

/* A namespace is read right-to-left: the trailing segment is the one that
   identifies the object, the prefix is shared by hundreds of rows. Dim the
   prefix rather than truncating it, so the column still sorts and scans. */
.oe-objects__ns[b-ftv0xkwjoy] { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--ink-4); }

/* Under `table-layout: fixed` a long namespace has to break somewhere, and
   `overflow-wrap: anywhere` on the cell was splitting it mid-segment
   (`Microsoft.S / ales.Postin / g`) at 1100px. Break the prefix - it is dim and
   repeated on hundreds of rows - and keep the trailing segment whole, since
   that is the half that identifies the object. The full value is on `title`. */
.oe-objects__ns-tail[b-ftv0xkwjoy] { color: var(--ink-2); white-space: nowrap; }

/* Version List is a C/AL-era field; it only appears on legacy TXT imports, so
   it hangs under the name rather than claiming a column of its own. */
.oe-objects__versions[b-ftv0xkwjoy] { font-family: var(--font-mono); font-size: var(--text-2xs); color: var(--ink-4); }

/* Said in the actions cell rather than left blank: two rows with a button and
   seventeen with an empty cell reads as the two being flagged. Quieter than the
   row's own text so it does not compete with the name. */
.oe-objects__nosource[b-ftv0xkwjoy] { font-size: var(--text-2xs); }

/* Lazy-load sentinel and the ranked-mode "Show more" button. Both sit under
   the table and are centred on it, not on the page. */
.oe-objects__sentinel[b-ftv0xkwjoy],
.oe-objects__more[b-ftv0xkwjoy] { display: flex; align-items: center; justify-content: center; gap: var(--space-2); padding: var(--space-3) 0; font-size: var(--text-sm); }

/* Below ~1200px the four fixed columns leave Name and Namespace ~200px each,
   the name wraps to three lines and the row height triples - the grid stops
   scanning, which is the one thing it is for. Namespace is the column you can
   lose: the object detail page carries it, and the tree's breadcrumb prefers
   it over the folder path. */
@media (max-width: 1200px) {
    .oe-objects__col-ns[b-ftv0xkwjoy],
    .oe-objects th:nth-child(5)[b-ftv0xkwjoy],
    .oe-objects td:nth-child(5)[b-ftv0xkwjoy] { display: none; }
}
/* /Components/Pages/ObjectExplorer/OeReleaseDetail.razor.rz.scp.css */
/*
    Scoped chrome for the release search page.

    Everything this page used to take from tools.css under
    `.object-explorer__browser` / `.object-explorer__filters` - its own grid,
    its own input and select chrome, its own label typography - is gone: the
    page is a `.page` with a `.filter-bar` now, and the design layer draws all
    of that. What is left here is the two controls the design system has no
    counterpart for, plus two one-off text blocks.
*/

/* The repository list under a release's heading. Wraps, because a project
   release can carry several long clone URLs. */
.oe-release__repos[b-7id97h1cxv] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-1);
    margin-top: 2px;
}

.oe-release__repos a[b-7id97h1cxv] { word-break: break-all; }

/* Feedback when a row-level compare cannot run. */
.oe-release__notice[b-7id97h1cxv] { margin: 0; }

/* The namespace filter is a plain .input with a datalist, so it needs a width
   in the flex row the way the .select-wrap dropdowns get one inline. */
.oe-release__ns[b-7id97h1cxv] { width: 190px; }

/* ---- Filter dropdowns ----------------------------------------------------
   A <details> that holds what a native <select> cannot: the object-type filter
   (several types at once) and Options (a namespace box and the include-base
   toggle). The summary wears the design system's .select chrome (see the
   markup) so it reads as one of the dropdowns in the row; only the parts
   .select cannot supply - the open state, the panel, the option rows - live
   here. Shared by both since Options arrived; the widths are the only thing
   that differ. */
.fdrop[b-7id97h1cxv] { position: relative; }

.fdrop__summary[b-7id97h1cxv] {
    list-style: none;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2);
    /* .select is styled for a real <select>; a <summary> needs the box
       properties spelled out to match its height and inline padding. */
    padding-left: var(--space-2);
    padding-right: var(--space-2);
}

.fdrop__summary[b-7id97h1cxv]::-webkit-details-marker { display: none; }

.fdrop__summary > span:first-child[b-7id97h1cxv] {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.fdrop[open] .fdrop__summary[b-7id97h1cxv] {
    border-color: var(--primary);
    outline: var(--focus-ring);
    outline-offset: var(--focus-offset);
}

/* .menu supplies the surface, border, radius and shadow; this adds only the
   placement and the scroll cap, because the type list is long. */
.fdrop__panel[b-7id97h1cxv] {
    position: absolute;
    z-index: 20;
    top: calc(100% + 4px);
    left: 0;
    min-width: 100%;
    max-height: 280px;
    overflow-y: auto;
}

/* The rows are .menu__item as well as .check, so the padding, radius, size and
   hover all come from components.css. This used to restate every one of them,
   including a :hover that was character-for-character the design layer's. */
.fdrop__option[b-7id97h1cxv] { white-space: nowrap; }

/* The type list is one column of rows; Options is a little form, so it needs
   room for a labelled input rather than menu-item padding alone. */
/* Width on the summary itself, not on a wrapper: the Options control renders as
   a bare disabled <button class="select fdrop__summary"> when the current tab
   has nothing to put in it, with no .fdrop-- wrapper to hang a width off. It
   inherits .select's full-width behaviour and stretched to the whole bar. */
.fdrop__summary[b-7id97h1cxv] { width: 128px; }
.fdrop--kinds .fdrop__summary[b-7id97h1cxv] { width: 170px; }
.fdrop__panel--form[b-7id97h1cxv] { padding: var(--space-2); display: grid; gap: var(--space-2); min-width: 232px; }
.fdrop__field[b-7id97h1cxv] { display: grid; gap: 3px; }
.fdrop__field .input[b-7id97h1cxv] { width: 100%; }

/* The scope tabs sit on their own line above the filter row - see the note in
   the markup. align-self keeps the strip its own width rather than stretching
   across the column the page's grid gives it. */
.oe-release__scopes[b-7id97h1cxv] { align-self: start; }

/* ---------- search tips (#575) ----------
   The box accepts six forms and shows about 26 characters of placeholder, so
   the syntax used to be discoverable only from the no-results empty state -
   you had to search wrong before the tool told you how to search right. A
   .fdrop like the Type and Options dropdowns beside it, so it reads as one
   more control in the row rather than a new kind of thing. */

/* The other two summaries borrow .select chrome because they are pickers with
   a current value. This one is a button: it has no value, it opens a reference.
   So it undoes the three box properties .fdrop__summary spells out for a
   <select>-shaped control and takes .btn's own instead - the padding and gap
   included, which the rule above overrides at scoped-CSS specificity and which
   left this narrower and tighter than Clear filters in the same row (#612). */
.fdrop__summary--plain[b-7id97h1cxv] {
    width: auto;
    justify-content: flex-start;
    gap: var(--space-2);
    padding-left: var(--space-3);
    padding-right: var(--space-3);
}

/* Opens rightward. The control sits near the left end of the filter bar, so
   anchoring the panel's RIGHT edge to it (the default for the pickers further
   along the row) pushed 400px of panel off the left of the viewport. */
.fdrop--tips .fdrop__panel[b-7id97h1cxv] { left: 0; right: auto; }

.fdrop__panel--tips[b-7id97h1cxv] {
    padding: var(--space-3);
    width: 400px;
    max-width: min(400px, calc(100vw - var(--space-6) * 2));
    /* .menu caps at 280px and scrolls, which is right for a list of actions -
       you pick one and it closes. This is a reference you read, and 453px of
       content in a 278px box showed two of seventeen prefixes with no hint
       there were more. Tall enough to fit, still bounded by the viewport. */
    max-height: min(72vh, 520px);
}

.tips[b-7id97h1cxv] {
    margin: 0;
    display: grid;
    grid-template-columns: max-content minmax(0, 1fr);
    column-gap: var(--space-3);
    row-gap: var(--space-1);
    align-items: baseline;
}

.tips__form[b-7id97h1cxv], .tips__means[b-7id97h1cxv] { margin: 0; }
.tips__means[b-7id97h1cxv] { font-size: var(--text-xs); color: var(--ink-3); text-wrap: pretty; }

.tips__rule[b-7id97h1cxv] {
    margin: var(--space-3) 0 var(--space-2);
    padding-top: var(--space-3);
    border-top: 1px solid var(--border);
    font-size: var(--text-xs);
    color: var(--ink-3);
    text-wrap: pretty;
}

/* Two columns of short pairs rather than one long list: seventeen kinds in a
   single column makes the panel taller than the page it drops out of. */
.tips__kinds[b-7id97h1cxv] {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 2px var(--space-3);
}

.tips__kind[b-7id97h1cxv] {
    display: flex;
    align-items: baseline;
    gap: var(--space-2);
    font-size: var(--text-xs);
    color: var(--ink-3);
}

.tips__kind .code[b-7id97h1cxv] { flex: none; }
/* /Components/Pages/ObjectExplorer/ReleasesBrowserView.razor.rz.scp.css */
/* Object Explorer landing — the list archetype, plus two things the handoff has
   no component for: the "latest release" hero and the version timeline. Both are
   composed from its own pieces rather than given a private look. */

/* The three categories are one word each, and Microsoft / Third-party / C/AL are
   not distinguishable at a glance without their glyphs. .pill-tab has no icon
   slot but nothing in it objects to one. */
.oe-tabs .pill-tab[b-t9us3eljjx] {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
}

.oe-tabs .pill-tab svg[b-t9us3eljjx] {
    width: 15px;
    height: 15px;
    color: var(--ink-4);
}

.oe-tabs .pill-tab.is-active svg[b-t9us3eljjx] {
    color: var(--primary);
}

/* The tabs' panel. It only exists to give role="tabpanel" something to attach
   to, so it must not introduce a box of its own between .page's grid and the
   sections inside it. */
.oe-panel[b-t9us3eljjx] {
    display: contents;
}

/* Sits at the right end of the filter bar, where the eye lands after the tabs. */
.oe-tally[b-t9us3eljjx] {
    font-size: var(--text-xs);
    color: var(--ink-4);
    white-space: nowrap;
}

.oe-tally b[b-t9us3eljjx] {
    color: var(--ink-2);
    font-weight: var(--fw-medium);
    font-variant-numeric: tabular-nums;
}

/* ---------- latest-release hero ---------- */

.oe-hero__title[b-t9us3eljjx] {
    margin-top: 2px;
}

.oe-hero__body[b-t9us3eljjx] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-5);
    flex-wrap: wrap;
    padding: var(--space-4);
}

/* .meta-row draws its own card fill and border, which would be a second card
   inside this one. Here it is a bare row of facts. */
.oe-hero__meta[b-t9us3eljjx] {
    flex: 1;
    min-width: 320px;
    padding: 0;
    background: none;
    border: 0;
}

.oe-hero__actions[b-t9us3eljjx] {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex: none;
}

/* ---------- version timeline ---------- */

.oe-group + .oe-group[b-t9us3eljjx] {
    margin-top: var(--space-5);
}

.oe-group__head[b-t9us3eljjx] {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin-bottom: var(--space-3);
}

/* The rule carries the eye across to the count and gives the group a spine —
   the old design's dot-and-line timeline, minus the dot, which was a decoration
   the square system has no other instance of. */
.oe-group__rule[b-t9us3eljjx] {
    flex: 1;
    height: 1px;
    background: var(--border);
}

.oe-group__count[b-t9us3eljjx] {
    flex: none;
    font-size: var(--text-2xs);
    color: var(--ink-4);
    font-variant-numeric: tabular-nums;
}

/* ---------- release card ---------- */

.oe-card[b-t9us3eljjx] {
    color: inherit;
    text-decoration: none;
    display: flex;
    flex-direction: column;
}

.oe-card .browse-card__foot[b-t9us3eljjx] {
    margin-top: auto;
}

.oe-card:hover .browse-card__title[b-t9us3eljjx] {
    color: var(--primary-ink);
}

.oe-card:focus-visible[b-t9us3eljjx] {
    outline: var(--focus-ring);
    outline-offset: var(--focus-offset);
}

.oe-card .browse-card__top[b-t9us3eljjx] {
    gap: var(--space-3);
}

.oe-card .code[b-t9us3eljjx] {
    flex: none;
}

.oe-card__files[b-t9us3eljjx],
.oe-card__go[b-t9us3eljjx] {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
}

.oe-card__files b[b-t9us3eljjx] {
    color: var(--ink-2);
    font-weight: var(--fw-medium);
    font-variant-numeric: tabular-nums;
}

.oe-card__go[b-t9us3eljjx] {
    font-weight: var(--fw-medium);
    transition: gap var(--transition-fast), color var(--transition-fast);
}

.oe-card:hover .oe-card__go[b-t9us3eljjx] {
    color: var(--primary-ink);
    gap: var(--space-2);
}
/* /Components/Pages/Pipelines/PipelineBuilds.razor.rz.scp.css */
/*
    Scoped chrome for the pipeline detail page.

    The page follows PageDetail.dc.html: crumbs, .detail-head with the state
    pill beside the title, a full-width .meta-row of facts, then sections. What
    the design system answers is gone from here - .card, .data-table--edge,
    .sub-rows, .meta-row, .code-block, .commit-chip, .status-pill,
    .section-label, .state-label. What is left is the latest-build card's
    internals and the changelog, which is a nested list of commits per
    repository and has no counterpart in the system at all.
*/

/* .pb-sec / __head / __title retired: they were a heading for a self-bordered
   block that could not use .card__head, because a .card__head belongs to a card
   and a bordered list inside a card is a box in a box. `.card--flush` is the
   answer that was missing - the card frames the section and the list gives its
   own frame up - so Repositories and Build history are ordinary cards now and
   the page has one heading treatment instead of three. */
/* A quiet note at the end of a card head. Not .state-label - that one draws an
   18px rule before itself, which is right above a table and reads as a stray
   dash at the end of a heading row. */
.pb-sec__note[b-pzsqi592f4] { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--ink-4); }

/* "+4 more" after a commit message: the build has a changelog, and the row is
   showing its head commit only. */
.pb-more[b-pzsqi592f4] { margin-left: var(--space-1); font-size: var(--text-xs); color: var(--ink-4); white-space: nowrap; }
/* The quiet "Preview build" tag in a history row (#994). */
.pb-preview[b-pzsqi592f4] { margin-left: var(--space-1); }

/* The latest build's identity line: commit and branch as chips, then the
   version and the time as quiet meta. Wraps rather than truncating - a long
   branch name is worth a second line on the page's focal card. */
.pb-topline[b-pzsqi592f4] { display: flex; align-items: center; flex-wrap: wrap; gap: var(--space-2); }
.pb-topline__meta[b-pzsqi592f4] { font-size: var(--text-xs); color: var(--ink-3); }
.pb-topline__when[b-pzsqi592f4] { margin-left: auto; white-space: nowrap; }

/* An explanatory line inside a card body, between blocks that set their own
   margins. */
.pb-note[b-pzsqi592f4] { margin: 0; font-size: var(--text-sm); color: var(--ink-3); }

.pb-explore[b-pzsqi592f4] { display: flex; }

/* The card body stacks: top line, note/alert, deliverables, explore, changelog.
   Each is a sibling and none of them should own the spacing between them. */
.card__body > * + *[b-pzsqi592f4] { margin-top: var(--space-3); }

/* Changes since the last successful build: one group per repository, each a
   short list of commit messages. No counterpart in the design system - its
   screens show a diff or a run, never a changelog. */
.pb-chg[b-pzsqi592f4] { display: grid; gap: var(--space-3); }
.pb-chg__repo[b-pzsqi592f4] { display: grid; gap: var(--space-1); }
.pb-chg__name[b-pzsqi592f4] { display: flex; align-items: center; gap: var(--space-1); font-size: var(--text-xs); font-weight: var(--fw-medium); color: var(--ink-2); }
.pb-chg__name svg[b-pzsqi592f4] { color: var(--ink-4); }
.pb-chg__list[b-pzsqi592f4] { margin: 0; padding-left: var(--space-4); display: grid; gap: 2px; font-size: var(--text-sm); color: var(--ink-2); }
.pb-chg__list li[b-pzsqi592f4] { text-wrap: pretty; }
/* A synthetic entry ("first build", "no commits found") rather than a real
   commit: it has no hash, so it takes the quieter tone of a caption. */
.pb-chg__note[b-pzsqi592f4] { color: var(--ink-3); font-style: italic; }

/* The build log can run to thousands of lines; cap it and let the pane scroll
   rather than the page. Raw log downloads the whole thing. */
.pb-log[b-pzsqi592f4] { max-height: 420px; overflow: auto; white-space: pre-wrap; word-break: break-word; }

/* Severity tint for a log line. RenderLog emits these spans as a MarkupString,
   which is built at runtime and therefore never receives the scope attribute
   Blazor stamps onto compiled markup - so they need ::deep, which moves the
   scope up onto .pb-log and leaves the descendants unqualified. Without it the
   rules compile to `.l-err[b-xxx]` and match nothing, silently. */
.pb-log[b-pzsqi592f4]  .l-ok   { color: var(--success-text); }
.pb-log[b-pzsqi592f4]  .l-warn { color: var(--warning-text); }
.pb-log[b-pzsqi592f4]  .l-err  { color: var(--danger-text); }
.pb-log[b-pzsqi592f4]  .l-dim  { color: var(--ink-4); }

/* Two selects and a button in a 300px rail: stacked, not inline. */
.pb-compare[b-pzsqi592f4] { display: grid; gap: var(--space-3); }
.pb-compare .btn[b-pzsqi592f4] { justify-self: start; }

/* Build history. The four short columns must not wrap - "4 hours ago" broken
   over two lines doubles the row height and the grid stops scanning, which is
   the one thing a history table is for. Description is the column that takes
   the slack. */
.data-table td:nth-child(4)[b-pzsqi592f4],
.data-table td:nth-child(5)[b-pzsqi592f4],
.data-table th:nth-child(4)[b-pzsqi592f4],
.data-table th:nth-child(5)[b-pzsqi592f4] { white-space: nowrap; }

/* Why an extension did not build. A sentence, not a value: it wraps in body
   text where .sub-row__val would truncate a mono line, because the part that
   says what to do is at the end. */
.pb-fail__msg[b-pzsqi592f4] { font-size: var(--text-sm); color: var(--ink-2); line-height: 1.45; overflow-wrap: anywhere; }

/* The Branch card (#964): the freshness sentence, then per repository the branch,
   its latest commit and the commit the last build used as .kv-grid pairs, then what
   merged in between. Repositories are separated by space, not rules - a multi-repo
   solution has two or three at most. */
.pb-fresh__lead[b-pzsqi592f4] { margin: 0; }
.pb-fresh__repo[b-pzsqi592f4] { display: grid; gap: var(--space-2); }
.pb-fresh__repo + .pb-fresh__repo[b-pzsqi592f4] { margin-top: var(--space-4); }
/* Who merged it and when, after the pull request's title: quieter than the title. */
.pb-fresh__by[b-pzsqi592f4] { margin-left: var(--space-1); font-size: var(--text-xs); color: var(--ink-4); white-space: nowrap; }
/* /Components/Pages/Pipelines/PipelineEdit.razor.rz.scp.css */
/*
    Scoped chrome for the build pipeline editor page.

    The extension picker is the design system's .sub-rows + .check +
    .sub-rows__foot. What is left here is about this page rather than about a
    form: the discovery footer, and the count.
*/

.pe-picker__count[b-nvfscdxspy] { margin-left: auto; font-size: var(--text-xs); color: var(--ink-3); }

/* A .sub-row is a grid; a .check is an inline-flex. The row wins, and the
   checkbox lands in the actions cell on the right - which is where a per-row
   toggle belongs in a list you scan by name. */
.pe-picker .sub-row[b-nvfscdxspy] { cursor: pointer; }

/* When the extensions were last discovered, and the button to do it again. */
.pe-discovery[b-nvfscdxspy] { display: flex; align-items: center; gap: var(--space-2); }
.pe-discovery .btn[b-nvfscdxspy] { margin-left: auto; }

/* Why the primary action is disabled - shown only when it is user-correctable. */
.pe-hint[b-nvfscdxspy] { margin: 0; }
/* /Components/Pages/Pipelines/PipelinesBrowser.razor.rz.scp.css */
/* The "Latest build" cell: a commit chip, its branch, and the BC version, kept
   on one line so the column scans. .commit-chip itself comes from pages.css. */

.pl-build[b-n0jdquyhv9] {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    flex-wrap: wrap;
}

.pl-branch[b-n0jdquyhv9] {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    font-size: var(--text-xs);
    color: var(--ink-3);
    white-space: nowrap;
}

.pl-branch svg[b-n0jdquyhv9] {
    opacity: .7;
}

/* A pipeline whose branch has moved past its last build (#964): the warning
   keyline, in place of the latest build's own. The design system's edge table
   has no warning row state; the component library's warning token is the
   nearest honest colour. */
.data-table tr.pl-ahead td:last-child[b-n0jdquyhv9] { border-right-color: var(--warning); }

/* The pipeline cell: name and branch sentence, with Build beside the sentence
   when the branch has moved on. The stack takes the slack; the button keeps its
   size. */
.pl-name[b-n0jdquyhv9] { display: flex; align-items: center; gap: var(--space-3); }
.pl-name .cell-stack[b-n0jdquyhv9] { flex: 1 1 auto; }
.pl-name .btn[b-n0jdquyhv9] { flex: none; }
/* /Components/Pages/Pipelines/PipelinesDashboard.razor.rz.scp.css */
/* The Pipelines dashboard (#955), from .design/handoff/PipelinesBody.dc.html. The cue
   tiles, activity rows and cards are components.css / pages.css; these are the sheet's
   inline styles given names, and nothing else. */

/* The head wraps as the sheet draws it (flex-wrap on the head, the title block 280px
   before it wraps), so on a phone the two buttons drop under the title instead of
   running off the screen. PageHead renders the head, hence ::deep from the page. */
.pd-page[b-xiedzf4fsz]  .page-head { flex-wrap: wrap; }
.pd-page[b-xiedzf4fsz]  .page-head > div:first-child { min-width: 0; flex: 1 1 280px; }
.pd-page[b-xiedzf4fsz]  .page-head__actions { flex: 0 1 auto; }

/* The head's subtitle while the numbers load. */
.pd-sub-skeleton[b-xiedzf4fsz] { display: block; width: 260px; max-width: 100%; margin-top: var(--space-2); }

.pd-actions[b-xiedzf4fsz] { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.pd-card-head[b-xiedzf4fsz] { flex-wrap: wrap; gap: var(--space-2); }
.pd-empty-actions[b-xiedzf4fsz] { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--space-2); }

/* The sheet's two columns: side by side while each can be 420px, stacked below that. */
.pd-cols[b-xiedzf4fsz] { grid-template-columns: repeat(auto-fit, minmax(min(420px, 100%), 1fr)); }

/* "Waiting for approval" above zero: the warning cue from Components.dc.html, "Pipelines
   dashboard additions". The cue's own custom properties, set to the warning tokens. */
.pd-cue--warning[b-xiedzf4fsz] {
    --cue-bg: var(--warning-bg);
    --cue-bg-hover: var(--warning-bg);
    --cue-ink: var(--warning-text);
    --cue-ink-dim: var(--warning-text);
    --cue-rule: var(--warning);
    box-shadow: inset 0 0 0 1px var(--warning);
}

.pd-attn-text[b-xiedzf4fsz] { color: var(--ink); }
.pd-review[b-xiedzf4fsz] { margin-top: var(--space-1); }
/* The half-set-up row: a next step, not a problem, so no keyline and a quiet glyph. */
.activity__row.pd-attn--quiet .activity__icon[b-xiedzf4fsz] { color: var(--ink-3); }

/* A row nobody in particular started: a pull request's build, or a deployment the
   pipeline prepared. The sunken avatar from Components.dc.html. */
.pd-avatar-auto[b-xiedzf4fsz] { background: var(--surface-sunken); color: var(--ink-2); font-size: 9px; letter-spacing: 0; }

/* The loading state's placeholder rows. */
.pd-skel-avatar[b-xiedzf4fsz] { width: 26px; height: 26px; border-radius: var(--r-pill); }
.pd-skel-body[b-xiedzf4fsz] { display: grid; gap: 6px; }
.pd-skel-sub[b-xiedzf4fsz] { width: 40%; height: 9px; }
.pd-skel-time[b-xiedzf4fsz] { width: 44px; height: 9px; }
.pd-skel-line[b-xiedzf4fsz] { height: 12px; }
/* /Components/Pages/Pipelines/ReleasePipelineDetail.razor.rz.scp.css */
/*
    Scoped chrome for one deployment pipeline (.design/handoff/ReleasePipelineBody.dc.html,
    issue #929). The sheet draws its layout with inline styles over the design system's
    classes; they are named here instead, one rule per drawn style, with the tokens the
    sheet used. No colour is new: every tone below is the sheet's own state map
    (scheduled, running, deployed/completed, failed, cancelled/skipped, pending, handed
    to Business Central), and every keyline a --bar-* token.
*/

/* ── State tones: the text colour of a glyph or a state word ─────────────── */
.rp-tone--queued[b-iv62ns9yut], .rp-tone--cancelled[b-iv62ns9yut], .rp-tone--skipped[b-iv62ns9yut] { color: var(--ink-3); }
.rp-tone--running[b-iv62ns9yut] { color: var(--info-text); }
.rp-tone--succeeded[b-iv62ns9yut] { color: var(--success-text); }
.rp-tone--failed[b-iv62ns9yut] { color: var(--danger-text); }
.rp-tone--pending[b-iv62ns9yut] { color: var(--ink-4); }
.rp-tone--handed[b-iv62ns9yut] { color: var(--ink-2); }
.rp-tone--draft[b-iv62ns9yut] { color: var(--warning-text); }
.rp-strong[b-iv62ns9yut] { font-weight: var(--fw-medium); }
.rp-glyph[b-iv62ns9yut] { flex: none; }

/* ── Right-edge keylines, the same vocabulary as every table ─────────────── */
.rp-bar--queued[b-iv62ns9yut], .rp-bar--handed[b-iv62ns9yut] { border-right-color: var(--bar-queued); }
.rp-bar--running[b-iv62ns9yut] { border-right-color: var(--bar-running); }
.rp-bar--succeeded[b-iv62ns9yut] { border-right-color: var(--bar-succeeded); }
.rp-bar--failed[b-iv62ns9yut] { border-right-color: var(--bar-failed); }
.rp-bar--cancelled[b-iv62ns9yut], .rp-bar--skipped[b-iv62ns9yut] { border-right-color: var(--bar-cancelled); }
.rp-bar--pending[b-iv62ns9yut] { border-right-color: var(--border); }
.rp-bar--draft[b-iv62ns9yut] { border-right-color: var(--bar-draft); }

/* ── Loading skeleton ─────────────────────────────────────────────────────── */
.rp-skel-head[b-iv62ns9yut] { justify-content: flex-start; }
.rp-skel-glyph[b-iv62ns9yut] { width: 15px; height: 15px; flex: none; }
.rp-skel-stack[b-iv62ns9yut] { display: grid; gap: 6px; flex: 1; }
.rp-skel-title[b-iv62ns9yut] { width: 180px; }
.rp-skel-sub[b-iv62ns9yut] { width: 55%; height: 9px; }
.rp-skel-label[b-iv62ns9yut] { width: 40%; height: 9px; }
.rp-skel-grid[b-iv62ns9yut] { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: var(--space-4); }
.rp-skel-row[b-iv62ns9yut] { display: flex; align-items: center; gap: var(--space-3); height: 50px; padding: 0 var(--space-4); border-bottom: 1px solid var(--border); }
.rp-skel-line[b-iv62ns9yut] { max-width: 260px; }
.rp-skel-fill[b-iv62ns9yut] { flex: 1; }
.rp-skel-end[b-iv62ns9yut] { width: 60px; }

/* ── Summary card ─────────────────────────────────────────────────────────── */
.rp-summary[b-iv62ns9yut] { border-top: 3px solid var(--border); }
.rp-summary--succeeded[b-iv62ns9yut] { border-top-color: var(--bar-succeeded); }
.rp-summary--failed[b-iv62ns9yut] { border-top-color: var(--bar-failed); }
.rp-summary--queued[b-iv62ns9yut], .rp-summary--handed[b-iv62ns9yut] { border-top-color: var(--bar-queued); }
.rp-summary--running[b-iv62ns9yut] { border-top-color: var(--bar-running); }
.rp-summary--draft[b-iv62ns9yut] { border-top-color: var(--bar-draft); }
.rp-summary__head[b-iv62ns9yut] { justify-content: flex-start; align-items: flex-start; }
.rp-summary__glyph[b-iv62ns9yut] { display: inline-flex; flex: none; margin-top: 2px; color: var(--ink); }
.rp-summary__text[b-iv62ns9yut] { min-width: 0; }
.rp-summary__sentence[b-iv62ns9yut] { color: var(--ink-2); text-wrap: pretty; }
.rp-summary--succeeded .rp-summary__glyph[b-iv62ns9yut], .rp-summary--succeeded .rp-summary__title[b-iv62ns9yut] { color: var(--success-text); }
.rp-summary--failed .rp-summary__glyph[b-iv62ns9yut], .rp-summary--failed .rp-summary__title[b-iv62ns9yut] { color: var(--danger-text); }
.rp-summary--queued .rp-summary__glyph[b-iv62ns9yut], .rp-summary--queued .rp-summary__title[b-iv62ns9yut] { color: var(--ink-3); }
.rp-summary--running .rp-summary__glyph[b-iv62ns9yut], .rp-summary--running .rp-summary__title[b-iv62ns9yut] { color: var(--info-text); }
.rp-summary--handed .rp-summary__glyph[b-iv62ns9yut], .rp-summary--handed .rp-summary__title[b-iv62ns9yut] { color: var(--ink-2); }
.rp-summary--draft .rp-summary__glyph[b-iv62ns9yut], .rp-summary--draft .rp-summary__title[b-iv62ns9yut] { color: var(--warning-text); }

.rp-summary__blocks[b-iv62ns9yut] { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr)); }
.rp-summary__block[b-iv62ns9yut] { display: grid; gap: var(--space-3); align-content: start; }
/* Read from Business Central's mirror, not stored by us: a sunken, separate block. */
.rp-summary__block--bc[b-iv62ns9yut] { border-left: 1px solid var(--border); background: var(--surface-sunken); }
.rp-summary__label[b-iv62ns9yut] { margin: 0; display: flex; align-items: center; gap: var(--space-2); }

.rp-facts[b-iv62ns9yut] { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(150px, 100%), 1fr)); gap: var(--space-3) var(--space-4); }
.rp-facts--narrow[b-iv62ns9yut] { grid-template-columns: repeat(auto-fit, minmax(min(130px, 100%), 1fr)); }
.rp-fact[b-iv62ns9yut] { min-width: 0; overflow-wrap: anywhere; }
/* The sheet lets a fact wrap rather than clip: "Handed to Business Central" is a whole state, not a prefix. */
.rp-fact .meta-item__value[b-iv62ns9yut] { white-space: normal; }
.rp-force[b-iv62ns9yut] { display: flex; align-items: center; gap: var(--space-1); color: var(--warning-text); font-weight: var(--fw-semibold); }
.rp-env-type[b-iv62ns9yut] { color: var(--ink-3); }
.rp-env-type--prod[b-iv62ns9yut] { color: var(--danger-text); font-weight: var(--fw-semibold); }

/* ── Deployments list ────────────────────────────────────────────────────────── */
.rp-releases[b-iv62ns9yut] { overflow: hidden; }

/* One grid for the header and every collapsed row, so the columns line up. */
.rp-cols[b-iv62ns9yut],
.rp-rel__row[b-iv62ns9yut] {
    display: grid;
    grid-template-columns: 28px 24px minmax(0, 1.5fr) minmax(0, 1.3fr) minmax(0, 1fr) 72px minmax(0, 1fr) 190px;
    align-items: center;
    gap: var(--space-3);
    padding: 0 var(--space-4);
}
.rp-cols[b-iv62ns9yut] {
    height: 34px;
    background: var(--surface-sunken);
    border-bottom: 1px solid var(--border);
    border-right: 4px solid transparent;
    font-size: var(--text-xs);
    font-weight: var(--fw-semibold);
    color: var(--ink-3);
}
.rp-cols__num[b-iv62ns9yut] { text-align: right; }

/* Width and style only: the colour comes from the rp-bar--* rule, which a shorthand here would override. */
.rp-rel[b-iv62ns9yut] { border-bottom: 1px solid var(--border); border-right-width: 4px; border-right-style: solid; }
.rp-rel__row[b-iv62ns9yut] { min-height: 50px; cursor: pointer; }
.rp-rel.is-open > .rp-rel__row[b-iv62ns9yut] { background: var(--surface-sunken); }
.rp-rel__toggle svg[b-iv62ns9yut] { transition: transform 120ms; }
.rp-rel.is-open .rp-rel__toggle svg[b-iv62ns9yut] { transform: rotate(90deg); }
.rp-rel__title[b-iv62ns9yut] { font-weight: var(--fw-medium); color: var(--ink); }
/* The state word beside the title belongs to the phone layout, where the Outcome column is gone. */
.rp-rel__word[b-iv62ns9yut] { display: none; font-weight: var(--fw-medium); }
.rp-rel__compact[b-iv62ns9yut] { display: none; }
.rp-rel__cell[b-iv62ns9yut] { font-size: var(--text-sm); color: var(--ink-2); }
.rp-rel__took[b-iv62ns9yut] { text-align: right; }
.rp-rel__acts[b-iv62ns9yut] { display: flex; justify-content: flex-end; gap: var(--space-2); }
/* A deployment that used Force sync once, while the pipeline stays on Add (#931). */
.rp-rel__force[b-iv62ns9yut] { color: var(--warning-text); }

.rp-rel__detail[b-iv62ns9yut] {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-4);
    padding: var(--space-4);
    background: var(--surface-sunken);
    border-top: 1px solid var(--border);
}
.rp-rel__phone-acts[b-iv62ns9yut] { display: none; }

.rp-rel__detail[b-iv62ns9yut]  .alert { margin: 0; }

/* The failure's short line on the closed row, with Business Central's code as a tag
   (DeliveryRowPanel.dc.html, section 1). It wraps; nothing about a failure is clipped. */
.rp-rel__why[b-iv62ns9yut] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-1) var(--space-2);
    color: var(--ink-2);
    text-wrap: pretty;
    overflow-wrap: anywhere;
}
.rp-next__label[b-iv62ns9yut] { font-size: var(--text-xs); font-weight: var(--fw-semibold); color: var(--ink-2); }
.rp-next__text[b-iv62ns9yut] { font-size: var(--text-sm); color: var(--ink-2); text-wrap: pretty; }
/* "Deploy again with Force sync" under the suggestion that names it (#931). */
.rp-next__acts[b-iv62ns9yut] { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-top: var(--space-2); }

/* "What happened" (section 2): our sentence, Business Central's message in its own
   block, what the environment reports. */
.rp-what[b-iv62ns9yut] {
    display: grid;
    gap: var(--space-2);
    padding: var(--space-3) var(--space-4);
    background: var(--surface);
    border: 1px solid var(--border);
    border-left: 3px solid var(--bar-failed);
    border-radius: var(--r);
}
.rp-what__label[b-iv62ns9yut] { font-size: var(--text-xs); font-weight: var(--fw-semibold); color: var(--danger-text); }
.rp-what__text[b-iv62ns9yut] { margin: 0; font-size: var(--text-base); line-height: var(--leading-normal); color: var(--ink); text-wrap: pretty; }
.rp-what__bc[b-iv62ns9yut] { display: grid; gap: var(--space-1); padding-left: var(--space-3); border-left: 2px solid var(--border); }
.rp-what__bc-label[b-iv62ns9yut] { font-size: var(--text-xs); color: var(--ink-3); }
.rp-what__bc-text[b-iv62ns9yut] { margin: 0; font-size: var(--text-sm); color: var(--ink); text-wrap: pretty; overflow-wrap: anywhere; }
.rp-what__env[b-iv62ns9yut] { margin: 0; font-size: var(--text-sm); color: var(--ink-2); text-wrap: pretty; }

.rp-next[b-iv62ns9yut] {
    display: grid;
    gap: 2px;
    padding: var(--space-3) var(--space-4);
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r);
}
.rp-next__label[b-iv62ns9yut] { font-size: var(--text-xs); font-weight: var(--fw-semibold); color: var(--ink-2); }
.rp-next__text[b-iv62ns9yut] { font-size: var(--text-sm); color: var(--ink-2); text-wrap: pretty; }
/* "Deploy again with Force sync" under the suggestion that names it (#931). */
.rp-next__acts[b-iv62ns9yut] { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-top: var(--space-2); }

/* The raw response, closed until support needs it. */
.rp-raw[b-iv62ns9yut] { min-width: 0; background: var(--surface); border: 1px solid var(--border); border-radius: var(--r); }
.rp-raw__summary[b-iv62ns9yut] {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    min-height: 36px;
    padding: var(--space-1) var(--space-3);
    cursor: pointer;
    font-size: var(--text-sm);
    color: var(--ink-3);
}
.rp-raw__body[b-iv62ns9yut] { display: grid; gap: var(--space-2); padding: var(--space-3); border-top: 1px solid var(--border); }
.rp-raw__text[b-iv62ns9yut] {
    margin: 0;
    padding: var(--space-3);
    background: var(--surface-sunken);
    border-radius: var(--r-control);
    font-family: var(--font-mono);
    font-size: var(--text-xs);
    line-height: 1.6;
    color: var(--ink-2);
    white-space: pre-wrap;
    word-break: break-word;
}
.rp-raw__foot[b-iv62ns9yut] { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); font-size: var(--text-xs); color: var(--ink-3); }

/* Step strip */
.rp-steps[b-iv62ns9yut] {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(110px, 1fr));
    gap: 1px;
    margin: 0;
    padding: 0;
    list-style: none;
    background: var(--border);
    border: 1px solid var(--border);
    border-radius: var(--r);
    overflow: hidden;
}
.rp-step[b-iv62ns9yut] { display: grid; gap: 2px; padding: var(--space-2) var(--space-3); background: var(--surface); border-top: 3px solid var(--border); }
.rp-step__label[b-iv62ns9yut] { font-size: var(--text-xs); font-weight: var(--fw-semibold); }
.rp-step__at[b-iv62ns9yut] { font-size: var(--text-sm); color: var(--ink); }
.rp-step__took[b-iv62ns9yut] { font-size: var(--text-xs); color: var(--ink-3); min-height: 1em; }
.rp-step--queued[b-iv62ns9yut], .rp-step--handed[b-iv62ns9yut] { border-top-color: var(--bar-queued); }
.rp-step--queued .rp-step__label[b-iv62ns9yut] { color: var(--ink-3); }
.rp-step--handed .rp-step__label[b-iv62ns9yut] { color: var(--ink-2); }
.rp-step--running[b-iv62ns9yut] { border-top-color: var(--bar-running); }
.rp-step--running .rp-step__label[b-iv62ns9yut] { color: var(--info-text); }
.rp-step--succeeded[b-iv62ns9yut] { border-top-color: var(--bar-succeeded); }
.rp-step--succeeded .rp-step__label[b-iv62ns9yut] { color: var(--success-text); }
.rp-step--failed[b-iv62ns9yut] { border-top-color: var(--bar-failed); }
.rp-step--failed .rp-step__label[b-iv62ns9yut] { color: var(--danger-text); }
.rp-step--cancelled[b-iv62ns9yut] { border-top-color: var(--bar-cancelled); }
.rp-step--cancelled .rp-step__label[b-iv62ns9yut] { color: var(--ink-3); }
.rp-step--pending .rp-step__label[b-iv62ns9yut], .rp-step--pending .rp-step__at[b-iv62ns9yut] { color: var(--ink-4); }

/* Per-app sub-rows */
.rp-apps[b-iv62ns9yut] { display: grid; gap: var(--space-2); }
.rp-apps__list[b-iv62ns9yut] { background: var(--surface); border: 1px solid var(--border); border-radius: var(--r); }
.rp-app[b-iv62ns9yut] {
    display: grid;
    grid-template-columns: 18px minmax(0, 1fr) auto;
    gap: 2px var(--space-3);
    align-items: start;
    padding: var(--space-2) var(--space-3);
    border-bottom: 1px solid var(--border);
    border-right-width: 3px;
    border-right-style: solid;
}
.rp-app:last-child[b-iv62ns9yut] { border-bottom: 0; }
.rp-app .rp-glyph[b-iv62ns9yut] { padding-top: 2px; }
.rp-app__main[b-iv62ns9yut] { display: grid; gap: 2px; min-width: 0; }
.rp-app__line[b-iv62ns9yut] { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 var(--space-2); }
.rp-app__name[b-iv62ns9yut] { font-weight: var(--fw-medium); color: var(--ink); }
.rp-app__ver[b-iv62ns9yut] { font-size: var(--text-sm); color: var(--ink-3); }
.rp-app__msg[b-iv62ns9yut] { font-size: var(--text-sm); color: var(--ink-3); text-wrap: pretty; overflow-wrap: anywhere; }
.rp-app__msg--failed[b-iv62ns9yut] { color: var(--danger-text); }
.rp-app__end[b-iv62ns9yut] { display: grid; justify-items: end; gap: 2px; font-size: var(--text-sm); }
.rp-app__took[b-iv62ns9yut] { font-size: var(--text-xs); color: var(--ink-3); }

/* Diagnostics log: the one place mono is used */
.rp-log[b-iv62ns9yut] { min-width: 0; background: var(--surface); border: 1px solid var(--border); border-radius: var(--r); }
.rp-log__summary[b-iv62ns9yut] {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-3);
    cursor: pointer;
    font-size: var(--text-sm);
    font-weight: var(--fw-medium);
    color: var(--ink-2);
}
.rp-log__summary .u-muted[b-iv62ns9yut] { font-weight: normal; }
.rp-log__spacer[b-iv62ns9yut] { flex: 1; }
.rp-log__scroll[b-iv62ns9yut] { overflow-x: auto; border-top: 1px solid var(--border); }
.rp-log__lines[b-iv62ns9yut] {
    padding: var(--space-2) 0;
    font-family: var(--font-mono);
    font-size: var(--text-xs);
    line-height: 1.7;
    min-width: max-content;
}
/* The time is an inline-block rather than a grid cell so the copied text keeps each
   line as "02:00:00 message" instead of splitting it across two lines. */
.rp-log__line[b-iv62ns9yut] { padding: 0 var(--space-3); color: var(--ink-2); white-space: pre; }
.rp-log__line--err[b-iv62ns9yut] { color: var(--danger-text); background: var(--danger-bg); }
.rp-log__t[b-iv62ns9yut] { display: inline-block; width: 64px; margin-right: var(--space-3); color: var(--ink-4); }

.rp-foot[b-iv62ns9yut] { justify-content: center; }

/* ── Phone: the sheet's compact variant, from the page's own width ───────── */
@container (max-width: 720px) {
    .rp-cols[b-iv62ns9yut] { display: none; }
    .rp-rel__row[b-iv62ns9yut] {
        grid-template-columns: 20px minmax(0, 1fr) auto;
        gap: 2px var(--space-3);
        align-items: start;
        padding: var(--space-3);
        min-height: 44px;
    }
    .rp-rel__row > .rp-glyph[b-iv62ns9yut] { grid-column: 1; grid-row: 1; padding-top: 2px; }
    .rp-rel__name[b-iv62ns9yut] { grid-column: 2; grid-row: 1; padding: 0; }
    .rp-rel__toggle[b-iv62ns9yut] { grid-column: 3; grid-row: 1; }
    .rp-rel__outcome[b-iv62ns9yut], .rp-rel__cell[b-iv62ns9yut], .rp-rel__acts[b-iv62ns9yut] { display: none; }
    .rp-rel__word[b-iv62ns9yut] { display: inline; }
    .rp-rel__build[b-iv62ns9yut] { display: none; }
    .rp-rel__compact[b-iv62ns9yut] { display: block; }
    .rp-rel__phone-acts[b-iv62ns9yut] { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-2); }
    .rp-rel__phone-acts--one[b-iv62ns9yut] { grid-template-columns: 1fr; }
    .rp-rel__phone-acts .btn[b-iv62ns9yut] { height: 44px; justify-content: center; }
    .rp-summary__block--bc[b-iv62ns9yut] { border-left: 0; border-top: 1px solid var(--border); }
    /* On a phone the log wraps rather than scrolls sideways, so a failure line reads whole. */
    .rp-log__lines[b-iv62ns9yut] { min-width: 0; }
    .rp-log__line[b-iv62ns9yut] { white-space: pre-wrap; overflow-wrap: anywhere; padding-left: calc(64px + var(--space-3) * 2); text-indent: calc(-64px - var(--space-3)); }
    .rp-log__t[b-iv62ns9yut] { text-indent: 0; }
}

/* ── Waiting for approval (#934): the band above the newest deployment ───────── */
.rp-approval[b-iv62ns9yut] {
    display: grid; grid-template-columns: auto minmax(0, 1fr); gap: var(--space-1) var(--space-3);
    padding: var(--space-3) var(--space-4); background: var(--warning-bg);
    border-bottom: 1px solid var(--border); border-right: 4px solid var(--bar-draft);
}
.rp-approval__glyph[b-iv62ns9yut] { color: var(--warning-text); margin-top: 2px; display: inline-flex; }
.rp-approval__body[b-iv62ns9yut] { display: grid; gap: var(--space-1); min-width: 0; }
.rp-approval__head[b-iv62ns9yut] { display: flex; gap: var(--space-2); align-items: baseline; flex-wrap: wrap; }
.rp-approval__eyebrow[b-iv62ns9yut] {
    font-size: var(--text-2xs); font-weight: var(--fw-semibold); letter-spacing: .09em;
    text-transform: uppercase; color: var(--warning-text);
}
.rp-approval__title[b-iv62ns9yut] { font-weight: var(--fw-semibold); color: var(--ink); }
.rp-approval__text[b-iv62ns9yut] { font-size: var(--text-sm); color: var(--ink-2); text-wrap: pretty; }
.rp-approval__acts[b-iv62ns9yut] { display: flex; gap: var(--space-2); margin-top: var(--space-1); flex-wrap: wrap; }
.rp-approval-error[b-iv62ns9yut] { padding: var(--space-3) var(--space-4) 0; }
.rp-none[b-iv62ns9yut] { margin: 0; padding: var(--space-4); color: var(--ink-3); font-size: var(--text-sm); }
/* /Components/Pages/Pipelines/ReleasePipelinesBrowser.razor.rz.scp.css */
/* The Deployment pipelines list, after .design/handoff/ReleasePipelinesBody.dc.html. The sheet
   draws these with inline styles over the design system's tokens; they live here as
   classes instead, with the same tokens. */

/* ── "Shipping now": one band per deployment in flight, above the filter row ── */
.rp-live[b-98aur5rvbf] {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    align-items: center;
    gap: var(--space-2) var(--space-4);
    padding: var(--space-3) var(--space-4);
    background: var(--info-bg);
    border: 1px solid var(--info);
    border-left: 4px solid var(--bar-running);
    border-radius: var(--r);
}
.rp-live__spinner[b-98aur5rvbf] { border-top-color: var(--info-text); }
.rp-live__body[b-98aur5rvbf] { display: grid; gap: var(--space-1); min-width: 0; }
.rp-live__head[b-98aur5rvbf] { display: flex; align-items: baseline; gap: var(--space-2); flex-wrap: wrap; }
.rp-live__eyebrow[b-98aur5rvbf] {
    font-size: var(--text-2xs);
    font-weight: var(--fw-semibold);
    letter-spacing: .09em;
    text-transform: uppercase;
    color: var(--info-text);
}
.rp-live__name[b-98aur5rvbf] { font-size: var(--text-md); font-weight: var(--fw-semibold); color: var(--ink); }
.rp-live__text[b-98aur5rvbf] { font-size: var(--text-sm); color: var(--ink-2); text-wrap: pretty; }
.rp-live__meter[b-98aur5rvbf] { display: flex; align-items: center; gap: var(--space-2); max-width: 420px; }
.rp-live__progress[b-98aur5rvbf] { height: 6px; flex: 1; }
.rp-live__step[b-98aur5rvbf] { font-size: var(--text-xs); color: var(--info-text); font-weight: var(--fw-medium); white-space: nowrap; }

/* ── The table ── */
.rp-list__table[b-98aur5rvbf] { table-layout: fixed; }
/* A fixed layout takes the state column's 1% literally; the glyph needs its 44px. */
.rp-list__table .data-table__col-state[b-98aur5rvbf] { width: 44px; }
.rp-list__table .rp-list__col-pipeline[b-98aur5rvbf] { width: 19%; }
.rp-list__table .rp-list__col-env[b-98aur5rvbf] { width: 15%; }
.rp-list__table .rp-list__col-delivery[b-98aur5rvbf] { width: 19%; }
.rp-list__table .rp-list__col-next[b-98aur5rvbf] { width: 15%; }
.rp-list__table .rp-list__col-source[b-98aur5rvbf] { width: 15%; }
.rp-list__table .rp-list__col-installs[b-98aur5rvbf] { width: 13%; }
.rp-list__table .rp-list__col-actions[b-98aur5rvbf] { width: 56px; }

/* On a narrow page the tabs scroll sideways rather than wrapping their labels. */
.rp-list__tabs[b-98aur5rvbf] { display: flex; min-width: 0; max-width: 100%; overflow-x: auto; }
.rp-list__tabs .pill-tabs[b-98aur5rvbf] { width: max-content; }
.rp-list__tabs .pill-tab[b-98aur5rvbf] { white-space: nowrap; }

.rp-list__name[b-98aur5rvbf] { font-weight: var(--fw-medium); }
.rp-list__quiet[b-98aur5rvbf] { color: inherit; }
.rp-list__prod[b-98aur5rvbf] { color: var(--danger-text); font-weight: var(--fw-semibold); }
.rp-list__strong[b-98aur5rvbf] { font-weight: var(--fw-medium); }
.rp-list__none[b-98aur5rvbf] { color: var(--ink-4); }
/* "Environment not found" is also the way to the fix: the solution's Business Central tab. */
.rp-list__fix[b-98aur5rvbf] { color: var(--danger-text); text-decoration: underline; text-underline-offset: 2px; }

/* A row in flight is tinted as well as keylined: it is the one thing on the page
   that is changing while you look at it. */
.rp-list__table tr.is-running td[b-98aur5rvbf] { background: var(--info-bg); }
/* Nothing deployed yet: no keyline, and the dashed ring stays quiet. */
.rp-list__table tr.rp-list__idle .data-table__state[b-98aur5rvbf] { color: var(--ink-4); }
.rp-list__table tr.is-queued .data-table__state[b-98aur5rvbf] { color: var(--ink-2); }

.rp-list__live[b-98aur5rvbf] { color: var(--info-text); font-weight: var(--fw-semibold); }
.rp-list__live-sub[b-98aur5rvbf] { display: flex; align-items: center; gap: var(--space-2); }
.rp-list__meter[b-98aur5rvbf] { height: 5px; width: 48px; flex: none; }

.rp-list__source[b-98aur5rvbf] { display: flex; align-items: center; gap: var(--space-2); min-width: 0; }
.rp-list__source[b-98aur5rvbf]  .rp-list__source-icon { flex: none; color: var(--ink-3); }

.rp-list__force[b-98aur5rvbf] {
    display: flex;
    align-items: center;
    gap: var(--space-1);
    color: var(--warning-text);
    font-weight: var(--fw-semibold);
}

/* Tones for a word inside a cell. */
.rp-tone--success[b-98aur5rvbf] { color: var(--success-text); }
.rp-tone--danger[b-98aur5rvbf] { color: var(--danger-text); }
.rp-tone--warning[b-98aur5rvbf] { color: var(--warning-text); }
.rp-tone--muted[b-98aur5rvbf] { color: var(--ink-3); }
.rp-tone--ink[b-98aur5rvbf] { color: var(--ink); }
.cell-stack__main.rp-tone--success[b-98aur5rvbf],
.cell-stack__main.rp-tone--danger[b-98aur5rvbf],
.cell-stack__main.rp-tone--muted[b-98aur5rvbf],
.cell-stack__main.rp-tone--ink[b-98aur5rvbf] { font-weight: var(--fw-medium); }

/* ── The phone layout: cards instead of the table, from the sheet's compact
   variant. .page is a size container, so this follows the page's width. ── */
.rp-cards[b-98aur5rvbf] { display: none; }

.rp-card[b-98aur5rvbf] {
    display: grid;
    grid-template-columns: 20px minmax(0, 1fr) auto;
    gap: var(--space-1) var(--space-3);
    padding: var(--space-3);
    border-bottom: 1px solid var(--border);
    border-right: 4px solid transparent;
}
.rp-card:last-child[b-98aur5rvbf] { border-bottom: 0; }
.rp-card.is-running[b-98aur5rvbf] { border-right-color: var(--bar-running); background: var(--info-bg); }
.rp-card.is-failed[b-98aur5rvbf] { border-right-color: var(--bar-failed); }
.rp-card.is-queued[b-98aur5rvbf] { border-right-color: var(--bar-queued); }
.rp-card.is-succeeded[b-98aur5rvbf] { border-right-color: var(--bar-succeeded); }
.rp-card.is-cancelled[b-98aur5rvbf] { border-right-color: var(--bar-cancelled); }
.rp-card.is-draft[b-98aur5rvbf] { border-right-color: var(--bar-draft); }
.rp-card.is-draft .rp-card__state[b-98aur5rvbf] { color: var(--warning-text); }
.rp-card.is-running .rp-card__state[b-98aur5rvbf] { color: var(--info-text); }
.rp-card.is-failed .rp-card__state[b-98aur5rvbf] { color: var(--danger-text); }
.rp-card.is-succeeded .rp-card__state[b-98aur5rvbf] { color: var(--success-text); }
.rp-card.is-queued .rp-card__state[b-98aur5rvbf] { color: var(--ink-2); }
.rp-card.rp-list__idle .rp-card__state[b-98aur5rvbf] { color: var(--ink-4); }

.rp-card__state[b-98aur5rvbf] { padding-top: 2px; }
.rp-card__head[b-98aur5rvbf] { padding: 0; }
.rp-card__name[b-98aur5rvbf] { font-weight: var(--fw-semibold); }
/* A 44px touch target, pulled into the card's padding so it does not push the row. */
.rp-card__menu[b-98aur5rvbf] { width: 44px; height: 44px; margin: -10px -10px 0 0; }
.rp-card__lines[b-98aur5rvbf] { grid-column: 2 / span 2; display: grid; gap: 2px; font-size: var(--text-sm); }
.rp-card__meter[b-98aur5rvbf] { height: 5px; margin: 2px 0; }
.rp-card__outcome[b-98aur5rvbf] { font-weight: var(--fw-medium); }
.rp-card__next[b-98aur5rvbf] { color: var(--ink-2); }
.rp-card__next-when[b-98aur5rvbf] { font-weight: var(--fw-medium); color: var(--ink); }
.rp-card__warn[b-98aur5rvbf] { font-weight: var(--fw-medium); }

@container (max-width: 700px) {
    .rp-list__wide[b-98aur5rvbf] { display: none; }
    .rp-cards[b-98aur5rvbf] {
        display: block;
        background: var(--surface);
        border: 1px solid var(--border);
        border-radius: var(--r);
    }
    /* The tabs get a row of their own and scroll inside it. Without the containment
       their full width becomes the page's minimum and the whole page scrolls sideways. */
    .rp-list__tabs[b-98aur5rvbf] { contain: inline-size; flex: 1 1 100%; }
    .rp-live[b-98aur5rvbf] { grid-template-columns: auto minmax(0, 1fr); }
    .rp-live__open[b-98aur5rvbf] { grid-column: 2; justify-self: start; }
}
/* /Components/Pages/Piper.razor.rz.scp.css */
/* Piper's two-column layout and the few things the design system has no
   component for. Everything else - the card, the pill tabs, the fields, the
   inputs, the checks - comes from the shared layers now (PR 17c). */

.piper-layout[b-mc5t6vyaml] {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 280px;
    gap: var(--space-6);
    align-items: start;
}

.piper-main[b-mc5t6vyaml] {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
    min-width: 0;
}

/* Without align-self the inline-flex pill bar still gets stretched to
   the column-flex parent's cross axis (full width), which feels loose
   next to a 100% textarea. flex-start sizes it to its content. */
.piper-main[b-mc5t6vyaml]  .pill-tabs {
    align-self: flex-start;
}

/* Both boxes hold separated values, which are read column-wise as often as
   left to right - so they get the mono face the rest of the app gives code. */
.piper-main[b-mc5t6vyaml]  .textarea {
    font-family: var(--font-mono);
    font-size: var(--text-sm);
}

/* The settings rail is a .card; what is local is that it follows the page as
   it scrolls, because every control in it re-runs the transform above. */
.piper-settings[b-mc5t6vyaml] {
    position: sticky;
    top: calc(var(--top-h) + var(--space-4));
}

.piper-settings[b-mc5t6vyaml]  .card__title {
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

.piper-settings__body[b-mc5t6vyaml] {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

.piper-meta[b-mc5t6vyaml],
.piper-hint[b-mc5t6vyaml] {
    margin: 0;
}

/* Prefix and suffix are one setting in two halves, so they share a line. */
.piper-wrap-row[b-mc5t6vyaml] {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-1);
}

.piper-hint[b-mc5t6vyaml]  code {
    font-family: var(--font-mono);
    font-size: var(--text-2xs);
    background: var(--surface-sunken);
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    padding: 0 4px;
}

@media (max-width: 900px) {
    .piper-layout[b-mc5t6vyaml] {
        grid-template-columns: 1fr;
    }

    .piper-settings[b-mc5t6vyaml] {
        position: static;
    }
}
/* /Components/Pages/Projects/DependencyDriftPanel.razor.rz.scp.css */
/* The dependency-drift panel on the Solutions page. Structure comes from the
   design system - .card, .btn, .alert - so what is local is the row geometry and
   the small type of the change list, neither of which those carry. */

/* The padding is the panel's own, as on the untracked-repositories panel above it:
   .card is only a shell, and its usual padding comes from .card__head and
   .card__body, which this flat panel does not use. Without it the heading and the
   buttons sat flush against the border. */
.drift[b-6z7v4e6aj0] {
    display: grid;
    gap: var(--space-3);
    margin-bottom: var(--space-4);
    padding: var(--space-4);
}

.drift__head[b-6z7v4e6aj0] {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-3);
    flex-wrap: wrap;
}

.drift__head-actions[b-6z7v4e6aj0] {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex-wrap: wrap;
}

.drift__title[b-6z7v4e6aj0] {
    margin: 0;
    font-size: var(--text-md);
    font-weight: var(--fw-semibold);
    color: var(--ink);
}

.drift__sub[b-6z7v4e6aj0] {
    margin: var(--space-1) 0 0;
    font-size: var(--text-sm);
    color: var(--ink-3);
}

.drift__list[b-6z7v4e6aj0] {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: var(--space-2);
}

.drift__row[b-6z7v4e6aj0] {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-3);
    flex-wrap: wrap;
    padding: var(--space-2) 0;
    border-top: 1px solid var(--border);
}

.drift__repo[b-6z7v4e6aj0] {
    display: grid;
    gap: 2px;
    min-width: 0;
}

.drift__name[b-6z7v4e6aj0] {
    font-weight: var(--fw-medium);
}

.drift__on[b-6z7v4e6aj0],
.drift__file[b-6z7v4e6aj0] {
    font-size: var(--text-xs);
    color: var(--ink-3);
    margin: 0;
}

/* Folded away by default: on a page listing a dozen repositories, what moves in
   each one is the detail somebody opens for the one they are about to bump. */
.drift__what[b-6z7v4e6aj0] {
    font-size: var(--text-xs);
    color: var(--ink-3);
}

.drift__what > summary[b-6z7v4e6aj0] {
    cursor: pointer;
    padding: 2px 0;
}

.drift__changes[b-6z7v4e6aj0] {
    list-style: none;
    margin: 0 0 var(--space-2);
    padding: 0;
    display: grid;
    gap: 2px;
}

.drift__result[b-6z7v4e6aj0] {
    margin: var(--space-1) 0 0;
    font-size: var(--text-xs);
}

.drift__refusal[b-6z7v4e6aj0] {
    margin: var(--space-1) 0 0;
    font-size: var(--text-xs);
    color: var(--danger-text);
}

.drift__actions[b-6z7v4e6aj0] {
    display: flex;
    align-items: center;
    gap: var(--space-2);
}
/* /Components/Pages/Projects/ProjectDetailAccess.razor.rz.scp.css */
/*
    Scoped chrome for the Access tab of the solution settings page. The levels
    are the design system's .module-card selection cards; only the marker and
    the unavailable note are local.
*/

/* The visibility levels are a one-of-three choice, and .module-card's tick is
   square because every other caller of it is a multi-select. Three square ticks
   in a row read as "pick as many as you like", which is the one thing this
   control must not say - so the marker goes round here, the way a radio does
   everywhere else in the app (.check__dot). Nothing else about the card
   changes; it is the same selection card the rest of the app uses. */
.pd-choice .module-card__check[b-zssqz8mjzd] { border-radius: var(--r-pill); }

/* The "needs a team" note on a level the org can't reach yet. .module-card__text
   is the caption line; this is a second one that has to read as a constraint,
   not as more explanation - so it takes the muted-warning ink and sits tight
   under the caption rather than as another paragraph. */
.pd-choice .pd-choice__blocked[b-zssqz8mjzd] { color: var(--ink-4); font-weight: var(--fw-medium); }
/* /Components/Pages/Projects/ProjectDetailBc.razor.rz.scp.css */
/*
    Scoped chrome for the Business Central tab of the solution settings page.

    The tab is the settings archetype - .card + .card__body, .form-sec,
    .form-actions - with the environment list as a .data-table. What is left
    here is what the design system has no opinion about: the update-window
    editor that opens as a table sub-row, the environment panel under it, and
    the setup checklist in the rail.
*/

/* An environment Business Central no longer reports. The row's keyline and
   glyph already say something is wrong; this says what. */
.pd-gone[b-ulmjlayjdg] { margin-left: var(--space-2); font-size: var(--text-xs); color: var(--danger-text); }

/* The environment's BC version, under its status pill - context for the status,
   not a column of its own. */
.pd-env-version[b-ulmjlayjdg] { margin-top: var(--space-1); font-size: var(--text-xs); }

/* What a non-ready status means for the delivery the user came to make. */
.pd-env-note[b-ulmjlayjdg] { margin-top: var(--space-1); font-size: var(--text-xs); }

/* The delivery slot colliding with Microsoft's maintenance hours. A warning tone
   rather than a danger one: the deployment is not broken, it is aimed at a time the
   environment will refuse. Icon plus text, never colour alone. */
.pd-env-note--warn[b-ulmjlayjdg] {
    display: inline-flex;
    align-items: flex-start;
    gap: var(--space-1);
    color: var(--warning-text);
}

/* The environment name opens the environment in Business Central. The icon is
   what says "this leaves the workbench" - a bare underline would read as a link
   to another page in here. */
.pd-env-link[b-ulmjlayjdg] { display: inline-flex; align-items: center; gap: var(--space-1); color: inherit; text-decoration: none; }
.pd-env-link:hover span[b-ulmjlayjdg] { text-decoration: underline; }
.pd-env-link__icon[b-ulmjlayjdg] { color: var(--ink-4); flex: none; }

/* Production is the row to be careful with, not a row with a problem. It takes
   the neutral pill and earns its weight from the type instead of from red -
   red in this table now means the environment itself is in a bad state. */
/* ::deep: the pill is rendered by StatusPill, outside this file's scope. */
[b-ulmjlayjdg] .pd-env-prod { font-weight: var(--fw-semibold); border-color: var(--ink-4); }
[b-ulmjlayjdg] .pd-env-prod .status-pill__dot { background: var(--ink-2); }

/* The environments table scrolls inside its own box rather than widening the
   card. Without this the table's min-content width (status column, and buttons
   that say what they do) grows the settings grid track until the card slides
   under the setup rail and covers the row actions. min-width:0 on the card is
   the half that lets the track shrink; overflow-x is the half that gives the
   table somewhere to go. */
.pd-env-card[b-ulmjlayjdg] { min-width: 0; }
.pd-env-scroll[b-ulmjlayjdg] { overflow-x: auto; }

/* The Business Central tab's main column. .settings__body is a two-column grid
   when the rail is present, so the section's rows have to arrive as one grid
   item; this restates the single-column stack they had under --wide. */
.pd-bc[b-ulmjlayjdg] { display: grid; gap: var(--space-5); align-content: start; min-width: 0; }

/* Whose app registration the solution connects with. */
.pd-reg[b-ulmjlayjdg] { border: 0; margin: 0; padding: 0; display: grid; gap: var(--space-2); }
.pd-reg__opt[b-ulmjlayjdg] { display: inline-flex; align-items: center; gap: var(--space-2); font-size: var(--text-sm); color: var(--ink-2); }

/* The setup note reads as paragraphs, one under the other, whatever the alert's own
   layout does with several children. */
.pd-before[b-ulmjlayjdg] { display: grid; gap: var(--space-2); }
.pd-before p[b-ulmjlayjdg] { margin: 0; }
/* /Components/Pages/Projects/ProjectDetailCustomer.razor.rz.scp.css */
/* Three across, not the sheet's six: a tenant id and a hosting sentence are read and
   copied here, so they wrap in full rather than ending in an ellipsis. */
.cust__grid[b-tszpbimpk4] { grid-template-columns: repeat(3, minmax(0, 1fr)); row-gap: var(--space-4); }
.cust__grid .meta-item__value[b-tszpbimpk4] { white-space: normal; overflow: visible; text-overflow: clip; overflow-wrap: anywhere; }
.cust__url[b-tszpbimpk4] { margin: var(--space-4) 0 0; overflow-wrap: anywhere; }

/* The version and address Business Central reported, in the editor where the inputs
   would be: read, not typed, so plain text on the field's baseline. */
.cust__fixed[b-tszpbimpk4] { display: block; padding: var(--space-2) 0; overflow-wrap: anywhere; }
/* /Components/Pages/Projects/ProjectDetailGeneral.razor.rz.scp.css */
/*
    Scoped chrome for the General tab of the solution settings page.
*/

/* The destructive setting at the foot of General. .setting is a two-column grid
   built for a .setting-list inside a card body; here it is the card's only row,
   so the card supplies no body of its own and the row's bottom rule is dead.
   No .card--danger either: .setting--danger already tints the row and draws the
   keyline, and a red border under a red fill is a second telling of one fact.

   The columns are re-proportioned for the same reason. The archetype's 260px
   label column is sized for a *list* of rows, where the neighbours fill the
   wide control column and the labels line up down the page; the handoff's own
   danger rows (PageSettings.dc.html) sit in a .setting-list and hold a select
   plus a button. Alone in a full-width card the 260px column wrapped a
   two-sentence hint into a narrow ribbon and left three quarters of the row
   empty beside one button. Flipping to 1fr + auto gives the hint the line
   length it was written for and puts the button at the row's end, where a
   setting's control belongs. ::deep because the row is rendered by SettingRow,
   so the markup carries that component's scope, not this one's. */
.pd-danger[b-i61eprrkuz] { overflow: hidden; }
.pd-danger[b-i61eprrkuz]  .setting { grid-template-columns: minmax(0, 1fr) auto; border-bottom: 0; }
@container (max-width: 720px) { .pd-danger[b-i61eprrkuz]  .setting { grid-template-columns: minmax(0, 1fr); } }
/* /Components/Pages/Projects/ProjectDetailPipelines.razor.rz.scp.css */
/*
    Scoped chrome for the Pipelines tab of the solution settings page. The list
    is the design system's .sub-rows; only the row's "this is a link" affordance
    is local.
*/

/* A whole-row link into the Pipelines tool. The chevron is the affordance that
   says so - .sub-row is normally an editor row, not a link. */
.pd-pipe[b-rm05gcd1gs] { text-decoration: none; color: inherit; }
.pd-pipe:hover .sub-row__name[b-rm05gcd1gs] { color: var(--primary-ink); }
.pd-pipe__chev[b-rm05gcd1gs] { color: var(--ink-4); flex: none; }
/* /Components/Pages/Projects/ProjectDetailRepositories.razor.rz.scp.css */
/*
    Scoped chrome for the Repositories tab of the solution settings page. The tab
    is the settings archetype - .card + .card__body, the list as a .data-table
    inside .row-editor - so what is left here is the two things the design system
    has no opinion about: a read-only URL cell, and the GitHub picker's rule.
*/

/* A read-only repository URL in the repositories table. The system has no
   mono utility - .u-num is numerics only - and .sub-row__val, which would fit,
   belongs to a component this cell is not part of. */
.pd-url[b-bwz4umms6h] { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--ink-2); overflow-wrap: anywhere; }

/* The GitHub picker at the top of the repositories card, ruled off from the
   list it adds to so the two read as "pick one" and "the ones you picked"
   rather than as one long form. */
.pd-repo-pick[b-bwz4umms6h] {
    display: grid;
    gap: var(--space-2);
    padding-bottom: var(--space-4);
    margin-bottom: var(--space-4);
    border-bottom: 1px solid var(--border);
}

.pd-repo-pick__note[b-bwz4umms6h] { margin: 0; }

/* The table is fixed-layout, so without widths every column gets an equal
   share and the two link buttons stack under each other while the URL is
   cut short. Host, name and links get what they need; the URL takes the rest. */
.pd-repo-col-host[b-bwz4umms6h] { width: 170px; }
.pd-repo-col-name[b-bwz4umms6h] { width: 200px; }
.pd-repo-col-links[b-bwz4umms6h] { width: 360px; }

/* Those widths leave the URL nothing on a narrow screen, so below the width
   they need the table scrolls sideways inside its card instead. */
.pd-repo-table-wrap[b-bwz4umms6h] { overflow-x: auto; }
.pd-repo-table-wrap > .row-editor__table[b-bwz4umms6h] { min-width: 1000px; }

/* Open on the host and Clone in VS Code, side by side in a row's links cell. */
.pd-repo-links[b-bwz4umms6h] { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.pd-repo-links .btn[b-bwz4umms6h] { white-space: nowrap; }

/* Where the buttons will be once a new or changed row is saved, lined up
   with the inputs beside it. */
.pd-repo-links__pending[b-bwz4umms6h] { display: block; padding-top: var(--space-1); }
/* /Components/Pages/Projects/ProjectDetailSymbols.razor.rz.scp.css */
/*
    Scoped chrome for the Symbols tab of the solution settings page. The list is
    the design system's .sub-rows; only the upload dialog's file line is local,
    drawn the way the environment page's upload dialog draws its own.
*/

.pd-sym__file[b-rpvcnjoy2k] {
    margin: var(--space-3) 0 0;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3);
    font-size: var(--text-sm);
}

.pd-sym__chosen[b-rpvcnjoy2k] {
    margin: var(--space-3) 0 0;
    padding-left: var(--space-5);
    font-family: var(--font-mono);
    font-size: var(--text-sm);
    color: var(--ink-2);
}
/* /Components/Pages/Projects/ProjectsBrowser.razor.rz.scp.css */
/*
    Scoped chrome for the Projects directory.

    The page is the list archetype's .data-table--edge; the only thing the
    design system has no opinion about is the locked row - a private project
    the viewer is not on the team for. See .design/teams-and-visibility.md.
*/

/* Greyed and inert: the row carries the project's name so it does not simply
   vanish from the list, and nothing else, because owner / status / counts all
   report activity on the customer. The name is a plain span, not a link -
   there is nothing behind it for this viewer. */
.projects__locked td[b-con1j7qv7o] { color: var(--ink-3); }
.sol-list__locked-name[b-con1j7qv7o] { display: inline-flex; align-items: center; gap: var(--space-2); }
.sol-list__locked-name[b-con1j7qv7o]  svg { color: var(--ink-4); }

/* The row is the selector. Its first cell holds an empty link whose ::after covers the
   whole row, so a click anywhere on it opens the customer info; the name and the
   "Last shipped" date are lifted above that cover and keep their own destinations.
   Two separate links, never one inside the other - nested anchors are invalid HTML
   and browsers split them apart. */
.sol-list__row[b-con1j7qv7o] { position: relative; }
.sol-list__select[b-con1j7qv7o]::after { content: ""; position: absolute; inset: 0; cursor: pointer; }
/* The cover has no box of its own, so its focus ring is drawn on the row it covers. */
.sol-list__select:focus-visible[b-con1j7qv7o] { outline: none; }
.sol-list__select:focus-visible[b-con1j7qv7o]::after { box-shadow: inset 0 0 0 2px var(--focus-color); }
.sol-list__name[b-con1j7qv7o],
.sol-list__shipped[b-con1j7qv7o] { position: relative; z-index: 1; }

/* .sol-list__short lives in app.css: the Upgrades page shows the short name the same way (#966). */

.sol-list__shipped[b-con1j7qv7o] { display: inline-flex; align-items: center; gap: var(--space-1); }
/* Handed off: Business Central has the apps but installs them in a later window, so it
   is shipped but not yet seen installed. The date stays a link like any other; the glyph
   and the words after it are a step quieter, and say it without a hover. */
.sol-list__shipped--handed-off[b-con1j7qv7o]  svg,
.sol-list__shipped-note[b-con1j7qv7o] { color: var(--ink-3); }
.sol-list__shipped-note[b-con1j7qv7o] { font-size: var(--text-sm); }

/* The customer summary beside the list. 280px wide, so everything wraps in full - a
   phone number or an address cut off with an ellipsis is no use on a call. */
.sol-rail[b-con1j7qv7o] { display: grid; gap: var(--space-3); }
.sol-rail__name[b-con1j7qv7o] { overflow-wrap: anywhere; }
.sol-rail__body[b-con1j7qv7o] { display: grid; gap: var(--space-3); }
.sol-rail__value[b-con1j7qv7o] { overflow-wrap: anywhere; }
.sol-rail__text[b-con1j7qv7o] { margin: 0; white-space: pre-wrap; overflow-wrap: anywhere; }
.sol-rail__item[b-con1j7qv7o] { display: grid; gap: 2px; overflow-wrap: anywhere; }
.sol-rail__strong[b-con1j7qv7o] { font-weight: var(--fw-semibold); color: var(--ink); }
.sol-rail__version[b-con1j7qv7o] { font-family: var(--font-mono); font-size: var(--text-sm); }
.sol-rail__foot[b-con1j7qv7o] { margin: 0; font-size: var(--text-sm); }
/* /Components/Pages/Projects/UntrackedRepositoriesPanel.razor.rz.scp.css */
/* The untracked-repositories panel above the Solutions list. Everything
   structural comes from the design system - .card, .btn, .field, .input,
   .loading-block, .alert - so what is local here is only the row geometry a
   short offer list needs and that none of those carry. */

/* The padding is the panel's own: .card is only a shell, and its usual padding comes
   from .card__head and .card__body, which this flat panel does not use. Without it
   the heading and the button sat flush against the border. */
.untracked-repos[b-im6hoxh1jk] {
    display: grid;
    gap: var(--space-3);
    margin-bottom: var(--space-4);
    padding: var(--space-4);
}

.untracked-repos__head[b-im6hoxh1jk] {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-3);
    flex-wrap: wrap;
}

.untracked-repos__title[b-im6hoxh1jk] {
    margin: 0;
    font-size: var(--text-md);
    font-weight: var(--fw-semibold);
    color: var(--ink);
}

.untracked-repos__sub[b-im6hoxh1jk],
.untracked-repos__none[b-im6hoxh1jk] {
    margin: var(--space-1) 0 0;
    font-size: var(--text-sm);
    color: var(--ink-3);
}

.untracked-repos__list[b-im6hoxh1jk] {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: var(--space-2);
}

.untracked-repos__row[b-im6hoxh1jk] {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-3);
    flex-wrap: wrap;
    padding: var(--space-2) 0;
    border-top: 1px solid var(--border);
}

.untracked-repos__repo[b-im6hoxh1jk] {
    display: grid;
    gap: 2px;
    min-width: 0;
}

.untracked-repos__name[b-im6hoxh1jk] {
    font-weight: var(--fw-medium);
}

.untracked-repos__app[b-im6hoxh1jk] {
    font-size: var(--text-xs);
    color: var(--ink-3);
}

.untracked-repos__actions[b-im6hoxh1jk] {
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

/* The confirm step sits in the row it belongs to rather than in a dialog: it is
   two fields, and moving them into an overlay would hide the repository they
   are about. */
.untracked-repos__form[b-im6hoxh1jk] {
    display: grid;
    gap: var(--space-2);
    min-width: 260px;
}

/* The re-check button and the line saying it also happens on its own. */
.untracked-repos__check[b-im6hoxh1jk] {
    display: grid;
    justify-items: end;
    gap: 2px;
}

/* "{repo} hidden. Undo" - a line that replaces the row it undoes, so it sits
   where the row was rather than as a banner at the top of the panel. */
.untracked-repos__hidden[b-im6hoxh1jk] {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--text-sm);
    color: var(--ink-3);
}
/* /Components/Pages/RecipeDetail.razor.rz.scp.css */
/* Recipe detail — archetype 3 (master-detail), laid out like /pipelines/{id}:
   .detail-head for the title row and its actions, .detail-body for the content
   plus its factbox rail, .card / .meta-item for the facts, .code-block for each
   file. What's left here is the page's own trimmings and the two things the
   handoff's code block doesn't do: collapse, and line numbers. */

/* .detail-head is a flex row (title block | actions). The title block is the
   part that stacks, and it has to be allowed to shrink so a long recipe title
   wraps instead of shoving the download button off the edge. */
.rd-head[b-ctpmp6sjjc] {
    min-width: 0;
    display: grid;
    gap: var(--space-2);
}

.rd-desc[b-ctpmp6sjjc] {
    margin: 0;
    font-size: var(--text-base);
    color: var(--ink-2);
    line-height: var(--leading-normal);
    max-width: 76ch;
    text-wrap: pretty;
    /* Typed into a textarea; keep the author's line breaks. */
    white-space: pre-line;
}

.rd-tags[b-ctpmp6sjjc] {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1);
}

/* Release names are sentences ("Business Central 2024 release wave 2"), and
   .meta-item__value ellipsises on one line. These values earn two. */
.rd-meta-wrap[b-ctpmp6sjjc] {
    white-space: normal;
    overflow: visible;
    line-height: var(--leading-tight);
}

/* The qualifier under a meta value — the exact app version, or what the hours
   are for. Visible, because it used to be a title attribute. */
.rd-meta-sub[b-ctpmp6sjjc] {
    display: block;
    margin-top: 2px;
    font-size: var(--text-2xs);
    color: var(--ink-4);
}

/* ---------- factbox rail ---------- */

.rd-facts[b-ctpmp6sjjc] {
    display: grid;
    gap: var(--space-3);
}

/* ---------- sections ---------- */

/* minmax(0, 1fr), not the implicit `auto` column: a grid's auto track is sized
   to its content's MIN-content, and an unwrapped code line's min-content is its
   full width. One long AL procedure signature once stretched this section past
   its column and off the right edge, where `.app__content`'s
   `overflow-x: hidden` clipped it. Letting the track shrink puts the scrolling
   back in the code viewer. */
.rd-sec[b-ctpmp6sjjc] {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-3);
}

.rd-sec__head[b-ctpmp6sjjc] {
    display: flex;
    align-items: baseline;
    gap: var(--space-2);
}

.rd-sec__note[b-ctpmp6sjjc] {
    font-size: var(--text-xs);
    color: var(--ink-4);
    font-variant-numeric: tabular-nums;
}

.rd-prose[b-ctpmp6sjjc] {
    font-size: var(--text-base);
    color: var(--ink-2);
    line-height: var(--leading-normal);
    max-width: 76ch;
}

.rd-prose[b-ctpmp6sjjc]  :first-child {
    margin-top: 0;
}

.rd-prose[b-ctpmp6sjjc]  :last-child {
    margin-bottom: 0;
}

.rd-prose[b-ctpmp6sjjc]  code {
    font-family: var(--font-mono);
    font-size: var(--text-xs);
    background: var(--surface-sunken);
    border: 1px solid var(--border);
    border-radius: var(--r-badge);
    padding: 1px 5px;
}

/* The stand-in when a recipe ships no write-up. Same weight as the Files
   section's empty state: a quiet line, not an empty-state card - there is
   nothing here for the reader to do about it. */
/* Markdown can carry a fenced code block, a wide table or a long URL. Left
   alone they spill out of the column and under the rail; scroll or break them. */
.rd-prose[b-ctpmp6sjjc] {
    overflow-wrap: anywhere;
}

.rd-prose[b-ctpmp6sjjc]  pre,
.rd-prose[b-ctpmp6sjjc]  table {
    display: block;
    max-width: 100%;
    overflow-x: auto;
}

.rd-prose--muted[b-ctpmp6sjjc] {
    margin: 0;
    color: var(--ink-3);
}

/* Collapsed to one column the rail lands after the files it describes, which
   buries the facts a reader wants first. Ordering it above the content is what the FactBox does on a narrow
   Business Central page, and it beats the old rule here, which hid the rail
   outright - the facts have to survive. The breakpoint is .detail-body's own. */
@container (max-width: 1080px) {
    .detail-body__aside[b-ctpmp6sjjc] {
        order: -1;
    }
}

/* The second way out of the dialog (issue #626): commit the recipe into a
   repository instead of downloading it. Ruled off from the customer field above
   because it is an alternative to the download, not another of its settings. */
.rd-repo[b-ctpmp6sjjc] {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    margin-top: var(--space-4);
    padding-top: var(--space-4);
    border-top: 1px solid var(--border);
    align-items: flex-start;
}
/* /Components/Pages/SiteAdmin/SiteAdminBackups.razor.rz.scp.css */
/* Each row action posts its own form; keep them on one line instead of
   stacking one per line, which made the Actions column a tall column of
   buttons. */
.data-table__actions form[b-3n1n95gs83] { display: inline-block; }
.data-table__actions form + form[b-3n1n95gs83],
.data-table__actions a + form[b-3n1n95gs83],
.data-table__actions form + .u-muted[b-3n1n95gs83] { margin-left: var(--space-2); }
/* Captions set as a card body paragraph keep the card padding only, not the
   paragraph margin on top of it. */
p.card__body[b-3n1n95gs83] { margin: 0; }
/* /Components/Pages/SiteAdmin/SiteAdminEmailPreviews.razor.rz.scp.css */
/* Email list beside the selected preview; the two parts of an email side by
   side once there is room for the 560px email next to its text. */
.email-previews[b-qexzyvjrc3] { display: grid; grid-template-columns: 260px minmax(0, 1fr); gap: var(--space-4); align-items: start; }
@container (max-width: 900px) { .email-previews[b-qexzyvjrc3] { grid-template-columns: minmax(0, 1fr); } }

.email-previews__list[b-qexzyvjrc3] { display: flex; flex-direction: column; padding: var(--space-2); gap: 2px; }
.email-previews__item[b-qexzyvjrc3] { display: flex; flex-direction: column; gap: 2px; padding: var(--space-2) var(--space-3); border-left: 2px solid transparent; border-radius: var(--r-control); color: var(--ink-2); text-decoration: none; }
.email-previews__item:hover[b-qexzyvjrc3] { background: var(--surface-2); }
.email-previews__item.is-active[b-qexzyvjrc3] { border-left-color: var(--primary); background: var(--primary-weak); color: var(--primary-ink); }
.email-previews__name[b-qexzyvjrc3] { font-size: var(--text-sm); font-weight: var(--fw-medium); }
.email-previews__when[b-qexzyvjrc3] { font-size: var(--text-xs); color: var(--ink-3); }

.email-previews__view > :not(.card__head)[b-qexzyvjrc3] { margin: var(--space-4); }
.email-previews__subject[b-qexzyvjrc3] { display: flex; gap: var(--space-3); font-size: var(--text-sm); }
.email-previews__subject dt[b-qexzyvjrc3] { color: var(--ink-3); }
.email-previews__subject dd[b-qexzyvjrc3] { margin: 0; font-weight: var(--fw-medium); color: var(--ink); }

.email-previews__parts[b-qexzyvjrc3] { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--space-4); }
@container (min-width: 1400px) { .email-previews__parts[b-qexzyvjrc3] { grid-template-columns: minmax(600px, 1.3fr) minmax(0, 1fr); } }
.email-previews__frame[b-qexzyvjrc3] { display: block; width: 100%; height: 640px; border: 0; border-radius: 0 0 var(--r) var(--r); background: var(--surface); }
.email-previews__text[b-qexzyvjrc3] { white-space: pre-wrap; overflow-wrap: anywhere; }
/* /Components/Pages/SiteAdmin/SiteAdminTenantBackups.razor.rz.scp.css */
/* One header row per organisation in the off-site snapshot list, so the
   newest snapshots of each read as a group rather than a long run of rows. */
.data-table__group th[b-jcll1r298z] {
    background: var(--surface-2);
    text-align: left;
    font-weight: var(--fw-medium);
}
.data-table__group .tag[b-jcll1r298z] { margin-left: var(--space-2); }
/* Each row action posts its own form; keep them on one line instead of
   stacking one per line, which made the Actions column a tall column of
   buttons. */
.data-table__actions form[b-jcll1r298z] { display: inline-block; }
.data-table__actions form + form[b-jcll1r298z],
.data-table__actions a + form[b-jcll1r298z],
.data-table__actions form + .u-muted[b-jcll1r298z] { margin-left: var(--space-2); }
/* Put the off-site Refresh button at the end of its heading row, where the
   Whole site tab has it. */
.card header.u-row[b-jcll1r298z] { justify-content: space-between; }
/* /Components/Pages/Translator.razor.rz.scp.css */
/* Translator — page archetype 9 (translation grid).

   The frame, the grid, the panes, the progress ribbon and the keycaps all come
   from pages-power.css; the controls come from components.css. What is left
   here is the part of this tool the design system has no counterpart for: the
   first-run drop target, the focused editor rail (source box, state picker,
   memory suggestions and their votes) and the list view's three-line row.

   Tokens only. The old copy of this file declared its own four-colour XLIFF
   ramp on .tr-page, which shadowed the design system's --st-* / --bar-* tokens
   for the whole subtree; the states are the system's now. */

/* ── First run ──────────────────────────────────────────────────────────── */

.tdrop[b-pg98q3zrne] {
    position: relative;
    display: grid;
    justify-items: center;
    gap: var(--space-3);
    min-height: 260px;
    align-content: center;
    padding: var(--space-8) var(--space-5);
    border: 2px dashed var(--border-strong);
    border-radius: var(--r-lg);
    background: var(--surface);
    text-align: center;
}
/* The whole panel is the drop target; Translator.razor.js toggles is-over. */
.tdrop.is-over[b-pg98q3zrne] { border-color: var(--primary); background: var(--primary-weak); }

/* Both paths end in the same control: on browsers that can save in place it is
   a <button> that opens the picker, elsewhere a <label> over a transparent file
   input. Both wear .btn.btn--primary, so the panel has one obvious next step
   instead of a bold line of text that happens to be clickable. */
.tdrop__btn[b-pg98q3zrne], .tdrop__label[b-pg98q3zrne] { margin-top: var(--space-2); }
/* `position: static` on purpose, overriding the `position: relative` every
   `.btn` carries for its loading spinner. The transparent file input inside
   this label is `position: absolute; inset: 0` and is meant to cover the dashed
   PANEL, not the button, so its containing block has to be `.tdrop`. A static
   label is also not in that chain, so it does not clip the input either. */
.tdrop__label[b-pg98q3zrne] { position: static; }
.tdrop__icon[b-pg98q3zrne] {
    display: grid;
    place-items: center;
    width: 46px;
    height: 46px;
    margin-bottom: var(--space-2);
    border-radius: var(--r);
    background: var(--primary-weak);
    color: var(--primary-ink);
}
.tdrop__title[b-pg98q3zrne] { font-size: var(--text-md); font-weight: var(--fw-semibold); color: var(--ink); }
.tdrop__title code[b-pg98q3zrne] { font-family: var(--font-mono); font-size: var(--text-sm); }
.tdrop__hint[b-pg98q3zrne] { font-size: var(--text-sm); color: var(--ink-3); }
/* The file input covers the whole dashed panel at zero opacity, so the panel
   IS the click target and the browser's own "Choose File / No file chosen"
   chrome never shows. ::deep because <InputFile> renders the <input>, which
   means it does not carry this page's scope attribute -- a plain
   `.tdrop__input` rule here matches nothing and the native "Choose File / No
   file chosen" chrome appears. Not a regression: the pre-port rule had the same
   shape and the same hole. It went unseen because this branch only renders on a
   browser WITHOUT the File System Access API -- Firefox and Safari, neither of
   which anyone had shot. */
.tdrop[b-pg98q3zrne]  .tdrop__input {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    margin: 0;
    padding: 0;
    opacity: 0;
    cursor: pointer;
}
/* There used to be a `position: fixed` override here, to get the input out of
   the label's containing block so it could cover the whole dashed panel. It
   escaped too far: `fixed` + `inset: 0` is the VIEWPORT, so a transparent file
   input covered the entire app and every click anywhere - the sidebar included
   - opened a file dialog instead. Invisible in development, because this branch
   only renders without the File System Access API, which means Firefox, Safari,
   or ANY deployment served over plain HTTP. Dropping `position: relative` from
   the label above fixes it properly: the input's containing block is now
   `.tdrop`, which is what "cover the panel" meant all along. */
.tdrop__aside[b-pg98q3zrne] { max-width: 58ch; margin: var(--space-2) 0 0; font-size: var(--text-xs); color: var(--ink-4); text-wrap: pretty; }
.tdrop__note[b-pg98q3zrne] { margin: 0; font-size: var(--text-sm); color: var(--ink-3); }
.tdrop__note--error[b-pg98q3zrne] { display: inline-flex; align-items: center; gap: var(--space-1); color: var(--danger-text); }

/* ── Open from a repository (issue #625) ────────────────────────────────── */
/* A plain card under the drop panel rather than a second dashed target: the
   upload is still the way in, and this one is a list you read before you pick
   from it. Left-aligned for the same reason - the drop panel centres because
   it is one gesture, this has a picker, a paragraph and a list. */
.trepo[b-pg98q3zrne] {
    display: grid;
    gap: var(--space-3);
    margin-top: var(--space-4);
    padding: var(--space-5);
    border: 1px solid var(--border);
    border-radius: var(--r-lg);
    background: var(--surface);
}
.trepo__head[b-pg98q3zrne] { display: flex; gap: var(--space-3); align-items: flex-start; }
.trepo__icon[b-pg98q3zrne] {
    display: grid;
    place-items: center;
    flex: none;
    width: 34px;
    height: 34px;
    border-radius: var(--r);
    background: var(--surface-2);
    color: var(--ink-3);
}
.trepo__title[b-pg98q3zrne] { font-size: var(--text-md); font-weight: var(--fw-semibold); color: var(--ink); }
.trepo__sub[b-pg98q3zrne] { max-width: 68ch; margin: var(--space-1) 0 0; font-size: var(--text-sm); color: var(--ink-3); text-wrap: pretty; }
.trepo__sub code[b-pg98q3zrne] { font-family: var(--font-mono); font-size: var(--text-xs); }

.trepo__files[b-pg98q3zrne] { display: grid; gap: 2px; margin: 0; padding: 0; list-style: none; }
/* The extension the Translations folder belongs to. Two extensions in one
   repository can both have a da-DK file, so the name alone is not enough. */
.trepo__group[b-pg98q3zrne] {
    padding: var(--space-2) var(--space-2) var(--space-1);
    font-family: var(--font-mono);
    font-size: var(--text-xs);
    color: var(--ink-4);
}
.trepo__group:not(:first-child)[b-pg98q3zrne] { margin-top: var(--space-2); border-top: 1px solid var(--border); }
/* A row is one file you open. The leading icon and the trailing chevron are
   what say so without a caption explaining that the row is clickable. */
.trepo__file[b-pg98q3zrne] {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    width: 100%;
    padding: var(--space-2) var(--space-3);
    border: 1px solid transparent;
    border-radius: var(--r);
    background: none;
    text-align: left;
    cursor: pointer;
}
.trepo__file:hover:not(:disabled)[b-pg98q3zrne] { border-color: var(--border); background: var(--surface-2); }
.trepo__file:disabled[b-pg98q3zrne] { opacity: 0.55; cursor: default; }
.trepo__file-icon[b-pg98q3zrne], .trepo__file-go[b-pg98q3zrne] { display: grid; place-items: center; flex: none; color: var(--ink-4); }
.trepo__file-go[b-pg98q3zrne] { opacity: 0.5; }
.trepo__file:hover:not(:disabled) .trepo__file-go[b-pg98q3zrne] { opacity: 1; color: var(--primary-ink); }
.trepo__file-text[b-pg98q3zrne] { display: grid; gap: 1px; flex: 1; min-width: 0; }
.trepo__file-name[b-pg98q3zrne] { font-family: var(--font-mono); font-size: var(--text-sm); color: var(--ink); }
.trepo__file-sub[b-pg98q3zrne] { font-size: var(--text-xs); color: var(--ink-4); }

/* ── Head ───────────────────────────────────────────────────────────────── */

/* .pw__file is a span in the design system; ours is the rename affordance, so
   it needs a button's reset and a hover that says "this is clickable". */
.tr-rename[b-pg98q3zrne] {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    max-width: 30ch;
    padding: 2px var(--space-1);
    background: none;
    border: 1px solid transparent;
    border-radius: var(--r-control);
    cursor: pointer;
}
.tr-rename:hover[b-pg98q3zrne] { background: var(--surface-sunken); color: var(--ink-2); border-color: var(--border); }
.tr-rename:focus-visible[b-pg98q3zrne] { outline: var(--focus-ring); outline-offset: var(--focus-offset); }
/* ::deep throughout: <Icon> is a child component, so its <svg> carries Icon's
   scope attribute rather than this page's. */
.tr-rename[b-pg98q3zrne] >  svg { flex: none; color: var(--ink-4); }
.tr-rename--input[b-pg98q3zrne] {
    min-width: 26ch;
    height: var(--control-h);
    background: var(--input-bg);
    border-color: var(--input-border);
    color: var(--ink);
    cursor: text;
}

/* Same dot the design system puts on a dirty file tab (.ftab--dirty). */
.tr-dirty[b-pg98q3zrne] { width: 6px; height: 6px; flex: none; border-radius: var(--r-pill); background: var(--primary); }

.tr-langs[b-pg98q3zrne] { display: inline-flex; align-items: center; gap: var(--space-2); flex: none; }
.tr-langs[b-pg98q3zrne] >  svg { color: var(--ink-4); flex: none; }
.tr-flag[b-pg98q3zrne] {
    display: inline-grid;
    place-items: center;
    height: 18px;
    padding: 0 6px;
    border-radius: 3px;
    background: var(--surface-sunken);
    border: 1px solid var(--border);
    font-family: var(--font-mono);
    font-size: var(--text-2xs);
    font-weight: var(--fw-semibold);
    letter-spacing: .04em;
    color: var(--ink-3);
}
/* ::deep: the wrapper is rendered by SelectBox, outside this file's scope. */
[b-pg98q3zrne] .tr-langsel { width: 18ch; flex: none; }

/* ── Toolbar ────────────────────────────────────────────────────────────── */

[b-pg98q3zrne] .tr-kindsel { width: 13ch; flex: none; }

/* The elastic control: it absorbs the slack when the bar is wide and gives it
   back before anything wraps. */
.tr-search[b-pg98q3zrne] { position: relative; flex: 1 1 160px; min-width: 120px; max-width: 320px; }
.tr-search[b-pg98q3zrne] >  svg { position: absolute; left: var(--space-2); top: 50%; transform: translateY(-50%); width: 14px; height: 14px; color: var(--ink-4); pointer-events: none; z-index: 1; }
.tr-search .input[b-pg98q3zrne] { padding-left: calc(var(--space-2) * 2 + 14px); }

/* ── List view: units pane + editor rail ────────────────────────────────── */

.tr-split[b-pg98q3zrne] {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 4px var(--tr-rail, 420px);
    min-height: 0;
    min-width: 0;
}
.tr-split > .pane + .pw-split + .pane[b-pg98q3zrne] { border-left: 1px solid var(--border); }

/* The grip that makes the 4px handle findable moved to pages-power.css in PR
   14b, when the Object Explorer became the second power tool to need it. Only
   the hover fill stays here - the handoff's own rule goes to --primary, which
   is right for a tool with one split and loud for a tool with two. */
.pw-split:hover[b-pg98q3zrne], .pw-split:focus-visible[b-pg98q3zrne] { background: var(--border-strong); }

/* Three lines per unit: what it is, the source, the translation so far. A
   .trow would clip all three to one line, which is right for the grid's fast
   pass and wrong here, where the point is to read the string. */
.tr-urow[b-pg98q3zrne] {
    display: grid;
    grid-template-columns: 3px minmax(0, 1fr);
    align-items: stretch;
    width: 100%;
    padding: 0;
    background: var(--surface);
    border: 0;
    border-bottom: 1px solid var(--border);
    text-align: left;
    font-family: var(--font-sans);
    cursor: pointer;
}
.tr-urow:hover[b-pg98q3zrne] { background: var(--surface-2); }
.tr-urow:focus-visible[b-pg98q3zrne] { outline: var(--focus-ring); outline-offset: -2px; }
.tr-urow.is-selected[b-pg98q3zrne] { background: var(--primary-weak); }
/* Same leading keyline as .trow, from the same tokens. */
.tr-urow__edge[b-pg98q3zrne] { background: var(--bar-unchanged); }
/* The glyph takes the state colour the same way the grid's does. ::deep because
   the glyph is RowStateIcon's markup, not ours. */
.tr-urow.is-untranslated[b-pg98q3zrne]  .data-table__state { color: var(--st-untrans-text); }
.tr-urow.is-fuzzy[b-pg98q3zrne]         .data-table__state { color: var(--st-fuzzy-text); }
.tr-urow.is-translated[b-pg98q3zrne]    .data-table__state { color: var(--st-trans-text); }
.tr-urow.is-final[b-pg98q3zrne]         .data-table__state { color: var(--st-final-text); }
.tr-urow.is-untranslated .tr-urow__edge[b-pg98q3zrne] { background: var(--bar-untranslated); }
.tr-urow.is-fuzzy        .tr-urow__edge[b-pg98q3zrne] { background: var(--bar-fuzzy); }
.tr-urow.is-translated   .tr-urow__edge[b-pg98q3zrne] { background: var(--bar-translated); }
.tr-urow.is-final        .tr-urow__edge[b-pg98q3zrne] { background: var(--bar-final); }

.tr-urow__body[b-pg98q3zrne] { display: grid; gap: 3px; min-width: 0; padding: var(--space-2) var(--space-3); }
.tr-urow__meta[b-pg98q3zrne] { display: flex; align-items: center; gap: var(--space-2); min-width: 0; }
.tr-urow__st[b-pg98q3zrne] { display: inline-flex; flex: none; }
.tr-urow__src[b-pg98q3zrne] { font-size: var(--text-sm); color: var(--ink); text-wrap: pretty; }
.tr-urow__tgt[b-pg98q3zrne] { font-size: var(--text-sm); color: var(--ink-3); text-wrap: pretty; }
.tr-urow__tgt--empty[b-pg98q3zrne] { color: var(--ink-4); font-style: italic; }

.tr-kind[b-pg98q3zrne] {
    flex: none;
    padding: 0 5px;
    border-radius: 3px;
    background: var(--surface-sunken);
    color: var(--ink-4);
    font-size: var(--text-2xs);
    font-weight: var(--fw-semibold);
    letter-spacing: .05em;
    text-transform: uppercase;
}
.tr-id[b-pg98q3zrne] {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-family: var(--font-mono);
    font-size: var(--text-2xs);
    color: var(--ink-4);
}

/* ── Editor rail ────────────────────────────────────────────────────────── */

.tr-srcbox[b-pg98q3zrne] {
    margin: 0 var(--space-3);
    padding: var(--space-2) var(--space-3);
    border-radius: var(--r-control);
    background: var(--surface-sunken);
    font-size: var(--text-base);
    line-height: var(--leading-normal);
    color: var(--ink);
    text-wrap: pretty;
    /* Long AL strings; the rail is not where you scroll horizontally. */
    overflow-wrap: anywhere;
}
.tr-unitid[b-pg98q3zrne] { padding: var(--space-1) var(--space-3) 0; font-family: var(--font-mono); font-size: var(--text-2xs); color: var(--ink-4); overflow-wrap: anywhere; }
.tr-notebox[b-pg98q3zrne] {
    margin: var(--space-2) var(--space-3) 0;
    padding: var(--space-2) var(--space-3);
    border-left: 2px solid var(--border-strong);
    font-size: var(--text-xs);
    color: var(--ink-3);
    text-wrap: pretty;
    overflow-wrap: anywhere;
}

.tr-tgtwrap[b-pg98q3zrne] { display: grid; gap: var(--space-2); padding: 0 var(--space-3); }
.tr-tgtarea[b-pg98q3zrne] { min-height: 108px; font-size: var(--text-base); }

.tr-statepick[b-pg98q3zrne] { display: flex; gap: var(--space-1); flex-wrap: wrap; }
.tr-statebtn.is-fuzzy[b-pg98q3zrne]  .data-table__state { color: var(--st-fuzzy-text); }
.tr-statebtn[b-pg98q3zrne] {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    height: var(--control-h);
    padding: 0 var(--space-2);
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-control);
    color: var(--ink-3);
    font-family: var(--font-sans);
    font-size: var(--text-xs);
    cursor: pointer;
}
.tr-statebtn:hover[b-pg98q3zrne] { border-color: var(--border-strong); color: var(--ink); }
.tr-statebtn:focus-visible[b-pg98q3zrne] { outline: var(--focus-ring); outline-offset: var(--focus-offset); }
/* The glyph carries the state colour whether or not the button is the active
   one, so the picker reads as a legend as well as a control. ::deep because
   RowStateIcon is a child component with its own scope. */
.tr-statebtn.is-untranslated[b-pg98q3zrne]  .data-table__state { color: var(--st-untrans-text); }
.tr-statebtn.is-translated[b-pg98q3zrne]    .data-table__state { color: var(--st-trans-text); }
.tr-statebtn.is-final[b-pg98q3zrne]         .data-table__state { color: var(--st-final-text); }
.tr-statebtn.is-active[b-pg98q3zrne] { border-color: var(--primary); background: var(--primary-weak); color: var(--primary-ink); font-weight: var(--fw-medium); }
/* Icon-only, for the open grid row where the state column is 104px. */
.tr-statebtn--icon[b-pg98q3zrne] { width: var(--control-h-sm); height: var(--control-h-sm); padding: 0; justify-content: center; }
.tr-statepick--row[b-pg98q3zrne] { flex-wrap: nowrap; gap: 2px; }

.tr-mtstatus[b-pg98q3zrne] >  svg { flex: none; }
.tr-mtstatus[b-pg98q3zrne] { display: inline-flex; align-items: center; gap: var(--space-1); font-size: var(--text-2xs); color: var(--ink-4); text-transform: none; letter-spacing: 0; font-weight: var(--fw-regular); }

/* ── Memory suggestions ─────────────────────────────────────────────────── */

.tr-sugg__list[b-pg98q3zrne] { display: grid; gap: var(--space-1); padding: 0 var(--space-3); }
.tr-sugg__empty[b-pg98q3zrne] { padding: var(--space-2) var(--space-3); font-size: var(--text-xs); color: var(--ink-4); text-wrap: pretty; }

.tr-sugg[b-pg98q3zrne] {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    align-items: start;
    gap: var(--space-2);
    padding: var(--space-2);
    border: 1px solid var(--border);
    border-radius: var(--r-control);
    background: var(--surface);
    cursor: pointer;
}
.tr-sugg:hover[b-pg98q3zrne] { border-color: var(--primary); background: var(--primary-weak); }
.tr-sugg:focus-visible[b-pg98q3zrne] { outline: var(--focus-ring); outline-offset: var(--focus-offset); }
.tr-skey[b-pg98q3zrne] { margin-top: 1px; }
.tr-sugg__body[b-pg98q3zrne] { min-width: 0; display: grid; gap: 2px; }
.tr-stext[b-pg98q3zrne] { font-size: var(--text-sm); color: var(--ink); text-wrap: pretty; overflow-wrap: anywhere; }
.tr-smeta[b-pg98q3zrne] { display: flex; align-items: center; gap: var(--space-2); }
.tr-sorigin[b-pg98q3zrne] { display: inline-flex; align-items: center; gap: 4px; font-size: var(--text-2xs); color: var(--ink-4); }
.tr-sorigin[b-pg98q3zrne] >  svg { flex: none; }
/* A suggestion learned from a file in one of the organisation's own repositories
   links to that file (#631). A link people can see is a link: dotted at rest,
   solid on hover, so the repository does not read as a caption nobody clicks. */
.tr-sorigin--link[b-pg98q3zrne] { color: var(--primary-ink); text-decoration: underline dotted; text-underline-offset: 2px; }
.tr-sorigin--link:hover[b-pg98q3zrne] { color: var(--primary-ink); text-decoration: underline; }
.tr-sugg__side[b-pg98q3zrne] { display: grid; justify-items: end; gap: var(--space-1); }

.tr-ssim[b-pg98q3zrne] {
    padding: 1px 6px;
    border-radius: var(--r-pill);
    background: var(--surface-sunken);
    font-family: var(--font-mono);
    font-size: var(--text-2xs);
    color: var(--ink-3);
    white-space: nowrap;
}
.tr-ssim.exact[b-pg98q3zrne] { background: var(--st-final-bg); color: var(--st-final-text); }
.tr-ssim.high[b-pg98q3zrne]  { background: var(--st-trans-bg); color: var(--st-trans-text); }
.tr-ssim--mt[b-pg98q3zrne]   { background: var(--st-fuzzy-bg); color: var(--st-fuzzy-text); }

.tr-vote[b-pg98q3zrne] { display: inline-flex; align-items: center; gap: 1px; }
.tr-vbtn[b-pg98q3zrne] {
    display: grid;
    place-items: center;
    width: 20px;
    height: 20px;
    padding: 0;
    background: none;
    border: 0;
    border-radius: 3px;
    color: var(--ink-4);
    cursor: pointer;
}
.tr-vbtn:hover[b-pg98q3zrne] { background: var(--surface-sunken); color: var(--ink-2); }
.tr-vbtn:focus-visible[b-pg98q3zrne] { outline: var(--focus-ring); outline-offset: -1px; }
.tr-vbtn.is-active[b-pg98q3zrne] { color: var(--primary-ink); }
.tr-vbtn--del:hover[b-pg98q3zrne] { color: var(--danger-text); }
.tr-vscore[b-pg98q3zrne] { min-width: 14px; text-align: center; font-family: var(--font-mono); font-size: var(--text-2xs); color: var(--ink-4); font-variant-numeric: tabular-nums; }
.tr-vscore.is-pos[b-pg98q3zrne] { color: var(--success-text); }
.tr-vscore.is-neg[b-pg98q3zrne] { color: var(--danger-text); }

/* ── Grid view ──────────────────────────────────────────────────────────── */

/* --tg-cols is declared on .tgrid so a column change is a one-line edit; this
   is that edit. The handoff's 84px key column assumes a short key, and a BC
   XLIFF id is "Codeunit 1465371914 - NamedType 1138880009" -- at 84px every
   row read "Codeunit ...". GridKey() drops the element-kind words so both
   numbers fit at 184px: the leading one groups the row by object, the trailing
   one separates it from its neighbours, and clipping either way round loses
   one of the two. The state column takes the extra, because four state buttons
   have to fit in it when a row is open. */
/* Seven tracks, where the design system has six. Its sixth is the
   hover-revealed .trow__acts; ours carries the unit's Kind (Label / Tooltip /
   Caption), the one attribute the grid otherwise drops - so the actions track
   is appended rather than swapped in. Divergence 10 in
   .design/design-migration.md, now with an action in it (#560). */
.tgrid[b-pg98q3zrne] { --tg-cols: 3px 208px minmax(0, 1fr) minmax(0, 1fr) 116px 84px 40px; }


/* The design system's .trow ends in a hover-actions column. We have no per-row
   action yet (see the PR), so the track carries the unit kind instead — the
   one attribute the grid otherwise dropped. */
.trow__kind[b-pg98q3zrne] {
    padding: 0 var(--cell-pad-x);
    font-size: var(--text-2xs);
    font-weight: var(--fw-semibold);
    letter-spacing: .05em;
    text-transform: uppercase;
    color: var(--ink-4);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.trow--editing .trow__kind[b-pg98q3zrne], .trow--editing .trow__st[b-pg98q3zrne] { padding-top: 6px; }
.trow:focus-visible[b-pg98q3zrne] { outline: var(--focus-ring); outline-offset: -2px; }
/* The key is the two ids with the element-kind words dropped (see GridKey), so
   it fits the column left-to-right and reads the same way as the list view. */
.trow__key[b-pg98q3zrne] { direction: ltr; }

/* ── Status bar ─────────────────────────────────────────────────────────── */

.tr-foot__orig[b-pg98q3zrne] { font-family: var(--font-mono); }
/* Where the open file goes back to, and the pull request it is in once it has
   been saved. The link is the payoff of the whole round trip, so it keeps the
   accent colour the rest of the status line does without. */
/* nowrap: this row is 26px tall, so an item that wraps is not shorter, it is
   clipped. The repository takes the origin's place rather than sitting beside
   it, so the row is no wider than it was. */
.tr-foot__repo[b-pg98q3zrne] { display: inline-flex; align-items: center; gap: 4px; flex: none; font-family: var(--font-mono); white-space: nowrap; }

/* The pull request, in the head beside the file it belongs to. */
.tr-pr[b-pg98q3zrne] {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    flex: none;
    font-size: var(--text-xs);
    font-weight: var(--fw-medium);
    color: var(--primary-ink);
    white-space: nowrap;
}
.tr-foot__unsaved[b-pg98q3zrne] { color: var(--primary-ink); font-weight: var(--fw-medium); }
/* .tprog is authored for a flex row and takes the slack with margin-left: auto,
   which is exactly what the 26px status bar wants. The bar shrinks a little
   here -- it is a status readout now, not the headline. */
.pw__foot .tprog[b-pg98q3zrne] { gap: var(--space-2); }
.pw__foot .tprog__bar[b-pg98q3zrne] { width: 130px; height: 5px; }
/* The keyboard hints go before the counts when the bar runs out of room. */
.pw__foot .kbd-hint[b-pg98q3zrne] { flex: none; }

.tr-hiddenform[b-pg98q3zrne] { display: none; }

/* ── Narrow ─────────────────────────────────────────────────────────────── */

@media (max-width: 1100px) {
    /* Stacked: the units list takes a capped slice off the top and the editor
       fills the rest, because two 300px columns are worse than one of each. */
    .tr-split[b-pg98q3zrne] {
        grid-template-columns: minmax(0, 1fr);
        grid-template-rows: minmax(0, 40%) 4px minmax(0, 1fr);
    }
    .tr-split > .pane + .pw-split + .pane[b-pg98q3zrne] { border-left: 0; border-top: 1px solid var(--border); }
    .tr-split > .pw-split[b-pg98q3zrne] { width: auto; height: 4px; cursor: row-resize; }
    /* The ribbon's four named counts are the first thing to go. */
    .tprog__keys[b-pg98q3zrne] { display: none; }
}

/* ── Generated-file notice ──────────────────────────────────────────────── */

/* The frame's grid has one row each for head, bar, body and foot, so the
   notice rides in the bar (which wraps) and takes a whole line of it. The
   frame, tint and icon slot are <Alert>'s; ::deep because that component
   renders the box. */
.pw__bar[b-pg98q3zrne]  .tr-gennote { flex: 1 0 100%; align-items: center; }
.pw__bar .tr-gennote__text[b-pg98q3zrne] { flex: 1; min-width: 0; }
/* /Components/Pages/Upgrades/AddToUpgradeDialog.razor.rz.scp.css */
/* "Add to upgrade..." (UpgradePicker.dc.html, mode="add"). */

.atu-title[b-vkon37loxs] {
    display: grid;
    gap: 2px;
}

.atu-title__sub[b-vkon37loxs] {
    font-size: var(--text-sm);
    color: var(--ink-3);
}

.atu-body[b-vkon37loxs] {
    display: grid;
    gap: var(--space-4);
    overflow: auto;
}

.atu-group[b-vkon37loxs] {
    display: grid;
    gap: var(--space-2);
    min-width: 0;
    margin: 0;
    padding: 0;
    border: 0;
}

/* The design system's .section-label, without its margin, as the sheet has it -
   as a legend and as a plain label alike. */
.atu-label[b-vkon37loxs] {
    margin: 0;
    padding: 0;
}

.atu-choices[b-vkon37loxs],
.atu-envs[b-vkon37loxs] {
    display: grid;
    margin: 0;
    padding: 0;
    list-style: none;
    border: 1px solid var(--border);
    border-radius: var(--r-control);
}

/* One radio row: the dot, the upgrade over its target and slot, its size. */
.atu-choice[b-vkon37loxs] {
    display: grid;
    grid-template-columns: 18px minmax(0, 1fr) auto;
    align-items: start;
    gap: var(--space-3);
    min-height: 44px;
    padding: var(--space-2) var(--space-3);
    border-bottom: 1px solid var(--border);
}

.atu-choice--new[b-vkon37loxs] {
    grid-template-columns: 18px minmax(0, 1fr);
    border-bottom: 0;
}

.atu-choice.is-picked[b-vkon37loxs] {
    background: var(--primary-weak);
}

.atu-choice .check__dot[b-vkon37loxs] {
    margin-top: 2px;
}

.atu-choice__text[b-vkon37loxs] {
    padding: 0;
}

.atu-choice__name[b-vkon37loxs] {
    color: var(--ink);
    font-weight: var(--fw-medium);
}

.atu-choice__count[b-vkon37loxs] {
    font-size: var(--text-sm);
    color: var(--ink-3);
    white-space: nowrap;
}

/* The new upgrade's name and target, inline under its radio, indented to its text. */
.atu-new[b-vkon37loxs] {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 140px;
    gap: var(--space-2);
    padding: 0 var(--space-3) var(--space-3) calc(var(--space-3) * 2 + 18px);
    background: var(--primary-weak);
}

@media (max-width: 700px) {
    .atu-new[b-vkon37loxs] {
        grid-template-columns: minmax(0, 1fr);
        padding-left: var(--space-3);
    }
}

.atu-env[b-vkon37loxs] {
    display: grid;
    grid-template-columns: 16px minmax(0, 1fr);
    gap: var(--space-2);
    padding: var(--space-2) var(--space-3);
    border-bottom: 1px solid var(--border);
}

.atu-env:last-child[b-vkon37loxs] {
    border-bottom: 0;
}

.atu-env__icon[b-vkon37loxs] {
    margin-top: 2px;
}

.atu-env__icon--ok[b-vkon37loxs] {
    color: var(--success-text);
}

.atu-env__icon--muted[b-vkon37loxs] {
    color: var(--ink-4);
}

.atu-env__icon--warn[b-vkon37loxs] {
    color: var(--warning-text);
}

.atu-env__text[b-vkon37loxs] {
    padding: 0;
}

.atu-env__name[b-vkon37loxs] {
    font-size: var(--text-sm);
    color: var(--ink);
}

.atu-env--out .atu-env__name[b-vkon37loxs] {
    color: var(--ink-3);
}

.atu-env__why[b-vkon37loxs] {
    color: var(--warning-text);
    font-weight: var(--fw-medium);
}

.atu-none[b-vkon37loxs] {
    margin: 0;
    font-size: var(--text-sm);
    color: var(--ink-2);
}
/* /Components/Pages/Upgrades/NewUpgradeDialog.razor.rz.scp.css */
/* "New upgrade": four fields in one column, the sheet's spacing. */
.nu-body[b-f14yeev4w5] {
    display: grid;
    gap: var(--space-3);
}

/* The slot as a date and a time side by side, the time the narrower. */
.nu-slot[b-f14yeev4w5] {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 120px;
    gap: var(--space-2);
}
/* /Components/Pages/Upgrades/TargetVersionInput.razor.rz.scp.css */
/* The typed version, under the list it was picked from with "Another version...". */
.tvi-other[b-6a0bzyoa54] {
    margin-top: var(--space-2);
}

/* With nothing offered it is the only control, so no gap above it. */
.tvi-other:first-child[b-6a0bzyoa54] {
    margin-top: 0;
}
/* /Components/Pages/Upgrades/UpgradeActionRunner.razor.rz.scp.css */
/* The three moves' confirm dialogs: the preview of what each will do, the choice of
   when and of which version, and the run reported in the dialog that started it.
   Moved here with the markup from the Upgrades page's sheet - the dialog bodies are
   authored in this component, so they carry its scope and not the page's. */

/* A run, reported inside the dialog that started it. */
.upg-run[b-s9wux7cxtr] { display: grid; gap: var(--space-3); }

.upg-run__text[b-s9wux7cxtr] { margin: 0; color: var(--ink); }

.upg-run__foot[b-s9wux7cxtr] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    font-size: var(--text-sm);
}

/* Production, emphasised but not alarmed - matching the project page's
   treatment of the same pill. */
/* ::deep: the pill is rendered by StatusPill, outside this file's scope. */
[b-s9wux7cxtr] .upg-prod {
    font-weight: 600;
}

/* The confirm dialogs' preview: one line per environment, and the ones that
   will be passed over set apart rather than hidden. */
.upg-preview[b-s9wux7cxtr] {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

.upg-preview li[b-s9wux7cxtr] {
    display: flex;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-1) 0;
    border-bottom: 1px solid var(--border);
}

.upg-preview li:last-child[b-s9wux7cxtr] { border-bottom: none; }

.upg-preview__who[b-s9wux7cxtr] { font-weight: 600; }
.upg-preview__what[b-s9wux7cxtr] { color: var(--ink-3); text-align: right; }
.upg-preview__skip .upg-preview__who[b-s9wux7cxtr],
.upg-preview__skip .upg-preview__what[b-s9wux7cxtr] { color: var(--ink-4); }

/* The skipped group's heading inside a confirm dialog. */
.upg-preview__head[b-s9wux7cxtr] {
    margin: var(--space-3) 0 var(--space-1);
    font-size: var(--text-xs);
    font-weight: 600;
    color: var(--ink-3);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

/* How much of the fleet the update-now dialog is about, read just before the
   confirmation word is typed. */
.upg-preview__count[b-s9wux7cxtr] {
    margin: var(--space-3) 0 0;
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--ink-2);
}

/* The Production marker inside a preview row. */
/* ::deep: the pill is rendered by StatusPill, outside this file's scope. */
.upg-preview__who[b-s9wux7cxtr]  .status-pill {
    margin-left: var(--space-2);
}

/* Reads in flow, directly above the confirm. It used to be pinned to the bottom
   of the scrolling detail block; once that block also carried the when-choice,
   a pinned line sat on top of the picker's own caption. The lists below scroll
   on their own instead, which keeps this and the choice both in view without
   either overlapping the other. */
.upg-preview__count[b-s9wux7cxtr] {
    padding: var(--space-2) 0 0;
}

/* Ninety environments still can't push the choice or the buttons off the
   screen: the list gives way, not the controls. */
.upg-preview[b-s9wux7cxtr] {
    max-height: 12rem;
    overflow-y: auto;
}

/* Booking an update for an agreed slot. */

/* The when-choice inside the update-now confirm. A fieldset because the two
   radios are one question, and the question has to be readable as one. */
.upg-when[b-s9wux7cxtr] {
    margin: var(--space-3) 0 0;
    padding: var(--space-3);
    border: 1px solid var(--border);
    border-radius: var(--r);
    background: var(--surface-2);
}

.upg-when__legend[b-s9wux7cxtr] {
    padding: 0 var(--space-1);
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--ink-2);
}

.upg-when__opt[b-s9wux7cxtr] {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    margin-right: var(--space-4);
    font-size: var(--text-sm);
    color: var(--ink-2);
}

.upg-when__pick[b-s9wux7cxtr] {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex-wrap: wrap;
    margin-top: var(--space-2);
}

/* The booking said back in the page's own 24-hour words, under a field the
   browser draws in its own locale. Emphasised because it, not the field, is
   what settles what was picked. */
.upg-when__echo[b-s9wux7cxtr] {
    margin: var(--space-2) 0 0;
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--ink-2);
}

/* An environment in the preview that already has a booking waiting. Warned, not
   dimmed: the run will still act on it, which is the thing to notice. */
.upg-preview__booked[b-s9wux7cxtr] {
    color: var(--warning-text);
}

/* ── Change the next version (#960) ─────────────────────────────────── */

/* The versions stacked, one per line: each carries a count, and a row of radios
   with counts beside them reads as one long sentence. */
.upg-version__opts[b-s9wux7cxtr] {
    display: grid;
    gap: var(--space-2);
}

.upg-version__name[b-s9wux7cxtr] {
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

.upg-version__count[b-s9wux7cxtr] {
    color: var(--ink-3);
    font-size: var(--text-sm);
}

/* Said once, above the count: the date is Business Central's to pick. */
.upg-version__date[b-s9wux7cxtr] {
    display: flex;
    align-items: center;
    gap: var(--space-1);
    margin: var(--space-3) 0 0;
    font-size: var(--text-sm);
    color: var(--ink-2);
}

.upg-version__none[b-s9wux7cxtr] {
    margin: 0;
    color: var(--ink-2);
}

/* Up to seven groups, so the version preview is one scroller - the dialog's own - not
   a scroller per group inside it: each list cut at 12rem left the last group's
   heading at the foot of the dialog with its rows in a second box nobody scrolled.
   Each heading sticks to the top of its own group while that group scrolls past, so
   a heading scrolled up never leaves its rows behind. */
.upg-version__groups .upg-preview[b-s9wux7cxtr] {
    max-height: none;
    overflow: visible;
}

.upg-version__group .upg-preview__head[b-s9wux7cxtr] {
    position: sticky;
    top: 0;
    z-index: 1;
    margin: 0;
    padding: var(--space-3) 0 var(--space-1);
    background: var(--surface);
}
/* /Components/Pages/Upgrades/UpgradeAssignDialog.razor.rz.scp.css */
/* The people as a radio list in one bordered box, the way the "Add to upgrade" sheet
   (UpgradePicker.dc.html, mode="add") lists the open upgrades: one row per choice, the
   picked row tinted. */
.uad-list[b-5b6d7iarbj] {
    display: grid;
    max-height: min(360px, 50vh);
    overflow: auto;
    border: 1px solid var(--border);
    border-radius: var(--r-control);
}

.uad-row[b-5b6d7iarbj] {
    display: grid;
    grid-template-columns: 18px 22px minmax(0, 1fr);
    align-items: center;
    gap: var(--space-3);
    min-height: 44px;
    padding: var(--space-2) var(--space-3);
    border-bottom: 1px solid var(--border);
}

.uad-row:last-child[b-5b6d7iarbj] { border-bottom: 0; }

.uad-row.is-picked[b-5b6d7iarbj] { background: var(--primary-weak); }

.uad-avatar[b-5b6d7iarbj] {
    width: 22px;
    height: 22px;
    font-size: 10px;
}

.uad-who[b-5b6d7iarbj] { padding: 0; }

.uad-nobody[b-5b6d7iarbj] {
    grid-column: 2 / -1;
    color: var(--ink);
    font-weight: var(--fw-medium);
}
/* /Components/Pages/Upgrades/UpgradeDetail.razor.rz.scp.css */
/* An upgrade's own page (#984): UpgradeBody.dc.html, ported onto our tokens. The frame
   (crumbs, head, meta row) is DetailPage's; this is the loading skeleton, the command
   bar, the lines table and its phone cards, and the notes a run leaves on a line. */

/* ── Loading ─────────────────────────────────────────────────────────── */

.upd-skel[b-5xc9pmbcsm] { display: block; }
.upd-skel--box[b-5xc9pmbcsm] { width: 16px; height: 16px; flex: none; }
.upd-skel--short[b-5xc9pmbcsm] { width: 30%; height: 9px; }
.upd-skel--pill[b-5xc9pmbcsm] { width: 64px; height: 18px; }

.upd-skel-row[b-5xc9pmbcsm] {
    display: flex;
    align-items: center;
    gap: var(--space-4);
    min-height: 50px;
    padding: 0 var(--space-4);
    border-bottom: 1px solid var(--border);
}

.upd-skel-row__text[b-5xc9pmbcsm] {
    display: grid;
    gap: 6px;
    flex: 1;
}

/* ── Head ────────────────────────────────────────────────────────────── */

.upd-actions-pair[b-5xc9pmbcsm] {
    display: flex;
    gap: var(--space-2);
    justify-content: center;
    flex-wrap: wrap;
}

/* The outline commands collapse into the overflow on a phone, and appear there only
   then. */
.upd-phone-only[b-5xc9pmbcsm] { display: none; }

.upd-alerts[b-5xc9pmbcsm]  .alert { margin: 0 0 var(--space-3); }

/* ── The command bar ─────────────────────────────────────────────────── */

.upd-bar[b-5xc9pmbcsm] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2) var(--space-3);
    min-height: 48px;
    margin-bottom: var(--space-2);
}

.upd-search[b-5xc9pmbcsm] {
    flex: 1 1 200px;
    max-width: 280px;
}

.upd-bar[b-5xc9pmbcsm]  .upd-mine { min-height: 44px; }
.upd-bar[b-5xc9pmbcsm]  .upd-state { width: 150px; }

.upd-bar__spacer[b-5xc9pmbcsm] { flex: 1; }

.upd-bar__sel[b-5xc9pmbcsm] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
}

.upd-bar__count[b-5xc9pmbcsm] {
    font-size: var(--text-sm);
    font-weight: var(--fw-medium);
    color: var(--ink);
}

/* ── The lines ───────────────────────────────────────────────────────── */

.upd-table[b-5xc9pmbcsm] { table-layout: fixed; }

.upd-col-check[b-5xc9pmbcsm] { width: 40px; }
.upd-col-env[b-5xc9pmbcsm] { width: 17%; }
.upd-col-now[b-5xc9pmbcsm] { width: 14%; }
.upd-col-state[b-5xc9pmbcsm] { width: 10%; }
.upd-col-last[b-5xc9pmbcsm] { width: 17%; }
.upd-col-who[b-5xc9pmbcsm] { width: 12%; }
.upd-col-checked[b-5xc9pmbcsm] { width: 17%; }
.upd-col-contact[b-5xc9pmbcsm] { width: 13%; }
.upd-col-actions[b-5xc9pmbcsm] { width: 48px; }

.upd-sol[b-5xc9pmbcsm] { font-weight: var(--fw-medium); }

.upd-envlink[b-5xc9pmbcsm] { color: inherit; }

/* Production is the one to be careful with, so it reads a shade heavier. Not red: the
   review settled that red is for a failure. */
.upd-prod[b-5xc9pmbcsm] {
    color: var(--ink);
    font-weight: var(--fw-semibold);
}

.upd-small[b-5xc9pmbcsm] { font-size: var(--text-sm); }

/* The facts wrap rather than cut "5 of 8 updated, 3 checked" short, as the sheet's do. The
   meta items are this page's own markup in DetailPage's Meta slot, so the rule is scoped. */
.meta-item__value[b-5xc9pmbcsm] { white-space: normal; }

/* The narrow columns wrap rather than cut a sentence off: "Update to 28.5 failed 20:37"
   ending in an ellipsis loses the one word that matters. */
.upd-wrap[b-5xc9pmbcsm] {
    white-space: normal;
    overflow: visible;
    text-overflow: clip;
    text-wrap: pretty;
}

.upd-now--bad[b-5xc9pmbcsm] { color: var(--danger-text); }
.upd-now--info[b-5xc9pmbcsm] { color: var(--info-text); }

.upd-row--locked td[b-5xc9pmbcsm] { color: var(--ink-3); }

/* A padlocked line has no checkbox, and the legend under the table says why. */
.upd-legend[b-5xc9pmbcsm] {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin: var(--space-2) 0 0;
    font-size: var(--text-sm);
    color: var(--ink-3);
}

/* Assignee: a quiet button when nobody is set, the person when somebody is. */
.upd-assign[b-5xc9pmbcsm] { color: var(--ink-3); }

.upd-assignee[b-5xc9pmbcsm] {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    min-height: 32px;
    font-size: var(--text-sm);
    color: var(--ink);
}

.upd-assignee--button[b-5xc9pmbcsm] {
    padding: 0;
    border: 0;
    background: none;
    font: inherit;
    font-size: var(--text-sm);
    cursor: pointer;
    text-align: left;
}

.upd-assignee--button:focus-visible[b-5xc9pmbcsm] {
    outline: var(--focus-ring);
    outline-offset: 2px;
    border-radius: var(--r-control);
}

.upd-avatar[b-5xc9pmbcsm] {
    width: 22px;
    height: 22px;
    font-size: 10px;
    flex: none;
}

/* Checked: the tick with its words, then the note under them. On a done upgrade a tick
   or a cross stands where the checkbox was, beside the stamp. */
.upd-check[b-5xc9pmbcsm] {
    display: grid;
    gap: 2px;
    align-items: start;
}

.upd-check--done[b-5xc9pmbcsm] {
    grid-template-columns: auto minmax(0, 1fr);
    column-gap: var(--space-2);
}

/* The note lines up under the words, not under the box. */
.upd-check:not(.upd-check--done) .upd-check__text[b-5xc9pmbcsm] { padding-left: calc(16px + var(--space-2)); }

.upd-check__box[b-5xc9pmbcsm] {
    align-items: flex-start;
    margin-top: 2px;
    font-size: var(--text-sm);
}

.upd-check__box .check__box[b-5xc9pmbcsm] { flex: none; margin-top: 1px; }

.upd-check__stamp[b-5xc9pmbcsm] { color: var(--ink); }

.upd-check__hint[b-5xc9pmbcsm] {
    font-size: var(--text-xs);
    color: var(--ink-3);
}

.upd-check__text[b-5xc9pmbcsm] {
    padding: 0;
    min-width: 0;
}

.upd-mark[b-5xc9pmbcsm] { margin-top: 1px; }
.upd-ok[b-5xc9pmbcsm] { color: var(--success-text); }
.upd-bad[b-5xc9pmbcsm] { color: var(--danger-text); }

.upd-note-text[b-5xc9pmbcsm] {
    white-space: normal;
    text-wrap: pretty;
}

/* The note is the way to change the note: a link-quiet button, so it reads as the note
   and not as a control until it is pointed at. */
.upd-note-button[b-5xc9pmbcsm] {
    padding: 0;
    border: 0;
    background: none;
    font: inherit;
    font-size: var(--text-xs);
    color: var(--ink-3);
    text-align: left;
    white-space: normal;
    text-wrap: pretty;
    cursor: pointer;
    text-decoration: underline dotted;
    text-underline-offset: 2px;
}

.upd-note-button:hover[b-5xc9pmbcsm] { color: var(--primary-ink); }

.upd-note-button:focus-visible[b-5xc9pmbcsm] {
    outline: var(--focus-ring);
    outline-offset: 2px;
}

/* ── What a run or the watch says about a line ───────────────────────── */

.upd-note[b-5xc9pmbcsm] {
    display: flex;
    align-items: flex-start;
    flex-wrap: wrap;
    gap: var(--space-1) var(--space-2);
    margin-top: var(--space-1);
    font-size: var(--text-xs);
}

.upd-note--ok[b-5xc9pmbcsm] { color: var(--success-text); }
.upd-note--bad[b-5xc9pmbcsm] { color: var(--danger-text); }
.upd-note--warn[b-5xc9pmbcsm] { color: var(--warning-text); }
.upd-note--busy[b-5xc9pmbcsm] { color: var(--ink-3); }
.upd-note--muted[b-5xc9pmbcsm] { color: var(--ink-3); }

.upd-note[b-5xc9pmbcsm]  svg {
    flex: 0 0 auto;
    margin-top: 1px;
}

.upd-note .spinner[b-5xc9pmbcsm] {
    width: 12px;
    height: 12px;
    flex: 0 0 auto;
}

.upd-note__link[b-5xc9pmbcsm] { font-weight: var(--fw-medium); }

.upd-note__cancel[b-5xc9pmbcsm] { margin-left: var(--space-1); }

.upd-table tr.upd-result-row td[b-5xc9pmbcsm] {
    padding-top: 0;
    border-top: 0;
}

/* ── Mark done ───────────────────────────────────────────────────────── */

.upd-unchecked__head[b-5xc9pmbcsm] { margin: var(--space-3) 0 var(--space-2); }
.upd-unchecked__head:first-child[b-5xc9pmbcsm] { margin-top: 0; }

.upd-unchecked[b-5xc9pmbcsm] {
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--r-control);
}

.upd-unchecked__row[b-5xc9pmbcsm] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-2) var(--space-3);
    border-bottom: 1px solid var(--border);
}

.upd-unchecked__row:last-child[b-5xc9pmbcsm] { border-bottom: 0; }

.upd-unchecked__who[b-5xc9pmbcsm] { padding: 0; }

.upd-unchecked__who .cell-stack__main[b-5xc9pmbcsm] {
    font-size: var(--text-sm);
    font-weight: var(--fw-medium);
}

.upd-unchecked__after[b-5xc9pmbcsm] {
    margin: var(--space-3) 0 0;
    font-size: var(--text-sm);
    color: var(--ink-3);
    text-wrap: pretty;
}

/* ── Phone ───────────────────────────────────────────────────────────── */

.upd-compact[b-5xc9pmbcsm] { display: none; }

.upd-card[b-5xc9pmbcsm] {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: var(--space-1) var(--space-3);
    padding: var(--space-3);
    border-bottom: 1px solid var(--border);
}

.upd-card:last-child[b-5xc9pmbcsm] { border-bottom: 0; }

.upd-card__who[b-5xc9pmbcsm] { padding: 0; }

.upd-card__sol[b-5xc9pmbcsm] { font-weight: var(--fw-semibold); }

.upd-card[b-5xc9pmbcsm]  .upd-card__pill { align-self: start; }

.upd-card__last[b-5xc9pmbcsm] {
    grid-column: 1 / -1;
    font-size: var(--text-sm);
    color: var(--ink-3);
    text-wrap: pretty;
}

.upd-card__foot[b-5xc9pmbcsm] {
    grid-column: 1 / -1;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    min-height: 44px;
}

.upd-card__check[b-5xc9pmbcsm] {
    min-height: 44px;
    align-items: center;
}

.upd-card__checktext[b-5xc9pmbcsm] {
    display: grid;
    font-size: var(--text-sm);
    color: var(--ink);
}

.upd-card__note[b-5xc9pmbcsm] {
    color: var(--ink-3);
    font-size: var(--text-xs);
}

.upd-card__acts[b-5xc9pmbcsm] {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex: none;
}

.upd-card__call[b-5xc9pmbcsm] {
    min-height: 44px;
    flex: none;
}

.upd-card__notebutton[b-5xc9pmbcsm] { grid-column: 1 / -1; }

@media (max-width: 700px) {
    .upd-wide[b-5xc9pmbcsm] { display: none; }

    .upd-compact[b-5xc9pmbcsm] {
        display: block;
        background: var(--surface);
        border: 1px solid var(--border);
        border-radius: var(--r);
    }

    .upd-outline[b-5xc9pmbcsm] { display: none; }

    /* The ribbon wraps under the name here, so the overflow sits at the left of the
       screen and its menu opens rightwards rather than off the edge. */
    .upd-more .ra__menu[b-5xc9pmbcsm] { left: 0; right: auto; }
    .upd-phone-only[b-5xc9pmbcsm] { display: flex; }
    div.upd-phone-only[b-5xc9pmbcsm] { display: block; }

    .upd-search[b-5xc9pmbcsm] { max-width: none; }
}
/* /Components/Pages/Upgrades/UpgradeDetailsDialog.razor.rz.scp.css */
/* The upgrade's four fields, one column; the version and the slot share a row because
   each is short and they are read together ("28.5 on Thursday at 20:00"). */
.udd-fields[b-41nk304zf5] {
    display: grid;
    gap: var(--space-3);
}

.udd-pair[b-41nk304zf5] {
    display: grid;
    grid-template-columns: minmax(0, 140px) minmax(0, 1fr);
    gap: var(--space-3);
}

@media (max-width: 560px) {
    .udd-pair[b-41nk304zf5] { grid-template-columns: minmax(0, 1fr); }
}
/* /Components/Pages/Upgrades/UpgradePicker.razor.rz.scp.css */
/* The environment picker (UpgradePicker.dc.html, mode="picker").

   A 1000px dialog is a size components.css does not have - .confirm-dialog is 420px and
   --wide 560px - so the sheet's inline width lives here until the design project adds a
   size for it (port note in .design/handoff/README.md). The height is fixed so the dialog
   does not jump as a search narrows the list; only the table scrolls. */
.upk-dialog[b-461vxagkh9] {
    width: min(1000px, 100%);
    height: min(640px, calc(100vh - 2 * var(--space-5)));
    min-height: 0;
    overflow: hidden;
    display: grid;
    grid-template-rows: auto minmax(0, 1fr) auto;
}

.upk-head[b-461vxagkh9] {
    align-items: center;
    justify-content: space-between;
}

.upk-head__text[b-461vxagkh9] {
    display: grid;
    gap: 2px;
    min-width: 0;
}

.upk-head__sub[b-461vxagkh9] {
    font-size: var(--text-sm);
    color: var(--ink-3);
}

.upk-close[b-461vxagkh9] {
    width: 44px;
    height: 44px;
    flex: none;
}

.upk-body[b-461vxagkh9] {
    display: grid;
    grid-template-rows: auto auto minmax(0, 1fr);
    gap: var(--space-3);
    min-height: 0;
    overflow: hidden;
}

.upk-fill[b-461vxagkh9],
.upk-filters[b-461vxagkh9] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
}

.upk-fill__label[b-461vxagkh9] {
    font-size: var(--text-sm);
    color: var(--ink-3);
}

.upk-search[b-461vxagkh9] { flex: 1 1 220px; }

.upk-filters[b-461vxagkh9]  .upk-select { width: 140px; }
.upk-filters[b-461vxagkh9]  .upk-select--solution { width: 160px; }

.upk-scroll[b-461vxagkh9] {
    overflow: auto;
    min-height: 0;
    border: 1px solid var(--border);
    border-radius: var(--r-control);
}

.upk-table[b-461vxagkh9] {
    table-layout: fixed;
    border: 0;
}

.upk-col-check[b-461vxagkh9] { width: 40px; }
.upk-col-env[b-461vxagkh9] { width: 36%; }
.upk-col-short[b-461vxagkh9],
.upk-col-ver[b-461vxagkh9] { width: 14%; }

.upk-sol[b-461vxagkh9] {
    font-weight: var(--fw-medium);
    color: var(--ink);
}

/* Production is the one to be careful with, so it reads a shade heavier - not red: the
   sheet's review settled that red is for failures. */
.upk-prod[b-461vxagkh9] {
    color: var(--ink);
    font-weight: var(--fw-semibold);
}

.upk-why[b-461vxagkh9] {
    color: var(--ink-3);
    font-weight: var(--fw-medium);
}

.upk-why--other[b-461vxagkh9] { color: var(--warning-text); }

/* A row held by another upgrade, or out of this person's reach, reads as unavailable. */
.upk-row--locked .upk-sol[b-461vxagkh9],
.upk-row--locked td[b-461vxagkh9] { color: var(--ink-3); }

.upk-next[b-461vxagkh9] {
    color: var(--ink-2);
    font-size: var(--text-sm);
}

.upk-foot[b-461vxagkh9] {
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2) var(--space-3);
}

.upk-foot__count[b-461vxagkh9] {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    min-height: 44px;
    white-space: nowrap;
}

.upk-foot__selected[b-461vxagkh9] {
    font-size: var(--text-sm);
    font-weight: var(--fw-medium);
    color: var(--ink);
}

.upk-foot__buttons[b-461vxagkh9] {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin-left: auto;
}

/* Phone: the dialog takes the screen, and the table keeps what fits - the sheet's compact
   picker drops the three selects and the two narrow columns. */
@media (max-width: 700px) {
    .upk-layer[b-461vxagkh9] { padding: 0; }

    .upk-dialog[b-461vxagkh9] {
        width: 100%;
        height: 100%;
        max-width: none;
        border-radius: 0;
    }

    .upk-filters[b-461vxagkh9]  .upk-wide,
    .upk-col-short[b-461vxagkh9],
    .upk-col-next[b-461vxagkh9] { display: none; }

    .upk-table[b-461vxagkh9] { table-layout: auto; }
    .upk-col-env[b-461vxagkh9] { width: auto; }
}
/* /Components/Pages/Upgrades/UpgradesArchiveList.razor.rz.scp.css */
/* The Archive view's rows (UpgradesListBody.dc.html, view="archive"), the sheet's
   widths on a fixed-layout table. */

.upa-table[b-7t0amio2v1] {
    table-layout: fixed;
}

.upa-col-name[b-7t0amio2v1] { width: 28%; }
.upa-col-target[b-7t0amio2v1] { width: 10%; }
.upa-col-envs[b-7t0amio2v1] { width: 18%; }
.upa-col-closed[b-7t0amio2v1] { width: 22%; }
.upa-col-by[b-7t0amio2v1] { width: 16%; }
.upa-col-menu[b-7t0amio2v1] { width: 52px; }

.upa-name[b-7t0amio2v1] {
    font-weight: var(--fw-medium);
}

/* A wave that left environments behind says so in the danger tone. */
.upa-failed[b-7t0amio2v1] {
    color: var(--danger-text);
    font-weight: var(--fw-medium);
}

/* ── Phone: stacked items instead of the table ───────────────────────── */

.upa-cards[b-7t0amio2v1] {
    display: none;
    margin: 0;
    padding: 0;
    list-style: none;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r);
}

.upa-card[b-7t0amio2v1] {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 2px var(--space-3);
    padding: var(--space-3);
    border-bottom: 1px solid var(--border);
}

.upa-card:last-child[b-7t0amio2v1] {
    border-bottom: 0;
}

.upa-card__head[b-7t0amio2v1] {
    padding: 0;
}

.upa-card__name[b-7t0amio2v1] {
    font-weight: var(--fw-semibold);
}

.upa-card__menu[b-7t0amio2v1]  .btn {
    width: 44px;
    height: 44px;
    margin: -10px -10px 0 0;
}

@media (max-width: 700px) {
    .upa-table[b-7t0amio2v1] {
        display: none;
    }

    .upa-cards[b-7t0amio2v1] {
        display: block;
    }
}
/* /Components/Pages/Upgrades/UpgradesOpenList.razor.rz.scp.css */
/* The Open view's rows (UpgradesListBody.dc.html, view="open"). Widths are the
   sheet's; the table is fixed-layout so a long name ellipsises rather than pushing
   the Planned column off the page. */

.upl-table[b-dlw3panowb] {
    table-layout: fixed;
}

.upl-col-name[b-dlw3panowb] { width: 24%; }
.upl-col-status[b-dlw3panowb] { width: 11%; }
.upl-col-envs[b-dlw3panowb] { width: 24%; }
.upl-col-checked[b-dlw3panowb] { width: 13%; }
.upl-col-slot[b-dlw3panowb] { width: 13%; }
.upl-col-by[b-dlw3panowb] { width: 11%; }
.upl-col-menu[b-dlw3panowb] { width: 52px; }

/* The name is the link to the upgrade: link-coloured, not the stack's plain ink. */
.upl-name[b-dlw3panowb],
.upl-card__name[b-dlw3panowb] {
    color: var(--primary-ink);
    font-weight: var(--fw-medium);
}

/* The breakdown wraps rather than ellipsising: "6 updated 1 running 1 failed" is
   the part the morning-after reader came for. */
.upl-parts[b-dlw3panowb] {
    display: flex;
    flex-wrap: wrap;
    gap: 0 var(--space-2);
    white-space: normal;
}

.upl-part[b-dlw3panowb] {
    color: var(--ink-2);
    white-space: nowrap;
}

/* Tone only on the two counts that need somebody. */
.upl-part--running[b-dlw3panowb] {
    color: var(--info-text);
    font-weight: var(--fw-semibold);
}

.upl-part--failed[b-dlw3panowb] {
    color: var(--danger-text);
    font-weight: var(--fw-semibold);
}

.upl-check[b-dlw3panowb] {
    display: grid;
    gap: 4px;
}

.upl-check__text[b-dlw3panowb] {
    font-size: var(--text-sm);
    color: var(--ink);
}

.upl-check__bar[b-dlw3panowb] {
    width: 88px;
    height: 5px;
}

/* Tonight and last night: the slots the page is opened for. */
.upl-slot--near[b-dlw3panowb] {
    font-weight: var(--fw-semibold);
}

/* ── Phone: stacked items instead of the table ───────────────────────── */

.upl-cards[b-dlw3panowb] {
    display: none;
    margin: 0;
    padding: 0;
    list-style: none;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r);
}

.upl-card[b-dlw3panowb] {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: var(--space-1) var(--space-3);
    padding: var(--space-3);
    border-bottom: 1px solid var(--border);
}

.upl-card:last-child[b-dlw3panowb] {
    border-bottom: 0;
}

.upl-card__head[b-dlw3panowb] {
    padding: 0;
}

.upl-card__name[b-dlw3panowb] {
    font-weight: var(--fw-semibold);
}


/* A 44px target on a touch screen, pulled into the card's corner. */
.upl-card__menu[b-dlw3panowb]  .btn {
    width: 44px;
    height: 44px;
    margin: -10px -10px 0 0;
}

.upl-card__line[b-dlw3panowb] {
    grid-column: 1 / -1;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-1) var(--space-2);
    font-size: var(--text-sm);
}

.upl-card__count[b-dlw3panowb] {
    color: var(--ink-2);
}

.upl-card__checked[b-dlw3panowb] {
    color: var(--ink-2);
}

.upl-card__checked .upl-check[b-dlw3panowb] {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex: 1;
}

.upl-card__checked .upl-check__bar[b-dlw3panowb] {
    flex: 1;
    max-width: 160px;
}

@media (max-width: 700px) {
    .upl-table[b-dlw3panowb] {
        display: none;
    }

    .upl-cards[b-dlw3panowb] {
        display: block;
    }
}
/* /Components/Pages/Upgrades/UpgradesPage.razor.rz.scp.css */
/* Upgrades page. The command bar, the table, its selection column and the empty
   states come from the design system unchanged; what is here is the scrolling box
   the table sits in and the small notes a row carries beside its values. */

/* "8 minutes ago" reads as one thing, and wrapping it makes the rows uneven for
   no gain. */
.upg-checked[b-pwwlr31ma1] {
    white-space: nowrap;
}

/* What just happened, or what is happening now. Sits between the buttons and
   the table because that is where the eye already is after a click. */
.upg-notice[b-pwwlr31ma1] {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-3);
    margin-bottom: var(--space-2);
    font-size: var(--text-sm);
    color: var(--ink-2);
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--r);
}

/* A short line: the ignores-window marker under a value, and each row's result
   on the line below it. */
.upg-note[b-pwwlr31ma1] {
    display: flex;
    align-items: center;
    gap: var(--space-1);
    margin-top: var(--space-1);
    font-size: var(--text-xs);
    color: var(--ink-3);
}

.upg-note--warn[b-pwwlr31ma1] { color: var(--warning-text); }
.upg-note--ok[b-pwwlr31ma1] { color: var(--success-text); }
.upg-note--bad[b-pwwlr31ma1] { color: var(--danger-text); }
.upg-note--busy[b-pwwlr31ma1] { color: var(--ink-3); }
.upg-note--muted[b-pwwlr31ma1] { color: var(--ink-3); }

.upg-note .spinner[b-pwwlr31ma1] {
    width: 12px;
    height: 12px;
    border-width: 2px;
}

/* Older than a nightly refresh. Muted-with-emphasis rather than a warning
   colour: the answer is probably still right, it is just not fresh. */
.upg-stale[b-pwwlr31ma1] {
    color: var(--ink-4);
    font-style: italic;
}

/* A row whose customer this person can't act on. Same information, no
   checkbox - dimming it would hide the fact that it exists, which is the one
   thing the row is there to say. */
.upg-row--locked .data-table__col-check[b-pwwlr31ma1] {
    color: var(--ink-4);
}

/* What the padlock in a row means. Only rendered when a padlock is on screen -
   a hover title was invisible on a touch screen, to the keyboard and to a
   screen reader, which is most of the ways someone meets it. */
.upg-legend[b-pwwlr31ma1] {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin: var(--space-2) 0 0;
    font-size: var(--text-xs);
    color: var(--ink-3);
}

/* A run's summary stays reachable after a long batch: the rows below scroll,
   this doesn't leave with them. */
.upg-notice[b-pwwlr31ma1] {
    position: sticky;
    top: 0;
    z-index: 2;
}

/* An outcome with anything skipped or failed is not neutral news. */
.upg-notice--warn[b-pwwlr31ma1] {
    color: var(--warning-text);
    background: var(--warning-bg);
    border-color: var(--warning-text);
}

/* The link on a row result that needs the reader somewhere else. */
.upg-note__link[b-pwwlr31ma1] {
    margin-left: var(--space-1);
    white-space: nowrap;
}

/* The next-update cell also carries a booking and a row's live result, which are
   sentences rather than values. Without a floor they wrap to five words a line. */
.upg-next[b-pwwlr31ma1] {
    min-width: 13rem;
}

/* The view select's width, from the sheet's embedded bar: narrower than the
   standalone page's 230px, so the command row stays one line at 1440px. */
/* ::deep: the wrapper is rendered by SelectBox, outside this file's scope. */
[b-pwwlr31ma1] .upg-view {
    width: 190px;
}

/* The link drops onto its own line rather than stealing width from the sentence
   it belongs to. */
.upg-note[b-pwwlr31ma1] {
    flex-wrap: wrap;
    align-items: flex-start;
}

.upg-note__link[b-pwwlr31ma1] {
    flex: 0 0 100%;
    margin-left: 0;
}

/* The neutral tone, spelled out beside the warning one so the pair is visible
   in one place rather than half-inherited from the base rule. */
.upg-notice--info[b-pwwlr31ma1] {
    color: var(--ink-2);
    background: var(--surface-2);
    border-color: var(--border);
}

/* Stage 4b: a booked update on its row, and the per-row history. The dialog that
   books one is UpgradeActionRunner's, and so are its rules. */

/* Taking back a booking, on the result that announced it. */
.upg-note__cancel[b-pwwlr31ma1] {
    margin-left: var(--space-2);
}

/* One environment's history, opened under its row. */
.upg-feed[b-pwwlr31ma1] {
    padding: var(--space-3);
}

.upg-feed__title[b-pwwlr31ma1] {
    margin: 0 0 var(--space-2);
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--ink-2);
}

/* The booking marker on a row. It is the only trace of a booked update that
   survives a reload, so it carries the whole fact and both ways to act on it:
   the sentence opens the history, and a lone booking can be called off from
   here without opening anything. It reads at the foot of the next-update cell,
   under the date Business Central would otherwise run on - the two are answers
   to one question and belong in one column. */
.upg-booked[b-pwwlr31ma1] {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-top: var(--space-1);
}

/* A sentence you can press. Styled as text rather than as a button because it
   is a fact first - the button behaviour is how you get to the detail behind
   it, not the point of the row. */
.upg-booked__open[b-pwwlr31ma1] {
    display: inline-flex;
    /* Top, not centre: in a narrow cell the sentence wraps to two lines, and a
       vertically centred icon then floats down beside the second one, reading as
       a bullet on the wrong line. */
    align-items: flex-start;
    gap: var(--space-1);
    padding: 0;
    border: 0;
    background: none;
    font: inherit;
    font-size: var(--text-xs);
    color: var(--warning-text);
    text-align: left;
    cursor: pointer;
}

/* Same reach as the note's glyph: the icon is another component's markup. */
.upg-booked__open[b-pwwlr31ma1]  svg { margin-top: 2px; flex: 0 0 auto; }

.upg-booked__open:hover span[b-pwwlr31ma1],
.upg-booked__open:focus-visible span[b-pwwlr31ma1] {
    text-decoration: underline;
}

.upg-booked__cancel[b-pwwlr31ma1] {
    flex: 0 0 auto;
}

/* A note's text shares the line with its glyph rather than being pushed below
   it. The wrap rule above exists so a result's link can drop onto its own line;
   the sentence beside the glyph has to shrink instead of wrapping whole, and
   that needs a zero basis - with `auto` the browser measures the untruncated
   sentence, finds it too wide, and moves the entire span to the next line,
   leaving the icon sitting alone above it. */
.upg-note > span[b-pwwlr31ma1] {
    flex: 1 1 0;
    min-width: 0;
}

/* The glyph comes from the Icon component, so it carries that component's scope
   and not this page's - ::deep is what reaches it. */
.upg-note[b-pwwlr31ma1]  svg {
    flex: 0 0 auto;
    margin-top: 2px;
}

/* Headings here are longer than most of the values under them ("Latest possible
   date" over a date). Letting them wrap when the window is narrow keeps the table
   inside it for longer; on a wide window they stay on one line, as on the sheet. */
.data-table th[b-pwwlr31ma1] {
    white-space: normal;
}

/* The page's container clips what overflows it rather than scrolling (#574),
   so the fleet table - nine columns of real customer names and dates - gets a
   box of its own to scroll in instead of running off the right of the window. */
.upg-scroll[b-pwwlr31ma1] {
    min-width: 0;
    overflow-x: auto;
    /* Named as a size container so the open history below can be asked to be as
       wide as this box rather than as wide as the table inside it. */
    container-type: inline-size;
}

/* What a row cannot be read without stays put while the rest scrolls under it.
   Nine columns do not fit a laptop window, and the first thing to leave on the
   left was the solution name - which is the only thing saying whose environment
   the row in front of you is. The checkbox and the state glyph travel with it so
   the name is never stranded from the box that selects it. Both leading columns
   get a fixed width here because the offsets have to add up to something, and the
   border is what tells the reader the columns beyond it moved. */
.upg-scroll .data-table__col-check[b-pwwlr31ma1],
.upg-scroll .data-table__col-state[b-pwwlr31ma1] {
    width: 2.25rem;
    min-width: 2.25rem;
}

.upg-scroll .data-table__col-check[b-pwwlr31ma1],
.upg-scroll .data-table__col-state[b-pwwlr31ma1],
.upg-scroll .upg-env[b-pwwlr31ma1],
.upg-scroll .upg-customer[b-pwwlr31ma1] {
    position: sticky;
    z-index: 1;
    background: var(--surface);
}

.upg-scroll .data-table__col-check[b-pwwlr31ma1] { left: 0; }
.upg-scroll .data-table__col-state[b-pwwlr31ma1] { left: 2.25rem; }

/* The environment leads and the solution follows it, both pinned. The environment
   column has a fixed width because the solution's offset has to be a number; a name
   longer than that is cut with an ellipsis and is whole on hover and on its own page. */
.upg-scroll .upg-env[b-pwwlr31ma1] {
    left: 4.5rem;
    width: 11rem;
    min-width: 11rem;
    max-width: 11rem;
}

.upg-scroll .upg-env .cell-stack__main[b-pwwlr31ma1] {
    display: block;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.upg-scroll .upg-customer[b-pwwlr31ma1] {
    left: 15.5rem;
    white-space: nowrap;
    border-right: 1px solid var(--border);
}

/* A pinned cell paints its own background, which would otherwise leave the left
   end of a ticked row white while the rest of it is tinted. */
.upg-scroll tr.is-selected .data-table__col-check[b-pwwlr31ma1],
.upg-scroll tr.is-selected .data-table__col-state[b-pwwlr31ma1],
.upg-scroll tr.is-selected .upg-env[b-pwwlr31ma1],
.upg-scroll tr.is-selected .upg-customer[b-pwwlr31ma1] {
    background: var(--primary-weak);
}

/* The heading keeps its own tone while it sticks - the shared rule above would
   otherwise paint it as a body cell - and outranks the body cells it passes. */
.upg-scroll thead .data-table__col-check[b-pwwlr31ma1],
.upg-scroll thead .data-table__col-state[b-pwwlr31ma1],
.upg-scroll thead .upg-env[b-pwwlr31ma1],
.upg-scroll thead .upg-customer[b-pwwlr31ma1] {
    background: var(--surface-sunken);
    z-index: 2;
}

/* A row menu opens inside the scrolling box, which clips it. On a fleet of two or
   three rows there is no room in either direction, so the box makes some while a
   menu is open. Taller tables are unaffected. */
.upg-scroll:has(.ra.is-open)[b-pwwlr31ma1] {
    min-height: 15rem;
}

/* An open history spans every column, so scrolling right would carry its heading
   off the left of the box and leave the panel unreadable while the reader is
   looking at the columns that made them open it. Pinned to the box's left edge,
   it stays where it was read from. Pinning alone is not enough: a sticky box can
   only slide as far as its own containing block allows, and at the table's full
   width there is nowhere to slide - so it is sized to the scrolling box instead,
   and capped at the cell's width for the case where nothing scrolls at all. */
.upg-feed[b-pwwlr31ma1] {
    position: sticky;
    left: 0;
    width: 100cqw;
    max-width: 100%;
}

/* The panel brings its own padding, and the cell's would otherwise shorten the
   distance the pinned panel can travel by exactly that much - which showed up as
   the first letter of the heading clipped at the left edge. */
.upg-scroll tr.is-subrow td[b-pwwlr31ma1] {
    padding: 0;
}

/* A row's result, on its own line under the row and starting where the
   environment's name does. Zero width with a full min-width: the sentence fills
   the cell but adds nothing to the table's column sizing, so a long refusal
   cannot move a column. The feed's zero-padding rule is undone for this one. */
.upg-scroll tr.upg-result-row td[b-pwwlr31ma1] {
    padding: 0 var(--cell-pad-x) var(--space-2);
}

.upg-result[b-pwwlr31ma1] {
    width: 0;
    min-width: 100%;
}

.upg-result .upg-note[b-pwwlr31ma1] {
    margin-top: 0;
    font-size: var(--text-sm);
}

/* The result belongs to the row above it, so it takes that row's background
   (ticked or not) rather than the sunken tone a sub-panel gets, and the line
   between the two goes. */
.upg-scroll tr.upg-result-row td[b-pwwlr31ma1],
.upg-scroll tr.upg-result-row:hover td[b-pwwlr31ma1] {
    background: var(--surface);
}

.upg-scroll tr.upg-result-row.is-selected td[b-pwwlr31ma1] {
    background: var(--primary-weak);
}

.upg-scroll tr:has(+ tr.upg-result-row) td[b-pwwlr31ma1] {
    border-bottom: 0;
}

/* The environment is what the row is and what its first link opens, so it reads as
   the link: the stacked cell's main line is ink by default, which left the solution
   beside it looking like the only thing to click. */
a.cell-stack__main[b-pwwlr31ma1] {
    color: var(--primary-ink);
    font-weight: var(--fw-semibold);
}

/* The search box the size it is on Solutions and Environments (.filter-bar__search),
   so the three lists' first control lines up when you move between them (#966). */
.upg-search[b-pwwlr31ma1] {
    flex: 1 1 300px;
    min-width: 220px;
    max-width: 380px;
}

/* The selection, once there is one: its count, then Show selected and Clear
   selection. The count is text in the bar rather than a button, so it gets the
   bar's own control height to sit level with the buttons beside it. */
.upg-picked__count[b-pwwlr31ma1] {
    display: inline-flex;
    align-items: center;
    min-height: var(--control-h);
    padding: 0 var(--space-2);
    font-size: var(--text-sm);
    font-weight: var(--fw-medium);
    color: var(--ink-2);
    white-space: nowrap;
}

/* ── The Open and Archive views, and the page-wide parts ─────────────────── */

/* The view switch on its own row under the head. On a phone it scrolls sideways
   rather than wrapping under itself (UpgradesListBody.dc.html). */
.upg-views[b-pwwlr31ma1] {
    overflow-x: auto;
}

.upg-views[b-pwwlr31ma1]  .pill-tabs {
    width: max-content;
}

/* A plain grid item, so the filter bar inside keeps its place in the page's rhythm. */
.upg-plan-filters[b-pwwlr31ma1] {
    display: grid;
}

/* The Open view's status filter, the sheet's width. */
.upg-plan-filters[b-pwwlr31ma1]  .upg-status {
    width: 170px;
}

/* On a phone the Open view's filter is the search alone, as the sheet draws it. */
@media (max-width: 700px) {
    .upg-plan-filters[b-pwwlr31ma1]  .upg-status {
        display: none;
    }
}

/* The loading skeleton's columns, the Open table's widths. */
.upg-plan-skeleton[b-pwwlr31ma1] {
    table-layout: fixed;
}

.upg-skel[b-pwwlr31ma1] {
    display: block;
    width: 60%;
}

.upg-skel--wide[b-pwwlr31ma1] {
    width: 75%;
}

.upg-skel--pill[b-pwwlr31ma1] {
    width: 70px;
    height: 18px;
}

/* Mark done: the unchecked lines, in a sunken box under the sentence. */
.upg-done-list[b-pwwlr31ma1] {
    margin: 0;
    padding: 0;
    list-style: none;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--r-control);
}

.upg-done-list__row[b-pwwlr31ma1] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-2) var(--space-3);
    border-bottom: 1px solid var(--border);
}

.upg-done-list__row:last-child[b-pwwlr31ma1] {
    border-bottom: 0;
}

.upg-done-list__name[b-pwwlr31ma1] {
    font-size: var(--text-sm);
    font-weight: var(--fw-medium);
}

.upg-done-hint[b-pwwlr31ma1] {
    margin: var(--space-3) 0 0;
    font-size: var(--text-sm);
    color: var(--ink-3);
}

/* On a phone the command group wraps inside itself. Kept on one line it was wider
   than the screen, and since the page clips rather than scrolls sideways (#574) the
   commands at its end - and the head's New upgrade, pushed out with them - were cut
   off. */
@media (max-width: 700px) {
    .cmdbar__group[b-pwwlr31ma1] {
        flex-wrap: wrap;
    }

    .upg-search[b-pwwlr31ma1] {
        max-width: none;
    }
}
/* /Components/Shared/Archetypes/DetailPage.razor.rz.scp.css */
/* The skeleton head DetailPage draws while a page with a Loading body waits for its
   record (UpgradeBody.dc.html, kind="loading"): a title and a subtitle bar where the
   name and the note will be, and label-and-value bars in the meta row. */
.detail-skel[b-dhhh4fsv8j] { display: block; }

.detail-skel__head[b-dhhh4fsv8j] {
    display: grid;
    gap: var(--space-2);
    flex: 1;
}

.detail-skel--title[b-dhhh4fsv8j] { width: 280px; max-width: 80%; height: 22px; }
.detail-skel--sub[b-dhhh4fsv8j] { width: 180px; height: 10px; }
.detail-skel--label[b-dhhh4fsv8j] { width: 50px; height: 9px; }
.detail-skel--value[b-dhhh4fsv8j] { width: 60%; margin-top: 6px; }
/* /Components/Shared/Archetypes/FilterBar.razor.rz.scp.css */
/* The submitting search's own row: the box and the button it submits, side by
   side. Takes the flex-item role in .filter-bar that the box has when there is
   no form, so the bar lays out the same either way (#805).
   Holding only the box (and hidden inputs), the form sizes exactly as the bare
   box does in pages.css. A wider form left a gap between the search and the
   selects after it that the bare box never has (build pipelines, #1078). */
.filter-bar-form[b-fayuel6ceq] {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex: 1;
    min-width: 220px;
    max-width: 380px;
}

/* Room for what the page puts beside the box inside the form: a button, a select. */
.filter-bar-form:has(> :not(.filter-bar__search, input[type="hidden"]))[b-fayuel6ceq] {
    flex: 1 1 auto;
    min-width: 260px;
    max-width: 480px;
}
/* /Components/Shared/Archetypes/GeneratorPage.razor.rz.scp.css */
/* The Generate button lives in the sticky aside rather than a bottom bar, so
   it spans the rail and gets the taller control height the handoff gives it
   (PageGenerator.dc.html sets both inline). */
.gen__go[b-khk2omnwln] {
    width: 100%;
    height: var(--control-h-lg);
}

.gen__note[b-khk2omnwln] {
    text-align: center;
}
/* /Components/Shared/Archetypes/PageHead.razor.rz.scp.css */
/* pages-forms.css zeroes --sticky-head on .gen (its DIVERGENCE 7) because no page
   applied .page-head--sticky, and says to restore the handoff's value if one ever
   did. The admin edit pages do now, and three of them have a sticky rail
   (.gen__aside) that would otherwise slide up underneath the head. Restored here,
   by the component that makes a head sticky, and only after a head that is - so
   the generators keep their zero. */
.page-head--sticky[b-4z37hhmw2p] ~  .gen,
.page-head--sticky[b-4z37hhmw2p] ~  * .gen {
    --sticky-head: 132px;
}
/* /Components/Shared/AuditDiffViewer.razor.rz.scp.css */
/* A field diff has no line numbers, so the two .diff__gut columns the handoff's
   line diff reserves collapse to nothing. The +/- /~ marker still comes from
   .diff__ln--*::before, so a row reads the same as theirs without them. */

.diff__ln[b-kx627omvi2] {
    grid-template-columns: minmax(0, 1fr);
}

/* Field paths and values wrap rather than scroll: a JSON path plus both values
   is longer than a line of code, and this block sits in a narrow audit panel. */
.diff__code[b-kx627omvi2] {
    white-space: pre-wrap;
    word-break: break-word;
    padding-block: 2px;
}
/* /Components/Shared/AuditHistoryPanel.razor.rz.scp.css */
/* The "showing the most recent N" caveat, above the list. */
.audit-note[b-7xk612o0bs] {
    padding: var(--space-2) var(--space-4);
    border-bottom: 1px solid var(--border);
    background: var(--surface-2);
    font-size: var(--text-xs);
    color: var(--ink-3);
}

/* The handoff's audit row has no permalink; ours does, because the diff also
   lives at its own URL and people paste those into tickets. */
.audit__foot a[b-7xk612o0bs] {
    color: var(--primary-ink);
}
/* /Components/Shared/BulkAppCadenceDialog.razor.rz.scp.css */
/*
    Scoped chrome for the bulk AppSource cadence dialog. The dialog, the select and
    the field are the design system's; what is left is the grouped preview, drawn the
    same way as the bulk delivery-window dialog's, and the result marks.
*/

.bac-body[b-hcmedvj4ui] { display: grid; gap: var(--space-3); }
.bac-lead[b-hcmedvj4ui] { margin: 0; text-wrap: pretty; }
.bac-count[b-hcmedvj4ui] { margin: 0; font-size: var(--text-sm); color: var(--ink-2); }

.bac-body[b-hcmedvj4ui]  .bac-select { width: 280px; max-width: 100%; }

/* Ninety environments still can't push the buttons off the screen: the groups
   scroll, not the dialog's controls. */
.bac-groups[b-hcmedvj4ui] { display: grid; gap: var(--space-3); max-height: 22rem; overflow-y: auto; }

.bac-group__head[b-hcmedvj4ui] {
    margin: 0 0 var(--space-1);
    font-size: var(--text-xs);
    font-weight: var(--fw-semibold);
    color: var(--ink-3);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.bac-list[b-hcmedvj4ui] { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }

/* The change sits under the name, never beside it: "With major and minor updates →
   Only with major updates" is too long to share a line, and a column that is right-
   aligned on some rows and wrapped left on others can't be scanned. */
.bac-row[b-hcmedvj4ui] {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: var(--space-1) 0;
    border-bottom: 1px solid var(--border);
    font-size: var(--text-sm);
}
.bac-row:last-child[b-hcmedvj4ui] { border-bottom: none; }

.bac-row__who[b-hcmedvj4ui] { font-weight: var(--fw-semibold); color: var(--ink); }
.bac-row__what[b-hcmedvj4ui] { color: var(--ink-3); }
.bac-row--skip .bac-row__who[b-hcmedvj4ui],
.bac-row--skip .bac-row__what[b-hcmedvj4ui] { color: var(--ink-4); font-weight: var(--fw-regular); }

.bac-row__what--done[b-hcmedvj4ui] { color: var(--success-text); }
.bac-row__what--failed[b-hcmedvj4ui] { color: var(--danger-text); }
.bac-row__what--done[b-hcmedvj4ui], .bac-row__what--failed[b-hcmedvj4ui] { display: inline-flex; align-items: center; gap: var(--space-1); }

/* ::deep: the pill is rendered by StatusPill, outside this file's scope. */
.bac-row__who[b-hcmedvj4ui]  .bac-prod { margin-left: var(--space-2); font-weight: var(--fw-semibold); }

/* Names only, several to a line: fifty environments are a few lines per group, not
   fifty rows of two. */
.bac-names[b-hcmedvj4ui] {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
    gap: var(--space-1) var(--space-3);
    font-size: var(--text-sm);
}
.bac-name[b-hcmedvj4ui] { color: var(--ink); }
.bac-names--skip .bac-name[b-hcmedvj4ui] { color: var(--ink-4); }
.bac-name[b-hcmedvj4ui]  .bac-prod { margin-left: var(--space-1); }

.bac-group__head--done[b-hcmedvj4ui] { display: inline-flex; align-items: center; gap: var(--space-1); color: var(--success-text); }

/* The skipped groups start folded: a heading with its count, opened on demand. */
.bac-fold > summary[b-hcmedvj4ui] { cursor: pointer; list-style: none; display: flex; align-items: center; gap: var(--space-1); }
.bac-fold > summary[b-hcmedvj4ui]::-webkit-details-marker { display: none; }
.bac-fold > summary[b-hcmedvj4ui]::before {
    content: "";
    flex: none;
    width: 6px;
    height: 6px;
    border-right: 1.5px solid var(--ink-4);
    border-bottom: 1.5px solid var(--ink-4);
    transform: rotate(-45deg);
    transition: transform var(--transition-fast);
}
.bac-fold[open] > summary[b-hcmedvj4ui]::before { transform: rotate(45deg); }
.bac-fold > summary:focus-visible[b-hcmedvj4ui] { outline: var(--focus-ring); outline-offset: 2px; }
.bac-fold__why[b-hcmedvj4ui] { margin: 0 0 var(--space-1); font-size: var(--text-sm); color: var(--ink-3); }
/* /Components/Shared/BulkDeliveryWindowDialog.razor.rz.scp.css */
/*
    Scoped chrome for the bulk delivery-window dialog (issue #961). The dialog, the
    inputs and the check are the design system's; what is left is the window row, the
    grouped preview (the Upgrades page's preview, one line per environment) and the
    result marks.
*/

.bdw-body[b-izyvjaghdl] { display: grid; gap: var(--space-3); }
.bdw-lead[b-izyvjaghdl] { margin: 0; text-wrap: pretty; }

.bdw-window[b-izyvjaghdl] { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); }
.bdw-window__time[b-izyvjaghdl] { display: inline-flex; align-items: center; gap: var(--space-2); font-size: var(--text-sm); color: var(--ink-2); }
.bdw-zone[b-izyvjaghdl] { margin: 0; }

/* Ninety environments still can't push the buttons off the screen: the groups
   scroll, not the dialog's controls. */
.bdw-groups[b-izyvjaghdl] { display: grid; gap: var(--space-3); max-height: 22rem; overflow-y: auto; }

.bdw-group__head[b-izyvjaghdl] {
    margin: 0 0 var(--space-1);
    font-size: var(--text-xs);
    font-weight: var(--fw-semibold);
    color: var(--ink-3);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.bdw-list[b-izyvjaghdl] { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }

.bdw-row[b-izyvjaghdl] {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: var(--space-1) var(--space-3);
    padding: var(--space-1) 0;
    border-bottom: 1px solid var(--border);
    font-size: var(--text-sm);
}
.bdw-row:last-child[b-izyvjaghdl] { border-bottom: none; }

.bdw-row__who[b-izyvjaghdl] { font-weight: var(--fw-semibold); color: var(--ink); }
.bdw-row__what[b-izyvjaghdl] { color: var(--ink-3); text-align: right; font-variant-numeric: tabular-nums; }
.bdw-row--skip .bdw-row__who[b-izyvjaghdl],
.bdw-row--skip .bdw-row__what[b-izyvjaghdl] { color: var(--ink-4); font-weight: var(--fw-regular); }

.bdw-row__what--done[b-izyvjaghdl] { color: var(--success-text); }
.bdw-row__what--failed[b-izyvjaghdl] { color: var(--danger-text); }
.bdw-row__what--done[b-izyvjaghdl], .bdw-row__what--failed[b-izyvjaghdl] { display: inline-flex; align-items: center; gap: var(--space-1); }

/* A sentence under the row, not a value beside it. */
.bdw-row__note[b-izyvjaghdl] {
    flex-basis: 100%;
    display: inline-flex;
    align-items: flex-start;
    gap: var(--space-1);
    font-size: var(--text-xs);
    color: var(--ink-3);
}

/* ::deep: the pill is rendered by StatusPill, outside this file's scope. */
.bdw-row__who[b-izyvjaghdl]  .bdw-prod { margin-left: var(--space-2); font-weight: var(--fw-semibold); }
/* /Components/Shared/CodeViewer.razor.rz.scp.css */
.code-viewer-host[b-n9ykjeg9fc] {
    border: 1px solid var(--border);
    border-radius: 6px;
    overflow: hidden;
    /* Default: fixed viewport-relative height with internal scrolling.
       Used by the side-by-side diff so both panes stay aligned. The
       single-file viewer overrides this via .code-viewer-host--fluid
       to grow with content and defer scrolling to the page. */
    height: 75vh;
    display: flex;
}

.code-viewer-host--fluid[b-n9ykjeg9fc] {
    height: auto;
    min-height: 240px;
    flex-direction: column;
}

[b-n9ykjeg9fc] .cm-editor {
    height: 100%;
    width: 100%;
}

.code-viewer-host--fluid[b-n9ykjeg9fc]  .cm-editor {
    height: auto;
}

[b-n9ykjeg9fc] .cm-scroller {
    overflow: auto;
}

.code-viewer-host--fluid[b-n9ykjeg9fc]  .cm-scroller {
    /* Page scrolls vertically; the scroller itself handles horizontal
       overflow for files with long lines. Without overflow-x: auto the
       host's overflow: hidden would clip long lines entirely.
       Per CSS spec, overflow-y: visible is implicitly auto when
       overflow-x is set — but since the fluid cm-editor has
       height: auto, vertical content fits its parent exactly, so no
       phantom vertical scrollbar appears. CodeMirror still
       virtualizes via the scroller's bounding rect intersected with
       the visible window, so long files only render lines near the
       viewport. */
    overflow-x: auto;
    overflow-y: visible;
}
/* /Components/Shared/CompareReleasePickerDialog.razor.rz.scp.css */
/* Searchable release list inside the shared .confirm-dialog panel.
   Tokens mirror the ones used across tools.css; fallbacks keep it sane if a
   variable is renamed. */

.crp-search[b-rasmr5trhp] {
    width: 100%;
    margin: 3.5px 0 10.5px;
}

.crp-list[b-rasmr5trhp] {
    display: flex;
    flex-direction: column;
    gap: 2px;
    max-height: 48vh;
    overflow-y: auto;
    margin: 0;
    padding: 2px;
    border: 1px solid var(--border);
    border-radius: var(--r);
}

.crp-row[b-rasmr5trhp] {
    display: block;
    width: 100%;
    text-align: left;
    padding: 7px 9.8px;
    font: inherit;
    color: inherit;
    background: transparent;
    border: 1px solid transparent;
    border-radius: var(--r-sm);
    cursor: pointer;
}

.crp-row:hover[b-rasmr5trhp],
.crp-row:focus-visible[b-rasmr5trhp] {
    background: var(--surface-2);
    border-color: var(--border);
    outline: none;
}
/* /Components/Shared/ConfirmDialog.razor.rz.scp.css */
/* Scoped styles for the two optional halves of a confirm: the detail list a
   bulk action previews, and the type-to-confirm gate. Both live here rather
   than in components.css, which is byte-locked to the design handoff. */

/* The detail block scrolls on its own so a selection of forty environments
   can't push the buttons off the bottom of the screen. Bounded by the viewport
   rather than by a flat 15rem: a caller's detail may carry a control as well as
   a list (the Upgrades page asks when to run inside this block), and squeezing a
   field and its explanation into a short scroller hides the very thing being
   chosen. Long lists still scroll - inside themselves, not by pushing the
   control out of view. */
.confirm-dialog__detail[b-73ig27808s] {
    max-height: min(30rem, 60vh);
    overflow-y: auto;
    padding-top: 0;
}

.confirm-dialog__gate[b-73ig27808s] {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    padding-top: 0;
}

.confirm-dialog__gate-label[b-73ig27808s] {
    font-size: var(--text-sm);
    color: var(--ink-2);
}

/* The grace period: a bar that empties over the seconds left to call it off. It is
   the design system's .progress track drawn by hand, because a native <progress>
   only moves when the server sends a new value - once a second, in steps. */
.confirm-dialog__grace p[b-73ig27808s] { margin: 0 0 var(--space-3); }

.confirm-dialog__grace-bar[b-73ig27808s] {
    height: 8px;
    border-radius: var(--r-pill);
    background: var(--surface-sunken);
    overflow: hidden;
}

.confirm-dialog__grace-bar span[b-73ig27808s] {
    display: block;
    height: 100%;
    border-radius: var(--r-pill);
    background: var(--danger-strong);
    transform-origin: left;
    animation: confirm-grace-drain-b-73ig27808s linear forwards;
}

@keyframes confirm-grace-drain-b-73ig27808s {
    from { transform: scaleX(1); }
    to { transform: scaleX(0); }
}
/* /Components/Shared/CopyEnvironmentDialog.razor.rz.scp.css */
.copy-env__name[b-4snk6xyuip] { margin: var(--space-3) 0 0; }

/* The same "choose one" block the upload dialog draws for its timing. */
.copy-env__type[b-4snk6xyuip] {
    margin: var(--space-3) 0 0;
    padding: var(--space-3);
    border: 1px solid var(--border);
    border-radius: var(--r);
    background: var(--surface-2);
    display: grid;
    gap: var(--space-2);
}

.copy-env__type-legend[b-4snk6xyuip] {
    padding: 0 var(--space-1);
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--ink-2);
}

.copy-env__type-opt[b-4snk6xyuip] {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--text-sm);
    color: var(--ink-2);
}

.copy-env__notes[b-4snk6xyuip] {
    display: grid;
    gap: var(--space-2);
}

.copy-env__notes:not(:empty)[b-4snk6xyuip] { margin: var(--space-3) 0 0; }

/* Not a note: nothing here is a risk, it is how long to expect and where to look. */
.copy-env__wait[b-4snk6xyuip] {
    margin: var(--space-3) 0 0;
    font-size: var(--text-xs);
    color: var(--ink-3);
}
/* /Components/Shared/DependencyPicker.razor.rz.scp.css */
/* What is left after PR 17d. The catalogue rows are .module-card - the same
   component the sibling generator page picks modules with, which is the whole
   point of them looking identical - and the manual list is .sub-rows. Local
   here is only the geometry those two have no slot for.

   Was .dep-picker* / .dep-row* / .dep-chip* in tools.css, with its own copies of
   the input, the card and the selected-state tint. */

/* A category is a quiet grouping inside the section, one level below the
   section label - so it gets weight, not case: uppercase here would compete
   with the .section-label above it. */
.dep-cat[b-b35qsdw2f2] {
    display: grid;
    gap: var(--space-1);
}

.dep-cat + .dep-cat[b-b35qsdw2f2] {
    margin-top: var(--space-3);
}

.dep-cat__name[b-b35qsdw2f2] {
    font-size: var(--text-xs);
    font-weight: var(--fw-medium);
    color: var(--ink-3);
}

/* The version only appears once a dependency is ticked, so it sits inside the
   card rather than beside it - a column of mostly-empty version boxes reads as
   fields waiting to be filled in. */
.dep-version[b-b35qsdw2f2] {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin-top: var(--space-1);
}

.dep-version__label[b-b35qsdw2f2] {
    font-size: var(--text-2xs);
    color: var(--ink-4);
}

.dep-version__input[b-b35qsdw2f2] {
    width: 128px;
    font-family: var(--font-mono);
    font-size: var(--text-xs);
}

/* Four fields and a button on one line: id is the longest, version the
   shortest, and the button sizes to its label. */
.dep-manual[b-b35qsdw2f2] {
    display: grid;
    grid-template-columns: minmax(0, 2fr) minmax(0, 1.5fr) minmax(0, 1.5fr) minmax(0, 1fr) auto;
    gap: var(--space-2);
    align-items: center;
}

@media (max-width: 700px) {
    .dep-manual[b-b35qsdw2f2] { grid-template-columns: 1fr 1fr; }
}

/* .sub-row's own grid reserves 26px for a drag grip and 96px for a short
   value; a manual dependency has no grip and four values, one of them a GUID. */
/* A GUID is 36 mono characters and the column is sized in px to hold all of
   them - an id truncated to `63ca2fa4-...-172fef3` is exactly as useful as no
   id at all when what you are checking is whether you mistyped it. Not `ch`:
   grid track sizes resolve against the GRID CONTAINER's font, which is the
   sans body text, not the mono the cell renders in. */
.dep-manual-row[b-b35qsdw2f2] {
    grid-template-columns: 22px minmax(0, 1fr) 264px minmax(0, 1fr) 40px;
}

.dep-manual-row .sub-row__val:first-of-type[b-b35qsdw2f2] {
    width: 100%;
}

.dep-manual-row__mark[b-b35qsdw2f2] {
    width: 14px;
    height: 14px;
    color: var(--ink-4);
}
/* /Components/Shared/EnvironmentActivityFeed.razor.rz.scp.css */
/* One environment's upgrade history. A list of events rather than a table: each
   entry is a sentence about a person, and the columns a table would impose
   (kind, who, when, outcome) are exactly the words the sentence already has. */

.eaf[b-6gzutz0u5u] {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

.eaf__item[b-6gzutz0u5u] {
    display: flex;
    align-items: flex-start;
    gap: var(--space-2);
    padding: var(--space-2) 0;
    border-bottom: 1px solid var(--border);
    font-size: var(--text-sm);
}

.eaf__item:last-child[b-6gzutz0u5u] { border-bottom: none; }

/* The glyph carries the status at a glance; its colour is the only colour in
   the entry, so a failed run is findable in a long history without reading it. */
.eaf__icon[b-6gzutz0u5u] {
    display: inline-flex;
    padding-top: 2px;
    color: var(--ink-4);
}

.eaf__item--ok .eaf__icon[b-6gzutz0u5u] { color: var(--success-text); }
.eaf__item--bad .eaf__icon[b-6gzutz0u5u] { color: var(--danger-text); }
.eaf__item--pending .eaf__icon[b-6gzutz0u5u] { color: var(--warning-text); }
/* Cancelled: spelled out rather than left to the base rule, so all four states
   are visible together and none of them is an undefined class name. */
.eaf__item--muted .eaf__icon[b-6gzutz0u5u] { color: var(--ink-4); }

.eaf__body[b-6gzutz0u5u] {
    flex: 1 1 auto;
    min-width: 0;
}

/* What was asked for, then who asked and when - in that order, because the
   first question is always "has this already been done?". */
.eaf__what[b-6gzutz0u5u] {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--space-2);
}

/* The upgrade an action was run from. Muted like the who and the when beside it;
   the link keeps the link colour, since it is the way to that evening's other lines. */
.eaf__from[b-6gzutz0u5u] {
    color: var(--ink-3);
}

.eaf__status[b-6gzutz0u5u] {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-top: 2px;
    color: var(--ink-2);
}

.eaf__item--bad .eaf__status[b-6gzutz0u5u] { color: var(--danger-text); }

/* What came back. Muted: it is the detail under the headline, and on a failed
   entry the headline is already red. */
.eaf__outcome[b-6gzutz0u5u] {
    margin-top: 2px;
    font-size: var(--text-xs);
    color: var(--ink-3);
}

.eaf__cancel[b-6gzutz0u5u] {
    flex: 0 0 auto;
}
/* /Components/Shared/EnvironmentOperationsList.razor.rz.scp.css */
.env-ops__counted[b-oj1e6lx9uu] { display: flex; align-items: center; gap: var(--space-2); }
.env-ops__error[b-oj1e6lx9uu] { display: block; margin-top: var(--space-1); color: var(--danger-text); font-size: var(--fs-sm); }
.env-ops__when[b-oj1e6lx9uu] { white-space: nowrap; }
/* /Components/Shared/EnvironmentSessionsList.razor.rz.scp.css */
.env-sessions__counted[b-5iv73i45sz] { display: flex; align-items: center; gap: var(--space-2); }
.env-sessions__tools[b-5iv73i45sz] { gap: var(--space-2); align-items: center; }
.env-sessions__fresh[b-5iv73i45sz] { font-size: var(--text-sm); white-space: nowrap; }
.env-sessions__when[b-5iv73i45sz] { white-space: nowrap; }
.env-sessions__count[b-5iv73i45sz] { font-size: var(--text-sm); }
.env-sessions__note[b-5iv73i45sz] { display: flex; align-items: center; gap: var(--space-2); color: var(--ink-3); font-size: var(--text-sm); border-bottom: 1px solid var(--border); }
/* /Components/Shared/FileBrowser.razor.rz.scp.css */
/* Tree and viewer share one bordered box, like an editor window. */
.fb[b-hxdisg8eil] {
    display: grid;
    grid-template-columns: minmax(160px, 300px) minmax(0, 1fr);
    min-width: 0;
    border: 1px solid var(--border);
    border-radius: var(--r);
    background: var(--surface);
    overflow: hidden;
}

.fb--single[b-hxdisg8eil] { grid-template-columns: minmax(0, 1fr); }

/* .otree is a grid sized to its widest row; capped, so long names ellipsise
   instead of pushing the viewer over. */
.fb__tree[b-hxdisg8eil] {
    grid-template-columns: minmax(0, 1fr);
    align-content: start;
    max-height: 70vh;
    overflow-y: auto;
    border-right: 1px solid var(--border);
    background: var(--surface-2);
}

.fb__group[b-hxdisg8eil] { display: grid; grid-template-columns: minmax(0, 1fr); }

.fb__main[b-hxdisg8eil] {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.fb__bar[b-hxdisg8eil] {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    height: 30px;
    padding: 0 var(--space-3);
    border-bottom: 1px solid var(--border);
    background: var(--surface-2);
    color: var(--ink-3);
}

.fb__path[b-hxdisg8eil] {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-family: var(--font-mono);
    font-size: var(--text-2xs);
}

.fb__lines[b-hxdisg8eil] {
    margin-left: auto;
    flex: none;
    font-size: var(--text-2xs);
    color: var(--ink-4);
}

/* Inside the browser's own border the viewer drops its frame. It grows with
   the file up to the same cap as the tree, and from there the editor's own
   scroller takes both axes, so the sideways scrollbar stays in view rather
   than sitting at the foot of a tall file. */
.fb__main[b-hxdisg8eil]  .code-viewer-host {
    border: 0;
    border-radius: 0;
    min-height: 0;
}

.fb__main[b-hxdisg8eil]  .cm-scroller {
    max-height: 70vh;
    overflow: auto;
}

/* Last, so it wins over the side-by-side rules above at equal specificity. */
@container (max-width: 760px) {
    .fb[b-hxdisg8eil] { grid-template-columns: minmax(0, 1fr); }
    .fb__tree[b-hxdisg8eil] { max-height: 12rem; border-right: 0; border-bottom: 1px solid var(--border); }
}
/* /Components/Shared/FolderTreePreview.razor.rz.scp.css */
/* A folder row is a <button> so the whole row toggles, which is the affordance
   the handoff's static tree has no need for. Strip the button chrome so it is
   pixel-identical to the plain rows beside it, and give it a hover so it reads
   as clickable. */

.tree__row--toggle[b-hyr31fuyfm] {
    width: 100%;
    background: none;
    border: 0;
    font: inherit;
    text-align: left;
    cursor: pointer;
    border-radius: var(--r-control);
}

.tree__row--toggle:hover[b-hyr31fuyfm] {
    background: var(--surface-2);
}

.tree__row--toggle:focus-visible[b-hyr31fuyfm] {
    outline: var(--focus-ring);
    outline-offset: -1px;
}

/* The struck-through treatment for rows the generator will skip lives in
   app.css, not here: it also has to colour the row's icon, and that <svg>
   comes from the Icon component, so a scoped rule would never reach it. */
/* /Components/Shared/FreshnessLine.razor.rz.scp.css */
/* The freshness sentence (#964): a quiet caption-sized line under a pipeline's name,
   or at the top of the pipeline page's card. Ahead takes the warning ink, which is
   the only thing on it that asks for a look; the rest stays in the muted ink of a
   .cell-stack__sub. */
.branch-state[b-omsu4mmfxy] {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    min-width: 0;
    font-size: var(--text-sm);
    color: var(--ink-3);
}

.branch-state svg[b-omsu4mmfxy] { flex: none; opacity: .8; }

.branch-state--ahead[b-omsu4mmfxy] { color: var(--warning-text); }
/* /Components/Shared/ImportProgressBanner.razor.rz.scp.css */
/* The root rule (.oe-import-progress) is in app.css: the root is rendered by Alert,
   which a scoped rule here cannot reach. */

.oe-import-progress__body[b-ew5ie458hk] {
    flex: 1;
    display: grid;
    gap: var(--space-2);
    min-width: 0;
}

.oe-import-progress__row[b-ew5ie458hk] {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: var(--space-3);
    font-weight: var(--fw-semibold);
}

.oe-import-progress__pct[b-ew5ie458hk] {
    font-variant-numeric: tabular-nums;
    color: var(--ink-3);
}

.oe-import-progress__hint[b-ew5ie458hk] {
    margin: 0;
    font-size: var(--text-xs);
    color: var(--ink-3);
}
/* /Components/Shared/InstallTimingPicker.razor.rz.scp.css */
/* The "when" block both install dialogs draw: an upload, and an AppSource update. */
.install-when[b-m97kogo43g] {
    margin: var(--space-3) 0 0;
    padding: var(--space-3);
    border: 1px solid var(--border);
    border-radius: var(--r);
    background: var(--surface-2);
    display: grid;
    gap: var(--space-2);
}

.install-when__legend[b-m97kogo43g] {
    padding: 0 var(--space-1);
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--ink-2);
}

.install-when__opt[b-m97kogo43g] {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--text-sm);
    color: var(--ink-2);
}

/* Why the delivery window isn't offered, under the option that stands in for it. */
.install-when__hint[b-m97kogo43g] { margin: calc(-1 * var(--space-1)) 0 0 calc(var(--space-2) + 1em); }

/* The picked time, indented under its option like the Upgrades page's picker. */
.install-when__pick[b-m97kogo43g] {
    display: grid;
    gap: var(--space-2);
    margin: 0 0 var(--space-1) calc(var(--space-2) + 1em);
}

/* What was picked, said back in the page's own zone: the sentence that settles it. */
.install-when__echo[b-m97kogo43g] {
    margin: 0;
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--ink-2);
}
/* /Components/Shared/NotificationList.razor.rz.scp.css */
/* A list of notifications, on the Notifications page and in the bell's flyout:
   one line per event, unread ones marked by weight and a dot, the whole row a
   link to the page it is about. */

.notif-list[b-uvch080gig] {
    list-style: none;
    margin: 0;
    padding: 0;
}

.notif + .notif[b-uvch080gig] { border-top: 1px solid var(--border); }

.notif__link[b-uvch080gig] {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    color: var(--ink-2);
    text-decoration: none;
    font-size: var(--text-sm);
}

.notif__link:hover[b-uvch080gig] { background: var(--surface-2); }

.notif__icon[b-uvch080gig] {
    position: relative;
    display: inline-flex;
    padding-top: 2px;
    color: var(--ink-4);
}

.notif__body[b-uvch080gig] {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
    flex: 1;
}

.notif__title[b-uvch080gig] { color: var(--ink-2); }

.notif__detail[b-uvch080gig] {
    color: var(--ink-3);
    font-size: var(--text-xs);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.notif__when[b-uvch080gig] {
    flex: none;
    color: var(--ink-3);
    font-size: var(--text-xs);
    white-space: nowrap;
}

.notif--unread .notif__link[b-uvch080gig] { background: var(--primary-weak); }
.notif--unread .notif__link:hover[b-uvch080gig] { background: var(--primary-weak-strong); }

.notif--unread .notif__title[b-uvch080gig] {
    color: var(--ink);
    font-weight: var(--fw-semibold);
}

.notif--unread .notif__icon[b-uvch080gig] { color: var(--primary); }

/* The dot on the icon is the unread mark a scanning eye finds; the weight is
   the one a reader notices. */
.notif--unread .notif__icon[b-uvch080gig]::after {
    content: "";
    position: absolute;
    top: 0;
    right: -3px;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--primary);
}
/* /Components/Shared/PreviewCheckSummary.razor.rz.scp.css */
/* The nightly preview check's results, one item per upcoming version (#994). */
.pcs[b-a8em03tn27] { display: inline-flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-3); font-size: var(--text-xs); }
.pcs__item[b-a8em03tn27] { display: inline-flex; align-items: center; gap: var(--space-1); color: var(--ink-3); white-space: nowrap; }
a.pcs__item[b-a8em03tn27] { text-decoration: none; }
a.pcs__item:hover span[b-a8em03tn27] { text-decoration: underline; }
.pcs__item--passed[b-a8em03tn27] { color: var(--success-text); }
.pcs__item--failed[b-a8em03tn27] { color: var(--danger-text); }
.pcs__item--paused[b-a8em03tn27] { color: var(--warning-text); }
.pcs__item--waiting[b-a8em03tn27] { color: var(--ink-3); }
/* /Components/Shared/RecipeFileEditor.razor.rz.scp.css */
/* Row geometry only. The card, the fields, the inputs, the buttons and the
   empty state are all the design system's; what is genuinely local is that a
   file row puts two growing fields and a fixed action cluster on one line, and
   the system has no utility that makes a flex child grow.

   Was .snippet-file* in tools.css before PR 17c, along with its own copies of
   the input and textarea chrome - which is what made it drift from every other
   field on the page. */

.file-rows[b-y2gpry5vo6] {
    display: grid;
    gap: var(--space-3);
}

.file-row__head[b-y2gpry5vo6] {
    display: flex;
    align-items: flex-end;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
}

/* The toggle is a control, not a field, so it sits on the input's line rather
   than the label's - hence the fixed height matching --control-h. */
.file-row__toggle[b-y2gpry5vo6] {
    flex: none;
    align-self: flex-end;
    height: var(--control-h);
}

.file-row__field[b-y2gpry5vo6] {
    flex: 1;
    min-width: 0;
}

.file-row__actions[b-y2gpry5vo6] {
    flex: none;
    align-self: flex-end;
}

.file-row__content[b-y2gpry5vo6] {
    padding: 0 var(--space-4) var(--space-4);
}

/* The mono face is .textarea--code; .textarea already resizes vertically. What
   is left is the horizontal scroll: the markup sets wrap="off" so an AL line
   runs off the side rather than reflowing mid-statement, and the textarea has
   to be allowed to scroll to it. */
.file-row__code[b-y2gpry5vo6] {
    overflow-x: auto;
}
/* /Components/Shared/RecipeTypeBadge.razor.rz.scp.css */
/* A recipe's type is a category, not a lifecycle state, so it is neither a
   .status-pill (which the design system reserves for states) nor a plain .tag
   (which is one neutral colour). Three fixed hues, matched to the icons.

   Sized against .status-pill deliberately: on the recipe-detail head the two
   sit side by side and any height difference reads as a mistake. Square, not
   pill-shaped - the curve is the one thing the BC redesign removed. Was .rtype
   in tools.css until PR 17c; the shape stayed, the home moved. Closes #536.

   The type modifiers are bare words (.snippet / .pattern / .module) because the
   C# returns those strings; scoped CSS keeps them from colliding with anything
   else, which is what they used to do in a shared sheet. */

.rtype[b-wnvqpx16co] {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    flex: 0 0 auto;
    height: 20px;
    padding: 0 var(--space-2);
    font-size: var(--text-2xs);
    font-weight: var(--fw-semibold);
    letter-spacing: .09em;
    text-transform: uppercase;
    border-radius: var(--r-badge);
}

.rtype[b-wnvqpx16co]  svg { width: 13px; height: 13px; }

.rtype.snippet[b-wnvqpx16co] { color: var(--st-trans); background: var(--st-trans-bg); }
.rtype.pattern[b-wnvqpx16co] { color: var(--code-num); background: color-mix(in srgb, var(--code-num) 12%, transparent); }
.rtype.module[b-wnvqpx16co]  { color: var(--st-final); background: var(--st-final-bg); }
/* /Components/Shared/ReleaseAgainDialog.razor.rz.scp.css */
/*
    Scoped chrome for the "Deploy again" dialog (DeliveryRowPanel.dc.html, section 4).
    The dialog, the checks and the facts' label/value pairs are the design system's;
    what is left is the sunken facts box, the environment type beside its name, and a
    check whose label carries a title and a caption.
*/

.ra-body[b-l2kfly9jgw] { display: grid; gap: var(--space-3); }
.ra-lead[b-l2kfly9jgw] { margin: 0; text-wrap: pretty; }

.ra-facts[b-l2kfly9jgw] {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
    gap: var(--space-2) var(--space-4);
    padding: var(--space-3);
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--r-control);
}

/* A fact wraps rather than clips: the apps and the build's source are read whole. */
.ra-facts .meta-item__value[b-l2kfly9jgw] { white-space: normal; overflow-wrap: anywhere; }

.ra-type[b-l2kfly9jgw] { color: var(--ink-3); }
.ra-type--prod[b-l2kfly9jgw] { color: var(--danger-text); font-weight: var(--fw-semibold); }

.ra-check[b-l2kfly9jgw] { align-items: flex-start; }
.ra-check__box[b-l2kfly9jgw] { margin-top: 2px; }
.ra-check__text[b-l2kfly9jgw] { display: grid; gap: 1px; }
.ra-check__title[b-l2kfly9jgw] { color: var(--ink); font-size: var(--text-sm); font-weight: var(--fw-medium); }
.ra-check__hint[b-l2kfly9jgw] { font-size: var(--text-xs); color: var(--ink-3); }
/* /Components/Shared/ReleaseBuildDialog.razor.rz.scp.css */
/*
    Scoped chrome for the deployment dialog.

    Everything else is the design system's - .field, .input, .select,
    .field__hint, .field-warn, .check. What is left is the one row that pairs a
    datetime input with a "Now" shortcut, and the production acknowledgement.
*/

.rb-when-row[b-e8fnw83g7y] { display: flex; align-items: center; gap: var(--space-2); }
.rb-when-row .input[b-e8fnw83g7y] { flex: 1; min-width: 0; }

/* What the picked build installs, listed just above the acknowledgement so the
   apps and versions are on screen at the point of no return (#714). */
.rb-apps[b-e8fnw83g7y] { margin: var(--space-3) 0; }
.rb-apps__label[b-e8fnw83g7y] { display: block; font-size: var(--text-xs); font-weight: var(--fw-medium); color: var(--ink-3); margin-bottom: var(--space-1); }
.rb-apps__list[b-e8fnw83g7y] { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; }
.rb-apps__list li[b-e8fnw83g7y] { display: flex; align-items: baseline; gap: var(--space-2); font-size: var(--text-sm); }
.rb-apps__name[b-e8fnw83g7y] { color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rb-apps__ver[b-e8fnw83g7y] { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--ink-3); font-variant-numeric: tabular-nums; }
/* /Components/Shared/RepositoryPicker.razor.rz.scp.css */
/* The shared GitHub repository picker. Everything structural comes from the
   design system - .input, .btn, .empty-state, .field__hint - so what is local
   here is only the geometry a typeahead needs and that none of those carry:
   the magnifier sitting inside the box, and the result rows. */

.repo-picker[b-f0xyk2oxol] {
    display: grid;
    gap: var(--space-2);
}

/* The search box, with the magnifier inside it rather than beside it: the icon
   is what says "type to search", so it has to be part of the control. */
.repo-picker__search[b-f0xyk2oxol] {
    position: relative;
    display: block;
}

.repo-picker__search-icon[b-f0xyk2oxol] {
    position: absolute;
    display: inline-flex;
    left: var(--space-3);
    top: 50%;
    transform: translateY(-50%);
    color: var(--ink-4);
    pointer-events: none;
}

.repo-picker__input[b-f0xyk2oxol] {
    width: 100%;
    padding-left: calc(var(--space-3) * 2 + 15px);
}

/* The results are a short list, not a dropdown: this picker lives inside a
   card in a column, where an overlay would cover the very copy explaining what
   picking one does. */
.repo-picker__results[b-f0xyk2oxol] {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: var(--space-1);
    max-height: 260px;
    overflow-y: auto;
}

.repo-picker__result[b-f0xyk2oxol] {
    display: grid;
    gap: 2px;
    width: 100%;
    text-align: left;
    padding: var(--space-2) var(--space-3);
    border: 1px solid var(--border);
    border-radius: var(--r-control);
    background: var(--surface);
    color: var(--ink-2);
    cursor: pointer;
    font: inherit;
}

.repo-picker__result:hover:not(:disabled)[b-f0xyk2oxol],
.repo-picker__result:focus-visible[b-f0xyk2oxol] {
    border-color: var(--primary);
    background: var(--surface-2);
}

.repo-picker__result:disabled[b-f0xyk2oxol] {
    cursor: default;
    opacity: 0.6;
}

.repo-picker__result-name[b-f0xyk2oxol] {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--text-sm);
    font-weight: var(--fw-medium);
}

.repo-picker__result-sub[b-f0xyk2oxol] {
    font-size: var(--text-xs);
    color: var(--ink-3);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Once one is chosen the control collapses to a single row: the name, the
   branch a pull request would target, and the way back to the list. */
.repo-picker__chosen[b-f0xyk2oxol] {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-3);
    border: 1px solid var(--border);
    border-radius: var(--r-control);
    background: var(--surface-2);
}

.repo-picker__mark[b-f0xyk2oxol] {
    display: inline-flex;
    color: var(--ink-3);
    flex: none;
}

.repo-picker__name[b-f0xyk2oxol] {
    flex: 1 1 auto;
    min-width: 0;
    font-size: var(--text-sm);
    font-weight: var(--fw-medium);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Named rather than bare - see the markup's note - so this is a phrase with a
   branch in it rather than a lone monospace chip. */
.repo-picker__branch[b-f0xyk2oxol] {
    flex: none;
    font-size: var(--text-2xs);
    color: var(--ink-4);
}

.repo-picker__private[b-f0xyk2oxol] {
    display: inline-flex;
    color: var(--ink-4);
}

/* A repository the caller already has. Quiet - it is a statement of fact on a
   row that cannot be clicked, not an outcome the user just produced. */
.repo-picker__added[b-f0xyk2oxol] {
    flex: none;
    padding: 1px var(--space-2);
    border: 1px solid var(--border);
    border-radius: var(--r-pill);
    background: var(--surface);
    font-size: var(--text-2xs);
    font-weight: var(--fw-medium);
    color: var(--ink-3);
}
/* /Components/Shared/RescheduleDeploymentDialog.razor.rz.scp.css */
/* The "when" choices, drawn like the install dialogs' (InstallTimingPicker.razor.css). */
.rs-when[b-2isgf5qs5h] {
    margin: var(--space-3) 0 0;
    padding: var(--space-3);
    border: 1px solid var(--border);
    border-radius: var(--r);
    background: var(--surface-2);
    display: grid;
    gap: var(--space-2);
}

.rs-when__legend[b-2isgf5qs5h] {
    padding: 0 var(--space-1);
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--ink-2);
}

.rs-when__opt[b-2isgf5qs5h] {
    display: inline-flex;
    align-items: flex-start;
    gap: var(--space-2);
    font-size: var(--text-sm);
    color: var(--ink-2);
}

/* The radio sits beside the first line when an option wraps. */
.rs-when__opt input[b-2isgf5qs5h] { margin-top: 0.2em; flex: none; }

.rs-when__opt input:disabled + span[b-2isgf5qs5h] { color: var(--ink-3); }

/* Why the two Business Central updates can't be picked, said plainly under them. */
.rs-when__why[b-2isgf5qs5h] {
    font-size: var(--text-sm);
    color: var(--ink-2);
}

/* The picked time and the hints, indented under their option. */
.rs-when__sub[b-2isgf5qs5h] {
    display: grid;
    gap: var(--space-2);
    margin: 0 0 var(--space-1) calc(var(--space-2) + 1em);
}

/* The picked time said back on the customer's clock. */
.rs-when__echo[b-2isgf5qs5h] {
    margin: 0;
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--ink-2);
}
/* /Components/Shared/SolutionPicker.razor.rz.scp.css */
/* The customer combobox. Everything structural comes from the design system -
   .input, .btn - so what is local here is the geometry a typeahead needs: the
   list that hangs under the box, and its rows. Unlike the repository picker,
   this one overlays: it sits in the middle of a long form, where pushing the
   rest of the fields down on every keystroke would be the more disruptive of
   the two. */

.solution-picker[b-vqw2zcqcq5] {
    display: grid;
    gap: var(--space-1);
}

.solution-picker__control[b-vqw2zcqcq5] {
    position: relative;
    display: block;
}

.solution-picker__input[b-vqw2zcqcq5] {
    width: 100%;
}

/* Picked: the name and the way back to searching, on one row. */
.solution-picker__chosen[b-vqw2zcqcq5] {
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

.solution-picker__input--chosen[b-vqw2zcqcq5] {
    background: var(--surface-2);
    color: var(--ink-2);
}

.solution-picker__clear[b-vqw2zcqcq5] {
    flex: none;
}

.solution-picker__list[b-vqw2zcqcq5] {
    position: absolute;
    z-index: 20;
    left: 0;
    right: 0;
    top: calc(100% + var(--space-1));
    list-style: none;
    margin: 0;
    padding: var(--space-1);
    display: grid;
    gap: 2px;
    max-height: 280px;
    overflow-y: auto;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-control);
    box-shadow: var(--shadow-lg);
}

.solution-picker__row[b-vqw2zcqcq5] {
    display: grid;
    gap: 2px;
    padding: var(--space-2) var(--space-3);
    border-radius: var(--r-control);
    color: var(--ink-2);
    cursor: pointer;
}

.solution-picker__row:hover[b-vqw2zcqcq5],
.solution-picker__row[aria-selected="true"][b-vqw2zcqcq5] {
    background: var(--surface-2);
}

.solution-picker__row-name[b-vqw2zcqcq5] {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--text-sm);
    font-weight: var(--fw-medium);
}

.solution-picker__row-sub[b-vqw2zcqcq5] {
    display: flex;
    gap: var(--space-2);
    font-size: var(--text-xs);
    color: var(--ink-3);
}

/* The last row is an act, not a match, so it reads as one. */
.solution-picker__row--create[b-vqw2zcqcq5] {
    border-top: 1px solid var(--border);
    border-radius: 0 0 var(--r-control) var(--r-control);
    color: var(--primary);
}

/* The last line of a truncated list. A statement, not a row: no hover, no
   pointer, nothing to press. */
.solution-picker__more[b-vqw2zcqcq5] {
    padding: var(--space-2) var(--space-3);
    border-top: 1px solid var(--border);
    font-size: var(--text-xs);
    color: var(--ink-3);
}

/* The create choice, once it has been made. Quiet but visible: the field
   otherwise looks exactly like plain typing, which is the one thing this
   state is not. */
.solution-picker__new[b-vqw2zcqcq5] {
    display: flex;
    align-items: flex-start;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-top: var(--space-1);
    padding: var(--space-2) var(--space-3);
    border: 1px solid var(--border);
    border-radius: var(--r-control);
    background: var(--surface-2);
    font-size: var(--text-xs);
    color: var(--ink-2);
}

/* The sentence takes the width it needs so the icon stays beside its first
   line rather than sitting alone above it. */
.solution-picker__new > span[b-vqw2zcqcq5] {
    flex: 1 1 12ch;
    min-width: 0;
}
/* /Components/Shared/StorageBar.razor.rz.scp.css */
/* The bar itself is the design system's .quota block in shell.css, including
   the --warn / --danger fills (which used to be two hardcoded hex values here).
   What the handoff has no equivalent for is calling out the *number* once an
   org is over its quota — the fill is already full at that point, so the fill
   alone can't distinguish "at the limit" from "past it". */

.quota--danger .quota__val[b-8rp66vn00a] {
    color: var(--danger-text);
    font-weight: var(--fw-semibold);
}
/* /Components/Shared/ToastHost.razor.rz.scp.css */
/* The design system's .toast is a static component: it ships the look and a
   .is-dismissed hard-hide, but no entry or exit, because in the hand-off the
   toast is drawn in place on a spec sheet. Ours appear and leave on a timer,
   so the fade lives here.

   Scoped, so it wins over components.css on specificity without editing the
   shared sheet -- there is nothing to push upstream, the design system is
   right not to bake a transition into a static spec. */

.toast[b-hecmgbs9zz] {
    opacity: 0;
    transform: translateY(6px);
    transition: opacity var(--transition-fast), transform var(--transition-fast);
}

.toast.is-shown[b-hecmgbs9zz] {
    opacity: 1;
    transform: none;
}

/* The stack stays mounted whether or not there is a message, so the fade has
   something to run on. An invisible box in the bottom-right corner would still
   swallow clicks, and the toast is never interactive, so neither takes them.

   It is also a fixed pill that sizes to the one message inside it -- but it is
   mounted at the page root, and a page frame can set a height on every root
   child. The power-tool frame does (`.app__content-inner:has(.pw) > *` in
   pages-power.css, for the panes that have to fill the column), and
   `height: 100%` on a fixed box resolves against the VIEWPORT: the stack grew
   to the full window and stretched its single grid row, so the Translator's
   save confirmation was a message box the height of the screen. Same shape as
   the `:not(.toast-stack)` width exclusion in app.css, kept here so the stack
   is immune to the next frame rule too. */
.toast-stack[b-hecmgbs9zz] {
    pointer-events: none;
    height: auto;
}

@media (prefers-reduced-motion: reduce) {
    .toast[b-hecmgbs9zz] {
        transform: none;
        transition: opacity var(--transition-fast);
    }
}
/* /Components/Shared/UploadAppDialog.razor.rz.scp.css */
.upload-app__file[b-isyhtl2ago] {
    margin: var(--space-3) 0 0;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3);
    font-size: var(--text-sm);
}

.upload-app__name[b-isyhtl2ago] { font-family: var(--font-mono); color: var(--ink-2); }

/* The chosen files, numbered: the order they will install in. */
.upload-app__list[b-isyhtl2ago] {
    margin: var(--space-2) 0 0;
    padding-left: var(--space-5);
    display: grid;
    gap: var(--space-1);
    font-size: var(--text-sm);
}

.upload-app__item[b-isyhtl2ago] {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
    align-items: baseline;
}
