@import '/_content/Microsoft.FluentUI.AspNetCore.Components/css/reboot.css';

::-webkit-scrollbar {
    width: 6px;
    height: 6px;
}

::-webkit-scrollbar-track {
    background: transparent;
}

::-webkit-scrollbar-thumb {
    border-radius: 6px;
    background-color: rgba(128, 128, 128, 0.3);
}

::-webkit-scrollbar-thumb:hover {
    background-color: rgba(128, 128, 128, 0.5);
}

::-webkit-scrollbar-button {
    width: 0;
    height: 0;
    display: none;
}

::-webkit-scrollbar-corner {
    background-color: transparent;
}

* {
    scrollbar-width: thin;
    scrollbar-color: rgba(128, 128, 128, 0.3) transparent;
}

html, body {
    height: 100%;
    margin: 0;
    padding: 0;
}

body {
    --body-font: "Segoe UI Variable", "Segoe UI", -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif;
    font-family: var(--body-font);
    font-size: var(--type-ramp-base-font-size);
    line-height: var(--type-ramp-base-line-height);
}

.main {
    height: calc(100dvh - 86px);
    color: var(--neutral-foreground-rest);
    align-items: stretch !important;
    column-gap: 0 !important;
}

.main-content-stack {
    height: 100%;
}

.body-content {
    padding: 16px
}

/* Side-menu splitter (NodeType shell) — give each pane a definite-height flex
   context so menu and content scroll INDEPENDENTLY instead of the whole page
   overflowing. Mirrors the treatment PortalLayoutBase applies to its outer
   .body-splitter. The splitter fills its parent .layout-area-container (a flex
   column) rather than a viewport-minus-magic-number guess.

   The SETTINGS splitter deliberately does NOT get this treatment (any more):
   settings pages flow at their natural content height and the PAGE scrolls in
   .body-content, like every other page. FluentMultiSplitter's own stylesheet
   pins `.fluent-multi-splitter { height: 100% }`, so the settings skin sets an
   inline `height: auto; flex: 1 0 auto` (SettingsLayoutArea.BuildSettingsPage)
   — grow-to-fill short pages, never shrink-and-clip long ones. */
.shell-splitter {
    flex: 1 1 auto;
    min-height: 0;
}

/* Ultra-wide screens: keep the reader shell (nav rail + content) a comfortably
   sized, centered block instead of letting the content pane stretch edge-to-edge.
   Without a cap, on an ultra-wide monitor the pane is enormous and — offset by the
   300px rail — the page's own max-width text column (max-width: 1200px; margin: 0
   auto) centers WITHIN the pane, so it floats far right of the viewport centre
   beside a large empty gutter. Capping + centering the whole shell keeps rail and
   content balanced. Below the cap this is a no-op (the shell stays full width). */
.shell-splitter {
    width: 100%;
    max-width: 1600px;
    margin-inline: auto;
}

/* NOTE: the pane is a <div class="fluent-multi-splitter-pane"> (a CLASS), not a
   <fluent-multi-splitter-pane> element. The leading dot is mandatory — without it
   these rules match nothing, the pane keeps FluentUI's default
   `display:block; overflow:hidden`, and the content stack below never gets a
   definite height to scroll within (it just clips). */
.shell-splitter .fluent-multi-splitter-pane {
    overflow: hidden;
    display: flex;
    flex-direction: column;
    min-height: 0;
}

/* Settings panes must NOT clip: the settings page flows at content height and
   scrolls in .body-content, so the pane only needs to stop hiding overflow
   (FluentUI's pane default is overflow:hidden). Kept a flex column so the
   > div fill rule below still applies. */
.settings-splitter .fluent-multi-splitter-pane {
    overflow: visible;
    display: flex;
    flex-direction: column;
}

.settings-splitter .fluent-multi-splitter-pane > div,
.shell-splitter .fluent-multi-splitter-pane > div {
    width: 100%;
    /* flex:1 1 auto, NOT height:100% — the pane's height comes from flex stretch,
       which is INDEFINITE for percentage resolution, so a child height:100% collapses
       to auto (content height) and the pane's overflow:hidden clips it = no scroll.
       Filling via flex against the column-flex pane gives a used height the inner
       overflow:auto can scroll within. */
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
}

