/* ==========================================================================
   NextGen Plants — Shared foundation
   Design language: "liquid glass" — translucent, layered surfaces with
   specular edges floating over botanical imagery. Only genuinely shared
   styles live here; page-specific work lives in each page's own stylesheet.
   ========================================================================== */

/* ---------- Fonts ---------- */
@font-face {
    font-family: 'Termina';
    src: url('../fonts/Termina Test/TerminaTest-Thin.otf') format('opentype');
    font-weight: 100; font-style: normal; font-display: swap;
}
@font-face {
    font-family: 'Termina';
    src: url('../fonts/Termina Test/TerminaTest-ExtraLight.otf') format('opentype');
    font-weight: 200; font-style: normal; font-display: swap;
}
@font-face {
    font-family: 'Termina';
    src: url('../fonts/Termina Test/TerminaTest-Light.otf') format('opentype');
    font-weight: 300; font-style: normal; font-display: swap;
}
@font-face {
    font-family: 'Termina';
    src: url('../fonts/Termina Test/TerminaTest-Regular.otf') format('opentype');
    font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
    font-family: 'Termina';
    src: url('../fonts/Termina Test/TerminaTest-Medium.otf') format('opentype');
    font-weight: 500; font-style: normal; font-display: swap;
}
@font-face {
    font-family: 'Termina';
    src: url('../fonts/Termina Test/TerminaTest-Demi.otf') format('opentype');
    font-weight: 600; font-style: normal; font-display: swap;
}
@font-face {
    font-family: 'Termina';
    src: url('../fonts/Termina Test/TerminaTest-Bold.otf') format('opentype');
    font-weight: 700; font-style: normal; font-display: swap;
}
@font-face {
    font-family: 'Termina';
    src: url('../fonts/Termina Test/TerminaTest-Heavy.otf') format('opentype');
    font-weight: 800; font-style: normal; font-display: swap;
}
@font-face {
    font-family: 'Termina';
    src: url('../fonts/Termina Test/TerminaTest-Black.otf') format('opentype');
    font-weight: 900; font-style: normal; font-display: swap;
}
@font-face {
    font-family: 'Montserrat';
    src: url('../fonts/Montserrat/Montserrat-VariableFont_wght.ttf') format('truetype-variations');
    font-weight: 100 900; font-style: normal; font-display: swap;
}
@font-face {
    font-family: 'Montserrat';
    src: url('../fonts/Montserrat/Montserrat-Italic-VariableFont_wght.ttf') format('truetype-variations');
    font-weight: 100 900; font-style: italic; font-display: swap;
}

