html, body {
    font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
}

/* Room for the scrollbar on every page, so a page short enough not to scroll does not
   centre 5px to the right of one that does. */
html {
    scrollbar-gutter: stable;
}

a {
    color: var(--portal-color-primary);
}

.content {
    padding-top: 1.1rem;
}

h1:focus {
    outline: none;
}

.valid.modified:not([type=checkbox]) {
    outline: 1px solid #26b050;
}

.invalid {
    outline: 1px solid #e50000;
}

.validation-message {
    color: #e50000;
}

.blazor-error-boundary {
    background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
    padding: 1rem 1rem 1rem 3.7rem;
    color: white;
}

    .blazor-error-boundary::after {
        content: "An error has occurred."
    }


.api-docs-search {
    display: flex;
    gap: 0.5rem;
    align-items: center;
    max-width: 480px;
}

.api-docs-search input[type="search"] {
    flex: 1;
    padding: 0.5rem 0.75rem;
    font-family: var(--portal-font);
    color: var(--portal-color-text);
    background: var(--portal-color-surface);
    border: 1px solid var(--portal-color-border);
    border-radius: var(--portal-radius);
}

/* App-bar docs search. The outlined MudAutocomplete sits on the app bar,
   where MudBlazor's defaults are too faint to read: the placeholder is currentColor at
   .42 opacity and the outline uses --mud-palette-lines-inputs, neither of which is tuned
   for the app-bar surface. Selectors are app-bar-scoped so inputs elsewhere are untouched,
   and carry enough specificity to beat MudBlazor's own ::placeholder rule. */
/* A preferred width that can still shrink. As an inline `min-width: 320px` it could not:
   the box kept its 320px in a phone-width bar and ran off the right edge. The sizing has
   to go on MudAutocomplete's outer wrapper, which is the toolbar's actual flex child —
   the Class parameter lands on an inner element, where min-width:0 does nothing. */
.mud-appbar .mud-toolbar-appbar > .mud-autocomplete {
    flex: 0 1 20rem;
    min-width: 0;
}

.mud-appbar .portal-appbar-search {
    width: 100%;
}

.mud-appbar .portal-appbar-search .mud-input {
    background-color: rgba(255, 255, 255, 0.06);
    border-radius: var(--portal-radius);
}

.mud-appbar .portal-appbar-search .mud-input-root {
    color: var(--mud-palette-appbar-text);
}

.mud-appbar .portal-appbar-search input.mud-input-root::placeholder {
    color: var(--mud-palette-appbar-text);
    opacity: 0.7;
}

.mud-appbar .portal-appbar-search .mud-input-outlined-border {
    border-color: rgba(255, 255, 255, 0.35);
}

.mud-appbar .portal-appbar-search:hover .mud-input-outlined-border {
    border-color: rgba(255, 255, 255, 0.6);
}

.mud-appbar .portal-appbar-search .mud-icon-root {
    color: var(--mud-palette-appbar-text);
}

/* Scalar's floating layer — the client picker, the developer-tools menus, the search
   modal — renders into a .scalar-app container appended to <body> and is positioned by
   floating-ui, which writes `position: absolute` as an inline style. MudBlazor's utility
   CSS happens to declare the same class names as Scalar's Tailwind build, and its
   `.relative { position: relative !important }` outranks that inline declaration (an
   !important rule beats a non-important inline style). The panels therefore stayed in
   normal flow at the end of <body>: they rendered far below the reference instead of
   beside their trigger, and their z-index of 1000 put them behind the drawer (1100).
   Restore the position Scalar asked for, and lift the layer clear of MudBlazor's chrome
   (drawer 1100, app bar 1300).
   Matching is by the inline declaration rather than by position in the tree: some
   layers are direct children of the overlay container and others (the per-operation
   auth popover, which only takes this path in the wide two-column layout) are nested
   deeper, and floating-ui writes the same inline style in every case. Keying on it also
   leaves the many ordinary `.relative` elements inside the reference untouched, and
   preserves whichever strategy floating-ui chose. */
.scalar-app .relative[style*="position: absolute"],
.scalar-app .relative[style*="position:absolute"] {
    position: absolute !important;
    z-index: var(--mud-zindex-dialog, 1400);
}