/* NodeType shell: the pane's child div (the area's actual control — no wrapper
   stack, so tests and embeds see the real control) IS the scroll container.
   Settings keeps its dedicated .settings-content-pane inner scroller instead. */
.shell-splitter .fluent-multi-splitter-pane > div {
    overflow-y: auto;
    overflow-x: hidden;
}

/* Shell menu pane scrolls on its own. This is shell chrome, not a per-caller choice, so it
   belongs in the stylesheet rather than on a control's inline Style. (NavMenuView DOES forward
   inline Style now — see #742 — but a caller-set style would be the wrong place for it.)
   flex:1 1 auto (not height:100%) for the same indefinite-percentage-height reason as the
   content pane. The settings nav menu is NOT listed here: it flows with the page scroll. */
.shell-splitter .navmenu {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overflow-x: hidden;
}

/* Settings menu pane: pinned search box on top, the live-filtered nav menu fills
   and scrolls below it. The pane's > div (this stack) is already a flex column via
   the rule above; pin the search, let the menu area grow. */
.settings-menu-search {
    flex: 0 0 auto;
    margin: 8px 8px 4px 8px;
}

.settings-menu-pane .layout-area {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
}

/* Make the collapse/expand chevrons on the splitter bar an easier click target —
   the FluentUI default is an 8px glyph that is easy to miss. */
.settings-splitter > .fluent-multi-splitter-bar > span[part="collapse"],
.settings-splitter > .fluent-multi-splitter-bar > span[part="expand"],
.shell-splitter > .fluent-multi-splitter-bar > span[part="collapse"],
.shell-splitter > .fluent-multi-splitter-bar > span[part="expand"] {
    font-size: 10px;
    padding: 8px 0;
}

/* No inner scroller and no min-height:0 here — the settings page scrolls as a
   whole in .body-content. flex:1 1 auto only lets a SHORT page's background
   reach the bottom of the pane; a long page sizes the pane (and the page scroll)
   by its content. overflow-x CLIP (not hidden!) keeps wide content (tables/code)
   from widening the whole page: `hidden` would force overflow-y to compute to
   `auto` and quietly reintroduce the inner vertical scroller this fix removed,
   while `clip` contains the axis without creating a scroll container (same
   treatment as mobile .body-content). */
.settings-content-pane {
    flex: 1 1 auto;
    overflow-x: clip;
    padding: 32px 40px 56px;
    background: var(--neutral-layer-1);
}


/* Comfortable, centered reading column — modern settings/admin convention. */
.settings-content-pane > * {
    max-width: 920px;
    margin-inline: auto;
}

/* ── Settings section card (modern business) ─────────────────────────────────
   Replaces inline border/padding on each section (SettingsLayoutArea.BuildSection)
   so the look is consistent and tweakable in one place. */
.settings-section {
    width: 100%;
    background: var(--neutral-layer-2);
    border: 1px solid var(--neutral-stroke-rest);
    border-radius: 12px;
    overflow: hidden;
    margin-bottom: 20px;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04), 0 2px 6px rgba(0, 0, 0, 0.05);
    transition: box-shadow 0.15s ease, border-color 0.15s ease;
}

.settings-section:hover {
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.06), 0 8px 20px rgba(0, 0, 0, 0.07);
    border-color: var(--neutral-stroke-hover);
}

.settings-section-header {
    padding: 13px 20px;
    font-weight: 600;
    font-size: 0.72rem;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: var(--neutral-foreground-hint);
    background: var(--neutral-layer-3);
    border-bottom: 1px solid var(--neutral-stroke-rest);
}

.settings-section-body {
    padding: 20px;
    display: flex;
    flex-direction: column;
    gap: 14px;
}

fluent-toolbar {
    width: 100%;
    padding-bottom: 12px;
    border-bottom: 1px solid #eee;
}

.context-panel {
    padding: 12px;
    height: 100%;
    overflow-y: auto;
}

.dimension-filter {
    /* height: 400px; */
    display: grid !important;
    grid-template-columns: 200px 1fr;
}

    .dimension-filter > :first-child {
        height: 100%;
        overflow-y: auto;
    }

.dimension-values {
    height: 100%;
    overflow-y: auto;
}

    .dimension-values fluent-checkbox {
        white-space: nowrap;
    }

.manage {
    width: 100dvw;
}

