h1:focus {
    outline: none;
}

.content {
    padding-top: 1.1rem;
}

/* WCAG AA fix (QUICK-260722-nr5, color-contrast): the current-page (disabled) breadcrumb item
   rendered as MudBlazor's default disabled neutral (#b7b8b8 over the page background = 1.88:1).
   Raise it to the theme's secondary text color, which meets AA in both light (5.19:1) and dark
   (7.8:1) mode while keeping the current item visually de-emphasised relative to the active links.
   Loaded before MudBlazor.min.css, so #app adds specificity and !important beats the base rule. */
#app .mud-breadcrumbs .mud-disabled > a,
#app .mud-breadcrumbs .mud-breadcrumb-item.mud-disabled a {
    color: var(--mud-palette-text-secondary) !important;
}

/* CountrySelect: hide region group labels from page layout; show only inside MudBlazor popover */
.country-group-label {
    display: none !important;
}

.mud-popover .country-group-label {
    display: block !important;
    padding: 6px 16px 2px;
    margin-top: 2px;
    font-size: 0.68rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--mud-palette-text-disabled);
    pointer-events: none;
    user-select: none;
    border-top: 1px solid var(--mud-palette-divider);
    line-height: normal;
}

.mud-popover .country-group-label:first-child {
    border-top: none;
    margin-top: 0;
}


/* Single flat listing surface: subtle border + theme radius, no drop shadow. */
.fp-data-card {
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: var(--mud-default-borderradius);
    overflow: hidden;
}

/* DS-1: selection is a border, never elevation. A selected/current content surface (e.g.
   PricingCard's "Current plan") gets a 2px primary-colored border instead of a raised shadow --
   the shadow-based state it replaces was nearly invisible on the dark theme's #1B241F surface.
   The two-class selector (.fp-data-card.fp-card-selected) beats the one-class .fp-data-card rule's
   specificity on its own, so no !important is needed. Theme-token driven so it tracks light/dark. */
.fp-data-card.fp-card-selected {
    border: 2px solid var(--mud-palette-primary);
}

/* PU-1 (owner feedback 2026-08-01): the Current-usage pair — quota panel left, issuance-history
   chart right — stretch to one shared row height, so the shorter card's bottom edge lines up with
   the taller one instead of floating above a gap (same treatment as .fp-detail-layout). Each grid
   item becomes a flex column whose LAST child (the card; QuotaAlerts may render above it) grows. */
.fp-usage-grid .mud-grid-item {
    display: flex;
    flex-direction: column;
}

.fp-usage-grid .mud-grid-item > :last-child {
    flex: 1 1 auto;
}

/* PU-2: PricingCard's header (title + chip row) and body (price/copy/CTA) split into their own
   padded regions, replacing the root MudPaper's flat pa-6 -- lets the header alone take the
   current-tier tint below without also tinting the card's body. */
.fp-pricing-card__header {
    padding: 20px 24px 14px;
}

.fp-pricing-card__body {
    padding: 0 24px 24px;
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
}

/* PU-2: the current tier's header band gets a tinted background instead of a shadow -- reuses the
   SAME tonal palette token already used for the primary tonal-chip backgrounds (DS-4/IR-1), never
   a new hard-coded colour. */
.fp-card-selected .fp-pricing-card__header {
    background: var(--mud-palette-primary-hover);
}

/* Account settings row: label+value on the left, action button on the right.
   Mirrors GitHub / Linear / Vercel's account-settings row pattern. */
.fp-settings-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 16px 20px;
}

