@import url('open-iconic/font/css/open-iconic-bootstrap.min.css');

/* Noema design tokens (noema.tech-aligned) — use CSS variables everywhere */
:root {
    /* Colors — primary / accent */
    --noema-green: #7EC062;
    --noema-green-light: #9BD286;
    --noema-green-muted: rgba(126, 192, 98, 0.5);
    --noema-teal: #51BBB3;

    /* Colors — dark surfaces */
    --noema-bar-bg: #303741;
    --noema-footer-bg: #2D323B;

    /* Colors — neutrals & text */
    --noema-white: #FFFFFF;
    --noema-text-on-dark: #E0E0E0;
    --noema-text-muted: #B0B0B0;
    --noema-text-inactive: #7A828A;                 /* readable muted grey for inactive/deactivated items on white */
    --noema-heading: #303741;
    --noema-body: #555555;
    --noema-body-alt: #666666;
    --noema-link: #7EC062;
    --noema-link-hover: #6EAF52;
    --noema-bg-light: #F5F7FA;
    --noema-bg-content: #FFFFFF;
    --noema-border: #E0E0E0;
    --noema-divider: #303741;

    /* Buttons & states */
    --noema-btn-primary-bg: var(--noema-green);
    --noema-btn-primary-border: var(--noema-green);
    --noema-btn-primary-hover-bg: #6EAF52;
    --noema-btn-primary-hover-border: #6EAF52;
    --noema-btn-danger-bg: #dc3545;
    --noema-btn-danger-border: #dc3545;
    --noema-btn-danger-hover-bg: #c82333;
    --noema-btn-danger-hover-border: #bd2130;
    --noema-btn-disabled-bg: #6c757d;
    --noema-btn-disabled-border: #6c757d;
    --noema-btn-disabled-opacity: 0.65;
    --noema-green-darker: #5E9644;                  /* pressed / active green */
    --noema-focus-ring: rgba(126, 192, 98, 0.25);   /* green focus glow (replaces Bootstrap blue) */
    --noema-valid-outline: #26b050;
    --noema-invalid-outline: #dc3545;
    --noema-validation-message: #dc3545;
    --noema-warning: #C77700;                       /* amber warning text/labels (readable on white) */

    /* Typography */
    --noema-font-sans: 'Open Sans', sans-serif;
    --noema-font-size-body: 0.9375rem;   /* 15px */
    --noema-font-size-small: 0.875rem;     /* 14px */
    --noema-font-size-nav: 0.9rem;
    --noema-font-size-brand: 1.1rem;
    --noema-font-size-modal-title: 1.25rem;
    --noema-line-height-body: 1.5;
    --noema-heading-size-section: 3rem;  /* 48px */
    --noema-heading-size-card: 1.5rem;   /* 24px */
    --noema-heading-weight: 700;

    /* Spacing scale (rem) — use these instead of raw rem values */
    --noema-rem-3xs: 0.25rem;
    --noema-rem-2xs: 0.35rem;
    --noema-rem-xs: 0.5rem;
    --noema-rem-sm: 0.6rem;
    --noema-rem-md: 0.75rem;
    --noema-rem-lg: 1rem;
    --noema-rem-xl: 1.25rem;
    --noema-rem-2xl: 1.5rem;
    --noema-rem-3xl: 2rem;
    --noema-rem-4xl: 2.5rem;
    --noema-rem-5xl: 3rem;
    --noema-rem-6xl: 3.5rem;
    --noema-rem-7xl: 5rem;
    --noema-rem-content: 1.1rem;
    --noema-rem-brand-max: 12rem;

    /* Size scale (px) — use these instead of raw px values */
    --noema-px-1: 1px;
    --noema-px-2: 2px;
    --noema-px-3: 3px;
    --noema-px-4: 4px;
    --noema-px-5: 5px;
    --noema-px-10: 10px;
    --noema-px-12: 12px;
    --noema-px-150: 150px;

    /* Breakpoints. A custom property cannot be read inside an @media condition, so each query still
       spells the number out; these declarations are the one place that says what the numbers mean,
       and every query that uses one names the token in a comment.
         --noema-breakpoint-nav     641px  nav collapses into the burger menu (MainLayout, NavMenu)
         --noema-breakpoint-mobile  768px  phone layout: page actions stack, dialogs go full-bleed,
                                           and Radzen's own card-layout query for a responsive grid
         --noema-breakpoint-cards   480px  ViewerContext's RadzenMediaQuery turns grids into cards */
    --noema-breakpoint-nav: 641px;
    --noema-breakpoint-mobile: 768px;
    --noema-breakpoint-cards: 480px;
    --noema-topbar-height: var(--noema-rem-6xl);
    --noema-footer-min-height: var(--noema-rem-5xl);
    --noema-radius: var(--noema-px-4);
    --noema-content-padding-top: var(--noema-rem-content);
    --noema-section-gap: var(--noema-rem-3xl);
    --noema-divider-width: var(--noema-px-1);
    --noema-divider-title-width: var(--noema-px-150);

    /* Motion */
    --noema-transition: color 0.2s ease, border-color 0.2s ease, background-color 0.2s ease;
}

