/* =====================================================================================
   ESG Service Catalog — custom dark theme.
   - Brand tokens are derived from the logo + docs/07-design-system.md.
   - Loaded AFTER Radzen's own theme stylesheet so the variable overrides win.
   - All numeric values are tweakable here — components consume tokens, not raw colours.
   =====================================================================================*/

:root {
    /* ---- Brand colours (from the ESG logo) ---- */
    --esg-ink:        #161616;   /* near-black, used in logo frame */
    --esg-paper:      #F2F2F2;
    --esg-accent:     #335B7F;   /* logo steel/navy blue */
    --esg-accent-2:   #304878;
    --esg-accent-soft:#4f7fb0;   /* lightened for contrast on dark backgrounds */

    /* ---- Dark UI palette (derived around the brand tokens) ---- */
    --esg-bg:         #0c1119;
    --esg-bg2:        #0f1620;
    --esg-surface:    #141c28;
    --esg-surface-2:  #1a2533;
    --esg-line:       #26323f;
    --esg-text:       #eaf0f7;
    --esg-muted:      #90a0b5;

    /* ---- Semantic ---- */
    --esg-ok:         #57b894;
    --esg-warn:       #e0a04a;
    --esg-danger:     #d9534f;
}

/* =====================================================================================
   Map ESG tokens onto Radzen CSS variables.
   We override the bundled Material-Dark base — only the tokens that change.
   ===================================================================================== */
:root {
    --rz-primary:                       var(--esg-accent-soft);
    --rz-primary-light:                 var(--esg-accent-soft);
    --rz-primary-dark:                  var(--esg-accent);
    --rz-on-primary:                    var(--esg-ink);

    --rz-secondary:                     var(--esg-accent-2);
    --rz-secondary-dark:                var(--esg-accent-2);

    --rz-body-background-color:         var(--esg-bg);
    --rz-text-color:                    var(--esg-text);
    --rz-text-secondary-color:          var(--esg-muted);
    /* Radzen's `--rz-text-tertiary-color` is the colour for input placeholders
       (see `--rz-input-placeholder-color: var(--rz-text-tertiary-color)`). The
       Radzen default points at `--rz-base-200`, but we re-map that to
       `--esg-bg2` (#0f1620) further down — which left placeholders effectively
       invisible against the dark surface. Pin it to a dimmer-than-secondary
       grey so placeholders are legible without competing with real values. */
    --rz-text-tertiary-color:           #6e7d8c;

    --rz-base-100:                      var(--esg-bg);
    --rz-base-200:                      var(--esg-bg2);
    --rz-base-300:                      var(--esg-surface);
    --rz-base-400:                      var(--esg-surface-2);
    --rz-base-500:                      var(--esg-line);

    --rz-content-background-color:      var(--esg-bg);
    --rz-panel-background-color:        var(--esg-surface);
    --rz-card-background-color:         var(--esg-surface);
    --rz-card-border:                   1px solid var(--esg-line);
    --rz-border:                        1px solid var(--esg-line);

    --rz-success:                       var(--esg-ok);
    --rz-warning:                       var(--esg-warn);
    --rz-danger:                        var(--esg-danger);
    --rz-info:                          var(--esg-accent-soft);
}

/* =====================================================================================
   Typography
   - Material 3 ships with Roboto (variable Roboto Flex) bundled in wwwroot/fonts. We
     don't override font-family here — let --rz-text-font-family from the theme own it.
   - Only tune background, smoothing + heading weights.
   ===================================================================================== */
html, body {
    background: var(--esg-bg);
    color: var(--esg-text);
    margin: 0;
    -webkit-font-smoothing: antialiased;
    line-height: 1.5;
    /* Defensive: no element should be able to push the viewport horizontally on small
       screens. Vertical scroll is opt-in per-layout below (app-shell on desktop, native
       body scroll on mobile via EmptyLayout / content-wrap defaults). */
    overflow-x: hidden;
}

