/* ═══ GreenTrust® eudr — page background, glass surfaces, render tiers ═══

   Loaded by every page shell that shows a full-page background: the
   dashboards (operator, supplier, admin) and the login-family pages (login,
   signup, select-role, pending-approval, email-not-verified).

   1. BACKGROUND LAYER
      <div class="gt-page-bg gt-page-bg--dashboard|login"> is the first child
      of <body>: one fixed, composited element behind everything, so neither
      scrolling nor any repaint above it ever repaints the photo (the former
      `background-attachment: fixed` body background repainted on scroll).
      <body> itself paints no background (it would cover a z-index:-1 layer
      once <html> has a background of its own, e.g. html.dark-mode-pending).

      Images are content-hashed files in /frontend/media/ (built by
      scripts/build_background_images.py, immutable in nginx). Format comes
      from image-set() type(): AVIF, else WebP, else JPEG. Resolution comes
      from media queries instead of image-set() x-descriptors: the <head> of
      each shell preloads the photo with the SAME media queries
      (frontend/html/_bg_preload.html), and x-descriptor selection differs
      between image-set() and preload srcset (Chrome rounds DPR 1.25 down for
      srcset but up for image-set), which would download both files.

        dashboard  aspect >= 4:3 : 4:3 centre crop, 1920 or 3840 px wide
                   aspect <  4:3 : the whole photo, 1440 px wide
        login      poster = first frame of the login loop, 1920 px; the
                   3840 px frame only with .gt-page-bg--hires, which
                   _bg_video.html adds after the load event when the
                   loop will not play (reduced motion...). While the
                   loop plays it covers the poster within ~1-3 s, so a
                   4K poster (a 0.66 MB AVIF, 0.3-0.8 s to decode
                   during page load) would only delay the first paint.
        "3840" when the viewport is >= 2200 px wide, or >= 1100 px wide at
        a device pixel ratio >= 1.5.

   2. GLASS SURFACES
      Large translucent cards used to blur the photo live with
      backdrop-filter: blur(12-16px), re-run by the GPU on every composited
      frame (animations, scrolling, map panning). They now paint a pre-blurred
      copy of the photo (dashboard-bg-blur, Gaussian sigma 15 px at 2250 px
      = blur(12px) at 1920) with `background-attachment: fixed`, which puts it
      exactly under the sharp layer, below their own tint: the same look,
      painted once. Use as `background: var(--gt-glass-light)` /
      `var(--gt-glass-dark)`. Constraints: no transform on the surface or an
      ancestor (a transform turns `fixed` into `scroll`, so hover lifts use
      `position: relative; top`), and not inside a scrolling list (fixed
      backgrounds inside a scroller are repainted on every scroll step).
      Surfaces nested in a glass card drop backdrop-filter and keep a plain
      tint: their old filter only re-drew the parent's tint inside them (the
      parent was their backdrop root), so 0.5 on 0.5 becomes 0.75 opaque.

   3. RENDER TIERS
      html.gt-lite (set by frontend/html/_render_tier.html for reduced motion
      or transparency, <= 4 GB RAM, <= 4 cores or a < 50 fps probe) turns off
      the remaining blur, the large shadows, the background video and every
      animation/transition. `?gt-render=lite|full` forces a tier for the tab.
   ═══════════════════════════════════════════════════════════════════════ */

/* ── 1. Background layer ── */
.gt-page-bg {
    position: fixed;
    inset: 0;
    z-index: -1;
    transform: translateZ(0);
    pointer-events: none;
    background-color: #162b0e;
    background-position: center;
    background-size: cover;
    background-repeat: no-repeat;
}

body.gt-has-page-bg {
    background: none;
}

/* Vignette over the photo until the dashboard shell mounts (the shell has
   always shown the plain photo). */
.gt-page-bg--dashboard::after,
.gt-page-bg--app::after {
    content: "";
    position: absolute;
    inset: 0;
    background:
        radial-gradient(ellipse at center, rgba(14, 29, 8, 0) 55%, rgba(14, 29, 8, 0.20) 100%),
        linear-gradient(180deg, rgba(22, 43, 14, 0.04) 0%, rgba(22, 43, 14, 0) 40%, rgba(22, 43, 14, 0.12) 100%);
}