html, body {
    font-family: var(--noema-font-sans);
    font-size: var(--noema-font-size-body);
    line-height: var(--noema-line-height-body);
    color: var(--noema-body);
}

a, .btn-link {
    color: var(--noema-link);
    transition: var(--noema-transition);
}

a:hover, .btn-link:hover {
    color: var(--noema-link-hover);
}

/* Primary / success (noema green) */
.btn-primary, .btn-success {
    color: var(--noema-white);
    background-color: var(--noema-btn-primary-bg);
    border-color: var(--noema-btn-primary-border);
    transition: var(--noema-transition);
}

.btn-primary:hover, .btn-success:hover {
    background-color: var(--noema-btn-primary-hover-bg);
    border-color: var(--noema-btn-primary-hover-border);
    color: var(--noema-white);
}

.btn-primary:disabled, .btn-success:disabled {
    background-color: var(--noema-btn-disabled-bg);
    border-color: var(--noema-btn-disabled-border);
    color: var(--noema-white);
    opacity: var(--noema-btn-disabled-opacity);
    cursor: not-allowed;
}

.btn-outline-primary, .btn-outline-success {
    color: var(--noema-btn-primary-bg);
    border-color: var(--noema-btn-primary-border);
    background-color: transparent;
    transition: var(--noema-transition);
}

.btn-outline-primary:hover, .btn-outline-success:hover {
    color: var(--noema-white);
    background-color: var(--noema-btn-primary-hover-bg);
    border-color: var(--noema-btn-primary-hover-border);
}

/* Danger */
.btn-danger {
    color: var(--noema-white);
    background-color: var(--noema-btn-danger-bg);
    border-color: var(--noema-btn-danger-border);
    transition: var(--noema-transition);
}

.btn-danger:hover {
    background-color: var(--noema-btn-danger-hover-bg);
    border-color: var(--noema-btn-danger-hover-border);
    color: var(--noema-white);
}

.btn-outline-danger {
    color: var(--noema-btn-danger-bg);
    border-color: var(--noema-btn-danger-border);
    background-color: transparent;
    transition: var(--noema-transition);
}

.btn-outline-danger:hover {
    color: var(--noema-white);
    background-color: var(--noema-btn-danger-hover-bg);
    border-color: var(--noema-btn-danger-hover-border);
}

/* Section heading (noema.tech style) */
h1, .noema-heading-section {
    font-size: var(--noema-heading-size-section);
    font-weight: var(--noema-heading-weight);
    color: var(--noema-heading);
    margin-top: 0;
    margin-bottom: var(--noema-section-gap);
}

/* Card-style title */
.noema-heading-card {
    font-size: var(--noema-heading-size-card);
    font-weight: var(--noema-heading-weight);
    color: var(--noema-heading);
    margin-bottom: var(--noema-rem-md);
}

.noema-divider-title {
    width: var(--noema-divider-title-width);
    height: var(--noema-divider-width);
    background-color: var(--noema-divider);
    margin-bottom: var(--noema-rem-lg);
}

.content {
    padding-top: var(--noema-content-padding-top);
    background-color: var(--noema-bg-content);
}

.valid.modified:not([type=checkbox]) {
    outline: var(--noema-px-1) solid var(--noema-valid-outline);
}

.invalid {
    outline: var(--noema-px-1) solid var(--noema-invalid-outline);
}

.validation-message {
    color: var(--noema-validation-message);
}

#blazor-error-ui {
    background: var(--noema-bg-light);
    border-top: var(--noema-divider-width) solid var(--noema-border);
    bottom: 0;
    box-shadow: 0 calc(-1 * var(--noema-px-1)) var(--noema-px-2) rgba(0, 0, 0, 0.2);
    display: none;
    left: 0;
    padding: var(--noema-rem-sm) var(--noema-rem-xl) var(--noema-rem-sm) var(--noema-rem-xl);
    position: fixed;
    width: 100%;
    z-index: 1000;
}

#blazor-error-ui .dismiss {
    cursor: pointer;
    position: absolute;
    right: var(--noema-rem-md);
    top: var(--noema-rem-xs);
}