h1, h2, h3, .esg-display {
    /* font-family inherited from --rz-text-font-family (Roboto) */
    font-weight: 700;
    letter-spacing: -0.02em;
    color: var(--esg-text);
    margin: 0;
}

h1 { font-size: 1.85rem; line-height: 1.15; }
h2 { font-size: 1.4rem;  line-height: 1.2;  font-weight: 600; }
h3 { font-size: 1.1rem;  line-height: 1.25; font-weight: 600; }

p {
    color: var(--esg-text);
}

small, .esg-muted {
    color: var(--esg-muted);
}

a {
    color: var(--esg-accent-soft);
    text-decoration: none;
}
a:hover {
    color: var(--esg-text);
    text-decoration: underline;
}

/* =====================================================================================
   Page chrome: header + sidebar + content
   ===================================================================================== */
.esg-page {
    min-height: 100vh;
    display: grid;
    grid-template-rows: auto 1fr;
    background:
        radial-gradient(900px 500px at 85% -10%, rgba(79, 127, 176, 0.10), transparent 60%),
        radial-gradient(700px 600px at -5% 10%, rgba(48, 72, 120, 0.30), transparent 55%),
        var(--esg-bg);
    background-attachment: fixed;
}

.esg-header {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 18px 28px;
    border-bottom: 1px solid var(--esg-line);
    background: rgba(12, 17, 25, 0.86);
    backdrop-filter: blur(10px);
    position: sticky;
    top: 0;
    z-index: 40;
}

.esg-header img.esg-logo {
    height: 36px;
    width: auto;
    flex: none;
}

.esg-brand {
    /* Inherits Roboto from the theme; we just tune weight + spacing. */
    font-weight: 600;
    font-size: 1.05rem;
    letter-spacing: 0.2px;
}

.esg-brand small {
    display: block;
    font-weight: 600;
    font-size: 0.65rem;
    letter-spacing: 4px;
    color: var(--esg-accent-soft);
    margin-top: 3px;
    text-transform: uppercase;
}

.esg-header-spacer {
    flex: 1;
}

.esg-header-actions {
    display: flex;
    gap: 10px;
    align-items: center;
}

.esg-content {
    padding: 28px 32px 80px;
    max-width: 1180px;
    margin: 0 auto;
    width: 100%;
}

/* =====================================================================================
   Cards / panels / tables — tone down the heavy Radzen defaults for our dark surface
   ===================================================================================== */
.rz-card {
    background: var(--esg-surface);
    border: 1px solid var(--esg-line);
    box-shadow: 0 1px 0 rgba(255, 255, 255, 0.02), 0 2px 12px rgba(0, 0, 0, 0.32);
}

.rz-data-grid, .rz-grid-table {
    background: var(--esg-surface);
    color: var(--esg-text);
}

.rz-button-primary {
    background: var(--esg-accent);
    border-color: var(--esg-accent);
    color: var(--esg-paper);
}
.rz-button-primary:hover {
    filter: brightness(1.1);
}

/* Subtle utility classes used by ESG pages */
.esg-card {
    background: var(--esg-surface);
    border: 1px solid var(--esg-line);
    border-radius: 12px;
    padding: 24px 28px;
}

.esg-row {
    display: flex;
    gap: 12px;
    flex-wrap: wrap;
}

.esg-mt-2 { margin-top: 12px; }
.esg-mt-3 { margin-top: 18px; }
.esg-mt-4 { margin-top: 28px; }

/* =====================================================================================
   Anchor buttons (.esg-button) — used for auth navigation where we semantically need an
   <a href>, not a <button>. Reset the link defaults (color, underline) and apply a real
   button look.
   ===================================================================================== */
a.esg-button,
a.esg-button:visited {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 10px 18px;
    border-radius: 8px;
    /* font-family inherited from --rz-text-font-family (Roboto) */
    font-weight: 600;
    font-size: 0.9rem;
    line-height: 1.2;
    letter-spacing: 0.01em;
    text-decoration: none;
    border: 1px solid var(--esg-accent);
    background: var(--esg-accent);
    color: var(--esg-paper);
    transition: filter 0.15s ease, background 0.15s ease, border-color 0.15s ease;
    cursor: pointer;
    user-select: none;
}
a.esg-button:hover {
    filter: brightness(1.12);
    text-decoration: none;
    color: var(--esg-paper);
}