footer {
    background: var(--neutral-layer-4);
    color: var(--neutral-foreground-rest);
    align-items: center;
    padding: 10px 10px;
    position: fixed;
    bottom: 0;
    width: 100%;
}

    footer a {
        color: var(--neutral-foreground-rest);
        text-decoration: none;
    }

        footer a:focus {
            outline: 1px dashed;
            outline-offset: 3px;
        }

        footer a:hover {
            text-decoration: underline;
        }

.alert {
    border: 1px dashed var(--accent-fill-rest);
    padding: 5px;
}

#blazor-error-ui {
    background: lightyellow;
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
    display: none;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 1000;
    margin: 20px 0;
}

    #blazor-error-ui .dismiss {
        cursor: pointer;
        position: absolute;
        right: 0.75rem;
        top: 0.5rem;
    }

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

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

.loading-progress {
    position: relative;
    display: block;
    width: 8rem;
    height: 8rem;
    margin: 20vh auto 1rem auto;
}

    .loading-progress circle {
        fill: none;
        stroke: #e0e0e0;
        stroke-width: 0.6rem;
        transform-origin: 50% 50%;
        transform: rotate(-90deg);
    }

        .loading-progress circle:last-child {
            stroke: #1b6ec2;
            stroke-dasharray: calc(3.141 * var(--blazor-load-percentage, 0%) * 0.8), 500%;
            transition: stroke-dasharray 0.05s ease-in-out;
        }

.loading-progress-text {
    position: absolute;
    text-align: center;
    font-weight: bold;
    inset: calc(20vh + 3.25rem) 0 auto 0.2rem;
}

    .loading-progress-text:after {
        content: var(--blazor-load-percentage-text, "Loading");
    }

code {
    color: #c02d76;
}

:root[data-theme='light'] {
    --code-block-border-color: #e1e4e8 !important; /* GitHub light theme border color */
    --code-block-background-color: #f6f8fa !important; /* GitHub light theme background color */
}

:root[data-theme='dark'] {
    --code-block-border-color: #444c56 !important; /* GitHub dark theme border color */
    --code-block-background-color: #2d333b !important; /* GitHub dark theme background color */
}

/* Monaco editor autocomplete widget - ensure it can overflow containers */
.monaco-editor .suggest-widget,
.monaco-editor .monaco-hover,
.monaco-editor .parameter-hints-widget {
    z-index: 10000 !important;
}

/* Monaco FixedOverflowWidgets container - rendered at body level */
.overflowingContentWidgets {
    z-index: 10000 !important;
    position: fixed !important;
}

.overflowingContentWidgets .suggest-widget {
    z-index: 10001 !important;
}

/* ————————————————————————————————————————————————————————————————— toast layer
   The toast container must paint ABOVE the portal's top menu bar.

   Fluent ships `.fluent-toast-provider { position: fixed; top: 24px; right: 24px; z-index: 999 }`,
   while the portal header is `z-index: 1100` (PortalLayoutBase.razor.css, desktop AND mobile) and
   occupies the top ~48px of the viewport. A top-right toast therefore opened INSIDE the header's
   band with a LOWER z-index, and the header painted over it — issue #1883, where the
   download-complete confirmation was hidden behind the menu bar.

   🚨 This is a plain ordering collision in the ROOT stacking context, NOT a trapped-context bug:
   no ancestor of the provider establishes one. `.body-content` is deliberately `position: relative`
   with NO z-index for exactly this reason (see the comment on it in PortalLayoutBase.razor.css,
   left behind by the same bug hitting the chat popups), and `.layout`'s `overflow: hidden` cannot
   clip a `position: fixed` descendant. So a z-index above the header is sufficient and sufficient
   alone — the value is what was missing, not a containing block.

   `!important` because Fluent's own rule is SCOPED — `.fluent-toast-provider[b-wmvy1145n8]`,
   specificity 0-2-0 — so a global class selector (0-1-0) loses to it outright and an
   equal-specificity override would be decided by bundle order. Same reason the Monaco overflow
   widgets above carry it.

   The value joins the established "clears the header" tier already used by the chat widget, the
   /model · /agent pickers and the Monaco popups (10000). PortalOverlayLayeringTest pins the
   RELATIONSHIP (toast > header) rather than the literal number, so re-tiering the header fails
   loudly here instead of silently burying the toast again.

   This lives in the GLOBAL sheet, not in PortalLayoutBase's scoped CSS, so it covers every
   FluentToastProvider the app mounts — the portal layout's, MainView's and AreaPage's — rather
   than only the shell that happened to report the bug. */
