h1:focus {
    outline: none;
}

.valid.modified:not([type=checkbox]) {
    outline: 1px solid #26b050;
}

.invalid {
    outline: 1px solid #e50000;
}

.validation-message {
    color: #e50000;
}

/* Ricerca opportunità's Servizi tree (MudMenu + MudExpansionPanels): wide enough that the longer
   service/category names and their checkboxes aren't clipped — global, not component-scoped CSS,
   since the popup is portal-rendered outside OpportunityFinder's own DOM subtree (same reason
   .blurred-text above lives here instead of in a .razor.css file). MudMenu's popover otherwise caps
   width to its default max-width regardless of the content div's own inline width. */
/* Ricerca opportunità's Fulcro/Servizi trees nest a second MudExpansionPanels level (one category's
   own Clienti/Non clienti sub-selection) inside each group's ChildContent — indented so the extra
   depth reads clearly against the group-level panel it sits inside. */
.pt-subcode-panels {
    margin-left: 16px;
}

.pt-service-tree-popover {
    min-width: 500px !important;
    max-width: 90vw !important;
}

/* DualRangeSlider.razor — two native range inputs sharing one visual track. Each input's own native
   track is hidden (transparent) so only the drawn .pt-range-slider-track/-range show, and
   pointer-events are disabled on the input itself except on its own thumb — otherwise the topmost
   input's full-width invisible track would swallow every click, making the one underneath
   undraggable anywhere except where its thumb happens to already be. */
.pt-range-slider {
    position: relative;
    height: 24px;
    width: 100%;
}

.pt-range-slider-track,
.pt-range-slider-range {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    height: 4px;
    border-radius: 2px;
}