/* Secondary / outline variant for less-prominent CTAs */
a.esg-button.esg-button-secondary,
a.esg-button.esg-button-secondary:visited {
    background: transparent;
    color: var(--esg-text);
    border-color: var(--esg-line);
}
a.esg-button.esg-button-secondary:hover {
    background: var(--esg-surface-2);
    border-color: var(--esg-accent-soft);
    color: var(--esg-text);
}

/* Small "ghost" button for header chrome (Anmelden / Abmelden link) */
a.esg-button.esg-button-ghost,
a.esg-button.esg-button-ghost:visited {
    padding: 6px 14px;
    font-size: 0.8rem;
    background: transparent;
    border-color: var(--esg-line);
    color: var(--esg-muted);
}
a.esg-button.esg-button-ghost:hover {
    border-color: var(--esg-accent-soft);
    color: var(--esg-text);
}

/* Submit / form buttons (<button class="esg-button">) — match the anchor variant exactly */
button.esg-button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 10px 18px;
    border-radius: 8px;
    font-weight: 600;
    font-size: 0.9rem;
    line-height: 1.2;
    letter-spacing: 0.01em;
    border: 1px solid var(--esg-accent);
    background: var(--esg-accent);
    color: var(--esg-paper);
    cursor: pointer;
    transition: filter 0.15s ease;
    font-family: inherit;
}
button.esg-button:hover {
    filter: brightness(1.12);
}
button.esg-button:disabled {
    opacity: 0.55;
    cursor: not-allowed;
    filter: none;
}

/* =====================================================================================
   Form inputs used inside <EditForm> on the auth pages.
   The Blazor <InputText> renders as a native <input class="esg-input">.
   ===================================================================================== */
.esg-input {
    display: block;
    width: 100%;
    padding: 9px 12px;
    border-radius: 8px;
    border: 1px solid var(--esg-line);
    background: var(--esg-surface-2);
    color: var(--esg-text);
    font-family: inherit;
    font-size: 0.95rem;
    line-height: 1.3;
    box-sizing: border-box;
    transition: border-color 0.12s ease, background 0.12s ease;
}
.esg-input:focus {
    outline: none;
    border-color: var(--esg-accent-soft);
    background: var(--esg-surface);
}
.esg-input.invalid,
.esg-input[aria-invalid="true"] {
    border-color: var(--esg-danger);
}

.esg-validation {
    display: block;
    color: var(--esg-danger);
    font-size: 0.78rem;
    margin-top: 4px;
}

/* =====================================================================================
   Responsive tweaks for the authenticated shell
   -----------------------------------------------------------------------------------
   Sidebar collapse + slide-in are handled by RadzenSidebarToggle (server-side state,
   sidebar Expanded binding) — nothing to do in CSS for that. The bits below tame the
   header + content on small viewports.
   ===================================================================================== */

/* Body content wrapper — always centred, never wider than 1180. */
.esg-content-wrap {
    max-width: 1180px;
    margin: 0 auto;
}