.fluent-toast-provider {
    z-index: 10000 !important;
}

/* Title bar text field - borderless inline editor for page titles */
fluent-text-field.title-bar-field::part(root) {
    border: none;
    background: transparent;
    box-shadow: none;
}

fluent-text-field.title-bar-field::part(control) {
    font-size: 1.25rem;
    font-weight: 600;
    padding: 0 4px;
}

/* ————————————————————————————————————————————————————————————————— hero CTA pill
   A bold, solid, caller-coloured button — the look a marketing hero wants, on a real
   ButtonControl that can raise a dialog (an authored <a> cannot).

   🚨 Why a class + ::part and not just an inline style. `fluent-button` paints its visible
   surface on the shadow-DOM `control` part, so `style="background: …"` on the HOST changes
   nothing — the host is a transparent wrapper. Custom properties DO cross the boundary, so the
   caller sets `--cta-*` on the host (via ButtonControl.WithStyle) and this rule forwards them
   onto the part. Same mechanism as .title-bar-field above.

   Every value falls back to the Fluent design token, so `.cta-pill` with no custom properties is
   simply a chunkier accent button — never an unstyled or invisible one. */
fluent-button.cta-pill::part(control) {
    background: var(--cta-bg, var(--accent-fill-rest));
    color: var(--cta-fg, var(--foreground-on-accent-rest));
    border: none;
    border-radius: var(--cta-radius, 8px);
    padding: var(--cta-padding, 12px 22px);
    height: auto;
    font-weight: var(--cta-weight, 700);
    font-size: var(--cta-size, 1rem);
}

/* 🚨 The QUIET pill — every CTA button that is not the row's bold one.

   The rule above falls back to `--accent-fill-rest`, which is right for the ONE accent button and
   wrong for every pill beside it. A cover declares its palette as `heroCta.background`/`.foreground`
   (the accent pair) and MAY declare a secondary pair; when it does not, `CtaPillVars` contributes no
   custom property for the quiet pill — and the quiet pill then fell through to the ACCENT token. So
   the row's deliberately quiet button (Start, once a returning learner's Resume takes the lead —
   Plugins#378) rendered the same solid blue as an accent button, and the hierarchy read backwards
   on every course cover that declares only the primary pair.

   `:not([appearance="accent"])` rather than a list of the quiet appearances: it also covers a
   button that emits no `appearance` attribute at all. The inset shadow is load-bearing — without an
   edge the neutral fill is nearly the page ground, and a quiet button becomes invisible text. */
fluent-button.cta-pill:not([appearance="accent"])::part(control) {
    background: var(--cta-bg, var(--neutral-fill-rest));
    color: var(--cta-fg, var(--neutral-foreground-rest));
    box-shadow: inset 0 0 0 1px var(--neutral-stroke-rest);
}

fluent-button.cta-pill:hover::part(control) {
    filter: brightness(0.94);
}

/* A disabled pill is the PLACEHOLDER state — the row is already laid out and the label arrives
   when the viewer's state resolves. Keep it the same size and shape so nothing shifts; only the
   contrast says "not yet". */
fluent-button.cta-pill[disabled]::part(control) {
    opacity: 0.55;
    cursor: default;
}

/* Sticky action menu button - stays in top right when scrolling */
.sticky-action-menu {
    position: fixed;
    top: 70px;  /* Below the header bar */
    right: 24px;
    z-index: 100;
}

/* Ensure Monaco editor containers allow overflow for autocomplete */
.monaco-editor-container,
.search-container,
.search-box-container,
.search-bar-container,
.links {
    overflow: visible !important;
}

/* Header needs to allow Monaco autocomplete to overflow */
header,
fluent-header,
.header-gutters,
.header-gutters > * {
    overflow: visible !important;
}

