/* /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;
}
/* /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;
}
/* /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/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); }

/* What the last "Refresh from repositories" run did, and where a learned pair
   came from - the repository, linked to the file itself on GitHub. */
.tr-mem-refresh[b-184apg9c9s] { margin-bottom: 14px; }
/* 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/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. */

.gen__go[b-vh89n9u8vc] {
    width: 100%;
    height: var(--control-h-lg);
}

.gen__note[b-vh89n9u8vc] {
    text-align: center;
}

/* 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);
}

.ext-deliver > .alert[b-vh89n9u8vc] {
    justify-self: stretch;
}

.ext-repo p[b-vh89n9u8vc],
.ext-deliver p[b-vh89n9u8vc] {
    margin: 0;
}

/* 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 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. */

.gen__go[b-f0j5s9zbnc] {
    width: 100%;
    height: var(--control-h-lg);
}

.gen__note[b-f0j5s9zbnc] {
    text-align: center;
}

/* 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);
}

.ws-repo p[b-f0j5s9zbnc] {
    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;
}
/* /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 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; }
/* /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;
}
/* /Components/Pages/Pipelines/ReleasePipelineDetail.razor.rz.scp.css */
/*
    Scoped chrome for the release-pipeline detail page.

    The page follows PageDetail.dc.html - crumbs, .detail-head with the
    environment type beside the title, a .meta-row of facts - and the delivery
    history is a .run-list, which the archetype sheet reserves for "card-like
    histories that are not tabular". What is left here is the one thing that
    makes this history non-tabular: a release expands into one sub-row per app
    it installed.
*/

/* The sub-rows span the row's six tracks, the way .run-progress does, so the
   apps hang under the release they belong to instead of starting rows of their
   own. The row's own column gap would push them off the id column, so they take
   the id track's width as a left inset and line up with the title above. */
.rp-apps[b-iv62ns9yut] {
    grid-column: 1 / -1;
    display: grid;
    gap: 2px;
    margin: var(--space-1) 0 var(--space-2);
    padding-left: calc(92px + var(--space-3));
}