body.gt-shell-active .gt-page-bg--dashboard::after {
    content: none;
}

/* The login page's legacy supplier-form layer keeps the dashboard photo. */
.gt-page-bg--app { display: none; }
body.gt-app-entered .gt-page-bg--app { display: block; }
body.gt-app-entered .gt-page-bg--login { display: none; }

/* Fallback (no image-set() type()): JPEG */
.gt-page-bg--dashboard,
.gt-page-bg--app {
    background-image: url("/frontend/media/dashboard-bg-1920.478e48b5.jpg");
}

.gt-page-bg--login {
    background-color: #0e1d08;
    background-image: url("/frontend/media/login-bg-1920.cb450773.jpg");
}

@media (min-aspect-ratio: 4/3) and (min-width: 2200px), (min-aspect-ratio: 4/3) and (min-resolution: 1.5dppx) and (min-width: 1100px) {
    .gt-page-bg--dashboard,
    .gt-page-bg--app {
        background-image: url("/frontend/media/dashboard-bg-3840.fa5b0754.jpg");
    }
}

@media not all and (min-aspect-ratio: 4/3) {
    .gt-page-bg--dashboard,
    .gt-page-bg--app {
        background-image: url("/frontend/media/dashboard-bg-tall.f0cf6a71.jpg");
    }
}

@media (min-width: 2200px), (min-resolution: 1.5dppx) and (min-width: 1100px) {
    .gt-page-bg--login.gt-page-bg--hires {
        background-image: url("/frontend/media/login-bg-3840.daed0547.jpg");
    }
}

@supports (background-image: image-set(url("/x.avif") type("image/avif"))) {
    .gt-page-bg--dashboard,
    .gt-page-bg--app {
        background-image: image-set(
            url("/frontend/media/dashboard-bg-1920.613d8d4c.avif") type("image/avif"),
            url("/frontend/media/dashboard-bg-1920.77cac18c.webp") type("image/webp"),
            url("/frontend/media/dashboard-bg-1920.478e48b5.jpg") type("image/jpeg"));
    }

    .gt-page-bg--login {
        background-image: image-set(
            url("/frontend/media/login-bg-1920.e4575d89.avif") type("image/avif"),
            url("/frontend/media/login-bg-1920.19383eef.webp") type("image/webp"),
            url("/frontend/media/login-bg-1920.cb450773.jpg") type("image/jpeg"));
    }

    @media (min-aspect-ratio: 4/3) and (min-width: 2200px), (min-aspect-ratio: 4/3) and (min-resolution: 1.5dppx) and (min-width: 1100px) {
        .gt-page-bg--dashboard,
        .gt-page-bg--app {
            background-image: image-set(
                url("/frontend/media/dashboard-bg-3840.996e7507.avif") type("image/avif"),
                url("/frontend/media/dashboard-bg-3840.13c84baf.webp") type("image/webp"),
                url("/frontend/media/dashboard-bg-3840.fa5b0754.jpg") type("image/jpeg"));
        }
    }

    @media not all and (min-aspect-ratio: 4/3) {
        .gt-page-bg--dashboard,
        .gt-page-bg--app {
            background-image: image-set(
                url("/frontend/media/dashboard-bg-tall.97020710.avif") type("image/avif"),
                url("/frontend/media/dashboard-bg-tall.4a7899bc.webp") type("image/webp"),
                url("/frontend/media/dashboard-bg-tall.f0cf6a71.jpg") type("image/jpeg"));
        }
    }

    @media (min-width: 2200px), (min-resolution: 1.5dppx) and (min-width: 1100px) {
        .gt-page-bg--login.gt-page-bg--hires {
            background-image: image-set(
                url("/frontend/media/login-bg-3840.a8bbc0bd.avif") type("image/avif"),
                url("/frontend/media/login-bg-3840.c3e784e2.webp") type("image/webp"),
                url("/frontend/media/login-bg-3840.daed0547.jpg") type("image/jpeg"));
        }
    }
}

/* ── 2. Glass surfaces ── */
body {
    --gt-glass-photo: url("/frontend/media/dashboard-bg-blur.565b3c48.jpg") center / cover no-repeat fixed;
    /* Mean colour of the blurred photo: the flat stand-in used by gt-lite. */
    --gt-glass-solid: #2e391f;
    --gt-glass-light: linear-gradient(rgba(245, 248, 243, 0.72), rgba(245, 248, 243, 0.72)), var(--gt-glass-photo);
    --gt-glass-dark: linear-gradient(rgba(15, 30, 10, 0.5), rgba(15, 30, 10, 0.5)), var(--gt-glass-photo);
}