.scalar-app .relative[style*="position: fixed"],
.scalar-app .relative[style*="position:fixed"] {
    position: fixed !important;
    z-index: var(--mud-zindex-dialog, 1400);
}

/* Scalar lays itself out as if it owned the viewport: it sizes its sidebar as
   `calc(var(--full-height, 100dvh) - var(--refs-header-height))` and sticks it to
   `top: var(--scalar-custom-header-height, 0)`, both defaulting to assuming nothing sits
   above it. Embedded below the portal's app bar that makes the sidebar taller than the
   space it actually has, so its search box scrolls out of view at the top before its
   footer appears at the bottom. --scalar-custom-header-height is the contract Scalar
   offers for exactly this, and it feeds both the height and the sticky offset.

   Only the app bar is subtracted, because only the app bar is fixed. The page furniture
   above the reference (title, version chips, search, provider docs) scrolls away, so it
   must not shrink the sidebar - it just delays when the sidebar becomes sticky. */
#scalar-reference {
    --scalar-custom-header-height: var(--mud-appbar-height, 64px);
}

/* Scalar's two-column layout gives the parameters 3/5 of the width rather than 1/2, and
   pads each section 32px a side rather than 60px: the code sample needs less room than
   the parameters do. Scoped to Scalar's own wide layout: at 900px and under it stacks
   the columns and sets its narrow padding, which stays as is. */
@container narrow-references-container (width > 900px) {
    #scalar-reference .section-container {
        padding-inline: var(--portal-scalar-section-gutter);
    }

    #scalar-reference .section-column:first-of-type {
        flex: 3 1 0;
    }

    #scalar-reference .section-column:nth-of-type(2) {
        flex: 2 1 0;
    }

    /* Operations lay out on a grid of their own rather than in section columns. */
    #scalar-reference .operation-layout {
        grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
    }
}

/* The home page: what Hubix does, the published areas, and what every API has in common. */
.home-hero {
    max-width: var(--portal-prose-width);
    padding: 2.5rem 0 2rem;
}

.home-hero h1 {
    margin: 0 0 1rem;
    color: var(--portal-color-heading);
    font-size: 2.5rem;
    font-weight: 500;
}

.home-lead {
    margin: 0 0 1.75rem;
    max-width: 52rem;
    color: var(--portal-color-body);
    font-size: 1.15rem;
    line-height: 1.6;
}

.home-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
}

.home-action {
    padding: 0.6rem 1.25rem;
    border: 1px solid var(--portal-color-primary);
    border-radius: var(--portal-radius);
    color: var(--portal-color-primary);
    font-weight: 500;
    text-decoration: none;
}

.home-action:hover {
    background: color-mix(in srgb, var(--portal-color-primary) 12%, transparent);
}

.home-action-primary {
    background: var(--portal-color-primary);
    color: var(--mud-palette-background);
}

.home-action-primary:hover {
    background: color-mix(in srgb, var(--portal-color-primary) 85%, white);
}

.home-block {
    padding: 1.5rem 0;
    border-top: 1px solid var(--portal-color-border);
}

.home-block h2 {
    margin: 0 0 1.25rem;
    color: var(--portal-color-heading);
    font-size: 1.4rem;
    font-weight: 500;
}

.home-areas,
.home-conventions {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(20rem, 100%), 1fr));
    gap: 1.25rem 2rem;
    list-style: none;
    margin: 0;
    padding: 0;
}

/* An area's description runs longer than a convention's, so its columns are wider: four across the full shell. */
.home-areas {
    grid-template-columns: repeat(auto-fill, minmax(min(24rem, 100%), 1fr));
}

.home-areas a {
    color: var(--portal-color-primary);
    font-size: 1.1rem;
    font-weight: 500;
    text-decoration: none;
}

.home-areas a:hover {
    text-decoration: underline;
}

.home-areas p,
.home-conventions p {
    margin: 0.3rem 0 0;
    color: var(--portal-color-body);
    font-size: 0.95rem;
    line-height: 1.55;
}