/* ── Catalog / search card grid — cards fill their grid cell ──────────────────
   The grid cell, the wrapping <a>/<div>, and the <fluent-card> host are rendered by
   DIFFERENT Blazor components (MeshSearchView → MeshNodeCardView → FluentCard), so a
   component-scoped `.razor.css` rule never reaches the inner hosts — the CSS-isolation
   b-* attribute is not applied across component boundaries (nor to a child-component's
   host element). That is why the earlier `display:block;width:100%` on `.mesh-node-card`
   in MeshNodeCardView.razor.css never landed. These GLOBAL (non-scoped) rules cross every
   boundary, so each card tiles to the FULL cell width instead of shrinking to its content
   (the cause of the gaps + overlapping titles). <fluent-card> defaults to
   display:inline-block (content width) — force block fill; min-width:0 lets long titles
   ellipsize instead of widening the auto-fill track. */
.mesh-search-area-grid > * {
    min-width: 0;
}

.mesh-search-area-grid > * > * {
    /* the card wrapper is a flex item of the grid cell — grow to fill it. Absolutely-
       positioned affordances (drill-down / delete) are NOT flex items, so this never
       stretches them. */
    flex: 1 1 auto;
    min-width: 0;
}

.mesh-search-area-grid .mesh-node-card,
.mesh-search-area-grid .mesh-search-card {
    display: block;
    width: 100%;
    min-width: 0;
    box-sizing: border-box;
    height: 100%;
}

.mesh-search-area-grid .mesh-node-card:hover,
.mesh-search-area-grid .mesh-search-card:hover {
    box-shadow: var(--elevation-shadow-card-active);
}

/* Global SVG icon mask — any element with --icon-url renders the SVG as a mask */
[style*="--icon-url"] {
    -webkit-mask-image: var(--icon-url);
    mask-image: var(--icon-url);
    -webkit-mask-size: contain;
    mask-size: contain;
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    -webkit-mask-position: center;
    mask-position: center;
    -webkit-mask-mode: alpha;
    mask-mode: alpha;
    background-color: currentColor;
}

@media (max-width: 600px) {
    .header-gutters {
        margin: 0.5rem 3rem 0.5rem 1.5rem !important;
    }


    [dir="rtl"] .header-gutters {
        margin: 0.5rem 1.5rem 0.5rem 3rem !important;
    }

    .main {
        flex-direction: column !important;
        row-gap: 0 !important;
        overflow-y: auto;
    }

    #main-menu {
        width: 100% !important;
    }

        #main-menu > div:first-child:is(.expander) {
            display: none;
        }

}

/* ── The render-error placeholder ───────────────────────────────────────────────────────────────
   Shown by every ErrorBoundary that wraps a view, an area or a dialog. It used to be styled inline
   as `color: var(--error, #d13438)` over `rgba(209,52,56,0.08)`, which is a mid-dark red on a
   near-transparent ground: legible on white, and dark-red-on-black in dark mode — exactly when a
   reader most needs to read it, because the message IS the diagnosis.

   Fluent's `--error` is a single value that does not flip with the theme, so the fix is not a
   better token but a theme-aware rule. The foreground lightens in dark mode while the tinted
   background and the border carry the "this is an error" signal in both. */
.meshweaver-render-error {
    padding: 0.75rem;
    border: 1px solid rgba(209, 52, 56, 0.55);
    border-radius: 4px;
    background: rgba(209, 52, 56, 0.08);
    color: #b3261e;
    font-size: 0.875rem;
}

/* The message itself is a stack trace or an import failure — monospace, and allowed to wrap rather
   than pushing the page sideways on a phone. */
.meshweaver-render-error .meshweaver-render-error-detail {
    margin-top: 0.25rem;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}

@media (prefers-color-scheme: dark) {
    .meshweaver-render-error {
        border-color: rgba(255, 138, 128, 0.45);
        background: rgba(209, 52, 56, 0.14);
        color: #ff9a91;
    }
}

/* An explicit theme choice wins over the OS preference, in both directions — the portal stamps the
   root, and a rule that only answers `prefers-color-scheme` is wrong for exactly the readers who
   went and set the toggle. */
:root[data-theme="dark"] .meshweaver-render-error,
body[data-theme="dark"] .meshweaver-render-error,
.dark .meshweaver-render-error {
    border-color: rgba(255, 138, 128, 0.45);
    background: rgba(209, 52, 56, 0.14);
    color: #ff9a91;
}

:root[data-theme="light"] .meshweaver-render-error,
body[data-theme="light"] .meshweaver-render-error {
    border-color: rgba(209, 52, 56, 0.55);
    background: rgba(209, 52, 56, 0.08);
    color: #b3261e;
}