@media (max-width: 767.98px) {
    /* Logo + auth buttons are the only header chrome on small viewports. */
    .esg-brand-stack { display: none !important; }

    /* Long user names eat the header — truncate. */
    .esg-user-name {
        max-width: 7em;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    /* Cards / content should NOT carry desktop padding on mobile. */
    .esg-card { padding: 16px 18px; }
}

/* =====================================================================================
   Touch targets
   ===================================================================================== */

/* Minimum 44 px (Apple HIG, WCAG 2.5.5 Level AAA). Applies to all the small
   icon-actions in our grids without changing visual size on desktop — only
   the hit area grows. */
.rz-button.rz-button-icon-only,
a.esg-button,
button.esg-button {
    min-height: 44px;
    min-width: 44px;
}

/* RadzenPanelMenu items also need taller targets on touch. */
.rz-navigation-item-link,
.rz-panel-menu-item {
    min-height: 44px;
}

/* =====================================================================================
   Empty layout (anonymous auth pages)
   ===================================================================================== */

.esg-empty-layout {
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    overflow-x: hidden;  /* belt + braces; html, body already block horizontal overflow */
    background:
        radial-gradient(900px 500px at 85% -10%, rgba(79, 127, 176, 0.10), transparent 60%),
        radial-gradient(700px 600px at -5% 10%, rgba(48, 72, 120, 0.30), transparent 55%),
        var(--esg-bg);
}

@media (min-width: 768px) {
    /* On desktop the body is locked by the app-shell rules above; EmptyLayout becomes
       its own scroll container so long auth content (e.g. consent screen) is reachable. */
    .esg-empty-layout {
        height: 100%;
        min-height: 0;
        overflow-y: auto;
    }
}

.esg-empty-header {
    padding: 18px 28px;
    border-bottom: 1px solid var(--esg-line);
}

.esg-empty-header a {
    /* The brand link is an inline-flex row with logo + wordmark. On narrow phones
       it has to wrap so it doesn't push the viewport sideways. */
    flex-wrap: wrap;
    min-width: 0;
}

.esg-empty-main {
    flex: 1;
    width: 100%;
    max-width: 720px;
    margin: 0 auto;
    padding: 48px 24px;
    box-sizing: border-box;
}

@media (max-width: 575.98px) {
    .esg-empty-header { padding: 14px 18px; }
    .esg-empty-main   { padding: 24px 16px; }
}

/* =====================================================================================
   Mobile step-progress (Konfigurator, < 768 px)
   -----------------------------------------------------------------------------------
   RadzenSteps renders four horizontal pills which overflow a phone viewport (the
   "Übersicht & Senden" pill got truncated). Below the breakpoint we replace it
   with a slim progress bar + "Schritt N / 4" caption. Step navigation happens via
   the existing Zurück/Weiter buttons under the wizard body — no clickable pills,
   so swipe / scroll-snap quirks don't apply.
   ===================================================================================== */
.esg-step-progress-bar {
    height: 4px;
    background: var(--esg-line);
    border-radius: 2px;
    overflow: hidden;
}

.esg-step-progress-fill {
    height: 100%;
    background: var(--esg-accent-soft);
    transition: width 0.25s ease;
}

/* =====================================================================================
   List cards (RadzenDataList on mobile — see PR-2 for the responsive switch)
   -----------------------------------------------------------------------------------
   Tighter padding than the default Radzen card so a tap-friendly card fits ~3 per
   viewport on phones. Visual rhythm matches `.esg-card` (auth pages) without the
   header chrome.
   ===================================================================================== */
.esg-list-card {
    padding: 12px 14px;
    margin-bottom: 0.5rem;
}
.esg-list-card:last-child {
    margin-bottom: 0;
}

/* Single option row inside a mobile tier card (CatalogTiersPage). A subtle
   border-top groups consecutive options visually without the heaviness of a
   nested DataGrid; the first option in a tier carries no separator. */
.esg-tier-option-row {
    padding-top: 0.4rem;
    border-top: 1px solid var(--esg-line);
}
.esg-tier-option-row:first-child {
    padding-top: 0;
    border-top: 0;
}

/* =====================================================================================
   Status pages (404 NotFound, 500 Error, inline ErrorBoundary fallback in MainLayout).
   -----------------------------------------------------------------------------------
   Centred card on a generous outer wrapper. The big numeric "404" / "500" sits
   above the heading as an aria-hidden glyph so it reads visually as a status
   marker without polluting the accessible name of the heading.
   ===================================================================================== */
.esg-status-page {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 60vh;
    padding: 24px 0;
}

.esg-status-card {
    background: var(--esg-surface);
    border: 1px solid var(--esg-line);
    border-radius: 16px;
    padding: 36px 32px;
    max-width: 560px;
    width: 100%;
    text-align: center;
}

.esg-status-card h1 {
    margin: 12px 0 8px;
    font-size: 1.5rem;
    font-weight: 600;
}

.esg-status-card p {
    margin: 0;
}

.esg-status-icon {
    font-size: 3rem;
    font-weight: 700;
    line-height: 1;
    color: var(--esg-accent-soft);
    letter-spacing: 0.05em;
}

/* =====================================================================================
   Broker full-view banner — shows under the header when a broker has opted into
   "full-view" (i.e. provision data is on screen). Loud orange so it cannot be
   missed when the broker is about to share their screen with a customer.
   ===================================================================================== */
.esg-full-view-banner {
    display: flex;
    gap: 0.6rem;
    align-items: center;
    justify-content: center;
    padding: 0.5rem 1rem;
    background: rgba(217, 119, 6, 0.18);   /* tinted orange, matches RadzenAlert.Warning */
    color: #fbbf24;
    font-size: 0.85rem;
    border-bottom: 1px solid rgba(217, 119, 6, 0.45);
    text-align: center;
}
.esg-full-view-banner .rzi {
    color: #fbbf24;
    flex: 0 0 auto;
}

/* =====================================================================================
   Compliance hint (CatalogBrowsePage — Elektro GU-Koordination, SHK-Leitung, …).
   -----------------------------------------------------------------------------------
   Earlier this rendered as a full RadzenAlert (Info) and dominated each position
   card — Ramon flagged it as too prominent for what is a regulatory side-note.
   New form: small icon + secondary-text run that reads as a footnote. Required
   information (docs/12-compliance) but visually subordinate to the position
   title + price.
   ===================================================================================== */
.esg-compliance-note {
    display: flex;
    gap: 0.45rem;
    align-items: flex-start;
    margin: 0.25rem 0;
    padding: 0;
    color: var(--rz-text-secondary-color);
    font-size: 0.82rem;
    line-height: 1.4;
}
.esg-compliance-note .rzi {
    color: var(--rz-text-secondary-color);
    opacity: 0.7;
    margin-top: 0.1rem;
}

/* =====================================================================================
   Wizard fixed footer (ConfiguratorPage Zurück / Weiter / Absenden bar).
   -----------------------------------------------------------------------------------
   Before this the Weiter-button sat at the bottom of the page — on a phone with 30
   selected positions the user had to scroll through everything to get to it. Now
   the nav bar sticks to the viewport bottom so step navigation is always reachable
   regardless of how long the position list grows.

   Implementation notes:
     - `position: fixed; bottom: 0` on BOTH desktop and mobile. We tried sticky on
       desktop first (the wizard lives inside the scrollable .rz-body, so sticky-
       bottom: 0 should clip to the viewport-bottom of that container), but the
       Konfigurator's Step-2 content is often SHORTER than the viewport — and when
       a sticky element's threshold never gets crossed, it just sits at its natural
       place mid-content. Ramon caught that on the desktop browser test: the bar
       was visible but mid-page, not flush at the viewport bottom. Switching to
       fixed is the only way to guarantee the visual.
     - Material3-Dark base sets `.rz-layout .rz-body { transform: translateZ(0) }`
       as a GPU hint, which silently makes .rz-body the containing block for
       position:fixed descendants (CSS spec: any transformed ancestor wins). That
       breaks the "fixed = viewport-bottom" promise on BOTH desktop and mobile,
       just for different reasons. Override `transform: none` everywhere — we lose
       the perf hint, gain a predictable layout. See memory
       feedback_radzen_rzbody_transform_containing_block.
     - Desktop left-offset matches the sidebar so the bar doesn't span across it.
       `--rz-sidebar-width` is the Radzen-internal variable that flips between
       expanded (250px) and collapsed (56px) when the toggle fires — we ride it
       so the bar repositions on toggle without JS.
     - Padding-bottom uses env(safe-area-inset-bottom) for iOS Safari home-bar /
       Android nav-bar.
   ===================================================================================== */
.rz-layout .rz-body {
    /* Cancel the Material3-Dark translateZ(0) so position:fixed descendants live
       in the viewport's containing block, not .rz-body's. */
    transform: none;
}

.esg-wizard-nav {
    position: fixed;
    bottom: 0;
    right: 0;
    /* On desktop the sidebar consumes the left strip. CSS var falls back to 250 px
       (Radzen's expanded sidebar default) when the toggle hasn't been touched. */
    left: var(--rz-sidebar-width, 250px);
    z-index: 5;
    padding: 0.75rem 1rem calc(0.75rem + env(safe-area-inset-bottom, 0px));
    background: var(--esg-bg);
    border-top: 1px solid var(--esg-line);
    box-shadow: 0 -8px 20px rgba(0, 0, 0, 0.25);
}

/* Inner content gets bottom padding so the LAST list card isn't trapped under
   the fixed bar. Bar height ≈ button 44 px + 2× 0.75 rem vertical padding +
   safe-area-inset-bottom. Applies on both desktop and mobile. */
.esg-wizard-page-body {
    padding-bottom: calc(72px + env(safe-area-inset-bottom, 0px));
}

@media (max-width: 767.98px) {
    /* Mobile: no sidebar — bar spans the full viewport. */
    .esg-wizard-nav {
        left: 0;
        padding-left: 1rem;
        padding-right: 1rem;
        box-shadow: 0 -8px 20px rgba(0, 0, 0, 0.35);
    }
}

/* =====================================================================================
   Checkbox contrast bump (Konfigurator Step 2, Catalog selectors, …).
   -----------------------------------------------------------------------------------
   Default Radzen unchecked checkboxes in the Material3-Dark theme render with a
   barely-visible border on the page background — Ramon flagged that he couldn't
   tell what was selected. We strengthen the border + add a faint inner fill so
   unchecked boxes are clearly present; checked stays the accent-soft Radzen
   primary so the state delta is unmistakable.
   ===================================================================================== */
.rz-chkbox-box {
    border: 1px solid var(--rz-text-secondary-color);
    background: rgba(255, 255, 255, 0.04);
    transition: border-color 0.15s, background 0.15s;
}
.rz-chkbox:hover .rz-chkbox-box {
    border-color: var(--esg-accent-soft);
}
.rz-chkbox-box.rz-state-active {
    /* Radzen's own checked styling owns the colour — we just bump opacity. */
    border-color: var(--esg-accent-soft);
}

/* =====================================================================================
   Side dialog (DialogService.OpenSideAsync — see DialogServiceExtensions)
   -----------------------------------------------------------------------------------
   Two things Radzen's Material3-Dark theme leaves us with that bite on a dark UI:

   1. `--rz-shadow-0` resolves to `none`, so the side dialog ships without any shadow
      or border — it visually melts into the body on desktop. Fixed below with an
      explicit edge shadow + separator line.
   2. `position: fixed` + `right: 0` + `height: 100%` is rendered with `top: auto`
      out-of-the-box, which means the element starts wherever the normal block flow
      would place it — at the bottom of <body>, off-screen. Forcing `top: 0` snaps
      it back to the viewport's top edge.

   We keep Radzen's own `--rz-base-600` (#292c30) as the dialog background — it's a
   neutral mid-grey that already contrasts our `--esg-bg` (#0c1119) once shadow +
   border are in place. Earlier attempts overrode it to `var(--esg-surface)` which
   tinted it bluer than the body and made the panel look "stuck on".
   ===================================================================================== */
.rz-dialog-side-position-right {
    top: 0;
    box-shadow: -12px 0 28px rgba(0, 0, 0, 0.45);
}

.rz-dialog-side-position-bottom {
    inset-inline: 0;
    bottom: 0;
    /* Grow with content up to 92 vh — Brokers (~4 fields) collapses, Position
       (~10 fields) hits the cap. Radzen's own rule sets height: auto for the
       bottom variant; we add the cap. */
    height: auto;
    max-height: 92vh;
    box-shadow: 0 -12px 28px rgba(0, 0, 0, 0.45);
    border-radius: 16px 16px 0 0;
}

/* Titlebar styling intentionally left to Radzen — it defaults to the same
   `--rz-base-600` background as the content with no border, so the header sits
   flush with the content as a single panel and reads as a title purely through
   typography (size + weight + padding). Earlier we forced a darker background
   plus an `--esg-line` (bluish) bottom border; Ramon flagged the abrupt colour
   change plus the blue tint as glitchy — see the screenshots in the review of
   pipeline #83. The dialog now reads as one continuous surface. */

/* =====================================================================================
   App-Shell — viewport-locked layout for the authenticated chrome (MainLayout).
   -----------------------------------------------------------------------------------
   Desktop (≥ 768 px): html/body are pinned to 100vh and never scroll. RadzenLayout
   fills the viewport, RadzenBody owns a flex column, and the inner scroll lives
   EITHER in the data-grid (grid pages) OR in .esg-content-wrap itself (everything
   else). Only ONE scroll container, like every serious admin UI (Linear, Notion,
   Stripe, Shopify Admin etc.).

   Mobile (< 768 px): native body scroll. Internal grid scroll + touch panning
   conflict, so we don't try. PR-2 replaces the data-grid with a card list on
   mobile anyway.

   :has() support: Chrome 105+, Safari 15.4+, Firefox 121+ — all evergreen browsers
   are fine in 2026.
   ===================================================================================== */

/* Body content wrapper — always centred, never wider than 1180, full width up to that
   cap. Breathing-space below the header is owned by .rz-body's margin-top (see desktop
   block below); doing it on .esg-content-wrap doesn't take because Radzen's RadzenBody
   resets margins on its direct children. */
.esg-content-wrap {
    max-width: 1180px;
    margin-inline: auto;
    width: 100%;
}

@media (min-width: 768px) {
    html, body {
        height: 100%;
        overflow: hidden;
    }

    /* RadzenLayout fills the body region. .rz-layout is the outermost wrapper Radzen
       emits; .rz-body is the flex slot under header.

       Scroll ownership policy:
         - Default (non-grid pages: dashboard, /auth/me, configurator, forms):
             .rz-body owns the scroll → scrollbar sits at the VIEWPORT RIGHT EDGE,
             not inside the centred content column. Standard app-shell look.
         - Grid pages (detected via CSS :has()):
             .rz-body does NOT scroll; the RadzenDataGrid's internal data area is the
             only scroll surface, so the pager stays pinned at the bottom of the
             viewport regardless of row count.
    */
    .rz-layout {
        height: 100vh;
    }

    .rz-body {
        min-height: 0;
        overflow-y: auto;
        overflow-x: hidden;
        display: flex;
        flex-direction: column;
        /* Breathing space between the header shadow and the first content card.
           Radzen exposes `--rz-layout-body-margin` for this; we ride the variable
           so future Radzen tweaks compose. The default token resolves to 0 on top
           in our theme, which is why the content sat flush against the header. */
        margin-top: 0.75rem;
    }

    /* Grid LIST pages opt into "grid owns the scroll": rz-body stops scrolling,
       the data-grid stretches and its internal data area takes over.
       -------------------------------------------------------------------------
       The selector intentionally uses direct-child `>`: the grid must sit as a
       NEAR-DIRECT child of `.esg-content-wrap` (either directly, or under one
       wrapping RadzenStack that holds page header / page-button row above it).
       This is the shape of every list page (BrokersPage, CatalogPage,
       CustomersPage, RequestsPage etc.).

       Detail pages (RequestDetailPage admin / broker / customer) have the grid
       buried in a RadzenCard several levels deep — they intentionally do NOT
       match here, so the wrapper keeps its default `overflow-y: auto` and the
       whole page scrolls naturally. Previously the descendant-selector matched
       any grid anywhere on the page and clamped the detail-page height. */
    .rz-body:has(> .esg-content-wrap > .rz-data-grid),
    .rz-body:has(> .esg-content-wrap > .rz-stack > .rz-data-grid) {
        overflow: hidden;
    }

    .rz-body:has(> .esg-content-wrap > .rz-data-grid) .esg-content-wrap,
    .rz-body:has(> .esg-content-wrap > .rz-stack > .rz-data-grid) .esg-content-wrap {
        flex: 1 1 auto;
        min-height: 0;
        display: flex;
        flex-direction: column;
    }

    .esg-content-wrap > .rz-data-grid,
    .esg-content-wrap > .rz-stack > .rz-data-grid {
        flex: 1 1 auto;
        min-height: 0;
        display: flex;
        flex-direction: column;
    }

    .esg-content-wrap > .rz-data-grid .rz-data-grid-data,
    .esg-content-wrap > .rz-stack > .rz-data-grid .rz-data-grid-data {
        flex: 1 1 auto;
        min-height: 0;
        overflow: auto;
    }
}

/* =====================================================================================
   RadzenHeader — give it a visible separation from the body region. Without this the
   content sits flush against the chrome and the eye has nothing to grab onto.
   ===================================================================================== */
.rz-header {
    border-bottom: 1px solid var(--esg-line);
    box-shadow: 0 1px 0 rgba(255, 255, 255, 0.02), 0 4px 12px rgba(0, 0, 0, 0.22);
    z-index: 110;  /* stay above the mobile-sidebar overlay (z 100) and its backdrop (z 90) */
    position: relative;  /* establish stacking context */
}

/* =====================================================================================
   NavMenu — section groups inside the sidebar
   -----------------------------------------------------------------------------------
   Each section is a tiny uppercase caption + a RadzenPanelMenu block. The caption is
   muted and small — it signposts the role without competing with the menu items.

   No outer top-padding on the sections container: the sidebar already has its own
   chrome (Radzen) and we don't want a fat empty band above the first section header,
   which looked off on the mobile overlay.
   ===================================================================================== */
.esg-nav-sections {
    display: flex;
    flex-direction: column;
}

/* Border-line + breathing space only BETWEEN sections; the first section starts
   flush at the top of the sidebar. */
.esg-nav-section + .esg-nav-section {
    border-top: 1px solid var(--esg-line);
    margin-top: 0.5rem;
    padding-top: 0.5rem;
}

.esg-nav-section-title {
    padding: 0.6rem 1rem 0.35rem 1rem;
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--esg-muted);
}