.home-area-count {
    display: inline-block;
    margin-top: 0.35rem;
    color: var(--mud-palette-text-secondary);
    font-size: 0.8rem;
}

.home-conventions a {
    color: var(--portal-color-primary);
}

.home-conventions h3 {
    margin: 0;
    color: var(--portal-color-heading);
    font-size: 1rem;
    font-weight: 600;
}

.home-conventions code {
    padding: 0.1em 0.35em;
    border-radius: 4px;
    background: var(--mud-palette-background-gray);
    font-family: var(--portal-font-code);
    font-size: 0.85em;
}

/* The /apis catalogue: a card per section, as many across as fit. */
.section-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(24rem, 100%), 1fr));
    gap: 1.5rem;
    list-style: none;
    margin: 0;
    padding: 0;
}

.section-card {
    display: flex;
    flex-direction: column;
    padding: 1.25rem 1.5rem;
    background: var(--portal-color-surface);
    border: 1px solid var(--portal-color-border);
    border-radius: var(--portal-radius);
}

.section-card-title {
    margin: 0 0 0.35rem;
    font-size: 1.25rem;
    font-weight: 500;
}

.section-card-title a {
    color: var(--portal-color-heading);
    text-decoration: none;
}

.section-card-title a:hover,
.section-card-api:is(a):hover {
    color: var(--portal-color-primary);
    text-decoration: underline;
}

.section-card-description,
.section-card-empty {
    margin: 0 0 1rem;
    color: var(--mud-palette-text-secondary);
    font-size: 0.9rem;
    line-height: 1.5;
}

.section-card-apis {
    display: flex;
    flex-direction: column;
    gap: 0.9rem;
    list-style: none;
    margin: 0;
    padding: 1rem 0 0;
    border-top: 1px solid var(--portal-color-border);
}

.section-card-api {
    color: var(--portal-color-primary);
    font-size: 1.05rem;
    font-weight: 500;
    text-decoration: none;
}

.section-card-api-description {
    margin: 0.2rem 0 0;
    color: var(--portal-color-body);
    font-size: 0.9rem;
}

.section-card-api-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.25rem 0.75rem;
    margin-top: 0.35rem;
    font-size: 0.85rem;
}

.section-card-api-meta .mud-chip {
    margin: 0;
}

/* Tab strip on the API page. Plain links rather than MudTabs: the page is Static SSR and
   the selected view lives in the URL, so there is no client state for a component to own
   (and it stays shareable and back-button friendly). aria-current marks the active tab for
   assistive tech as well as for the underline. */
.api-view-tabs {
    display: flex;
    gap: 0.25rem;
    margin: 0 0 1.5rem;
    border-bottom: 1px solid var(--portal-color-border);
}

.api-view-tabs a {
    padding: 0.6rem 1rem;
    color: var(--mud-palette-text-secondary);
    text-decoration: none;
    font-size: 0.95rem;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
}

.api-view-tabs a:hover {
    color: var(--portal-color-text);
    background: var(--mud-palette-background-gray);
    border-radius: var(--portal-radius) var(--portal-radius) 0 0;
}

.api-view-tabs a[aria-current="page"] {
    color: var(--portal-color-primary);
    border-bottom-color: var(--portal-color-primary);
}

/* Page titles outside Markdown — the API name, the catalog headings, the home page —
   render through MudBlazor's typography, which uses one text colour for everything. They
   join the same ramp as the docs (tokens.css) so a heading is a heading wherever it is. */
.mud-typography-h3,
.mud-typography-h4,
.mud-typography-h5,
.mud-typography-h6 {
    color: var(--portal-color-heading);
}

/* The centred page shell. Applied to the page body and, below, to the app bar's own
   toolbar — the bar itself still spans the window so its background reaches the edges,
   but what sits in it lines up with the content underneath. Both use the same gutter, or
   the wordmark and the page would start at different x. */
.portal-container {
    max-width: var(--portal-content-width);
    margin-inline: auto;
    /* Its own padding rather than MudBlazor's pa-6, whose `!important` would win against
       the padding-inline this rule needs. Border-box, so the gutter is inside the max. */
    padding: var(--portal-content-gutter);
}