.blazored-toast-container,
body > .blazored-toast-container,
.blazored-toast-container.position-bottomright,
.blazored-toast-container.position-bottomleft,
.blazored-toast-container.position-topright,
.blazored-toast-container.position-topleft {
    position: fixed !important;
    z-index: 2147483000 !important;
}

.btn-cursor-pointer {
    cursor: pointer;
}

/* Radzen — use noema variables where applicable */
.rz-state-highlight a,
.rz-state-highlight a:hover {
    color: var(--noema-white);
}

/* Radzen success button (green) — use noema variables */
.rz-button.rz-success,
.rz-button.rz-button-success,
.rz-button[data-style="success"] {
    color: var(--noema-white);
    background-color: var(--noema-btn-primary-bg);
    border-color: var(--noema-btn-primary-border);
    transition: var(--noema-transition);
}

.rz-button.rz-success:hover,
.rz-button.rz-button-success:hover,
.rz-button[data-style="success"]:hover {
    background-color: var(--noema-btn-primary-hover-bg);
    border-color: var(--noema-btn-primary-hover-border);
    color: var(--noema-white);
}

/* Radzen data grid header (noema dark bar feel) */
.rz-datatable .rz-datatable-thead > tr > th {
    background-color: var(--noema-bar-bg);
    color: var(--noema-text-on-dark);
    font-weight: var(--noema-heading-weight);
    border-color: var(--noema-border);
}

/* Keep a grid's width-less columns readable on a narrow viewport.

   Radzen renders every grid with `table-layout: fixed`. There the columns that declare a Width are
   served first and the ones that don't split what is left over, so the narrower the viewport the
   less those columns get — down to nothing once the declared widths alone fill it. Blink stops at
   the column's own min-width; WebKit ignores min-width on `col`, `th` and `td` alike and takes them
   to zero, which is how five columns went missing on an iPhone in landscape.

   A floor on the table is honoured by both engines, and it is what the columns are then divided out
   of, so each width-less column keeps 150px and the grid's own scroller takes over sideways. It
   binds only while the viewport is narrow: above it the table is wider anyway and the division is
   untouched, so a full-width desktop grid renders exactly as it would without this rule.

   A grid opts in with `grid-column-floor` and reports its own two numbers, because neither is
   knowable from CSS — and both can move at runtime, as columns come and go with the data or the
   viewer's role:

       class="… grid-column-floor" Style="--grid-sized-columns: 810px; --grid-unsized-columns: 5"

   Excluded in card mode: there are no columns to divide there, and a floor would only push the card
   past the screen edge and stop its long values wrapping. */
.grid-column-floor.rz-datatable:not(.rz-datatable-reflow) .rz-grid-table {
    min-width: calc(var(--grid-sized-columns) + var(--grid-unsized-columns) * 150px);
}

/* Radzen breadcrumb links */
.rz-breadcrumb .rz-link {
    color: var(--noema-body);
    transition: var(--noema-transition);
}

.rz-breadcrumb .rz-link:hover {
    color: var(--noema-link);
}

/* Radzen fieldset legend (card-style title) */
.rz-fieldset-legend {
    font-size: var(--noema-heading-size-card);
    font-weight: var(--noema-heading-weight);
    color: var(--noema-heading);
}

/* Blazored modal — ensure overlay sits above the sticky top-bar (z-index: 100) */
.bm-container {
    z-index: 200 !important;
}

/* Blazored modal — header and content (project uses blazored-modal for overlay/container) */
.blazored-modal {
    margin-top: var(--noema-rem-7xl) !important;
    padding: 0 !important;
    border: 0 !important;
}

.bm-content {
    border-radius: var(--noema-radius);
    padding: var(--noema-rem-2xl);
}

.bm-header {
    align-items: center !important;
    padding: var(--noema-rem-lg) var(--noema-rem-xl) !important;
    margin-bottom: var(--noema-rem-lg);
    background-color: var(--noema-bar-bg);
    color: var(--noema-text-on-dark);
}

/* Title and close must be light — override Bootstrap/global heading color */
.bm-header .bm-title {
    color: var(--noema-white);
    margin: 0;
    padding: 0;
    font-size: var(--noema-font-size-modal-title);
}

.bm-close {
    color: var(--noema-white);
    background: transparent;
    border: none;
    padding: var(--noema-rem-3xs);
    margin: 0;
    transition: var(--noema-transition);
}

.bm-close:hover {
    color: var(--noema-green);
}

.bm-close:focus {
    border: none;
    outline: none;
}

/* --- Identity layout (login / account pages) — noema.tech aligned --- */
.identity-layout {
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    background-color: var(--noema-bg-light);
}