.rp-app[b-iv62ns9yut] { display: flex; align-items: center; gap: var(--space-2); font-size: var(--text-sm); min-width: 0; }
.rp-app__state[b-iv62ns9yut] { display: inline-flex; flex: none; color: var(--ink-4); }
.rp-app__state--succeeded[b-iv62ns9yut] { color: var(--success-text); }
.rp-app__state--failed[b-iv62ns9yut] { color: var(--danger-text); }
.rp-app__state--running[b-iv62ns9yut] { color: var(--info-text); }
.rp-app__name[b-iv62ns9yut] { font-weight: var(--fw-medium); color: var(--ink-2); }
.rp-app__ver[b-iv62ns9yut] { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--ink-4); font-variant-numeric: tabular-nums; }
.rp-app__msg[b-iv62ns9yut] { color: var(--danger-text); font-size: var(--text-xs); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* A scheduled release that falls outside the customer's update window. Allowed,
   and merely recorded - so it takes the warning tone, not the error one, for
   the same reason .field-warn exists. */
.rp-outside[b-iv62ns9yut] { display: inline-flex; align-items: center; gap: 2px; margin-left: var(--space-2); font-size: var(--text-xs); font-weight: var(--fw-medium); color: var(--warning-text); }

/* A delivery's failure message, on the row's second line. */
.rp-fail[b-iv62ns9yut] { color: var(--danger-text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* The .run-row grid is `92px 1fr auto auto auto auto` with align-items: center.
   A row that carries sub-rows is two grid rows tall, and centring the first one
   in the leftover space floats the id and the state away from the title they
   describe - they belong on the top line. */
.run-row:has(.rp-apps)[b-iv62ns9yut] { align-items: start; padding-top: var(--space-3); }
.run-row:has(.rp-apps) .run-row__id[b-iv62ns9yut],
.run-row:has(.rp-apps) .run-row__state[b-iv62ns9yut],
.run-row:has(.rp-apps) .run-row__time[b-iv62ns9yut],
.run-row:has(.rp-apps) .run-row__dur[b-iv62ns9yut],
.run-row:has(.rp-apps) .run-row__acts[b-iv62ns9yut] { margin-top: 1px; }
/* /Components/Pages/Pipelines/ReleasePipelinesBrowser.razor.rz.scp.css */
/* The target cell keeps its environment-type pill next to the environment name
   — a cell, not a row, so the pill is the right carrier here. */

.rp-env[b-98aur5rvbf] {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    flex-wrap: wrap;
}

/* Force Sync can drop columns on install, so it is called out beside the name
   rather than hidden in the row menu. Not a row state: the pipeline is fine,
   the setting is just one worth seeing before you publish. */
.rp-force[b-98aur5rvbf] {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    margin-left: var(--space-2);
    font-size: var(--text-2xs);
    font-weight: var(--fw-medium);
    color: var(--warning-text);
}
/* /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. */

.drift[b-6z7v4e6aj0] {
    display: grid;
    gap: var(--space-3);
    margin-bottom: 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/ProjectDetail.razor.rz.scp.css */
/*
    Scoped chrome for the project settings page.

    The page is the settings archetype - .settings, .header-tabs, .card +
    .card__body + .form-sec, .form-actions - with the environment list as a
    .data-table and the pipeline list as .sub-rows. What is left here is the
    two things the design system has no opinion about: the update-window
    editor that opens as a table sub-row, and the pipeline row's chevron.
*/

/* The update window opens under the environment it belongs to, as a
   .data-table sub-row rather than a floating panel - so it can never drift
   away from the row that opened it. */
.pd-window[b-a2zlxe053a] { display: flex; align-items: center; flex-wrap: wrap; gap: var(--space-2); margin-bottom: var(--space-2); }
.pd-window__time[b-a2zlxe053a] { display: inline-flex; align-items: center; gap: var(--space-2); font-size: var(--text-sm); color: var(--ink-3); }
.pd-window__time .input[b-a2zlxe053a] { width: 120px; }

/* An environment Business Central no longer reports. The row's keyline and
   glyph already say something is wrong; this says what. */
.pd-gone[b-a2zlxe053a] { 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-a2zlxe053a] { 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-a2zlxe053a] { 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 release is not broken, it is aimed at a time the
   environment will refuse. Icon plus text, never colour alone. */
.pd-env-note--warn[b-a2zlxe053a] {
    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 toolbox" - a bare underline would read as a link
   to another page in here. */
.pd-env-link[b-a2zlxe053a] { display: inline-flex; align-items: center; gap: var(--space-1); color: inherit; text-decoration: none; }
.pd-env-link:hover span[b-a2zlxe053a] { text-decoration: underline; }
.pd-env-link__icon[b-a2zlxe053a] { 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. */
.pd-env-prod[b-a2zlxe053a] { font-weight: var(--fw-semibold); border-color: var(--ink-4); }
.pd-env-prod .status-pill__dot[b-a2zlxe053a] { 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-a2zlxe053a] { min-width: 0; }
.pd-env-scroll[b-a2zlxe053a] { overflow-x: auto; }

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

/* 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-a2zlxe053a] { text-decoration: none; color: inherit; }
.pd-pipe:hover .sub-row__name[b-a2zlxe053a] { color: var(--primary-ink); }
.pd-pipe__chev[b-a2zlxe053a] { color: var(--ink-4); flex: none; }

/* 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-a2zlxe053a] { 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-a2zlxe053a] {
    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-a2zlxe053a] { margin: 0; }

/* 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-a2zlxe053a] { display: grid; gap: var(--space-5); align-content: start; min-width: 0; }

/* The setup checklist in the rail. The system's .steps is built for the wide
   main column - a 30px counter badge in its own grid column - which leaves
   about 200px of measure once it is squeezed into the 280px rail. This is the
   same idea at rail density: the number is inline, and each step leads with
   the portal it happens in, because "which of the three admin centers is this"
   is the question a reader actually has. */
.pd-setup[b-a2zlxe053a] { display: grid; gap: var(--space-3); margin: 0; padding: 0 0 0 var(--space-4); font-size: var(--text-xs); color: var(--ink-3); }
.pd-setup li[b-a2zlxe053a] { display: grid; gap: 2px; text-wrap: pretty; }
.pd-setup li[b-a2zlxe053a]::marker { color: var(--ink-4); font-weight: var(--fw-semibold); }
.pd-setup__where[b-a2zlxe053a] { font-weight: var(--fw-medium); color: var(--ink); overflow-wrap: anywhere; }
.pd-setup code[b-a2zlxe053a] { font-family: var(--font-mono); font-size: var(--text-2xs); overflow-wrap: anywhere; }
.pd-setup__lead[b-a2zlxe053a] { margin: 0; font-size: var(--text-xs); color: var(--ink-3); text-wrap: pretty; }
/* The partner case is a footnote, not a fourth step - most connections never
   need it, and numbering it would imply they do. */
.pd-setup__note[b-a2zlxe053a] { 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 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 page's. */
.pd-danger[b-a2zlxe053a] { overflow: hidden; }
.pd-danger[b-a2zlxe053a]  .setting { grid-template-columns: minmax(0, 1fr) auto; border-bottom: 0; }
@container (max-width: 720px) { .pd-danger[b-a2zlxe053a]  .setting { grid-template-columns: minmax(0, 1fr); } }


/* 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-a2zlxe053a] { 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-a2zlxe053a] { color: var(--ink-4); font-weight: var(--fw-medium); }

/* The environment panel: four live reads from Business Central, shown in a sub-row
   under the environment they describe. Sections stack rather than sitting in a grid,
   because each one is a short list and a consultant reads them top to bottom. */
.pd-panel[b-a2zlxe053a] { display: flex; flex-direction: column; gap: var(--space-4); }

.pd-panel__head[b-a2zlxe053a] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    font-size: var(--text-xs);
}

.pd-panel__sec[b-a2zlxe053a] { display: flex; flex-direction: column; gap: var(--space-1); }

.pd-panel__title[b-a2zlxe053a] {
    margin: 0;
    font-size: var(--text-xs);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-muted);
}

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

.pd-panel__list > li[b-a2zlxe053a] {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: var(--space-2);
    font-size: var(--text-sm);
}

.pd-panel__name[b-a2zlxe053a] { font-weight: 500; }

/* Ours, or at least per-tenant: the whole reason a consultant scans this list. A
   left keyline rather than a colour swap, so it survives a colour-blind reading. */
.pd-panel__list > li.is-ours[b-a2zlxe053a] {
    border-left: 2px solid var(--accent);
    padding-left: var(--space-2);
}

.pd-panel__ours[b-a2zlxe053a] {
    font-size: var(--text-xs);
    color: var(--accent);
}

/* Writes that reach the customer's tenant. The banner is not decoration: it is the
   one line that tells a consultant these controls are not local settings. */
.pd-panel__warn[b-a2zlxe053a] {
    display: inline-flex;
    align-items: flex-start;
    gap: var(--space-1);
    color: var(--warning-text);
    font-size: var(--text-xs);
}

.pd-panel__setting[b-a2zlxe053a] {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-2);
    padding: var(--space-2) 0;
    border-top: 1px solid var(--border);
}

/* The caption owns the full width under its control rather than joining the row. */
.pd-panel__setting .field__hint[b-a2zlxe053a] { flex-basis: 100%; margin: 0; }

/* The line that says what Business Central reports after a write. Without it a
   successful cadence change looks identical to nothing happening. */
.pd-panel__done[b-a2zlxe053a] {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    font-size: var(--text-xs);
    color: var(--success-text);
}
/* /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); }
.projects__locked td:first-child[b-con1j7qv7o] { color: var(--ink-4); }
/* /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. */

.untracked-repos[b-im6hoxh1jk] {
    display: grid;
    gap: var(--space-3);
    margin-bottom: 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;
}

.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);
}

.rd-jumps[b-ctpmp6sjjc] {
    padding: var(--space-1);
    display: grid;
    gap: 1px;
    /* The rail track is a fixed 280px. Without this a grid item is free to grow
       to its content's min-content width, and a jump row's min-content is the
       longest unbroken file name in the recipe - which pushed the whole card out
       past the right edge of .app__content (overflow-x: hidden, so it was cut
       off rather than scrollable). See issue #605. */
    min-width: 0;
}

.rd-jump[b-ctpmp6sjjc] {
    min-width: 0;
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2);
    border-radius: var(--r);
    color: var(--ink-2);
    font-family: var(--font-mono);
    font-size: var(--text-2xs);
    text-decoration: none;
    transition: background var(--transition-fast), color var(--transition-fast);
}

.rd-jump svg[b-ctpmp6sjjc] {
    color: var(--ink-4);
    flex: none;
}

.rd-jump__stack[b-ctpmp6sjjc] {
    min-width: 0;
    display: grid;
    gap: 1px;
}

.rd-jump__name[b-ctpmp6sjjc],
.rd-jump__dir[b-ctpmp6sjjc] {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.rd-jump__dir[b-ctpmp6sjjc] {
    color: var(--ink-4);
}

.rd-jump:hover[b-ctpmp6sjjc] {
    background: var(--surface-2);
    color: var(--ink);
}

.rd-jump.is-active[b-ctpmp6sjjc] {
    background: var(--primary-weak);
    color: var(--primary-ink);
}

.rd-jump.is-active svg[b-ctpmp6sjjc] {
    color: var(--primary);
}

.rd-jump:focus-visible[b-ctpmp6sjjc] {
    outline: var(--focus-ring);
    outline-offset: calc(var(--focus-offset) * -1);
}

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

/* minmax(0, 1fr), not the implicit `auto` column: a grid's auto track is sized
   to its content's MIN-content, and `.cl-c { white-space: pre }` makes a code
   line's min-content its full unwrapped width. So one long AL procedure
   signature stretched this section to 1600px inside a 916px column, pushing the
   block off the right edge — and `.app__content` has `overflow-x: hidden`, so
   it was clipped rather than scrollable. Letting the track shrink below its
   content puts the scrolling back where it belongs, in .rd-file__body. */
.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. */
.rd-prose--muted[b-ctpmp6sjjc] {
    margin: 0;
    color: var(--ink-3);
}

/* ---------- file blocks ---------- */

.rd-file + .rd-file[b-ctpmp6sjjc] {
    margin-top: var(--space-3);
}

/* .code-block__bar is built for a name and a button; the name is a toggle here
   so the whole left side collapses the block. */
.rd-file__name[b-ctpmp6sjjc] {
    appearance: none;
    border: 0;
    background: transparent;
    font: inherit;
    cursor: pointer;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: 0;
    color: var(--ink-2);
    text-align: left;
}

.rd-file__name > svg[b-ctpmp6sjjc] {
    flex: none;
    color: var(--ink-4);
}

.rd-file__name:hover .code-block__name[b-ctpmp6sjjc] {
    color: var(--ink);
}

.rd-file__name:focus-visible[b-ctpmp6sjjc] {
    outline: var(--focus-ring);
    outline-offset: var(--focus-offset);
}

.rd-file__chev[b-ctpmp6sjjc] {
    transition: transform var(--transition-fast);
}

.rd-file.is-collapsed .rd-file__chev[b-ctpmp6sjjc] {
    transform: rotate(-90deg);
}

.rd-file.is-collapsed .code-block__bar[b-ctpmp6sjjc] {
    border-bottom: 0;
}

.rd-file__lines[b-ctpmp6sjjc] {
    flex: none;
    font-size: var(--text-2xs);
    color: var(--ink-4);
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

/* The handoff's .code-block pre pads and scrolls itself. Ours can't: the line
   numbers are a per-row grid, so the gutter has to stay put while the code
   scrolls, which means the scroll belongs to the wrapper and the padding to the
   rows. */
.rd-file__body[b-ctpmp6sjjc] {
    overflow-x: auto;
}

.rd-file pre[b-ctpmp6sjjc] {
    padding: 0;
    overflow: visible;
    white-space: normal;
}

.rd-file code[b-ctpmp6sjjc] {
    display: block;
    padding-block: var(--space-2);
    white-space: normal;
}

.rd-file .cl[b-ctpmp6sjjc] {
    display: grid;
    grid-template-columns: 46px 1fr;
}

.rd-file .cl-n[b-ctpmp6sjjc] {
    text-align: right;
    padding-right: var(--space-4);
    color: var(--ink-4);
    opacity: .65;
    user-select: none;
    font-variant-numeric: tabular-nums;
}

.rd-file .cl-c[b-ctpmp6sjjc] {
    white-space: pre;
    padding-right: var(--space-5);
    color: var(--ink-2);
}

/* Collapsed to one column the rail lands after the files it describes, which
   buries the facts a reader wants first and puts a jump list below its own
   targets. 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;
    }
}

/* .code-block__name ellipsises, but only if it is allowed to shrink; as a flex
   item its default min-width is its (unwrapped, nowrap) text, so a long file
   name widened the whole block instead. Same fix as the rail's, same issue. */
.rd-file__name .code-block__name[b-ctpmp6sjjc] {
    min-width: 0;
}

/* 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/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);
}
.tr-langsel[b-pg98q3zrne] { width: 18ch; flex: none; }

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

.tr-kindsel[b-pg98q3zrne] { 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; }
}
/* /Components/Pages/Upgrades/UpgradesPage.razor.rz.scp.css */
/* Upgrades page. Everything here is either the selection column (which no other
   table in the app has) or a small note beside a value; the table, pills,
   buttons and empty states come from the design system unchanged. */

/* The checkbox column: narrow, centred, and the same width in the loading
   skeleton as in the real table so the header doesn't jump when data lands. */
.upg__pick[b-pwwlr31ma1] {
    width: 2.25rem;
    text-align: center;
}

/* A customer name and a "checked 8 minutes ago" both read as one thing and both
   wrap into two lines at this table's width, which makes the rows uneven for no
   gain. */
.upg-customer[b-pwwlr31ma1],
.upg-checked[b-pwwlr31ma1] {
    white-space: nowrap;
}

.upg-check[b-pwwlr31ma1] {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--text-sm);
    color: var(--ink-2);
    white-space: nowrap;
}

/* The selection count and the two actions, directly above the table they act
   on - close enough that "12 selected" and the button are read together. */
.upg-bar[b-pwwlr31ma1] {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    flex-wrap: wrap;
    margin: var(--space-3) 0 var(--space-2);
}

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

.upg-bar__acts[b-pwwlr31ma1] {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin-left: auto;
    flex-wrap: wrap;
}

/* 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);
}

.upg-notice--busy[b-pwwlr31ma1] {
    justify-content: flex-start;
}

.upg-notice--busy .btn[b-pwwlr31ma1] {
    margin-left: auto;
}

/* A short line under a value: the ignores-window marker, and each row's live
   result while a run is going through. */
.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 .upg__pick[b-pwwlr31ma1] {
    color: var(--ink-4);
}

/* Production, emphasised but not alarmed - matching the project page's
   treatment of the same pill. */
.upg-prod[b-pwwlr31ma1] {
    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-pwwlr31ma1] {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

.upg-preview li[b-pwwlr31ma1] {
    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-pwwlr31ma1] { border-bottom: none; }

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

/* The zone note, said once above the table rather than stamped on every value. */
.upg-tz[b-pwwlr31ma1] {
    margin: 0 0 var(--space-2);
    font-size: var(--text-xs);
    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);
}

/* Separates the two acting buttons from the harmless refresh beside them, so
   "Start the update now" doesn't sit in an undifferentiated row of three. */
.upg-bar__sep[b-pwwlr31ma1] {
    width: 1px;
    align-self: stretch;
    margin: 0 var(--space-1);
    background: var(--border);
}

/* 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 skipped group's heading inside a confirm dialog. */
.upg-preview__head[b-pwwlr31ma1] {
    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-pwwlr31ma1] {
    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. */
.upg-preview__who .status-pill[b-pwwlr31ma1] {
    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-pwwlr31ma1] {
    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-pwwlr31ma1] {
    max-height: 12rem;
    overflow-y: auto;
}

/* The next-update cell also carries a row's live result, which is a sentence
   rather than a value. Without a floor it wraps to five words a line and the
   link beside it squeezes the text further. */
.upg-next[b-pwwlr31ma1] {
    min-width: 17rem;
}

/* 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: booking an update for an agreed slot, and the per-row history. */

/* 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-pwwlr31ma1] {
    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-pwwlr31ma1] {
    padding: 0 var(--space-1);
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--ink-2);
}

.upg-when__opt[b-pwwlr31ma1] {
    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-pwwlr31ma1] {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex-wrap: wrap;
    margin-top: var(--space-2);
}

/* Whose evening this is. Beside the picker rather than under it, because the
   time and the zone are one fact and reading them apart is how a customer gets
   updated at the wrong hour. */
.upg-when__zone[b-pwwlr31ma1] {
    font-size: var(--text-sm);
    color: var(--ink-2);
}

/* The per-row Activity toggle. Quiet: it is a way in, not an action. On its own
   line under the type pill, so a Production row and a Sandbox row line up
   instead of the button landing wherever the pill's width leaves room. */
.upg-activity-btn[b-pwwlr31ma1] {
    display: flex;
    width: fit-content;
    margin-top: var(--space-1);
}

/* 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. */
.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;
}

/* 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-pwwlr31ma1] {
    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-pwwlr31ma1] {
    color: var(--warning-text);
}

/* The environment cell carries more than a name: the type, a booking with its
   time, zone and owner, and the way into the history. Without a floor the
   booking wrapped to four lines and the column read as a paragraph; much above
   this and the eight columns stop fitting the page, which costs the Refresh
   button and the data-age column their place on screen. */
.upg-env[b-pwwlr31ma1] {
    min-width: 12.5rem;
}

/* 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;
}

/* Eight columns is a lot for one table, and the headings here are longer than
   most of the values under them ("Latest Microsoft allows" over a date). Letting
   the headings wrap keeps the table narrower than the words in it. */
.data-table th[b-pwwlr31ma1] {
    white-space: normal;
}

/* The page's container clips what overflows it rather than scrolling (#574),
   so the fleet table - eight 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;
}
/* /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/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);
}
/* /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);
}

.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/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;
}
/* /Components/Shared/ImportProgressBanner.razor.rz.scp.css */
/* Layout only. The frame, tint and icon slot are .alert .alert--info; the bar
   is .progress, which this component is the reason exists (#586). What is left
   is that .alert is a flex row (icon | text) and this banner has no icon, so
   the body has to claim the full width itself. */

.oe-import-progress:not([hidden])[b-ew5ie458hk] { display: flex; }

.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/PipelineEditorDialog.razor.rz.scp.css */
/*
    Scoped chrome for the pipeline editor.

    PR 15d took the extension picker off its own list (.nb-list / .nb-row /
    .nb-foot / .nb-linkbtn) and onto the design system's .sub-rows + .check +
    .sub-rows__foot. What is left here is the two things that are about this
    dialog rather than about a form: the discovery footer, and the count.
*/

/* The picker is a checkbox list inside a dialog, so it has to be the thing that
   scrolls - the dialog itself must not grow past the viewport on a project with
   thirty extensions. */
.pe-picker[b-jc6zcttoq7] { max-height: 340px; overflow-y: auto; }
.pe-picker__count[b-jc6zcttoq7] { 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-jc6zcttoq7] { cursor: pointer; }

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

/* Why the primary action is disabled - shown only when it is user-correctable. */
.pe-hint[b-jc6zcttoq7] { margin: var(--space-2) 0 0; }
/* /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/ReleaseBuildDialog.razor.rz.scp.css */
/*
    Scoped chrome for the release 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/SiteBanner.razor.rz.scp.css */
/* Frame, tint and icon slot are .alert .alert--warn from components.css; this
   only turns it into a full-width strip above the shell — square corners, no
   side border, and never squeezed by the flex column it sits in. */
.site-banner[b-hg52ehnwk6] {
    flex: none;
    border-width: 0 0 1px 0;
    border-radius: 0;
    align-items: center;
    padding: var(--space-2) var(--space-5);
}
/* /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);
    }
}