.fp-settings-row__content {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

/* On very small screens, stack the action button below the content. */
@media (max-width: 480px) {
    .fp-settings-row {
        flex-direction: column;
        align-items: flex-start;
    }
}

/* Divider lines that separate the drawer's header/footer from its scrollable body. */
.fp-form-drawer__header {
    border-bottom: 1px solid var(--mud-palette-divider);
}

.fp-form-drawer__footer {
    border-top: 1px solid var(--mud-palette-divider);
}

/* Search grows to fill the toolbar row once it wraps onto its own line (mobile/tablet). */
@media (max-width: 600px) {
    .fp-crud-toolbar__search {
        max-width: 100% !important;
        width: 100%;
    }
}

/* IR-1/FLT-01: removable filter chips row beneath the toolbar's main stack. Spacing only. */
.fp-crud-toolbar__chips {
    margin-top: .5rem;
}

.fp-filter-chip {
    display: inline-flex;
    align-items: center;
}

.fp-filter-chip__remove {
    margin-left: -6px;
}

/* Inset panel for an expanded table row's detail content. */
.fp-details-panel {
    background-color: var(--mud-palette-background-gray);
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: var(--mud-default-borderradius);
}

/* Monospace treatment for shown-once secrets (API keys) and inline key prefixes. */
.fp-mono input,
.fp-mono-inline {
    font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
    letter-spacing: 0.02em;
    font-variant-numeric: tabular-nums;
}

/* DS-2: fixed-width digits so metric/quota/date figures don't jitter or drift out of column
   alignment as their values change. Non-numeric text is visually unaffected. */
.fp-num {
    font-variant-numeric: tabular-nums;
}

/* DS-2: app-wide — every MudTd in every MudTable gets tabular digits for free, with zero edits to
   any individual listing page. MudSimpleTable cells (plain <td>, no .mud-table-cell class) are not
   reached by this rule and are wrapped directly where needed. */
.mud-table-cell {
    font-variant-numeric: tabular-nums;
}

/* PASS-3/FMT-01: botanical-nomenclature convention — genus/species pairs render italic everywhere,
   via Shared/BotanicalName.razor. The cultivar segment (after a single quote) is rendered in a plain
   <span> alongside this <i>, so it stays upright without a separate class. */
.fp-botanical {
    font-style: italic;
}

/* PASS-2: the passports list's merged primary identity cell — botanical name and passport number
   stack on their own lines inside the one anchor that is the row's single link. */
.fp-primary-cell {
    display: flex;
    flex-direction: column;
}

.fp-primary-cell .fp-botanical {
    font-weight: 500;
}

.fp-primary-cell .fp-mono-inline {
    color: var(--mud-palette-text-secondary);
    font-size: 0.8125rem;
}

/* PASS-2: signals that the whole row (not just the primary cell's link) navigates to the
   passport's detail page on click. */
.fp-row-clickable {
    cursor: pointer;
}

/* ADM-1 (50-01): the admin tenant list's "Usage this month" cell -- a quota bar over its
   "used / quota" text, both stacked in the row's own column instead of a fixed pixel width. */
.fp-usage-cell {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    min-width: 96px;
}

.fp-usage-cell__bar {
    border-radius: var(--mud-default-borderradius);
}

/* CP-1: MudTooltip's root is inline-flex and sizes to its content, so a gated full-width input
   wrapped in GateTooltip collapses inside its grid column. Opt-in stretch for those wrappers. */
.fp-gate-fill {
    display: block;
    width: 100%;
}

/* FRM-3: single source of the section-title weight, now that the tag itself carries real heading
   semantics (h2/h3) instead of styled body text. Shared by FormSection, BatchDetail.razor and
   PassportDetail.razor's own section titles. */
.fp-section-title {
    font-weight: 600;
}

/* PASS-2: MudButtonGroup paints its own surface-coloured rounded root behind the segments, and its
   direct MudMenu child wraps the chevron in a .mud-menu div that does not stretch to the buttons'
   height — the group's pale background then peeks out beneath the chevron as a white sliver.
   Stretch the menu wrapper to the group's full height, let the chevron button fill it (carrying
   the group's right-side radius), and keep the group root itself transparent — the segments paint
   their own fills. */
.fp-split-button.mud-button-group-root {
    background: transparent;
}

.fp-split-button .mud-menu {
    display: inline-flex;
    align-self: stretch;
}

.fp-split-button .mud-menu .mud-button-root {
    height: 100%;
    border-radius: 0 var(--mud-default-borderradius) var(--mud-default-borderradius) 0;
}

/* DS-4: Issued passport chips read as a soft tonal fill instead of the fully saturated Material
   Color.Success fill, so a Voided row (unchanged solid filled error) stands out against a list
   that is mostly Issued. MudBlazor 9.7's Variant enum has no native "tonal" member (Text/Outlined/
   Filled only), so this overrides Variant.Filled's background/text color on top. The background is
   the alpha-tint hover token, NOT success-lighten: the mockup draws a pale #EEF4F0-style tint,
   while success-lighten is a saturated green that read as a second filled chip (owner feedback
   2026-08-01). */
.fp-chip-tonal.mud-chip-filled.mud-chip-color-success {
    background-color: var(--mud-palette-success-hover);
    color: var(--chip-success-fg);
}

/* IR-1: active-filter chips are tonal brand pills (mockup: tinted background + primary border),
   not neutral outlined grey — the same tonal override mechanism as DS-4's success arm above. */
.fp-chip-tonal.mud-chip-filled.mud-chip-color-primary {
    background-color: var(--mud-palette-primary-hover);
    color: var(--chip-primary-fg);
    border: 1px solid var(--mud-palette-primary);
}

/* Owner decision 2026-08-01: the tonal treatment is the vocabulary for EVERY status chip —
   error (Voided/Revoked/Suspended/Rejected: a softer red than the old solid fill), info
   (Pending), warning, and the grey fallback alike. Exceptions stay visible through hue, not
   saturation; only Draft/Withdrawn remain outlined neutral (see StatusChipStyle.cs). */
.fp-chip-tonal.mud-chip-filled.mud-chip-color-error {
    background-color: var(--mud-palette-error-hover);
    color: var(--chip-error-fg);
}

.fp-chip-tonal.mud-chip-filled.mud-chip-color-info {
    background-color: var(--mud-palette-info-hover);
    color: var(--chip-info-fg);
}

.fp-chip-tonal.mud-chip-filled.mud-chip-color-warning {
    background-color: var(--mud-palette-warning-hover);
    color: var(--chip-warning-fg);
}

.fp-chip-tonal.mud-chip-filled.mud-chip-color-default {
    background-color: var(--mud-palette-action-default-hover);
    color: var(--chip-default-fg);
}

/* ---- Design-system item 7: the Italian layout budget ----
   The localisation MECHANISM was already complete (L["…"], UiText.it.resx, UiCultureTests). What was
   missing is the layout budget: Italian runs 20-40% longer than English across this product, and
   +45% is the growth any container holding a translated string has to survive.

   Only one container actually failed, but it failed by CLIPPING, which is the worst way to fail —
   MudBlazor gives .mud-nav-link-text `white-space: nowrap; overflow: hidden; text-overflow: ellipsis`,
   so in the 240px drawer "Inspection register" -> "Registro delle ispezioni" (+26%) rendered as
   "Registro delle isp…". A truncated navigation item is unreadable in a way a wrapped one is not, and
   nothing in the build could see it because the English string fits.

   The other four measured cases were checked and already hold, which is why there is no rule for them
   here: status chips are inline-flex and size to content (nowrap is correct for a chip — "Annullato"
   should not break mid-word); .mud-table-cell sets no white-space, so headers wrap; and MudBlazor
   puts no nowrap on buttons, so a full-width button wraps at 320px. ItalianLayoutBudgetTests measures
   all five and fails if any of those three defaults change underneath us. */
.mud-nav-link .mud-nav-link-text {
    white-space: normal;
    overflow: visible;
    text-overflow: clip;
}

/* ---- Design-system item 3: bulk selection ----
   The bar a listing shows while rows are ticked. --fp-field, the same subtle green-tinted surface
   the marketing home and the gated empty state use: a selection is a WORKING state, not a status,
   and a saturated strip would put a fourth traffic-light colour on a page where colour already means
   validity. See Shared/BulkActionBar.razor for the rules it carries. */
.fp-bulk-bar {
    display: flex;
    align-items: center;
    gap: .75rem;
    flex-wrap: wrap;
    padding: .5rem .25rem .5rem .75rem;
    background: var(--fp-field);
    border-radius: var(--mud-default-borderradius);
}

.fp-bulk-bar__count {
    font-weight: 600;
}

.fp-bulk-bar__actions {
    display: flex;
    align-items: center;
    gap: .25rem;
    flex-wrap: wrap;
    margin-left: auto;
}

/* 44px is the whole point of this column: the register is read and ticked in a warehouse, by a thumb
   over a glove, not by a mouse. MudBlazor's dense checkbox is ~30px, which is a desk target. The
   padding reset is what stops the table's own cell padding pushing the column past 44 and squeezing
   the passport column on a phone. */
.fp-select-col {
    width: 44px;
    min-width: 44px;
    padding-left: .25rem !important;
    padding-right: 0 !important;
}

.fp-select-col .mud-button-root {
    min-width: 44px;
    min-height: 44px;
}

/* NVX-02/NAV-3: trailing tier tag on a plan-gated nav item ("Starter+"/"Pro"), rendered only when
   the tenant lacks the item's RequiredCapability -- see NavMenu.razor. One tonal hue for every tag
   regardless of tier (mockup renders its lone "PRO" tag with the same amber swatch the marketing
   site uses for "Starter+"), reusing the same warning token pair as the .fp-chip-tonal warning arm
   above -- never a hard-coded hex value. */
.fp-nav-tag {
    display: inline-block;
    margin-left: auto;
    padding: 0.1rem 0.4rem;
    border-radius: var(--mud-default-borderradius);
    background-color: var(--mud-palette-warning-hover);
    color: var(--chip-warning-fg);
    font-size: 0.65rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

/* ST-3/EMX-01: a plan-gated empty state sits inside a tinted panel (a subtle green wash, the same
   --fp-field surface already used on the marketing home) so it never reads as an error, with the
   capability's tonal tier tag pinned to the corner -- reusing .fp-nav-tag's warning-hover/
   warning-darken tokens verbatim (fp-gated-empty__tag overrides its margin-left:auto so the two
   classes combine correctly on the same span). See CapabilityGate.razor/ApiKeys.razor. */
.fp-gated-empty {
    position: relative;
    background: var(--fp-field);
    border-radius: var(--mud-default-borderradius);
    padding: 1.5rem;
}

.fp-gated-empty__tag {
    position: absolute;
    top: 0.75rem;
    right: 0.75rem;
    margin-left: 0;
}

/* ADT-03/ADM-6: capability tag-chips on the admin plans table reuse .fp-nav-tag's tonal treatment
   outside its nav context -- this modifier only resets the nav-specific margin-left:auto (the same
   override fp-gated-empty__tag makes) so the tags sit in a small wrapping flex row. */
.fp-plan-cap-tag {
    margin-left: 0;
}

/* QUICK-260721-vk6 + QUICK-260722-nr5: classic sticky-footer flexbox pattern. Ownership of the
   flex column moved UP from MudMainContent to the layout root now that the footer is an external
   sibling of MudMainContent (moved out so its contentinfo landmark is top-level). #app .mud-layout
   becomes a flex column at least one viewport tall; the fixed app bar and positioned drawer are out
   of normal flow and unaffected. MudMainContent (.mud-main-content, flex:1 1 auto) grows to fill the
   column, pushing the external footer to the bottom edge on short pages while it still flows below
   content on tall pages. The #app prefix beats MudBlazor's later-loading .mud-layout{height:100%}.
   The footer is never pulled out of normal document flow through a CSS position override -- only flex
   layout (here) and a mirrored drawer margin (below) move it. */
#app .mud-layout {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    min-height: 100dvh;
}

/* main grows to fill the flex column; the min-height budget now lives on .mud-layout above (leaving
   it here too would force main alone to a full viewport and create a double-viewport scrollbar). */
#app .fp-main-content {
    flex: 1 0 auto;
}

