/*──────────────────────────────────────────────────────────
  MANOVA TECH — ATMOSPHERE
  One global background language, used by every hero on the site.

  The idea: instead of each page inventing its own backdrop, every hero
  renders the same seven-layer stack (see atmosphere.php) and each page
  only re-tunes a handful of custom properties. Same identity
  everywhere, a different composition on every page.

  The layer stack, back to front:
    1. __base    flat deep field, the anchor tone
    2. __mesh    large soft mesh gradient — the color "weather"
    3. __grid    fine technical grid / rules, masked so it never tiles
                 edge-to-edge
    4. __rings   abstract geometric forms (thin concentric arcs)
    5. __orb a/b two slow-drifting ambient light sources
    6. __beam    a single wide specular sweep
    7. __noise   fine film grain, kills gradient banding
    8. __fade    vignette + bottom blend into the following section

  PERFORMANCE NOTES
  - Glow is drawn with radial-gradients, NOT filter: blur(). Big blurred
    layers are the single most expensive thing you can put in a hero;
    a gradient costs effectively nothing and looks the same at this
    softness.
  - Only transform and opacity are animated, so everything stays on the
    compositor and off the main thread.
  - Layers are progressively dropped on smaller screens, and all motion
    stops for prefers-reduced-motion.
──────────────────────────────────────────────────────────*/

.atmos {
  /* Palette — every variant below overrides these and nothing else. */
  --atm-a: rgba(0,175,193, .30);      /* primary light  */
  --atm-b: rgba(0,127,147, .22);      /* secondary light */
  --atm-c: rgba(41,211,223, .14);      /* accent rim      */
  --atm-base: #050505;                   /* field tone      */
  --atm-fade: #050505;                   /* blend-out tone  */
  --atm-line: rgba(255, 255, 255, .045); /* grid rules      */
  --atm-grid-size: 78px;
  --atm-beam-angle: 16deg;
  --atm-beam-opacity: .30;
  --atm-noise: .032;

  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
  contain: layout paint;
  background: var(--atm-base);
}

/* Every layer fills the box. Spans so the markup stays valid anywhere. */
.atmos > span {
  display: block;
  position: absolute;
  inset: 0;
}

/*── 1 · BASE ──────────────────────────────────────────────
  A barely-there vertical lift so the field isn't dead flat. */
.atmos__base {
  background: linear-gradient(180deg, rgba(255, 255, 255, .028), transparent 42%);
}

/*── 2 · MESH ──────────────────────────────────────────────
  The color weather. Three wide, very soft radials at different
  scales — this is what makes it read as "lit" rather than "gradient". */
.atmos__mesh {
  background:
    radial-gradient(ellipse 62% 58% at var(--atm-mesh-a, 18% 8%), var(--atm-a), transparent 62%),
    radial-gradient(ellipse 54% 52% at var(--atm-mesh-b, 86% 72%), var(--atm-b), transparent 64%),
    radial-gradient(ellipse 70% 40% at var(--atm-mesh-c, 62% 4%), var(--atm-c), transparent 70%);
}

/*── 3 · GRID ──────────────────────────────────────────────
  Technical substrate. Double-masked (radial + linear) so it dissolves
  toward the edges instead of stopping on a hard line. */