.pt-range-slider-track {
    left: 0;
    right: 0;
    background: var(--mud-palette-lines-default, #e0e0e0);
}

.pt-range-slider-range {
    background: var(--mud-palette-primary, #594ae2);
}

.pt-range-slider-input {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 24px;
    margin: 0;
    background: transparent;
    pointer-events: none;
    -webkit-appearance: none;
    appearance: none;
}

.pt-range-slider-input::-webkit-slider-runnable-track {
    background: transparent;
}

.pt-range-slider-input::-moz-range-track {
    background: transparent;
}

.pt-range-slider-input::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    pointer-events: auto;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: var(--mud-palette-primary, #594ae2);
    border: 2px solid var(--mud-palette-white, #fff);
    box-shadow: 0 1px 3px rgba(0, 0, 0, .4);
    cursor: pointer;
}

.pt-range-slider-input::-moz-range-thumb {
    pointer-events: auto;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: var(--mud-palette-primary, #594ae2);
    border: 2px solid var(--mud-palette-white, #fff);
    box-shadow: 0 1px 3px rgba(0, 0, 0, .4);
    cursor: pointer;
}

/* On top so a thumb sitting exactly on the max input is always the one grabbed first — the common
   case of narrowing a range from its upper end. */
.pt-range-slider-input-max {
    z-index: 2;
}

.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."
    }

.darker-border-checkbox.form-check-input {
    border-color: #929292;
}

.form-floating > .form-control-plaintext::placeholder, .form-floating > .form-control::placeholder {
    color: var(--bs-secondary-color);
    text-align: end;
}

.form-floating > .form-control-plaintext:focus::placeholder, .form-floating > .form-control:focus::placeholder {
    text-align: start;
}

/* Prominent, sticky header for every data table (used together with FixedHeader+Height on
   MudTable, which scrolls the rows in their own container instead of the whole page).
   !important needed to beat MudBlazor's own .mud-table-cell rules on the same th elements. */
.pt-table thead.mud-table-head th.mud-table-cell {
    background-color: var(--mud-palette-background-gray) !important;
    color: var(--mud-palette-text-primary) !important;
    font-weight: 700 !important;
    font-size: 0.8rem !important;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    border-bottom: 2px solid var(--mud-palette-primary) !important;
}

/* Lets a page's main list table grow to fill the remaining space down to the bottom of the
   viewport, so the gap below it matches the pa-4 gap on the sides instead of a fixed vh guess.
   Requires a bounded-height flex chain from .mud-layout down to the page container (below). */
html, body {
    height: 100%;
    margin: 0;
}

.mud-layout {
    height: 100vh;
    overflow: hidden;
}

.pt-fill-main {
    height: 100vh;
    box-sizing: border-box;
    overflow: hidden;
}

.pt-fill-container {
    height: 100%;
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    /* auto, not hidden: pages whose content doesn't opt into flex-grow-1 (Home, Mappa, etc.) must
       still be able to scroll if their content is taller than the viewport, exactly as before this
       change — only a page with a flex-grow-1 table fills the box exactly and needs no scrollbar here. */
    overflow-y: auto;
    overflow-x: hidden;
}

.pt-table.flex-grow-1 {
    min-height: 0;
}

/* Matrice opportunità's MudSimpleTable: sticky header row (position/attributi + opportunity-type
   buttons) while its rows scroll internally. MudSimpleTable has no FixedHeader option like MudTable,
   so this is plain CSS "position: sticky" — global (not scoped to the page's own .razor.css) because
   these divs are rendered by MudSimpleTable's own template, not directly by the page, so Blazor's
   per-component CSS scope attribute never lands on them (same reasoning as .pt-table above, which is
   global for the same reason).

   MudSimpleTable already wraps its <table> in an inner "mud-table-container" div that ships with
   overflow-x:auto (and therefore, per the CSS overflow spec, an implicit overflow-y:auto too) — that
   inner div, not the outer one this Class parameter lands on, ends up being the actual nearest
   scrolling ancestor for sticky's purposes. Fighting that by adding another overflow on the OUTER div
   just creates a second, useless scroll context: the outer div would scroll, but sticky binds to the
   inner one, which never internally scrolls (it's always exactly as tall as its content), so the
   header never visually moves. Instead this makes the EXISTING inner container the one true bounded,
   scrolling box (flex-grow to fill .pt-fill-container's remaining height) — working with MudBlazor's
   default structure instead of layering another one on top of it. */
.pt-matrix-table {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
}

.pt-matrix-table .mud-table-container {
    flex: 1 1 auto;
    min-height: 0;
    overflow-x: auto;
    overflow-y: auto;
}

/* MudSimpleTable's <table> uses border-collapse:collapse by default, which silently breaks
   position:sticky on <th> in Chromium (a well-known engine limitation, not a MudBlazor bug) — cells
   in a collapsed-border table don't paint independently of the table's own layout, so a "stuck" th
   never repaints in its new position. border-collapse:separate (with border-spacing:0 to avoid
   introducing visible gaps) restores normal per-cell painting and makes sticky work again. */
.pt-matrix-table table {
    border-collapse: separate;
    border-spacing: 0;
}

.pt-matrix-table thead th {
    position: sticky;
    top: 0;
    z-index: 1;
    background-color: var(--mud-palette-background-gray);
    color: var(--mud-palette-text-primary);
    font-weight: 700;
    border-bottom: 2px solid var(--mud-palette-primary);
}

/* The weight/override/edit-button trio inside each editable matrix cell used to be a plain
   inline-flex row, which content-hugs each child's own width — since a 1-digit weight and a 2-digit
   weight (or a missing override) take up different widths, the Tune edit button ended up at a
   different horizontal offset from row to row. A fixed 3-column grid instead reserves the same width
   for the primary weight, the grayed-out base weight, and the edit button on every row, regardless of
   which of those three are actually populated in a given cell, so all three line up vertically down
   the whole column. */
.pt-weight-cell {
    display: grid;
    grid-template-columns: 2.5em 2.5em 2.5em;
    align-items: center;
    column-gap: 4px;
}

/* Demo-account preview limit: content past the 3rd row/item in a results table or list popup is
   shown but unreadable, rather than removed outright, so a Demo user can see there's more data
   without seeing the data itself. Global (not scoped to any one .razor.css) because it's shared by
   OpportunityFinder.razor's results table and ServicePointsDialog's popup list — a
   component-scoped class only matches elements written directly in that one component's own markup. */
.blurred-text {
    filter: blur(4px);
    user-select: none;
    color: var(--mud-palette-text-disabled);
}