/* First section's title has slightly tighter top padding — the sidebar's own top edge
   gives it enough air already. */
.esg-nav-section:first-child .esg-nav-section-title {
    padding-top: 0.4rem;
}

/* =====================================================================================
   Mobile sidebar overlay
   -----------------------------------------------------------------------------------
   On phones (< 768 px) the sidebar must overlay the body region instead of taking
   its own grid column. We reassign its grid-area from `rz-sidebar` to `rz-body` so
   it sits in the SAME cell as the body — RadzenLayout's grid already places that
   cell exactly below the header, so we don't need a magic-number header offset
   (there's no `--rz-header-height` token in RadzenLayout's grid setup).

   The backdrop shares the same trick: grid-area rz-body, slightly lower z-index,
   covers the page area behind the sidebar. Tapping closes the drawer (handler in
   NavSidebar.razor).

   `justify-self: start` keeps the sidebar's effective width to its own (collapsed
   = 0 px, expanded = var(--rz-sidebar-width) via Radzen's own width rules); the
   body still fills the whole cell behind it.
   ===================================================================================== */
@media (max-width: 767.98px) {
    .rz-layout .rz-sidebar {
        grid-area: rz-body;
        align-self: stretch;
        justify-self: start;
        z-index: 100;
    }

    .esg-sidebar-backdrop {
        grid-area: rz-body;
        align-self: stretch;
        justify-self: stretch;
        z-index: 90;
        background: rgba(0, 0, 0, 0.45);
        backdrop-filter: blur(2px);
        cursor: pointer;
    }
}