/* ---------- Design tokens ---------- */
:root {
    /* Brand — sampled from the NextGen Plants mark */
    --ngp-forest:      #1b3524;
    --ngp-deep:        #233b2b;
    --ngp-sage:        #538665;
    --ngp-leaf:        #7fb04a;
    --ngp-leaf-bright: #9ccc51;
    --ngp-soil:        #6b4a2f;
    --ngp-cream:       #faf8f2;
    --ngp-mist:        #eef3ec;

    /* Text */
    --ink:        #1b3524;
    --ink-muted:  #4a5c50;
    --ink-soft:   #6d7c72;
    --ink-invert: #f4f8f2;

    /* Liquid glass — light surfaces over imagery */
    --glass-fill: linear-gradient(150deg,
                     rgba(255, 255, 255, 0.62) 0%,
                     rgba(255, 255, 255, 0.34) 42%,
                     rgba(255, 255, 255, 0.20) 100%);
    --glass-fill-strong: linear-gradient(150deg,
                     rgba(255, 255, 255, 0.86) 0%,
                     rgba(255, 255, 255, 0.62) 50%,
                     rgba(255, 255, 255, 0.46) 100%);
    /* Blur radius is the single most expensive thing on this site: the compositor
       re-samples and re-blurs the backdrop of every glass pane on every scroll
       frame, and the cost scales with the radius. 28px looked all but identical
       to 18px while costing far more on integrated GPUs, where memory bandwidth
       is shared with the CPU. Raise these only with a scroll test to hand. */
    --glass-blur: blur(18px) saturate(170%);
    --glass-blur-lite: blur(11px) saturate(148%);
    --glass-edge: rgba(255, 255, 255, 0.58);
    --glass-edge-soft: rgba(255, 255, 255, 0.32);

    /* Liquid glass — dark surfaces over bright imagery */
    --glass-dark-fill: linear-gradient(150deg,
                     rgba(27, 53, 36, 0.58) 0%,
                     rgba(27, 53, 36, 0.38) 50%,
                     rgba(27, 53, 36, 0.26) 100%);
    --glass-dark-edge: rgba(255, 255, 255, 0.24);

    /* Specular + depth */
    --sheen-top:   inset 0 1px 0 rgba(255, 255, 255, 0.75);
    --sheen-inner: inset 0 0 24px rgba(255, 255, 255, 0.22);
    --lift-sm: 0 4px 16px -6px rgba(27, 53, 36, 0.28);
    --lift:    0 20px 48px -22px rgba(27, 53, 36, 0.42), 0 4px 14px -8px rgba(27, 53, 36, 0.22);
    --lift-lg: 0 36px 90px -34px rgba(27, 53, 36, 0.52), 0 8px 24px -12px rgba(27, 53, 36, 0.24);

    /* Radii — generously round, the way liquid pools */
    --r-sm: 0.875rem;
    --r-md: 1.25rem;
    --r-lg: 1.75rem;
    --r-xl: 2.25rem;
    --r-pill: 62.4375rem;

    /* Motion */
    --ease-glass: cubic-bezier(0.22, 1, 0.36, 1);
    --t-fast: 0.22s var(--ease-glass);
    --t-med:  0.42s var(--ease-glass);
    --t-slow: 0.7s  var(--ease-glass);

    /* Layout */
    --header-h: 5rem;
}