/* Mirror MudBlazor's responsive left-drawer offset onto the now-external footer region so it stays
   horizontally aligned with page content when the drawer is open on desktop, and un-offsets when the
   drawer collapses to a mobile overlay. Selectors + media-query breakpoints match MudBlazor's own
   .mud-drawer-open-responsive-<bp>-left .mud-main-content rules exactly; --mud-drawer-width-left is
   set at runtime on .mud-layout and inherited by this child region. */
.fp-footer-region {
    /* Item 8: was 225ms cubic-bezier(0,0,.2,1) inline. This tracks the drawer it is following, so it
       reads the drawer's own duration and easing — and now stops moving with it under
       prefers-reduced-motion, which the inline value could not do. */
    transition: margin var(--fp-duration-drawer) var(--fp-ease-out);
}

/* Environment identification carries NO styling of its own any more. It used to be .fp-dev-banner, a
   sticky 28px strip whose hardcoded app-bar offset MudDrawer never honoured (first nav item clipped),
   then briefly .fp-env-frame, a fixed pointer-events:none viewport outline. Both are gone: the owner's
   decision (2026-08-11) is that the footer caption alone is sufficient, and a text caption needs no
   rule here. Do not reintroduce a full-bleed banner that occupies document flow — every fixed-position
   sibling MudBlazor positions (app bar, drawer) then has to be offset by a constant that nothing keeps
   in step, which is the exact defect that removed the last one. */

/* CHR-1: Footer.razor's default (Compact="false") public density. PublicLayout places it once for
   every anonymous route. Reads --mud-palette-* tokens directly; no hard-coded hex anywhere here. */
.fp-footer-full {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: flex-start;
    gap: 16px;
}

.fp-footer-public-content {
    padding-inline: 24px;
}

.fp-footer-full__brand {
    max-width: 44ch;
}

.fp-footer-full__brand-link {
    display: inline-flex;
    color: inherit;
    text-decoration: none;
}

.fp-footer-full__reg {
    margin: 6px 0 0;
    font-size: .82rem;
    color: var(--mud-palette-text-secondary);
}

.fp-footer-full__links {
    display: flex;
    flex-wrap: wrap;
    gap: 8px 20px;
}

.fp-footer-full__copy {
    margin-top: 16px;
    font-size: .82rem;
    color: var(--mud-palette-text-secondary);
}

/* CHR-1: mirrors #app .mud-layout's own sticky-footer pattern above, generalised to every
   PublicLayout consumer (Verify + the whole AuthLayout family). PublicLayout becomes a flex column
   at least one viewport tall; .fp-public-main grows to fill it, pinning the footer to the bottom
   edge on short pages while it still flows below content on tall pages. */