.identity-header {
    flex-shrink: 0;
}

.identity-nav {
    background-color: var(--noema-bar-bg);
    padding: var(--noema-rem-md) 0;
}

.identity-nav__container {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
}

.identity-nav__brand {
    font-family: var(--noema-font-sans);
    font-size: var(--noema-font-size-brand);
    font-weight: var(--noema-heading-weight);
    color: var(--noema-white);
    text-decoration: none;
    transition: var(--noema-transition);
}

.identity-nav__brand:hover {
    color: var(--noema-green);
}

.identity-nav__toggler {
    border-color: var(--noema-text-muted);
}

.identity-nav__toggler .navbar-toggler-icon {
    background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba(255, 255, 255, 0.8)' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");
}

.identity-nav .nav-link,
.identity-nav .navbar-nav .btn-link {
    color: var(--noema-white);
    transition: var(--noema-transition);
}

.identity-nav .nav-link:hover,
.identity-nav .navbar-nav .btn-link:hover {
    color: var(--noema-green);
}

.identity-nav .text-dark {
    color: var(--noema-white);
}

.identity-main {
    flex: 1;
    padding-top: var(--noema-rem-5xl);
    padding-bottom: var(--noema-rem-5xl);
}

.identity-main__content {
    max-width: 28rem;
    margin-left: auto;
    margin-right: auto;
}

.identity-footer {
    flex-shrink: 0;
    background-color: var(--noema-footer-bg);
    color: var(--noema-text-muted);
    font-size: var(--noema-font-size-small);
    padding: var(--noema-rem-lg) 0;
    text-align: center;
}

/* --- Login page (BEM) --- */
.login-page {
    background-color: var(--noema-bg-content);
    border-radius: var(--noema-radius);
    box-shadow: 0 var(--noema-px-2) var(--noema-px-10) rgba(0, 0, 0, 0.08);
    padding: var(--noema-rem-3xl);
}

.login-page__title {
    font-size: var(--noema-heading-size-card);
    font-weight: var(--noema-heading-weight);
    color: var(--noema-heading);
    margin: 0 0 var(--noema-rem-xl) 0;
    padding-bottom: var(--noema-rem-md);
    border-bottom: var(--noema-divider-width) solid var(--noema-border);
    width: 100%;
}

.login-form__group {
    margin-bottom: var(--noema-rem-xl);
}

.login-form__label {
    display: block;
    font-size: var(--noema-font-size-small);
    font-weight: 600;
    color: var(--noema-heading);
    margin-bottom: var(--noema-rem-xs);
}

.login-form__input {
    display: block;
    width: 100%;
    padding: var(--noema-rem-sm) var(--noema-rem-md);
    font-family: var(--noema-font-sans);
    font-size: var(--noema-font-size-body);
    color: var(--noema-body);
    background-color: var(--noema-bg-content);
    border: var(--noema-px-1) solid var(--noema-border);
    border-radius: var(--noema-radius);
    transition: var(--noema-transition);
}

.login-form__input:focus {
    outline: none;
    border-color: var(--noema-green);
    box-shadow: 0 0 0 var(--noema-px-2) var(--noema-green-light);
}

.login-form__input::placeholder {
    color: var(--noema-text-muted);
}

.login-form__error {
    font-size: var(--noema-font-size-small);
    color: var(--noema-validation-message);
    margin-top: var(--noema-rem-xs);
}

.login-form__row {
    display: flex;
    align-items: center;
    margin-bottom: var(--noema-rem-xl);
    min-height: 1.25rem;
}

.login-form__checkbox {
    width: 1rem;
    height: 1rem;
    margin: 0 var(--noema-rem-xs) 0 0;
    flex-shrink: 0;
    accent-color: var(--noema-green);
    align-self: center;
}

.login-form__checkbox-label {
    font-size: var(--noema-font-size-small);
    color: var(--noema-body);
    cursor: pointer;
    line-height: 1rem;
    padding-top: 0.125rem;
    margin-bottom: 0;
}

.login-form__submit {
    width: 100%;
    padding: var(--noema-rem-md) var(--noema-rem-xl);
    font-family: var(--noema-font-sans);
    font-size: var(--noema-font-size-body);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.02em;
    color: var(--noema-white);
    background-color: var(--noema-btn-primary-bg);
    border: var(--noema-px-1) solid var(--noema-btn-primary-border);
    border-radius: var(--noema-radius);
    cursor: pointer;
    transition: var(--noema-transition);
}

.login-form__submit:hover {
    background-color: var(--noema-btn-primary-hover-bg);
    border-color: var(--noema-btn-primary-hover-border);
}