/* ---------- Reset + base ---------- */
*, *::before, *::after {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

html {
    font-size: 16px;
    scroll-behavior: smooth;
    scroll-padding-top: calc(var(--header-h) + 1rem);
}

body {
    font-family: 'Montserrat', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    font-size: 1rem;
    line-height: 1.65;
    color: var(--ink);
    background: var(--ngp-cream);
    overflow-x: hidden;
    max-width: 100vw;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    -webkit-tap-highlight-color: transparent;
}

/* Soft botanical wash behind every page, so glass always has something
   to refract even where a section sets no imagery of its own. */
body::before {
    content: '';
    position: fixed;
    inset: 0;
    z-index: -2;
    background:
        radial-gradient(60rem 40rem at 12% -10%, rgba(156, 204, 81, 0.20), transparent 60%),
        radial-gradient(50rem 38rem at 92% 8%,  rgba(83, 134, 101, 0.22), transparent 62%),
        radial-gradient(46rem 40rem at 50% 108%, rgba(107, 74, 47, 0.13), transparent 60%),
        var(--ngp-cream);
    pointer-events: none;
}

h1, h2, h3, h4, h5, h6,
.hero-title, .section-title, .page-title, .display {
    font-family: 'Termina', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    font-weight: 500;
    line-height: 1.14;
    letter-spacing: -0.01em;
    color: var(--ink);
}

a { color: inherit; }

img, svg, video { max-width: 100%; display: block; }

::selection {
    background: rgba(127, 176, 74, 0.32);
    color: var(--ngp-forest);
}

:focus-visible {
    outline: 2px solid var(--ngp-leaf);
    outline-offset: 3px;
    border-radius: 0.375rem;
}

/* ---------- Layout ---------- */
.container {
    width: 100%;
    max-width: 78rem;
    margin: 0 auto;
    padding: 0 1.75rem;
}

.container-narrow {
    width: 100%;
    max-width: 52rem;
    margin: 0 auto;
    padding: 0 1.75rem;
}

.section {
    position: relative;
    padding: clamp(4.5rem, 9vw, 8rem) 0;

    /* Skip rendering work for sections that are off screen. On a page carrying
       this many blurred panes that is the difference between the compositor
       re-blurring the whole document on every scroll frame and re-blurring only
       what is actually in view. `auto` on contain-intrinsic-size lets the browser
       remember each section's real measured height once it has been on screen,
       so the scrollbar stays put instead of rescaling as you go. */
    content-visibility: auto;
    contain-intrinsic-size: auto 40rem;
}

/* The hero is on screen at load and sets the first paint — never defer it.
   Same for anything holding a fixed/sticky child, which containment would clip. */
.hero,
.section--always-render {
    content-visibility: visible;
}

.section-tight { padding: clamp(3rem, 6vw, 5rem) 0; }

@media (max-width: 768px) {
    .container, .container-narrow { padding: 0 1.25rem; }
}
@media (max-width: 480px) {
    .container, .container-narrow { padding: 0 1rem; }
}

/* ==========================================================================
   Liquid glass primitives
   ========================================================================== */

/* Base pane. Compose with .glass--dark / .glass--strong / .glass--interactive
   and, ONLY over photography, .glass--refract.

   Note what is NOT here: backdrop-filter. It used to be, and it was the single
   thing making this site stutter. Every blurred element forces the compositor to
   allocate an offscreen render surface and re-blur it on every frame — measured
   on an integrated GPU, backdrop-filter accounted for 100% of the render
   surfaces this page allocated while scrolling. The cost is per surface per
   frame, so it scales with how MANY panes blur, not how strong the blur is.

   And most panes gained nothing from it: a blur over flat colour or a smooth
   gradient computes to the same picture you would get without it. The footer
   pane alone was blurring ~794k pixels a frame, on every page, to no visible
   effect. So the blur is now opt-in — see .glass--refract. */
.glass {
    position: relative;
    background: var(--glass-fill);
    border: 1px solid var(--glass-edge);
    border-radius: var(--r-lg);
    box-shadow: var(--lift), var(--sheen-top), var(--sheen-inner);
    overflow: hidden;
    isolation: isolate;
}

/* Opt in to real refraction. Use this ONLY where a photograph sits behind the
   pane and the blur is genuinely visible — hero panels, the contact form over
   the flat-lay, the floating nav. Over a flat or gradient background it costs a
   full render surface per frame and changes nothing on screen. */
.glass--refract {
    -webkit-backdrop-filter: var(--glass-blur);
    backdrop-filter: var(--glass-blur);
}

/* ---------------------------------------------------------------------------
   KILL SWITCH. If scrolling still stutters on a given machine, uncomment this
   block: it removes every remaining backdrop-filter on the site in one move.
   The panes keep their fill and border, so the layout and legibility are
   unchanged — only the refraction is lost. Use it to settle, in one reload,
   whether blur is still the bottleneck on that hardware.
   --------------------------------------------------------------------------- */
/*
.glass--refract,
.glass--lite,
.nav,
.cc-inner {
    -webkit-backdrop-filter: none !important;
    backdrop-filter: none !important;
}
*/

/* Specular sweep — the highlight that reads as a curved liquid surface */
.glass::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: -1;
    background: linear-gradient(115deg,
        rgba(255, 255, 255, 0.55) 0%,
        rgba(255, 255, 255, 0.10) 26%,
        rgba(255, 255, 255, 0)    46%,
        rgba(255, 255, 255, 0)    62%,
        rgba(255, 255, 255, 0.22) 100%);
    pointer-events: none;
}

/* Refracted edge — a bright hairline pooling at the bottom right */
.glass::after {
    content: '';
    position: absolute;
    inset: 0;
    z-index: -1;
    border-radius: inherit;
    padding: 1px;
    background: linear-gradient(140deg,
        rgba(255, 255, 255, 0.9) 0%,
        rgba(255, 255, 255, 0.05) 38%,
        rgba(255, 255, 255, 0) 60%,
        rgba(156, 204, 81, 0.35) 100%);
    -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
    -webkit-mask-composite: xor;
            mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
            mask-composite: exclude;
    pointer-events: none;
}

.glass--strong {
    background: var(--glass-fill-strong);
    border-color: rgba(255, 255, 255, 0.72);
}