.fp-public-shell {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    min-height: 100dvh;
}

.fp-public-main {
    flex: 1 0 auto;
}

@media (min-width: 0px) {
    #app .mud-drawer-open-responsive-xs-left .fp-footer-region {
        margin-left: var(--mud-drawer-width-left);
    }
}

@media (min-width: 600px) {
    #app .mud-drawer-open-responsive-sm-left .fp-footer-region {
        margin-left: var(--mud-drawer-width-left);
    }
}

@media (min-width: 960px) {
    #app .mud-drawer-open-responsive-md-left .fp-footer-region {
        margin-left: var(--mud-drawer-width-left);
    }
}

@media (min-width: 1280px) {
    #app .mud-drawer-open-responsive-lg-left .fp-footer-region {
        margin-left: var(--mud-drawer-width-left);
    }
}

@media (min-width: 1920px) {
    #app .mud-drawer-open-responsive-xl-left .fp-footer-region {
        margin-left: var(--mud-drawer-width-left);
    }
}

@media (min-width: 2560px) {
    #app .mud-drawer-open-responsive-xxl-left .fp-footer-region {
        margin-left: var(--mud-drawer-width-left);
    }
}

/* QUICK-260721-vk6: wraps the suspended banner + page content so that region grows to fill any
   leftover vertical space in the flex column, pushing the footer down to the bottom edge on
   short pages, while never shrinking below its natural content height so tall pages still scroll
   normally with no clipping. */
.fp-content-grow {
    flex: 1 0 auto;
}

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

    #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+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
    padding: 1rem 1rem 1rem 3.7rem;
    color: white;
}

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

/* PLAT-02 / D-03 (15-05): the pre-WASM #app boot loader (previously .loading-progress /
   .loading-progress-text here) was replaced by a self-contained loader whose CSS is inlined
   directly in wwwroot/index.html's <head> (class names .fp-boot / .fp-boot__spinner /
   .fp-boot__text) so first paint needs zero extra network round-trip, not even this stylesheet
   (15-RESEARCH.md Pattern 3 — the FCP-winning lever). Nothing in this codebase's bundled
   blazor.webassembly.js sets --blazor-load-percentage / --blazor-load-percentage-text (verified:
   grep found no occurrence in _framework/*.js), so the removed rules were dead/static anyway. */

/* ---- FloraPass brand identity tokens (2026-07-26 uniform restyle) ----
   Shared by the marketing home and the app kit. Colors that map onto the MudBlazor palette are read
   from --mud-palette-* directly (so light/dark tracks the theme); only values with no palette
   equivalent are defined here. */
:root {
    /* BR-1: the ONE brand green — the mark's own colour, deliberately not Primary. The mark is an
       identity, not an accent: it must not restyle itself when the palette does, and it must not
       change between light and dark. Authoritative copy is FloraPassTheme.BrandTile; favicon.svg
       and symbol.svg repeat the same literal because an SVG loaded as an icon cannot read this
       property. BrandTokenDriftTests keeps all four in step — do not edit one alone. */
    --fp-brand-tile: #14532D;
    /* BR-5: duplicated from FloraPassTheme.SerifDisplay because a static stylesheet cannot read a
       C# array. The C# copy is authoritative; the drift test asserts this line equals it. */
    --fp-serif: "Iowan Old Style", Cambria, Georgia, "Times New Roman", serif;
    --fp-leaf: #3FA372;                 /* brighter interactive green for hovers */
    --fp-forest-deep: #1B4D38;          /* deep forest ground for the closing CTA band */
    --fp-field: #EEF4F0;                /* subtle green-tinted surface */
    --fp-shadow-sm: 0 1px 2px rgba(20, 43, 34, .05), 0 6px 16px -10px rgba(20, 43, 34, .14);
    --fp-shadow: 0 1px 2px rgba(20, 43, 34, .04), 0 12px 32px -12px rgba(20, 43, 34, .16);

    /* ---- Tonal chip INK (design-system item 1) ----
       Every .fp-chip-tonal arm draws its label from one of these, so the answer lives in one place
       instead of five. They exist because MudBlazor's --mud-palette-*-darken is the WRONG token for
       this job twice over:

       1. It is not a text colour. MudBlazor.min.css uses -darken as the :active / :focus-visible
          BACKGROUND of filled buttons, chips, FABs and icon buttons. Retuning it for legibility
          would repaint every pressed control in the app — in dark mode a pressed error button would
          go pink. So the ink is separated from the palette slot rather than layered on top of it.
       2. Darkening a hue is only the right direction on a light ground. On the dark palette's near
          black wash it drives the label INTO the background.

       Measured with PaletteContrastTests.The_tonal_chip_label_is_readable_on_its_own_wash, which
       composites the 6% -hover wash over Surface exactly as the browser does. Do not edit a value
       here without re-reading that test's output. */
    --chip-success-fg: var(--mud-palette-success-darken);  /* 10.92:1 */
    --chip-primary-fg: var(--mud-palette-primary-darken);  /*  6.75:1 */
    --chip-error-fg: var(--mud-palette-error-darken);      /*  5.69:1 */
    --chip-info-fg: var(--mud-palette-info-darken);        /*  4.99:1 */
    /* The shipped defect this item names. -darken resolves to #F49906, which measures 2.15:1 on the
       chip's own #FFFAF2 wash — AA needs 4.5:1, and it fails on EVERY amber chip: "Expiring soon",
       the gated-nav TierTag, the warning alert, the protected-zone notice. #7C5C00 is not a new
       colour; it is the amber ink marketing.css already uses for the Starter tag. 5.95:1. */
    --chip-warning-fg: #7C5C00;
    /* The neutral arm needs no per-scheme override: text-secondary is already defined per palette
       and measures 5.20:1 light / 6.32:1 dark on the action-default wash. It is named here anyway so
       every tonal arm resolves through one layer. */
    --chip-default-fg: var(--mud-palette-text-secondary);

    /* ---- Motion (design-system item 8) ----
       FloraPass moves as little as possible: this is a compliance tool used under time pressure, so
       animation exists to show that state CHANGED, never to entertain. The rules the scale encodes:

         - Colour, border and opacity animate. Position and size do not, except the marketing
           surface's 1px hover lift and the drawer's slide.
         - Nothing on a data surface animates on load. A table that fades in reads as a slow table.
         - Verdicts never animate — see .fp-verify-band, which pins animation/transition to none.

       Components referenced durations inline (.18s, .15s, .2s, 225ms), so there was no shared answer
       and, more to the point, no way to switch it off. Reference a token instead of writing a
       duration; that is what makes the reduced-motion block below able to work at all. */
    --fp-duration-instant: 90ms;   /* press feedback, the checkbox tick */
    --fp-duration-fast: 150ms;     /* hover colour on dense controls — rows, chips, nav items */
    --fp-duration: 180ms;          /* the default: buttons, inputs, focus rings */
    --fp-duration-slow: 240ms;     /* disclosure — FAQ rows, expandable detail panels */
    --fp-duration-drawer: 280ms;   /* the form drawer's slide and its overlay fade */

    --fp-ease-standard: cubic-bezier(.4, 0, .2, 1); /* both ends visible: hovers, colour */
    --fp-ease-out: cubic-bezier(0, 0, .2, 1);       /* things entering: drawer, disclosure */
    --fp-ease-in: cubic-bezier(.4, 0, 1, 1);        /* things leaving */

    /* Ready-made. Prefer these over writing a duration inline. */
    --fp-transition-colors: color var(--fp-duration) var(--fp-ease-standard), background-color var(--fp-duration) var(--fp-ease-standard), border-color var(--fp-duration) var(--fp-ease-standard);
    --fp-transition-opacity: opacity var(--fp-duration-fast) var(--fp-ease-standard);
    --fp-transition-transform: transform var(--fp-duration) var(--fp-ease-standard);
    --fp-transition-drawer: transform var(--fp-duration-drawer) var(--fp-ease-out);
}