.login-form__submit:focus {
    outline: none;
    box-shadow: 0 0 0 var(--noema-px-2) var(--noema-green-light);
}

.login-form > .login-form__error:first-child {
    margin-bottom: var(--noema-rem-md);
}

/* Password input with an inline show/hide eye toggle (used on the Change Password page). */
.password-field {
    position: relative;
    display: flex;
    align-items: center;
}

.password-field__input {
    padding-right: 2.75rem;
}

.password-field__toggle {
    position: absolute;
    right: var(--noema-rem-sm);
    top: 50%;
    transform: translateY(-50%);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    line-height: 0;
    background: none;
    border: none;
    padding: var(--noema-rem-3xs);
    color: var(--noema-text-muted);
    cursor: pointer;
    transition: var(--noema-transition);
}

.password-field__toggle:hover {
    color: var(--noema-green);
}

.password-field__toggle:focus-visible {
    outline: var(--noema-px-2) solid var(--noema-focus-ring);
    outline-offset: var(--noema-px-2);
    border-radius: var(--noema-radius);
}

/* --- UI Polish: table & dialog utilities --- */
.dropdown-truncate {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    display: block;
    max-width: 100%;
}

/* Ensure Radzen dropdown items constrain width so truncation works */
.rz-dropdown-panel .rz-dropdown-item,
.rz-dropdown-panel .rz-multiselect-item {
    overflow: hidden;
    text-overflow: ellipsis;
}

/* In a Multiple dropdown's collapsed label the selected items render inline,
   joined by the separator; block display would stack them and hide all but
   the first selected customer (NOEMAPP-1898). */
.rz-dropdown-label .dropdown-truncate,
.rz-multiselect-label .dropdown-truncate {
    display: inline;
}

.filter-active-indicator {
    display: inline-block;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background-color: var(--noema-green);
    margin-left: 4px;
    flex-shrink: 0;
}

.truncate-cell {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    display: block;
    max-width: 100%;
}

/* Long read-only values in a grid cell (license key, comments). These used to render as a disabled
   RadzenTextArea with Rows="3": a form control for a value nobody edits, which meant a grey box
   with its own inner scrollbar — unreadable in a mobile card, where it competes with the card's
   own scroll. Plain text instead.

   A clamp hides the tail behind the title attribute, which is unreachable on touch — so only put
   .value-clamp on a value that also has a copy button beside it (the license key: a ~600-char JWT
   that is copied, not read). .value-clamp-desktop is the weaker form for values that only need
   taming inside a table row, where a hover tooltip is available. */
.value-block {
    white-space: pre-wrap;
    word-break: break-all;
}