.glass--dark {
    background: var(--glass-dark-fill);
    border-color: var(--glass-dark-edge);
    color: var(--ink-invert);
    box-shadow: var(--lift-lg), inset 0 1px 0 rgba(255, 255, 255, 0.28);
}

/* Dark glass relies on something dark behind it to refract. On a light section
   there is nothing to sample, so it collapses to flat grey — .glass--solid
   lays the translucent fill over an opaque forest base to keep it reading as
   a deliberate dark slab (and keeps text contrast well clear of AA). */
.glass--dark.glass--solid {
    background:
        var(--glass-dark-fill),
        linear-gradient(165deg, var(--ngp-forest) 0%, #12261a 100%);
    border-color: rgba(255, 255, 255, 0.16);

    /* The base layer above is opaque, so nothing behind this pane can ever show
       through — blurring that backdrop is work whose result is painted over.
       Dropping it is invisible on screen and removes a render surface. */
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
}

.glass--dark h1, .glass--dark h2, .glass--dark h3,
.glass--dark h4, .glass--dark h5, .glass--dark h6 { color: var(--ink-invert); }

.glass--dark::before {
    background: linear-gradient(115deg,
        rgba(255, 255, 255, 0.26) 0%,
        rgba(255, 255, 255, 0.04) 30%,
        rgba(255, 255, 255, 0) 55%,
        rgba(156, 204, 81, 0.14) 100%);
}

.glass--flush { border-radius: 0; }
.glass--sm { border-radius: var(--r-md); }
.glass--xl { border-radius: var(--r-xl); }

/* A cheaper refraction for panes that are small or always in front of moving
   content — the floating nav uses this. Like .glass--refract, it is opt-in. */
.glass--lite {
    -webkit-backdrop-filter: var(--glass-blur-lite);
    backdrop-filter: var(--glass-blur-lite);
}

/* Hover-responsive panes: lift, brighten, and let the sheen travel */
/* No standing `will-change` here. It permanently promotes every card to its own
   compositing layer for a hover that may never happen, and on a page with a
   dozen cards that is GPU memory spent all the time to save a few ms once.
   Promoting on hover-intent gets the same smoothness for the moment it matters. */
.glass--interactive {
    transition: transform var(--t-med), box-shadow var(--t-med), border-color var(--t-med);
}

@media (hover: hover) {
    .glass--interactive:hover,
    .glass--interactive:focus-within { will-change: transform; }
}

/* --sheen-x / --sheen-y are set from JS on pointer move, so the highlight
   leans towards the cursor. They default to 0, so the effect is purely
   additive and the pane still looks right without JS. */
.glass--interactive::before {
    transform: translate(var(--sheen-x, 0), var(--sheen-y, 0));
    transition: transform var(--t-med), opacity var(--t-med);
}

.glass--interactive:hover,
.glass--interactive:focus-within {
    transform: translateY(-0.375rem);
    box-shadow: var(--lift-lg), var(--sheen-top), var(--sheen-inner);
    border-color: rgba(255, 255, 255, 0.8);
}

.glass--interactive:hover::before,
.glass--interactive:focus-within::before {
    transform: translate(calc(9% + var(--sheen-x, 0px)), var(--sheen-y, 0));
    opacity: 0.85;
}

/* Padding helpers so panes don't each re-invent their inset */
.glass-pad    { padding: clamp(1.75rem, 3vw, 2.75rem); }
.glass-pad-lg { padding: clamp(2.25rem, 4.5vw, 4rem); }
.glass-pad-sm { padding: clamp(1.25rem, 2vw, 1.75rem); }

/* Graceful degradation where backdrop-filter is unavailable */
@supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
    .glass { background: rgba(255, 255, 255, 0.92); }
    .glass--dark { background: rgba(27, 53, 36, 0.92); }
}

/* ==========================================================================
   Photography
   Each photograph exists exactly once, in Shared/assets/images/photography/,
   at width tiers only — there are no pre-cut aspect-ratio variants. Every
   placement re-frames the same file at render time: the container decides the
   aspect ratio, and --focus decides which part of the image survives the crop.
   Browsers pick the right tier from srcset.
   ========================================================================== */
.photo {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: var(--focus-x, 50%) var(--focus-y, 50%);
}