@supports (background-image: image-set(url("/x.avif") type("image/avif"))) {
    body {
        --gt-glass-photo: image-set(
            url("/frontend/media/dashboard-bg-blur.ede3382a.avif") type("image/avif"),
            url("/frontend/media/dashboard-bg-blur.71b9be0c.webp") type("image/webp"),
            url("/frontend/media/dashboard-bg-blur.565b3c48.jpg") type("image/jpeg")) center / cover no-repeat fixed;
    }
}

/* Dark-mode items inside glass cards (list rows, panel sections) keep the
   compositing layer their former backdrop-filter gave them, now without the
   filter: in a scrolling list Chrome then moves the rows instead of
   repainting the list on every scroll step (measured on the supplier list:
   paint 4.5 -> 0.8 ms and GPU 8.8 -> 7.4 ms per frame at DPR 1). Same
   stacking context and containing block as with the filter, and none of
   them has a fixed background (a transform would unpin it). Light mode never
   composited them (LCD text on the opaque cards) and stays as it was. */
body.dark-mode .product-card,
body.dark-mode .matching-card,
body.dark-mode .op-product-card,
body.dark-mode .op-matching-card,
body.dark-mode .assess-supplier-card,
body.dark-mode .assess-plot-card,
body.dark-mode .ship-card,
body.dark-mode .gt-card,
body.dark-mode .sp-hero,
body.dark-mode .sp-sub-header,
body.dark-mode .sp-drill-card,
body.dark-mode .supplier-documents-panel .sup-doc-upload,
body.dark-mode .supplier-documents-panel .sup-doc-item,
body.dark-mode .ra-select-card,
body.dark-mode .ra-doc-card,
body.dark-mode .pah-entry,
body.dark-mode .pah-status-bar,
body.dark-mode .pah-loading,
body.dark-mode .pah-empty,
body.dark-mode .adv-hero,
body.dark-mode .adv-section,
body.dark-mode .adv-ind-row,
body.dark-mode .questionnaire-group,
body.dark-mode .plot-docs-format-card {
    will-change: transform;
}

/* Inside a modal overlay a card sits on the dimmed (live-blurred) page, not on
   the photo, and modals animate with transforms: plain tint there, as the
   former backdrop-filter showed. (Redeclared here because --gt-glass-light /
   -dark are resolved on <body>.) */
.modal-overlay,
.modal-backdrop,
.supplier-panel-overlay {
    --gt-glass-photo: linear-gradient(transparent, transparent);
    --gt-glass-light: rgba(245, 248, 243, 0.72);
    --gt-glass-dark: rgba(15, 30, 10, 0.5);
}

/* iOS / iPadOS WebKit treats `background-attachment: fixed` as `scroll`, which
   would scale the glass photo to each card: use the flat stand-in there. */
@supports (-webkit-touch-callout: none) {
    body {
        --gt-glass-photo: linear-gradient(var(--gt-glass-solid), var(--gt-glass-solid));
    }
}

/* ── 3. Lite tier ── */
html.gt-lite body {
    --gt-glass-photo: linear-gradient(var(--gt-glass-solid), var(--gt-glass-solid));
    --shadow: 0 1px 3px rgba(22, 43, 14, 0.10);
    --shadow-lg: 0 2px 6px rgba(22, 43, 14, 0.14);
}

html.gt-lite *,
html.gt-lite *::before,
html.gt-lite *::after {
    -webkit-backdrop-filter: none !important;
    backdrop-filter: none !important;
    animation-duration: 0.001ms !important;
    animation-delay: 0s !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    transition-delay: 0s !important;
}

html.gt-lite .gt-bg-video {
    display: none !important;
}

html.gt-lite .home-welcome,
html.gt-lite .home-map-card,
html.gt-lite .auth-card,
html.gt-lite .card,
html.gt-lite .gt-lock__card,
html.gt-lite .gt-bottomnav__pill {
    box-shadow: 0 2px 6px rgba(14, 29, 8, 0.18) !important;
}