.atmos__grid {
  background-image:
    linear-gradient(var(--atm-line) 1px, transparent 1px),
    linear-gradient(90deg, var(--atm-line) 1px, transparent 1px);
  background-size: var(--atm-grid-size) var(--atm-grid-size);
  -webkit-mask-image:
    radial-gradient(ellipse 78% 74% at var(--atm-grid-focus, 50% 32%), #000 8%, transparent 76%);
  mask-image:
    radial-gradient(ellipse 78% 74% at var(--atm-grid-focus, 50% 32%), #000 8%, transparent 76%);
  opacity: var(--atm-grid-opacity, 1);
}

/*── 4 · RINGS ─────────────────────────────────────────────
  Abstract geometry — thin concentric arcs, the "instrument" motif.
  Drawn with repeating-radial-gradient: one paint, no DOM cost. */
.atmos__rings {
  background:
    repeating-radial-gradient(circle at var(--atm-ring-pos, 78% 22%),
      transparent 0 78px,
      rgba(255, 255, 255, .05) 78px 79px,
      transparent 79px 158px);
  -webkit-mask-image: radial-gradient(circle at var(--atm-ring-pos, 78% 22%), #000, transparent 62%);
  mask-image: radial-gradient(circle at var(--atm-ring-pos, 78% 22%), #000, transparent 62%);
  opacity: var(--atm-ring-opacity, .55);
  animation: atmosBreathe 26s var(--ease-expo, ease-in-out) infinite;
}

/*── 5 · ORBS ──────────────────────────────────────────────
  Two ambient sources on long, offset drifts. Scaled up beyond the box
  so the falloff never reveals an edge while they move. */
.atmos__orb {
  inset: -30%;
  will-change: transform;
}
.atmos__orb--a {
  background: radial-gradient(circle at var(--atm-orb-a, 30% 34%), var(--atm-a), transparent 46%);
  animation: atmosDriftA 30s ease-in-out infinite;
}
.atmos__orb--b {
  background: radial-gradient(circle at var(--atm-orb-b, 72% 66%), var(--atm-b), transparent 44%);
  animation: atmosDriftB 38s ease-in-out infinite;
}

/*── 6 · BEAM ──────────────────────────────────────────────
  One wide specular sweep. Deliberately slow and low-contrast — it
  should register as "the light moved", never as an animation. */
.atmos__beam {
  inset: -60% -30%;
  background: linear-gradient(
    90deg,
    transparent 0%,
    rgba(255, 255, 255, .05) 42%,
    rgba(255, 255, 255, .09) 50%,
    rgba(255, 255, 255, .05) 58%,
    transparent 100%);
  opacity: 0;
  will-change: transform, opacity;
  animation: atmosBeam 22s linear infinite;
  animation-delay: var(--atm-beam-delay, 3s);
}

/*── 7 · NOISE ─────────────────────────────────────────────
  Inline SVG turbulence — no network request, and it's what stops the
  wide gradients from banding on 8-bit panels. */
.atmos__noise {
  opacity: var(--atm-noise);
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/*── 8 · FADE ──────────────────────────────────────────────
  Vignette plus a blend into whatever section follows, so heroes never
  end on a visible seam. */
.atmos__fade {
  background:
    radial-gradient(ellipse 90% 80% at 50% 40%, transparent 40%, rgba(0, 0, 0, .42)),
    linear-gradient(180deg, transparent 58%, var(--atm-fade) 100%);
}

/*──────────────────────────────────────────────────────────
  MOTION
──────────────────────────────────────────────────────────*/
@keyframes atmosDriftA {
  0%, 100% { transform: translate3d(0, 0, 0) scale(1); }
  50%      { transform: translate3d(3.5%, -3%, 0) scale(1.09); }
}
@keyframes atmosDriftB {
  0%, 100% { transform: translate3d(0, 0, 0) scale(1.06); }
  50%      { transform: translate3d(-4%, 3.5%, 0) scale(1); }
}
@keyframes atmosBeam {
  0%       { transform: translate3d(-115%, 0, 0) rotate(var(--atm-beam-angle)); opacity: 0; }
  12%      { opacity: var(--atm-beam-opacity); }
  88%      { opacity: var(--atm-beam-opacity); }
  100%     { transform: translate3d(115%, 0, 0) rotate(var(--atm-beam-angle)); opacity: 0; }
}
@keyframes atmosBreathe {
  0%, 100% { transform: scale(1); opacity: var(--atm-ring-opacity, .55); }
  50%      { transform: scale(1.06); opacity: calc(var(--atm-ring-opacity, .55) * .6); }
}

/*──────────────────────────────────────────────────────────
  VARIANTS
  Each page gets its own composition out of the same parts: different
  light positions, different geometry, different temperature. Nothing
  here changes the structure — only the tuning.
──────────────────────────────────────────────────────────*/

/*── HOME · the widest, brightest statement ─────────────────
  Dual sources low and wide, strong central rings, full beam. This is
  the only hero that runs every layer at full strength. */
.atmos--home {
  --atm-a: rgba(0,175,193, .34);
  --atm-b: rgba(0,127,147, .24);
  --atm-c: rgba(41,211,223, .13);
  --atm-mesh-a: 14% 4%;
  --atm-mesh-b: 88% 78%;
  --atm-mesh-c: 50% 0%;
  --atm-orb-a: 26% 30%;
  --atm-orb-b: 76% 70%;
  --atm-ring-pos: 50% 6%;
  --atm-ring-opacity: .5;
  --atm-grid-size: 84px;
  --atm-grid-focus: 50% 26%;
  --atm-beam-angle: 14deg;
  --atm-beam-opacity: .34;
}

/*── SERVICE · accent-driven ────────────────────────────────
  Single-service pages already set --svc-accent-start/end inline on
  <main> from each service's own ACF colors, so the atmosphere inherits
  them: every one of the nine services gets a genuinely different hue
  for free, with no per-service CSS. Falls back to blue/violet if a
  service has no accent set. */
.atmos--service {
  --atm-a: rgba(0,175,193, .26);
  --atm-b: rgba(0,127,147, .18);
  --atm-c: rgba(255, 255, 255, .05);
  --atm-mesh-a: 88% 10%;
  --atm-mesh-b: 8% 84%;
  --atm-mesh-c: 60% 100%;
  --atm-orb-a: 80% 24%;
  --atm-orb-b: 16% 78%;
  --atm-ring-pos: 88% 14%;
  --atm-ring-opacity: .4;
  --atm-grid-size: 64px;
  --atm-grid-focus: 72% 24%;
  --atm-beam-angle: -12deg;
  --atm-beam-opacity: .26;
  --atm-beam-delay: 6s;
}

/* Guarded: a custom property holding an unsupported function isn't
   caught at parse time — it fails later, when it's substituted into the
   gradient, taking the whole layer with it. @supports keeps the plain
   rgba values above as a real fallback. */
@supports (color: color-mix(in srgb, red 50%, transparent)) {
  .atmos--service {
    --atm-a: color-mix(in srgb, var(--svc-accent-start, #00afc1) 30%, transparent);
    --atm-b: color-mix(in srgb, var(--svc-accent-end, #007f93) 20%, transparent);
  }
}

/*── SERVICES ARCHIVE · the overview, calmer than a single ──*/
.atmos--services {
  --atm-a: rgba(0,175,193, .28);
  --atm-b: rgba(103,232,237, .18);
  --atm-c: rgba(0,127,147, .12);
  --atm-mesh-a: 50% 0%;
  --atm-mesh-b: 12% 86%;
  --atm-mesh-c: 88% 78%;
  --atm-orb-a: 50% 16%;
  --atm-orb-b: 82% 82%;
  --atm-ring-pos: 50% 0%;
  --atm-ring-opacity: .46;
  --atm-grid-size: 72px;
  --atm-grid-focus: 50% 20%;
  --atm-beam-angle: 10deg;
}

/*── RESOURCES · editorial ──────────────────────────────────
  The one variant that trades the square grid for vertical column
  rules — a masthead/print reference. Light sits high and cool so long
  headlines stay the loudest thing on screen. */
.atmos--resource {
  --atm-a: rgba(0,175,193, .22);
  --atm-b: rgba(103,232,237, .13);
  --atm-c: rgba(0,127,147, .10);
  --atm-base: #070708;
  --atm-fade: #070708;
  --atm-mesh-a: 80% 6%;
  --atm-mesh-b: 16% 70%;
  --atm-mesh-c: 50% 0%;
  --atm-orb-a: 78% 14%;
  --atm-orb-b: 22% 76%;
  --atm-ring-opacity: 0;
  --atm-beam-angle: 8deg;
  --atm-beam-opacity: .2;
  --atm-noise: .04;
}
/* Column rules instead of a grid — vertical only, evenly spaced. */
.atmos--resource .atmos__grid {
  background-image: linear-gradient(90deg, rgba(255, 255, 255, .04) 1px, transparent 1px);
  background-size: 20% 100%;
  -webkit-mask-image: linear-gradient(180deg, transparent, #000 18%, #000 76%, transparent);
  mask-image: linear-gradient(180deg, transparent, #000 18%, #000 76%, transparent);
}

/* Case studies run warmer than the blog so the two archives are
   instantly distinguishable while staying in the same system. */
.atmos--case {
  --atm-a: rgba(0,127,147, .22);
  --atm-b: rgba(34,199,214, .14);
  --atm-c: rgba(0,175,193, .12);
  --atm-mesh-a: 20% 6%;
  --atm-mesh-b: 84% 74%;
  --atm-orb-a: 22% 18%;
  --atm-orb-b: 80% 74%;
  --atm-beam-angle: -8deg;
}

/*── CONTACT · welcoming ────────────────────────────────────
  Centered, symmetrical, warmer. Concentric rings sit dead centre and
  read as an open signal rather than an instrument panel. */
.atmos--contact {
  --atm-a: rgba(0,175,193, .26);
  --atm-b: rgba(0,127,147, .18);
  --atm-c: rgba(41,211,223, .12);
  --atm-mesh-a: 50% 6%;
  --atm-mesh-b: 50% 96%;
  --atm-mesh-c: 12% 40%;
  --atm-orb-a: 50% 20%;
  --atm-orb-b: 50% 88%;
  --atm-ring-pos: 50% 34%;
  --atm-ring-opacity: .42;
  --atm-grid-size: 68px;
  --atm-grid-focus: 50% 40%;
  --atm-beam-angle: 0deg;
  --atm-beam-opacity: .24;
}
.atmos--contact .atmos__rings {
  background: repeating-radial-gradient(circle at var(--atm-ring-pos),
    transparent 0 96px,
    rgba(255, 255, 255, .055) 96px 97px,
    transparent 97px 194px);
}

/*── WORK / GENERIC PAGE · the quiet default ────────────────*/
.atmos--page {
  --atm-a: rgba(0,175,193, .24);
  --atm-b: rgba(0,127,147, .16);
  --atm-c: rgba(41,211,223, .10);
  --atm-mesh-a: 22% 10%;
  --atm-mesh-b: 84% 76%;
  --atm-orb-a: 24% 26%;
  --atm-orb-b: 80% 74%;
  --atm-ring-opacity: .34;
  --atm-grid-focus: 40% 30%;
  --atm-beam-opacity: .22;
}

/*──────────────────────────────────────────────────────────
  HOST HOOKS
  The hero sections that now carry an .atmos need a stacking context
  and their content lifted above it. Done here so the individual page
  stylesheets stay untouched.
──────────────────────────────────────────────────────────*/
.hero,
.service-hero,
.ab-hero,
.page-hero,
.service-archive-hero,
.resources-hub-hero,
.resource-single-hero { position: relative; }

.hero > .hero-content,
.hero > .scroll-hint,
.service-hero > .container,
.ab-hero > .container,
.page-hero > .container,
.service-archive-hero > .container,
.resources-hub-hero > .container,
.resource-single-hero > .container { position: relative; z-index: 2; }

/* The homepage particle canvas belongs ABOVE the atmosphere — the
   atmosphere is the sky it's drawn against. */
.hero > #heroCanvas { z-index: 1; }

/* Resource singles: the photograph sits above the atmosphere, because
   it only covers the right half and the atmosphere fills the rest. */
.resource-single-hero__backdrop { z-index: 1; }

/* Single services are the opposite case — the hero photo covers the
   whole section, so an atmosphere behind it would simply never be seen.
   Instead the stack is inverted and the light layers are screen-blended
   over the image: services WITH a hero photo get it tinted and lit in
   their own accent, services WITHOUT one get the same composition
   straight over the field. Same result either way, which is the point.
   Screen over black is a no-op, so the imageless case is unaffected. */
.service-hero-media { z-index: 0; }
.service-hero .atmos { z-index: 1; }
.atmos--service { --atm-base: transparent; }
.atmos--service .atmos__base { display: none; }
.atmos--service .atmos__mesh,
.atmos--service .atmos__orb,
.atmos--service .atmos__rings,
.atmos--service .atmos__beam { mix-blend-mode: screen; }

/* The old per-page backdrops are now redundant: the atmosphere replaces
   them. Retired here rather than deleted from their own stylesheets so
   the change is reversible in one place. */
.page-hero-bg,
.hero-aurora,
.hero-radial,
.hero-grid-bg,
.service-hero-grid,
.resources-hub-hero__wash { display: none; }

/*──────────────────────────────────────────────────────────
  RESPONSIVE
  Progressive simplification. Tablets lose the beam and rings (the two
  layers that read least at small sizes); phones also lose the second
  orb and tighten the grid, which keeps the paint area small on the
  hardware least able to afford it.
──────────────────────────────────────────────────────────*/
@media (max-width: 1024px) {
  .atmos__beam,
  .atmos__rings { display: none; }
  .atmos { --atm-grid-size: 58px; }
}
@media (max-width: 640px) {
  .atmos__orb--b { display: none; }
  .atmos {
    --atm-grid-size: 44px;
    --atm-noise: .028;
  }
  .atmos__grid { opacity: .8; }
  /* Mesh recentres for portrait so the light stays behind the headline
     instead of drifting off the side of the screen. */
  .atmos__mesh {
    background:
      radial-gradient(ellipse 110% 46% at 50% 4%, var(--atm-a), transparent 66%),
      radial-gradient(ellipse 96% 40% at 50% 92%, var(--atm-b), transparent 68%);
  }
}

/*──────────────────────────────────────────────────────────
  REDUCED MOTION
  The composition is designed to hold up completely static — motion is
  an enhancement, never load-bearing.
──────────────────────────────────────────────────────────*/
@media (prefers-reduced-motion: reduce) {
  .atmos__orb--a,
  .atmos__orb--b,
  .atmos__rings,
  .atmos__beam { animation: none !important; }
  .atmos__beam { display: none; }
}

/* Print: no atmosphere at all. */
@media print {
  .atmos { display: none !important; }
}

/* Resource heroes get a single soft top-light: editorial pages should
   feel lit from above the masthead, not from the sides. */
.resources-hub-hero::after{
  content: '';
  position: absolute;
  inset: 0 0 auto;
  height: 62%;
  z-index: 1;
  pointer-events: none;
  background: linear-gradient(180deg, rgba(255, 255, 255, .035), transparent 78%);
}

/* A thin measure line under the standfirst — the same detail the hub
   masthead uses, so the two read as one publication. */