.mud-appbar .mud-toolbar-appbar {
    max-width: var(--portal-content-width);
    margin-inline: auto;
    width: 100%;
    /* Overrides .mud-toolbar-gutters, whose 16px would leave the bar 8px out of step. */
    padding-inline: var(--portal-content-gutter);
}

/* Site sections in the app bar. Plain links: nothing here needs a render mode, so the
   chrome stays free for every Static SSR page. */
.portal-wordmark {
    color: var(--mud-palette-appbar-text);
    text-decoration: none;
    font-size: 1.25rem;
    font-weight: 500;
    margin-right: 2rem;
    white-space: nowrap;
    display: inline-flex;
    align-items: center;
    gap: 0.6rem;
}

.portal-sections {
    display: flex;
    gap: 0.5rem;
}

.portal-sections a {
    padding: 0.4rem 0.75rem;
    color: var(--mud-palette-appbar-text);
    text-decoration: none;
    font-size: 0.95rem;
    border-radius: var(--portal-radius);
    opacity: 0.75;
}

.portal-sections a:hover {
    background: rgba(255, 255, 255, 0.08);
    opacity: 1;
}

/* The current section reads as selected on its own, without a underline competing with
   the API page's view tabs directly below it. */
.portal-sections a[aria-current="page"] {
    background: rgba(255, 255, 255, 0.1);
    opacity: 1;
    font-weight: 500;
}

/* One of the two section lists is always display:none — which is also what keeps the
   duplicate out of the accessibility tree. */
.portal-sections-compact {
    display: none;
}

.portal-sections-compact > summary {
    list-style: none;
    cursor: pointer;
    padding: 0.25rem 0.5rem;
    color: var(--mud-palette-appbar-text);
}

.portal-sections-compact > summary::-webkit-details-marker {
    display: none;
}

.portal-sections-compact[open] > nav {
    /* Out of the bar's flex row and into a panel below it: inside the row it would
       stretch the app bar's height instead of overlaying the page. Offset from the bar
       itself (which is position:fixed, so it is the containing block) rather than from
       --mud-appbar-height: MudBlazor shrinks the bar to 56px on xs while that variable
       stays 64px, which left the panel floating 8px clear of it. */
    position: absolute;
    top: 100%;
    left: 0;
    display: flex;
    flex-direction: column;
    min-width: 12rem;
    padding: 0.5rem;
    background: var(--mud-palette-appbar-background);
    border-bottom: 1px solid var(--portal-color-border);
    z-index: var(--mud-zindex-appbar, 1300);
}

.portal-sections-compact[open] > nav a {
    padding: 0.6rem 0.75rem;
    color: var(--mud-palette-appbar-text);
    text-decoration: none;
}

@media (max-width: 599.98px) {
    /* The search box needs the room a phone-width bar has left over. */
    .portal-sections {
        display: none;
    }

    .portal-sections-compact {
        display: block;
    }

    .portal-wordmark {
        margin-right: 0.5rem;
        font-size: 1.1rem;
    }
}

/* Shared by both docs trees: the central tree on /docs and the per-API document picker.
   A fixed-width rail rather than a grid column — as a percentage of the content width it
   grew with the window, so short titles like "Overview" sat in a 300px block. min-width:0
   on the content side keeps wide code fences and tables from stretching the flex item
   past the container. */
.docs-layout {
    display: flex;
    align-items: flex-start;
    gap: 2.5rem;
    margin-bottom: 1.5rem;
}

.docs-rail {
    flex: 0 0 12rem;
    display: flex;
    flex-direction: column;
    /* Clears the fixed app bar, so the picker stays reachable inside a long document. */
    position: sticky;
    top: calc(var(--mud-appbar-height, 64px) + 1.5rem);
    max-height: calc(100vh - var(--mud-appbar-height, 64px) - 3rem);
    overflow-y: auto;
}

/* No background of its own: a filled panel here read as a stray card on the page. The
   rule is a hairline the current item colours in. */
.docs-rail a {
    padding: 0.3rem 0 0.3rem 0.75rem;
    color: var(--mud-palette-text-secondary);
    text-decoration: none;
    font-size: 0.9rem;
    line-height: 1.45;
    border-left: 2px solid var(--portal-color-border);
}