/* ==========================================================================
   Typography helpers
   ========================================================================== */
.eyebrow {
    display: inline-flex;
    align-items: center;
    gap: 0.625rem;
    font-family: 'Montserrat', sans-serif;
    font-size: clamp(0.6875rem, 0.8vw, 0.75rem);
    font-weight: 600;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--ngp-sage);
    margin-bottom: 1.125rem;
}

.eyebrow::before {
    content: '';
    width: 1.75rem;
    height: 1px;
    background: currentColor;
    opacity: 0.7;
}

.glass--dark .eyebrow,
.on-dark .eyebrow { color: var(--ngp-leaf-bright); }

.display {
    font-size: clamp(2.5rem, 6.2vw, 4.75rem);
    font-weight: 600;
    letter-spacing: -0.025em;
    line-height: 1.03;
}

.section-title {
    font-size: clamp(1.875rem, 3.6vw, 3rem);
    font-weight: 500;
    letter-spacing: -0.02em;
    margin-bottom: 1.25rem;
}

.section-lead {
    font-size: clamp(1rem, 1.25vw, 1.1875rem);
    line-height: 1.75;
    color: var(--ink-muted);
    max-width: 42rem;
}

.on-dark, .on-dark p { color: var(--ink-invert); }
.on-dark .section-lead { color: rgba(244, 248, 242, 0.82); }

.text-leaf { color: var(--ngp-leaf); }
.text-sage { color: var(--ngp-sage); }

/* A soft green-to-leaf gradient for emphasised words */
.text-gradient {
    background: linear-gradient(100deg, var(--ngp-sage), var(--ngp-leaf-bright));
    -webkit-background-clip: text;
            background-clip: text;
    -webkit-text-fill-color: transparent;
}

/* ==========================================================================
   Buttons — pill-shaped liquid glass
   ========================================================================== */
.btn {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.625rem;
    padding: 0.9375rem 1.875rem;
    min-height: 3rem;
    border: 1px solid transparent;
    border-radius: var(--r-pill);
    font-family: 'Montserrat', sans-serif;
    font-size: clamp(0.75rem, 0.85vw, 0.8125rem);
    font-weight: 600;
    letter-spacing: 0.11em;
    text-transform: uppercase;
    text-decoration: none;
    cursor: pointer;
    overflow: hidden;
    isolation: isolate;
    transition: transform var(--t-fast), box-shadow var(--t-med),
                background-color var(--t-med), border-color var(--t-med), color var(--t-med);
}

/* Travelling specular highlight on hover */
.btn::after {
    content: '';
    position: absolute;
    top: 0;
    left: -60%;
    width: 45%;
    height: 100%;
    z-index: -1;
    background: linear-gradient(100deg, transparent, rgba(255, 255, 255, 0.5), transparent);
    transform: skewX(-18deg);
    transition: left var(--t-slow);
    pointer-events: none;
}

.btn:hover::after { left: 125%; }

.btn:active { transform: translateY(1px) scale(0.99); }

.btn-primary {
    background: linear-gradient(140deg, var(--ngp-sage), var(--ngp-forest));
    color: var(--ink-invert);
    border-color: rgba(255, 255, 255, 0.22);
    box-shadow: var(--lift), inset 0 1px 0 rgba(255, 255, 255, 0.3);
}

.btn-primary:hover {
    transform: translateY(-2px);
    box-shadow: var(--lift-lg), inset 0 1px 0 rgba(255, 255, 255, 0.4);
}

/* Buttons deliberately carry no backdrop-filter. Each blurred element is its own
   render surface, and buttons are the most numerous glass thing on the site —
   yet at 2.5rem tall there is too little backdrop showing for a blur to read.
   A slightly denser fill gives the same impression for none of the cost. */
.btn-glass {
    background: var(--glass-fill-strong);
    border-color: var(--glass-edge);
    color: var(--ink);
    box-shadow: var(--lift-sm), var(--sheen-top);
}

.btn-glass:hover {
    transform: translateY(-2px);
    background: var(--glass-fill-strong);
    box-shadow: var(--lift), var(--sheen-top);
}

