html, body {
    font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
}

.content {
    padding-top: 1.1rem;
}

h1:focus {
    outline: none;
}

.valid.modified:not([type=checkbox]) {
    outline: 1px solid var(--bs-form-valid-border-color);
}

.invalid {
    outline: 1px solid var(--bs-form-invalid-border-color);
}

.validation-message {
    color: var(--bs-form-invalid-color);
}

.blazor-error-boundary {
    background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, var(--m3-danger);
    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: var(--bs-border-color);
}

/* Lot 030 (30.6): removed a scaffolded-template override that set the placeholder's color to
   var(--bs-secondary-color) (visible) instead of Bootstrap's own default transparent -- harmless
   for Login/Register, whose placeholder text ("username"/"password") only differed from its label
   ("Username"/"Password") by casing, so the visible duplicate was subtle enough nobody noticed.
   Every *Placeholder resx key added since (Export Lot J, Import this lot) intentionally holds the
   *same* text as its *Label counterpart (see e.g. ImportProfileEditor_ColonneNameLabel/Placeholder)
   -- with the placeholder made visible, an empty field rendered the label and the placeholder on
   top of each other showing the same string twice, which is exactly the "label overlapping the
   text" bug reported on /export-profiles' "Nom de la colonne" field. Bootstrap's own default
   (transparent placeholder, label is the only visible text at rest) is what every field in this
   project actually wants, so the override is removed rather than patched per-field. */

/* Block-field name/range rows: shared between the read-only sheet-rule summary
   (ImportProfileEditor.razor) and the editable sheet-rule form (SheetRuleForm.razor) so both
   render identically -- kept global rather than duplicated in two scoped .razor.css files. */
.block-field-list {
    list-style: none;
    padding-left: 0;
    margin-bottom: 1rem;
}

.block-field-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    padding: 0.5rem 0;
    border-bottom: 1px solid var(--bs-border-color);
}

.block-field-item-editing {
    padding: 0.5rem 0;
    border-bottom: 1px solid var(--bs-border-color);
}

.block-field-info {
    display: flex;
    flex-direction: column;
}

.block-field-name {
    font-weight: 600;
}

.block-field-range {
    font-size: 0.85rem;
}

/* Lot R (densification): compact multi-column layout for a field/column list once it's inside a
   read-only .sheet-rule-card summary -- kept as a distinct class from .block-field-list itself so
   the always-editable add/edit forms (SheetRuleForm/SheetGenerationRuleForm/BlockFieldForm/...)
   keep their existing one-per-row layout unchanged. */
.block-field-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: 0.25rem 1.5rem;
}

.block-field-grid > .block-field-item {
    border-bottom: none;
}

.block-field-actions {
    display: flex;
    gap: 0.25rem;
    flex-shrink: 0;
}

.block-field-icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    padding: 0;
}

/* Convention: docs/convention-ui-blazor-alignement-boutons.md -- every action-button row
   (create/modify/delete/save/cancel) is right-aligned within its enclosing container. Used across
   ImportProfileEditor.razor and SheetRuleForm.razor; not scoped to a single component's .razor.css
   for the same reason as the block-field-* rules above. */
.right-aligned-actions {
    display: flex;
    justify-content: flex-end;
    gap: 0.5rem;
}

/* Per-sheet-rule card (read-only summary, ImportProfileEditor.razor/ExportProfileEditor.razor):
   each rule gets a visually distinct bordered card. */
.sheet-rule-list {
    list-style: none;
    padding-left: 0;
    margin-bottom: 1rem;
}

/* Lot R (densification): responsive grid of cards -- as many columns as fit at >=480px each,
   rather than one full-width card per row, so more of a 6-sheet profile is visible without
   scrolling on a wide screen. Kept as a class distinct from .sheet-rule-list (list-reset/spacing)
   so a dedicated selector exists for tests to assert against, per the ticket's own requirement. */
.sheet-rule-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(480px, 1fr));
    gap: 1.5rem;
}

/* Y4 (Lot Y): minmax(480px, ...)'s 480px floor is wider than any mobile viewport -- CSS Grid never
   shrinks a track below its minmax minimum, so on mobile the grid itself (and everything after it in
   the page) was forced wider than the viewport, producing page-wide horizontal scroll and the
   client-reported left/right text truncation in ExportProfileEditor.razor's edit route. Below the
   same 768px breakpoint already used elsewhere (V2/w-md-auto), collapse to a single natural-width
   column instead. */
@media (max-width: 767.98px) {
    .sheet-rule-grid {
        grid-template-columns: 1fr;
    }
}

.sheet-rule-card {
    display: flex;
    flex-direction: column;
    border: 1px solid var(--bs-border-color);
    border-radius: 0.5rem;
    padding: 1rem 1.25rem;
}

/* Pin the Modify/Delete (and delete-confirm) action row to the bottom-right of the card
   regardless of how much content the card holds above it, so buttons line up across cards of
   different heights within the same .sheet-rule-grid row. Scoped to a direct child of the card
   (not every .right-aligned-actions, e.g. the page-level save-profile-button) since only this
   usage lives inside a variable-height flex column. */
.sheet-rule-card > .right-aligned-actions {
    margin-top: auto;
    padding-top: 0.75rem;
}