.value-clamp,
.value-clamp-desktop {
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

/* --noema-breakpoint-mobile */
@media (max-width: 768px) {
    .value-clamp {
        -webkit-line-clamp: 2;
    }

    /* In card layout there are no row heights to keep even, so show these in full. */
    .value-clamp-desktop {
        display: block;
        overflow: visible;
    }
}

/* Row of icon buttons inside a grid cell (copy / delete). Sitting next to each other with only an
   icon's own padding between them, copy and delete read as one control and are easy to mis-tap —
   especially on a phone, where .btn-cursor-pointer also grows each icon to a 44px touch target. */
.cell-actions {
    display: flex;
    align-items: center;
    gap: var(--noema-rem-lg);
}

/* Long identifiers in a page title (purchase GUIDs) wrap into three ragged lines at phone width
   and push the actions below the fold. Keep the human-readable part on its own line and drop the
   id underneath, smaller and muted, breaking anywhere so it never widens the page. */
.page-title-id {
    display: block;
    margin-top: var(--noema-rem-3xs);
    font-size: 0.55em;
    color: var(--noema-body-alt);
    word-break: break-all;
}

/* Narrow-viewport layout — --noema-breakpoint-mobile. The boundary is 768px because that is where
   Radzen switches a Responsive grid to card layout (hardcoded in its stylesheet) and where the page
   action bars stack; keeping the dialogs on the older 641px value left the 641–768px band with
   stacked page buttons but desktop-padded dialogs. The nav collapses on its own, narrower boundary
   (--noema-breakpoint-nav). */
@media (max-width: 768px) {
    /* Modal: at this width the dialog spans nearly the whole viewport, so it sat on the screen edge
       with its corners cut off and could grow taller than the screen (the page scrolled behind the
       overlay instead of the dialog scrolling). Give it a gutter and cap it to the viewport so the
       body scrolls inside while header and footer stay put. Blazored's own scoped rule already sets
       display/flex-direction/border-radius. */
    .blazored-modal {
        margin: var(--noema-rem-lg) var(--noema-rem-md) !important;
        width: auto !important;
        max-width: none !important;
        max-height: calc(100vh - 2 * var(--noema-rem-lg));
        max-height: calc(100dvh - 2 * var(--noema-rem-lg));
        overflow: hidden;
    }

    /* Modal content: reduce padding on mobile; it is the part that scrolls. */
    .bm-content {
        padding: var(--noema-rem-md);
        flex: 1 1 auto;
        overflow-y: auto;
    }

    .bm-header {
        flex: 0 0 auto;
    }

    /* Modal forms are wrapped in a RadzenFieldset. Its border draws a second frame just inside the
       dialog's own edge and its 20px content padding eats a fifth of a 375px screen — flatten it
       and let .bm-content own the padding. Only the first fieldset: GenerateSingleLicenseComponent
       puts its generated output in further fieldsets, where the border is the only thing separating
       the result from the form above it. */
    .blazored-modal .rz-fieldset:first-of-type {
        border: 0;
        padding: 0;
        margin: 0;
    }

    .blazored-modal .rz-fieldset:first-of-type > .rz-fieldset-content {
        padding: 0;
    }

    /* Stacked label/input pairs inherited the 16px row gap, so the gap between a label and its own
       input equalled the gap between fields and the pairs stopped reading as pairs. */
    .blazored-modal .rz-row {
        row-gap: var(--noema-rem-3xs);
    }

    /* Some form controls carry rz-w-100 in the markup and some don't, which on a stacked phone
       layout shows up as a ragged column of half-width inputs (Max Installations, Customer name,
       Project number, …). Stretch every text-entry control to its column; switches, checkboxes and
       buttons keep their intrinsic size. */
    .blazored-modal [class*="rz-col"] > .rz-textbox,
    .blazored-modal [class*="rz-col"] > .rz-textarea,
    .blazored-modal [class*="rz-col"] > .rz-numeric,
    .blazored-modal [class*="rz-col"] > .rz-dropdown,
    .blazored-modal [class*="rz-col"] > .rz-multiselect,
    .blazored-modal [class*="rz-col"] > .rz-datepicker,
    .blazored-modal [class*="rz-col"] > .rz-password {
        width: 100%;
        max-width: 100%;
    }

    /* Password fields put a visibility toggle next to the input, which shortens the input and
       leaves the icon floating by the dialog edge. Move the icon inside the field instead. */
    .blazored-modal [class*="rz-col"]:has(> .rz-textbox + .rzi) {
        position: relative;
    }

    .blazored-modal [class*="rz-col"] > .rz-textbox:has(+ .rzi) {
        margin-inline-end: 0 !important;
        padding-inline-end: var(--noema-rem-3xl);
    }

    .blazored-modal [class*="rz-col"] > .rz-textbox + .rzi {
        position: absolute;
        inset-inline-end: var(--noema-rem-xs);
        top: 50%;
        transform: translateY(-50%);
    }

    /* Modal header: tighter padding on mobile */
    .bm-header {
        padding: var(--noema-rem-md) var(--noema-rem-lg) !important;
    }

    /* Close button: larger touch target (min 44px) */
    .bm-close {
        padding: var(--noema-rem-sm);
        min-width: 44px;
        min-height: 44px;
        display: flex;
        align-items: center;
        justify-content: center;
    }

    /* Action icons: larger touch targets. The class lands either on RadzenIcon's own <i class="rzi">
       or on the <span> CopyButton wraps around one, so match the class itself rather than .rz-icon,
       which no Radzen component renders. */
    .btn-cursor-pointer {
        min-width: 44px;
        min-height: 44px;
        display: inline-flex;
        align-items: center;
        justify-content: center;
    }

    /* Breadcrumb: truncate long GUIDs */
    .rz-breadcrumb .rz-breadcrumb-item {
        max-width: 120px;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    /* Form inputs: full width on mobile (Radzen columns) */
    .blazored-modal .rz-row > [class*="rz-col"] {
        flex: 0 0 100%;
        max-width: 100%;
    }

    /* Form labels: small bottom margin when stacked */
    .blazored-modal .rz-row > [class*="rz-col-md-3"],
    .blazored-modal .rz-row > [class*="rz-col-lg-3"] {
        margin-bottom: var(--noema-rem-3xs);
    }
}

/* Card layout of RadzenDataGrid (Responsive="true"): each row renders as a stack of label/value
   pairs — `<td><span class="rz-column-title">Label</span><span class="rz-cell-data">value</span></td>`.
   Radzen marks a responsive grid with .rz-datatable-reflow at all widths and switches the card
   layout on inside a `@media (max-width: 768px)` block hardcoded in its own stylesheet (there is no
   parameter for it on the grid), so these rules repeat that media query — without it they would
   also hit the desktop table, where the labels are hidden and every blank cell would grow a dash.
   That is why --noema-breakpoint-mobile is 768px too: a Radzen upgrade moving its query has to be
   mirrored in the token and everywhere the token's value is spelled out. */
@media (max-width: 768px) {
    /* In card layout the grid's own frame is a second, rounded outline around the stack of cards:
       its corners cut across the card borders below and the two radii never line up. The cards
       carry the structure here, so drop the wrapper's frame and let them sit on the page.
       Two classes on purpose: the frame comes from Radzen's .rz-datatable rule, and site.css is
       linked before Radzen's default.css, so a single-class selector would tie on specificity and
       lose on source order. */
    .rz-data-grid.rz-datatable-reflow {
        border: 0;
        background: transparent;
    }

    /* One row = one card. Radzen only tints alternate rows, so two neighbouring cards run together
       — the tint alone doesn't say where a record ends, and it carries no meaning for anyone who
       can't tell the two shades apart. Give every card its own outline and a gap between them. */
    .rz-datatable-reflow .rz-data-row {
        margin-bottom: var(--noema-rem-xs);
        border: 1px solid var(--noema-border);
        border-radius: var(--noema-radius);
        overflow: hidden;
    }

    /* Radzen styles the in-card label exactly like the value (same size, weight and color), so the
       pairs blur into one another — bold, smaller and secondary-colored makes a card read as a list
       of fields. No --rz-* variable drives this (the --rz-grid-header-* tokens only reach thead),
       so a selector rule is unavoidable here. */
    .rz-datatable-reflow .rz-data-row > td > .rz-column-title {
        font-weight: 700;
        font-size: var(--rz-text-caption-font-size);
        line-height: 1.2;
        color: var(--rz-text-secondary-color);
        margin-bottom: var(--noema-px-2);
    }

    /* Radzen truncates every cell to a single ellipsised line (and .truncate-cell does the same for
       templated ones) to keep table columns aligned. A card has no columns to align, so all that
       does is hide the tail of a device id or a MAC with no way to read or select it on a phone.
       Let the values wrap; the ones that would run for dozens of lines carry .value-clamp. */
    .rz-datatable-reflow .rz-data-row > td > .rz-cell-data,
    .rz-datatable-reflow .rz-data-row .truncate-cell {
        white-space: normal;
        overflow: visible;
        text-overflow: clip;
        overflow-wrap: anywhere;
    }

    /* An empty column leaves a label with nothing under it, which reads as a rendering glitch —
       show an em dash instead. :empty matches the value span only when it has no child nodes at all
       (null/empty property, or a Template that rendered nothing); a whitespace-only value is a text
       node and keeps rendering as blank. Column templates that wrap the value in .truncate-cell
       keep .rz-cell-data non-empty, so that wrapper gets the same treatment. */
    .rz-datatable-reflow .rz-data-row > td > .rz-cell-data:empty::after,
    .rz-datatable-reflow .rz-data-row > td > .rz-cell-data > .truncate-cell:empty::after,
    .rz-datatable-reflow .rz-data-row > td > .rz-cell-data > .value-block:empty::after {
        content: "—";
        /* Secondary, not tertiary: the tertiary grey is ~3.6:1 on white, below the WCAG AA 4.5:1
           this dash has to meet as the only content of the field. */
        color: var(--rz-text-secondary-color);
    }

    /* Columns declared Frozen="true" keep their sticky positioning, side borders, opaque background
       and edge shadow in card layout, where there is nothing to freeze against — they show up as
       grey bands with stray vertical rules crossing the middle of a card. The ::before/::after
       overlays exist only to paint the frozen column over scrolled content, so they go too. */
    .rz-datatable-reflow .rz-data-row > td.rz-frozen-cell {
        position: static;
        background: transparent;
        box-shadow: none;
        /* Radzen sets the side borders with !important (.rz-grid-table-fixed .rz-frozen-cell-*),
           so matching it is the only way to drop them. */
        border-inline: 0 !important;
    }

    .rz-datatable-reflow .rz-data-row > td.rz-frozen-cell::before,
    .rz-datatable-reflow .rz-data-row > td.rz-frozen-cell::after {
        display: none;
    }

    /* Radzen's card layout converts the header and the body and leaves the footer a real table row,
       so a grid with column totals keeps the whole column grid alive down there: the cells that
       hold no total still claim their width, and the row ends up wider than the screen and drags a
       horizontal scrollbar under the cards. Stack it like everything else and drop the cells with
       nothing in them, so the totals read as a short list under the last card. */
    .rz-datatable-reflow tfoot,
    .rz-datatable-reflow tfoot > tr,
    .rz-datatable-reflow tfoot > tr > td {
        display: block;
    }

    /* The column's width is written onto the cell as an inline style and survives the switch to a
       block, which would keep each total boxed at its column's width. Only !important outranks an
       inline declaration — this is the same line Radzen uses on the body cells one rule above, for
       the same reason. And Radzen ellipsises a footer to a single line to keep table rows aligned,
       which in a stack only hides the label. */
    .rz-datatable-reflow tfoot > tr > td {
        width: 100% !important;
        /* A column centred for its table (Activated Instances) would leave one total centred and
           the next left in the stack. */
        text-align: left !important;
    }

    .rz-datatable-reflow tfoot .rz-column-footer {
        white-space: normal;
        overflow: visible;
        text-overflow: clip;
    }

    /* Radzen fills every footer cell with a `.rz-column-footer` span whether or not the column
       declared a total, so the cell is never `:empty` — match on the span instead, or the two real
       totals arrive under five blank lines. */
    .rz-datatable-reflow tfoot > tr > td:has(> .rz-column-footer:empty) {
        display: none;
    }

    /* Stacked, the totals lose the column heading that told them apart, so each footer may name
       what it counts. */
    .rz-datatable-reflow tfoot .footer-scope {
        display: inline;
    }
}

/* A grid footer can name what it counts for the card layout, where the column heading is gone. In
   the table the heading is right above the figure, and the column is only as wide as the figure
   needs, so the extra word stays out of it. */
.footer-scope {
    display: none;
}

/* Short-viewport density.

   A phone held sideways is only ~390px tall, and the chrome above a list — bar, breadcrumb, title,
   action buttons — is sized for a screen several times that. On the licence list it added up to
   more than the whole viewport, so the page opened on nothing but its own headings and the list
   read as empty until scrolled.

   Tighten that chrome once the viewport is short. Height alone decides it: a short window on a
   desktop wants the same thing, and none of it costs anything at that size. Only the space above a
   list is bought back — the list itself is untouched.

   The layout's own bands and the action bar are scoped to their components, whose stylesheet is
   linked after this file, so their share of this lives in MainLayout.razor.css and
   PageActions.razor.css. Keep the three in step. */
@media (max-height: 500px) {
    /* Qualified by the page container to outrank Radzen's own bare `h1` rule, which is linked after
       this file and would otherwise win on source order at equal specificity. */
    .content h1, .content .noema-heading-section {
        font-size: var(--noema-heading-size-card);
        margin-bottom: var(--noema-rem-xs);
    }

    .content {
        padding-top: var(--noema-rem-xs);
    }
}

/* Deactivated customers are rendered gray (but never hidden) across the UI. NOEMAPP-1717.
   Applies to inline labels/dropdown items (.customer-inactive span) as well as whole grid rows.
   Grid rows are marked with a data-inactive attribute (RadzenDataGrid RowRender) rather than a
   class, so Radzen keeps its own row classes (rz-data-row / rz-state-highlight) and selection +
   hover stay visible; the cells still inherit the muted text color here. */
.customer-inactive,
tr[data-inactive] td {
    color: var(--noema-text-inactive) !important;
}

/* When a deactivated row is selected, the muted grey above is unreadable on the green
   selection background — use the normal selected-row text color (white) for contrast,
   matching active selected rows. Higher specificity than the rule above so it wins. */
tr[data-inactive].rz-state-highlight td {
    color: var(--rz-grid-selected-color) !important;
}

/* "Deactivated" status badge keeps its own readable (white-on-grey) text even though the
   inactive-row rule above mutes cell text with !important. Sized below the row text. */
.rz-badge.customer-status-badge {
    color: var(--noema-white) !important;
    font-size: 0.6rem;
    font-weight: 600;
    line-height: 1.1;
    letter-spacing: 0.02em;
    padding: 0.1rem 0.4rem;
    vertical-align: middle;
}

/* Disable hover styles on touch devices */
@media (hover: none) {
    .bm-close:hover {
        color: var(--noema-white);
    }
}

/* Noema layout utilities — for the few Bootstrap utility classes that have no direct Radzen
   (rz-*) equivalent, used when migrating .razor layout off Bootstrap. */
.noema-mw-100 { max-width: 100% !important; }
.noema-align-self-center { align-self: center !important; }
.noema-align-self-baseline { align-self: baseline !important; }