/* An operator who has asked their OS to stop moving things gets a product that does not move. State
   still changes COLOUR — only the travel is removed, because removing the colour change too would
   take away the feedback that something happened. */
@media (prefers-reduced-motion: reduce) {
    :root {
        --fp-duration-instant: 1ms;
        --fp-duration-fast: 1ms;
        --fp-duration: 1ms;
        --fp-duration-slow: 1ms;
        --fp-duration-drawer: 1ms;
        --fp-transition-transform: none;
        --fp-transition-drawer: none;
    }
}

/* Dark mode is MudBlazor's IsDarkMode, which swaps --mud-palette-* inside :root and leaves NO
   selector behind to hang a rule on (.mud-theme-dark is an unrelated Color.Dark background
   utility). MainLayout/PublicLayout therefore stamp data-theme onto <html> — see ThemeAttribute.cs.

   The design system predicted "the same bug in mirror image" here. Measurement says otherwise, and
   the correction is worth recording: warning is the one arm that is FINE in dark (6.40:1, because
   #F49906 is a bright amber on a near-black wash). The four that actually fail are success 2.03:1,
   error 2.47:1, info 2.78:1 and primary 3.87:1 — a worse defect than the light-mode one, and
   invisible until measured. Every value below is pinned light-on-dark instead of darkened. */
[data-theme="dark"] {
    /* NOT --mud-palette-success-lighten: that is #3A9C3F, which lands at 4.33:1 — under AA by a
       hair. #4CAF50 is the same Material green ramp one step lighter (the base is Green 800) and
       clears it at 5.44:1. This is the one value corrected away from the design system's. */
    --chip-success-fg: #4CAF50;
    --chip-primary-fg: var(--mud-palette-primary-lighten); /* 6.01:1 */
    --chip-error-fg: #F08A8A;                              /* 6.40:1 */
    --chip-info-fg: #5FB8ED;                               /* 6.78:1 */
    --chip-warning-fg: #F9C55E;                            /* 8.88:1 */
}

/* Crisp leaf wordmark, replacing the 🌿 emoji everywhere (app bar, auth card, footer, home). */
.fp-brand { display: inline-flex; align-items: center; gap: .5rem; font-weight: 700; letter-spacing: -.01em; line-height: 1; }
.fp-brand__mark { width: 26px; height: 26px; flex: none; display: block; }
/* BR-6 (RFC-0003), owner decision 2026-08-10: the wordmark stays SANS while H1–H4 are the serif
   display stack (--fp-serif). This is a deliberate pairing, not an oversight — do not "correct" it
   to --fp-serif for consistency with the headings it sits above on /verify and in the marketing
   header. Roboto 700 is materially more legible at the 16px the footer renders it at, and the
   sans/serif contrast is what makes the lockup read as a mark rather than as more heading text.
   If this is ever revisited, check it at the 24px lockup minimum BEFORE committing. */
.fp-brand__name { font-weight: 700; letter-spacing: -.02em; }
.fp-brand--sm .fp-brand__mark { width: 20px; height: 20px; }
.fp-brand--sm .fp-brand__name { font-size: .95rem; }

/* PD-1 / LBL-01, LBL-02, LBL-03: the shared on-screen label facsimile (Shared/LabelPreview.razor),
   moved here from Home.razor's private .fph-pp* rules so every consuming page (Home, PassportDetail,
   CreatePassport, Verify) gets identical styling. Mirrors the REAL generated label
   (PassportLabelFrame): the EU flag top-left, "Plant Passport" (+ second-language wording) top-right,
   a single-column A/B/C/D with D = country of origin, and the EAN-13 beneath.
   RFC-0002 CHR-2: this frame represents a printed artefact and must render IDENTICALLY in light and
   dark mode — its background, ink and EU-flag colors are therefore deliberate literal hex values, a
   documented exception to the app's no-hard-coded-colour rule. Do not "fix" them into --mud-palette-*
   or --fp-* tokens; only the frame's structural border/divider chrome (not printed content) tracks the
   theme. POL-01: this frame's box-shadow below is ALSO deliberate, on purpose -- a physical-sticker
   affordance, since the frame represents a printed, adhesive label sitting on a surface rather than
   a flat content card, and is exempt from the app's flat-elevation rule; a future audit should not
   re-flag it. By contrast, the verify card's own box-shadow (see the verify section further down)
   was NOT deliberate and has been removed. */