.docs-rail a:hover {
    color: var(--portal-color-text);
    border-left-color: var(--mud-palette-text-secondary);
}

.docs-rail a[aria-current="page"] {
    color: var(--portal-color-primary);
    border-left-color: var(--portal-color-primary);
}

/* A folder in the central tree is a heading, not a destination. It carries no
   hairline of its own — the children's rule reads as the group's spine. */
.docs-rail-group {
    display: flex;
    flex-direction: column;
    margin-top: 0.75rem;
}

.docs-rail-group-title {
    padding: 0 0 0.25rem 0.75rem;
    color: var(--mud-palette-text-secondary);
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

/* A section doc's versions, latest first, as chips; Compare sits with them, dashed as the one that is no version. */
.doc-versions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 1rem;
}

.doc-versions a {
    padding: 0.15rem 0.75rem;
    border: 1px solid var(--portal-color-border);
    border-radius: 999px;
    color: var(--mud-palette-text-secondary);
    font-size: 0.85rem;
    text-decoration: none;
}

.doc-versions a[aria-current="page"] {
    color: var(--portal-color-primary);
    border-color: var(--portal-color-primary);
}

.doc-versions a.doc-compare-link {
    border-style: dashed;
}

.doc-compare {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 1rem;
    margin-bottom: 1rem;
}

/* An API in a section's tree: its name is a link to it, and its entries sit one step in. */
.docs-rail-group > a.docs-rail-api {
    color: var(--portal-color-heading);
    font-weight: 600;
}

.docs-rail-group > a:not(.docs-rail-api) {
    padding-left: 1.5rem;
}

.docs-body {
    flex: 1 1 auto;
    min-width: 0;
}

/* The open doc's "On this page" column, right after the doc rather than at the shell's
   edge, so a wide window leaves its spare room at the far right, not between the two.
   Drawn on the same hairline as the rail. */
.doc-with-outline {
    display: flex;
    align-items: flex-start;
    gap: 2.5rem;
}

.doc-with-outline > .markdown-body {
    flex: 1 1 auto;
    min-width: 0;
}

.doc-outline {
    flex: 0 0 14rem;
    display: flex;
    flex-direction: column;
    position: sticky;
    top: calc(var(--mud-appbar-height, 64px) + 1.5rem);
    max-height: calc(100vh - var(--mud-appbar-height, 64px) - 3rem);
    overflow-y: auto;
}