/* As .btn-glass — denser fill instead of a blur, so the button stays legible
   over photography without becoming another compositing layer. */
.btn-glass-dark {
    background: linear-gradient(150deg,
                    rgba(27, 53, 36, 0.82) 0%,
                    rgba(27, 53, 36, 0.68) 50%,
                    rgba(27, 53, 36, 0.58) 100%);
    border-color: rgba(255, 255, 255, 0.34);
    color: var(--ink-invert);
    box-shadow: var(--lift-sm), inset 0 1px 0 rgba(255, 255, 255, 0.26);
}

.btn-glass-dark:hover {
    transform: translateY(-2px);
    border-color: rgba(255, 255, 255, 0.55);
    box-shadow: var(--lift), inset 0 1px 0 rgba(255, 255, 255, 0.34);
}

.btn-text {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.375rem 0;
    font-family: 'Montserrat', sans-serif;
    font-size: 0.8125rem;
    font-weight: 600;
    letter-spacing: 0.11em;
    text-transform: uppercase;
    text-decoration: none;
    color: var(--ngp-sage);
    border-bottom: 1px solid rgba(83, 134, 101, 0.35);
    transition: color var(--t-fast), border-color var(--t-fast), gap var(--t-fast);
}

.btn-text:hover {
    color: var(--ngp-forest);
    border-color: var(--ngp-leaf);
    gap: 0.875rem;
}

.on-dark .btn-text,
.glass--dark .btn-text {
    color: var(--ngp-leaf-bright);
    border-color: rgba(156, 204, 81, 0.4);
}

.on-dark .btn-text:hover,
.glass--dark .btn-text:hover {
    color: #fff;
    border-color: #fff;
}

@media (max-width: 768px) {
    .btn { padding: 1rem 1.75rem; min-height: 3.125rem; }
}

/* ==========================================================================
   Shared page header (used by Legal / Terms / interior pages)
   ========================================================================== */
.page-header {
    position: relative;
    padding: calc(var(--header-h) + clamp(3.5rem, 7vw, 6rem)) 0 clamp(3rem, 6vw, 5rem);
    text-align: center;
    overflow: hidden;
}

.page-header::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: -1;
    background: linear-gradient(165deg, var(--ngp-forest) 0%, var(--ngp-deep) 55%, var(--ngp-sage) 140%);
}

.page-header h1 {
    color: var(--ink-invert);
    font-size: clamp(2rem, 4.4vw, 3.25rem);
    margin-bottom: 1rem;
}

.page-header p {
    color: rgba(244, 248, 242, 0.8);
    font-size: clamp(0.9375rem, 1.1vw, 1.0625rem);
    max-width: 40rem;
    margin: 0 auto;
}

/* ==========================================================================
   Scroll cue
   ========================================================================== */
.scroll-cue {
    position: absolute;
    left: 50%;
    bottom: 2.25rem;
    transform: translateX(-50%);
    display: grid;
    place-items: center;
    width: 3rem;
    height: 3rem;
    border-radius: 50%;
    color: var(--ink-invert);
    /* Sits low in the hero where the scrim is at its densest, so a blur here
       would refract almost nothing — and it would be a render surface over the
       parallaxing photograph. Denser fill instead. */
    background: linear-gradient(150deg,
                    rgba(27, 53, 36, 0.74) 0%,
                    rgba(27, 53, 36, 0.58) 100%);
    border: 1px solid rgba(255, 255, 255, 0.34);
    box-shadow: var(--lift-sm), inset 0 1px 0 rgba(255, 255, 255, 0.3);
    transition: background-color var(--t-fast), border-color var(--t-fast);
}

/* The bob lives on the chevron, not on the button.
   Animating an element that also carries a backdrop-filter forces the browser
   to re-sample and re-blur the backdrop on every single frame, forever — even
   while the visitor sits still. Moving the motion inside the blurred surface
   leaves that surface static, so the blur is computed once. */
.scroll-cue > svg {
    animation: cue-bob 2.6s var(--ease-glass) infinite;
}

.scroll-cue:hover { border-color: rgba(255, 255, 255, 0.7); }