.fp-label { margin: 0; background: #fff; border: 1px solid var(--mud-palette-lines-default); border-radius: 6px;
    box-shadow: var(--fp-shadow); max-width: 380px; width: 100%; justify-self: center; padding: 1rem 1.1rem; color: #14352A; }
.fp-label-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 1rem;
    padding-bottom: .7rem; border-bottom: 1px solid var(--mud-palette-divider); }
.fp-label-title { text-align: right; line-height: 1.25; }
.fp-label-title strong { display: block; font-size: 1rem; letter-spacing: .01em; }
.fp-label-title span { display: block; font-size: .74rem; color: #5B6B63; }
/* Official EU flag colors, printed on every physical label — must never track the app's theme.
   HOME-3: the single static eu-emblem.svg asset supplies the field colour and stars now, replacing
   the old CSS-approximated star-glyph ring; only box/placement stay pinned here. */
.fp-label-emblem { width: 46px; height: 30px; flex: none; border-radius: 3px; display: block; object-fit: cover; }
.fp-label-rows { display: flex; flex-direction: column; gap: .4rem; padding: .8rem 0; }
.fp-label-row { display: flex; gap: .55rem; align-items: baseline; font-size: .92rem; }
.fp-label-row .k { font-weight: 700; width: .8rem; flex: none; }
.fp-label-pz { font-style: italic; font-size: .88rem; padding-top: .6rem; color: #14352A; }
.fp-label-foot { padding-top: .7rem; border-top: 1px solid var(--mud-palette-divider); }
/* Barcode ink is a fixed literal (matching the frame's own #14352A ink), not the --fph-ink/
   --mud-palette-text-primary alias: that alias flips to a light color in dark mode, which would
   render the bars invisible/inverted against this frame's fixed white background — a latent bug that
   never surfaced while this rule only ever rendered on Home's permanently light-locked page. */
.fp-label-barcode { height: 44px; border-radius: 2px;
    background-image: repeating-linear-gradient(90deg,
        #14352A 0 2px, transparent 2px 3px, #14352A 3px 6px, transparent 6px 8px,
        #14352A 8px 9px, transparent 9px 12px, #14352A 12px 15px, transparent 15px 16px,
        #14352A 16px 17px, transparent 17px 20px, #14352A 20px 23px, transparent 23px 24px);
    background-size: 24px 100%; }
.fp-label-ean { display: block; text-align: center; font-family: ui-monospace, Consolas, monospace; font-size: .82rem;
    letter-spacing: .18em; color: #5B6B63; margin-top: .5rem; font-variant-numeric: tabular-nums; }

/* CRT-01: two-column create-passport layout — the grouped FormSections on the left, the sticky
   LabelPreview on the right; single column below MudBlazor's own md (960px) breakpoint. */
.fp-form-layout {
    display: grid;
    grid-template-columns: 1fr;
    gap: 24px;
    align-items: start;
}

@media (min-width: 960px) {
    .fp-form-layout {
        grid-template-columns: 1.25fr .75fr;
    }
}

/* Rare edge case: no operator profile loaded, so there is no second (preview) child to grid beside —
   the one remaining card takes the full width instead of being squeezed into the left track. */
.fp-form-layout--single {
    grid-template-columns: 1fr !important;
}

/* CRT-01: the label preview stays pinned in view (offset below the fixed app bar) while the form,
   usually the taller of the two columns, scrolls beside it. */
.fp-sticky-preview {
    position: sticky;
    top: calc(var(--mud-appbar-height, 64px) + 1rem);
    align-self: start;
}

/* PU-1: /plan's route-based scroll lands on #change-plan-section -- offset it below the fixed
   app bar by the same --mud-appbar-height token .fp-sticky-preview already uses above, so the
   "Change plan" heading isn't clipped underneath the bar when scrolled into view. */
.fp-section-anchor {
    scroll-margin-top: calc(var(--mud-appbar-height, 64px) + 1rem);
}

/* PD-4: TraceabilityChain's inline dot-and-connector steps (supplier lots -> batch -> this
   passport), replacing the old collapsed MudExpansionPanel. Theme-token driven so it tracks
   light/dark. */
.fp-trace-step {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 4px 0;
    position: relative;
}

.fp-trace-dot {
    flex: none;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--mud-palette-lines-default);
}

.fp-trace-dot--current {
    background: var(--mud-palette-primary);
}

/* #210: the "now <partner>" aside on a linked supplier delivery. Rendered only when the live
   partner name has diverged from the snapshot taken at receipt, so it must read as secondary to
   the record itself -- the snapshot is the evidence, this is context. */
.fp-trace-note {
    color: var(--mud-palette-text-secondary);
    font-size: 0.8125rem;
}

.fp-trace-step:not(:last-child)::after {
    content: "";
    position: absolute;
    left: 3px;
    top: 100%;
    width: 1px;
    height: 8px;
    background: var(--mud-palette-lines-default);
}

/* PD-5/DET-04: two-column detail composition. On PassportDetail the record card leads in the
   narrower left column and the facsimile uses the wider right column (owner review 2026-08-05);
   single column below the breakpoint (same convention as .fp-form-layout, Phase 40). */
/* align-items stretch (owner feedback 2026-08-01): both cards fill the row's full height so the
   two columns' edges line up instead of the shorter record card floating above a ragged gap. */
.fp-detail-layout {
    display: grid;
    grid-template-columns: 1fr;
    gap: 24px;
    align-items: stretch;
}

@media (min-width: 960px) {
    .fp-detail-layout {
        grid-template-columns: .85fr 1.15fr;
    }
}

/* V-1/VER-01: public verify becomes a mobile-first credential check -- a stranger's single,
   seconds-long trust check on a phone, outdoors. The verdict band deliberately uses a STRONG/solid
   palette fill (not the DS-4/owner decision 2026-08-01 soft-tonal fill mandated for status CHIPS
   app-wide) because this element serves a different purpose than a chip: maximum scannability at
   arm's length, not a quiet inline status marker. All colors are mud-palette/fp theme tokens --
   no literal hex anywhere in these rules. (NB: never write the token names with their asterisk
   wildcards inside a CSS comment -- the slash-star sequence terminates the comment early and the
   parser then swallows the NEXT rule, which is exactly how .fp-verify-page lost its centering.
   POL-01: min-height: 100dvh removed here -- redundant and actively counter-productive now that
   PublicLayout's own .fp-public-shell provides the "at least one viewport tall, footer pinned to
   the bottom on short pages" behaviour at the outer level (CHR-1); leaving it here would force the
   new footer below an extra full viewport of empty space on every load. */
.fp-verify-page {
    display: flex;
    justify-content: center;
    align-items: flex-start;
    padding: 2rem 1rem;
}

/* POL-01: box-shadow removed -- it was not a deliberate design choice (unlike .fp-label's own
   shadow above, which is). */
.fp-verify-card {
    width: 100%;
    max-width: 420px;
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: var(--mud-default-borderradius);
    overflow: hidden;
    font-size: 1rem;
}

.fp-verify-brand {
    display: flex;
    align-items: center;
    gap: .5rem;
    padding: .75rem 1rem;
    border-bottom: 1px solid var(--mud-palette-divider);
}

.fp-verify-brand__tag {
    margin-left: auto;
    font-size: .8125rem;
    color: var(--mud-palette-text-secondary);
}

/* Design-system item 2: the verdict is the HERO, not a strip.
   The person reading this is holding a phone at arm's length, in a loading bay, possibly in direct
   sun, with an inspector waiting. A compact band is sized for a desk. It claims the area above the
   fold so the verdict is the only thing on screen when the page resolves.

   Colour is never the only carrier — three things say the same thing independently, so the band
   survives greyscale, a colour-blind reader and a washed-out screen: the icon SHAPE (tick, cross,
   question mark, struck-out cloud), the verdict WORD at display size, and LUMINANCE separation
   between the fills. None of the three may be reduced to decoration; VerifyOutcomeCarriersTests
   is what holds that. */
.fp-verify-band {
    text-align: center;
    padding: 2.75rem 1.25rem 2.25rem;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    min-height: 46vh;
    /* Nothing animates. A verdict that fades in reads as a verdict still being decided, and this is
       the one surface in the product that someone acts on immediately. Declared rather than merely
       absent so the motion-token sweep cannot introduce one here by inheritance. */
    animation: none;
    transition: none;
}

.fp-verify-band--success {
    background: var(--mud-palette-success);
    color: var(--mud-palette-success-text);
}

.fp-verify-band--error {
    background: var(--mud-palette-error);
    color: var(--mud-palette-error-text);
}

.fp-verify-band--warning {
    background: var(--mud-palette-warning);
    color: var(--mud-palette-warning-text);
}

/* VER-1: the "couldn't check" and "bad link" states. Deliberately NEUTRAL rather than warning-
   coloured: neither is a verdict on the passport, and a third traffic-light colour beside the
   success and error bands is read as one. */
.fp-verify-band--neutral {
    background: var(--mud-palette-dark);
    color: var(--mud-palette-dark-text);
}

.fp-verify-band__actions {
    margin-top: .9rem;
}

/* 64px, held absolutely rather than as a fraction of anything. MudBlazor's Size.Large is 2rem, which
   is a toolbar icon — the shape has to be readable as a shape from further away than that. */
.fp-verify-band .mud-icon-root {
    font-size: 64px;
    width: 64px;
    height: 64px;
}

.fp-verify-band__title {
    font-family: var(--fp-serif);
    font-size: clamp(1.6rem, 7vw, 2.4rem);
    line-height: 1.15;
    font-weight: 600;
    margin: .75rem 0 0;
    /* Italian is what forces these two. "Valid plant passport" becomes "Passaporto delle piante
       valido" (+55%), which at display size on a 320px viewport sets as a ragged three-line stack
       without a measure and a balanced wrap. */
    max-width: 22ch;
    text-wrap: balance;
}

.fp-verify-band__reason {
    font-size: 1rem;
    opacity: .92;
    margin-top: .6rem;
    max-width: 34ch;
}

.fp-verify-band__caption {
    font-size: .8125rem;
    opacity: .85;
    margin-top: .35rem;
}

/* MudSimpleTable emits plain <td>, not reached by the app-wide .mud-table-cell rule -- same pattern
   the .fp-num/.mud-table-cell comment above already documents. */
.fp-verify-rows td {
    font-size: 1rem;
}

.fp-verify-explain {
    font-size: .875rem;
    color: var(--mud-palette-text-secondary);
    padding-top: .75rem;
    border-top: 1px solid var(--mud-palette-divider);
    margin: 0;
}

/* VER-4: the ONE persistent h1. It sits outside every state branch, so the document has a heading
   while the fetch is still in flight -- previously all three h1s lived inside resolved branches and
   a loading page was headingless. Each outcome's own headline is the band's h2 beneath this. */
.fp-verify-title {
    font-family: var(--fp-serif);
    font-size: 1rem;
    font-weight: 600;
    margin: 0;
    padding: .9rem 1rem .1rem;
    color: var(--mud-palette-text-secondary);
}

/* VER-2: the manual-entry route. A 36-character GUID is hostile to type, so give it room, tabular
   figures and no autocorrect -- this is the fallback for a label that got wet in a truck. */
.fp-verify-entry__input input {
    font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
    font-size: .95rem;
    letter-spacing: .01em;
}

/* VER-3: the actions row. Wraps rather than scrolls -- this is a phone screen at a loading bay. */
.fp-verify-actions {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
    margin-top: 1rem;
}

/* ---- VER-3: print / "Save this check" ----
   The first print stylesheet in the app. A saved check is evidence that someone verified a passport
   at a moment in time, so the sheet keeps exactly that: the outcome, the label facsimile, the A-D
   rows, the passport ID, the checked-at time and the source sentence. Everything that is navigation
   or an action is dropped -- a printed "Try again" button is noise on a filed document.

   LabelPreview keeps its white background and black text here as everywhere else: it represents a
   printed artefact (RFC-0002 CHR-2), and print-color-adjust keeps the verdict band's fill from
   being helpfully removed by the browser -- a "Valid" band that prints as white paper would be a
   record of nothing. */
.fp-no-print {
    /* no screen effect; the print block below hides it */
}

@media print {
    .fp-no-print,
    .fp-public-shell > footer,
    .fp-verify-brand__tag {
        display: none !important;
    }

    .fp-verify-page {
        padding: 0;
        display: block;
    }

    .fp-verify-card {
        max-width: none;
        border: 0;
        border-radius: 0;
    }

    /* Keep the coloured verdict band: it IS the result being recorded. */
    .fp-verify-band {
        -webkit-print-color-adjust: exact;
        print-color-adjust: exact;
        break-inside: avoid;
        /* On screen the verdict claims the fold; on paper that would spend half of page one on
           whitespace, and the saved PDF is a record rather than something read at a distance. */
        min-height: 0;
        padding: 1.5rem 1rem;
    }

    .fp-verify-rows,
    .fp-label {
        break-inside: avoid;
    }
}

/* AUL-01/LOG-1/AUTH-1: the light auth-family layout (Layout/AuthLayout.razor), nested inside
   PublicLayout rather than a fourth top-level layout. Reads --mud-palette-* custom properties
   directly, never a literal hex -- same convention as the .fp-verify-* block above.
   CHR-1: .fp-auth-shell no longer owns a viewport-height sticky-footer job -- PublicLayout's own
   .fp-public-shell (above) does that now, once, for every PublicLayout consumer. The selector stays
   in the HTML unstyled (harmless) to avoid an unrelated diff. */
.fp-auth-header {
    display: flex;
    align-items: center;
    gap: .5rem;
    padding: .75rem 1rem;
}

/* Back-link is the header's second (and last) direct child -- pushed to the right edge without a
   fifth named class, per the plan's exact class list. */
.fp-auth-header > a:last-child {
    margin-left: auto;
}

.fp-auth-body {
    padding: 1rem 1rem 2rem;
}

/* Mockup: the "Forgot?" affordance sits right-aligned on the password label line. */
.fp-auth-forgot-row {
    display: flex;
    justify-content: flex-end;
    margin-bottom: -6px;
}

/* AUL-02/LOG-2: the login card's remember-me row (checkbox + inline hint on one line) and meta row
   (Register / Resend-verification links sharing a single row) -- replaces four stacked text blocks. */
.fp-auth-remember-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .5rem;
}

/* Mockup: a single divider-topped, centred line under the primary button. */
.fp-auth-meta-row {
    display: flex;
    justify-content: center;
    flex-wrap: wrap;
    gap: .5rem;
    padding-top: .9rem;
    border-top: 1px solid var(--mud-palette-divider);
}

/* IRX-02/IR-3: the inspection register's tertiary columns (Batch, Traceability) are real desktop
   columns that collapse below 600px into the per-row expand toggle's ExpandableDetailsPanel child
   row, and vice versa -- the two rules are complementary halves of the same breakpoint. The
   !important guards against MudBlazor's own responsive `display` overrides for Breakpoint.Sm-mode
   cells at the same boundary; 600px matches the existing .fp-crud-toolbar__search media query above
   and MudBlazor's own Sm breakpoint value. */
@media (max-width: 599.98px) {
    .fp-tertiary-col {
        display: none !important;
    }
}

@media (min-width: 600px) {
    .fp-expand-col {
        display: none !important;
    }
}

.fp-recipient-country {
    color: var(--mud-palette-text-secondary);
}

/* LDG-01/ST-1: LoadingSkeleton's Table variant row shape -- the same 1.7/1.1/.7/.5 column ratio
   the register's own real columns and the rfc1-sec-9 mockup both use, so the skeleton and the
   loaded table read as one shape. */
.fp-skeleton-row {
    display: grid;
    grid-template-columns: 1.7fr 1.1fr .7fr .5fr;
    gap: 10px;
    align-items: center;
    padding: 8px 0;
}

.fp-skeleton-row__primary {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

/* UTIL-1 (Shared/LegalPage.razor): long-form Privacy/Terms content follows the same centered public
   page rhythm as Support. The page container is centered at Support's 760px measure; prose stays
   left-aligned inside it for readability. Token-driven (--mud-palette-*), no hard-coded colours. */
.fp-legal {
    width: 100%;
    max-width: 760px;
    margin-inline: auto;
}

.fp-legal-title {
    margin-bottom: .5rem;
}

.fp-legal-status {
    margin-bottom: 1.5rem;
}

.fp-legal-toc {
    width: 100%;
    margin-bottom: 1.5rem;
    padding: .75rem 1rem;
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: var(--mud-default-borderradius);
}

.fp-legal-toc-title {
    margin-bottom: .25rem;
}

.fp-legal-toc ul {
    margin: 0;
    padding-left: 1.25rem;
}

.fp-legal-toc li {
    margin-bottom: .25rem;
}

/* The capped reading measure: ~70 characters at the app's base font size, per UTIL-1. Applies to
   the consuming page's own prose (p, h2, h3, ul, ol) -- LegalPage itself only renders the h1. */
.fp-legal-body {
    max-width: 70ch;
    margin-inline: auto;
}

.fp-legal-body h2 {
    margin-top: 2rem;
    margin-bottom: .75rem;
    font-size: 1.25rem;
    font-weight: 600;
}

.fp-legal-body h3 {
    margin-top: 1.5rem;
    margin-bottom: .5rem;
    font-size: 1.05rem;
    font-weight: 600;
}

.fp-legal-body p,
.fp-legal-body ul,
.fp-legal-body ol {
    margin-top: 0;
    margin-bottom: 1rem;
    line-height: 1.6;
}

/* ADQ-01 (Pages/Admin/OperatorChangeRequests.razor): the review queue's primary cell shows both
   registration codes in one mono span -- the outgoing value recedes, the incoming value carries the
   theme primary (the brand green in both palettes). Token-driven, no hard-coded colours. */
.fp-code-old {
    color: var(--mud-palette-text-secondary);
}

.fp-code-new {
    font-weight: 600;
    color: var(--mud-palette-primary);
}

/* ADQ-01: urgency treatment for a queue row pending longer than a week -- the age figure goes amber
   and the whole row gets a warm wash, the same warning token pair the nav tier tag uses above. */
.fp-waiting-overdue {
    color: var(--chip-warning-fg);
    font-weight: 500;
}

.fp-row-attention {
    background-color: var(--mud-palette-warning-hover);
}