.sheet-rule-editing-item {
    padding: 1rem 0;
    /* An open edit form is wide (multiple input rows) -- let it span every grid column rather
       than being squeezed into a single ~480px cell. */
    grid-column: 1 / -1;
}

.sheet-rule-card-header {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 0.5rem 0.75rem;
    margin-bottom: 0.75rem;
}

.sheet-rule-card-title {
    margin: 0;
}

.sheet-rule-card-meta {
    font-size: 0.85rem;
}

/* Lot R (densification, R3): unbounded-size sub-lists inside a .sheet-rule-card (import's
   UnconditionalColonneNames/ConditionalPointRule; export's ColumnDefinition/PointColumnDefinition)
   are collapsed behind a <details>/<summary> disclosure, always closed by default. The full list
   markup itself is only rendered once expanded (a Razor @if on component state, not native
   <details> open/closed CSS) so it is genuinely absent from the DOM while collapsed, not just
   visually hidden -- see ImportProfileEditor.razor/ExportProfileEditor.razor's ToggleSheetRuleDetails. */
.sheet-rule-sublist-details {
    margin-top: 0.75rem;
}

.sheet-rule-sublist-details > summary {
    cursor: pointer;
    /* Lot 059 (59.5): was the app's link-color token, the same red used for alerts/the CTA,
       making a purely-informational disclosure read as an error. Neutral secondary-color token
       instead -- the disclosure affordance is carried by the cursor/underline, not by color. */
    color: var(--bs-secondary-color);
    font-size: 0.9rem;
    list-style: none;
}

.sheet-rule-sublist-details > summary::-webkit-details-marker {
    display: none;
}

/* Lot 053 (53.1): caps the 4 profile-editor routes (import/export new+edit) at 1140px on wide
   screens -- no Bootstrap .container-* variant fits, since all share the same
   --bs-container-max-widths scale (sm/md/lg/xl/xxl) and only differ in the breakpoint at which
   they start plateauing; .container-lg would render 1320px (xxl) on a >=1400px viewport, not
   1140px. Below 1140px the container-fluid the class is combined with already goes full width, so
   this rule alone changes nothing under that width -- mobile is untouched. Applied to both
   ImportProfileEditor.razor and ExportProfileEditor.razor's root container, which also resolves
   the divergence Lot 42.3 had left (import had no equivalent wrapper before this lot -- now both
   share the exact same root container class list). */
.profile-editor-container {
    max-width: 1140px;
    margin-inline: auto;
    /* Lot 056 (56.6): leaves room at the bottom of the (long) editor so the sticky save bar below
       never overlaps the last real field -- an approximate, generous fixed value (the bar's exact
       rendered height isn't known in pure CSS without extra JS), not a hard cap on anything else. */
    padding-bottom: 5rem;
}

/* Lot 056 (56.6): groups the "unsaved changes" indicator and the final CTA into one bar pinned to
   the bottom of the viewport while scrolling through a long profile-editor route, so saving never
   costs a scroll-to-bottom. Stays *inside* .profile-editor-container (no full-viewport-width bleed
   on wide screens) via its own max-width mirroring the container's -- not by being a child that
   inherits width from a `position: sticky` ancestor, which doesn't constrain a bar's own width on
   its own. `.right-aligned-actions` inside it is unaffected by the `.sheet-rule-card > ...` rule
   above (that selector only ever matches a direct child of a card). No fixed width/min-width, only
   a max-width -- full-bleed on mobile, matching every prior mobile-first rule in this file.
   z-index: Bootstrap's own `.form-floating > label` sets an explicit `z-index: 2` (to sit above
   its own input) -- with no z-index here (auto), a field's label painted after this bar in
   in-flow terms would still win, since an explicit positive z-index always paints above a
   z-index:auto sibling in the same stacking context regardless of DOM order. Most visible on
   mobile, where the bar's full-bleed width puts it directly under a field's label as the page
   scrolls. A z-index comfortably above 2 keeps the bar on top, as intended. */
.profile-editor-save-bar {
    position: sticky;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 10;
    max-width: 1140px;
    margin-inline: auto;
    background-color: var(--bs-body-bg);
    padding-block: 0.75rem;
}

/* V12 (Lot V): Bootstrap ships no responsive width utility (w-100 has no md-scoped counterpart) --
   this is the one custom rule needed to reset ExportProfileTest.razor's primary action button back
   to its natural width from md up, at the same 768px breakpoint V2 already established. */
@media (min-width: 768px) {
    .w-md-auto {
        width: auto !important;
    }

    /* Lot 058 (58.2): makes an add-button sitting beside a field (ImportProfileEditor.razor's
       Tableaux/Applications rows) fill its column's full height -- i.e. the same height as the
       adjacent form-floating field, since the row no longer forces align-items-end (the field
       and button columns stretch to match by Bootstrap's own row default). Scoped to >=768px
       only: below that the row stacks vertically and a 58px-tall button would be disproportionate
       (mobile-first precedent from lots V/030/53.5). No fixed pixel height anywhere -- height
       always follows the field's own, never replicates it by coincidence. */
    .field-inline-action {
        height: 100%;
    }
}