@keyframes cue-bob {
    0%, 100% { transform: translateY(0); }
    50%      { transform: translateY(0.35rem); }
}

/* ==========================================================================
   Off-screen render skipping
   Every page is main > section stacks with the footer injected after. Sections
   below the viewport are not laid out or painted at all until the visitor
   scrolls near them — the browser renders only what is (about to be) on
   screen instead of compositing the whole page on every frame.

   The hero (first section) is exempt: it is always on screen at load and
   carries negative-z-index media layers that paint containment could clip.

   contain-intrinsic-size is only a placeholder height for the scrollbar until
   a section has rendered once; `auto` then remembers the real size, so the
   scrollbar stays honest after the first pass down the page.
   ========================================================================== */
main > section:not(:first-child),
#footer-container {
    content-visibility: auto;
    contain-intrinsic-size: auto 48rem;
}

/* ==========================================================================
   Reveal-on-scroll (progressive enhancement — visible by default)
   ========================================================================== */
.reveal-ready .reveal {
    opacity: 0;
    transform: translateY(1.75rem);
    transition: opacity var(--t-slow), transform var(--t-slow);
}

.reveal-ready .reveal.is-visible {
    opacity: 1;
    transform: none;
}

/* ==========================================================================
   Loading overlay
   ========================================================================== */
body.loading { overflow: hidden; }

body.loading > *:not(#loading-overlay) {
    opacity: 0;
    pointer-events: none;
}

#loading-overlay {
    position: fixed;
    inset: 0;
    z-index: 9999;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    background:
        radial-gradient(40rem 30rem at 50% 30%, rgba(83, 134, 101, 0.5), transparent 70%),
        linear-gradient(165deg, var(--ngp-forest), #0f2016);
    transition: opacity 0.35s var(--ease-glass);
}

#loading-icon {
    width: 6.5rem;
    height: 6.5rem;
    object-fit: contain;
    animation: sprout-pulse 2.2s var(--ease-glass) infinite;
    filter: drop-shadow(0 8px 24px rgba(0, 0, 0, 0.35));
}

@keyframes sprout-pulse {
    0%, 100% { transform: scale(1)    rotate(-2deg); opacity: 0.92; }
    50%      { transform: scale(1.07) rotate(2deg);  opacity: 1; }
}

#loading-bar-container {
    margin-top: 3.25rem;
    width: 13rem;
    height: 0.375rem;
    border-radius: var(--r-pill);
    background: rgba(255, 255, 255, 0.16);
    border: 1px solid rgba(255, 255, 255, 0.14);
    overflow: hidden;
}

#loading-bar {
    width: 0%;
    height: 100%;
    border-radius: var(--r-pill);
    background: linear-gradient(90deg, var(--ngp-sage), var(--ngp-leaf-bright));
    box-shadow: 0 0 14px rgba(156, 204, 81, 0.6);
    transition: width 0.3s var(--ease-glass);
}

#loading-status {
    margin-top: 1.5rem;
    min-height: 1rem;
    color: rgba(244, 248, 242, 0.72);
    font-size: 0.6875rem;
    font-weight: 500;
    letter-spacing: 0.16em;
    text-transform: uppercase;
}

/* ==========================================================================
   Scrollbar
   ========================================================================== */
::-webkit-scrollbar { width: 0.625rem; }
::-webkit-scrollbar-track { background: var(--ngp-mist); }
::-webkit-scrollbar-thumb {
    background: linear-gradient(var(--ngp-sage), var(--ngp-forest));
    border-radius: var(--r-pill);
    border: 2px solid var(--ngp-mist);
}
::-webkit-scrollbar-thumb:hover { background: var(--ngp-forest); }

/* ==========================================================================
   Accessibility
   ========================================================================== */
.visually-hidden {
    position: absolute !important;
    width: 1px; height: 1px;
    margin: -1px; padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
}

@media (max-width: 768px) {
    a, button, input, select, textarea, [role="button"] { min-height: 44px; }
    body { font-size: 16px; }
}

@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
    .reveal-ready .reveal { opacity: 1 !important; transform: none !important; }
}