.doc-outline-title {
    padding: 0 0 0.5rem 0.75rem;
    color: var(--mud-palette-text-secondary);
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

.doc-outline-list {
    display: flex;
    flex-direction: column;
    list-style: none;
    margin: 0;
    padding: 0;
}

.doc-outline-list li {
    display: flex;
    flex-direction: column;
}

.doc-outline a {
    padding: 0.3rem 0 0.3rem 0.75rem;
    color: var(--mud-palette-text-secondary);
    text-decoration: none;
    font-size: 0.85rem;
    line-height: 1.45;
    border-left: 2px solid var(--portal-color-border);
}

.doc-outline-list .doc-outline-list a {
    padding-left: 1.5rem;
}

.doc-outline a:hover {
    color: var(--portal-color-text);
    border-left-color: var(--mud-palette-text-secondary);
}

.doc-outline a[aria-current="location"] {
    color: var(--portal-color-primary);
    border-left-color: var(--portal-color-primary);
}

/* portal-outline.js: subsections show only under the section being read. */
.doc-outline-list[data-tracking] .doc-outline-list {
    display: none;
}

.doc-outline-list[data-tracking] > li.is-open > .doc-outline-list {
    display: flex;
}

/* MudBlazor's lg breakpoint: below it a third column would squeeze the prose under its
   reading width, so the outline moves above the doc and stops being sticky. */
@media (max-width: 1279.98px) {
    .doc-with-outline {
        flex-direction: column;
        align-items: stretch;
        gap: 1.5rem;
    }

    .doc-outline {
        order: -1;
        position: static;
        flex-basis: auto;
        max-height: none;
    }
}

/* MudBlazor's md breakpoint: below it the rail becomes a plain list above the document,
   and stops being sticky — pinning it would eat most of a phone screen. */
@media (max-width: 959.98px) {
    .docs-layout {
        flex-direction: column;
        gap: 1.5rem;
        /* Stacked, the cross axis is the width: flex-start would size the document to its
           max-content (its widest table) and overflow the page sideways. */
        align-items: stretch;
    }

    .docs-rail {
        position: static;
        flex-basis: auto;
        max-height: none;
    }
}

/* Version diff (docs/reference/devportal.md#grading). The grade accent is the only colour carrying meaning, and it is
   always paired with the group's own label, so colour is never the sole channel. Constrained
   to the prose width for the same reason the docs are: a list of one-line changes running the
   full width of a large display is hard to scan back to the left edge. */
.version-diff {
    max-width: var(--portal-prose-width);
}

.version-diff h2 {
    margin: 2rem 0 1rem;
}

.version-diff h2:first-of-type {
    margin-top: 1rem;
}

.diff-advisory {
    color: var(--portal-color-muted);
    margin: 0 0 0.5rem;
}

.diff-group {
    border-left: 3px solid var(--diff-accent, var(--portal-color-muted));
    padding: 0.5rem 0 0.5rem 1rem;
    margin-bottom: 0.75rem;
    background: color-mix(in srgb, var(--diff-accent, transparent) 5%, transparent);
}

.diff-group[data-grade="breaking"] { --diff-accent: var(--mud-palette-error); }
.diff-group[data-grade="attention"] { --diff-accent: var(--mud-palette-warning); }
.diff-group[data-grade="additive"] { --diff-accent: var(--mud-palette-success); }
.diff-group[data-grade="cosmetic"] { --diff-accent: var(--portal-color-muted); }

.diff-group > summary {
    cursor: pointer;
    display: flex;
    align-items: baseline;
    gap: 0.5rem;
    flex-wrap: wrap;
}

.diff-group-label {
    color: var(--portal-color-heading);
    font-weight: 600;
}

.diff-count {
    background: var(--diff-accent, var(--portal-color-muted));
    color: var(--mud-palette-background);
    border-radius: 999px;
    padding: 0 0.5rem;
    font-size: 0.8rem;
    font-weight: 600;
}

.diff-group ul,
.diff-docs {
    list-style: none;
    padding: 0.75rem 0 0;
    margin: 0;
}

.diff-group li {
    margin-bottom: 0.4rem;
    color: var(--portal-color-body);
}

.diff-docs > li {
    border-top: 1px solid var(--portal-color-border);
    padding: 0.75rem 0;
}

.diff-doc-head {
    display: flex;
    align-items: baseline;
    gap: 0.5rem;
    flex-wrap: wrap;
    color: var(--portal-color-heading);
}

.diff-detail {
    color: var(--portal-color-muted);
    font-size: 0.9em;
}

/* A block, so a note or a deprecation message sits under the change rather than trailing off
   the end of a long line. */
.diff-group li > .diff-detail,
.diff-docs > li > .diff-detail {
    display: block;
    margin-top: 0.15rem;
}

.diff-doc-kind {
    border: 1px solid var(--portal-color-border);
    border-radius: var(--portal-radius);
    color: var(--portal-color-muted);
    font-size: 0.75rem;
    letter-spacing: 0.04em;
    padding: 0.1rem 0.4rem;
    text-transform: uppercase;
    white-space: nowrap;
}

.diff-docs > li[data-kind="added"] .diff-doc-kind { color: var(--mud-palette-success); }
.diff-docs > li[data-kind="removed"] .diff-doc-kind { color: var(--mud-palette-error); }
.diff-docs > li[data-kind="changed"] .diff-doc-kind { color: var(--mud-palette-warning); }
.diff-docs > li[data-kind="unavailable"] .diff-doc-kind { color: var(--mud-palette-error); }

.diff-prose > summary {
    color: var(--portal-color-primary);
    cursor: pointer;
    font-size: 0.9rem;
    margin-top: 0.5rem;
}

.diff-prose > .markdown-body {
    border-left: 2px solid var(--portal-color-border);
    margin-top: 0.75rem;
    padding-left: 1rem;
}
